xref: /original-bsd/old/dbx/object.c (revision f1656be1)
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.2 (Berkeley) 01/12/88";
9 #endif not lint
10 
11 static char rcsid[] = "$Header: object.c,v 1.5 87/03/26 20:24:58 donn 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     boolean afterlg, foundstab;
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     foundstab = false;
246     ub = &namelist[nlhdr.nsyms];
247     curnp = &namelist[0];
248     np = curnp;
249     while (np < ub) {
250 	index = np->n_un.n_strx;
251 	if (index != 0) {
252 	    name = &stringtab[index - 4];
253 	    /*
254              *  If the program contains any .f files a trailing _ is stripped
255        	     *  from the name on the assumption it was added by the compiler.
256 	     *  This only affects names that follow the sdb N_SO entry with
257              *  the .f name.
258              */
259             if (strip_ and name[0] != '\0' ) {
260 		lastchar = &name[strlen(name) - 1];
261 		if (*lastchar == '_') {
262 		    *lastchar = '\0';
263 		}
264             }
265 	} else {
266 	    name = nil;
267 	}
268 
269 	/*
270 	 * Assumptions:
271 	 *	not an N_STAB	==> name != nil
272 	 *	name[0] == '-'	==> name == "-lg"
273 	 *	name[0] != '_'	==> filename or invisible
274 	 *
275 	 * The "-lg" signals the beginning of global loader symbols.
276          *
277 	 */
278 	if ((np->n_type&N_STAB) != 0) {
279 	    foundstab = true;
280 	    enter_nl(name, np);
281 	} else if (name[0] == '-') {
282 	    afterlg = true;
283 	    foundglobals();
284 	} else if (afterlg) {
285 	    check_global(name, np);
286 	} else if ((np->n_type&N_EXT) == N_EXT) {
287 	    afterlg = true;
288 	    foundglobals();
289 	    check_global(name, np);
290 	} else if (name[0] == '_') {
291 	    check_local(&name[1], np);
292 	} else if ((np->n_type&N_TEXT) == N_TEXT) {
293 	    check_filename(name);
294 	}
295 	++curnp;
296 	np = curnp;
297     }
298     if (not foundstab) {
299 	warning("no source compiled with -g");
300     }
301     dispose(namelist);
302 }
303 
304 /*
305  * Get a continuation entry from the name list.
306  * Return the beginning of the name.
307  */
308 
309 public String getcont ()
310 {
311     register integer index;
312     register String name;
313 
314     ++curnp;
315     index = curnp->n_un.n_strx;
316     if (index == 0) {
317 	name = "";
318     } else {
319 	name = &stringtab[index - 4];
320     }
321     return name;
322 }
323 
324 /*
325  * Initialize symbol information.
326  */
327 
328 private initsyms ()
329 {
330     curblock = nil;
331     curlevel = 0;
332     nesting = 0;
333     program = insert(identname("", true));
334     program->class = PROG;
335     program->language = primlang;
336     program->symvalue.funcv.beginaddr = CODESTART;
337     program->symvalue.funcv.inline = false;
338     newfunc(program, codeloc(program));
339     findbeginning(program);
340     enterblock(program);
341     curmodule = program;
342 }
343 
344 /*
345  * Free all the object file information that's being stored.
346  */
347 
348 public objfree ()
349 {
350     symbol_free();
351     /* keywords_free(); */
352     /* names_free(); */
353     /* dispose(stringtab); */
354     clrfunctab();
355 }
356 
357 /*
358  * Enter a namelist entry.
359  */
360 
361 private enter_nl (name, np)
362 String name;
363 register struct nlist *np;
364 {
365     register Symbol s;
366     register Name n;
367 
368     s = nil;
369     switch (np->n_type) {
370 	/*
371 	 * Build a symbol for the FORTRAN common area.  All GSYMS that follow
372 	 * will be chained in a list with the head kept in common.offset, and
373 	 * the tail in common.chain.
374 	 */
375 	case N_BCOMM:
376  	    if (curcomm) {
377 		curcomm->symvalue.common.chain = commchain;
378 	    }
379 	    n = identname(name, true);
380 	    curcomm = lookup(n);
381 	    if (curcomm == nil) {
382 		curcomm = insert(n);
383 		curcomm->class = COMMON;
384 		curcomm->block = curblock;
385 		curcomm->level = program->level;
386 		curcomm->symvalue.common.chain = nil;
387 	    }
388 	    commchain = curcomm->symvalue.common.chain;
389 	    break;
390 
391 	case N_ECOMM:
392 	    if (curcomm) {
393 		curcomm->symvalue.common.chain = commchain;
394 		curcomm = nil;
395 	    }
396 	    break;
397 
398 	case N_LBRAC:
399 	    ++nesting;
400 	    addrstk[nesting] = (linep - 1)->addr;
401 	    break;
402 
403 	case N_RBRAC:
404 	    --nesting;
405 	    if (addrstk[nesting] == NOADDR) {
406 		exitblock();
407 		newfunc(curblock, (linep - 1)->addr);
408 		addrstk[nesting] = (linep - 1)->addr;
409 	    }
410 	    break;
411 
412 	case N_SLINE:
413 	    enterline((Lineno) np->n_desc, (Address) np->n_value);
414 	    break;
415 
416 	/*
417 	 * Source files.
418 	 */
419 	case N_SO:
420 	    n = identname(name, true);
421 	    enterSourceModule(n, (Address) np->n_value);
422 	    break;
423 
424 	/*
425 	 * Textually included files.
426 	 */
427 	case N_SOL:
428 	    enterfile(name, (Address) np->n_value);
429 	    break;
430 
431 	/*
432 	 * These symbols are assumed to have non-nil names.
433 	 */
434 	case N_GSYM:
435 	case N_FUN:
436 	case N_STSYM:
437 	case N_LCSYM:
438 	case N_RSYM:
439 	case N_PSYM:
440 	case N_LSYM:
441 	case N_SSYM:
442 	case N_LENG:
443 	    if (index(name, ':') == nil) {
444 		if (not warned) {
445 		    warned = true;
446 		    printf("warning: old style symbol information ");
447 		    printf("found in \"%s\"\n", curfilename());
448 		}
449 	    } else {
450 		entersym(name, np);
451 	    }
452 	    break;
453 
454 	case N_PC:
455 	case N_MOD2:
456 	    break;
457 
458 	default:
459 	    printf("warning:  stab entry unrecognized: ");
460 	    if (name != nil) {
461 		printf("name %s,", name);
462 	    }
463 	    printf("ntype %2x, desc %x, value %x'\n",
464 		np->n_type, np->n_desc, np->n_value);
465 	    break;
466     }
467 }
468 
469 /*
470  * Try to find the symbol that is referred to by the given name.  Since it's
471  * an external, we need to follow a level or two of indirection.
472  */
473 
474 private Symbol findsym (n, var_isextref)
475 Name n;
476 boolean *var_isextref;
477 {
478     register Symbol r, s;
479 
480     *var_isextref = false;
481     find(s, n) where
482 	(
483 	    s->level == program->level and (
484 		s->class == EXTREF or s->class == VAR or
485 		s->class == PROC or s->class == FUNC
486 	    )
487 	) or (
488 	    s->block == program and s->class == MODULE
489 	)
490     endfind(s);
491     if (s == nil) {
492 	r = nil;
493     } else if (s->class == EXTREF) {
494 	*var_isextref = true;
495 	r = s->symvalue.extref;
496 	delete(s);
497 
498 	/*
499 	 * Now check for another level of indirection that could come from
500 	 * a forward reference in procedure nesting information.  In this case
501 	 * the symbol has already been deleted.
502 	 */
503 	if (r != nil and r->class == EXTREF) {
504 	    r = r->symvalue.extref;
505 	}
506 /*
507     } else if (s->class == MODULE) {
508 	s->class = FUNC;
509 	s->level = program->level;
510 	r = s;
511  */
512     } else {
513 	r = s;
514     }
515     return r;
516 }
517 
518 /*
519  * Create a symbol for a text symbol with no source information.
520  * We treat it as an assembly language function.
521  */
522 
523 private Symbol deffunc (n)
524 Name n;
525 {
526     Symbol f;
527 
528     f = insert(n);
529     f->language = findlanguage(".s");
530     f->class = FUNC;
531     f->type = t_int;
532     f->block = curblock;
533     f->level = program->level;
534     f->symvalue.funcv.src = false;
535     f->symvalue.funcv.inline = false;
536     if (f->chain != nil) {
537 	panic("chain not nil in deffunc");
538     }
539     return f;
540 }
541 
542 /*
543  * Create a symbol for a data or bss symbol with no source information.
544  * We treat it as an assembly language variable.
545  */
546 
547 private Symbol defvar (n)
548 Name n;
549 {
550     Symbol v;
551 
552     v = insert(n);
553     v->language = findlanguage(".s");
554     v->storage = EXT;
555     v->class = VAR;
556     v->type = t_int;
557     v->level = program->level;
558     v->block = curblock;
559     return v;
560 }
561 
562 /*
563  * Update a symbol entry with a text address.
564  */
565 
566 private updateTextSym (s, name, addr)
567 Symbol s;
568 char *name;
569 Address addr;
570 {
571     if (s->class == VAR) {
572 	s->symvalue.offset = addr;
573     } else {
574 	s->symvalue.funcv.beginaddr = addr;
575 	if (name[0] == '_') {
576 	    newfunc(s, codeloc(s));
577 	    findbeginning(s);
578 	}
579     }
580 }
581 
582 /*
583  * Avoid seeing Pascal labels as text symbols.
584  */
585 
586 private boolean PascalLabel (n)
587 Name n;
588 {
589     boolean b;
590     register char *p;
591 
592     b = false;
593     if (curlang == findlanguage(".p")) {
594 	p = ident(n);
595 	while (*p != '\0') {
596 	    if (*p == '_' and *(p+1) == '$') {
597 		b = true;
598 		break;
599 	    }
600 	    ++p;
601 	}
602     }
603     return b;
604 }
605 
606 /*
607  * Check to see if a global _name is already in the symbol table,
608  * if not then insert it.
609  */
610 
611 private check_global (name, np)
612 String name;
613 register struct nlist *np;
614 {
615     register Name n;
616     register Symbol t, u;
617     char buf[4096];
618     boolean isextref;
619     integer count;
620 
621     if (not streq(name, "_end")) {
622 	if (name[0] == '_') {
623 	    n = identname(&name[1], true);
624 	} else {
625 	    n = identname(name, true);
626 	    if (lookup(n) != nil) {
627 		sprintf(buf, "$%s", name);
628 		n = identname(buf, false);
629 	    }
630 	}
631 	if ((np->n_type&N_TYPE) == N_TEXT) {
632 	    count = 0;
633 	    t = findsym(n, &isextref);
634 	    while (isextref) {
635 		++count;
636 		updateTextSym(t, name, np->n_value);
637 		t = findsym(n, &isextref);
638 	    }
639 	    if (count == 0) {
640 		if (t == nil) {
641 		    if (not PascalLabel(n)) {
642 			t = deffunc(n);
643 			updateTextSym(t, name, np->n_value);
644 			if (tracesyms) {
645 			    printdecl(t);
646 			}
647 		    }
648 		} else {
649 		    if (t->class == MODULE) {
650 			u = t;
651 			t = deffunc(n);
652 			t->block = u;
653 			if (tracesyms) {
654 			    printdecl(t);
655 			}
656 		    }
657 		    updateTextSym(t, name, np->n_value);
658 		}
659 	    }
660 	} else if ((np->n_type&N_TYPE) == N_BSS or (np->n_type&N_TYPE) == N_DATA) {
661 	    find(t, n) where
662 		t->class == COMMON
663 	    endfind(t);
664 	    if (t != nil) {
665 		u = (Symbol) t->symvalue.common.offset;
666 		while (u != nil) {
667 		    u->symvalue.offset = u->symvalue.common.offset+np->n_value;
668 		    u = u->symvalue.common.chain;
669 		}
670             } else {
671 		check_var(np, n);
672 	    }
673         } else {
674 	    check_var(np, n);
675 	}
676     }
677 }
678 
679 /*
680  * Check to see if a namelist entry refers to a variable.
681  * If not, create a variable for the entry.  In any case,
682  * set the offset of the variable according to the value field
683  * in the entry.
684  *
685  * If the external name has been referred to by several other symbols,
686  * we must update each of them.
687  */
688 
689 private check_var (np, n)
690 struct nlist *np;
691 register Name n;
692 {
693     register Symbol t, u, next;
694     Symbol conflict;
695 
696     t = lookup(n);
697     if (t == nil) {
698 	t = defvar(n);
699 	t->symvalue.offset = np->n_value;
700 	if (tracesyms) {
701 	    printdecl(t);
702 	}
703     } else {
704 	conflict = nil;
705 	do {
706 	    next = t->next_sym;
707 	    if (t->name == n) {
708 		if (t->class == MODULE and t->block == program) {
709 		    conflict = t;
710 		} else if (t->class == EXTREF and t->level == program->level) {
711 		    u = t->symvalue.extref;
712 		    while (u != nil and u->class == EXTREF) {
713 			u = u->symvalue.extref;
714 		    }
715 		    u->symvalue.offset = np->n_value;
716 		    delete(t);
717 		} else if (t->level == program->level and
718 		    (t->class == VAR or t->class == PROC or t->class == FUNC)
719 		) {
720 		    conflict = nil;
721 		    t->symvalue.offset = np->n_value;
722 		}
723 	    }
724 	    t = next;
725 	} while (t != nil);
726 	if (conflict != nil) {
727 	    u = defvar(n);
728 	    u->block = conflict;
729 	    u->symvalue.offset = np->n_value;
730 	}
731     }
732 }
733 
734 /*
735  * Check to see if a local _name is known in the current scope.
736  * If not then enter it.
737  */
738 
739 private check_local (name, np)
740 String name;
741 register struct nlist *np;
742 {
743     register Name n;
744     register Symbol t, cur;
745 
746     n = identname(name, true);
747     cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
748     find(t, n) where t->block == cur endfind(t);
749     if (t == nil) {
750 	t = insert(n);
751 	t->language = findlanguage(".s");
752 	t->type = t_int;
753 	t->block = cur;
754 	t->storage = EXT;
755 	t->level = cur->level;
756 	if ((np->n_type&N_TYPE) == N_TEXT) {
757 	    t->class = FUNC;
758 	    t->symvalue.funcv.src = false;
759 	    t->symvalue.funcv.inline = false;
760 	    t->symvalue.funcv.beginaddr = np->n_value;
761 	    newfunc(t, codeloc(t));
762 	    findbeginning(t);
763 	} else {
764 	    t->class = VAR;
765 	    t->symvalue.offset = np->n_value;
766 	}
767     }
768 }
769 
770 /*
771  * Check to see if a symbol corresponds to a object file name.
772  * For some reason these are listed as in the text segment.
773  */
774 
775 private check_filename (name)
776 String name;
777 {
778     register String mname;
779     register integer i;
780     Name n;
781     Symbol s;
782 
783     mname = strdup(name);
784     i = strlen(mname) - 2;
785     if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
786 	mname[i] = '\0';
787 	--i;
788 	while (mname[i] != '/' and i >= 0) {
789 	    --i;
790 	}
791 	n = identname(&mname[i+1], true);
792 	find(s, n) where s->block == program and s->class == MODULE endfind(s);
793 	if (s == nil) {
794 	    s = insert(n);
795 	    s->language = findlanguage(".s");
796 	    s->class = MODULE;
797 	    s->symvalue.funcv.beginaddr = 0;
798 	    findbeginning(s);
799 	}
800 	if (curblock->class != PROG) {
801 	    exitblock();
802 	    if (curblock->class != PROG) {
803 		exitblock();
804 	    }
805 	}
806 	enterblock(s);
807 	curmodule = s;
808     }
809 }
810 
811 /*
812  * Check to see if a symbol is about to be defined within an unnamed block.
813  * If this happens, we create a procedure for the unnamed block, make it
814  * "inline" so that tracebacks don't associate an activation record with it,
815  * and enter it into the function table so that it will be detected
816  * by "whatblock".
817  */
818 
819 public chkUnnamedBlock ()
820 {
821     register Symbol s;
822     static int bnum = 0;
823     char buf[100];
824     Address startaddr;
825 
826     if (nesting > 0 and addrstk[nesting] != NOADDR) {
827 	startaddr = (linep - 1)->addr;
828 	++bnum;
829 	sprintf(buf, "$b%d", bnum);
830 	s = insert(identname(buf, false));
831 	s->language = curlang;
832 	s->class = PROC;
833 	s->symvalue.funcv.src = false;
834 	s->symvalue.funcv.inline = true;
835 	s->symvalue.funcv.beginaddr = startaddr;
836 	enterblock(s);
837 	newfunc(s, startaddr);
838 	addrstk[nesting] = NOADDR;
839     }
840 }
841 
842 /*
843  * Compilation unit.  C associates scope with filenames
844  * so we treat them as "modules".  The filename without
845  * the suffix is used for the module name.
846  *
847  * Because there is no explicit "end-of-block" mark in
848  * the object file, we must exit blocks for the current
849  * procedure and module.
850  */
851 
852 private enterSourceModule (n, addr)
853 Name n;
854 Address addr;
855 {
856     register Symbol s;
857     Name nn;
858     String mname, suffix;
859 
860     mname = strdup(ident(n));
861     if (rindex(mname, '/') != nil) {
862 	mname = rindex(mname, '/') + 1;
863     }
864     suffix = rindex(mname, '.');
865     if (suffix > mname && *(suffix-1) == '.') {
866 	/* special hack for C++ */
867 	--suffix;
868     }
869     curlang = findlanguage(suffix);
870     if (curlang == findlanguage(".f")) {
871 	strip_ = true;
872     }
873     if (suffix != nil) {
874 	*suffix = '\0';
875     }
876     if (not (*language_op(curlang, L_HASMODULES))()) {
877 	if (curblock->class != PROG) {
878 	    exitblock();
879 	    if (curblock->class != PROG) {
880 		exitblock();
881 	    }
882 	}
883 	nn = identname(mname, true);
884 	if (curmodule == nil or curmodule->name != nn) {
885 	    s = insert(nn);
886 	    s->class = MODULE;
887 	    s->symvalue.funcv.beginaddr = 0;
888 	    findbeginning(s);
889 	} else {
890 	    s = curmodule;
891 	}
892 	s->language = curlang;
893 	enterblock(s);
894 	curmodule = s;
895     }
896     if (program->language == nil) {
897 	program->language = curlang;
898     }
899     warned = false;
900     enterfile(ident(n), addr);
901     initTypeTable();
902 }
903 
904 /*
905  * Allocate file and line tables and initialize indices.
906  */
907 
908 private allocmaps (nf, nl)
909 integer nf, nl;
910 {
911     if (filetab != nil) {
912 	dispose(filetab);
913     }
914     if (linetab != nil) {
915 	dispose(linetab);
916     }
917     filetab = newarr(Filetab, nf);
918     linetab = newarr(Linetab, nl);
919     filep = filetab;
920     linep = linetab;
921 }
922 
923 /*
924  * Add a file to the file table.
925  *
926  * If the new address is the same as the previous file address
927  * this routine used to not enter the file, but this caused some
928  * problems so it has been removed.  It's not clear that this in
929  * turn may not also cause a problem.
930  */
931 
932 private enterfile (filename, addr)
933 String filename;
934 Address addr;
935 {
936     filep->addr = addr;
937     filep->filename = filename;
938     filep->lineindex = linep - linetab;
939     ++filep;
940 }
941 
942 /*
943  * Since we only estimated the number of lines (and it was a poor
944  * estimation) and since we need to know the exact number of lines
945  * to do a binary search, we set it when we're done.
946  */
947 
948 private setnlines ()
949 {
950     nlhdr.nlines = linep - linetab;
951 }
952 
953 /*
954  * Similarly for nfiles ...
955  */
956 
957 private setnfiles ()
958 {
959     nlhdr.nfiles = filep - filetab;
960     setsource(filetab[0].filename);
961 }
962