/* * File stabs.c - read stabs information from the wine executable itself. * * Copyright (C) 1996, Eric Youngdale. */ #include #include #include #include #include #include #include #include #include #ifndef PATH_MAX #define PATH_MAX _MAX_PATH #endif #include "win.h" #include "debugger.h" #include "xmalloc.h" #ifdef __svr4__ #define __ELF__ #endif #ifdef __ELF__ #include #include #include #elif defined(__EMX__) #include #else #include #endif #ifndef N_UNDF #define N_UNDF 0x00 #endif #define N_GSYM 0x20 #define N_FUN 0x24 #define N_STSYM 0x26 #define N_LCSYM 0x28 #define N_MAIN 0x2a #define N_ROSYM 0x2c #define N_OPT 0x3c #define N_RSYM 0x40 #define N_SLINE 0x44 #define N_SO 0x64 #define N_LSYM 0x80 #define N_BINCL 0x82 #define N_SOL 0x84 #define N_PSYM 0xa0 #define N_EINCL 0xa2 #define N_LBRAC 0xc0 #define N_RBRAC 0xe0 /* * This is how we translate stab types into our internal representations * of datatypes. */ static struct datatype ** stab_types = NULL; static int num_stab_types = 0; /* * Set so that we know the main executable name and path. */ char * DEBUG_argv0; struct stab_nlist { union { char *n_name; struct stab_nlist *n_next; long n_strx; } n_un; unsigned char n_type; char n_other; short n_desc; unsigned long n_value; }; /* * This is used to keep track of known datatypes so that we don't redefine * them over and over again. It sucks up lots of memory otherwise. */ struct known_typedef { struct known_typedef * next; char * name; int ndefs; struct datatype * types[0]; }; #define NR_STAB_HASH 521 struct known_typedef * ktd_head[NR_STAB_HASH] = {NULL,}; static unsigned int stab_hash( const char * name ) { unsigned int hash = 0; unsigned int tmp; const char * p; p = name; while (*p) { hash = (hash << 4) + *p++; if( (tmp = (hash & 0xf0000000)) ) { hash ^= tmp >> 24; } hash &= ~tmp; } return hash % NR_STAB_HASH; } static void stab_strcpy(char * dest, const char * source) { /* * A strcpy routine that stops when we hit the ':' character. * Faster than copying the whole thing, and then nuking the * ':'. */ while(*source != '\0' && *source != ':') { *dest++ = *source++; } *dest++ = '\0'; } #define MAX_TD_NESTING 128 static int DEBUG_RegisterTypedef(const char * name, struct datatype ** types, int ndef) { int hash; struct known_typedef * ktd; if( ndef == 1 ) { return TRUE; } ktd = (struct known_typedef *) malloc(sizeof(struct known_typedef) + ndef * sizeof(struct datatype *)); hash = stab_hash(name); ktd->name = xstrdup(name); ktd->ndefs = ndef; memcpy(&ktd->types[0], types, ndef * sizeof(struct datatype *)); ktd->next = ktd_head[hash]; ktd_head[hash] = ktd; return TRUE; } static int DEBUG_HandlePreviousTypedef(const char * name, const char * stab) { int count; enum debug_type expect; int hash; struct known_typedef * ktd; char * ptr; char * tc; int typenum; hash = stab_hash(name); for(ktd = ktd_head[hash]; ktd; ktd = ktd->next) { if( (ktd->name[0] == name[0]) && (strcmp(name, ktd->name) == 0) ) { break; } } /* * Didn't find it. This must be a new one. */ if( ktd == NULL ) { return FALSE; } /* * Examine the stab to make sure it has the same number of definitions. */ count = 0; for(ptr = strchr(stab, '='); ptr; ptr = strchr(ptr+1, '=')) { if( count >= ktd->ndefs ) { return FALSE; } /* * Make sure the types of all of the objects is consistent with * what we have already parsed. */ switch(ptr[1]) { case '*': expect = POINTER; break; case 's': case 'u': expect = STRUCT; break; case 'a': expect = ARRAY; break; case '1': case 'r': expect = BASIC; break; case 'x': expect = STRUCT; break; case 'e': expect = ENUM; break; case 'f': expect = FUNC; break; default: fprintf(stderr, "Unknown type.\n"); return FALSE; } if( expect != DEBUG_GetType(ktd->types[count]) ) { return FALSE; } count++; } if( ktd->ndefs != count ) { return FALSE; } /* * OK, this one is safe. Go through, dig out all of the type numbers, * and substitute the appropriate things. */ count = 0; for(ptr = strchr(stab, '='); ptr; ptr = strchr(ptr+1, '=')) { /* * Back up until we get to a non-numeric character. This is the type * number. */ tc = ptr - 1; while( *tc >= '0' && *tc <= '9' ) { tc--; } typenum = atol(tc + 1); if( num_stab_types <= typenum ) { num_stab_types = typenum + 32; stab_types = (struct datatype **) xrealloc(stab_types, num_stab_types * sizeof(struct datatype *)); if( stab_types == NULL ) { return FALSE; } } stab_types[typenum] = ktd->types[count++]; } return TRUE; } static int DEBUG_FreeRegisteredTypedefs() { int count; int j; struct known_typedef * ktd; struct known_typedef * next; count = 0; for(j=0; j < NR_STAB_HASH; j++ ) { for(ktd = ktd_head[j]; ktd; ktd = next) { count++; next = ktd->next; free(ktd->name); free(ktd); } ktd_head[j] = NULL; } return TRUE; } static int DEBUG_ParseTypedefStab(char * ptr, const char * typename) { int arrmax; int arrmin; char * c; struct datatype * curr_type; struct datatype * datatype; struct datatype * curr_types[MAX_TD_NESTING]; char element_name[1024]; int ntypes = 0; int offset; const char * orig_typename; int rtn = FALSE; int size; char * tc; char * tc2; int typenum; orig_typename = typename; if( DEBUG_HandlePreviousTypedef(typename, ptr) == TRUE ) { return TRUE; } /* * Go from back to front. First we go through and figure out what * type numbers we need, and register those types. Then we go in * and fill the details. */ for( c = strchr(ptr, '='); c != NULL; c = strchr(c + 1, '=') ) { /* * Back up until we get to a non-numeric character. This is the type * number. */ tc = c - 1; while( *tc >= '0' && *tc <= '9' ) { tc--; } typenum = atol(tc + 1); if( num_stab_types <= typenum ) { num_stab_types = typenum + 32; stab_types = (struct datatype **) xrealloc(stab_types, num_stab_types * sizeof(struct datatype *)); if( stab_types == NULL ) { goto leave; } } if( ntypes >= MAX_TD_NESTING ) { /* * If this ever happens, just bump the counter. */ fprintf(stderr, "Typedef nesting overflow\n"); return FALSE; } switch(c[1]) { case '*': stab_types[typenum] = DEBUG_NewDataType(POINTER, NULL); curr_types[ntypes++] = stab_types[typenum]; break; case 's': case 'u': stab_types[typenum] = DEBUG_NewDataType(STRUCT, typename); curr_types[ntypes++] = stab_types[typenum]; break; case 'a': stab_types[typenum] = DEBUG_NewDataType(ARRAY, NULL); curr_types[ntypes++] = stab_types[typenum]; break; case '1': case 'r': stab_types[typenum] = DEBUG_NewDataType(BASIC, typename); curr_types[ntypes++] = stab_types[typenum]; break; case 'x': stab_strcpy(element_name, c + 3); stab_types[typenum] = DEBUG_NewDataType(STRUCT, element_name); curr_types[ntypes++] = stab_types[typenum]; break; case 'e': stab_types[typenum] = DEBUG_NewDataType(ENUM, NULL); curr_types[ntypes++] = stab_types[typenum]; break; case 'f': stab_types[typenum] = DEBUG_NewDataType(FUNC, NULL); curr_types[ntypes++] = stab_types[typenum]; break; default: fprintf(stderr, "Unknown type.\n"); } typename = NULL; } /* * Now register the type so that if we encounter it again, we will know * what to do. */ DEBUG_RegisterTypedef(orig_typename, curr_types, ntypes); /* * OK, now take a second sweep through. Now we will be digging * out the definitions of the various components, and storing * them in the skeletons that we have already allocated. We take * a right-to left search as this is much easier to parse. */ for( c = strrchr(ptr, '='); c != NULL; c = strrchr(ptr, '=') ) { /* * Back up until we get to a non-numeric character. This is the type * number. */ tc = c - 1; while( *tc >= '0' && *tc <= '9' ) { tc--; } typenum = atol(tc + 1); curr_type = stab_types[typenum]; switch(c[1]) { case 'x': tc = c + 3; while( *tc != ':' ) { tc ++; } tc++; if( *tc == '\0' ) { *c = '\0'; } else { strcpy(c, tc); } break; case '*': case 'f': tc = c + 2; datatype = stab_types[strtol(tc, &tc, 10)]; DEBUG_SetPointerType(curr_type, datatype); if( *tc == '\0' ) { *c = '\0'; } else { strcpy(c, tc); } break; case '1': case 'r': /* * We have already handled these above. */ *c = '\0'; break; case 'a': tc = c + 5; arrmin = strtol(tc, &tc, 10); tc++; arrmax = strtol(tc, &tc, 10); tc++; datatype = stab_types[strtol(tc, &tc, 10)]; if( *tc == '\0' ) { *c = '\0'; } else { strcpy(c, tc); } DEBUG_SetArrayParams(curr_type, arrmin, arrmax, datatype); break; case 's': case 'u': tc = c + 2; if( DEBUG_SetStructSize(curr_type, strtol(tc, &tc, 10)) == FALSE ) { /* * We have already filled out this structure. Nothing to do, * so just skip forward to the end of the definition. */ while( tc[0] != ';' && tc[1] != ';' ) { tc++; } tc += 2; if( *tc == '\0' ) { *c = '\0'; } else { strcpy(c, tc + 1); } continue; } /* * Now parse the individual elements of the structure/union. */ while(*tc != ';') { tc2 = element_name; while(*tc != ':') { *tc2++ = *tc++; } tc++; *tc2++ = '\0'; datatype = stab_types[strtol(tc, &tc, 10)]; tc++; offset = strtol(tc, &tc, 10); tc++; size = strtol(tc, &tc, 10); tc++; DEBUG_AddStructElement(curr_type, element_name, datatype, offset, size); } if( *tc == '\0' ) { *c = '\0'; } else { strcpy(c, tc + 1); } break; case 'e': tc = c + 2; /* * Now parse the individual elements of the structure/union. */ while(*tc != ';') { tc2 = element_name; while(*tc != ':') { *tc2++ = *tc++; } tc++; *tc2++ = '\0'; offset = strtol(tc, &tc, 10); tc++; DEBUG_AddStructElement(curr_type, element_name, NULL, offset, 0); } if( *tc == '\0' ) { *c = '\0'; } else { strcpy(c, tc + 1); } break; default: fprintf(stderr, "Unknown type.\n"); break; } } rtn = TRUE; leave: return rtn; } static struct datatype * DEBUG_ParseStabType(const char * stab) { char * c; int typenum; /* * Look through the stab definition, and figure out what datatype * this represents. If we have something we know about, assign the * type. */ c = strchr(stab, ':'); if( c == NULL ) { return NULL; } c++; /* * The next character says more about the type (i.e. data, function, etc) * of symbol. Skip it. */ c++; typenum = atol(c); if( typenum < num_stab_types && stab_types[typenum] != NULL ) { return stab_types[typenum]; } return NULL; } static int DEBUG_ParseStabs(char * addr, unsigned int load_offset, unsigned int staboff, int stablen, unsigned int strtaboff, int strtablen) { struct name_hash * curr_func = NULL; struct wine_locals * curr_loc = NULL; struct name_hash * curr_sym = NULL; char currpath[PATH_MAX]; int i; int ignore = FALSE; int last_nso = -1; int len; DBG_ADDR new_addr; int nstab; char * ptr; char * stabbuff; int stabbufflen; struct stab_nlist * stab_ptr; char * strs; int strtabinc; char * subpath = NULL; char symname[4096]; nstab = stablen / sizeof(struct stab_nlist); stab_ptr = (struct stab_nlist *) (addr + staboff); strs = (char *) (addr + strtaboff); memset(currpath, 0, sizeof(currpath)); /* * Allocate a buffer into which we can build stab strings for cases * where the stab is continued over multiple lines. */ stabbufflen = 65536; stabbuff = (char *) xmalloc(stabbufflen); if( stabbuff == NULL ) { goto leave; } strtabinc = 0; stabbuff[0] = '\0'; for(i=0; i < nstab; i++, stab_ptr++ ) { ptr = strs + (unsigned int) stab_ptr->n_un.n_name; if( ptr[strlen(ptr) - 1] == '\\' ) { /* * Indicates continuation. Append this to the buffer, and go onto the * next record. Repeat the process until we find a stab without the * '/' character, as this indicates we have the whole thing. */ len = strlen(ptr); if( strlen(stabbuff) + len > stabbufflen ) { stabbufflen += 65536; stabbuff = (char *) xrealloc(stabbuff, stabbufflen); if( stabbuff == NULL ) { goto leave; } } strncat(stabbuff, ptr, len - 1); continue; } else if( stabbuff[0] != '\0' ) { strcat( stabbuff, ptr); ptr = stabbuff; } if( strchr(ptr, '=') != NULL ) { /* * The stabs aren't in writable memory, so copy it over so we are * sure we can scribble on it. */ if( ptr != stabbuff ) { strcpy(stabbuff, ptr); ptr = stabbuff; } stab_strcpy(symname, ptr); DEBUG_ParseTypedefStab(ptr, symname); } switch(stab_ptr->n_type) { case N_GSYM: /* * These are useless with ELF. They have no value, and you have to * read the normal symbol table to get the address. Thus we * ignore them, and when we process the normal symbol table * we should do the right thing. * * With a.out, they actually do make some amount of sense. */ new_addr.seg = 0; new_addr.type = DEBUG_ParseStabType(ptr); new_addr.off = load_offset + stab_ptr->n_value; stab_strcpy(symname, ptr); #ifdef __ELF__ curr_sym = DEBUG_AddSymbol( symname, &new_addr, currpath, SYM_WINE | SYM_DATA | SYM_INVALID); #else curr_sym = DEBUG_AddSymbol( symname, &new_addr, currpath, SYM_WINE | SYM_DATA ); #endif break; case N_RBRAC: case N_LBRAC: /* * We need to keep track of these so we get symbol scoping * right for local variables. For now, we just ignore them. * The hooks are already there for dealing with this however, * so all we need to do is to keep count of the nesting level, * and find the RBRAC for each matching LBRAC. */ break; case N_LCSYM: case N_STSYM: /* * These are static symbols and BSS symbols. */ new_addr.seg = 0; new_addr.type = DEBUG_ParseStabType(ptr); new_addr.off = load_offset + stab_ptr->n_value; stab_strcpy(symname, ptr); curr_sym = DEBUG_AddSymbol( symname, &new_addr, currpath, SYM_WINE | SYM_DATA ); break; case N_PSYM: /* * These are function parameters. */ if( (curr_func != NULL) && (stab_ptr->n_value != 0) ) { stab_strcpy(symname, ptr); curr_loc = DEBUG_AddLocal(curr_func, 0, stab_ptr->n_value, 0, 0, symname); DEBUG_SetLocalSymbolType( curr_loc, DEBUG_ParseStabType(ptr)); } break; case N_RSYM: if( curr_func != NULL ) { stab_strcpy(symname, ptr); curr_loc = DEBUG_AddLocal(curr_func, stab_ptr->n_value, 0, 0, 0, symname); DEBUG_SetLocalSymbolType( curr_loc, DEBUG_ParseStabType(ptr)); } break; case N_LSYM: if( (curr_func != NULL) && (stab_ptr->n_value != 0) ) { stab_strcpy(symname, ptr); DEBUG_AddLocal(curr_func, 0, stab_ptr->n_value, 0, 0, symname); } else if (curr_func == NULL) { stab_strcpy(symname, ptr); } break; case N_SLINE: /* * This is a line number. These are always relative to the start * of the function (N_FUN), and this makes the lookup easier. */ if( curr_func != NULL ) { #ifdef __ELF__ DEBUG_AddLineNumber(curr_func, stab_ptr->n_desc, stab_ptr->n_value); #else #if 0 /* * This isn't right. The order of the stabs is different under * a.out, and as a result we would end up attaching the line * number to the wrong function. */ DEBUG_AddLineNumber(curr_func, stab_ptr->n_desc, stab_ptr->n_value - curr_func->addr.off); #endif #endif } break; case N_FUN: /* * First, clean up the previous function we were working on. */ DEBUG_Normalize(curr_func); /* * For now, just declare the various functions. Later * on, we will add the line number information and the * local symbols. */ if( !ignore ) { new_addr.seg = 0; new_addr.type = DEBUG_ParseStabType(ptr); new_addr.off = load_offset + stab_ptr->n_value; /* * Copy the string to a temp buffer so we * can kill everything after the ':'. We do * it this way because otherwise we end up dirtying * all of the pages related to the stabs, and that * sucks up swap space like crazy. */ stab_strcpy(symname, ptr); curr_func = DEBUG_AddSymbol( symname, &new_addr, currpath, SYM_WINE | SYM_FUNC); } else { /* * Don't add line number information for this function * any more. */ curr_func = NULL; } break; case N_SO: /* * This indicates a new source file. Append the records * together, to build the correct path name. */ #ifndef __ELF__ /* * With a.out, there is no NULL string N_SO entry at the end of * the file. Thus when we find non-consecutive entries, * we consider that a new file is started. */ if( last_nso < i-1 ) { currpath[0] = '\0'; DEBUG_Normalize(curr_func); curr_func = NULL; } #endif if( *ptr == '\0' ) { /* * Nuke old path. */ currpath[0] = '\0'; DEBUG_Normalize(curr_func); curr_func = NULL; /* * The datatypes that we would need to use are reset when * we start a new file. */ memset(stab_types, 0, num_stab_types * sizeof(stab_types)); } else { if (*ptr != '/') strcat(currpath, ptr); else strcpy(currpath, ptr); subpath = ptr; } last_nso = i; break; case N_SOL: /* * This indicates we are including stuff from an include file. * If this is the main source, enable the debug stuff, otherwise * ignore it. */ if( subpath == NULL || strcmp(ptr, subpath) == 0 ) { ignore = FALSE; } else { ignore = TRUE; DEBUG_Normalize(curr_func); curr_func = NULL; } break; case N_UNDF: strs += strtabinc; strtabinc = stab_ptr->n_value; DEBUG_Normalize(curr_func); curr_func = NULL; break; case N_OPT: /* * Ignore this. We don't care what it points to. */ break; case N_BINCL: case N_EINCL: case N_MAIN: /* * Always ignore these. GCC doesn't even generate them. */ break; default: break; } stabbuff[0] = '\0'; #if 0 fprintf(stderr, "%d %x %s\n", stab_ptr->n_type, (unsigned int) stab_ptr->n_value, strs + (unsigned int) stab_ptr->n_un.n_name); #endif } leave: if( stab_types != NULL ) { free(stab_types); stab_types = NULL; num_stab_types = 0; } DEBUG_FreeRegisteredTypedefs(); return TRUE; } #ifdef __ELF__ /* * Walk through the entire symbol table and add any symbols we find there. * This can be used in cases where we have stripped ELF shared libraries, * or it can be used in cases where we have data symbols for which the address * isn't encoded in the stabs. * * This is all really quite easy, since we don't have to worry about line * numbers or local data variables. */ static int DEBUG_ProcessElfSymtab(char * addr, unsigned int load_offset, Elf32_Shdr * symtab, Elf32_Shdr * strtab) { char * curfile = NULL; struct name_hash * curr_sym = NULL; int flags; int i; DBG_ADDR new_addr; int nsym; char * strp; char * symname; Elf32_Sym * symp; symp = (Elf32_Sym *) (addr + symtab->sh_offset); nsym = symtab->sh_size / sizeof(*symp); strp = (char *) (addr + strtab->sh_offset); for(i=0; i < nsym; i++, symp++) { /* * Ignore certain types of entries which really aren't of that much * interest. */ if( ELF32_ST_TYPE(symp->st_info) == STT_SECTION ) { continue; } symname = strp + symp->st_name; /* * Save the name of the current file, so we have a way of tracking * static functions/data. */ if( ELF32_ST_TYPE(symp->st_info) == STT_FILE ) { curfile = symname; continue; } /* * See if we already have something for this symbol. * If so, ignore this entry, because it would have come from the * stabs or from a previous symbol. If the value is different, * we will have to keep the darned thing, because there can be * multiple local symbols by the same name. */ if( (DEBUG_GetSymbolValue(symname, -1, &new_addr, FALSE ) == TRUE) && (new_addr.off == (load_offset + symp->st_value)) ) { continue; } new_addr.seg = 0; new_addr.type = NULL; new_addr.off = load_offset + symp->st_value; flags = SYM_WINE | (ELF32_ST_BIND(symp->st_info) == STT_FUNC ? SYM_FUNC : SYM_DATA); if( ELF32_ST_BIND(symp->st_info) == STB_GLOBAL ) { curr_sym = DEBUG_AddSymbol( symname, &new_addr, NULL, flags ); } else { curr_sym = DEBUG_AddSymbol( symname, &new_addr, curfile, flags ); } /* * Record the size of the symbol. This can come in handy in * some cases. Not really used yet, however. */ if( symp->st_size != 0 ) { DEBUG_SetSymbolSize(curr_sym, symp->st_size); } } return TRUE; } static int DEBUG_ProcessElfObject(char * filename, unsigned int load_offset) { int rtn = FALSE; struct stat statbuf; int fd = -1; int status; char * addr = (char *) 0xffffffff; Elf32_Ehdr * ehptr; Elf32_Shdr * spnt; char * shstrtab; int nsect; int i; int stabsect; int stabstrsect; /* * Make sure we can stat and open this file. */ if( filename == NULL ) { goto leave; } status = stat(filename, &statbuf); if( status == -1 ) { char *s,*t,*fn,*paths; if (strchr(filename,'/')) goto leave; paths = xstrdup(getenv("PATH")); s = paths; while (s && *s) { t = strchr(s,':'); if (t) *t='\0'; fn = (char*)xmalloc(strlen(filename)+1+strlen(s)+1); strcpy(fn,s); strcat(fn,"/"); strcat(fn,filename); if ((rtn = DEBUG_ProcessElfObject(fn,load_offset))) { free(fn); free(paths); goto leave; } free(fn); if (t) s = t+1; } if (!s || !*s) fprintf(stderr," %s not found",filename); free(paths); goto leave; } /* * Now open the file, so that we can mmap() it. */ fd = open(filename, O_RDONLY); if( fd == -1 ) { goto leave; } /* * Now mmap() the file. */ addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if( addr == (char *) 0xffffffff ) { goto leave; } /* * Give a nice status message here... * Well not, just print the name. */ fprintf(stderr, " %s", filename); /* * Next, we need to find a few of the internal ELF headers within * this thing. We need the main executable header, and the section * table. */ ehptr = (Elf32_Ehdr *) addr; if( load_offset == NULL ) { DEBUG_RegisterELFDebugInfo(ehptr->e_entry, statbuf.st_size, filename); } else { DEBUG_RegisterELFDebugInfo(load_offset, statbuf.st_size, filename); } spnt = (Elf32_Shdr *) (addr + ehptr->e_shoff); nsect = ehptr->e_shnum; shstrtab = (addr + spnt[ehptr->e_shstrndx].sh_offset); stabsect = stabstrsect = -1; for(i=0; i < nsect; i++) { if( strcmp(shstrtab + spnt[i].sh_name, ".stab") == 0 ) { stabsect = i; } if( strcmp(shstrtab + spnt[i].sh_name, ".stabstr") == 0 ) { stabstrsect = i; } } if( stabsect == -1 || stabstrsect == -1 ) { goto leave; } /* * OK, now just parse all of the stabs. */ rtn = DEBUG_ParseStabs(addr, load_offset, spnt[stabsect].sh_offset, spnt[stabsect].sh_size, spnt[stabstrsect].sh_offset, spnt[stabstrsect].sh_size); if( rtn != TRUE ) { goto leave; } for(i=0; i < nsect; i++) { if( (strcmp(shstrtab + spnt[i].sh_name, ".symtab") == 0) && (spnt[i].sh_type == SHT_SYMTAB) ) { DEBUG_ProcessElfSymtab(addr, load_offset, spnt + i, spnt + spnt[i].sh_link); } if( (strcmp(shstrtab + spnt[i].sh_name, ".dynsym") == 0) && (spnt[i].sh_type == SHT_DYNSYM) ) { DEBUG_ProcessElfSymtab(addr, load_offset, spnt + i, spnt + spnt[i].sh_link); } } leave: if( addr != (char *) 0xffffffff ) { munmap(addr, statbuf.st_size); } if( fd != -1 ) { close(fd); } return (rtn); } int DEBUG_ReadExecutableDbgInfo(void) { Elf32_Ehdr * ehdr; char * exe_name; Elf32_Dyn * dynpnt; struct r_debug * dbg_hdr; struct link_map * lpnt = NULL; extern Elf32_Dyn _DYNAMIC[]; int rtn = FALSE; exe_name = DEBUG_argv0; /* * Make sure we can stat and open this file. */ if( exe_name == NULL ) { goto leave; } DEBUG_ProcessElfObject(exe_name, 0); /* * Finally walk the tables that the dynamic loader maintains to find all * of the other shared libraries which might be loaded. Perform the * same step for all of these. */ dynpnt = _DYNAMIC; if( dynpnt == NULL ) { goto leave; } /* * Now walk the dynamic section (of the executable, looking for a DT_DEBUG * entry. */ for(; dynpnt->d_tag != DT_NULL; dynpnt++) { if( dynpnt->d_tag == DT_DEBUG ) { break; } } if( (dynpnt->d_tag != DT_DEBUG) || (dynpnt->d_un.d_ptr == NULL) ) { goto leave; } /* * OK, now dig into the actual tables themselves. */ dbg_hdr = (struct r_debug *) dynpnt->d_un.d_ptr; lpnt = dbg_hdr->r_map; /* * Now walk the linked list. In all known ELF implementations, * the dynamic loader maintains this linked list for us. In some * cases the first entry doesn't appear with a name, in other cases it * does. */ for(; lpnt; lpnt = lpnt->l_next ) { /* * We already got the stuff for the executable using the * argv[0] entry above. Here we only need to concentrate on any * shared libraries which may be loaded. */ ehdr = (Elf32_Ehdr *) lpnt->l_addr; if( (lpnt->l_addr == NULL) || (ehdr->e_type != ET_DYN) ) { continue; } if( lpnt->l_name != NULL ) { DEBUG_ProcessElfObject(lpnt->l_name, lpnt->l_addr); } } rtn = TRUE; leave: return (rtn); } #else /* !__ELF__ */ #ifdef linux /* * a.out linux. */ int DEBUG_ReadExecutableDbgInfo(void) { char * addr = (char *) 0xffffffff; char * exe_name; struct exec * ahdr; int fd = -1; int rtn = FALSE; unsigned int staboff; struct stat statbuf; int status; unsigned int stroff; exe_name = DEBUG_argv0; /* * Make sure we can stat and open this file. */ if( exe_name == NULL ) { goto leave; } status = stat(exe_name, &statbuf); if( status == -1 ) { goto leave; } /* * Now open the file, so that we can mmap() it. */ fd = open(exe_name, O_RDONLY); if( fd == -1 ) { goto leave; } /* * Now mmap() the file. */ addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if( addr == (char *) 0xffffffff ) { goto leave; } ahdr = (struct exec *) addr; staboff = N_SYMOFF(*ahdr); stroff = N_STROFF(*ahdr); rtn = DEBUG_ParseStabs(addr, 0, staboff, ahdr->a_syms, stroff, statbuf.st_size - stroff); /* * Give a nice status message here... */ fprintf(stderr, " %s", exe_name); rtn = TRUE; leave: if( addr != (char *) 0xffffffff ) { munmap(addr, statbuf.st_size); } if( fd != -1 ) { close(fd); } return (rtn); } #else /* * Non-linux, non-ELF platforms. */ int DEBUG_ReadExecutableDbgInfo(void) { return FALSE; } #endif #endif /* __ELF__ */