This is syms.c in view mode; [Download] [Up]
/* This is file SYMS.C */ /* ** 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 <stdio.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <dos.h> #include <io.h> #include "ed.h" #include "coff.h" #include "syms.h" #include "stab.h" #define DO_SYMS 1 int undefined_symbol=0; #define Ofs(n) ((int)&(((TSS *)0)->n)) struct { 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 }; #if !DO_SYMS void syms_init(char *fname) {} void syms_list(int byval) {} void syms_listwild(char *pattern) {} word32 syms_name2val(char *name) { if (isdigit(name[0])) { int v; if (strncmp(name, "0x", 2) == 0) sscanf(name+2, "%x", &v); else sscanf(name, "%d", &v); undefined_symbol = 0; return v; } else { undefined_symbol = 1; return 0; } } char *syms_val2name(word32 val, word32 *delta) { static char noname_buf[20]; sprintf(noname_buf, "%#lx", val); *delta = 0; return noname_buf; } char *syms_val2line(word32 val, int *lineret, int exact) { return 0; } #else /* From the file */ 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 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); 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_fh.f_nscns; i++) { if (f_sh[i].s_flags & STYP_TEXT) f_types[i] = 'T'; if (f_sh[i].s_flags & STYP_DATA) f_types[i] = 'D'; if (f_sh[i].s_flags & STYP_BSS) f_types[i] = 'B'; if (f_sh[i].s_nlnno) { fseek(fd, ofs + f_sh[i].s_lnnoptr, 0L); f_lnno[i] = (LINENO *)malloc(f_sh[i].s_nlnno * LINESZ); fread(f_lnno[i], LINESZ, f_sh[i].s_nlnno, fd); } else f_lnno[i] = 0; } fseek(fd, ofs + f_fh.f_symptr + f_fh.f_nsyms * SYMESZ, 0); fread(&strsize, 1, 4, fd); f_string_table = (char *)malloc(strsize); fread(f_string_table+4, 1, strsize-4, fd); f_string_table[0] = 0; fseek(fd, ofs+f_fh.f_symptr, 0); f_symtab = (SYMENT *)malloc(f_fh.f_nsyms * SYMESZ); fread(f_symtab, SYMESZ, f_fh.f_nsyms, fd); f_aux = (AUXENT *)f_symtab; num_syms = num_files = 0; for (i=0; i<f_fh.f_nsyms; i++) { switch (f_symtab[i].e_sclass) { case C_FILE: num_files++; break; case C_EXT: case C_STAT: if (!valid_symbol(i)) break; num_syms++; break; } i += f_symtab[i].e_numaux; } files = (FileNode *)malloc(num_files * sizeof(FileNode)); syms = (SymNode *)malloc(num_syms * sizeof(SymNode)); f = s = f_pending = l_pending = 0; for (i=0; i<f_fh.f_nsyms; i++) { switch (f_symtab[i].e_sclass) { case C_FILE: if (f_aux[i+1].x_file.x_n.x_zeroes) files[f].filename = symndup(f_aux[i+1].x_file.x_fname, 16); else files[f].filename = f_string_table + f_aux[i+1].x_file.x_n.x_offset; files[f].lines = 0; f_pending = 1; f++; break; case C_EXT: case C_STAT: if (f_symtab[i].e.e.e_zeroes) name = f_symtab[i].e.e_name; else name = f_string_table + f_symtab[i].e.e.e_offset; if (f_pending && strcmp(name, ".text") == 0) { files[f-1].first_address = f_symtab[i].e_value; files[f-1].last_address = f_symtab[i].e_value + f_aux[i+1].x_scn.x_scnlen - 1; files[f-1].num_lines = f_aux[i+1].x_scn.x_nlinno; f_pending = 0; } if (ISFCN(f_symtab[i].e_type)) { int scn = f_symtab[i].e_scnum - 1; l = f_lnno[scn] + ((f_aux[i+1].x_sym.x_fcnary.x_fcn.x_lnnoptr - f_sh[scn].s_lnnoptr)/LINESZ); l_pending = 1; 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) { 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; } } static void process_aout(FILE *fd, long ofs) { GNU_AOUT header; word32 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<nsyms; i++) { char *symn = f_string_table + f_aoutsyms[i].string_off; char *cp; switch (f_aoutsyms[i].type & ~N_EXT) { case N_SO: if (symn[strlen(symn)-1] == '/') break; num_files++; break; case N_TEXT: cp = symn + strlen(symn) - 2; if (strncmp(symn, "___gnu", 6) == 0 || strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ || strcmp(cp, ".o") == 0) break; case N_DATA: case N_ABS: case N_BSS: case N_FN: case N_SETV: case N_SETA: case N_SETT: case N_SETD: case N_SETB: case N_INDR: num_syms ++; break; } } syms = (SymNode *)malloc(num_syms * sizeof(SymNode)); memset(syms, num_syms * sizeof(SymNode), 0); files = (FileNode *)malloc(num_files * sizeof(FileNode)); memset(files, num_files * sizeof(FileNode), 0); f = s = 0; for (i=0; i<nsyms; i++) { char c, *cp; char *symn = f_string_table + f_aoutsyms[i].string_off; switch (f_aoutsyms[i].type & ~N_EXT) { case N_SO: if (symn[strlen(symn)-1] == '/') break; if (f && files[f-1].last_address == 0) files[f-1].last_address = f_aoutsyms[i].val - 1; files[f].filename = symn; files[f].first_address = f_aoutsyms[i].val; f ++; break; case N_SLINE: files[f-1].num_lines++; break; case N_TEXT: cp = symn + strlen(symn) - 2; if (strncmp(symn, "___gnu", 6) == 0 || strcmp(cp, "d.") == 0 /* as in gcc_compiled. */ || strcmp(cp, ".o") == 0) { if (f && files[f-1].last_address == 0) files[f-1].last_address = f_aoutsyms[i].val - 1; break; } c = 't'; goto sym_c; case N_DATA: c = 'd'; goto sym_c; case N_ABS: c = 'a'; goto sym_c; case N_BSS: c = 'b'; goto sym_c; case N_FN: c = 'f'; goto sym_c; case N_SETV: c = 'v'; goto sym_c; case N_SETA: c = 'v'; goto sym_c; case N_SETT: c = 'v'; goto sym_c; case N_SETD: c = 'v'; goto sym_c; case N_SETB: c = 'v'; goto sym_c; case N_INDR: c = 'i'; sym_c: syms[s].name = symn; syms[s].address = f_aoutsyms[i].val; syms[s].type_c = (f_aoutsyms[i].type & N_EXT) ? (c+'A'-'a') : c; s ++; break; } } l = f = 0; for (i=0; i<nsyms; i++) { char c, *cp; char *symn = f_string_table + f_aoutsyms[i].string_off; switch (f_aoutsyms[i].type & ~N_EXT) { case N_SO: if (symn[strlen(symn)-1] == '/') break; files[f].lines = (LINENO *)malloc(files[f].num_lines * sizeof(LINENO)); f++; l = 0; break; case N_SLINE: files[f-1].lines[l].l_addr.l_paddr = f_aoutsyms[i].val; files[f-1].lines[l].l_lnno = f_aoutsyms[i].desc; l ++; break; } } } static void process_file(FILE *fd, long ofs) { short s, exe[2]; fseek(fd, ofs, 0); fread(&s, 1, 2, fd); switch (s) { case 0x5a4d: /* .exe */ fread(exe, 2, 2, fd); ofs += (long)exe[1] * 512L; if (exe[0]) ofs += (long)exe[0] - 512L; process_file(fd, ofs); break; case 0x014c: /* .coff */ process_coff(fd, ofs); break; case 0x010b: /* a.out ZMAGIC */ case 0x0107: /* a.out object */ process_aout(fd, ofs); break; } } void syms_init(char *fname) { FILE *fd = fopen(fname, "rb"); if (fd == 0) { perror(fname); } else { process_file(fd, 0); syms_byname = (SymNode *)malloc(num_syms * sizeof(SymNode)); memcpy(syms_byname, syms, num_syms * sizeof(SymNode)); qsort(syms_byname, num_syms, sizeof(SymNode), syms_sort_bn); qsort(syms, num_syms, sizeof(SymNode), syms_sort_bv); fclose(fd); } } int lookup_sym_byname(char *name, int idx, int ofs) { int below, above; char ch = name[idx]; name[idx] = 0; below = -1; above = num_syms; while (above - below > 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 cval, idx, sign=1, i; word32 v; 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) { switch (regs[i].size) { case 1: v = *(word8 *)((word8 *)(&a_tss) + regs[i].ofs); break; case 2: v = *(word16 *)((word8 *)(&a_tss) + regs[i].ofs); break; case 4: v = *(word32 *)((word8 *)(&a_tss) + regs[i].ofs); break; } return v + syms_name2val(name+idx); } } for (i=0; i<idx; i++) if (name[i] == '#') { int f; int lnum, l; sscanf(name+i+1, "%d", &lnum); for (f=0; f<num_files; f++) { if ((strncmp(name, files[f].filename, i) == 0) && (files[f].filename[i] == 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 + syms_name2val(name+idx); } printf("undefined line number %.*s\n", idx, name); undefined_symbol = 1; return 0; } } printf("Undefined file name %.*s\n", i, name); undefined_symbol = 1; return 0; } i = lookup_sym_byname(name, idx, 0); if (i == -1) i = lookup_sym_byname(name, idx, 1); if (i != -1) return syms_byname[i].address * sign + syms_name2val(name+idx); printf("Undefined symbol %.*s\n", idx, name); undefined_symbol = 1; return 0; } static char noname_buf[11]; char *syms_val2name(word32 val, word32 *delta) { static char buf[1000]; int above, below, mid; if (delta) *delta = 0; if (num_syms <= 0) goto noname; above = num_syms; below = -1; while (above-below > 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<num_files; f++) { if (val >= 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) { int linecnt = 0; int lnum; char *name; int i, key; for (i=0; i<num_syms; i++) if (wild(pattern, syms_byname[i])) { if (++linecnt > 20) { printf("--- More ---"); fflush(stdout); key = getkey(); 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'); } } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.