This is symsaout.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" #define DO_SYMS 0 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 #define SYMADDR 0xa0000000 #define SYMSPACE ((sizeof(TSS) + 1023) & ~1023) /* collect this many symbols in real mode */ static word32 sym_brk=SYMADDR; static word32 sym_page=SYMADDR; static char *sym_ptr; static char *sym_buffer; static int sym_left; word32 salloc(word32 size) { word32 r = sym_brk; size = (size + 3) & ~3; sym_brk += size; return r; } void symwrite(void *ptr,int size) { size = (size + 3) & ~3; if(size <= 0) return; while(sym_left < size) { if(sym_left != 0) { memcpy(sym_ptr,ptr,sym_left); size -= sym_left; ptr = (void *)((char *)ptr + sym_left); } memput(sym_page,sym_buffer,SYMSPACE); sym_page += SYMSPACE; sym_left = SYMSPACE; sym_ptr = sym_buffer; } if(size > 0) { memcpy(sym_ptr,ptr,size); sym_ptr += size; sym_left -= size; } } void symwrite_at(word32 addr,void *ptr,int size) { size = (size + 3) & ~3; if(size <= 0) return; if(addr < sym_page) { word32 written_size = sym_page - addr; if(written_size < size) { memput(addr,ptr,(word16)written_size); addr += written_size; size -= (int)written_size; ptr = (void *)((char *)ptr + (int)written_size); } else { memput(addr,ptr,size); size = 0; } } if(size > 0) { int offset = (int)(addr - sym_page); memcpy(&sym_buffer[offset],ptr,size); } } #define symsput(where,ptr,size) memput(where,ptr,size) #define symsget(where,ptr,size) memget(where,ptr,size) typedef struct SYMTREE { word32 me; word32 nleft, nright, ndown; word32 vleft, vright, vdown; word32 val; word32 type; word32 name_len; } SYMTREE; typedef struct FILENODE { word32 me; word32 next; word32 line_list; word32 first_addr, last_addr; word32 name_len; } FILENODE; typedef struct LINENODE { word32 me; word32 next; word32 num; word32 addr; } LINENODE; static word32 symtree_root=0; static word32 file_list=0; static char tmps[256]; static char tmps2[256]; static symtree_print(word32 s, int byval, int level) { SYMTREE tmp; if (s == 0) return; symsget(s, &tmp, sizeof(tmp)); if (byval) symtree_print(tmp.vleft, byval, level+1); else symtree_print(tmp.nleft, byval, level+1); symsget(tmp.me+sizeof(tmp), tmps, tmp.name_len); printf("0x%08lx 0x%08lx %*s%s\n", tmp.val, tmp.type, level, "", tmps); if (byval) symtree_print(tmp.vdown, byval, level); else symtree_print(tmp.ndown, byval, level); if (byval) symtree_print(tmp.vright, byval, level+1); else symtree_print(tmp.nright, byval, level+1); } void syms_list(v) { symtree_print(symtree_root, v, 0); } typedef struct SYM_ENTRY { word32 string_off; word8 type; word8 other; word16 desc; word32 val; } SYM_ENTRY; void syms_init(char *fname) { GNU_AOUT header; int j, per, oldper=-1; word32 nsyms, i; FILE *fd,*sfd; word32 sfd_base,sfd_pos; SYM_ENTRY sym; char *strings, *cp; word32 string_size; word32 last_dot_o=0; FILENODE filen; LINENODE linen; SYMTREE temp; char symbuf[SYMSPACE]; sym_ptr = sym_buffer = symbuf; sym_left = SYMSPACE; filen.me = 0; linen.me = 0; fd = fopen(fname, "rb"); sfd = fopen(fname, "rb"); fread(&header, sizeof(header), 1, fd); switch((word16)header.info) { case 0x014c: fseek(fd, 0xa8L, 0); fread(&header, sizeof(header), 1, fd); fseek(fd, 0xa8+sizeof(header) + header.tsize + header.dsize, 0); break; case 0x010b: case 0x0107: fseek(fd, sizeof(header)+header.tsize+header.dsize+header.txrel+header.dtrel, 0); break; default: fclose(fd); fclose(sfd); return; } printf("Reading symbols... 0%%"); fflush(stdout); /* reserve space for the symbol tree root pointer */ salloc(sizeof(word32)); symwrite(&symtree_root,sizeof(word32)); nsyms = header.symsize / sizeof(SYM_ENTRY); fseek(sfd, ftell(fd)+header.symsize, 0); sfd_pos = sfd_base = ftell(sfd); for (i=0; i<nsyms; i++) { if (nsyms > 1) per = i*100L/(nsyms-1); else per = 100; if (per != oldper) { printf("\b\b\b\b%3d%%", per); fflush(stdout); oldper = per; } fread(&sym, sizeof(sym),1, fd); if (sym.string_off) { word32 where = sfd_base + sym.string_off; if(where != sfd_pos) fseek(sfd,(sfd_pos = where),0); for(cp = tmps2; (*cp = getc(sfd)) != '\0'; cp++); sfd_pos += (int)(cp - tmps2) + 1; } switch (sym.type) { case N_TEXT: case N_TEXT | N_EXT: cp = tmps2; cp += strlen(cp) - 2; if (strcmp(cp, ".o") == 0) { last_dot_o = sym.val; if (filen.me && (filen.last_addr == 0)) { filen.last_addr = last_dot_o - 1; } break; } if (strncmp(tmps2, "___gnu", 6) == 0) break; if (strcmp(cp, "d.") == 0) /* as in gcc_compiled. */ break; case N_DATA: case N_DATA | N_EXT: case N_ABS: case N_ABS | N_EXT: case N_BSS: case N_BSS | N_EXT: case N_FN: case N_SETV: case N_SETV | N_EXT: case N_SETA: case N_SETA | N_EXT: case N_SETT: case N_SETT | N_EXT: case N_SETD: case N_SETD | N_EXT: case N_SETB: case N_SETB | N_EXT: case N_INDR: case N_INDR | N_EXT: if (sym.string_off) { memset(&temp, 0, sizeof(SYMTREE)); temp.name_len = strlen(tmps2) + 1; temp.me = salloc(sizeof(temp)+temp.name_len); temp.val = sym.val; temp.type = sym.type; temp.nleft = symtree_root; symwrite(&temp, sizeof(temp)); symwrite(tmps2, temp.name_len); symtree_root = temp.me; } break; case N_SO: if(filen.me != 0) { /* update previous file name symbol */ symwrite_at(filen.me,&filen, sizeof(filen)); } memset(&filen, 0, sizeof(FILENODE)); filen.name_len = strlen(tmps2)+1; filen.me = salloc(sizeof(FILENODE)+filen.name_len); filen.next = file_list; file_list = filen.me; filen.first_addr = last_dot_o; symwrite(&filen, sizeof(filen)); symwrite(tmps2, filen.name_len); break; case N_SLINE: memset(&linen, 0, sizeof(linen)); linen.me = salloc(sizeof(LINENODE)); linen.next = filen.line_list; filen.line_list = linen.me; linen.num = sym.desc; linen.addr = sym.val; symwrite(&linen, sizeof(linen)); break; } } fclose(fd); fclose(sfd); printf(" %ld symbol%s read\n", nsyms, nsyms==1 ? "" : "s"); if(filen.me != 0) { /* update the last file name symbol */ symwrite_at(filen.me,&filen, sizeof(filen)); } if(sym_left < SYMSPACE) { /* flush symbol read buffer if necessary */ memput(sym_page,sym_buffer,(SYMSPACE - sym_left)); } if(symtree_root) { /* * Construct symbol tree from the simple linked list built above. * Do it using a 32-bit protected mode code fragment generated * from the code in "sym32.c" using GCC */ static char do_symsort32[] = { # include "sym32.h" 0 }; TSS *old_tss = tss_ptr; printf("Building symbol trees... "); fflush(stdout); tss_ptr = &a_tss; memput(SYMADDR,&symtree_root,sizeof(word32)); /* pass root to 32-bit code */ memcpy(symbuf,&a_tss,sizeof(TSS)); /* save arena TSS */ a_tss.tss_eip = 0xe0000000L + /* set it up */ ((word32)(word16)FP_SEG(do_symsort32) << 4) + (word32)(word16)FP_OFF(do_symsort32); a_tss.tss_esp -= 0x20; go_til_done(); memcpy(&a_tss,symbuf,sizeof(TSS)); /* restore ARENA TSS */ tss_ptr = old_tss; printf("DONE\n"); } } word32 syms_name2val(char *name) { SYMTREE s; 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 *)tss_ptr + regs[i].ofs); break; case 2: v = *(word16 *)((word8 *)tss_ptr + regs[i].ofs); break; case 4: v = *(word32 *)((word8 *)tss_ptr + regs[i].ofs); break; } return v + syms_name2val(name+idx); } } for (i=0; i<idx; i++) if (name[i] == '#') { FILENODE f; LINENODE l; int lnum; sscanf(name+i+1, "%d", &lnum); for (f.me=file_list; f.me; f.me=f.next) { symsget(f.me, &f, sizeof(f)); symsget(f.me+sizeof(f), tmps, f.name_len); if ((strncmp(name, tmps, i) == 0) && (tmps[i] == 0)) { for (l.me=f.line_list; l.me; l.me=l.next) { symsget(l.me, &l, sizeof(l)); if (l.num == lnum) return l.addr + 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; } s.me = symtree_root; while (s.me) { symsget(s.me, &s, sizeof(s)); symsget(s.me+sizeof(s), tmps, s.name_len); cval = strncmp(name, tmps, idx); if ((cval == 0) && tmps[idx]) cval = -1; if (cval == 0) return s.val*sign + syms_name2val(name+idx); else if (cval < 0) s.me = s.nleft; else s.me = s.nright; } s.me = symtree_root; while (s.me) { symsget(s.me, &s, sizeof(s)); symsget(s.me+sizeof(s), tmps, s.name_len); if (tmps[0] == '_') cval = strncmp(name, tmps+1, idx); else cval = '_' - tmps[0]; if ((cval == 0) && tmps[idx+1]) cval = -1; if (cval == 0) return s.val*sign + syms_name2val(name+idx); else if (cval < 0) s.me = s.nleft; else s.me = s.nright; } printf("Undefined symbol %.*s\n", idx, name); undefined_symbol = 1; return 0; } static char noname_buf[11]; char *syms_val2name(word32 val, word32 *delta) { SYMTREE s, lasts; if (delta) *delta = 0; lasts.me = 0; s.me = symtree_root; while (s.me) { symsget(s.me, &s, sizeof(s)); if (s.val <= val) lasts.me = s.me; if (val == s.val) { while (s.vdown) symsget(s.vdown, &s, sizeof(s)); symsget(s.me+sizeof(s), tmps2, s.name_len); return tmps2; } else if (val < s.val) s.me = s.vleft; else s.me = s.vright; } if (lasts.me) { symsget(lasts.me, &lasts, sizeof(lasts)); while (lasts.vdown) symsget(lasts.vdown, &lasts, sizeof(lasts)); symsget(lasts.me+sizeof(lasts), tmps2, lasts.name_len); if (strcmp(tmps2, "_etext") == 0) goto noname; if (strcmp(tmps2, "_end") == 0) goto noname; if (delta) *delta = val - lasts.val; return tmps2; } noname: sprintf(noname_buf, "%#lx", val); return noname_buf; } char *syms_val2line(word32 val, int *lineret, int exact) { FILENODE filen; LINENODE linen, closest; closest.me = 0; for (filen.me = file_list; filen.me; filen.me=filen.next) { symsget(filen.me, &filen, sizeof(filen)); if ((val <= filen.last_addr) && (val >= filen.first_addr)) { for (linen.me=filen.line_list; linen.me; linen.me = linen.next) { symsget(linen.me, &linen, sizeof(linen)); if (val == linen.addr) { *lineret = linen.num; symsget(filen.me+sizeof(filen), tmps2, filen.name_len); return tmps2; } if (val > linen.addr) { if (!closest.me) closest.me = linen.me; else if (closest.addr < linen.addr) closest.me = linen.me; } } if (closest.me && !exact) { symsget(closest.me, &closest, sizeof(closest)); *lineret = closest.num; symsget(filen.me+sizeof(filen), tmps2, filen.name_len); return tmps2; } } } return 0; } static char type2char(type) { switch (type) { case N_TEXT: return 't'; case N_TEXT | N_EXT: return 'T'; case N_DATA: return 'd'; case N_DATA | N_EXT: return 'D'; case N_BSS: return 'b'; case N_BSS | N_EXT: return 'B'; default: return ' '; } } static int linecnt, quit_list; static syms_listwild2(word32 s_pos, char *pattern) { SYMTREE s; char *name; int lnum; s.me = s_pos; if ((s.me == 0) || quit_list) return; symsget(s.me, &s, sizeof(s)); syms_listwild2(s.vleft, pattern); if (quit_list) return; symsget(s.me+sizeof(s), tmps, s.name_len); if (wild(pattern, tmps)) { if (++linecnt > 20) { printf("--- More ---"); switch (getch()) { case ' ': linecnt = 0; break; case 13: linecnt--; break; case 'q': quit_list = 1; return; } printf("\r \r"); } printf("0x%08lx %c %s", s.val, type2char(s.type), tmps); name = syms_val2line(s.val, &lnum, 0); if (name) printf(", line %d of %s", lnum, name); mputchar('\n'); } syms_listwild2(s.vdown, pattern); if (quit_list) return; syms_listwild2(s.vright, pattern); } void syms_listwild(char *pattern) { quit_list = linecnt = 0; syms_listwild2(symtree_root, pattern); } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.