xref: /original-bsd/old/dbx/object.c (revision 3708840b)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)object.c 1.8 05/18/83";
4 
5 /*
6  * Object code interface, mainly for extraction of symbolic information.
7  */
8 
9 #include "defs.h"
10 #include "object.h"
11 #include "main.h"
12 #include "symbols.h"
13 #include "names.h"
14 #include "languages.h"
15 #include "mappings.h"
16 #include "lists.h"
17 #include <a.out.h>
18 #include <stab.h>
19 #include <ctype.h>
20 
21 #ifndef public
22 
23 struct {
24     unsigned int stringsize;	/* size of the dumped string table */
25     unsigned int nsyms;		/* number of symbols */
26     unsigned int nfiles;	/* number of files */
27     unsigned int nlines;	/* number of lines */
28 } nlhdr;
29 
30 #endif
31 
32 public String objname = "a.out";
33 public Integer objsize;
34 public char *stringtab;
35 
36 private String progname = nil;
37 private Language curlang;
38 private Symbol curmodule;
39 private Symbol curparam;
40 private Boolean warned;
41 private Symbol curcomm;
42 private Symbol commchain;
43 private Boolean strip_ = false;
44 
45 private Filetab *filep;
46 private Linetab *linep, *prevlinep;
47 private Address curfaddr;
48 
49 #define curfilename() (filep-1)->filename
50 
51 /*
52  * Blocks are figured out on the fly while reading the symbol table.
53  */
54 
55 #define MAXBLKDEPTH 25
56 
57 private Symbol curblock;
58 private Symbol blkstack[MAXBLKDEPTH];
59 private Integer curlevel;
60 
61 #define enterblock(b) { \
62     blkstack[curlevel] = curblock; \
63     ++curlevel; \
64     b->level = curlevel; \
65     b->block = curblock; \
66     curblock = b; \
67 }
68 
69 #define exitblock() { \
70     if (curblock->class == FUNC or curblock->class == PROC) { \
71 	if (prevlinep != linep) { \
72 	    curblock->symvalue.funcv.src = true; \
73 	} \
74     } \
75     --curlevel; \
76     curblock = blkstack[curlevel]; \
77 }
78 
79 /*
80  * Enter a source line or file name reference into the appropriate table.
81  * Expanded inline to reduce procedure calls.
82  *
83  * private enterline(linenumber, address)
84  * Lineno linenumber;
85  * Address address;
86  *  ...
87  */
88 
89 #define enterline(linenumber, address) \
90 { \
91     register Linetab *lp; \
92  \
93     lp = linep - 1; \
94     if (linenumber != lp->line) { \
95 	if (address != lp->addr) { \
96 	    ++lp; \
97 	} \
98 	lp->line = linenumber; \
99 	lp->addr = address; \
100 	linep = lp + 1; \
101     } \
102 }
103 
104 #define NTYPES 1000
105 
106 private Symbol typetable[NTYPES];
107 
108 /*
109  * Read in the namelist from the obj file.
110  *
111  * Reads and seeks are used instead of fread's and fseek's
112  * for efficiency sake; there's a lot of data being read here.
113  */
114 
115 public readobj(file)
116 String file;
117 {
118     Fileid f;
119     struct exec hdr;
120     struct nlist nlist;
121 
122     f = open(file, 0);
123     if (f < 0) {
124 	fatal("can't open %s", file);
125     }
126     read(f, &hdr, sizeof(hdr));
127     objsize = hdr.a_text;
128     nlhdr.nsyms = hdr.a_syms / sizeof(nlist);
129     nlhdr.nfiles = nlhdr.nsyms;
130     nlhdr.nlines = nlhdr.nsyms;
131     lseek(f, (long) N_STROFF(hdr), 0);
132     read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize));
133     nlhdr.stringsize -= 4;
134     stringtab = newarr(char, nlhdr.stringsize);
135     read(f, stringtab, nlhdr.stringsize);
136     allocmaps(nlhdr.nfiles, nlhdr.nlines);
137     lseek(f, (long) N_SYMOFF(hdr), 0);
138     readsyms(f);
139     ordfunctab();
140     setnlines();
141     setnfiles();
142     close(f);
143 }
144 
145 /*
146  * Read in symbols from object file.
147  */
148 
149 private readsyms(f)
150 Fileid f;
151 {
152     struct nlist *namelist;
153     register struct nlist *np, *ub;
154     register int index;
155     register String name;
156     register Boolean afterlg;
157 
158     initsyms();
159     namelist = newarr(struct nlist, nlhdr.nsyms);
160     read(f, namelist, nlhdr.nsyms * sizeof(struct nlist));
161     afterlg = false;
162     ub = &namelist[nlhdr.nsyms];
163     for (np = &namelist[0]; np < ub; np++) {
164 	index = np->n_un.n_strx;
165 	if (index != 0) {
166 	    name = &stringtab[index - 4];
167 	    /*
168              *  if the program contains any .f files a trailing _ is stripped
169        	     *  from the name on the assumption it was added by the compiler.
170 	     *  This only affects names that follow the sdb N_SO entry with
171              *  the .f name.
172              */
173             if(strip_ && *name != '\0' ) {
174                  register char *p, *q;
175                  for(p=name,q=(name+1); *q != '\0'; p=q++);
176                  if (*p == '_')  *p = '\0';
177             }
178 
179 	} else {
180 	    name = nil;
181 	}
182 	/*
183 	 * assumptions:
184 	 *	not an N_STAB	==> name != nil
185 	 *	name[0] == '-'	==> name == "-lg"
186 	 *	name[0] != '_'	==> filename or invisible
187 	 *
188 	 * The "-lg" signals the beginning of global loader symbols.
189          *
190 	 */
191 	if ((np->n_type&N_STAB) != 0) {
192 	    enter_nl(name, np);
193 	} else if (name[0] == '-') {
194 	    afterlg = true;
195 	    if (curblock->class != PROG) {
196 		exitblock();
197 		if (curblock->class != PROG) {
198 		    exitblock();
199 		}
200 	    }
201 	    enterline(0, (linep-1)->addr + 1);
202 	} else if (afterlg) {
203 	    if (name[0] == '_') {
204 		check_global(&name[1], np);
205 	    }
206 	} else if (name[0] == '_') {
207 	    check_local(&name[1], np);
208 	} else if ((np->n_type&N_TEXT) == N_TEXT) {
209 	    check_filename(name);
210 	}
211     }
212     dispose(namelist);
213 }
214 
215 /*
216  * Initialize symbol information.
217  */
218 
219 private initsyms()
220 {
221     curblock = nil;
222     curlevel = 0;
223     if (progname == nil) {
224 	progname = strdup(objname);
225 	if (rindex(progname, '/') != nil) {
226 	    progname = rindex(progname, '/') + 1;
227 	}
228 	if (index(progname, '.') != nil) {
229 	    *(index(progname, '.')) = '\0';
230 	}
231     }
232     program = insert(identname(progname, true));
233     program->class = PROG;
234     program->symvalue.funcv.beginaddr = 0;
235     findbeginning(program);
236     newfunc(program);
237     enterblock(program);
238     curmodule = program;
239     t_boolean = maketype("$boolean", 0L, 1L);
240     t_int = maketype("$integer", 0x80000000L, 0x7fffffffL);
241     t_char = maketype("$char", 0L, 127L);
242     t_real = maketype("$real", 4L, 0L);
243     t_nil = maketype("$nil", 0L, 0L);
244 }
245 
246 /*
247  * Free all the object file information that's being stored.
248  */
249 
250 public objfree()
251 {
252     symbol_free();
253     keywords_free();
254     names_free();
255     dispose(stringtab);
256     clrfunctab();
257 }
258 
259 /*
260  * Enter a namelist entry.
261  */
262 
263 private enter_nl(name, np)
264 String name;
265 register struct nlist *np;
266 {
267     register Symbol s;
268     String mname, suffix;
269     register Name n, nn;
270 
271     s = nil;
272     if (name == nil) {
273 	n = nil;
274     } else {
275 	n = identname(name, true);
276     }
277     switch (np->n_type) {
278 
279 /* Build a symbol for the common; all GSYMS that follow will be chained;
280  * the head of this list is kept in common.offset, the tail in common.chain
281  */
282  	case N_BCOMM:
283  	    if(curcomm) {
284 	    curcomm->symvalue.common.chain = commchain;
285 	    }
286 	    curcomm = lookup(n);
287 	    if (  curcomm == nil) {
288 		  curcomm = insert(n);
289 		  curcomm->class = COMMON;
290 		  curcomm->block = curblock;
291 		  curcomm->level = program->level;
292 		  curcomm->symvalue.common.chain = nil;
293 	    }
294 	    commchain = curcomm->symvalue.common.chain;
295 	break;
296 
297 	case N_ECOMM:
298 	    if(curcomm) {
299 	    curcomm->symvalue.common.chain = commchain;
300 	    curcomm = nil;
301 	    }
302 	    break;
303 
304 	case N_LBRAC:
305 	    s = symbol_alloc();
306 	    s->class = PROC;
307 	    enterblock(s);
308 	    break;
309 
310 	case N_RBRAC:
311 	    exitblock();
312 	    break;
313 
314 	case N_SLINE:
315 	    enterline((Lineno) np->n_desc, (Address) np->n_value);
316 	    break;
317 
318 	/*
319 	 * Compilation unit.  C associates scope with filenames
320 	 * so we treat them as "modules".  The filename without
321 	 * the suffix is used for the module name.
322 	 *
323 	 * Because there is no explicit "end-of-block" mark in
324 	 * the object file, we must exit blocks for the current
325 	 * procedure and module.
326 	 */
327 	case N_SO:
328 	    mname = strdup(ident(n));
329 	    if (rindex(mname, '/') != nil) {
330 		mname = rindex(mname, '/') + 1;
331 	    }
332 	    suffix = rindex(mname, '.');
333 	    curlang = findlanguage(suffix);
334 	    if(curlang == findlanguage(".f")) {
335                             strip_ = true;
336             }
337 	    if (suffix != nil) {
338 		*suffix = '\0';
339 	    }
340 	    if (curblock->class != PROG) {
341 		exitblock();
342 		if (curblock->class != PROG) {
343 		    exitblock();
344 		}
345 	    }
346 	    nn = identname(mname, true);
347 	    if (curmodule == nil or curmodule->name != nn) {
348 		s = insert(nn);
349 		s->class = MODULE;
350 		s->symvalue.funcv.beginaddr = 0;
351 		findbeginning(s);
352 	    } else {
353 		s = curmodule;
354 	    }
355 	    s->language = curlang;
356 	    enterblock(s);
357 	    curmodule = s;
358 	    if (program->language == nil) {
359 		program->language = curlang;
360 	    }
361 	    warned = false;
362 	    enterfile(ident(n), (Address) np->n_value);
363 	    bzero(typetable, sizeof(typetable));
364 	    break;
365 
366 	/*
367 	 * Textually included files.
368 	 */
369 	case N_SOL:
370 	    enterfile(name, (Address) np->n_value);
371 	    break;
372 
373 	/*
374 	 * These symbols are assumed to have non-nil names.
375 	 */
376 	case N_GSYM:
377 	case N_FUN:
378 	case N_STSYM:
379 	case N_LCSYM:
380 	case N_RSYM:
381 	case N_PSYM:
382 	case N_LSYM:
383 	case N_SSYM:
384 	    if (index(name, ':') == nil) {
385 		if (not warned) {
386 		    warned = true;
387 		    /*
388 		     * Shouldn't do this if user might be typing.
389 		     *
390 		    warning("old style symbol information found in \"%s\"",
391 			curfilename());
392 		     *
393 		     */
394 		}
395 	    } else {
396 		entersym(name, np);
397 	    }
398 	    break;
399 
400 	case N_PC:
401 	    break;
402 
403 	case N_LENG:
404 	default:
405 	    /*
406 	     * Should complain out this, obviously the wrong symbol format.
407 	     *
408 	    if (name != nil) {
409 		printf("%s, ", name);
410 	    }
411 	    printf("ntype %2x, desc %x, value %x\n",
412 		np->n_type, np->n_desc, np->n_value);
413 	     *
414 	     */
415 	    break;
416     }
417 }
418 
419 /*
420  * Check to see if a global _name is already in the symbol table,
421  * if not then insert it.
422  */
423 
424 private check_global(name, np)
425 String name;
426 register struct nlist *np;
427 {
428     register Name n;
429     register Symbol t, u;
430 
431     if (not streq(name, "end")) {
432 	n = identname(name, true);
433 	if ((np->n_type&N_TYPE) == N_TEXT) {
434 	    find(t, n) where
435 		t->level == program->level and isblock(t)
436 	    endfind(t);
437 	    if (t == nil) {
438 		t = insert(n);
439 		t->language = findlanguage(".s");
440 		t->class = FUNC;
441 		t->type = t_int;
442 		t->block = curblock;
443 		t->level = program->level;
444 		t->symvalue.funcv.src = false;
445 	    }
446 	    t->symvalue.funcv.beginaddr = np->n_value;
447 	    newfunc(t);
448 	    findbeginning(t);
449 	}  else if ( (np->n_type&N_TYPE) == N_BSS ){
450 	    find(t, n) where
451 		t->class  == COMMON
452 	    endfind(t);
453 	    if(t != nil) {
454 		for(u= (Symbol) t->symvalue.common.offset;
455                         u != nil ;u=u->symvalue.common.chain){
456 		   u->symvalue.offset = u->symvalue.common.offset + np->n_value;
457 		   }
458             }
459         }
460         else {
461 	    find(t, n) where
462 		t->class == VAR and t->level == program->level
463 	    endfind(t);
464 	    if (t == nil) {
465 		t = insert(n);
466 		t->language = findlanguage(".s");
467 		t->class = VAR;
468 		t->type = t_int;
469 		t->block = curblock;
470 		t->level = program->level;
471 	    }
472 	    t->symvalue.offset = np->n_value;
473 	}
474     }
475 }
476 
477 /*
478  * Check to see if a local _name is known in the current scope.
479  * If not then enter it.
480  */
481 
482 private check_local(name, np)
483 String name;
484 register struct nlist *np;
485 {
486     register Name n;
487     register Symbol t, cur;
488 
489     n = identname(name, true);
490     cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
491     find(t, n) where t->block == cur endfind(t);
492     if (t == nil) {
493 	t = insert(n);
494 	t->language = findlanguage(".s");
495 	t->type = t_int;
496 	t->block = cur;
497 	t->level = cur->level;
498 	if ((np->n_type&N_TYPE) == N_TEXT) {
499 	    t->class = FUNC;
500 	    t->symvalue.funcv.src = false;
501 	    t->symvalue.funcv.beginaddr = np->n_value;
502 	    newfunc(t);
503 	    findbeginning(t);
504 	} else {
505 	    t->class = VAR;
506 	    t->symvalue.offset = np->n_value;
507 	}
508     }
509 }
510 
511 /*
512  * Check to see if a symbol corresponds to a object file name.
513  * For some reason these are listed as in the text segment.
514  */
515 
516 private check_filename(name)
517 String name;
518 {
519     register String mname;
520     register Integer i;
521     register Symbol s;
522 
523     mname = strdup(name);
524     i = strlen(mname) - 2;
525     if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
526 	mname[i] = '\0';
527 	--i;
528 	while (mname[i] != '/' and i >= 0) {
529 	    --i;
530 	}
531 	s = insert(identname(&mname[i+1], true));
532 	s->language = findlanguage(".s");
533 	s->class = MODULE;
534 	s->symvalue.funcv.beginaddr = 0;
535 	findbeginning(s);
536 	if (curblock->class != PROG) {
537 	    exitblock();
538 	    if (curblock->class != PROG) {
539 		exitblock();
540 	    }
541 	}
542 	enterblock(s);
543 	curmodule = s;
544     }
545 }
546 
547 /*
548  * Put an nlist into the symbol table.
549  * If it's already there just add the associated information.
550  *
551  * Type information is encoded in the name following a ":".
552  */
553 
554 private Symbol constype();
555 private Char *curchar;
556 
557 #define skipchar(ptr, ch) { \
558     if (*ptr != ch) { \
559 	panic("expected char '%c', found char '%c'", ch, *ptr); \
560     } \
561     ++ptr; \
562 }
563 
564 private entersym(str, np)
565 String str;
566 struct nlist *np;
567 {
568     register Symbol s;
569     register char *p;
570     register int c;
571     register Name n;
572     register Integer i;
573     Boolean knowtype, isnew;
574     Symclass class;
575     Integer level;
576 
577     p = index(str, ':');
578     *p = '\0';
579     c = *(p+1);
580     n = identname(str, true);
581     if (index("FfGV", c) != nil) {
582 	if (c == 'F' or c == 'f') {
583 	    class = FUNC;
584 	} else {
585 	    class = VAR;
586 	}
587 	level = (c == 'f' ? curmodule->level : program->level);
588 	find(s, n) where s->level == level and s->class == class endfind(s);
589 	if (s == nil) {
590 	    isnew = true;
591 	    s = insert(n);
592 	} else {
593 	    isnew = false;
594 	}
595     } else {
596 	isnew = true;
597 	s = insert(n);
598     }
599 
600     /*
601      * Default attributes.
602      */
603     s->language = curlang;
604     s->class = VAR;
605     s->block = curblock;
606     s->level = curlevel;
607     s->symvalue.offset = np->n_value;
608     curchar = p + 2;
609     knowtype = false;
610     switch (c) {
611 	case 't':	/* type name */
612 	    s->class = TYPE;
613 	    i = getint();
614 	    if (i == 0) {
615 		panic("bad input on type \"%s\" at \"%s\"", symname(s),
616 		    curchar);
617 	    } else if (i >= NTYPES) {
618 		panic("too many types in file \"%s\"", curfilename());
619 	    }
620 	    /*
621 	     * A hack for C typedefs that don't create new types,
622 	     * e.g. typedef unsigned int Hashvalue;
623 	     *  or  typedef struct blah BLAH;
624 	     */
625 	    if (*curchar == '\0') {
626 		s->type = typetable[i];
627 		if (s->type == nil) {
628 		    s->type = symbol_alloc();
629 		    typetable[i] = s->type;
630 		}
631 		knowtype = true;
632 	    } else {
633 		typetable[i] = s;
634 		skipchar(curchar, '=');
635 	    }
636 	    break;
637 
638 	case 'T':	/* tag */
639 	    s->class = TAG;
640 	    i = getint();
641 	    if (i == 0) {
642 		panic("bad input on tag \"%s\" at \"%s\"", symname(s),
643 		    curchar);
644 	    } else if (i >= NTYPES) {
645 		panic("too many types in file \"%s\"", curfilename());
646 	    }
647 	    if (typetable[i] != nil) {
648 		typetable[i]->language = curlang;
649 		typetable[i]->class = TYPE;
650 		typetable[i]->type = s;
651 	    } else {
652 		typetable[i] = s;
653 	    }
654 	    skipchar(curchar, '=');
655 	    break;
656 
657 	case 'F':	/* public function */
658 	case 'f':	/* private function */
659 	    s->class = FUNC;
660 	    if (curblock->class == FUNC or curblock->class == PROC) {
661 		exitblock();
662 	    }
663 	    enterblock(s);
664 	    if (c == 'F') {
665 		s->level = program->level;
666 		isnew = false;
667 	    }
668 	    curparam = s;
669 	    if (isnew) {
670 		s->symvalue.funcv.src = false;
671 		s->symvalue.funcv.beginaddr = np->n_value;
672 		newfunc(s);
673 		findbeginning(s);
674 	    }
675 	    break;
676 
677 	case 'G':	/* public variable */
678 	    s->level = program->level;
679 	    break;
680 
681 	case 'S':	/* private variable */
682 	    s->level = curmodule->level;
683 	    s->block = curmodule;
684 	    break;
685 
686 /*
687  *  keep global BSS variables chained so can resolve when get the start
688  *  of common; keep the list in order so f77 can display all vars in a COMMON
689 */
690 	case 'V':	/* own variable */
691 	    s->level = 2;
692 	    if (curcomm) {
693 	      if (commchain != nil) {
694  		  commchain->symvalue.common.chain = s;
695 	      }
696 	      else {
697 		  curcomm->symvalue.common.offset = (int) s;
698 	      }
699               commchain = s;
700               s->symvalue.common.offset = np->n_value;
701               s->symvalue.common.chain = nil;
702 	    }
703 	    break;
704 
705 	case 'r':	/* register variable */
706 	    s->level = -(s->level);
707 	    break;
708 
709 	case 'p':	/* parameter variable */
710 	    curparam->chain = s;
711 	    curparam = s;
712 	    break;
713 
714 	case 'v':	/* varies parameter */
715 	    s->class = REF;
716 	    s->symvalue.offset = np->n_value;
717 	    curparam->chain = s;
718 	    curparam = s;
719 	    break;
720 
721 	default:	/* local variable */
722 	    --curchar;
723 	    break;
724     }
725     if (not knowtype) {
726 	s->type = constype(nil);
727 	if (s->class == TAG) {
728 	    addtag(s);
729 	}
730     }
731     if (tracesyms) {
732 	printdecl(s);
733 	fflush(stdout);
734     }
735 }
736 
737 /*
738  * Construct a type out of a string encoding.
739  *
740  * The forms of the string are
741  *
742  *	<number>
743  *	<number>=<type>
744  *	r<type>;<number>;<number>		$ subrange
745  *	a<type>;<type>				$ array[index] of element
746  *	s{<name>:<type>;<number>;<number>}	$ record
747  *	*<type>					$ pointer
748  */
749 
750 private Symbol constype(type)
751 Symbol type;
752 {
753     register Symbol t, u;
754     register Char *p, *cur;
755     register Integer n;
756     Integer b;
757     Name name;
758     Char class;
759 
760     b = curlevel;
761     if (isdigit(*curchar)) {
762 	n = getint();
763 	if (n == 0) {
764 	    panic("bad type number at \"%s\"", curchar);
765 	} else if (n >= NTYPES) {
766 	    panic("too many types in file \"%s\"", curfilename());
767 	}
768 	if (*curchar == '=') {
769 	    if (typetable[n] != nil) {
770 		t = typetable[n];
771 	    } else {
772 		t = symbol_alloc();
773 		typetable[n] = t;
774 	    }
775 	    ++curchar;
776 	    constype(t);
777 	} else {
778 	    t = typetable[n];
779 	    if (t == nil) {
780 		t = symbol_alloc();
781 		typetable[n] = t;
782 	    }
783 	}
784     } else {
785 	if (type == nil) {
786 	    t = symbol_alloc();
787 	} else {
788 	    t = type;
789 	}
790 	t->language = curlang;
791 	t->level = b;
792 	t->block = curblock;
793 	class = *curchar++;
794 	switch (class) {
795 
796 	    case 'r':
797 		t->class = RANGE;
798 		t->type = constype(nil);
799 		skipchar(curchar, ';');
800                 /* some letters indicate a dynamic bound, ie what follows
801                    is the offset from the fp which contains the bound; this will
802                    need a different encoding when pc a['A'..'Z'] is
803                    added; J is a special flag to handle fortran a(*) bounds
804                 */
805 		switch(*curchar) {
806 			case 'A':
807 				t->symvalue.rangev.lowertype = R_ARG;
808                   		curchar++;
809 			        break;
810 
811 			case 'T':
812 				t->symvalue.rangev.lowertype = R_TEMP;
813                   		curchar++;
814 			        break;
815 
816 			case 'J':
817 				t->symvalue.rangev.lowertype = R_ADJUST;
818                   		curchar++;
819 			  	break;
820 
821 			default:
822 				 t->symvalue.rangev.lowertype = R_CONST;
823 			  	 break;
824 
825 		}
826 	        t->symvalue.rangev.lower = getint();
827 		skipchar(curchar, ';');
828 		switch(*curchar) {
829 			case 'A':
830 				t->symvalue.rangev.uppertype = R_ARG;
831                   		curchar++;
832 			        break;
833 
834 			case 'T':
835 				t->symvalue.rangev.uppertype = R_TEMP;
836                   		curchar++;
837 			        break;
838 
839 			case 'J':
840 				t->symvalue.rangev.uppertype = R_ADJUST;
841                   		curchar++;
842 			  	break;
843 
844 			default:
845 				 t->symvalue.rangev.uppertype = R_CONST;
846 			  	 break;
847 
848 		}
849 		t->symvalue.rangev.upper = getint();
850 		break;
851 
852 	    case 'a':
853 		t->class = ARRAY;
854 		t->chain = constype(nil);
855 		skipchar(curchar, ';');
856 		t->type = constype(nil);
857 		break;
858 
859 	    case 's':
860 	    case 'u':
861 		t->class = (class == 's') ? RECORD : VARNT;
862 		t->symvalue.offset = getint();
863 		u = t;
864 		cur = curchar;
865 		while (*cur != ';' and *cur != '\0') {
866 		    p = index(cur, ':');
867 		    if (p == nil) {
868 			panic("index(\"%s\", ':') failed", curchar);
869 		    }
870 		    *p = '\0';
871 		    name = identname(cur, true);
872 		    u->chain = newSymbol(name, b, FIELD, nil, nil);
873 		    cur = p + 1;
874 		    u = u->chain;
875 		    u->language = curlang;
876 		    curchar = cur;
877 		    u->type = constype(nil);
878 		    skipchar(curchar, ',');
879 		    u->symvalue.field.offset = getint();
880 		    skipchar(curchar, ',');
881 		    u->symvalue.field.length = getint();
882 		    skipchar(curchar, ';');
883 		    cur = curchar;
884 		}
885 		if (*cur == ';') {
886 		    ++cur;
887 		}
888 		curchar = cur;
889 		break;
890 
891 	    case 'e':
892 		t->class = SCAL;
893 		u = t;
894 		while (*curchar != ';' and *curchar != '\0') {
895 		    p = index(curchar, ':');
896 		    assert(p != nil);
897 		    *p = '\0';
898 		    u->chain = insert(identname(curchar, true));
899 		    curchar = p + 1;
900 		    u = u->chain;
901 		    u->language = curlang;
902 		    u->class = CONST;
903 		    u->level = b;
904 		    u->block = curblock;
905 		    u->type = t;
906 		    u->symvalue.iconval = getint();
907 		    skipchar(curchar, ',');
908 		}
909 		break;
910 
911 	    case '*':
912 		t->class = PTR;
913 		t->type = constype(nil);
914 		break;
915 
916 	    case 'f':
917 		t->class = FUNC;
918 		t->type = constype(nil);
919 		break;
920 
921 	    default:
922 		badcaseval(class);
923 	}
924     }
925     return t;
926 }
927 
928 /*
929  * Read an integer from the current position in the type string.
930  */
931 
932 private Integer getint()
933 {
934     register Integer n;
935     register char *p;
936     register Boolean isneg;
937 
938     n = 0;
939     p = curchar;
940     if (*p == '-') {
941 	isneg = true;
942 	++p;
943     } else {
944 	isneg = false;
945     }
946     while (isdigit(*p)) {
947 	n = 10*n + (*p - '0');
948 	++p;
949     }
950     curchar = p;
951     return isneg ? (-n) : n;
952 }
953 
954 /*
955  * Add a tag name.  This is a kludge to be able to refer
956  * to tags that have the same name as some other symbol
957  * in the same block.
958  */
959 
960 private addtag(s)
961 register Symbol s;
962 {
963     register Symbol t;
964     char buf[100];
965 
966     sprintf(buf, "$$%.90s", ident(s->name));
967     t = insert(identname(buf, false));
968     t->language = s->language;
969     t->class = TAG;
970     t->type = s->type;
971     t->block = s->block;
972 }
973 
974 /*
975  * Allocate file and line tables and initialize indices.
976  */
977 
978 private allocmaps(nf, nl)
979 Integer nf, nl;
980 {
981     if (filetab != nil) {
982 	dispose(filetab);
983     }
984     if (linetab != nil) {
985 	dispose(linetab);
986     }
987     filetab = newarr(Filetab, nf);
988     linetab = newarr(Linetab, nl);
989     filep = filetab;
990     linep = linetab;
991 }
992 
993 /*
994  * Add a file to the file table.
995  */
996 
997 private enterfile(filename, addr)
998 String filename;
999 Address addr;
1000 {
1001     if (addr != curfaddr) {
1002 	filep->addr = addr;
1003 	filep->filename = filename;
1004 	filep->lineindex = linep - linetab;
1005 	++filep;
1006 	curfaddr = addr;
1007     }
1008 }
1009 
1010 /*
1011  * Since we only estimated the number of lines (and it was a poor
1012  * estimation) and since we need to know the exact number of lines
1013  * to do a binary search, we set it when we're done.
1014  */
1015 
1016 private setnlines()
1017 {
1018     nlhdr.nlines = linep - linetab;
1019 }
1020 
1021 /*
1022  * Similarly for nfiles ...
1023  */
1024 
1025 private setnfiles()
1026 {
1027     nlhdr.nfiles = filep - filetab;
1028     setsource(filetab[0].filename);
1029 }
1030