xref: /csrg-svn/old/dbx/object.c (revision 13938)
19673Slinton /* Copyright (c) 1982 Regents of the University of California */
29673Slinton 
3*13938Slinton static char sccsid[] = "@(#)object.c 1.10 07/15/83";
49673Slinton 
59673Slinton /*
69673Slinton  * Object code interface, mainly for extraction of symbolic information.
79673Slinton  */
89673Slinton 
99673Slinton #include "defs.h"
109673Slinton #include "object.h"
119673Slinton #include "main.h"
129673Slinton #include "symbols.h"
139673Slinton #include "names.h"
149673Slinton #include "languages.h"
159673Slinton #include "mappings.h"
169673Slinton #include "lists.h"
179673Slinton #include <a.out.h>
189673Slinton #include <stab.h>
199673Slinton #include <ctype.h>
209673Slinton 
219673Slinton #ifndef public
229673Slinton 
239673Slinton struct {
249673Slinton     unsigned int stringsize;	/* size of the dumped string table */
259673Slinton     unsigned int nsyms;		/* number of symbols */
269673Slinton     unsigned int nfiles;	/* number of files */
279673Slinton     unsigned int nlines;	/* number of lines */
289673Slinton } nlhdr;
299673Slinton 
309673Slinton #endif
319673Slinton 
329673Slinton public String objname = "a.out";
339673Slinton public Integer objsize;
349673Slinton public char *stringtab;
359673Slinton 
369673Slinton private String progname = nil;
379673Slinton private Language curlang;
389673Slinton private Symbol curmodule;
399673Slinton private Symbol curparam;
409673Slinton private Boolean warned;
4112542Scsvaf private Symbol curcomm;
4212542Scsvaf private Symbol commchain;
4312542Scsvaf private Boolean strip_ = false;
449673Slinton 
459673Slinton private Filetab *filep;
4611875Slinton private Linetab *linep, *prevlinep;
479673Slinton 
489673Slinton #define curfilename() (filep-1)->filename
499673Slinton 
509673Slinton /*
519673Slinton  * Blocks are figured out on the fly while reading the symbol table.
529673Slinton  */
539673Slinton 
549673Slinton #define MAXBLKDEPTH 25
559673Slinton 
569673Slinton private Symbol curblock;
579673Slinton private Symbol blkstack[MAXBLKDEPTH];
589673Slinton private Integer curlevel;
599673Slinton 
609673Slinton #define enterblock(b) { \
619673Slinton     blkstack[curlevel] = curblock; \
629673Slinton     ++curlevel; \
639673Slinton     b->level = curlevel; \
649673Slinton     b->block = curblock; \
659673Slinton     curblock = b; \
669673Slinton }
679673Slinton 
689673Slinton #define exitblock() { \
6911875Slinton     if (curblock->class == FUNC or curblock->class == PROC) { \
7011875Slinton 	if (prevlinep != linep) { \
7111875Slinton 	    curblock->symvalue.funcv.src = true; \
7211875Slinton 	} \
7311875Slinton     } \
749673Slinton     --curlevel; \
759673Slinton     curblock = blkstack[curlevel]; \
769673Slinton }
779673Slinton 
789673Slinton /*
799673Slinton  * Enter a source line or file name reference into the appropriate table.
809673Slinton  * Expanded inline to reduce procedure calls.
819673Slinton  *
829673Slinton  * private enterline(linenumber, address)
839673Slinton  * Lineno linenumber;
849673Slinton  * Address address;
859673Slinton  *  ...
869673Slinton  */
879673Slinton 
889673Slinton #define enterline(linenumber, address) \
899673Slinton { \
909673Slinton     register Linetab *lp; \
919673Slinton  \
929673Slinton     lp = linep - 1; \
939673Slinton     if (linenumber != lp->line) { \
949673Slinton 	if (address != lp->addr) { \
959673Slinton 	    ++lp; \
969673Slinton 	} \
979673Slinton 	lp->line = linenumber; \
989673Slinton 	lp->addr = address; \
999673Slinton 	linep = lp + 1; \
1009673Slinton     } \
1019673Slinton }
1029673Slinton 
1039673Slinton #define NTYPES 1000
1049673Slinton 
1059673Slinton private Symbol typetable[NTYPES];
1069673Slinton 
1079673Slinton /*
1089673Slinton  * Read in the namelist from the obj file.
1099673Slinton  *
1109673Slinton  * Reads and seeks are used instead of fread's and fseek's
1119673Slinton  * for efficiency sake; there's a lot of data being read here.
1129673Slinton  */
1139673Slinton 
1149673Slinton public readobj(file)
1159673Slinton String file;
1169673Slinton {
1179673Slinton     Fileid f;
1189673Slinton     struct exec hdr;
1199673Slinton     struct nlist nlist;
1209673Slinton 
1219673Slinton     f = open(file, 0);
1229673Slinton     if (f < 0) {
1239673Slinton 	fatal("can't open %s", file);
1249673Slinton     }
1259673Slinton     read(f, &hdr, sizeof(hdr));
1269673Slinton     objsize = hdr.a_text;
1279673Slinton     nlhdr.nsyms = hdr.a_syms / sizeof(nlist);
1289673Slinton     nlhdr.nfiles = nlhdr.nsyms;
1299673Slinton     nlhdr.nlines = nlhdr.nsyms;
1309673Slinton     lseek(f, (long) N_STROFF(hdr), 0);
1319673Slinton     read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize));
1329673Slinton     nlhdr.stringsize -= 4;
1339673Slinton     stringtab = newarr(char, nlhdr.stringsize);
1349673Slinton     read(f, stringtab, nlhdr.stringsize);
1359673Slinton     allocmaps(nlhdr.nfiles, nlhdr.nlines);
1369673Slinton     lseek(f, (long) N_SYMOFF(hdr), 0);
1379673Slinton     readsyms(f);
1389673Slinton     ordfunctab();
1399673Slinton     setnlines();
1409673Slinton     setnfiles();
1419673Slinton     close(f);
1429673Slinton }
1439673Slinton 
1449673Slinton /*
1459673Slinton  * Read in symbols from object file.
1469673Slinton  */
1479673Slinton 
1489673Slinton private readsyms(f)
1499673Slinton Fileid f;
1509673Slinton {
1519673Slinton     struct nlist *namelist;
1529673Slinton     register struct nlist *np, *ub;
1539673Slinton     register int index;
1549673Slinton     register String name;
1559673Slinton     register Boolean afterlg;
1569673Slinton 
1579673Slinton     initsyms();
1589673Slinton     namelist = newarr(struct nlist, nlhdr.nsyms);
1599673Slinton     read(f, namelist, nlhdr.nsyms * sizeof(struct nlist));
1609673Slinton     afterlg = false;
1619673Slinton     ub = &namelist[nlhdr.nsyms];
1629673Slinton     for (np = &namelist[0]; np < ub; np++) {
1639673Slinton 	index = np->n_un.n_strx;
1649673Slinton 	if (index != 0) {
1659673Slinton 	    name = &stringtab[index - 4];
16612542Scsvaf 	    /*
16712542Scsvaf              *  if the program contains any .f files a trailing _ is stripped
16812542Scsvaf        	     *  from the name on the assumption it was added by the compiler.
16912542Scsvaf 	     *  This only affects names that follow the sdb N_SO entry with
17012542Scsvaf              *  the .f name.
17112542Scsvaf              */
17212542Scsvaf             if(strip_ && *name != '\0' ) {
17312542Scsvaf                  register char *p, *q;
17412542Scsvaf                  for(p=name,q=(name+1); *q != '\0'; p=q++);
17512542Scsvaf                  if (*p == '_')  *p = '\0';
17612542Scsvaf             }
17712542Scsvaf 
1789673Slinton 	} else {
1799673Slinton 	    name = nil;
18012542Scsvaf 	}
1819673Slinton 	/*
1829673Slinton 	 * assumptions:
1839673Slinton 	 *	not an N_STAB	==> name != nil
1849673Slinton 	 *	name[0] == '-'	==> name == "-lg"
1859673Slinton 	 *	name[0] != '_'	==> filename or invisible
1869673Slinton 	 *
1879673Slinton 	 * The "-lg" signals the beginning of global loader symbols.
18812542Scsvaf          *
1899673Slinton 	 */
1909673Slinton 	if ((np->n_type&N_STAB) != 0) {
1919673Slinton 	    enter_nl(name, np);
1929673Slinton 	} else if (name[0] == '-') {
1939673Slinton 	    afterlg = true;
1949673Slinton 	    if (curblock->class != PROG) {
1959673Slinton 		exitblock();
1969673Slinton 		if (curblock->class != PROG) {
1979673Slinton 		    exitblock();
1989673Slinton 		}
1999673Slinton 	    }
2009673Slinton 	    enterline(0, (linep-1)->addr + 1);
20111104Slinton 	} else if (afterlg) {
20211104Slinton 	    if (name[0] == '_') {
2039673Slinton 		check_global(&name[1], np);
2049673Slinton 	    }
20511104Slinton 	} else if (name[0] == '_') {
20611104Slinton 	    check_local(&name[1], np);
2079673Slinton 	} else if ((np->n_type&N_TEXT) == N_TEXT) {
2089673Slinton 	    check_filename(name);
2099673Slinton 	}
2109673Slinton     }
2119673Slinton     dispose(namelist);
2129673Slinton }
2139673Slinton 
2149673Slinton /*
2159673Slinton  * Initialize symbol information.
2169673Slinton  */
2179673Slinton 
2189673Slinton private initsyms()
2199673Slinton {
2209673Slinton     curblock = nil;
2219673Slinton     curlevel = 0;
2229673Slinton     if (progname == nil) {
2239673Slinton 	progname = strdup(objname);
2249673Slinton 	if (rindex(progname, '/') != nil) {
2259673Slinton 	    progname = rindex(progname, '/') + 1;
2269673Slinton 	}
2279673Slinton 	if (index(progname, '.') != nil) {
2289673Slinton 	    *(index(progname, '.')) = '\0';
2299673Slinton 	}
2309673Slinton     }
2319673Slinton     program = insert(identname(progname, true));
2329673Slinton     program->class = PROG;
23311769Slinton     program->symvalue.funcv.beginaddr = 0;
23411769Slinton     findbeginning(program);
2359673Slinton     newfunc(program);
2369673Slinton     enterblock(program);
2379673Slinton     curmodule = program;
2389673Slinton     t_boolean = maketype("$boolean", 0L, 1L);
2399673Slinton     t_int = maketype("$integer", 0x80000000L, 0x7fffffffL);
2409673Slinton     t_char = maketype("$char", 0L, 127L);
24113838Slinton     t_real = maketype("$real", 8L, 0L);
2429673Slinton     t_nil = maketype("$nil", 0L, 0L);
2439673Slinton }
2449673Slinton 
2459673Slinton /*
2469673Slinton  * Free all the object file information that's being stored.
2479673Slinton  */
2489673Slinton 
2499673Slinton public objfree()
2509673Slinton {
2519673Slinton     symbol_free();
2529673Slinton     keywords_free();
2539673Slinton     names_free();
2549673Slinton     dispose(stringtab);
2559673Slinton     clrfunctab();
2569673Slinton }
2579673Slinton 
2589673Slinton /*
2599673Slinton  * Enter a namelist entry.
2609673Slinton  */
2619673Slinton 
2629673Slinton private enter_nl(name, np)
2639673Slinton String name;
2649673Slinton register struct nlist *np;
2659673Slinton {
2669673Slinton     register Symbol s;
2679673Slinton     String mname, suffix;
26811875Slinton     register Name n, nn;
2699673Slinton 
2709673Slinton     s = nil;
2719673Slinton     if (name == nil) {
2729673Slinton 	n = nil;
2739673Slinton     } else {
2749673Slinton 	n = identname(name, true);
2759673Slinton     }
2769673Slinton     switch (np->n_type) {
27712542Scsvaf 
278*13938Slinton     /*
279*13938Slinton      * Build a symbol for the common; all GSYMS that follow will be chained;
280*13938Slinton      * the head of this list is kept in common.offset, the tail in common.chain
281*13938Slinton      */
282*13938Slinton 	case N_BCOMM:
283*13938Slinton  	    if (curcomm) {
284*13938Slinton 		curcomm->symvalue.common.chain = commchain;
28512542Scsvaf 	    }
28612542Scsvaf 	    curcomm = lookup(n);
287*13938Slinton 	    if (curcomm == nil) {
288*13938Slinton 		curcomm = insert(n);
289*13938Slinton 		curcomm->class = COMMON;
290*13938Slinton 		curcomm->block = curblock;
291*13938Slinton 		curcomm->level = program->level;
292*13938Slinton 		curcomm->symvalue.common.chain = nil;
29312542Scsvaf 	    }
29412542Scsvaf 	    commchain = curcomm->symvalue.common.chain;
295*13938Slinton 	    break;
29612542Scsvaf 
29712542Scsvaf 	case N_ECOMM:
298*13938Slinton 	    if (curcomm) {
299*13938Slinton 		curcomm->symvalue.common.chain = commchain;
300*13938Slinton 		curcomm = nil;
30112542Scsvaf 	    }
30212542Scsvaf 	    break;
30312542Scsvaf 
3049673Slinton 	case N_LBRAC:
3059673Slinton 	    s = symbol_alloc();
3069673Slinton 	    s->class = PROC;
3079673Slinton 	    enterblock(s);
3089673Slinton 	    break;
3099673Slinton 
3109673Slinton 	case N_RBRAC:
3119673Slinton 	    exitblock();
3129673Slinton 	    break;
3139673Slinton 
3149673Slinton 	case N_SLINE:
3159673Slinton 	    enterline((Lineno) np->n_desc, (Address) np->n_value);
3169673Slinton 	    break;
3179673Slinton 
3189673Slinton 	/*
3199673Slinton 	 * Compilation unit.  C associates scope with filenames
3209673Slinton 	 * so we treat them as "modules".  The filename without
3219673Slinton 	 * the suffix is used for the module name.
3229673Slinton 	 *
3239673Slinton 	 * Because there is no explicit "end-of-block" mark in
3249673Slinton 	 * the object file, we must exit blocks for the current
3259673Slinton 	 * procedure and module.
3269673Slinton 	 */
3279673Slinton 	case N_SO:
3289673Slinton 	    mname = strdup(ident(n));
3299673Slinton 	    if (rindex(mname, '/') != nil) {
3309673Slinton 		mname = rindex(mname, '/') + 1;
3319673Slinton 	    }
3329673Slinton 	    suffix = rindex(mname, '.');
3339673Slinton 	    curlang = findlanguage(suffix);
33412542Scsvaf 	    if(curlang == findlanguage(".f")) {
33512542Scsvaf                             strip_ = true;
33612542Scsvaf             }
3379673Slinton 	    if (suffix != nil) {
3389673Slinton 		*suffix = '\0';
3399673Slinton 	    }
3409673Slinton 	    if (curblock->class != PROG) {
3419673Slinton 		exitblock();
3429673Slinton 		if (curblock->class != PROG) {
3439673Slinton 		    exitblock();
3449673Slinton 		}
3459673Slinton 	    }
34611875Slinton 	    nn = identname(mname, true);
34711875Slinton 	    if (curmodule == nil or curmodule->name != nn) {
34811875Slinton 		s = insert(nn);
34911875Slinton 		s->class = MODULE;
35011875Slinton 		s->symvalue.funcv.beginaddr = 0;
35111875Slinton 		findbeginning(s);
35211875Slinton 	    } else {
35311875Slinton 		s = curmodule;
35411875Slinton 	    }
3559673Slinton 	    s->language = curlang;
3569673Slinton 	    enterblock(s);
3579673Slinton 	    curmodule = s;
3589673Slinton 	    if (program->language == nil) {
3599673Slinton 		program->language = curlang;
3609673Slinton 	    }
3619673Slinton 	    warned = false;
3629673Slinton 	    enterfile(ident(n), (Address) np->n_value);
36311769Slinton 	    bzero(typetable, sizeof(typetable));
3649673Slinton 	    break;
3659673Slinton 
3669673Slinton 	/*
3679673Slinton 	 * Textually included files.
3689673Slinton 	 */
3699673Slinton 	case N_SOL:
3709673Slinton 	    enterfile(name, (Address) np->n_value);
3719673Slinton 	    break;
3729673Slinton 
3739673Slinton 	/*
3749673Slinton 	 * These symbols are assumed to have non-nil names.
3759673Slinton 	 */
3769673Slinton 	case N_GSYM:
3779673Slinton 	case N_FUN:
3789673Slinton 	case N_STSYM:
3799673Slinton 	case N_LCSYM:
3809673Slinton 	case N_RSYM:
3819673Slinton 	case N_PSYM:
3829673Slinton 	case N_LSYM:
3839673Slinton 	case N_SSYM:
3849673Slinton 	    if (index(name, ':') == nil) {
3859673Slinton 		if (not warned) {
3869673Slinton 		    warned = true;
3879673Slinton 		    /*
3889673Slinton 		     * Shouldn't do this if user might be typing.
3899673Slinton 		     *
3909673Slinton 		    warning("old style symbol information found in \"%s\"",
3919673Slinton 			curfilename());
3929673Slinton 		     *
3939673Slinton 		     */
3949673Slinton 		}
3959673Slinton 	    } else {
3969673Slinton 		entersym(name, np);
3979673Slinton 	    }
3989673Slinton 	    break;
3999673Slinton 
4009673Slinton 	case N_PC:
4019673Slinton 	    break;
4029673Slinton 
4039840Slinton 	case N_LENG:
40411558Slinton 	default:
4059840Slinton 	    /*
4069840Slinton 	     * Should complain out this, obviously the wrong symbol format.
40711558Slinton 	     *
4089673Slinton 	    if (name != nil) {
4099673Slinton 		printf("%s, ", name);
4109673Slinton 	    }
4119673Slinton 	    printf("ntype %2x, desc %x, value %x\n",
4129673Slinton 		np->n_type, np->n_desc, np->n_value);
41311558Slinton 	     *
41411558Slinton 	     */
4159673Slinton 	    break;
4169673Slinton     }
4179673Slinton }
4189673Slinton 
4199673Slinton /*
4209673Slinton  * Check to see if a global _name is already in the symbol table,
4219673Slinton  * if not then insert it.
4229673Slinton  */
4239673Slinton 
4249673Slinton private check_global(name, np)
4259673Slinton String name;
4269673Slinton register struct nlist *np;
4279673Slinton {
4289673Slinton     register Name n;
42912542Scsvaf     register Symbol t, u;
4309673Slinton 
4319673Slinton     if (not streq(name, "end")) {
4329673Slinton 	n = identname(name, true);
4339673Slinton 	if ((np->n_type&N_TYPE) == N_TEXT) {
4349673Slinton 	    find(t, n) where
4359673Slinton 		t->level == program->level and isblock(t)
4369673Slinton 	    endfind(t);
4379673Slinton 	    if (t == nil) {
4389673Slinton 		t = insert(n);
4399673Slinton 		t->language = findlanguage(".s");
4409673Slinton 		t->class = FUNC;
4419673Slinton 		t->type = t_int;
4429673Slinton 		t->block = curblock;
4439673Slinton 		t->level = program->level;
44411875Slinton 		t->symvalue.funcv.src = false;
4459673Slinton 	    }
4469673Slinton 	    t->symvalue.funcv.beginaddr = np->n_value;
4479673Slinton 	    newfunc(t);
4489673Slinton 	    findbeginning(t);
449*13938Slinton 	} else if ((np->n_type&N_TYPE) == N_BSS) {
4509673Slinton 	    find(t, n) where
451*13938Slinton 		t->class == COMMON
45212542Scsvaf 	    endfind(t);
453*13938Slinton 	    if (t != nil) {
454*13938Slinton 		u = (Symbol) t->symvalue.common.offset;
455*13938Slinton 		while (u != nil) {
456*13938Slinton 		    u->symvalue.offset = u->symvalue.common.offset+np->n_value;
457*13938Slinton 		    u = u->symvalue.common.chain;
458*13938Slinton 		}
459*13938Slinton             } else {
460*13938Slinton 		check_var(np, n);
4619673Slinton 	    }
462*13938Slinton         } else {
463*13938Slinton 	    check_var(np, n);
4649673Slinton 	}
4659673Slinton     }
4669673Slinton }
4679673Slinton 
4689673Slinton /*
469*13938Slinton  * Check to see if a namelist entry refers to a variable.
470*13938Slinton  * If not, create a variable for the entry.  In any case,
471*13938Slinton  * set the offset of the variable according to the value field
472*13938Slinton  * in the entry.
473*13938Slinton  */
474*13938Slinton 
475*13938Slinton private check_var(np, n)
476*13938Slinton struct nlist *np;
477*13938Slinton register Name n;
478*13938Slinton {
479*13938Slinton     register Symbol t;
480*13938Slinton 
481*13938Slinton     find(t, n) where
482*13938Slinton 	t->class == VAR and t->level == program->level
483*13938Slinton     endfind(t);
484*13938Slinton     if (t == nil) {
485*13938Slinton 	t = insert(n);
486*13938Slinton 	t->language = findlanguage(".s");
487*13938Slinton 	t->class = VAR;
488*13938Slinton 	t->type = t_int;
489*13938Slinton 	t->level = program->level;
490*13938Slinton     }
491*13938Slinton     t->block = curblock;
492*13938Slinton     t->symvalue.offset = np->n_value;
493*13938Slinton }
494*13938Slinton 
495*13938Slinton /*
4969673Slinton  * Check to see if a local _name is known in the current scope.
4979673Slinton  * If not then enter it.
4989673Slinton  */
4999673Slinton 
5009673Slinton private check_local(name, np)
5019673Slinton String name;
5029673Slinton register struct nlist *np;
5039673Slinton {
5049673Slinton     register Name n;
5059673Slinton     register Symbol t, cur;
5069673Slinton 
5079673Slinton     n = identname(name, true);
5089673Slinton     cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock;
5099673Slinton     find(t, n) where t->block == cur endfind(t);
5109673Slinton     if (t == nil) {
5119673Slinton 	t = insert(n);
5129673Slinton 	t->language = findlanguage(".s");
5139673Slinton 	t->type = t_int;
5149673Slinton 	t->block = cur;
5159673Slinton 	t->level = cur->level;
5169673Slinton 	if ((np->n_type&N_TYPE) == N_TEXT) {
5179673Slinton 	    t->class = FUNC;
51811875Slinton 	    t->symvalue.funcv.src = false;
5199673Slinton 	    t->symvalue.funcv.beginaddr = np->n_value;
5209673Slinton 	    newfunc(t);
5219673Slinton 	    findbeginning(t);
5229673Slinton 	} else {
5239673Slinton 	    t->class = VAR;
5249673Slinton 	    t->symvalue.offset = np->n_value;
5259673Slinton 	}
5269673Slinton     }
5279673Slinton }
5289673Slinton 
5299673Slinton /*
5309673Slinton  * Check to see if a symbol corresponds to a object file name.
5319673Slinton  * For some reason these are listed as in the text segment.
5329673Slinton  */
5339673Slinton 
5349673Slinton private check_filename(name)
5359673Slinton String name;
5369673Slinton {
5379673Slinton     register String mname;
5389673Slinton     register Integer i;
5399673Slinton     register Symbol s;
5409673Slinton 
5419673Slinton     mname = strdup(name);
5429673Slinton     i = strlen(mname) - 2;
5439673Slinton     if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') {
5449673Slinton 	mname[i] = '\0';
5459673Slinton 	--i;
5469673Slinton 	while (mname[i] != '/' and i >= 0) {
5479673Slinton 	    --i;
5489673Slinton 	}
5499673Slinton 	s = insert(identname(&mname[i+1], true));
5509673Slinton 	s->language = findlanguage(".s");
5519673Slinton 	s->class = MODULE;
55211769Slinton 	s->symvalue.funcv.beginaddr = 0;
55311769Slinton 	findbeginning(s);
5549673Slinton 	if (curblock->class != PROG) {
5559673Slinton 	    exitblock();
5569673Slinton 	    if (curblock->class != PROG) {
5579673Slinton 		exitblock();
5589673Slinton 	    }
5599673Slinton 	}
5609673Slinton 	enterblock(s);
5619673Slinton 	curmodule = s;
5629673Slinton     }
5639673Slinton }
5649673Slinton 
5659673Slinton /*
5669673Slinton  * Put an nlist into the symbol table.
5679673Slinton  * If it's already there just add the associated information.
5689673Slinton  *
5699673Slinton  * Type information is encoded in the name following a ":".
5709673Slinton  */
5719673Slinton 
5729673Slinton private Symbol constype();
5739673Slinton private Char *curchar;
5749673Slinton 
5759673Slinton #define skipchar(ptr, ch) { \
5769673Slinton     if (*ptr != ch) { \
5779673Slinton 	panic("expected char '%c', found char '%c'", ch, *ptr); \
5789673Slinton     } \
5799673Slinton     ++ptr; \
5809673Slinton }
5819673Slinton 
5829673Slinton private entersym(str, np)
5839673Slinton String str;
5849673Slinton struct nlist *np;
5859673Slinton {
5869673Slinton     register Symbol s;
5879673Slinton     register char *p;
5889673Slinton     register int c;
5899673Slinton     register Name n;
5909673Slinton     register Integer i;
5919673Slinton     Boolean knowtype, isnew;
5929673Slinton     Symclass class;
5939673Slinton     Integer level;
5949673Slinton 
5959673Slinton     p = index(str, ':');
5969673Slinton     *p = '\0';
5979673Slinton     c = *(p+1);
5989673Slinton     n = identname(str, true);
5999673Slinton     if (index("FfGV", c) != nil) {
6009673Slinton 	if (c == 'F' or c == 'f') {
6019673Slinton 	    class = FUNC;
6029673Slinton 	} else {
6039673Slinton 	    class = VAR;
6049673Slinton 	}
6059673Slinton 	level = (c == 'f' ? curmodule->level : program->level);
6069673Slinton 	find(s, n) where s->level == level and s->class == class endfind(s);
6079673Slinton 	if (s == nil) {
6089673Slinton 	    isnew = true;
6099673Slinton 	    s = insert(n);
6109673Slinton 	} else {
6119673Slinton 	    isnew = false;
6129673Slinton 	}
6139673Slinton     } else {
6149673Slinton 	isnew = true;
6159673Slinton 	s = insert(n);
6169673Slinton     }
6179673Slinton 
6189673Slinton     /*
6199673Slinton      * Default attributes.
6209673Slinton      */
6219673Slinton     s->language = curlang;
6229673Slinton     s->class = VAR;
6239673Slinton     s->block = curblock;
6249673Slinton     s->level = curlevel;
6259673Slinton     s->symvalue.offset = np->n_value;
6269673Slinton     curchar = p + 2;
6279673Slinton     knowtype = false;
6289673Slinton     switch (c) {
6299673Slinton 	case 't':	/* type name */
6309673Slinton 	    s->class = TYPE;
6319673Slinton 	    i = getint();
6329673Slinton 	    if (i == 0) {
6339673Slinton 		panic("bad input on type \"%s\" at \"%s\"", symname(s),
6349673Slinton 		    curchar);
6359673Slinton 	    } else if (i >= NTYPES) {
6369673Slinton 		panic("too many types in file \"%s\"", curfilename());
6379673Slinton 	    }
6389673Slinton 	    /*
6399673Slinton 	     * A hack for C typedefs that don't create new types,
6409673Slinton 	     * e.g. typedef unsigned int Hashvalue;
64111558Slinton 	     *  or  typedef struct blah BLAH;
6429673Slinton 	     */
6439673Slinton 	    if (*curchar == '\0') {
6449673Slinton 		s->type = typetable[i];
6459673Slinton 		if (s->type == nil) {
64611558Slinton 		    s->type = symbol_alloc();
64711558Slinton 		    typetable[i] = s->type;
6489673Slinton 		}
6499673Slinton 		knowtype = true;
6509673Slinton 	    } else {
6519673Slinton 		typetable[i] = s;
6529673Slinton 		skipchar(curchar, '=');
6539673Slinton 	    }
6549673Slinton 	    break;
6559673Slinton 
6569673Slinton 	case 'T':	/* tag */
6579673Slinton 	    s->class = TAG;
6589673Slinton 	    i = getint();
6599673Slinton 	    if (i == 0) {
6609673Slinton 		panic("bad input on tag \"%s\" at \"%s\"", symname(s),
6619673Slinton 		    curchar);
6629673Slinton 	    } else if (i >= NTYPES) {
6639673Slinton 		panic("too many types in file \"%s\"", curfilename());
6649673Slinton 	    }
6659673Slinton 	    if (typetable[i] != nil) {
6669673Slinton 		typetable[i]->language = curlang;
6679673Slinton 		typetable[i]->class = TYPE;
6689673Slinton 		typetable[i]->type = s;
6699673Slinton 	    } else {
6709673Slinton 		typetable[i] = s;
6719673Slinton 	    }
6729673Slinton 	    skipchar(curchar, '=');
6739673Slinton 	    break;
6749673Slinton 
6759673Slinton 	case 'F':	/* public function */
6769673Slinton 	case 'f':	/* private function */
6779673Slinton 	    s->class = FUNC;
6789673Slinton 	    if (curblock->class == FUNC or curblock->class == PROC) {
6799673Slinton 		exitblock();
6809673Slinton 	    }
6819673Slinton 	    enterblock(s);
6829673Slinton 	    if (c == 'F') {
6839673Slinton 		s->level = program->level;
6849673Slinton 		isnew = false;
6859673Slinton 	    }
6869673Slinton 	    curparam = s;
6879673Slinton 	    if (isnew) {
68811875Slinton 		s->symvalue.funcv.src = false;
6899673Slinton 		s->symvalue.funcv.beginaddr = np->n_value;
6909673Slinton 		newfunc(s);
6919673Slinton 		findbeginning(s);
6929673Slinton 	    }
6939673Slinton 	    break;
6949673Slinton 
6959673Slinton 	case 'G':	/* public variable */
6969673Slinton 	    s->level = program->level;
6979673Slinton 	    break;
6989673Slinton 
6999673Slinton 	case 'S':	/* private variable */
7009673Slinton 	    s->level = curmodule->level;
7019673Slinton 	    s->block = curmodule;
7029673Slinton 	    break;
7039673Slinton 
70412542Scsvaf /*
70512542Scsvaf  *  keep global BSS variables chained so can resolve when get the start
70612542Scsvaf  *  of common; keep the list in order so f77 can display all vars in a COMMON
70712542Scsvaf */
7089673Slinton 	case 'V':	/* own variable */
7099673Slinton 	    s->level = 2;
71012542Scsvaf 	    if (curcomm) {
71112542Scsvaf 	      if (commchain != nil) {
71212542Scsvaf  		  commchain->symvalue.common.chain = s;
71312542Scsvaf 	      }
71412542Scsvaf 	      else {
71512542Scsvaf 		  curcomm->symvalue.common.offset = (int) s;
71612542Scsvaf 	      }
71712542Scsvaf               commchain = s;
71812542Scsvaf               s->symvalue.common.offset = np->n_value;
71912542Scsvaf               s->symvalue.common.chain = nil;
72012542Scsvaf 	    }
7219673Slinton 	    break;
7229673Slinton 
7239673Slinton 	case 'r':	/* register variable */
7249673Slinton 	    s->level = -(s->level);
7259673Slinton 	    break;
7269673Slinton 
7279673Slinton 	case 'p':	/* parameter variable */
7289673Slinton 	    curparam->chain = s;
7299673Slinton 	    curparam = s;
7309673Slinton 	    break;
7319673Slinton 
7329673Slinton 	case 'v':	/* varies parameter */
7339673Slinton 	    s->class = REF;
7349673Slinton 	    s->symvalue.offset = np->n_value;
7359673Slinton 	    curparam->chain = s;
7369673Slinton 	    curparam = s;
7379673Slinton 	    break;
7389673Slinton 
7399673Slinton 	default:	/* local variable */
7409673Slinton 	    --curchar;
7419673Slinton 	    break;
7429673Slinton     }
7439673Slinton     if (not knowtype) {
7449673Slinton 	s->type = constype(nil);
7459673Slinton 	if (s->class == TAG) {
7469673Slinton 	    addtag(s);
7479673Slinton 	}
7489673Slinton     }
7499673Slinton     if (tracesyms) {
7509673Slinton 	printdecl(s);
7519673Slinton 	fflush(stdout);
7529673Slinton     }
7539673Slinton }
7549673Slinton 
7559673Slinton /*
7569673Slinton  * Construct a type out of a string encoding.
7579673Slinton  *
7589673Slinton  * The forms of the string are
7599673Slinton  *
7609673Slinton  *	<number>
7619673Slinton  *	<number>=<type>
7629673Slinton  *	r<type>;<number>;<number>		$ subrange
7639673Slinton  *	a<type>;<type>				$ array[index] of element
7649673Slinton  *	s{<name>:<type>;<number>;<number>}	$ record
7659673Slinton  *	*<type>					$ pointer
7669673Slinton  */
7679673Slinton 
7689673Slinton private Symbol constype(type)
7699673Slinton Symbol type;
7709673Slinton {
7719673Slinton     register Symbol t, u;
7729673Slinton     register Char *p, *cur;
7739673Slinton     register Integer n;
7749673Slinton     Integer b;
7759673Slinton     Name name;
7769673Slinton     Char class;
7779673Slinton 
7789673Slinton     b = curlevel;
7799673Slinton     if (isdigit(*curchar)) {
7809673Slinton 	n = getint();
7819673Slinton 	if (n == 0) {
7829673Slinton 	    panic("bad type number at \"%s\"", curchar);
7839673Slinton 	} else if (n >= NTYPES) {
7849673Slinton 	    panic("too many types in file \"%s\"", curfilename());
7859673Slinton 	}
7869673Slinton 	if (*curchar == '=') {
7879673Slinton 	    if (typetable[n] != nil) {
7889673Slinton 		t = typetable[n];
7899673Slinton 	    } else {
7909673Slinton 		t = symbol_alloc();
7919673Slinton 		typetable[n] = t;
7929673Slinton 	    }
7939673Slinton 	    ++curchar;
7949673Slinton 	    constype(t);
7959673Slinton 	} else {
7969673Slinton 	    t = typetable[n];
7979673Slinton 	    if (t == nil) {
7989673Slinton 		t = symbol_alloc();
7999673Slinton 		typetable[n] = t;
8009673Slinton 	    }
8019673Slinton 	}
8029673Slinton     } else {
8039673Slinton 	if (type == nil) {
8049673Slinton 	    t = symbol_alloc();
8059673Slinton 	} else {
8069673Slinton 	    t = type;
8079673Slinton 	}
8089673Slinton 	t->language = curlang;
8099673Slinton 	t->level = b;
81012542Scsvaf 	t->block = curblock;
8119673Slinton 	class = *curchar++;
8129673Slinton 	switch (class) {
81312542Scsvaf 
8149673Slinton 	    case 'r':
8159673Slinton 		t->class = RANGE;
8169673Slinton 		t->type = constype(nil);
8179673Slinton 		skipchar(curchar, ';');
81812542Scsvaf                 /* some letters indicate a dynamic bound, ie what follows
81912542Scsvaf                    is the offset from the fp which contains the bound; this will
82012542Scsvaf                    need a different encoding when pc a['A'..'Z'] is
82112542Scsvaf                    added; J is a special flag to handle fortran a(*) bounds
82212542Scsvaf                 */
82312542Scsvaf 		switch(*curchar) {
82412542Scsvaf 			case 'A':
82512542Scsvaf 				t->symvalue.rangev.lowertype = R_ARG;
82612542Scsvaf                   		curchar++;
82712542Scsvaf 			        break;
82812542Scsvaf 
82912542Scsvaf 			case 'T':
83012542Scsvaf 				t->symvalue.rangev.lowertype = R_TEMP;
83112542Scsvaf                   		curchar++;
83212542Scsvaf 			        break;
83312542Scsvaf 
83412542Scsvaf 			case 'J':
83512542Scsvaf 				t->symvalue.rangev.lowertype = R_ADJUST;
83612542Scsvaf                   		curchar++;
83712542Scsvaf 			  	break;
83812542Scsvaf 
83912542Scsvaf 			default:
84012542Scsvaf 				 t->symvalue.rangev.lowertype = R_CONST;
84112542Scsvaf 			  	 break;
84212542Scsvaf 
84312542Scsvaf 		}
84412542Scsvaf 	        t->symvalue.rangev.lower = getint();
8459673Slinton 		skipchar(curchar, ';');
84612542Scsvaf 		switch(*curchar) {
84712542Scsvaf 			case 'A':
84812542Scsvaf 				t->symvalue.rangev.uppertype = R_ARG;
84912542Scsvaf                   		curchar++;
85012542Scsvaf 			        break;
85112542Scsvaf 
85212542Scsvaf 			case 'T':
85312542Scsvaf 				t->symvalue.rangev.uppertype = R_TEMP;
85412542Scsvaf                   		curchar++;
85512542Scsvaf 			        break;
85612542Scsvaf 
85712542Scsvaf 			case 'J':
85812542Scsvaf 				t->symvalue.rangev.uppertype = R_ADJUST;
85912542Scsvaf                   		curchar++;
86012542Scsvaf 			  	break;
86112542Scsvaf 
86212542Scsvaf 			default:
86312542Scsvaf 				 t->symvalue.rangev.uppertype = R_CONST;
86412542Scsvaf 			  	 break;
86512542Scsvaf 
86612542Scsvaf 		}
8679673Slinton 		t->symvalue.rangev.upper = getint();
8689673Slinton 		break;
8699673Slinton 
8709673Slinton 	    case 'a':
8719673Slinton 		t->class = ARRAY;
8729673Slinton 		t->chain = constype(nil);
8739673Slinton 		skipchar(curchar, ';');
8749673Slinton 		t->type = constype(nil);
8759673Slinton 		break;
8769673Slinton 
8779673Slinton 	    case 's':
8789673Slinton 	    case 'u':
8799673Slinton 		t->class = (class == 's') ? RECORD : VARNT;
8809673Slinton 		t->symvalue.offset = getint();
8819673Slinton 		u = t;
8829673Slinton 		cur = curchar;
8839673Slinton 		while (*cur != ';' and *cur != '\0') {
8849673Slinton 		    p = index(cur, ':');
8859673Slinton 		    if (p == nil) {
8869673Slinton 			panic("index(\"%s\", ':') failed", curchar);
8879673Slinton 		    }
8889673Slinton 		    *p = '\0';
8899673Slinton 		    name = identname(cur, true);
8909673Slinton 		    u->chain = newSymbol(name, b, FIELD, nil, nil);
8919673Slinton 		    cur = p + 1;
8929673Slinton 		    u = u->chain;
8939673Slinton 		    u->language = curlang;
8949673Slinton 		    curchar = cur;
8959673Slinton 		    u->type = constype(nil);
8969673Slinton 		    skipchar(curchar, ',');
8979673Slinton 		    u->symvalue.field.offset = getint();
8989673Slinton 		    skipchar(curchar, ',');
8999673Slinton 		    u->symvalue.field.length = getint();
9009673Slinton 		    skipchar(curchar, ';');
9019673Slinton 		    cur = curchar;
9029673Slinton 		}
9039673Slinton 		if (*cur == ';') {
9049673Slinton 		    ++cur;
9059673Slinton 		}
9069673Slinton 		curchar = cur;
9079673Slinton 		break;
9089673Slinton 
9099673Slinton 	    case 'e':
9109673Slinton 		t->class = SCAL;
9119673Slinton 		u = t;
9129673Slinton 		while (*curchar != ';' and *curchar != '\0') {
9139673Slinton 		    p = index(curchar, ':');
9149673Slinton 		    assert(p != nil);
9159673Slinton 		    *p = '\0';
9169673Slinton 		    u->chain = insert(identname(curchar, true));
9179673Slinton 		    curchar = p + 1;
9189673Slinton 		    u = u->chain;
9199673Slinton 		    u->language = curlang;
9209673Slinton 		    u->class = CONST;
9219673Slinton 		    u->level = b;
9229673Slinton 		    u->block = curblock;
9239673Slinton 		    u->type = t;
9249673Slinton 		    u->symvalue.iconval = getint();
9259673Slinton 		    skipchar(curchar, ',');
9269673Slinton 		}
9279673Slinton 		break;
9289673Slinton 
9299673Slinton 	    case '*':
9309673Slinton 		t->class = PTR;
9319673Slinton 		t->type = constype(nil);
9329673Slinton 		break;
9339673Slinton 
9349673Slinton 	    case 'f':
9359673Slinton 		t->class = FUNC;
9369673Slinton 		t->type = constype(nil);
9379673Slinton 		break;
9389673Slinton 
9399673Slinton 	    default:
9409673Slinton 		badcaseval(class);
9419673Slinton 	}
9429673Slinton     }
9439673Slinton     return t;
9449673Slinton }
9459673Slinton 
9469673Slinton /*
9479673Slinton  * Read an integer from the current position in the type string.
9489673Slinton  */
9499673Slinton 
9509673Slinton private Integer getint()
9519673Slinton {
9529673Slinton     register Integer n;
9539673Slinton     register char *p;
9549673Slinton     register Boolean isneg;
9559673Slinton 
9569673Slinton     n = 0;
9579673Slinton     p = curchar;
9589673Slinton     if (*p == '-') {
9599673Slinton 	isneg = true;
9609673Slinton 	++p;
9619673Slinton     } else {
9629673Slinton 	isneg = false;
9639673Slinton     }
9649673Slinton     while (isdigit(*p)) {
9659673Slinton 	n = 10*n + (*p - '0');
9669673Slinton 	++p;
9679673Slinton     }
9689673Slinton     curchar = p;
9699673Slinton     return isneg ? (-n) : n;
9709673Slinton }
9719673Slinton 
9729673Slinton /*
9739673Slinton  * Add a tag name.  This is a kludge to be able to refer
9749673Slinton  * to tags that have the same name as some other symbol
9759673Slinton  * in the same block.
9769673Slinton  */
9779673Slinton 
9789673Slinton private addtag(s)
9799673Slinton register Symbol s;
9809673Slinton {
9819673Slinton     register Symbol t;
9829673Slinton     char buf[100];
9839673Slinton 
9849673Slinton     sprintf(buf, "$$%.90s", ident(s->name));
9859673Slinton     t = insert(identname(buf, false));
9869673Slinton     t->language = s->language;
9879673Slinton     t->class = TAG;
9889673Slinton     t->type = s->type;
9899673Slinton     t->block = s->block;
9909673Slinton }
9919673Slinton 
9929673Slinton /*
9939673Slinton  * Allocate file and line tables and initialize indices.
9949673Slinton  */
9959673Slinton 
9969673Slinton private allocmaps(nf, nl)
9979673Slinton Integer nf, nl;
9989673Slinton {
9999673Slinton     if (filetab != nil) {
10009673Slinton 	dispose(filetab);
10019673Slinton     }
10029673Slinton     if (linetab != nil) {
10039673Slinton 	dispose(linetab);
10049673Slinton     }
10059673Slinton     filetab = newarr(Filetab, nf);
10069673Slinton     linetab = newarr(Linetab, nl);
10079673Slinton     filep = filetab;
10089673Slinton     linep = linetab;
10099673Slinton }
10109673Slinton 
10119673Slinton /*
10129673Slinton  * Add a file to the file table.
1013*13938Slinton  *
1014*13938Slinton  * If the new address is the same as the previous file address
1015*13938Slinton  * this routine used to not enter the file, but this caused some
1016*13938Slinton  * problems so it has been removed.  It's not clear that this in
1017*13938Slinton  * turn may not also cause a problem.
10189673Slinton  */
10199673Slinton 
10209673Slinton private enterfile(filename, addr)
10219673Slinton String filename;
10229673Slinton Address addr;
10239673Slinton {
1024*13938Slinton     filep->addr = addr;
1025*13938Slinton     filep->filename = filename;
1026*13938Slinton     filep->lineindex = linep - linetab;
1027*13938Slinton     ++filep;
10289673Slinton }
10299673Slinton 
10309673Slinton /*
10319673Slinton  * Since we only estimated the number of lines (and it was a poor
10329673Slinton  * estimation) and since we need to know the exact number of lines
10339673Slinton  * to do a binary search, we set it when we're done.
10349673Slinton  */
10359673Slinton 
10369673Slinton private setnlines()
10379673Slinton {
10389673Slinton     nlhdr.nlines = linep - linetab;
10399673Slinton }
10409673Slinton 
10419673Slinton /*
10429673Slinton  * Similarly for nfiles ...
10439673Slinton  */
10449673Slinton 
10459673Slinton private setnfiles()
10469673Slinton {
10479673Slinton     nlhdr.nfiles = filep - filetab;
10489673Slinton     setsource(filetab[0].filename);
10499673Slinton }
1050