BSD 3 development
[unix-history] / usr / src / cmd / sdb / symt.c
CommitLineData
b4484850
HK
1#include "head.h"
2#include <a.out.h>
3#include <sys/stat.h>
4
5struct user u;
6int compar();
7char *symfil;
8
9/* initialize file and procedure tables */
10initfp() {
11 struct nlist stentry;
12 register struct proct *procp;
13 register struct filet *filep;
14 struct stat stbuf;
15
16 long soffset;
17 int i;
18 char class;
19 register char *p, *q;
20
21 sbuf.fd = txtmap.ufd;
22 soffset = ststart;
23 blseek(&sbuf,ststart,0);
24 filep = files = badfile = (struct filet *) sbrk(sizeof filep[0]);
25 procp = procs = badproc = (struct proct *) sbrk(sizeof procp[0]);
26
27 for(;;) {
28 if (bread(&sbuf, &stentry, sizeof stentry) <
29 sizeof stentry) break;
30 class = stentry.n_type & STABMASK;
31 switch (class & STABMASK) {
32 case N_SO:
33 case N_SOL:
34 if (filep == badfile) {
35 p = sbrk(FILEINCR*sizeof filep[0]);
36 if (p < 0) {
37 perror("sdb");
38 exit(4);
39 }
40 q = p + FILEINCR*sizeof filep[0];
41 while (p > (char *) procs)
42 *--q = *--p;
43 badfile += FILEINCR;
44 procp = (struct proct *)
45 ((char *) procp +
46 FILEINCR*sizeof filep[0]);
47 procs = (struct proct *)
48 ((char *) procs +
49 FILEINCR*sizeof filep[0]);
50 badproc = (struct proct *)
51 ((char *)badproc +
52 FILEINCR*sizeof filep[0]);
53 }
54 filep->faddr = stentry.n_value;
55 filep->lineflag = (class == N_SOL);
56 filep->stf_offset = soffset;
57 p = filep->sfilename;
58 for (;;) {
59 for (i=0; i<8; i++) *p++ = stentry.n_name[i];
60 if (*(p-1) == '\0') break;
61 if (bread(&sbuf, &stentry, sizeof stentry)
62 < sizeof stentry)
63 error("Bad N_SO entry (1)");
64 if ((stentry.n_type & STABMASK) !=
65 (unsigned char) class)
66 error("Bad N_SO entry (2)");
67 soffset += sizeof stentry;
68 }
69 q = filep->sfilename;
70 for (p=fp; *q; *p++ = *q++) ;
71 *p = 0;
72 if (stat(filework, &stbuf) == -1)
73 printf("Warning: `%s' not found\n",
74 filep->sfilename);
75 else if (stbuf.st_mtime > symtime)
76 printf("Warning: `%s' newer than `%s'\n",
77 filep->sfilename,
78 symfil);
79 filep++;
80 break;
81
82 case N_TEXT:
83 if (stentry.n_name[0] != '_') break;
84 case N_FUN:
85 case N_ENTRY:
86 if (procp == badproc) {
87 if (sbrk(PROCINCR*sizeof procp[0]) < 0) {
88 perror("sdb");
89 exit(4);
90 }
91 badproc += PROCINCR;
92 }
93 for(i=0; i<8; i++)
94 procp->pname[i] = stentry.n_name[i];
95 procp->paddr = stentry.n_value;
96 procp->st_offset = soffset;
97 procp->sfptr = (class != N_TEXT) ? filep - 1 : badfile;
98 procp->lineno = (class != N_TEXT) ? stentry.n_desc : 0;
99 procp->entrypt = (class & STABMASK) == N_ENTRY;
100 procp++;
101 break;
102 }
103 if (stentry.n_type & N_EXT && !extstart) {
104 extstart = soffset;
105 }
106 soffset += sizeof stentry;
107 }
108 qsort(procs, procp-procs, sizeof procs[0], compar);
109 badproc->st_offset = soffset;
110 badproc->sfptr = procp->sfptr = badfile;
111 badproc->pname[0] = badfile->sfilename[0]=
112 procp->pname[0] = filep->sfilename[0] = '\0';
113
114 setcur(1);
115}
116
117/* returns current procedure from state (curfile, fline) */
118struct proct *
119curproc() {
120 register ADDR addr;
121
122 addr = getaddr("", fline);
123 if (addr == -1) return(badproc);
124 return(adrtoprocp(addr));
125
126}
127
128/* returns procedure s, uses curproc() if s == NULL */
129
130struct proct *
131findproc(s)
132char *s; {
133 register struct proct *p;
134
135 if (s[0] == '\0') return(curproc());
136
137 for(p=procs; p->pname[0]; p++)
138 if (eqstr(p->pname, s)) return(p);
139
140 if (debug) printf("%s(): unknown name\n", s);
141 return(badproc);
142}
143
144/* returns file s containing filename */
145struct filet *
146findfile(s)
147char *s; {
148 register struct filet *f;
149 for (f=files; f->sfilename[0]; f++) {
150 if (eqstr(f->sfilename, s)) {
151 for( ; f->lineflag; f--) ;
152 if (f < files) error("Bad file array");
153 return(f);
154 }
155 }
156 return(f);
157}
158
159/*
160 * slookup():
161 * looks up variable matching pat starting at offset in a.out, searching
162 * backwards, ignoring nested blocks to beginning to procedure.
163 * Returns its offset and symbol table entries decoded in sl_*
164 *
165 * If comblk == "*" then match both within and outside common blocks,
166 * if comblk == "" then match only outside common blocks,
167 * else match only within comblk.
168 */
169
170long
171slookup(pat, poffset, stelt)
172long poffset; char *pat; {
173 slookinit();
174 slooknext(pat, poffset, stelt, "*");
175}
176
177int clevel, level, fnameflag, comfound, incomm;
178
179slookinit() {
180 clevel = level = fnameflag = comfound = incomm = 0;
181}
182
183long
184slooknext(pat, poffset, stelt, comblk)
185long poffset; char *pat, *comblk; {
186 register int i;
187 register long offset;
188 char class, *q;
189 struct nlist stentry;
190 struct proct *procp, *p;
191
192 offset = poffset + sizeof stentry;
193 if (debug) printf("slookup(%s,%d)\n",pat,offset);
194 blseek(&sbuf, offset, 0);
195
196 for (;;) {
197 offset -= sizeof stentry;
198 if (offset < ststart) break;
199 if (bread(&sbuf, &stentry+1, -sizeof stentry)
200 < sizeof stentry) break;
201 class = stentry.n_type & STABMASK;
202 switch (class & STABMASK) {
203 case 0:
204 break;
205 case N_FUN:
206 return(-1);
207 case N_RBRAC:
208 level++;
209 break;
210 case N_LBRAC:
211 level--;
212 break;
213 case N_ECOMM:
214 for (q = &stentry.n_name[7]; q>=stentry.n_name; q--) {
215 if (*q == '_') {
216 *q = '\0';
217 break;
218 }
219 }
220 if (eqpat(comblk, stentry.n_name))
221 comfound = 1;
222 incomm = 1;
223 case N_ECOML:
224 clevel++;
225 break;
226 case N_BCOMM:
227 comfound = incomm = 0;
228 clevel--;
229 break;
230 case N_FNAME:
231 if (fnameflag)
232 break;
233 procp = findproc(stentry.n_name);
234 for (p=procs; p->pname[0]; p++) {
235 if (p->entrypt == 0 &&
236 p->st_offset > procp->st_offset &&
237 p->st_offset < offset)
238 offset = p->st_offset;
239 }
240 clevel = level = 0;
241 fnameflag++;
242 blseek(&sbuf, offset, 0);
243 break;
244 default:
245 if (level <= 0 && eqpat(pat, stentry.n_name) &&
246 stentry.n_name[0] && class & STABTYPES &&
247 (eqstr("*", comblk) ||
248 (comblk[0] == '\0' && incomm == 0) ||
249 comfound) &&
250 (stelt == (class == N_SSYM))) {
251 if (class == N_LENG) {
252 sl_size = stentry.n_value;
253 offset -= sizeof stentry;
254 bread(&sbuf, &stentry+1,
255 -sizeof stentry);
256 }
257 else sl_size = 0;
258 sl_class = stentry.n_type & STABMASK;
259 sl_type = stentry.n_desc;
260 sl_addr = stentry.n_value;
261 for (i=0; i<8; i++) sl_name[i] =
262 stentry.n_name[i];
263 if (clevel != 0) docomm(offset);
264 return(offset - sizeof stentry);
265 }
266 }
267 }
268 return(-1);
269}
270
271/*
272 * Look up global variable matching pat
273 * Return its offset and symbol table entries decoded in sl_*
274 */
275long
276globallookup(pat, filestart, stelt)
277char *pat; long filestart; {
278 register int offset, i;
279 struct nlist stentry;
280 int class, clevel;
281
282 if (debug) printf("globallookup(%s,%d)\n", pat,filestart);
283 blseek(&sbuf, filestart, 0);
284 offset = filestart - sizeof stentry;
285 clevel = 0;
286 do {
287 if (bread(&sbuf, &stentry, sizeof stentry) <
288 sizeof stentry) return(-1);
289 offset += sizeof stentry;
290 } while ((stentry.n_type & STABMASK) == N_SO);
291 for (;;) {
292 class = stentry.n_type & STABMASK;
293 switch (class & STABMASK) {
294 case N_SO:
295 return(-1);
296 case N_ECOMM:
297 clevel--;
298 break;
299 case N_BCOMM:
300 clevel++;
301 break;
302 default:
303 if (eqpat(pat, stentry.n_name)
304 && stentry.n_name[0] && class & STABTYPES) {
305 sl_class = stentry.n_type & STABMASK;
306 if (sl_class != N_GSYM && sl_class != N_SSYM &&
307 sl_class != N_STSYM) goto g1;
308 if (stelt != (sl_class == N_SSYM)) goto g1;
309 sl_size = 0;
310 sl_type = stentry.n_desc;
311 sl_addr = stentry.n_value;
312 for (i=0; i<8; i++) sl_name[i] = stentry.n_name[i];
313 if (clevel != 0) docomm(offset);
314 goto g2;
315 }
316 }
317g1: if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry)
318 return(-1);
319 offset += sizeof stentry;
320 }
321g2: bread(&sbuf, &stentry, sizeof stentry);
322 if (((stentry.n_type & STABMASK) == N_LENG) &&
323 (eqpat(sl_name, stentry.n_name)))
324 sl_size = stentry.n_value;
325
326 if (sl_class == N_GSYM && (clevel == 0)) {
327 blseek(&sbuf, extstart, 0);
328 for(;;) {
329 if (bread(&sbuf, &stentry, sizeof stentry)
330 < sizeof stentry)
331 return(-1);
332 if (stentry.n_name[0] != '_') continue;
333 if (eqpatr(sl_name, stentry.n_name+1, 1)) {
334 sl_addr = stentry.n_value;
335 break;
336 }
337 }
338 }
339 return(offset + sizeof stentry);
340}
341
342/* core address to procedure (pointer to proc array) */
343struct proct *
344adrtoprocp(addr)
345ADDR addr; {
346 register struct proct *procp, *lastproc;
347 lastproc = badproc;
348 for (procp=procs; procp->pname[0]; procp++) {
349 if (procp->paddr > addr) break;
350 if (procp->entrypt == 0)
351 lastproc = procp;
352 }
353 return (lastproc);
354}
355
356
357/* core address to file (pointer to file array) */
358struct filet *
359adrtofilep(addr)
360ADDR addr; {
361 register struct filet *filep;
362 for (filep=files; filep->sfilename[0]; filep++) {
363 if (filep->faddr > addr) break;
364 }
365 return (filep != files ? filep-1 : badfile);
366}
367
368/* core address to linenumber */
369long lastoffset;
370
371adrtolineno(addr)
372ADDR addr; {
373 register int lineno;
374 long offset;
375 struct nlist stentry;
376
377 lineno = lastoffset = -1;
378 offset = adrtoproc(addr)->st_offset;
379 blseek(&sbuf, offset, 0);
380 for (;;) {
381 if (bread(&sbuf, &stentry, sizeof stentry)
382 < sizeof stentry) break;
383 if (stentry.n_type == N_SLINE) {
384 if (stentry.n_value > addr) break;
385 lastoffset = offset;
386 lineno = stentry.n_desc;
387 }
388 offset += sizeof stentry;
389 }
390 return (lineno);
391}
392
393
394/* address to a.out offset */
395long
396adrtostoffset(addr)
397ADDR addr; {
398 adrtolineno(addr);
399 return(lastoffset);
400}
401
402
403/*
404 * Set (curfile, lineno) from core image.
405 * Returns 1 if there is a core image, 0 otherwise.
406 *
407 * Print the current line iff verbose is set.
408 */
409setcur(verbose) {
410 register struct proct *procp;
411
412 dot = *(ADDR *) (((ADDR) &u) + PC);
413
414 if (dot == 0) {
415 printf("No core image\n");
416 goto setmain;
417 }
418 procp = adrtoprocp(dot);
419 if ((procp->sfptr) != badfile) {
420 finit(adrtofilep(procp->paddr)->sfilename);
421 ffind(adrtolineno(dot));
422 if (verbose) {
423 printf("%.8s:", procp->pname);
424 fprint();
425 }
426 return(1);
427 }
428 if (verbose) {
429 if (procp->pname[0] == '_')
430 printf("%.7s: address 0x%x\n", procp->pname+1, dot);
431 else
432 printf("%.8s: address %d\n", procp->pname, dot);
433 }
434
435setmain:
436 procp = findproc("MAIN_");
437 if ((procp->pname[0] != 'M') || (procp->sfptr == badfile)) {
438 procp = findproc("main");
439 if ((procp->pname[0] != 'm') || (procp->sfptr == badfile)) {
440 nolines = 1;
441 printf("main not compiled with debug flag\n");
442 return(0);
443 }
444 }
445 finit(procp->sfptr->sfilename);
446 ffind(procp->lineno);
447 return(0);
448}
449
450compar(a, b)
451struct proct *a, *b; {
452 if (a->paddr == b->paddr) {
453 if (a->pname[0] == '_') return(-1);
454 if (b->pname[0] == '_') return(1);
455 return(0);
456 }
457 return(a->paddr < b->paddr ? -1 : 1);
458}
459
460/* gets offset of file or procedure named s */
461nametooffset(s)
462char *s; {
463 register struct filet *f;
464 register struct proct *p;
465
466 if (*s == '\0')
467 return(-1);
468 if (eqany('.', s)) {
469 f = findfile(s);
470 return(f->sfilename[0] ? f->stf_offset : -1);
471 }
472 p = findproc(s);
473 return(p->pname[0] ? p->st_offset : -1);
474}
475/* returns s if its a filename, its file otherwise */
476char *
477nametofile(s)
478char *s; {
479 register struct proct *p;
480
481 if (eqany('.', s)) {
482 return(s);
483 }
484 p = findproc(s);
485 return(adrtofilep(p->paddr)->sfilename);
486}
487
488
489/* line number to address, starting at offset in a.out */
490/* assumes that offset is within file */
491lntoaddr(lineno, offset, file)
492long offset; char *file; {
493 struct nlist stentry;
494 register int i, ignore = 0;
495 register int bestln=BIGNUM;
496 ADDR bestaddr;
497 char *p;
498
499 blseek(&sbuf, offset, 0);
500
501 do {
502 if (bread(&sbuf, &stentry, sizeof stentry) <
503 sizeof stentry) return(-1);
504 } while ((stentry.n_type & STABMASK) == N_SO);
505 for (;;) {
506 switch(stentry.n_type & STABMASK) {
507 case N_SLINE:
508 if (!ignore) {
509 if (stentry.n_desc == lineno)
510 return(stentry.n_value);
511 if (stentry.n_desc > lineno &&
512 stentry.n_desc < bestln) {
513 bestln = stentry.n_desc;
514 bestaddr = stentry.n_value;
515 }
516 }
517 break;
518
519 case N_SO:
520 goto ret;
521
522 case N_SOL:
523 p = file;
524 for (;;) {
525 for (i=0; i<8; i++) {
526 if (*p != stentry.n_name[i]) goto neq;
527 if (*p++ == '\0') break;
528 }
529 if (stentry.n_name[7] == '\0')
530 break;
531 if (bread(&sbuf, &stentry, sizeof stentry)
532 < sizeof stentry)
533 error("Bad N_SO entry (1)");
534 if ((stentry.n_type & STABMASK) !=
535 (unsigned char) N_SOL)
536 error("Bad N_SO entry (2)");
537 }
538 ignore = 0;
539 break;
540
541neq: ignore++;
542 break;
543 }
544 if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry)
545 break;
546 }
547ret: return(bestln == BIGNUM ? -1 : bestaddr);
548}
549
550/* gets address of proc:number */
551getaddr(proc,integ)
552char *proc; {
553 register long offset;
554 register char *s, *f;
555 ADDR addr;
556
557 s = proc[0] ? proc : curfile;
558 if (*s == '\0')
559 return(-1);
560 offset = nametooffset(s);
561 f = nametofile(s);
562 if (debug) printf("getaddr() computed offset %d", offset);
563 if (offset == -1) {
564 addr = extaddr(proc);
565 if (addr != -1) addr += 2; /* MACHINE DEPENDENT */
566 if (debug) printf(" extaddr computed %d\n", addr);
567 return(addr);
568 }
569 if (integ)
570 addr = lntoaddr(integ, offset, s);
571 else {
572 addr = findproc(proc)->paddr + 2; /* MACHINE DEPENDENT */
573 addr = lntoaddr(adrtolineno(addr)+1, offset, f);
574 }
575 if (debug) printf(" and addr %d\n", addr);
576 if (addr == -1) return(-1);
577 return(addr);
578}
579
580/* returns address of external */
581ADDR
582extaddr(name)
583char *name; {
584 struct nlist stentry;
585 blseek(&sbuf, extstart, 0);
586
587 for (;;) {
588 if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry)
589 return(-1);
590 if (stentry.n_name[0] == '_' &&
591 eqpatr(name, stentry.n_name+1, 1))
592 return(stentry.n_value);
593 }
594}
595
596/* find enclosing common blocks and fix up addresses */
597docomm(offset)
598long offset; {
599 struct nlist stentry;
600
601 for (;;) {
602 if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry) {
603 error("Bad common block");
604 return;
605 }
606 sl_class = N_GSYM;
607 if ((stentry.n_type & STABMASK) == N_ECOMM) {
608 sl_addr += extaddr(stentry.n_name);
609 blseek(&sbuf, offset, 0);
610 return;
611 }
612 if ((stentry.n_type & STABMASK) == N_ECOML) {
613 sl_addr += stentry.n_value;
614 blseek(&sbuf, offset, 0);
615 return;
616 }
617 }
618}
619
620/* determine if class is that of a variable */
621char pctypes[] = {N_GSYM, N_STSYM, N_LCSYM, N_RSYM, N_SSYM, N_LSYM,
622 N_PSYM, 0};
623varclass(class)
624char class; {
625 char *p;
626
627 for (p=pctypes; *p; p++) {
628 if (class == *p)
629 return(1);
630 }
631 return(0);
632}