/* This file is SYMS.C ** ** changed Rainer Schnitker */ /* ** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954 ** ** This file is distributed under the terms listed in the document ** "copying.dj", available from DJ Delorie at the address above. ** A copy of "copying.dj" should accompany this file; if not, a copy ** should be available from where this file was obtained. This file ** may not be distributed without a verbatim copy of "copying.dj". ** ** This file is distributed WITHOUT ANY WARRANTY; without even the implied ** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ #include #include #include #include #include #include #include #include #ifndef __GO32__ #include #else #include #endif typedef unsigned char word8; typedef unsigned short word16; typedef unsigned long word32; typedef short int16; #include "coff.h" #include "syms.h" #include "stab.h" extern int ptrace_get_register(int); int undefined_symbol = 0; struct reg_names { char *name; int size; int ofs; }; struct reg_names regs[] = { { "%eip", 4, EIP }, { "%eflags", 4, EFL }, { "%eax", 4, EAX }, { "%ebx", 4, EBX }, { "%ecx", 4, ECX }, { "%edx", 4, EDX }, { "%esp", 4, ESP }, { "%ebp", 4, EBP }, { "%esi", 4, ESI }, { "%edi", 4, EDI }, { "%ax", 2, EAX }, { "%bx", 2, EBX }, { "%cx", 2, ECX }, { "%dx", 2, EDX }, { "%ah", 0, EAX }, { "%bh", 0, EBX }, { "%ch", 0, ECX }, { "%dh", 0, EDX }, { "%al", 1, EAX }, { "%bl", 1, EBX }, { "%cl", 1, ECX }, { "%dl", 1, EDX }, { 0, 0, 0 } }; typedef struct SYM_ENTRY { word32 string_off; word8 type; word8 other; word16 desc; word32 val; } SYM_ENTRY; static FILHDR f_fh; static AOUTHDR f_ah; static SCNHDR *f_sh; static SYMENT *f_symtab; static SYM_ENTRY *f_aoutsyms; static AUXENT *f_aux; static LINENO **f_lnno; static char *f_string_table; static char *f_types; /* built internally */ typedef struct { char *filename; word32 first_address; word32 last_address; LINENO *lines; int num_lines; } FileNode; static FileNode *files; static int num_files; typedef struct SymNode { char *name; word32 address; char type_c; } SymNode; static SymNode *syms; static SymNode *syms_byname; static int num_syms; static int syms_sort_bn(const void *a, const void *b) { SymNode *sa = (SymNode *)a; SymNode *sb = (SymNode *)b; return strcmp(sa->name, sb->name); } static int syms_sort_bv(const void *a, const void *b) { SymNode *sa = (SymNode *)a; SymNode *sb = (SymNode *)b; return sa->address - sb->address; } static char *symndup(char *s, int len) { char c = s[len], *rv; s[len] = 0; rv = strdup(s); s[len] = c; return rv; } static int valid_symbol(int i) { char *sn; if (f_symtab[i].e.e.e_zeroes) sn = f_symtab[i].e.e_name; else sn = f_string_table + f_symtab[i].e.e.e_offset; if (sn[0] != '_') return 0; if (strncmp(sn, "___gnu_compiled", 15) == 0) return 0; if (strcmp(sn, "__DYNAMIC") == 0) return 0; return 1; } static void * xmalloc(int size) { void *p; if ((p = malloc(size)) == NULL) { printf("malloc %d failed", size); exit(1); } memset (p, 0, size); return p; } static void process_coff(FILE *fd, long ofs) { int i, f, s, f_pending; LINENO *l; int l_pending; word32 strsize; char *name; fseek(fd, ofs, 0); fread(&f_fh, 1, FILHSZ, fd); fread(&f_ah, 1, AOUTSZ, fd); printf("COFF HEADER\n"); printf("text = %08lX\n", f_ah.tsize); printf("data = %08lX\n", f_ah.dsize); printf("bss = %08lX\n", f_ah.bsize); printf("entry = %08lX\n", f_ah.entry); f_sh = (SCNHDR *)xmalloc(f_fh.f_nscns * SCNHSZ); f_types = (char *)xmalloc(f_fh.f_nscns); f_lnno = (LINENO **)xmalloc(f_fh.f_nscns * sizeof(LINENO *)); fread(f_sh, f_fh.f_nscns, SCNHSZ, fd); for (i=0; il_addr.l_paddr = f_symtab[i].e_value; } if (!valid_symbol(i)) break; syms[s].address = f_symtab[i].e_value; if (f_symtab[i].e.e.e_zeroes) syms[s].name = symndup(f_symtab[i].e.e_name, 8); else syms[s].name = f_string_table + f_symtab[i].e.e.e_offset; switch (f_symtab[i].e_scnum) { case 1 ... 10: syms[s].type_c = f_types[f_symtab[i].e_scnum-1]; break; case N_UNDEF: syms[s].type_c = 'U'; break; case N_ABS: syms[s].type_c = 'A'; break; case N_DEBUG: syms[s].type_c = 'D'; break; } if (f_symtab[i].e_sclass == C_STAT) syms[s].type_c += 'a' - 'A'; s++; break; case C_FCN: if (f_pending && files[f-1].lines == 0) { files[f-1].lines = l; } if (l_pending) { int lbase = f_aux[i+1].x_sym.x_misc.x_lnsz.x_lnno - 1; int i2; l->l_lnno = lbase; l++; for (i2=0; l[i2].l_lnno; i2++) l[i2].l_lnno += lbase; l_pending = 0; } break; } i += f_symtab[i].e_numaux; } } #define _N_HDROFF(x) _n_hdroff #define N_TXTOFF(x) ( _N_HDROFF((x)) + sizeof (GNU_AOUT)) #define N_DATOFF(x) (N_TXTOFF(x) + (x).tsize) #define N_TRELOFF(x) (N_DATOFF(x) + (x).dsize) #define N_DRELOFF(x) (N_TRELOFF(x) + (x).txrel) #define N_SYMOFF(x) (N_DRELOFF(x) + (x).dtrel) #define N_STROFF(x) (N_SYMOFF(x) + (x).symsize) static void process_aout(FILE *fd, long ofs) { GNU_AOUT header; word32 string_table_length; DWORD _n_hdroff; int nsyms, i, f, s, l; fseek(fd, ofs, 0); fread(&header, 1, sizeof(header), fd); if (header.entry == 0x10000) _n_hdroff = (1024 - sizeof(GNU_AOUT)); else if (header.entry == 0x1020) _n_hdroff = 0; else { printf("Not supported a.out file type\n"); return; } printf("GNUAOUT HEADER\n"); printf("text = %08lX\n", header.tsize); printf("data = %08lX\n", header.dsize); printf("bss = %08lX\n", header.bsize); printf("entry = %08lX\n", header.entry); printf("syms = %08lX\n", header.symsize); fseek(fd, ofs + N_SYMOFF(header),0); nsyms = header.symsize / sizeof(SYM_ENTRY); f_aoutsyms = (SYM_ENTRY *)xmalloc(header.symsize); fread(f_aoutsyms, 1, header.symsize, fd); fread(&string_table_length, 1, 4, fd); f_string_table = (char *)xmalloc(string_table_length); fread(f_string_table+4, 1, string_table_length-4, fd); f_string_table[0] = 0; num_files = num_syms = 0; for (i=0; i 1) { int mid = (above + below) / 2; int c = 0; if (ofs) c = '_' - syms_byname[mid].name[0]; if (c == 0) c = strcmp(name, syms_byname[mid].name+ofs); if (c == 0) { name[idx] = ch; return mid; } if (c < 0) above = mid; else below = mid; } name[idx] = ch; return -1; } word32 syms_name2val(char *name) { int idx, sign=1, i; word32 v,pt; char *cp; undefined_symbol = 0; idx = 0; sscanf(name, "%s", name); if (name[0] == 0) return 0; if (name[0] == '-') { sign = -1; name++; } else if (name[0] == '+') { name++; } if (isdigit(name[0])) { if (sign == -1) return -strtol(name, 0, 0); return strtol(name, 0, 0); } cp = strpbrk(name, "+-"); if (cp) idx = cp-name; else idx = strlen(name); if (name[0] == '%') /* register */ { for (i=0; regs[i].name; i++) if (strncmp(name, regs[i].name, idx) == 0) { pt = ptrace_get_register(regs[i].ofs * 4); switch (regs[i].size) { case 0: /* ah */ v = (pt>>8) & 0xFF; break; case 1: /* al */ v = pt & 0xFF; break; case 2: /* ax */ v = pt & 0xFFFF; break; case 4: /* eax */ v = pt; break; } return v + syms_name2val(name+idx); } } for (i=0; i 1) { mid = (above+below)/2; if (syms[mid].address == val) break; if (syms[mid].address > val) above = mid; else below = mid; } if (syms[mid].address > val) { if (mid == 0) goto noname; mid--; /* the last below was it */ } if (mid < 0) goto noname; if (strcmp(syms[mid].name, "_end") == 0) goto noname; if (strcmp(syms[mid].name, "__end") == 0) goto noname; if (strcmp(syms[mid].name, "_etext") == 0) goto noname; if (delta) *delta = val - syms[mid].address; return syms[mid].name; noname: sprintf(noname_buf, "%#lx", val); return noname_buf; } char *syms_val2line(word32 val, int *lineret, int exact) { int f, l; for (f=0; f= files[f].first_address && val <= files[f].last_address && files[f].lines) { for (l=files[f].num_lines-1; l >= 0 && files[f].lines[l].l_addr.l_paddr > val; l--); if ((files[f].lines[l].l_addr.l_paddr != val) && exact) return 0; *lineret = files[f].lines[l].l_lnno; return files[f].filename; } } return 0; } int wild(char *pattern, char *string) { int nlit; while (*pattern) { switch (*pattern) { case '*': pattern++; if (*pattern == 0) return 1; nlit=0; while ((pattern[nlit] != 0) && (pattern[nlit] != '*') && (pattern[nlit] != '?') ) nlit++; while (1) { if (strncmp(string, pattern, nlit) == 0) break; string++; if (*string == 0) return 0; } break; case '?': if (*string == 0) return 0; pattern++; string++; break; default: if (*pattern != *string) return 0; pattern++; string++; break; } } if (*string) return 0; return 1; } void syms_listwild(char *pattern) { int linecnt = 0; int lnum; char *name; int i, key; for (i=0; i 20) { printf("--- More ---"); fflush(stdout); key = getchar(); printf("\r \r"); switch (key) { case ' ': linecnt = 0; break; case 13: linecnt--; break; case 'q': case 27: return; } } printf("0x%08lx %c %s", syms_byname[i].address, syms_byname[i].type_c, syms_byname[i].name); name = syms_val2line(syms_byname[i].address, &lnum, 0); if (name) printf(", line %d of %s", lnum, name); putchar('\n'); } }