Commit | Line | Data |
---|---|---|
2a24676e DF |
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 | */ | |
2c3a9a86 | 6 | |
2a24676e DF |
7 | #ifndef lint |
8 | static char sccsid[] = "@(#)object.c 5.1 (Berkeley) %G%"; | |
9 | #endif not lint | |
0022c355 ML |
10 | |
11 | static char rcsid[] = "$Header: object.c,v 1.6 84/12/26 10:40:51 linton Exp $"; | |
2c3a9a86 ML |
12 | |
13 | /* | |
14 | * Object code interface, mainly for extraction of symbolic information. | |
15 | */ | |
16 | ||
17 | #include "defs.h" | |
18 | #include "object.h" | |
2fd0f574 | 19 | #include "stabstring.h" |
2c3a9a86 ML |
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 | ||
2fd0f574 SL |
39 | #include "languages.h" |
40 | #include "symbols.h" | |
41 | ||
42 | #endif | |
43 | ||
44 | #ifndef N_MOD2 | |
45 | # define N_MOD2 0x50 | |
2c3a9a86 ML |
46 | #endif |
47 | ||
48 | public String objname = "a.out"; | |
2fd0f574 SL |
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; | |
2c3a9a86 | 56 | |
2fd0f574 SL |
57 | private char *stringtab; |
58 | private struct nlist *curnp; | |
2c3a9a86 | 59 | private Boolean warned; |
d5eceaed | 60 | private Boolean strip_ = false; |
2c3a9a86 ML |
61 | |
62 | private Filetab *filep; | |
cc4262e8 | 63 | private Linetab *linep, *prevlinep; |
2c3a9a86 | 64 | |
2fd0f574 SL |
65 | public String curfilename () |
66 | { | |
67 | return ((filep-1)->filename); | |
68 | } | |
2c3a9a86 ML |
69 | |
70 | /* | |
71 | * Blocks are figured out on the fly while reading the symbol table. | |
72 | */ | |
73 | ||
74 | #define MAXBLKDEPTH 25 | |
75 | ||
2fd0f574 SL |
76 | public Symbol curblock; |
77 | ||
2c3a9a86 | 78 | private Symbol blkstack[MAXBLKDEPTH]; |
2fd0f574 SL |
79 | private integer curlevel; |
80 | private integer bnum, nesting; | |
7005bb75 | 81 | private Address addrstk[MAXBLKDEPTH]; |
2c3a9a86 | 82 | |
2fd0f574 SL |
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 | } | |
2c3a9a86 ML |
95 | } |
96 | ||
0022c355 ML |
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 | ||
2fd0f574 SL |
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]; | |
2c3a9a86 ML |
135 | } |
136 | ||
137 | /* | |
138 | * Enter a source line or file name reference into the appropriate table. | |
139 | * Expanded inline to reduce procedure calls. | |
140 | * | |
2fd0f574 | 141 | * private enterline (linenumber, address) |
2c3a9a86 ML |
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 | ||
2c3a9a86 ML |
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 | ||
2fd0f574 | 169 | public readobj (file) |
2c3a9a86 ML |
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)); | |
0022c355 ML |
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 | } | |
7005bb75 ML |
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(); | |
0022c355 ML |
204 | } else { |
205 | initsyms(); | |
7005bb75 | 206 | } |
2c3a9a86 ML |
207 | close(f); |
208 | } | |
209 | ||
0022c355 ML |
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 | ||
2c3a9a86 ML |
227 | /* |
228 | * Read in symbols from object file. | |
229 | */ | |
230 | ||
2fd0f574 | 231 | private readsyms (f) |
2c3a9a86 ML |
232 | Fileid f; |
233 | { | |
234 | struct nlist *namelist; | |
235 | register struct nlist *np, *ub; | |
2c3a9a86 ML |
236 | register String name; |
237 | register Boolean afterlg; | |
2fd0f574 SL |
238 | integer index; |
239 | char *lastchar; | |
2c3a9a86 ML |
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]; | |
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) { | |
278 | enter_nl(name, np); | |
279 | } else if (name[0] == '-') { | |
280 | afterlg = true; | |
0022c355 | 281 | foundglobals(); |
2d99de0e | 282 | } else if (afterlg) { |
0022c355 ML |
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); | |
2d99de0e ML |
288 | } else if (name[0] == '_') { |
289 | check_local(&name[1], np); | |
2c3a9a86 ML |
290 | } else if ((np->n_type&N_TEXT) == N_TEXT) { |
291 | check_filename(name); | |
292 | } | |
2fd0f574 SL |
293 | ++curnp; |
294 | np = curnp; | |
2c3a9a86 ML |
295 | } |
296 | dispose(namelist); | |
297 | } | |
298 | ||
2fd0f574 SL |
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 | ||
2c3a9a86 ML |
318 | /* |
319 | * Initialize symbol information. | |
320 | */ | |
321 | ||
2fd0f574 | 322 | private initsyms () |
2c3a9a86 ML |
323 | { |
324 | curblock = nil; | |
325 | curlevel = 0; | |
7005bb75 | 326 | nesting = 0; |
2fd0f574 | 327 | program = insert(identname("", true)); |
2c3a9a86 | 328 | program->class = PROG; |
e7df52e4 | 329 | program->symvalue.funcv.beginaddr = 0; |
7005bb75 ML |
330 | program->symvalue.funcv.inline = false; |
331 | newfunc(program, codeloc(program)); | |
2c3a9a86 ML |
332 | findbeginning(program); |
333 | enterblock(program); | |
334 | curmodule = program; | |
2c3a9a86 ML |
335 | } |
336 | ||
337 | /* | |
338 | * Free all the object file information that's being stored. | |
339 | */ | |
340 | ||
2fd0f574 | 341 | public objfree () |
2c3a9a86 ML |
342 | { |
343 | symbol_free(); | |
0022c355 ML |
344 | /* keywords_free(); */ |
345 | /* names_free(); */ | |
346 | /* dispose(stringtab); */ | |
2c3a9a86 ML |
347 | clrfunctab(); |
348 | } | |
349 | ||
350 | /* | |
351 | * Enter a namelist entry. | |
352 | */ | |
353 | ||
2fd0f574 | 354 | private enter_nl (name, np) |
2c3a9a86 ML |
355 | String name; |
356 | register struct nlist *np; | |
357 | { | |
358 | register Symbol s; | |
2fd0f574 | 359 | register Name n; |
2c3a9a86 ML |
360 | |
361 | s = nil; | |
2c3a9a86 | 362 | switch (np->n_type) { |
7005bb75 ML |
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 | */ | |
214731a7 ML |
368 | case N_BCOMM: |
369 | if (curcomm) { | |
370 | curcomm->symvalue.common.chain = commchain; | |
d5eceaed | 371 | } |
2fd0f574 | 372 | n = identname(name, true); |
d5eceaed | 373 | curcomm = lookup(n); |
214731a7 ML |
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; | |
d5eceaed AF |
380 | } |
381 | commchain = curcomm->symvalue.common.chain; | |
214731a7 | 382 | break; |
d5eceaed AF |
383 | |
384 | case N_ECOMM: | |
214731a7 ML |
385 | if (curcomm) { |
386 | curcomm->symvalue.common.chain = commchain; | |
387 | curcomm = nil; | |
d5eceaed AF |
388 | } |
389 | break; | |
7005bb75 | 390 | |
2c3a9a86 | 391 | case N_LBRAC: |
7005bb75 ML |
392 | ++nesting; |
393 | addrstk[nesting] = (linep - 1)->addr; | |
2c3a9a86 ML |
394 | break; |
395 | ||
396 | case N_RBRAC: | |
2fd0f574 | 397 | --nesting; |
7005bb75 ML |
398 | if (addrstk[nesting] == NOADDR) { |
399 | exitblock(); | |
400 | newfunc(curblock, (linep - 1)->addr); | |
2fd0f574 | 401 | addrstk[nesting] = (linep - 1)->addr; |
7005bb75 | 402 | } |
2c3a9a86 ML |
403 | break; |
404 | ||
405 | case N_SLINE: | |
406 | enterline((Lineno) np->n_desc, (Address) np->n_value); | |
407 | break; | |
408 | ||
409 | /* | |
7005bb75 | 410 | * Source files. |
2c3a9a86 ML |
411 | */ |
412 | case N_SO: | |
2fd0f574 | 413 | n = identname(name, true); |
7005bb75 | 414 | enterSourceModule(n, (Address) np->n_value); |
2c3a9a86 ML |
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: | |
7005bb75 | 435 | case N_LENG: |
2c3a9a86 ML |
436 | if (index(name, ':') == nil) { |
437 | if (not warned) { | |
438 | warned = true; | |
2c3a9a86 ML |
439 | warning("old style symbol information found in \"%s\"", |
440 | curfilename()); | |
2c3a9a86 ML |
441 | } |
442 | } else { | |
443 | entersym(name, np); | |
444 | } | |
445 | break; | |
446 | ||
447 | case N_PC: | |
2fd0f574 | 448 | case N_MOD2: |
2c3a9a86 ML |
449 | break; |
450 | ||
438b5736 | 451 | default: |
7005bb75 | 452 | printf("warning: stab entry unrecognized: "); |
2c3a9a86 | 453 | if (name != nil) { |
7005bb75 | 454 | printf("name %s,", name); |
2c3a9a86 | 455 | } |
7005bb75 | 456 | printf("ntype %2x, desc %x, value %x'\n", |
2c3a9a86 ML |
457 | np->n_type, np->n_desc, np->n_value); |
458 | break; | |
459 | } | |
460 | } | |
461 | ||
2fd0f574 | 462 | /* |
0022c355 ML |
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. | |
2fd0f574 SL |
465 | */ |
466 | ||
0022c355 | 467 | private Symbol findsym (n, var_isextref) |
2fd0f574 | 468 | Name n; |
0022c355 | 469 | boolean *var_isextref; |
2fd0f574 SL |
470 | { |
471 | register Symbol r, s; | |
472 | ||
0022c355 | 473 | *var_isextref = false; |
2fd0f574 | 474 | find(s, n) where |
0022c355 ML |
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 | ) | |
2fd0f574 | 483 | endfind(s); |
0022c355 ML |
484 | if (s == nil) { |
485 | r = nil; | |
486 | } else if (s->class == EXTREF) { | |
487 | *var_isextref = true; | |
2fd0f574 SL |
488 | r = s->symvalue.extref; |
489 | delete(s); | |
0022c355 ML |
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 | */ | |
2fd0f574 SL |
505 | } else { |
506 | r = s; | |
507 | } | |
508 | return r; | |
509 | } | |
510 | ||
0022c355 ML |
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 | ||
2c3a9a86 ML |
571 | /* |
572 | * Check to see if a global _name is already in the symbol table, | |
573 | * if not then insert it. | |
574 | */ | |
575 | ||
2fd0f574 | 576 | private check_global (name, np) |
2c3a9a86 ML |
577 | String name; |
578 | register struct nlist *np; | |
579 | { | |
580 | register Name n; | |
d5eceaed | 581 | register Symbol t, u; |
0022c355 ML |
582 | char buf[4096]; |
583 | boolean isextref; | |
584 | integer count; | |
2c3a9a86 | 585 | |
0022c355 ML |
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 | } | |
2c3a9a86 | 596 | if ((np->n_type&N_TYPE) == N_TEXT) { |
0022c355 ML |
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); | |
2c3a9a86 | 603 | } |
0022c355 ML |
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 | } | |
2fd0f574 | 622 | } |
214731a7 | 623 | } else if ((np->n_type&N_TYPE) == N_BSS) { |
2c3a9a86 | 624 | find(t, n) where |
214731a7 | 625 | t->class == COMMON |
2c3a9a86 | 626 | endfind(t); |
214731a7 ML |
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); | |
2c3a9a86 | 635 | } |
214731a7 ML |
636 | } else { |
637 | check_var(np, n); | |
2c3a9a86 ML |
638 | } |
639 | } | |
640 | } | |
641 | ||
214731a7 ML |
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. | |
0022c355 ML |
647 | * |
648 | * If the external name has been referred to by several other symbols, | |
649 | * we must update each of them. | |
214731a7 ML |
650 | */ |
651 | ||
2fd0f574 | 652 | private check_var (np, n) |
214731a7 ML |
653 | struct nlist *np; |
654 | register Name n; | |
655 | { | |
0022c355 ML |
656 | register Symbol t, u, next; |
657 | Symbol conflict; | |
214731a7 | 658 | |
0022c355 | 659 | t = lookup(n); |
214731a7 | 660 | if (t == nil) { |
0022c355 ML |
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 | } | |
214731a7 | 694 | } |
214731a7 ML |
695 | } |
696 | ||
2c3a9a86 ML |
697 | /* |
698 | * Check to see if a local _name is known in the current scope. | |
699 | * If not then enter it. | |
700 | */ | |
701 | ||
2fd0f574 | 702 | private check_local (name, np) |
2c3a9a86 ML |
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; | |
cc4262e8 | 720 | t->symvalue.funcv.src = false; |
7005bb75 | 721 | t->symvalue.funcv.inline = false; |
2c3a9a86 | 722 | t->symvalue.funcv.beginaddr = np->n_value; |
7005bb75 | 723 | newfunc(t, codeloc(t)); |
2c3a9a86 ML |
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 | ||
2fd0f574 | 737 | private check_filename (name) |
2c3a9a86 ML |
738 | String name; |
739 | { | |
740 | register String mname; | |
2fd0f574 | 741 | register integer i; |
0022c355 ML |
742 | Name n; |
743 | Symbol s; | |
2c3a9a86 ML |
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 | } | |
0022c355 ML |
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 | } | |
2c3a9a86 ML |
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 | ||
7005bb75 ML |
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 | ||
2fd0f574 | 781 | public chkUnnamedBlock () |
7005bb75 ML |
782 | { |
783 | register Symbol s; | |
784 | static int bnum = 0; | |
785 | char buf[100]; | |
2fd0f574 | 786 | Address startaddr; |
7005bb75 | 787 | |
2fd0f574 SL |
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 | } | |
7005bb75 ML |
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 | ||
2fd0f574 | 814 | private enterSourceModule (n, addr) |
7005bb75 ML |
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 | } | |
2fd0f574 | 834 | if (not (*language_op(curlang, L_HASMODULES))()) { |
7005bb75 ML |
835 | if (curblock->class != PROG) { |
836 | exitblock(); | |
2fd0f574 | 837 | if (curblock->class != PROG) { |
2c3a9a86 ML |
838 | exitblock(); |
839 | } | |
2c3a9a86 | 840 | } |
2fd0f574 SL |
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); | |
2c3a9a86 | 847 | } else { |
2fd0f574 | 848 | s = curmodule; |
2c3a9a86 | 849 | } |
2fd0f574 SL |
850 | s->language = curlang; |
851 | enterblock(s); | |
852 | curmodule = s; | |
2c3a9a86 | 853 | } |
2fd0f574 SL |
854 | if (program->language == nil) { |
855 | program->language = curlang; | |
2c3a9a86 | 856 | } |
2fd0f574 SL |
857 | warned = false; |
858 | enterfile(ident(n), addr); | |
859 | initTypeTable(); | |
2c3a9a86 ML |
860 | } |
861 | ||
862 | /* | |
863 | * Allocate file and line tables and initialize indices. | |
864 | */ | |
865 | ||
2fd0f574 SL |
866 | private allocmaps (nf, nl) |
867 | integer nf, nl; | |
2c3a9a86 ML |
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. | |
214731a7 ML |
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. | |
2c3a9a86 ML |
888 | */ |
889 | ||
2fd0f574 | 890 | private enterfile (filename, addr) |
2c3a9a86 ML |
891 | String filename; |
892 | Address addr; | |
893 | { | |
214731a7 ML |
894 | filep->addr = addr; |
895 | filep->filename = filename; | |
896 | filep->lineindex = linep - linetab; | |
897 | ++filep; | |
2c3a9a86 ML |
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 | ||
2fd0f574 | 906 | private setnlines () |
2c3a9a86 ML |
907 | { |
908 | nlhdr.nlines = linep - linetab; | |
909 | } | |
910 | ||
911 | /* | |
912 | * Similarly for nfiles ... | |
913 | */ | |
914 | ||
2fd0f574 | 915 | private setnfiles () |
2c3a9a86 ML |
916 | { |
917 | nlhdr.nfiles = filep - filetab; | |
918 | setsource(filetab[0].filename); | |
919 | } |