fixed @(#) stuff
[unix-history] / usr / src / old / dbx / object.c
CommitLineData
2c3a9a86
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
550fe947 3static char sccsid[] = "@(#)object.c 1.2 %G%";
2c3a9a86
ML
4
5/*
6 * Object code interface, mainly for extraction of symbolic information.
7 */
8
9#include "defs.h"
10#include "object.h"
11#include "main.h"
12#include "symbols.h"
13#include "names.h"
14#include "languages.h"
15#include "mappings.h"
16#include "lists.h"
17#include <a.out.h>
18#include <stab.h>
19#include <ctype.h>
20
21#ifndef public
22
23struct {
24 unsigned int stringsize; /* size of the dumped string table */
25 unsigned int nsyms; /* number of symbols */
26 unsigned int nfiles; /* number of files */
27 unsigned int nlines; /* number of lines */
28} nlhdr;
29
30#endif
31
32public String objname = "a.out";
33public Integer objsize;
34public char *stringtab;
35
36private String progname = nil;
37private Language curlang;
38private Symbol curmodule;
39private Symbol curparam;
40private Boolean warned;
41
42private Filetab *filep;
43private Linetab *linep;
44private Address curfaddr;
45
46#define curfilename() (filep-1)->filename
47
48/*
49 * Blocks are figured out on the fly while reading the symbol table.
50 */
51
52#define MAXBLKDEPTH 25
53
54private Symbol curblock;
55private Symbol blkstack[MAXBLKDEPTH];
56private Integer curlevel;
57
58#define enterblock(b) { \
59 blkstack[curlevel] = curblock; \
60 ++curlevel; \
61 b->level = curlevel; \
62 b->block = curblock; \
63 curblock = b; \
64}
65
66#define exitblock() { \
67 --curlevel; \
68 curblock = blkstack[curlevel]; \
69}
70
71/*
72 * Enter a source line or file name reference into the appropriate table.
73 * Expanded inline to reduce procedure calls.
74 *
75 * private enterline(linenumber, address)
76 * Lineno linenumber;
77 * Address address;
78 * ...
79 */
80
81#define enterline(linenumber, address) \
82{ \
83 register Linetab *lp; \
84 \
85 lp = linep - 1; \
86 if (linenumber != lp->line) { \
87 if (address != lp->addr) { \
88 ++lp; \
89 } \
90 lp->line = linenumber; \
91 lp->addr = address; \
92 linep = lp + 1; \
93 } \
94}
95
96#define NTYPES 1000
97
98private Symbol typetable[NTYPES];
99
100/*
101 * Read in the namelist from the obj file.
102 *
103 * Reads and seeks are used instead of fread's and fseek's
104 * for efficiency sake; there's a lot of data being read here.
105 */
106
107public readobj(file)
108String file;
109{
110 Fileid f;
111 struct exec hdr;
112 struct nlist nlist;
113
114 f = open(file, 0);
115 if (f < 0) {
116 fatal("can't open %s", file);
117 }
118 read(f, &hdr, sizeof(hdr));
119 objsize = hdr.a_text;
120 nlhdr.nsyms = hdr.a_syms / sizeof(nlist);
121 nlhdr.nfiles = nlhdr.nsyms;
122 nlhdr.nlines = nlhdr.nsyms;
123 lseek(f, (long) N_STROFF(hdr), 0);
124 read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize));
125 nlhdr.stringsize -= 4;
126 stringtab = newarr(char, nlhdr.stringsize);
127 read(f, stringtab, nlhdr.stringsize);
128 allocmaps(nlhdr.nfiles, nlhdr.nlines);
129 lseek(f, (long) N_SYMOFF(hdr), 0);
130 readsyms(f);
131 ordfunctab();
132 setnlines();
133 setnfiles();
134 close(f);
135}
136
137/*
138 * Read in symbols from object file.
139 */
140
141private readsyms(f)
142Fileid f;
143{
144 struct nlist *namelist;
145 register struct nlist *np, *ub;
146 register int index;
147 register String name;
148 register Boolean afterlg;
149
150 initsyms();
151 namelist = newarr(struct nlist, nlhdr.nsyms);
152 read(f, namelist, nlhdr.nsyms * sizeof(struct nlist));
153 afterlg = false;
154 ub = &namelist[nlhdr.nsyms];
155 for (np = &namelist[0]; np < ub; np++) {
156 index = np->n_un.n_strx;
157 if (index != 0) {
158 name = &stringtab[index - 4];
159 } else {
160 name = nil;
161 }
162 /*
163 * assumptions:
164 * not an N_STAB ==> name != nil
165 * name[0] == '-' ==> name == "-lg"
166 * name[0] != '_' ==> filename or invisible
167 *
168 * The "-lg" signals the beginning of global loader symbols.
169 */
170 if ((np->n_type&N_STAB) != 0) {
171 enter_nl(name, np);
172 } else if (name[0] == '-') {
173 afterlg = true;
174 if (curblock->class != PROG) {
175 exitblock();
176 if (curblock->class != PROG) {
177 exitblock();
178 }
179 }
180 enterline(0, (linep-1)->addr + 1);
181 } else if (name[0] == '_') {
182 if (afterlg) {
183 check_global(&name[1], np);
184 } else if (curblock->name != nil) {
185 check_local(&name[1], np);
186 }
187 } else if ((np->n_type&N_TEXT) == N_TEXT) {
188 check_filename(name);
189 }
190 }
191 dispose(namelist);
192}
193
194/*
195 * Initialize symbol information.
196 */
197
198private initsyms()
199{
200 curblock = nil;
201 curlevel = 0;
202 if (progname == nil) {
203 progname = strdup(objname);
204 if (rindex(progname, '/') != nil) {
205 progname = rindex(progname, '/') + 1;
206 }
207 if (index(progname, '.') != nil) {
208 *(index(progname, '.')) = '\0';
209 }
210 }
211 program = insert(identname(progname, true));
212 program->class = PROG;
213 newfunc(program);
214 findbeginning(program);
215 enterblock(program);
216 curmodule = program;
217 t_boolean = maketype("$boolean", 0L, 1L);
218 t_int = maketype("$integer", 0x80000000L, 0x7fffffffL);
219 t_char = maketype("$char", 0L, 127L);
220 t_real = maketype("$real", 4L, 0L);
221 t_nil = maketype("$nil", 0L, 0L);
222}
223
224/*
225 * Free all the object file information that's being stored.
226 */
227
228public objfree()
229{
230 symbol_free();
231 keywords_free();
232 names_free();
233 dispose(stringtab);
234 clrfunctab();
235}
236
237/*
238 * Enter a namelist entry.
239 */
240
241private enter_nl(name, np)
242String name;
243register struct nlist *np;
244{
245 register Symbol s;
246 String mname, suffix;
247 register Name n;
248 register Symbol *tt;
249
250 s = nil;
251 if (name == nil) {
252 n = nil;
253 } else {
254 n = identname(name, true);
255 }
256 switch (np->n_type) {
257 case N_LBRAC:
258 s = symbol_alloc();
259 s->class = PROC;
260 enterblock(s);
261 break;
262
263 case N_RBRAC:
264 exitblock();
265 break;
266
267 case N_SLINE:
268 enterline((Lineno) np->n_desc, (Address) np->n_value);
269 break;
270
271 /*
272 * Compilation unit. C associates scope with filenames
273 * so we treat them as "modules". The filename without
274 * the suffix is used for the module name.
275 *
276 * Because there is no explicit "end-of-block" mark in
277 * the object file, we must exit blocks for the current
278 * procedure and module.
279 */
280 case N_SO:
281 mname = strdup(ident(n));
282 if (rindex(mname, '/') != nil) {
283 mname = rindex(mname, '/') + 1;
284 }
285 suffix = rindex(mname, '.');
286 curlang = findlanguage(suffix);
287 if (suffix != nil) {
288 *suffix = '\0';
289 }
290 if (curblock->class != PROG) {
291 exitblock();
292 if (curblock->class != PROG) {
293 exitblock();
294 }
295 }
296 s = insert(identname(mname, true));
297 s->language = curlang;
298 s->class = MODULE;
299 enterblock(s);
300 curmodule = s;
301 if (program->language == nil) {
302 program->language = curlang;
303 }
304 warned = false;
305 enterfile(ident(n), (Address) np->n_value);
306 for (tt = &typetable[0]; tt < &typetable[NTYPES]; tt++) {
307 *tt = nil;
308 }
309 break;
310
311 /*
312 * Textually included files.
313 */
314 case N_SOL:
315 enterfile(name, (Address) np->n_value);
316 break;
317
318 /*
319 * These symbols are assumed to have non-nil names.
320 */
321 case N_GSYM:
322 case N_FUN:
323 case N_STSYM:
324 case N_LCSYM:
325 case N_RSYM:
326 case N_PSYM:
327 case N_LSYM:
328 case N_SSYM:
329 if (index(name, ':') == nil) {
330 if (not warned) {
331 warned = true;
332 /*
333 * Shouldn't do this if user might be typing.
334 *
335 warning("old style symbol information found in \"%s\"",
336 curfilename());
337 *
338 */
339 }
340 } else {
341 entersym(name, np);
342 }
343 break;
344
345 case N_PC:
346 break;
347
348 default:
349 if (name != nil) {
350 printf("%s, ", name);
351 }
352 printf("ntype %2x, desc %x, value %x\n",
353 np->n_type, np->n_desc, np->n_value);
354 break;
355 }
356}
357
358/*
359 * Check to see if a global _name is already in the symbol table,
360 * if not then insert it.
361 */
362
363private check_global(name, np)
364String name;
365register struct nlist *np;
366{
367 register Name n;
368 register Symbol t;
369
370 if (not streq(name, "end")) {
371 n = identname(name, true);
372 if ((np->n_type&N_TYPE) == N_TEXT) {
373 find(t, n) where
374 t->level == program->level and isblock(t)
375 endfind(t);
376 if (t == nil) {
377 t = insert(n);
378 t->language = findlanguage(".s");
379 t->class = FUNC;
380 t->type = t_int;
381 t->block = curblock;
382 t->level = program->level;
383 }
384 t->symvalue.funcv.beginaddr = np->n_value;
385 newfunc(t);
386 findbeginning(t);
387 } else {
388 find(t, n) where
389 t->class == VAR and t->level == program->level
390 endfind(t);
391 if (t == nil) {
392 t = insert(n);
393 t->language = findlanguage(".s");
394 t->class = VAR;
395 t->type = t_int;
396 t->block = curblock;
397 t->level = program->level;
398 }
399 t->symvalue.offset = np->n_value;
400 }
401 }
402}
403
404/*
405 * Check to see if a local _name is known in the current scope.
406 * If not then enter it.
407 */
408
409private check_local(name, np)
410String name;
411register struct nlist *np;
412{
413 register Name n;
414 register Symbol t, cur;
415
416 n = identname(name, true);
417 cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
418 find(t, n) where t->block == cur endfind(t);
419 if (t == nil) {
420 t = insert(n);
421 t->language = findlanguage(".s");
422 t->type = t_int;
423 t->block = cur;
424 t->level = cur->level;
425 if ((np->n_type&N_TYPE) == N_TEXT) {
426 t->class = FUNC;
427 t->symvalue.funcv.beginaddr = np->n_value;
428 newfunc(t);
429 findbeginning(t);
430 } else {
431 t->class = VAR;
432 t->symvalue.offset = np->n_value;
433 }
434 }
435}
436
437/*
438 * Check to see if a symbol corresponds to a object file name.
439 * For some reason these are listed as in the text segment.
440 */
441
442private check_filename(name)
443String name;
444{
445 register String mname;
446 register Integer i;
447 register Symbol s;
448
449 mname = strdup(name);
450 i = strlen(mname) - 2;
451 if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
452 mname[i] = '\0';
453 --i;
454 while (mname[i] != '/' and i >= 0) {
455 --i;
456 }
457 s = insert(identname(&mname[i+1], true));
458 s->language = findlanguage(".s");
459 s->class = MODULE;
460 if (curblock->class != PROG) {
461 exitblock();
462 if (curblock->class != PROG) {
463 exitblock();
464 }
465 }
466 enterblock(s);
467 curmodule = s;
468 }
469}
470
471/*
472 * Put an nlist into the symbol table.
473 * If it's already there just add the associated information.
474 *
475 * Type information is encoded in the name following a ":".
476 */
477
478private Symbol constype();
479private Char *curchar;
480
481#define skipchar(ptr, ch) { \
482 if (*ptr != ch) { \
483 panic("expected char '%c', found char '%c'", ch, *ptr); \
484 } \
485 ++ptr; \
486}
487
488private entersym(str, np)
489String str;
490struct nlist *np;
491{
492 register Symbol s;
493 register char *p;
494 register int c;
495 register Name n;
496 register Integer i;
497 Boolean knowtype, isnew;
498 Symclass class;
499 Integer level;
500
501 p = index(str, ':');
502 *p = '\0';
503 c = *(p+1);
504 n = identname(str, true);
505 if (index("FfGV", c) != nil) {
506 if (c == 'F' or c == 'f') {
507 class = FUNC;
508 } else {
509 class = VAR;
510 }
511 level = (c == 'f' ? curmodule->level : program->level);
512 find(s, n) where s->level == level and s->class == class endfind(s);
513 if (s == nil) {
514 isnew = true;
515 s = insert(n);
516 } else {
517 isnew = false;
518 }
519 } else {
520 isnew = true;
521 s = insert(n);
522 }
523
524 /*
525 * Default attributes.
526 */
527 s->language = curlang;
528 s->class = VAR;
529 s->block = curblock;
530 s->level = curlevel;
531 s->symvalue.offset = np->n_value;
532 curchar = p + 2;
533 knowtype = false;
534 switch (c) {
535 case 't': /* type name */
536 s->class = TYPE;
537 i = getint();
538 if (i == 0) {
539 panic("bad input on type \"%s\" at \"%s\"", symname(s),
540 curchar);
541 } else if (i >= NTYPES) {
542 panic("too many types in file \"%s\"", curfilename());
543 }
544 /*
545 * A hack for C typedefs that don't create new types,
546 * e.g. typedef unsigned int Hashvalue;
547 */
548 if (*curchar == '\0') {
549 s->type = typetable[i];
550 if (s->type == nil) {
551 panic("nil type for %d", i);
552 }
553 knowtype = true;
554 } else {
555 typetable[i] = s;
556 skipchar(curchar, '=');
557 }
558 break;
559
560 case 'T': /* tag */
561 s->class = TAG;
562 i = getint();
563 if (i == 0) {
564 panic("bad input on tag \"%s\" at \"%s\"", symname(s),
565 curchar);
566 } else if (i >= NTYPES) {
567 panic("too many types in file \"%s\"", curfilename());
568 }
569 if (typetable[i] != nil) {
570 typetable[i]->language = curlang;
571 typetable[i]->class = TYPE;
572 typetable[i]->type = s;
573 } else {
574 typetable[i] = s;
575 }
576 skipchar(curchar, '=');
577 break;
578
579 case 'F': /* public function */
580 case 'f': /* private function */
581 s->class = FUNC;
582 if (curblock->class == FUNC or curblock->class == PROC) {
583 exitblock();
584 }
585 enterblock(s);
586 if (c == 'F') {
587 s->level = program->level;
588 isnew = false;
589 }
590 curparam = s;
591 if (isnew) {
592 s->symvalue.funcv.beginaddr = np->n_value;
593 newfunc(s);
594 findbeginning(s);
595 }
596 break;
597
598 case 'G': /* public variable */
599 s->level = program->level;
600 break;
601
602 case 'S': /* private variable */
603 s->level = curmodule->level;
604 s->block = curmodule;
605 break;
606
607 case 'V': /* own variable */
608 s->level = 2;
609 break;
610
611 case 'r': /* register variable */
612 s->level = -(s->level);
613 break;
614
615 case 'p': /* parameter variable */
616 curparam->chain = s;
617 curparam = s;
618 break;
619
620 case 'v': /* varies parameter */
621 s->class = REF;
622 s->symvalue.offset = np->n_value;
623 curparam->chain = s;
624 curparam = s;
625 break;
626
627 default: /* local variable */
628 --curchar;
629 break;
630 }
631 if (not knowtype) {
632 s->type = constype(nil);
633 if (s->class == TAG) {
634 addtag(s);
635 }
636 }
637 if (tracesyms) {
638 printdecl(s);
639 fflush(stdout);
640 }
641}
642
643/*
644 * Construct a type out of a string encoding.
645 *
646 * The forms of the string are
647 *
648 * <number>
649 * <number>=<type>
650 * r<type>;<number>;<number> $ subrange
651 * a<type>;<type> $ array[index] of element
652 * s{<name>:<type>;<number>;<number>} $ record
653 * *<type> $ pointer
654 */
655
656private Symbol constype(type)
657Symbol type;
658{
659 register Symbol t, u;
660 register Char *p, *cur;
661 register Integer n;
662 Integer b;
663 Name name;
664 Char class;
665
666 b = curlevel;
667 if (isdigit(*curchar)) {
668 n = getint();
669 if (n == 0) {
670 panic("bad type number at \"%s\"", curchar);
671 } else if (n >= NTYPES) {
672 panic("too many types in file \"%s\"", curfilename());
673 }
674 if (*curchar == '=') {
675 if (typetable[n] != nil) {
676 t = typetable[n];
677 } else {
678 t = symbol_alloc();
679 typetable[n] = t;
680 }
681 ++curchar;
682 constype(t);
683 } else {
684 t = typetable[n];
685 if (t == nil) {
686 t = symbol_alloc();
687 typetable[n] = t;
688 }
689 }
690 } else {
691 if (type == nil) {
692 t = symbol_alloc();
693 } else {
694 t = type;
695 }
696 t->language = curlang;
697 t->level = b;
698 class = *curchar++;
699 switch (class) {
700 case 'r':
701 t->class = RANGE;
702 t->type = constype(nil);
703 skipchar(curchar, ';');
704 t->symvalue.rangev.lower = getint();
705 skipchar(curchar, ';');
706 t->symvalue.rangev.upper = getint();
707 break;
708
709 case 'a':
710 t->class = ARRAY;
711 t->chain = constype(nil);
712 skipchar(curchar, ';');
713 t->type = constype(nil);
714 break;
715
716 case 's':
717 case 'u':
718 t->class = (class == 's') ? RECORD : VARNT;
719 t->symvalue.offset = getint();
720 u = t;
721 cur = curchar;
722 while (*cur != ';' and *cur != '\0') {
723 p = index(cur, ':');
724 if (p == nil) {
725 panic("index(\"%s\", ':') failed", curchar);
726 }
727 *p = '\0';
728 name = identname(cur, true);
729 u->chain = newSymbol(name, b, FIELD, nil, nil);
730 cur = p + 1;
731 u = u->chain;
732 u->language = curlang;
733 curchar = cur;
734 u->type = constype(nil);
735 skipchar(curchar, ',');
736 u->symvalue.field.offset = getint();
737 skipchar(curchar, ',');
738 u->symvalue.field.length = getint();
739 skipchar(curchar, ';');
740 cur = curchar;
741 }
742 if (*cur == ';') {
743 ++cur;
744 }
745 curchar = cur;
746 break;
747
748 case 'e':
749 t->class = SCAL;
750 u = t;
751 while (*curchar != ';' and *curchar != '\0') {
752 p = index(curchar, ':');
753 assert(p != nil);
754 *p = '\0';
755 u->chain = insert(identname(curchar, true));
756 curchar = p + 1;
757 u = u->chain;
758 u->language = curlang;
759 u->class = CONST;
760 u->level = b;
761 u->block = curblock;
762 u->type = t;
763 u->symvalue.iconval = getint();
764 skipchar(curchar, ',');
765 }
766 break;
767
768 case '*':
769 t->class = PTR;
770 t->type = constype(nil);
771 break;
772
773 case 'f':
774 t->class = FUNC;
775 t->type = constype(nil);
776 break;
777
778 default:
779 badcaseval(class);
780 }
781 }
782 return t;
783}
784
785/*
786 * Read an integer from the current position in the type string.
787 */
788
789private Integer getint()
790{
791 register Integer n;
792 register char *p;
793 register Boolean isneg;
794
795 n = 0;
796 p = curchar;
797 if (*p == '-') {
798 isneg = true;
799 ++p;
800 } else {
801 isneg = false;
802 }
803 while (isdigit(*p)) {
804 n = 10*n + (*p - '0');
805 ++p;
806 }
807 curchar = p;
808 return isneg ? (-n) : n;
809}
810
811/*
812 * Add a tag name. This is a kludge to be able to refer
813 * to tags that have the same name as some other symbol
814 * in the same block.
815 */
816
817private addtag(s)
818register Symbol s;
819{
820 register Symbol t;
821 char buf[100];
822
823 sprintf(buf, "$$%.90s", ident(s->name));
824 t = insert(identname(buf, false));
825 t->language = s->language;
826 t->class = TAG;
827 t->type = s->type;
828 t->block = s->block;
829}
830
831/*
832 * Allocate file and line tables and initialize indices.
833 */
834
835private allocmaps(nf, nl)
836Integer nf, nl;
837{
838 if (filetab != nil) {
839 dispose(filetab);
840 }
841 if (linetab != nil) {
842 dispose(linetab);
843 }
844 filetab = newarr(Filetab, nf);
845 linetab = newarr(Linetab, nl);
846 filep = filetab;
847 linep = linetab;
848}
849
850/*
851 * Add a file to the file table.
852 */
853
854private enterfile(filename, addr)
855String filename;
856Address addr;
857{
858 if (addr != curfaddr) {
859 filep->addr = addr;
860 filep->filename = filename;
861 filep->lineindex = linep - linetab;
862 ++filep;
863 curfaddr = addr;
864 }
865}
866
867/*
868 * Since we only estimated the number of lines (and it was a poor
869 * estimation) and since we need to know the exact number of lines
870 * to do a binary search, we set it when we're done.
871 */
872
873private setnlines()
874{
875 nlhdr.nlines = linep - linetab;
876}
877
878/*
879 * Similarly for nfiles ...
880 */
881
882private setnfiles()
883{
884 nlhdr.nfiles = filep - filetab;
885 setsource(filetab[0].filename);
886}