home *** CD-ROM | disk | FTP | other *** search
- /* 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)
- {
- char c = s[8], *rv;
- s[8] = 0;
- rv = strdup(s);
- s[8] = 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);
- 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);
- 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
-