|
|
1.1 root 1: /*
2: * db/db6.c
3: * A debugger.
4: * Symbol handling.
5: */
6:
7: #include <canon.h>
8: #include "db.h"
9:
10: /*
11: * In earlier versions of db, a SYM included an id hash, a type and a symbol
12: * table index, but not did not include the symbol id[] itself.
13: * This allowed db to handle lots of symbols in a small address space,
14: * but each symbol lookup required reading the symbol again from
15: * the symbol table in the program file (i.e. from the disk).
16: * Since memory is no longer as critical an issue, now db stores the id[]
17: * as part of the SYM and symbol lookup does not need to access the file.
18: */
19:
20: /*
21: * Given a value 'm' in segment 's', find the closest symbol below.
22: * Return a pointer to the symbol, or NULL if none.
23: * In COFF, with a flat address space, the segment can be ignored.
24: * In l.out, where the same address can represent a code or a data item,
25: * it had better not be ignored.
26: */
27: SYM *
28: findsym(s, addr) int s; ADDR_T addr;
29: {
30: register int n;
31: register SYM *hp, *sp;
32:
33: dbprintf(("findsym(%d, %lX):\n", s, addr));
34: sp = (SYM *)NULL;
35: if (sfp == (FILE *)NULL)
36: return sp; /* no symbols */
37: for (n = 0; n < NHASH; n++) { /* search all hash buckets */
38: for (hp = symhash[n]; hp != (SYM *)NULL; hp = hp->s_next) {
39:
40: dbprintf(("findsym: (%d, %lX) id=%s @ (%d, %lX)\n", s, addr, hp->s_id, hp->s_segn, hp->s_addr));
41: if (IS_LOUT && hp->s_segn != s)
42: continue; /* segment mismatch */
43:
44: /* If below and better than previous best guess... */
45: if (hp->s_addr <= addr
46: && (sp==(SYM *)NULL || hp->s_addr > sp->s_addr)) {
47: sp = hp; /* best so far */
48: dbprintf((" best so far: %s addr=%lX s=%d\n", sp->s_id, sp->s_addr, sp->s_segn));
49: if (sp->s_addr == addr)
50: return sp; /* gotcha! */
51: }
52: }
53: }
54: return sp; /* NULL or best guess */
55: }
56:
57: /*
58: * Hash a symbol name.
59: * The '_' character has no effect on the hash, so "foo" and "foo_" hash
60: * to the same value; this is convenient for l.out symbol lookup,
61: * where is_symbol() understands "foo" to mean "foo_" if there is no "foo".
62: */
63: int
64: hash(id) register char *id;
65: {
66: register int c, h;
67:
68: for (h = 0; (c = *id++) != 0; )
69: if (c != '_')
70: h += c;
71: return h % NHASH;
72: }
73:
74: /*
75: * See if the given symbol is a special symbol "d", "i" or "u".
76: */
77: int
78: is_special(sp) register SYM *sp;
79: {
80: register int s;
81:
82: if (sp->s_id[1] != '\0')
83: return 0;
84: switch (sp->s_id[0]) {
85: case 'd': s = DSEG; break;
86: case 'i': s = ISEG; break;
87: case 'u': s = USEG; break;
88: default: return 0;
89: }
90: sp->s_addr = 0;
91: sp->s_segn = s;
92: return 1;
93: }
94:
95: /*
96: * Find the value of a symbol.
97: * Return 1 on success, 0 on failure.
98: * For l.out, "foo" matches "foo_" if "foo" is not found.
99: */
100: int
101: is_symbol(sp) SYM *sp;
102: {
103: register char *cp;
104: register SYM *hp;
105: register int len;
106:
107: dbprintf(("is_symbol(%s): "));
108: cp = sp->s_id;
109: for (hp = symhash[hash(cp)]; hp != (SYM *)NULL; hp = hp->s_next) {
110: if (strcmp(cp, hp->s_id) == 0) {
111: dbprintf(("addr=%lX segn=%d\n", hp->s_addr, hp->s_segn));
112: sp->s_addr = hp->s_addr;
113: sp->s_segn = hp->s_segn;
114: return 1;
115: }
116: }
117:
118: /* The symbol was not found. If l.out, try again with trailing '_'. */
119: if (IS_LOUT) {
120: len = strlen(cp);
121: for (hp = symhash[hash(cp)]; hp != (SYM *)NULL; hp = hp->s_next) {
122: if (strncmp(cp, hp->s_id, len) == 0
123: && hp->s_id[len] == '_'
124: && hp->s_id[len+1] == '\0') {
125: dbprintf(("(%s) addr=%lX segn=%d\n", hp->s_id, hp->s_addr, hp->s_segn));
126: sp->s_addr = hp->s_addr;
127: sp->s_segn = hp->s_segn;
128: return 1;
129: }
130: }
131: }
132: dbprintf((" is_symbol(): %s not found\n", cp));
133: return 0;
134: }
135:
136: /*
137: * Allocate a new SYM with the given id, address and segment.
138: * Initialize it and link it into the hash chain.
139: * db.h declares char s_id[1], but the nalloc() call below
140: * leaves room for the actual id char s_id[len+1].
141: */
142: void
143: new_sym(id, addr, s) char *id; ADDR_T addr; int s;
144: {
145: register int len, h;
146: register SYM *sp;
147:
148: h = hash(id);
149: len = strlen(id); /* len+1 is s_id len with NUL */
150: dbprintf(("new_sym(%s, %x, %lX) len=%d hash=%x\n", id, type, addr, len, h));
151: sp = (SYM *)nalloc(sizeof(SYM) + len, "symbol");
152: sp->s_next = symhash[h];
153: symhash[h] = sp;
154: sp->s_addr = addr;
155: sp->s_segn = s;
156: strcpy(sp->s_id, id);
157: }
158:
159: /*
160: * Read COFF symbols.
161: */
162: int
163: read_coff_sym()
164: {
165: SYMENT coffsym;
166: long n;
167: register int len, segn;
168: char *strtab;
169: SCNHDR *shp;
170:
171: dbprintf(("read_coff_sym()\n"));
172:
173: /* Read the COFF string table. */
174: strtab = read_strtab();
175:
176: /* Read the COFF section headers. */
177: len = coff_hdr.f_nscns * sizeof(SCNHDR);
178: shp = (SCNHDR *)nalloc(len, "COFF section headers");
179: if (fseek(sfp, (long)(sizeof(FILEHDR) + coff_hdr.f_opthdr), SEEK_SET) == -1
180: || fread(shp, len, 1, sfp) != 1)
181: return printe("Cannot read section headers");
182:
183: /* Read symbols. */
184: if (fseek(sfp, (long)coff_hdr.f_symptr, SEEK_SET) == -1)
185: return printe("COFF symbol seek failed");
186: for (nsyms = 0, n = coff_hdr.f_nsyms; n--; ) {
187: /* Read a COFF symbol. */
188: if (fread(&coffsym, sizeof(SYMENT), 1, sfp) != 1)
189: return printe("Cannot read COFF symbol");
190: switch (coffsym.n_sclass) {
191: case C_EXT:
192: case C_EXTDEF:
193: break;
194: default:
195: continue;
196: }
197: /* Ignore undefined and absolute symbols. */
198: if (coffsym.n_scnum == N_UNDEF || coffsym.n_scnum == N_ABS)
199: continue;
200:
201: switch((int)shp[coffsym.n_scnum-1].s_flags) {
202: case STYP_TEXT: segn = ISEG; break;
203: case STYP_DATA:
204: case STYP_BSS: segn = DSEG; break;
205: default:
206: panic("Unallowed section flags 0x%lX for symbol in section %d",
207: shp[coffsym.n_scnum-1].s_flags, coffsym.n_scnum-1);
208: }
209: ++nsyms;
210: new_sym(symName(&coffsym, strtab), coffsym.n_value, segn);
211: }
212: dbprintf(("COFF nsyms=%d\n", nsyms));
213: if (strtab != NULL)
214: nfree(strtab);
215: nfree(shp);
216: return 1;
217: }
218:
219: /*
220: * Read l.out symbols.
221: */
222: int
223: read_lout_sym(symseek) long symseek;
224: {
225: register int n, segn;
226: struct ldsym lds;
227: char id[NCPLN+1];
228:
229: if (fseek(sfp, symseek, SEEK_SET) == -1)
230: return printr("Cannot seek to l.out symbols");
231: for (n = nsyms; n--; ) {
232: /* Read an l.out symbol. */
233: if (fread(&lds, sizeof(struct ldsym), 1, sfp) != 1)
234: return printr("Cannot read l.out symbol");
235: canint(lds.ls_type);
236: switch(lds.ls_type & LR_SEG) {
237: case L_ABS:
238: case L_SHRI:
239: case L_PRVI:
240: case L_BSSI:
241: segn = ISEG;
242: break;
243: case L_SHRD:
244: case L_PRVD:
245: case L_BSSD:
246: segn = DSEG;
247: break;
248: default:
249: dbprintf(("Unexpected l.out segment %d\n", lds.ls_type & LR_SEG));
250: continue;
251: }
252: canvaddr(lds.ls_addr);
253: strncpy(id, lds.ls_id, NCPLN);
254: id[NCPLN] = '\0';
255: new_sym(id, (ADDR_T)lds.ls_addr, segn);
256: }
257: dbprintf(("l.out nsyms=%d\n", nsyms));
258: return 1;
259: }
260:
261: /*
262: * Read the COFF string table.
263: * Return a pointer to the allocated table, or NULL if empty.
264: */
265: char *
266: read_strtab()
267: {
268: register unsigned int len;
269: int llen;
270: char *strtab;
271:
272: dbprintf(("read_strtab()\n"));
273: len = llen = sizeof(SYMENT) * coff_hdr.f_nsyms;
274: if (len == 0)
275: return NULL; /* no symbols */
276: if (llen != len)
277: panic("COFF symbol table too big");
278:
279: /* Seek to strtab length. */
280: if (fseek(sfp, coff_hdr.f_symptr+len, SEEK_SET) == -1
281: || fread(&llen, sizeof(llen), 1, sfp) != 1)
282: llen = 0;
283: if (llen == 0)
284: return NULL; /* no string table */
285: len = llen -= 4;
286: if (len != llen)
287: panic("COFF string table too big");
288: strtab = nalloc((int)len, "COFF string table");
289: if (fread(strtab, len, 1, sfp) != 1) {
290: printe("Cannot read symbol string table");
291: return NULL;
292: }
293: return strtab;
294: }
295:
296: /*
297: * Given a COFF symbol table entry, return its NUL-terminated name.
298: */
299: char *
300: symName(sym, strtab) SYMENT *sym; char *strtab;
301: {
302: static char work[SYMNMLEN+1];
303:
304: if (sym->n_zeroes == 0)
305: return strtab + sym->n_offset - 4; /* name in string table */
306:
307: /* Copy name from n_name to make sure it's NUL-terminated. */
308: memcpy(work, sym->n_name, SYMNMLEN);
309: work[SYMNMLEN] = '\0';
310: return work;
311: }
312:
313: /*
314: * Read a symbol and return its value in the given 'VAL' structure.
315: * The symbol name can contain alphanumeric characters and '_';
316: * a leading '%' indicates a register name.
317: */
318: int
319: symval(vp) VAL *vp;
320: {
321: register int c;
322: register char *cp;
323: int regf;
324: static SYM *sp;
325: static int sym_len = 128;
326:
327: /* Allocate a SYM first time through. */
328: if (sp == (SYM *)NULL)
329: sp = (SYM *)nalloc(sizeof(SYM)+sym_len+1, "symbol id buffer");
330:
331: /* Read the symbol name into the SYM id[] buffer. */
332: for (regf = 0, cp = sp->s_id; ; cp++) {
333: c = getn();
334: /* Allow leading '%' to indicate register name. */
335: if (cp==sp->s_id && c=='%') {
336: c = getn();
337: ++regf;
338: }
339: if (!isascii(c) || (!isalnum(c) && c!= '_'))
340: break;
341: if (cp == &sp->s_id[sym_len]) {
342: register SYM *sp2;
343:
344: /* Grow the symbol id buffer when required. */
345: sp2 = (SYM *)nalloc(sizeof(SYM)+sym_len+sym_len+1, "symbol id buffer");
346: strncpy(sp2->s_id, sp->s_id, sym_len);
347: cp = &sp2->s_id[sym_len];
348: sym_len += sym_len;
349: nfree(sp);
350: sp = sp2;
351: }
352: *cp = c;
353: }
354: *cp = '\0';
355: ungetn(c);
356: if (regf) {
357: if (is_reg(sp) == 0)
358: return printe("Register not found");
359: } else if (!is_special(sp) && !is_symbol(sp) && !is_reg(sp))
360: return printe("Symbol not found");
361:
362: /* Copy the value and segment to vp. */
363: vp->v_nval = (long)sp->s_addr;
364: vp->v_segn = sp->s_segn;
365: vp->v_flag = VSEGN;
366: return 1;
367: }
368:
369: /* end of db/db6.c */
370:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.