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