changed allocation stuff to use bzero rather than have static
[unix-history] / usr / src / old / dbx / object.c
CommitLineData
2c3a9a86
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
7df2b2eb 3static char sccsid[] = "@(#)object.c 1.3 %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
7df2b2eb
ML
348 case N_LENG:
349 /*
350 * Should complain out this, obviously the wrong symbol format.
351 */
352 break;
353
2c3a9a86
ML
354 default:
355 if (name != nil) {
356 printf("%s, ", name);
357 }
358 printf("ntype %2x, desc %x, value %x\n",
359 np->n_type, np->n_desc, np->n_value);
360 break;
361 }
362}
363
364/*
365 * Check to see if a global _name is already in the symbol table,
366 * if not then insert it.
367 */
368
369private check_global(name, np)
370String name;
371register struct nlist *np;
372{
373 register Name n;
374 register Symbol t;
375
376 if (not streq(name, "end")) {
377 n = identname(name, true);
378 if ((np->n_type&N_TYPE) == N_TEXT) {
379 find(t, n) where
380 t->level == program->level and isblock(t)
381 endfind(t);
382 if (t == nil) {
383 t = insert(n);
384 t->language = findlanguage(".s");
385 t->class = FUNC;
386 t->type = t_int;
387 t->block = curblock;
388 t->level = program->level;
389 }
390 t->symvalue.funcv.beginaddr = np->n_value;
391 newfunc(t);
392 findbeginning(t);
393 } else {
394 find(t, n) where
395 t->class == VAR and t->level == program->level
396 endfind(t);
397 if (t == nil) {
398 t = insert(n);
399 t->language = findlanguage(".s");
400 t->class = VAR;
401 t->type = t_int;
402 t->block = curblock;
403 t->level = program->level;
404 }
405 t->symvalue.offset = np->n_value;
406 }
407 }
408}
409
410/*
411 * Check to see if a local _name is known in the current scope.
412 * If not then enter it.
413 */
414
415private check_local(name, np)
416String name;
417register struct nlist *np;
418{
419 register Name n;
420 register Symbol t, cur;
421
422 n = identname(name, true);
423 cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
424 find(t, n) where t->block == cur endfind(t);
425 if (t == nil) {
426 t = insert(n);
427 t->language = findlanguage(".s");
428 t->type = t_int;
429 t->block = cur;
430 t->level = cur->level;
431 if ((np->n_type&N_TYPE) == N_TEXT) {
432 t->class = FUNC;
433 t->symvalue.funcv.beginaddr = np->n_value;
434 newfunc(t);
435 findbeginning(t);
436 } else {
437 t->class = VAR;
438 t->symvalue.offset = np->n_value;
439 }
440 }
441}
442
443/*
444 * Check to see if a symbol corresponds to a object file name.
445 * For some reason these are listed as in the text segment.
446 */
447
448private check_filename(name)
449String name;
450{
451 register String mname;
452 register Integer i;
453 register Symbol s;
454
455 mname = strdup(name);
456 i = strlen(mname) - 2;
457 if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
458 mname[i] = '\0';
459 --i;
460 while (mname[i] != '/' and i >= 0) {
461 --i;
462 }
463 s = insert(identname(&mname[i+1], true));
464 s->language = findlanguage(".s");
465 s->class = MODULE;
466 if (curblock->class != PROG) {
467 exitblock();
468 if (curblock->class != PROG) {
469 exitblock();
470 }
471 }
472 enterblock(s);
473 curmodule = s;
474 }
475}
476
477/*
478 * Put an nlist into the symbol table.
479 * If it's already there just add the associated information.
480 *
481 * Type information is encoded in the name following a ":".
482 */
483
484private Symbol constype();
485private Char *curchar;
486
487#define skipchar(ptr, ch) { \
488 if (*ptr != ch) { \
489 panic("expected char '%c', found char '%c'", ch, *ptr); \
490 } \
491 ++ptr; \
492}
493
494private entersym(str, np)
495String str;
496struct nlist *np;
497{
498 register Symbol s;
499 register char *p;
500 register int c;
501 register Name n;
502 register Integer i;
503 Boolean knowtype, isnew;
504 Symclass class;
505 Integer level;
506
507 p = index(str, ':');
508 *p = '\0';
509 c = *(p+1);
510 n = identname(str, true);
511 if (index("FfGV", c) != nil) {
512 if (c == 'F' or c == 'f') {
513 class = FUNC;
514 } else {
515 class = VAR;
516 }
517 level = (c == 'f' ? curmodule->level : program->level);
518 find(s, n) where s->level == level and s->class == class endfind(s);
519 if (s == nil) {
520 isnew = true;
521 s = insert(n);
522 } else {
523 isnew = false;
524 }
525 } else {
526 isnew = true;
527 s = insert(n);
528 }
529
530 /*
531 * Default attributes.
532 */
533 s->language = curlang;
534 s->class = VAR;
535 s->block = curblock;
536 s->level = curlevel;
537 s->symvalue.offset = np->n_value;
538 curchar = p + 2;
539 knowtype = false;
540 switch (c) {
541 case 't': /* type name */
542 s->class = TYPE;
543 i = getint();
544 if (i == 0) {
545 panic("bad input on type \"%s\" at \"%s\"", symname(s),
546 curchar);
547 } else if (i >= NTYPES) {
548 panic("too many types in file \"%s\"", curfilename());
549 }
550 /*
551 * A hack for C typedefs that don't create new types,
552 * e.g. typedef unsigned int Hashvalue;
553 */
554 if (*curchar == '\0') {
555 s->type = typetable[i];
556 if (s->type == nil) {
557 panic("nil type for %d", i);
558 }
559 knowtype = true;
560 } else {
561 typetable[i] = s;
562 skipchar(curchar, '=');
563 }
564 break;
565
566 case 'T': /* tag */
567 s->class = TAG;
568 i = getint();
569 if (i == 0) {
570 panic("bad input on tag \"%s\" at \"%s\"", symname(s),
571 curchar);
572 } else if (i >= NTYPES) {
573 panic("too many types in file \"%s\"", curfilename());
574 }
575 if (typetable[i] != nil) {
576 typetable[i]->language = curlang;
577 typetable[i]->class = TYPE;
578 typetable[i]->type = s;
579 } else {
580 typetable[i] = s;
581 }
582 skipchar(curchar, '=');
583 break;
584
585 case 'F': /* public function */
586 case 'f': /* private function */
587 s->class = FUNC;
588 if (curblock->class == FUNC or curblock->class == PROC) {
589 exitblock();
590 }
591 enterblock(s);
592 if (c == 'F') {
593 s->level = program->level;
594 isnew = false;
595 }
596 curparam = s;
597 if (isnew) {
598 s->symvalue.funcv.beginaddr = np->n_value;
599 newfunc(s);
600 findbeginning(s);
601 }
602 break;
603
604 case 'G': /* public variable */
605 s->level = program->level;
606 break;
607
608 case 'S': /* private variable */
609 s->level = curmodule->level;
610 s->block = curmodule;
611 break;
612
613 case 'V': /* own variable */
614 s->level = 2;
615 break;
616
617 case 'r': /* register variable */
618 s->level = -(s->level);
619 break;
620
621 case 'p': /* parameter variable */
622 curparam->chain = s;
623 curparam = s;
624 break;
625
626 case 'v': /* varies parameter */
627 s->class = REF;
628 s->symvalue.offset = np->n_value;
629 curparam->chain = s;
630 curparam = s;
631 break;
632
633 default: /* local variable */
634 --curchar;
635 break;
636 }
637 if (not knowtype) {
638 s->type = constype(nil);
639 if (s->class == TAG) {
640 addtag(s);
641 }
642 }
643 if (tracesyms) {
644 printdecl(s);
645 fflush(stdout);
646 }
647}
648
649/*
650 * Construct a type out of a string encoding.
651 *
652 * The forms of the string are
653 *
654 * <number>
655 * <number>=<type>
656 * r<type>;<number>;<number> $ subrange
657 * a<type>;<type> $ array[index] of element
658 * s{<name>:<type>;<number>;<number>} $ record
659 * *<type> $ pointer
660 */
661
662private Symbol constype(type)
663Symbol type;
664{
665 register Symbol t, u;
666 register Char *p, *cur;
667 register Integer n;
668 Integer b;
669 Name name;
670 Char class;
671
672 b = curlevel;
673 if (isdigit(*curchar)) {
674 n = getint();
675 if (n == 0) {
676 panic("bad type number at \"%s\"", curchar);
677 } else if (n >= NTYPES) {
678 panic("too many types in file \"%s\"", curfilename());
679 }
680 if (*curchar == '=') {
681 if (typetable[n] != nil) {
682 t = typetable[n];
683 } else {
684 t = symbol_alloc();
685 typetable[n] = t;
686 }
687 ++curchar;
688 constype(t);
689 } else {
690 t = typetable[n];
691 if (t == nil) {
692 t = symbol_alloc();
693 typetable[n] = t;
694 }
695 }
696 } else {
697 if (type == nil) {
698 t = symbol_alloc();
699 } else {
700 t = type;
701 }
702 t->language = curlang;
703 t->level = b;
704 class = *curchar++;
705 switch (class) {
706 case 'r':
707 t->class = RANGE;
708 t->type = constype(nil);
709 skipchar(curchar, ';');
710 t->symvalue.rangev.lower = getint();
711 skipchar(curchar, ';');
712 t->symvalue.rangev.upper = getint();
713 break;
714
715 case 'a':
716 t->class = ARRAY;
717 t->chain = constype(nil);
718 skipchar(curchar, ';');
719 t->type = constype(nil);
720 break;
721
722 case 's':
723 case 'u':
724 t->class = (class == 's') ? RECORD : VARNT;
725 t->symvalue.offset = getint();
726 u = t;
727 cur = curchar;
728 while (*cur != ';' and *cur != '\0') {
729 p = index(cur, ':');
730 if (p == nil) {
731 panic("index(\"%s\", ':') failed", curchar);
732 }
733 *p = '\0';
734 name = identname(cur, true);
735 u->chain = newSymbol(name, b, FIELD, nil, nil);
736 cur = p + 1;
737 u = u->chain;
738 u->language = curlang;
739 curchar = cur;
740 u->type = constype(nil);
741 skipchar(curchar, ',');
742 u->symvalue.field.offset = getint();
743 skipchar(curchar, ',');
744 u->symvalue.field.length = getint();
745 skipchar(curchar, ';');
746 cur = curchar;
747 }
748 if (*cur == ';') {
749 ++cur;
750 }
751 curchar = cur;
752 break;
753
754 case 'e':
755 t->class = SCAL;
756 u = t;
757 while (*curchar != ';' and *curchar != '\0') {
758 p = index(curchar, ':');
759 assert(p != nil);
760 *p = '\0';
761 u->chain = insert(identname(curchar, true));
762 curchar = p + 1;
763 u = u->chain;
764 u->language = curlang;
765 u->class = CONST;
766 u->level = b;
767 u->block = curblock;
768 u->type = t;
769 u->symvalue.iconval = getint();
770 skipchar(curchar, ',');
771 }
772 break;
773
774 case '*':
775 t->class = PTR;
776 t->type = constype(nil);
777 break;
778
779 case 'f':
780 t->class = FUNC;
781 t->type = constype(nil);
782 break;
783
784 default:
785 badcaseval(class);
786 }
787 }
788 return t;
789}
790
791/*
792 * Read an integer from the current position in the type string.
793 */
794
795private Integer getint()
796{
797 register Integer n;
798 register char *p;
799 register Boolean isneg;
800
801 n = 0;
802 p = curchar;
803 if (*p == '-') {
804 isneg = true;
805 ++p;
806 } else {
807 isneg = false;
808 }
809 while (isdigit(*p)) {
810 n = 10*n + (*p - '0');
811 ++p;
812 }
813 curchar = p;
814 return isneg ? (-n) : n;
815}
816
817/*
818 * Add a tag name. This is a kludge to be able to refer
819 * to tags that have the same name as some other symbol
820 * in the same block.
821 */
822
823private addtag(s)
824register Symbol s;
825{
826 register Symbol t;
827 char buf[100];
828
829 sprintf(buf, "$$%.90s", ident(s->name));
830 t = insert(identname(buf, false));
831 t->language = s->language;
832 t->class = TAG;
833 t->type = s->type;
834 t->block = s->block;
835}
836
837/*
838 * Allocate file and line tables and initialize indices.
839 */
840
841private allocmaps(nf, nl)
842Integer nf, nl;
843{
844 if (filetab != nil) {
845 dispose(filetab);
846 }
847 if (linetab != nil) {
848 dispose(linetab);
849 }
850 filetab = newarr(Filetab, nf);
851 linetab = newarr(Linetab, nl);
852 filep = filetab;
853 linep = linetab;
854}
855
856/*
857 * Add a file to the file table.
858 */
859
860private enterfile(filename, addr)
861String filename;
862Address addr;
863{
864 if (addr != curfaddr) {
865 filep->addr = addr;
866 filep->filename = filename;
867 filep->lineindex = linep - linetab;
868 ++filep;
869 curfaddr = addr;
870 }
871}
872
873/*
874 * Since we only estimated the number of lines (and it was a poor
875 * estimation) and since we need to know the exact number of lines
876 * to do a binary search, we set it when we're done.
877 */
878
879private setnlines()
880{
881 nlhdr.nlines = linep - linetab;
882}
883
884/*
885 * Similarly for nfiles ...
886 */
887
888private setnfiles()
889{
890 nlhdr.nfiles = filep - filetab;
891 setsource(filetab[0].filename);
892}