|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)object.c 5.1 (Berkeley) 5/31/85";
9: #endif not lint
10:
11: static char rcsid[] = "$Header: object.c,v 1.6 84/12/26 10:40:51 linton Exp $";
12:
13: /*
14: * Object code interface, mainly for extraction of symbolic information.
15: */
16:
17: #include "defs.h"
18: #include "object.h"
19: #include "stabstring.h"
20: #include "main.h"
21: #include "symbols.h"
22: #include "names.h"
23: #include "languages.h"
24: #include "mappings.h"
25: #include "lists.h"
26: #include <a.out.h>
27: #include <stab.h>
28: #include <ctype.h>
29:
30: #ifndef public
31:
32: struct {
33: unsigned int stringsize; /* size of the dumped string table */
34: unsigned int nsyms; /* number of symbols */
35: unsigned int nfiles; /* number of files */
36: unsigned int nlines; /* number of lines */
37: } nlhdr;
38:
39: #include "languages.h"
40: #include "symbols.h"
41:
42: #endif
43:
44: #ifndef N_MOD2
45: # define N_MOD2 0x50
46: #endif
47:
48: public String objname = "a.out";
49: public integer objsize;
50:
51: public Language curlang;
52: public Symbol curmodule;
53: public Symbol curparam;
54: public Symbol curcomm;
55: public Symbol commchain;
56:
57: private char *stringtab;
58: private struct nlist *curnp;
59: private Boolean warned;
60: private Boolean strip_ = false;
61:
62: private Filetab *filep;
63: private Linetab *linep, *prevlinep;
64:
65: public String curfilename ()
66: {
67: return ((filep-1)->filename);
68: }
69:
70: /*
71: * Blocks are figured out on the fly while reading the symbol table.
72: */
73:
74: #define MAXBLKDEPTH 25
75:
76: public Symbol curblock;
77:
78: private Symbol blkstack[MAXBLKDEPTH];
79: private integer curlevel;
80: private integer bnum, nesting;
81: private Address addrstk[MAXBLKDEPTH];
82:
83: public pushBlock (b)
84: Symbol b;
85: {
86: if (curlevel >= MAXBLKDEPTH) {
87: fatal("nesting depth too large (%d)", curlevel);
88: }
89: blkstack[curlevel] = curblock;
90: ++curlevel;
91: curblock = b;
92: if (traceblocks) {
93: printf("entering block %s\n", symname(b));
94: }
95: }
96:
97: /*
98: * Change the current block with saving the previous one,
99: * since it is assumed that the symbol for the current one is to be deleted.
100: */
101:
102: public changeBlock (b)
103: Symbol b;
104: {
105: curblock = b;
106: }
107:
108: public enterblock (b)
109: Symbol b;
110: {
111: if (curblock == nil) {
112: b->level = 1;
113: } else {
114: b->level = curblock->level + 1;
115: }
116: b->block = curblock;
117: pushBlock(b);
118: }
119:
120: public exitblock ()
121: {
122: if (curblock->class == FUNC or curblock->class == PROC) {
123: if (prevlinep != linep) {
124: curblock->symvalue.funcv.src = true;
125: }
126: }
127: if (curlevel <= 0) {
128: panic("nesting depth underflow (%d)", curlevel);
129: }
130: --curlevel;
131: if (traceblocks) {
132: printf("exiting block %s\n", symname(curblock));
133: }
134: curblock = blkstack[curlevel];
135: }
136:
137: /*
138: * Enter a source line or file name reference into the appropriate table.
139: * Expanded inline to reduce procedure calls.
140: *
141: * private enterline (linenumber, address)
142: * Lineno linenumber;
143: * Address address;
144: * ...
145: */
146:
147: #define enterline(linenumber, address) \
148: { \
149: register Linetab *lp; \
150: \
151: lp = linep - 1; \
152: if (linenumber != lp->line) { \
153: if (address != lp->addr) { \
154: ++lp; \
155: } \
156: lp->line = linenumber; \
157: lp->addr = address; \
158: linep = lp + 1; \
159: } \
160: }
161:
162: /*
163: * Read in the namelist from the obj file.
164: *
165: * Reads and seeks are used instead of fread's and fseek's
166: * for efficiency sake; there's a lot of data being read here.
167: */
168:
169: public readobj (file)
170: String file;
171: {
172: Fileid f;
173: struct exec hdr;
174: struct nlist nlist;
175:
176: f = open(file, 0);
177: if (f < 0) {
178: fatal("can't open %s", file);
179: }
180: read(f, &hdr, sizeof(hdr));
181: if (N_BADMAG(hdr)) {
182: objsize = 0;
183: nlhdr.nsyms = 0;
184: nlhdr.nfiles = 0;
185: nlhdr.nlines = 0;
186: } else {
187: objsize = hdr.a_text;
188: nlhdr.nsyms = hdr.a_syms / sizeof(nlist);
189: nlhdr.nfiles = nlhdr.nsyms;
190: nlhdr.nlines = nlhdr.nsyms;
191: }
192: if (nlhdr.nsyms > 0) {
193: lseek(f, (long) N_STROFF(hdr), 0);
194: read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize));
195: nlhdr.stringsize -= 4;
196: stringtab = newarr(char, nlhdr.stringsize);
197: read(f, stringtab, nlhdr.stringsize);
198: allocmaps(nlhdr.nfiles, nlhdr.nlines);
199: lseek(f, (long) N_SYMOFF(hdr), 0);
200: readsyms(f);
201: ordfunctab();
202: setnlines();
203: setnfiles();
204: } else {
205: initsyms();
206: }
207: close(f);
208: }
209:
210: /*
211: * Found the beginning of the externals in the object file
212: * (signified by the "-lg" or find an external), close the
213: * block for the last procedure.
214: */
215:
216: private foundglobals ()
217: {
218: if (curblock->class != PROG) {
219: exitblock();
220: if (curblock->class != PROG) {
221: exitblock();
222: }
223: }
224: enterline(0, (linep-1)->addr + 1);
225: }
226:
227: /*
228: * Read in symbols from object file.
229: */
230:
231: private readsyms (f)
232: Fileid f;
233: {
234: struct nlist *namelist;
235: register struct nlist *np, *ub;
236: register String name;
237: register Boolean afterlg;
238: integer index;
239: char *lastchar;
240:
241: initsyms();
242: namelist = newarr(struct nlist, nlhdr.nsyms);
243: read(f, namelist, nlhdr.nsyms * sizeof(struct nlist));
244: afterlg = false;
245: ub = &namelist[nlhdr.nsyms];
246: curnp = &namelist[0];
247: np = curnp;
248: while (np < ub) {
249: index = np->n_un.n_strx;
250: if (index != 0) {
251: name = &stringtab[index - 4];
252: /*
253: * If the program contains any .f files a trailing _ is stripped
254: * from the name on the assumption it was added by the compiler.
255: * This only affects names that follow the sdb N_SO entry with
256: * the .f name.
257: */
258: if (strip_ and name[0] != '\0' ) {
259: lastchar = &name[strlen(name) - 1];
260: if (*lastchar == '_') {
261: *lastchar = '\0';
262: }
263: }
264: } else {
265: name = nil;
266: }
267:
268: /*
269: * Assumptions:
270: * not an N_STAB ==> name != nil
271: * name[0] == '-' ==> name == "-lg"
272: * name[0] != '_' ==> filename or invisible
273: *
274: * The "-lg" signals the beginning of global loader symbols.
275: *
276: */
277: if ((np->n_type&N_STAB) != 0) {
278: enter_nl(name, np);
279: } else if (name[0] == '-') {
280: afterlg = true;
281: foundglobals();
282: } else if (afterlg) {
283: check_global(name, np);
284: } else if ((np->n_type&N_EXT) == N_EXT) {
285: afterlg = true;
286: foundglobals();
287: check_global(name, np);
288: } else if (name[0] == '_') {
289: check_local(&name[1], np);
290: } else if ((np->n_type&N_TEXT) == N_TEXT) {
291: check_filename(name);
292: }
293: ++curnp;
294: np = curnp;
295: }
296: dispose(namelist);
297: }
298:
299: /*
300: * Get a continuation entry from the name list.
301: * Return the beginning of the name.
302: */
303:
304: public String getcont ()
305: {
306: register integer index;
307: register String name;
308:
309: ++curnp;
310: index = curnp->n_un.n_strx;
311: if (index == 0) {
312: panic("continuation followed by empty stab");
313: }
314: name = &stringtab[index - 4];
315: return name;
316: }
317:
318: /*
319: * Initialize symbol information.
320: */
321:
322: private initsyms ()
323: {
324: curblock = nil;
325: curlevel = 0;
326: nesting = 0;
327: program = insert(identname("", true));
328: program->class = PROG;
329: program->symvalue.funcv.beginaddr = 0;
330: program->symvalue.funcv.inline = false;
331: newfunc(program, codeloc(program));
332: findbeginning(program);
333: enterblock(program);
334: curmodule = program;
335: }
336:
337: /*
338: * Free all the object file information that's being stored.
339: */
340:
341: public objfree ()
342: {
343: symbol_free();
344: /* keywords_free(); */
345: /* names_free(); */
346: /* dispose(stringtab); */
347: clrfunctab();
348: }
349:
350: /*
351: * Enter a namelist entry.
352: */
353:
354: private enter_nl (name, np)
355: String name;
356: register struct nlist *np;
357: {
358: register Symbol s;
359: register Name n;
360:
361: s = nil;
362: switch (np->n_type) {
363: /*
364: * Build a symbol for the FORTRAN common area. All GSYMS that follow
365: * will be chained in a list with the head kept in common.offset, and
366: * the tail in common.chain.
367: */
368: case N_BCOMM:
369: if (curcomm) {
370: curcomm->symvalue.common.chain = commchain;
371: }
372: n = identname(name, true);
373: curcomm = lookup(n);
374: if (curcomm == nil) {
375: curcomm = insert(n);
376: curcomm->class = COMMON;
377: curcomm->block = curblock;
378: curcomm->level = program->level;
379: curcomm->symvalue.common.chain = nil;
380: }
381: commchain = curcomm->symvalue.common.chain;
382: break;
383:
384: case N_ECOMM:
385: if (curcomm) {
386: curcomm->symvalue.common.chain = commchain;
387: curcomm = nil;
388: }
389: break;
390:
391: case N_LBRAC:
392: ++nesting;
393: addrstk[nesting] = (linep - 1)->addr;
394: break;
395:
396: case N_RBRAC:
397: --nesting;
398: if (addrstk[nesting] == NOADDR) {
399: exitblock();
400: newfunc(curblock, (linep - 1)->addr);
401: addrstk[nesting] = (linep - 1)->addr;
402: }
403: break;
404:
405: case N_SLINE:
406: enterline((Lineno) np->n_desc, (Address) np->n_value);
407: break;
408:
409: /*
410: * Source files.
411: */
412: case N_SO:
413: n = identname(name, true);
414: enterSourceModule(n, (Address) np->n_value);
415: break;
416:
417: /*
418: * Textually included files.
419: */
420: case N_SOL:
421: enterfile(name, (Address) np->n_value);
422: break;
423:
424: /*
425: * These symbols are assumed to have non-nil names.
426: */
427: case N_GSYM:
428: case N_FUN:
429: case N_STSYM:
430: case N_LCSYM:
431: case N_RSYM:
432: case N_PSYM:
433: case N_LSYM:
434: case N_SSYM:
435: case N_LENG:
436: if (index(name, ':') == nil) {
437: if (not warned) {
438: warned = true;
439: warning("old style symbol information found in \"%s\"",
440: curfilename());
441: }
442: } else {
443: entersym(name, np);
444: }
445: break;
446:
447: case N_PC:
448: case N_MOD2:
449: break;
450:
451: default:
452: printf("warning: stab entry unrecognized: ");
453: if (name != nil) {
454: printf("name %s,", name);
455: }
456: printf("ntype %2x, desc %x, value %x'\n",
457: np->n_type, np->n_desc, np->n_value);
458: break;
459: }
460: }
461:
462: /*
463: * Try to find the symbol that is referred to by the given name. Since it's
464: * an external, we need to follow a level or two of indirection.
465: */
466:
467: private Symbol findsym (n, var_isextref)
468: Name n;
469: boolean *var_isextref;
470: {
471: register Symbol r, s;
472:
473: *var_isextref = false;
474: find(s, n) where
475: (
476: s->level == program->level and (
477: s->class == EXTREF or s->class == VAR or
478: s->class == PROC or s->class == FUNC
479: )
480: ) or (
481: s->block == program and s->class == MODULE
482: )
483: endfind(s);
484: if (s == nil) {
485: r = nil;
486: } else if (s->class == EXTREF) {
487: *var_isextref = true;
488: r = s->symvalue.extref;
489: delete(s);
490:
491: /*
492: * Now check for another level of indirection that could come from
493: * a forward reference in procedure nesting information. In this case
494: * the symbol has already been deleted.
495: */
496: if (r != nil and r->class == EXTREF) {
497: r = r->symvalue.extref;
498: }
499: /*
500: } else if (s->class == MODULE) {
501: s->class = FUNC;
502: s->level = program->level;
503: r = s;
504: */
505: } else {
506: r = s;
507: }
508: return r;
509: }
510:
511: /*
512: * Create a symbol for a text symbol with no source information.
513: * We treat it as an assembly language function.
514: */
515:
516: private Symbol deffunc (n)
517: Name n;
518: {
519: Symbol f;
520:
521: f = insert(n);
522: f->language = findlanguage(".s");
523: f->class = FUNC;
524: f->type = t_int;
525: f->block = curblock;
526: f->level = program->level;
527: f->symvalue.funcv.src = false;
528: f->symvalue.funcv.inline = false;
529: return f;
530: }
531:
532: /*
533: * Create a symbol for a data or bss symbol with no source information.
534: * We treat it as an assembly language variable.
535: */
536:
537: private Symbol defvar (n)
538: Name n;
539: {
540: Symbol v;
541:
542: v = insert(n);
543: v->language = findlanguage(".s");
544: v->class = VAR;
545: v->type = t_int;
546: v->level = program->level;
547: v->block = curblock;
548: return v;
549: }
550:
551: /*
552: * Update a symbol entry with a text address.
553: */
554:
555: private updateTextSym (s, name, addr)
556: Symbol s;
557: char *name;
558: Address addr;
559: {
560: if (s->class == VAR) {
561: s->symvalue.offset = addr;
562: } else {
563: s->symvalue.funcv.beginaddr = addr;
564: if (name[0] == '_') {
565: newfunc(s, codeloc(s));
566: findbeginning(s);
567: }
568: }
569: }
570:
571: /*
572: * Check to see if a global _name is already in the symbol table,
573: * if not then insert it.
574: */
575:
576: private check_global (name, np)
577: String name;
578: register struct nlist *np;
579: {
580: register Name n;
581: register Symbol t, u;
582: char buf[4096];
583: boolean isextref;
584: integer count;
585:
586: if (not streq(name, "_end")) {
587: if (name[0] == '_') {
588: n = identname(&name[1], true);
589: } else {
590: n = identname(name, true);
591: if (lookup(n) != nil) {
592: sprintf(buf, "$%s", name);
593: n = identname(buf, false);
594: }
595: }
596: if ((np->n_type&N_TYPE) == N_TEXT) {
597: count = 0;
598: t = findsym(n, &isextref);
599: while (isextref) {
600: ++count;
601: updateTextSym(t, name, np->n_value);
602: t = findsym(n, &isextref);
603: }
604: if (count == 0) {
605: if (t == nil) {
606: t = deffunc(n);
607: updateTextSym(t, name, np->n_value);
608: if (tracesyms) {
609: printdecl(t);
610: }
611: } else {
612: if (t->class == MODULE) {
613: u = t;
614: t = deffunc(n);
615: t->block = u;
616: if (tracesyms) {
617: printdecl(t);
618: }
619: }
620: updateTextSym(t, name, np->n_value);
621: }
622: }
623: } else if ((np->n_type&N_TYPE) == N_BSS) {
624: find(t, n) where
625: t->class == COMMON
626: endfind(t);
627: if (t != nil) {
628: u = (Symbol) t->symvalue.common.offset;
629: while (u != nil) {
630: u->symvalue.offset = u->symvalue.common.offset+np->n_value;
631: u = u->symvalue.common.chain;
632: }
633: } else {
634: check_var(np, n);
635: }
636: } else {
637: check_var(np, n);
638: }
639: }
640: }
641:
642: /*
643: * Check to see if a namelist entry refers to a variable.
644: * If not, create a variable for the entry. In any case,
645: * set the offset of the variable according to the value field
646: * in the entry.
647: *
648: * If the external name has been referred to by several other symbols,
649: * we must update each of them.
650: */
651:
652: private check_var (np, n)
653: struct nlist *np;
654: register Name n;
655: {
656: register Symbol t, u, next;
657: Symbol conflict;
658:
659: t = lookup(n);
660: if (t == nil) {
661: t = defvar(n);
662: t->symvalue.offset = np->n_value;
663: if (tracesyms) {
664: printdecl(t);
665: }
666: } else {
667: conflict = nil;
668: do {
669: next = t->next_sym;
670: if (t->name == n) {
671: if (t->class == MODULE and t->block == program) {
672: conflict = t;
673: } else if (t->class == EXTREF and t->level == program->level) {
674: u = t->symvalue.extref;
675: while (u != nil and u->class == EXTREF) {
676: u = u->symvalue.extref;
677: }
678: u->symvalue.offset = np->n_value;
679: delete(t);
680: } else if (t->level == program->level and
681: (t->class == VAR or t->class == PROC or t->class == FUNC)
682: ) {
683: conflict = nil;
684: t->symvalue.offset = np->n_value;
685: }
686: }
687: t = next;
688: } while (t != nil);
689: if (conflict != nil) {
690: u = defvar(n);
691: u->block = conflict;
692: u->symvalue.offset = np->n_value;
693: }
694: }
695: }
696:
697: /*
698: * Check to see if a local _name is known in the current scope.
699: * If not then enter it.
700: */
701:
702: private check_local (name, np)
703: String name;
704: register struct nlist *np;
705: {
706: register Name n;
707: register Symbol t, cur;
708:
709: n = identname(name, true);
710: cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
711: find(t, n) where t->block == cur endfind(t);
712: if (t == nil) {
713: t = insert(n);
714: t->language = findlanguage(".s");
715: t->type = t_int;
716: t->block = cur;
717: t->level = cur->level;
718: if ((np->n_type&N_TYPE) == N_TEXT) {
719: t->class = FUNC;
720: t->symvalue.funcv.src = false;
721: t->symvalue.funcv.inline = false;
722: t->symvalue.funcv.beginaddr = np->n_value;
723: newfunc(t, codeloc(t));
724: findbeginning(t);
725: } else {
726: t->class = VAR;
727: t->symvalue.offset = np->n_value;
728: }
729: }
730: }
731:
732: /*
733: * Check to see if a symbol corresponds to a object file name.
734: * For some reason these are listed as in the text segment.
735: */
736:
737: private check_filename (name)
738: String name;
739: {
740: register String mname;
741: register integer i;
742: Name n;
743: Symbol s;
744:
745: mname = strdup(name);
746: i = strlen(mname) - 2;
747: if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
748: mname[i] = '\0';
749: --i;
750: while (mname[i] != '/' and i >= 0) {
751: --i;
752: }
753: n = identname(&mname[i+1], true);
754: find(s, n) where s->block == program and s->class == MODULE endfind(s);
755: if (s == nil) {
756: s = insert(n);
757: s->language = findlanguage(".s");
758: s->class = MODULE;
759: s->symvalue.funcv.beginaddr = 0;
760: findbeginning(s);
761: }
762: if (curblock->class != PROG) {
763: exitblock();
764: if (curblock->class != PROG) {
765: exitblock();
766: }
767: }
768: enterblock(s);
769: curmodule = s;
770: }
771: }
772:
773: /*
774: * Check to see if a symbol is about to be defined within an unnamed block.
775: * If this happens, we create a procedure for the unnamed block, make it
776: * "inline" so that tracebacks don't associate an activation record with it,
777: * and enter it into the function table so that it will be detected
778: * by "whatblock".
779: */
780:
781: public chkUnnamedBlock ()
782: {
783: register Symbol s;
784: static int bnum = 0;
785: char buf[100];
786: Address startaddr;
787:
788: if (nesting > 0 and addrstk[nesting] != NOADDR) {
789: startaddr = (linep - 1)->addr;
790: ++bnum;
791: sprintf(buf, "$b%d", bnum);
792: s = insert(identname(buf, false));
793: s->language = curlang;
794: s->class = PROC;
795: s->symvalue.funcv.src = false;
796: s->symvalue.funcv.inline = true;
797: s->symvalue.funcv.beginaddr = startaddr;
798: enterblock(s);
799: newfunc(s, startaddr);
800: addrstk[nesting] = NOADDR;
801: }
802: }
803:
804: /*
805: * Compilation unit. C associates scope with filenames
806: * so we treat them as "modules". The filename without
807: * the suffix is used for the module name.
808: *
809: * Because there is no explicit "end-of-block" mark in
810: * the object file, we must exit blocks for the current
811: * procedure and module.
812: */
813:
814: private enterSourceModule (n, addr)
815: Name n;
816: Address addr;
817: {
818: register Symbol s;
819: Name nn;
820: String mname, suffix;
821:
822: mname = strdup(ident(n));
823: if (rindex(mname, '/') != nil) {
824: mname = rindex(mname, '/') + 1;
825: }
826: suffix = rindex(mname, '.');
827: curlang = findlanguage(suffix);
828: if (curlang == findlanguage(".f")) {
829: strip_ = true;
830: }
831: if (suffix != nil) {
832: *suffix = '\0';
833: }
834: if (not (*language_op(curlang, L_HASMODULES))()) {
835: if (curblock->class != PROG) {
836: exitblock();
837: if (curblock->class != PROG) {
838: exitblock();
839: }
840: }
841: nn = identname(mname, true);
842: if (curmodule == nil or curmodule->name != nn) {
843: s = insert(nn);
844: s->class = MODULE;
845: s->symvalue.funcv.beginaddr = 0;
846: findbeginning(s);
847: } else {
848: s = curmodule;
849: }
850: s->language = curlang;
851: enterblock(s);
852: curmodule = s;
853: }
854: if (program->language == nil) {
855: program->language = curlang;
856: }
857: warned = false;
858: enterfile(ident(n), addr);
859: initTypeTable();
860: }
861:
862: /*
863: * Allocate file and line tables and initialize indices.
864: */
865:
866: private allocmaps (nf, nl)
867: integer nf, nl;
868: {
869: if (filetab != nil) {
870: dispose(filetab);
871: }
872: if (linetab != nil) {
873: dispose(linetab);
874: }
875: filetab = newarr(Filetab, nf);
876: linetab = newarr(Linetab, nl);
877: filep = filetab;
878: linep = linetab;
879: }
880:
881: /*
882: * Add a file to the file table.
883: *
884: * If the new address is the same as the previous file address
885: * this routine used to not enter the file, but this caused some
886: * problems so it has been removed. It's not clear that this in
887: * turn may not also cause a problem.
888: */
889:
890: private enterfile (filename, addr)
891: String filename;
892: Address addr;
893: {
894: filep->addr = addr;
895: filep->filename = filename;
896: filep->lineindex = linep - linetab;
897: ++filep;
898: }
899:
900: /*
901: * Since we only estimated the number of lines (and it was a poor
902: * estimation) and since we need to know the exact number of lines
903: * to do a binary search, we set it when we're done.
904: */
905:
906: private setnlines ()
907: {
908: nlhdr.nlines = linep - linetab;
909: }
910:
911: /*
912: * Similarly for nfiles ...
913: */
914:
915: private setnfiles ()
916: {
917: nlhdr.nfiles = filep - filetab;
918: setsource(filetab[0].filename);
919: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.