blob: 280ab76019546b57b81a91d7deeb5ea70acdb540 [file] [log] [blame]
/* -----------------------------------------------------------------------------
* segment.c
*
* This file provides access to the virtual memory map of a process
* including the location of the executable, data segments, shared
* libraries, and memory mapped regions.
*
* The primary purpose of this module is to collect this information
* and store it in a form that hides platform specific details (the
* WadSegment structure).
*
* Author(s) : David Beazley (beazley@cs.uchicago.edu)
*
* Copyright (C) 2000. The University of Chicago.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* See the file COPYING for a complete copy of the LGPL.
* ----------------------------------------------------------------------------- */
#include "wad.h"
static char cvs[] = "$Header$";
/* Include the proper code for reading the segment map */
#ifdef WAD_SOLARIS
/* This code is used to read the process virtual memory map on Solaris machines */
static int
segment_open() {
int f;
f = open("/proc/self/map", O_RDONLY);
return f;
}
static int
segment_read(int fs, WadSegment *s) {
int dz;
int n;
prmap_t pmap;
n = read(fs, &pmap, sizeof(prmap_t));
if (n <= 0) return 0;
s->mapname = wad_strdup(pmap.pr_mapname);
s->mappath = (char *) wad_malloc(20+strlen(pmap.pr_mapname));
wad_strcpy(s->mappath,"/proc/self/object/");
strcat(s->mappath,pmap.pr_mapname);
s->vaddr = (char *) pmap.pr_vaddr;
/* This is a solaris oddity. a.out section starts 1 page up, but
symbols are relative to a base of 0 */
if (strcmp(s->mapname,"a.out") == 0) s->base = 0;
else s->base = s->vaddr;
s->size = pmap.pr_size;
s->offset = pmap.pr_offset;
return 1;
}
#endif /* WAD_SOLARIS */
#ifdef WAD_LINUX
static char linux_firstsegment[1024];
static int linux_first = 1;
static int
segment_open() {
FILE *f;
f = fopen("/proc/self/maps", "r");
linux_first =1;
return (int) f;
}
static int
segment_read(int fd, WadSegment *s)
{
char pbuffer[1024];
char *c;
int len;
FILE *fs = (FILE *) fd;
c = fgets(pbuffer,1024,fs);
if (!c) return 0;
pbuffer[strlen(pbuffer)-1] = 0; /* Chop off endline */
/* Break up the field into records */
/* 0-8 : Starting address
9-17 : Ending Address
18 : r
19 : w
20 : x
21 : p
23-31 : Offset
49- : Filename */
len = strlen(pbuffer);
pbuffer[8] = 0;
pbuffer[17] = 0;
pbuffer[31] = 0;
if (len >= 49) {
s->mapname = wad_strdup(pbuffer+49);
s->mappath = s->mapname;
} else {
s->mapname = "";
s->mappath = s->mapname;
}
if (linux_first) {
wad_strcpy(linux_firstsegment, s->mappath);
linux_first = 0;
}
s->vaddr = (char *) strtoul(pbuffer,NULL,16);
s->size = strtoul(pbuffer+9,NULL,16) - (long) (s->vaddr);
s->offset = strtoul(pbuffer+23,NULL,16);
if (strcmp(linux_firstsegment, s->mappath) == 0) {
s->base = 0;
} else {
s->base = s->vaddr;
}
s++;
return 1;
}
#endif /* WAD_LINUX */
static WadSegment *segments = 0; /* Linked list of segments */
/* -----------------------------------------------------------------------------
* wad_segment_read()
*
* Read all of the memory segments into a linked list. Any previous segment
* map is simply lost. The only way to reclaim this memory is to call
* wad_release_memory().
* ----------------------------------------------------------------------------- */
int
wad_segment_read() {
int fs;
int n;
WadSegment *s, *lasts;
segments = 0;
lasts = 0;
fs = segment_open();
while (1) {
s = (WadSegment *) wad_malloc(sizeof(WadSegment));
skip:
n = segment_read(fs,s);
if (n <= 0) break;
if (wad_file_check(s->vaddr)) goto skip; /* Skip files we already loaded */
s->next = 0;
if (!lasts) {
segments = s;
lasts = s;
} else {
lasts->next = s;
lasts = s;
}
if (wad_debug_mode & DEBUG_SEGMENT) {
wad_printf("wad_segment: read : %08x-%08x, base=%x in %s\n", s->vaddr, ((char *) s->vaddr) + s->size, s->base, s->mappath);
}
}
close(fs);
return 0;
}
/* -----------------------------------------------------------------------------
* wad_segment_find()
*
* Try to find the virtual memory segment corresponding to a virtual address.
* If a segment is mapped to a file, this function actually returns the *first*
* segment that is mapped. This is because symbol relocations are always
* performed relative to the beginning of the file (so we need the base address)
* ----------------------------------------------------------------------------- */
WadSegment *
wad_segment_find(void *vaddr) {
WadSegment *ls;
WadSegment *s;
char *addr = (char *)vaddr;
s = segments;
ls = segments;
while (s) {
if (strcmp(s->mapname,ls->mapname) || (!strlen(ls->mapname))) {
ls = s; /* First segment for a given name */
}
if ((addr >= s->vaddr) && (addr < (s->vaddr + s->size))) {
if (wad_debug_mode & DEBUG_SEGMENT) {
wad_printf("wad_segment: %08x --> %08x-%08x in %s\n", vaddr, s->vaddr, ((char *) s->vaddr) + s->size, s->mappath);
}
return ls;
}
s = s->next;
}
return 0;
}
/* -----------------------------------------------------------------------------
* wad_segment_valid()
*
* Checks to see if a memory address is valid or not based on data in the
* segment map
* ----------------------------------------------------------------------------- */
int wad_segment_valid(void *vaddr) {
return wad_segment_find(vaddr) ? 1 : 0;
}