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