diff --git a/Tools/WAD/Include/wad.h b/Tools/WAD/Include/wad.h index 055bf74b4..18964beb4 100644 --- a/Tools/WAD/Include/wad.h +++ b/Tools/WAD/Include/wad.h @@ -25,29 +25,21 @@ extern "C" { #define MAX_PATH 1024 #endif -/* Typedef's for various addresses and sizes */ -typedef char * wadaddr_t; -typedef unsigned long wadlen_t; - -/* Memory management */ -extern void *wadmalloc(unsigned int); -extern void wadfree(void *ptr); +/* Memory segment management */ typedef struct WadSegment { - wadaddr_t vaddr; /* Virtual address start */ - wadlen_t size; /* Size of the segment (bytes) */ + char *base; /* Base address for symbol lookup */ + char *vaddr; /* Virtual address start */ + unsigned long size; /* Size of the segment (bytes) */ int flags; /* Memory access permissions */ - wadlen_t offset; /* Offset into mapped object */ + unsigned long offset; /* Offset into mapped object */ char mapname[MAX_PATH]; /* Filename mapped to this region */ char mappath[MAX_PATH]; /* Full path to mapname */ - int identifier; /* identifier (if SysV shmem) */ - long wad; /* Private wad data (if any) */ } WadSegment; -extern void wad_segment_print(WadSegment *s); -extern WadSegment *wad_segment_find(wadaddr_t addr); -extern WadSegment *wad_segment_first(); -extern WadSegment *wad_segment_next(); +extern void wad_segment_print(WadSegment *s); +extern WadSegment *wad_segment_find(char *addr); +extern void wad_segment_release(); /* Structure for managing object files */ typedef struct WadObject { diff --git a/Tools/WAD/Wad/init.c b/Tools/WAD/Wad/init.c index 913c11e55..bb4ae4332 100644 --- a/Tools/WAD/Wad/init.c +++ b/Tools/WAD/Wad/init.c @@ -40,7 +40,7 @@ void wad_init() { sigaddset(&newvec.sa_mask, SIGABRT); sigaddset(&newvec.sa_mask, SIGILL); sigaddset(&newvec.sa_mask, SIGFPE); - newvec.sa_flags = SA_SIGINFO | SA_ONSTACK; + newvec.sa_flags = SA_SIGINFO | SA_ONSTACK /* | SA_RESETHAND */; newvec.sa_sigaction = ((void (*)(int,siginfo_t *, void *)) wad_signalhandler); sigaction(SIGSEGV, &newvec, NULL); sigaction(SIGBUS, &newvec, NULL); diff --git a/Tools/WAD/Wad/segment.c b/Tools/WAD/Wad/segment.c index 5f5ac29d3..f3e5e3847 100644 --- a/Tools/WAD/Wad/segment.c +++ b/Tools/WAD/Wad/segment.c @@ -14,20 +14,122 @@ #include "wad.h" #include +#include +/* The segment map is actually stored in an mmap'd data structure so we + can avoid the use of malloc()/free(). */ +static WadSegment *segments = 0; /* mmap data containing segment info */ +static int segments_size; /* Size of mmap'd region */ +static int nsegments = 0; /* Number of segments */ -/* The current segment is stored in statically allocated memory to avoid - the use of malloc()/free(). If a caller wants to make a copy, that is - their problem */ +/* This function reads the segment map into memory */ +static +void read_segments() { + int fd; + int dz; + prmap_t pmap; + int offset = 0; + int i; + int n = 0; + WadSegment *s; -static WadSegment segment; /* Currently loaded segment */ -static int read_segment = 0; + /* Try to load the virtual address map */ + fd = open("/proc/self/map", O_RDONLY); + if (fd < 0) { + return; + } + nsegments = 0; + while (1) { + n = read(fd,&pmap,sizeof(prmap_t)); + if (n <= 0) break; + nsegments++; + } + nsegments++; + close(fd); + + dz = open("/dev/zero", O_RDWR, 0644); + if (fd < 0) { + puts("Couldn't open /dev/zero\n"); + return; + } + segments = (WadSegment *) mmap(NULL, nsegments*sizeof(WadSegment), PROT_READ | PROT_WRITE, MAP_PRIVATE, dz, 0); + close(dz); + segments_size = nsegments*sizeof(WadSegment); + + fd = open("/proc/self/map", O_RDONLY); + if (fd < 0) return; + i = 0; + s = segments; + while (1) { + n = read(fd,&pmap,sizeof(prmap_t)); + if (n <= 0) break; + strncpy(s->mapname, pmap.pr_mapname, MAX_PATH); + 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; + s->flags = pmap.pr_mflags; + s++; + } + close(fd); +} + +/* ----------------------------------------------------------------------------- + * wad_segment_release() + * + * This function releases all of the segments. + * ----------------------------------------------------------------------------- */ +void wad_segment_release() { + munmap((void *)segments, segments_size); + segments = 0; + segments_size = 0; + nsegments = 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(char *addr) { + int i; + WadSegment *s, *ls; + + if (!segments) read_segments(); + if (!segments) return 0; + + s = segments; + ls = s; + for (i = 0; i < nsegments; i++, s++) { + if (strcmp(s->mapname,ls->mapname)) { + ls = s; /* First segment for a given name */ + } + + if ((addr >= s->vaddr) && (addr < (s->vaddr + s->size))) { + return ls; + } + } + return 0; +} /* ----------------------------------------------------------------------------- * wad_segment_print() * - * Print the contents of a memory segment. (Debugging) + * Print the contents of a memory segment. (For debugging WAD) * ----------------------------------------------------------------------------- */ void @@ -39,128 +141,4 @@ wad_segment_print(WadSegment *s) { printf(" size = %d\n", s->size); printf(" offset = %d\n", s->offset); printf(" flags = 0x%x\n", s->flags); - printf(" identifier = %d\n", s->identifier); -} - - -/* ----------------------------------------------------------------------------- - * wad_segment_find() - * - * Try to find the virtual memory segment corresponding to a virtual address. - * This overwrites the previously returned segment data. - * ----------------------------------------------------------------------------- */ - -WadSegment * -wad_segment_find(wadaddr_t addr) { - char dirname[MAX_PATH]; - char filename[MAX_PATH]; - int fd; - prmap_t pmap; - int offset = 0; - int i; - int n; - - if (read_segment) { - if ((addr >= segment.vaddr) && (addr < (segment.vaddr+segment.size))) return &segment; - } - - /* Set location in /proc */ - sprintf(dirname,"/proc/%d",getpid()); - - /* Try to load the virtual address map */ - sprintf(filename,"%s/map",dirname); - fd = open(filename, O_RDONLY); - if (fd < 0) { - printf("wad_segment_find: couldn't open '%s'\n", filename); - return 0; - } - - segment.mapname[0] = 0; - - read_segment = 0; - while (1) { - n = read(fd,&pmap,sizeof(prmap_t)); - if (n <= 0) break; - offset += n; - if ((addr >= (wadaddr_t) pmap.pr_vaddr) && (addr <= (wadaddr_t) (pmap.pr_vaddr + pmap.pr_size))) { - /* We are in a new segment */ - strncpy(segment.mapname, pmap.pr_mapname, MAX_PATH); - strcpy(segment.mappath,dirname); - strcat(segment.mappath,"/object/"); - strcat(segment.mappath,pmap.pr_mapname); - segment.vaddr = (wadaddr_t) pmap.pr_vaddr; - segment.size = pmap.pr_size; - segment.offset = pmap.pr_offset; - segment.flags = pmap.pr_mflags; - segment.identifier = pmap.pr_shmid; - segment.wad = offset; - read_segment = 1; - close(fd); - return &segment; - } - } - close(fd); - return 0; -} - -/* ----------------------------------------------------------------------------- - * wad_segment_next() - * - * Read the next segment - * ----------------------------------------------------------------------------- */ - -WadSegment *wad_segment_next() { - - char dirname[MAX_PATH]; - char filename[MAX_PATH]; - int fd; - prmap_t pmap; - int offset = 0; - int i; - int n; - - if (!read_segment) { - segment.wad = 0; - } - - /* Set location in /proc */ - sprintf(dirname,"/proc/%d",getpid()); - - /* Try to load the virtual address map */ - sprintf(filename,"%s/map",dirname); - fd = open(filename, O_RDONLY); - if (fd < 0) { - printf("wad_segment_find: couldn't open '%s'\n", filename); - return 0; - } - if (lseek(fd, segment.wad, SEEK_SET) < 0) { - close(fd); - return 0; - } - n = read(fd,&pmap,sizeof(prmap_t)); - if (n <= 0) { - read_segment = 0; - close(fd); - return 0; - } - strncpy(segment.mapname, pmap.pr_mapname, MAX_PATH); - strcpy(segment.mappath,dirname); - strcat(segment.mappath,"/object/"); - strcat(segment.mappath,pmap.pr_mapname); - segment.vaddr = (wadaddr_t) pmap.pr_vaddr; - segment.size = pmap.pr_size; - segment.offset = pmap.pr_offset; - segment.flags = pmap.pr_mflags; - segment.identifier = pmap.pr_shmid; - segment.wad += n; - read_segment = 1; - close(fd); - return &segment; -} - -WadSegment * -wad_segment_first() { - segment.wad = 0; - read_segment = 0; - return wad_segment_next(); } diff --git a/Tools/WAD/Wad/signal.c b/Tools/WAD/Wad/signal.c index bcf527536..37b267dc2 100644 --- a/Tools/WAD/Wad/signal.c +++ b/Tools/WAD/Wad/signal.c @@ -120,16 +120,6 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) { addr = (unsigned long) si->si_addr; p_pc = (unsigned long) (*pc); p_sp = (unsigned long) (*sp); - - - /* { - Dl_info dli; - if (dladdr((void *) p_pc, &dli) >= 0) { - printf("dli_fname = %s\n", dli.dli_fname); - printf("dli_sname = %s\n", dli.dli_sname); - } - } - */ frame = wad_stack_trace(p_pc, p_sp, 0); origframe =frame; if (!frame) { @@ -138,7 +128,6 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) { } /* Walk the exception frames and try to find a return point */ - framedata = (char *) frame; while (frame->size) { diff --git a/Tools/WAD/Wad/stab.c b/Tools/WAD/Wad/stab.c index 3122f6d72..8f138ba2e 100644 --- a/Tools/WAD/Wad/stab.c +++ b/Tools/WAD/Wad/stab.c @@ -120,8 +120,7 @@ wad_search_stab(void *sp, int size, char *stabstr, char *symbol, unsigned long o } else if (debug.found && (s->n_type == 0x44) && (infunc)) { /* Line number location */ - - if (s->n_value <= offset) { + if (s->n_value < offset) { debug.line_number = s->n_desc; } else return &debug; } else if (debug.found && ((s->n_type == 0xa0) || (s->n_type == 0x40)) && (infunc)) { diff --git a/Tools/WAD/Wad/stack.c b/Tools/WAD/Wad/stack.c index cbb8b3287..5c5c02656 100644 --- a/Tools/WAD/Wad/stack.c +++ b/Tools/WAD/Wad/stack.c @@ -63,12 +63,12 @@ wad_stack_trace(unsigned long pc, unsigned long sp, unsigned long fp) { while (p_sp) { /* Add check for stack validity here */ - ws = wad_segment_find((wadaddr_t) p_sp); + ws = wad_segment_find((char *) p_sp); if (!ws) { /* If the stack is bad, we are really hosed here */ break; } - ws = wad_segment_find((wadaddr_t) p_pc); + ws = wad_segment_find((char *) p_pc); { int symsize = 0; int srcsize = 0; @@ -85,7 +85,6 @@ wad_stack_trace(unsigned long pc, unsigned long sp, unsigned long fp) { if (ws) { wo = wad_object_load(ws->mappath); /* Special hack needed for base address */ - if (strcmp(ws->mapname,"a.out") == 0) ws->vaddr= 0; } else { wo = 0; @@ -93,13 +92,7 @@ wad_stack_trace(unsigned long pc, unsigned long sp, unsigned long fp) { /* Try to find the symbol corresponding to this PC */ if (wo) { - symname = wad_find_symbol(wo, (void *) p_pc, (unsigned long) ws->vaddr, &value); - /* if (!symname) { - Dl_info dli; - if (dladdr((void *) p_pc, &dli) >= 0) { - symname = (char *) dli.dli_sname; - } - }*/ + symname = wad_find_symbol(wo, (void *) p_pc, (unsigned long) ws->base, &value); } else { symname = 0; } @@ -117,7 +110,7 @@ wad_stack_trace(unsigned long pc, unsigned long sp, unsigned long fp) { symsize = strlen(symname)+1; /* Try to gather some debugging information about this symbol */ - wd = wad_debug_info(wo,symname, p_pc - (unsigned long) ws->vaddr - value); + wd = wad_debug_info(wo,symname, p_pc - (unsigned long) ws->base - value); if (wd) { srcname = wd->srcfile; srcsize = strlen(srcname)+1; @@ -222,6 +215,7 @@ wad_stack_trace(unsigned long pc, unsigned long sp, unsigned long fp) { lseek(ffile,0,SEEK_SET); trace_addr = mmap(NULL, trace_len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, ffile, 0); close(ffile); + wad_segment_release(); return (WadFrame *) trace_addr; } @@ -243,7 +237,6 @@ long wad_steal_arg(WadFrame *f, char *symbol, int argno, int *error) { fd = (char *) f; - *error = 0; /* Start searching */ while (f->size) {