home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DOS/V Power Report 1997 October
/
VPR9710A.ISO
/
BENCH
/
DJ1SRC_K
/
105
/
SYMS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-02
|
13KB
|
575 lines
/* This is file SYMS.C */
/*
** Copyright (C) 1991 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.
*/
/* 1997/05/01 modified by Kimio Itoh(kitoh@nn.iij4u.or.jp)
for reduce binary size and for dead code elimination.
*/
/* History:250,1 */
#include "build.h"
#if DEBUGGER
extern int __pascal wild(char *pattern, char *string);
#define SYMADDR 0xa0000000L
static word32 sym_brk = SYMADDR;
word32 __pascal salloc(word32 size)
{
word32 r = sym_brk;
size = (size + 3) & ~3;
sym_brk += size;
return r;
}
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 word32 nsyms = 0;
static char tmps[256];
static char tmps2[256];
static word32 __cdecl symtree_add(word32 val, word32 type, char *name)
{
SYMTREE s, sv, temp;
int cval;
int32 cval32;
memset(&temp, 0, sizeof(temp));
temp.name_len = strlen(name) + 1;
temp.me = salloc(sizeof(temp) + temp.name_len);
temp.val = val;
temp.type = type;
symsput(temp.me, &temp, sizeof(temp));
symsput(temp.me + sizeof(temp), name, temp.name_len);
if (!symtree_root) {
symtree_root = temp.me;
return temp.me;
}
s.me = symtree_root;
while (1) {
symsget(s.me, &s, sizeof(s));
symsget(s.me + sizeof(s), tmps, s.name_len);
cval = strcmp(name, tmps);
if (!cval && (!s.val || !val || (s.val == val))) {
if (val) {
s.val = val;
s.type = type;
symsput(s.me, &s, sizeof(s));
}
return temp.me;
} else if (!cval) {
if (!s.ndown) {
s.ndown = temp.me;
symsput(s.me, &s, sizeof(s));
break;
}
s.me = s.ndown;
} else if (cval < 0) {
if (!s.nleft) {
s.nleft = temp.me;
symsput(s.me, &s, sizeof(s));
break;
}
s.me = s.nleft;
} else {
if (!s.nright) {
s.nright = temp.me;
symsput(s.me, &s, sizeof(s));
break;
}
s.me = s.nright;
}
}
nsyms++;
sv.me = symtree_root;
while (1) {
symsget(sv.me, &sv, sizeof(sv));
if (sv.me == temp.me)
return temp.me;
cval32 = val - sv.val;
if (!cval32) {
if (!sv.vdown) {
sv.vdown = temp.me;
symsput(sv.me, &sv, sizeof(sv));
break;
}
sv.me = sv.vdown;
} else if (cval32 < 0) {
if (!sv.vleft) {
sv.vleft = temp.me;
symsput(sv.me, &sv, sizeof(sv));
break;
}
sv.me = sv.vleft;
} else {
if (!sv.vright) {
sv.vright = temp.me;
symsput(sv.me, &sv, sizeof(sv));
break;
}
sv.me = sv.vright;
}
}
return temp.me;
}
typedef struct SYM_ENTRY {
word32 string_off;
word8 type;
word8 other;
word16 desc;
word32 val;
} SYM_ENTRY;
static void __cdecl get_string(FILE * f, word32 where)
{
char *cp;
if (where != ftell(f))
fseek(f, where, 0);
cp = tmps2;
do {
*cp++ = fgetc(f);
} while (cp[-1]);
}
void __pascal syms_init(char *fname)
{
GNU_AOUT header;
int fd, per, oldper = -1;
word32 nsyms, i;
FILE *sfd;
word32 sfd_base;
SYM_ENTRY sym;
char *cp;
word32 last_dot_o = 0;
FILENODE filen;
LINENODE linen;
filen.me = linen.me = 0;
fd = open(fname, O_RDONLY | O_BINARY);
sfd = fopen(fname, "rb");
read(fd, &header, sizeof(header));
if ((header.info & 0xffff) == 0x14c) {
lseek(fd, 0xa8L, 0);
read(fd, &header, sizeof(header));
lseek(fd, 0xa8 + sizeof(header) + header.tsize + header.dsize, 0);
} else if (((header.info & 0xffff) == 0x10b) || ((header.info & 0xffff) == 0x0107)) {
lseek(fd, sizeof(header) + header.tsize + header.dsize + header.txrel + header.dtrel, 0);
} else {
nsyms = 0;
return;
}
printf("Reading symbols... 0%%");
fflush(stdout);
nsyms = header.symsize / sizeof(SYM_ENTRY);
fseek(sfd, tell(fd) + header.symsize, 0);
sfd_base = ftell(sfd);
for (i = 0; i < nsyms; i++) {
if (nsyms > 1)
per = (int)(i * 100L / (nsyms - 1));
else
per = 100;
if (per != oldper) {
printf("\b\b\b\b%3d%%", per);
fflush(stdout);
oldper = per;
}
read(fd, &sym, sizeof(sym));
if (sym.string_off)
get_string(sfd, sfd_base + sym.string_off);
switch (sym.type) {
case N_TEXT:
case N_TEXT | N_EXT:
cp = tmps2;
cp += strlen(cp) - 2;
if (!strcmp(cp, ".o")) {
last_dot_o = sym.val;
if (filen.me && !filen.last_addr) {
filen.last_addr = last_dot_o - 1;
symsput(filen.me, &filen, sizeof(filen));
}
break;
}
if (!strcmp(cp, "d.")) /* 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)
symtree_add(sym.val, sym.type, tmps2);
break;
case N_SO:
memset(&filen, 0, sizeof(FILENODE));
filen.name_len = strlen(tmps2) + 1;
filen.me = salloc(sizeof(FILENODE) + filen.name_len);
symsput(filen.me + sizeof(filen), tmps2, filen.name_len);
filen.next = file_list;
file_list = filen.me;
filen.first_addr = last_dot_o;
symsput(filen.me, &filen, sizeof(filen));
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;
symsput(linen.me, &linen, sizeof(linen));
symsput(filen.me, &filen, sizeof(filen));
break;
}
}
printf(" %ld symbol%s read\n", nsyms, nsyms == 1 ? "" : "s");
return;
}
#define Ofs(n) ((int)&(((TSS *)0)->n))
struct regs_t {
char *name;
int size;
int ofs;
};
struct regs_t 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}
};
int undefined_symbol = 0;
word32 __pascal 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])
return 0;
if (name[0] == '-') {
sign = -1;
name++;
} else if (name[0] == '+') {
name++;
}
if (isdigit(name[0])) {
if (sign == -1)
return -strtol(name, 0, 16);
return strtol(name, 0, 16);
}
cp = strpbrk(name, "+-");
idx = cp ? (cp - name) : strlen(name);
if (name[0] == '%') { /* register */
for (i = 0; regs[i].name; i++)
if (!strncmp(name, regs[i].name, idx)) {
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) && !tmps[i]) {
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 && tmps[idx])
cval = -1;
if (!cval)
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);
cval = (tmps[0] == '_') ? strncmp(name, tmps + 1, idx) : ('_' - tmps[0]);
if (!cval && tmps[idx + 1])
cval = -1;
if (!cval)
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 *__pascal 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"))
goto noname;
if (!strcmp(tmps2, "_end"))
goto noname;
if (delta)
*delta = val - lasts.val;
return tmps2;
}
noname:
sprintf(noname_buf, "%#lx", val);
return noname_buf;
}
char *__pascal 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 = (int)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 = (int)closest.num;
symsget(filen.me + sizeof(filen), tmps2, filen.name_len);
return tmps2;
}
}
}
return 0;
}
static char __fastcall type2char(int 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 void __pascal syms_listwild2(word32 s_pos, char *pattern)
{
SYMTREE s;
char *name;
int lnum;
s.me = s_pos;
if (!s.me || 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("%#08lx %c %s", s.val, type2char((int)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 __fastcall syms_listwild(char *pattern)
{
quit_list = linecnt = 0;
syms_listwild2(symtree_root, pattern);
}
#endif