/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ /* ** 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. */ /* Modified by Charles Sandmann 1995 for DJGPP V2 (bug fixes) incorporate changes by Morten Welinder, terra@diku.dk */ #include #include #include #include #include #include #include #include #include #include #include #include int undefined_symbol=0; int syms_printwhy=0; #define Ofs(n) ((int)&(((TSS *)0)->n)) struct { const char *name; int size; int ofs; } regs[] = { {"eip", 4, Ofs(tss_eip)}, {"eflags", 4, Ofs(tss_eflags)}, {"eax", 4, Ofs(tss_eax)}, {"ebx", 4, Ofs(tss_ebx)}, {"ecx", 4, Ofs(tss_ecx)}, {"edx", 4, Ofs(tss_edx)}, {"esp", 4, Ofs(tss_esp)}, {"ebp", 4, Ofs(tss_ebp)}, {"esi", 4, Ofs(tss_esi)}, {"edi", 4, Ofs(tss_edi)}, {"ax", 2, Ofs(tss_eax)}, {"bx", 2, Ofs(tss_ebx)}, {"cx", 2, Ofs(tss_ecx)}, {"dx", 2, Ofs(tss_edx)}, {"ah", 1, Ofs(tss_eax)+1}, {"bh", 1, Ofs(tss_ebx)+1}, {"ch", 1, Ofs(tss_ecx)+1}, {"dh", 1, Ofs(tss_edx)+1}, {"al", 1, Ofs(tss_eax)}, {"bl", 1, Ofs(tss_ebx)}, {"cl", 1, Ofs(tss_ecx)}, {"dl", 1, Ofs(tss_edx)}, {0, 0, 0} }; /* From the file */ typedef struct SYM_ENTRY { unsigned long string_off; unsigned char type; unsigned char other; unsigned short desc; unsigned long 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; unsigned long first_address; unsigned long last_address; LINENO *lines; int num_lines; } FileNode; static FileNode *files; static int num_files; typedef struct SymNode { char *name; unsigned long 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) { const SymNode *sa = (const SymNode *)a; const SymNode *sb = (const SymNode *)b; return strcmp(sa->name, sb->name); } static int syms_sort_bv(const void *a, const void *b) { const SymNode *sa = (const SymNode *)a; const SymNode *sb = (const SymNode *)b; return sa->address - sb->address; } static char *symndup(char *s, int len) { char *rv; if(!(rv = malloc(len+1))) return (char *)NULL; memcpy(rv,s,len); rv[len] = 0; 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 process_coff(FILE *fd, long ofs) { int i, f, s, f_pending; LINENO *l = NULL; /* CWS note: uninitialized? */ int l_pending; unsigned long strsize; char *name; int i2_max; fseek(fd, ofs, 0); fread(&f_fh, 1, FILHSZ, fd); fread(&f_ah, 1, AOUTSZ, fd); f_sh = (SCNHDR *)malloc(f_fh.f_nscns * SCNHSZ); f_types = (char *)malloc(f_fh.f_nscns); f_lnno = (LINENO **)malloc(f_fh.f_nscns * sizeof(LINENO *)); fread(f_sh, f_fh.f_nscns, SCNHSZ, fd); for (i=0; i= f_sh[scn].s_lnnoptr) { size_t l_idx = (f_aux[i+1].x_sym.x_fcnary.x_fcn.x_lnnoptr - f_sh[scn].s_lnnoptr) / LINESZ; /* No line number info can be at offset larger than 0xffff from f_lnno[scn], because COFF is limited to 64K line-number entries. If they have more line entries than that, they had line number overflow at link time. */ if (l_idx < 0xffffU) { l = f_lnno[scn] + l_idx; l_pending = 1; i2_max = f_sh[scn].s_nlnno - l_idx; l->l_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 && f_aux[i+1].x_sym.x_misc.x_lnsz.x_lnno) { 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; i2 < i2_max && l[i2].l_lnno; i2++) l[i2].l_lnno += lbase; l_pending = 0; } break; } i += f_symtab[i].e_numaux; } } static void process_aout(FILE *fd, long ofs) { GNU_AOUT header; unsigned long string_table_length; int nsyms, i, f, s, l; fseek(fd, ofs, 0); fread(&header, 1, sizeof(header), fd); fseek(fd, ofs + sizeof(header) + header.tsize + header.dsize + header.txrel + header.dtrel, 0); nsyms = header.symsize / sizeof(SYM_ENTRY); f_aoutsyms = (SYM_ENTRY *)malloc(header.symsize); fread(f_aoutsyms, 1, header.symsize, fd); fread(&string_table_length, 1, 4, fd); f_string_table = (char *)malloc(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 = strncmp(name, syms_byname[mid].name+ofs, idx); if (c == 0) { while (mid && strncmp(name, syms_byname[mid-1].name+ofs, idx) == 0) mid--; return mid; } if (c < 0) above = mid; else below = mid; } return -1; } unsigned long syms_name2val(const char *name) { int idx, sign=1, i; unsigned long v; char *cp; undefined_symbol = 0; idx = 0; cp = unconst(name, char *); sscanf(cp, "%s", cp); if (name[0] == 0) return 0; if (name[0] == '-') { sign = -1; name++; } else if (name[0] == '+') { name++; } if (isdigit((unsigned char)name[0])) { if (sign == -1) return -strtoul(name, 0, 0); /* MW change from strtol */ return strtoul(name, 0, 0); } cp = strpbrk(name, "+-"); if (cp) idx = cp-name; else idx = strlen(name); 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(unsigned long 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; } void syms_listwild(char *pattern, void (*handler)(unsigned long addr, char type_c, char *name, char *name2, int lnum)) { int lnum; char *name; int i; for (i=0; i= num_files)) return 0; else return files[no].filename; } unsigned long syms_line2val(char *filename, int lnum) { int f,l; for (f = 0; f < num_files; f++) if (strcmp (filename, files[f].filename) == 0) { for (l = 0; l < files[f].num_lines; l++) if (files[f].lines[l].l_lnno == lnum) return files[f].lines[l].l_addr.l_paddr; return 0; } return 0; }