/* ----------------------------------------------------------------------------- * 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[] = "$Id: segment.c 10001 2007-10-17 21:33:57Z wsfulton $"; /* 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; }