19673Slinton /* Copyright (c) 1982 Regents of the University of California */ 29673Slinton 3*9840Slinton static char sccsid[] = "@(#)object.c 1.3 12/18/82"; 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; 419673Slinton 429673Slinton private Filetab *filep; 439673Slinton private Linetab *linep; 449673Slinton private Address curfaddr; 459673Slinton 469673Slinton #define curfilename() (filep-1)->filename 479673Slinton 489673Slinton /* 499673Slinton * Blocks are figured out on the fly while reading the symbol table. 509673Slinton */ 519673Slinton 529673Slinton #define MAXBLKDEPTH 25 539673Slinton 549673Slinton private Symbol curblock; 559673Slinton private Symbol blkstack[MAXBLKDEPTH]; 569673Slinton private Integer curlevel; 579673Slinton 589673Slinton #define enterblock(b) { \ 599673Slinton blkstack[curlevel] = curblock; \ 609673Slinton ++curlevel; \ 619673Slinton b->level = curlevel; \ 629673Slinton b->block = curblock; \ 639673Slinton curblock = b; \ 649673Slinton } 659673Slinton 669673Slinton #define exitblock() { \ 679673Slinton --curlevel; \ 689673Slinton curblock = blkstack[curlevel]; \ 699673Slinton } 709673Slinton 719673Slinton /* 729673Slinton * Enter a source line or file name reference into the appropriate table. 739673Slinton * Expanded inline to reduce procedure calls. 749673Slinton * 759673Slinton * private enterline(linenumber, address) 769673Slinton * Lineno linenumber; 779673Slinton * Address address; 789673Slinton * ... 799673Slinton */ 809673Slinton 819673Slinton #define enterline(linenumber, address) \ 829673Slinton { \ 839673Slinton register Linetab *lp; \ 849673Slinton \ 859673Slinton lp = linep - 1; \ 869673Slinton if (linenumber != lp->line) { \ 879673Slinton if (address != lp->addr) { \ 889673Slinton ++lp; \ 899673Slinton } \ 909673Slinton lp->line = linenumber; \ 919673Slinton lp->addr = address; \ 929673Slinton linep = lp + 1; \ 939673Slinton } \ 949673Slinton } 959673Slinton 969673Slinton #define NTYPES 1000 979673Slinton 989673Slinton private Symbol typetable[NTYPES]; 999673Slinton 1009673Slinton /* 1019673Slinton * Read in the namelist from the obj file. 1029673Slinton * 1039673Slinton * Reads and seeks are used instead of fread's and fseek's 1049673Slinton * for efficiency sake; there's a lot of data being read here. 1059673Slinton */ 1069673Slinton 1079673Slinton public readobj(file) 1089673Slinton String file; 1099673Slinton { 1109673Slinton Fileid f; 1119673Slinton struct exec hdr; 1129673Slinton struct nlist nlist; 1139673Slinton 1149673Slinton f = open(file, 0); 1159673Slinton if (f < 0) { 1169673Slinton fatal("can't open %s", file); 1179673Slinton } 1189673Slinton read(f, &hdr, sizeof(hdr)); 1199673Slinton objsize = hdr.a_text; 1209673Slinton nlhdr.nsyms = hdr.a_syms / sizeof(nlist); 1219673Slinton nlhdr.nfiles = nlhdr.nsyms; 1229673Slinton nlhdr.nlines = nlhdr.nsyms; 1239673Slinton lseek(f, (long) N_STROFF(hdr), 0); 1249673Slinton read(f, &(nlhdr.stringsize), sizeof(nlhdr.stringsize)); 1259673Slinton nlhdr.stringsize -= 4; 1269673Slinton stringtab = newarr(char, nlhdr.stringsize); 1279673Slinton read(f, stringtab, nlhdr.stringsize); 1289673Slinton allocmaps(nlhdr.nfiles, nlhdr.nlines); 1299673Slinton lseek(f, (long) N_SYMOFF(hdr), 0); 1309673Slinton readsyms(f); 1319673Slinton ordfunctab(); 1329673Slinton setnlines(); 1339673Slinton setnfiles(); 1349673Slinton close(f); 1359673Slinton } 1369673Slinton 1379673Slinton /* 1389673Slinton * Read in symbols from object file. 1399673Slinton */ 1409673Slinton 1419673Slinton private readsyms(f) 1429673Slinton Fileid f; 1439673Slinton { 1449673Slinton struct nlist *namelist; 1459673Slinton register struct nlist *np, *ub; 1469673Slinton register int index; 1479673Slinton register String name; 1489673Slinton register Boolean afterlg; 1499673Slinton 1509673Slinton initsyms(); 1519673Slinton namelist = newarr(struct nlist, nlhdr.nsyms); 1529673Slinton read(f, namelist, nlhdr.nsyms * sizeof(struct nlist)); 1539673Slinton afterlg = false; 1549673Slinton ub = &namelist[nlhdr.nsyms]; 1559673Slinton for (np = &namelist[0]; np < ub; np++) { 1569673Slinton index = np->n_un.n_strx; 1579673Slinton if (index != 0) { 1589673Slinton name = &stringtab[index - 4]; 1599673Slinton } else { 1609673Slinton name = nil; 1619673Slinton } 1629673Slinton /* 1639673Slinton * assumptions: 1649673Slinton * not an N_STAB ==> name != nil 1659673Slinton * name[0] == '-' ==> name == "-lg" 1669673Slinton * name[0] != '_' ==> filename or invisible 1679673Slinton * 1689673Slinton * The "-lg" signals the beginning of global loader symbols. 1699673Slinton */ 1709673Slinton if ((np->n_type&N_STAB) != 0) { 1719673Slinton enter_nl(name, np); 1729673Slinton } else if (name[0] == '-') { 1739673Slinton afterlg = true; 1749673Slinton if (curblock->class != PROG) { 1759673Slinton exitblock(); 1769673Slinton if (curblock->class != PROG) { 1779673Slinton exitblock(); 1789673Slinton } 1799673Slinton } 1809673Slinton enterline(0, (linep-1)->addr + 1); 1819673Slinton } else if (name[0] == '_') { 1829673Slinton if (afterlg) { 1839673Slinton check_global(&name[1], np); 1849673Slinton } else if (curblock->name != nil) { 1859673Slinton check_local(&name[1], np); 1869673Slinton } 1879673Slinton } else if ((np->n_type&N_TEXT) == N_TEXT) { 1889673Slinton check_filename(name); 1899673Slinton } 1909673Slinton } 1919673Slinton dispose(namelist); 1929673Slinton } 1939673Slinton 1949673Slinton /* 1959673Slinton * Initialize symbol information. 1969673Slinton */ 1979673Slinton 1989673Slinton private initsyms() 1999673Slinton { 2009673Slinton curblock = nil; 2019673Slinton curlevel = 0; 2029673Slinton if (progname == nil) { 2039673Slinton progname = strdup(objname); 2049673Slinton if (rindex(progname, '/') != nil) { 2059673Slinton progname = rindex(progname, '/') + 1; 2069673Slinton } 2079673Slinton if (index(progname, '.') != nil) { 2089673Slinton *(index(progname, '.')) = '\0'; 2099673Slinton } 2109673Slinton } 2119673Slinton program = insert(identname(progname, true)); 2129673Slinton program->class = PROG; 2139673Slinton newfunc(program); 2149673Slinton findbeginning(program); 2159673Slinton enterblock(program); 2169673Slinton curmodule = program; 2179673Slinton t_boolean = maketype("$boolean", 0L, 1L); 2189673Slinton t_int = maketype("$integer", 0x80000000L, 0x7fffffffL); 2199673Slinton t_char = maketype("$char", 0L, 127L); 2209673Slinton t_real = maketype("$real", 4L, 0L); 2219673Slinton t_nil = maketype("$nil", 0L, 0L); 2229673Slinton } 2239673Slinton 2249673Slinton /* 2259673Slinton * Free all the object file information that's being stored. 2269673Slinton */ 2279673Slinton 2289673Slinton public objfree() 2299673Slinton { 2309673Slinton symbol_free(); 2319673Slinton keywords_free(); 2329673Slinton names_free(); 2339673Slinton dispose(stringtab); 2349673Slinton clrfunctab(); 2359673Slinton } 2369673Slinton 2379673Slinton /* 2389673Slinton * Enter a namelist entry. 2399673Slinton */ 2409673Slinton 2419673Slinton private enter_nl(name, np) 2429673Slinton String name; 2439673Slinton register struct nlist *np; 2449673Slinton { 2459673Slinton register Symbol s; 2469673Slinton String mname, suffix; 2479673Slinton register Name n; 2489673Slinton register Symbol *tt; 2499673Slinton 2509673Slinton s = nil; 2519673Slinton if (name == nil) { 2529673Slinton n = nil; 2539673Slinton } else { 2549673Slinton n = identname(name, true); 2559673Slinton } 2569673Slinton switch (np->n_type) { 2579673Slinton case N_LBRAC: 2589673Slinton s = symbol_alloc(); 2599673Slinton s->class = PROC; 2609673Slinton enterblock(s); 2619673Slinton break; 2629673Slinton 2639673Slinton case N_RBRAC: 2649673Slinton exitblock(); 2659673Slinton break; 2669673Slinton 2679673Slinton case N_SLINE: 2689673Slinton enterline((Lineno) np->n_desc, (Address) np->n_value); 2699673Slinton break; 2709673Slinton 2719673Slinton /* 2729673Slinton * Compilation unit. C associates scope with filenames 2739673Slinton * so we treat them as "modules". The filename without 2749673Slinton * the suffix is used for the module name. 2759673Slinton * 2769673Slinton * Because there is no explicit "end-of-block" mark in 2779673Slinton * the object file, we must exit blocks for the current 2789673Slinton * procedure and module. 2799673Slinton */ 2809673Slinton case N_SO: 2819673Slinton mname = strdup(ident(n)); 2829673Slinton if (rindex(mname, '/') != nil) { 2839673Slinton mname = rindex(mname, '/') + 1; 2849673Slinton } 2859673Slinton suffix = rindex(mname, '.'); 2869673Slinton curlang = findlanguage(suffix); 2879673Slinton if (suffix != nil) { 2889673Slinton *suffix = '\0'; 2899673Slinton } 2909673Slinton if (curblock->class != PROG) { 2919673Slinton exitblock(); 2929673Slinton if (curblock->class != PROG) { 2939673Slinton exitblock(); 2949673Slinton } 2959673Slinton } 2969673Slinton s = insert(identname(mname, true)); 2979673Slinton s->language = curlang; 2989673Slinton s->class = MODULE; 2999673Slinton enterblock(s); 3009673Slinton curmodule = s; 3019673Slinton if (program->language == nil) { 3029673Slinton program->language = curlang; 3039673Slinton } 3049673Slinton warned = false; 3059673Slinton enterfile(ident(n), (Address) np->n_value); 3069673Slinton for (tt = &typetable[0]; tt < &typetable[NTYPES]; tt++) { 3079673Slinton *tt = nil; 3089673Slinton } 3099673Slinton break; 3109673Slinton 3119673Slinton /* 3129673Slinton * Textually included files. 3139673Slinton */ 3149673Slinton case N_SOL: 3159673Slinton enterfile(name, (Address) np->n_value); 3169673Slinton break; 3179673Slinton 3189673Slinton /* 3199673Slinton * These symbols are assumed to have non-nil names. 3209673Slinton */ 3219673Slinton case N_GSYM: 3229673Slinton case N_FUN: 3239673Slinton case N_STSYM: 3249673Slinton case N_LCSYM: 3259673Slinton case N_RSYM: 3269673Slinton case N_PSYM: 3279673Slinton case N_LSYM: 3289673Slinton case N_SSYM: 3299673Slinton if (index(name, ':') == nil) { 3309673Slinton if (not warned) { 3319673Slinton warned = true; 3329673Slinton /* 3339673Slinton * Shouldn't do this if user might be typing. 3349673Slinton * 3359673Slinton warning("old style symbol information found in \"%s\"", 3369673Slinton curfilename()); 3379673Slinton * 3389673Slinton */ 3399673Slinton } 3409673Slinton } else { 3419673Slinton entersym(name, np); 3429673Slinton } 3439673Slinton break; 3449673Slinton 3459673Slinton case N_PC: 3469673Slinton break; 3479673Slinton 348*9840Slinton case N_LENG: 349*9840Slinton /* 350*9840Slinton * Should complain out this, obviously the wrong symbol format. 351*9840Slinton */ 352*9840Slinton break; 353*9840Slinton 3549673Slinton default: 3559673Slinton if (name != nil) { 3569673Slinton printf("%s, ", name); 3579673Slinton } 3589673Slinton printf("ntype %2x, desc %x, value %x\n", 3599673Slinton np->n_type, np->n_desc, np->n_value); 3609673Slinton break; 3619673Slinton } 3629673Slinton } 3639673Slinton 3649673Slinton /* 3659673Slinton * Check to see if a global _name is already in the symbol table, 3669673Slinton * if not then insert it. 3679673Slinton */ 3689673Slinton 3699673Slinton private check_global(name, np) 3709673Slinton String name; 3719673Slinton register struct nlist *np; 3729673Slinton { 3739673Slinton register Name n; 3749673Slinton register Symbol t; 3759673Slinton 3769673Slinton if (not streq(name, "end")) { 3779673Slinton n = identname(name, true); 3789673Slinton if ((np->n_type&N_TYPE) == N_TEXT) { 3799673Slinton find(t, n) where 3809673Slinton t->level == program->level and isblock(t) 3819673Slinton endfind(t); 3829673Slinton if (t == nil) { 3839673Slinton t = insert(n); 3849673Slinton t->language = findlanguage(".s"); 3859673Slinton t->class = FUNC; 3869673Slinton t->type = t_int; 3879673Slinton t->block = curblock; 3889673Slinton t->level = program->level; 3899673Slinton } 3909673Slinton t->symvalue.funcv.beginaddr = np->n_value; 3919673Slinton newfunc(t); 3929673Slinton findbeginning(t); 3939673Slinton } else { 3949673Slinton find(t, n) where 3959673Slinton t->class == VAR and t->level == program->level 3969673Slinton endfind(t); 3979673Slinton if (t == nil) { 3989673Slinton t = insert(n); 3999673Slinton t->language = findlanguage(".s"); 4009673Slinton t->class = VAR; 4019673Slinton t->type = t_int; 4029673Slinton t->block = curblock; 4039673Slinton t->level = program->level; 4049673Slinton } 4059673Slinton t->symvalue.offset = np->n_value; 4069673Slinton } 4079673Slinton } 4089673Slinton } 4099673Slinton 4109673Slinton /* 4119673Slinton * Check to see if a local _name is known in the current scope. 4129673Slinton * If not then enter it. 4139673Slinton */ 4149673Slinton 4159673Slinton private check_local(name, np) 4169673Slinton String name; 4179673Slinton register struct nlist *np; 4189673Slinton { 4199673Slinton register Name n; 4209673Slinton register Symbol t, cur; 4219673Slinton 4229673Slinton n = identname(name, true); 4239673Slinton cur = ((np->n_type&N_TYPE) == N_TEXT) ? curmodule : curblock; 4249673Slinton find(t, n) where t->block == cur endfind(t); 4259673Slinton if (t == nil) { 4269673Slinton t = insert(n); 4279673Slinton t->language = findlanguage(".s"); 4289673Slinton t->type = t_int; 4299673Slinton t->block = cur; 4309673Slinton t->level = cur->level; 4319673Slinton if ((np->n_type&N_TYPE) == N_TEXT) { 4329673Slinton t->class = FUNC; 4339673Slinton t->symvalue.funcv.beginaddr = np->n_value; 4349673Slinton newfunc(t); 4359673Slinton findbeginning(t); 4369673Slinton } else { 4379673Slinton t->class = VAR; 4389673Slinton t->symvalue.offset = np->n_value; 4399673Slinton } 4409673Slinton } 4419673Slinton } 4429673Slinton 4439673Slinton /* 4449673Slinton * Check to see if a symbol corresponds to a object file name. 4459673Slinton * For some reason these are listed as in the text segment. 4469673Slinton */ 4479673Slinton 4489673Slinton private check_filename(name) 4499673Slinton String name; 4509673Slinton { 4519673Slinton register String mname; 4529673Slinton register Integer i; 4539673Slinton register Symbol s; 4549673Slinton 4559673Slinton mname = strdup(name); 4569673Slinton i = strlen(mname) - 2; 4579673Slinton if (i >= 0 and mname[i] == '.' and mname[i+1] == 'o') { 4589673Slinton mname[i] = '\0'; 4599673Slinton --i; 4609673Slinton while (mname[i] != '/' and i >= 0) { 4619673Slinton --i; 4629673Slinton } 4639673Slinton s = insert(identname(&mname[i+1], true)); 4649673Slinton s->language = findlanguage(".s"); 4659673Slinton s->class = MODULE; 4669673Slinton if (curblock->class != PROG) { 4679673Slinton exitblock(); 4689673Slinton if (curblock->class != PROG) { 4699673Slinton exitblock(); 4709673Slinton } 4719673Slinton } 4729673Slinton enterblock(s); 4739673Slinton curmodule = s; 4749673Slinton } 4759673Slinton } 4769673Slinton 4779673Slinton /* 4789673Slinton * Put an nlist into the symbol table. 4799673Slinton * If it's already there just add the associated information. 4809673Slinton * 4819673Slinton * Type information is encoded in the name following a ":". 4829673Slinton */ 4839673Slinton 4849673Slinton private Symbol constype(); 4859673Slinton private Char *curchar; 4869673Slinton 4879673Slinton #define skipchar(ptr, ch) { \ 4889673Slinton if (*ptr != ch) { \ 4899673Slinton panic("expected char '%c', found char '%c'", ch, *ptr); \ 4909673Slinton } \ 4919673Slinton ++ptr; \ 4929673Slinton } 4939673Slinton 4949673Slinton private entersym(str, np) 4959673Slinton String str; 4969673Slinton struct nlist *np; 4979673Slinton { 4989673Slinton register Symbol s; 4999673Slinton register char *p; 5009673Slinton register int c; 5019673Slinton register Name n; 5029673Slinton register Integer i; 5039673Slinton Boolean knowtype, isnew; 5049673Slinton Symclass class; 5059673Slinton Integer level; 5069673Slinton 5079673Slinton p = index(str, ':'); 5089673Slinton *p = '\0'; 5099673Slinton c = *(p+1); 5109673Slinton n = identname(str, true); 5119673Slinton if (index("FfGV", c) != nil) { 5129673Slinton if (c == 'F' or c == 'f') { 5139673Slinton class = FUNC; 5149673Slinton } else { 5159673Slinton class = VAR; 5169673Slinton } 5179673Slinton level = (c == 'f' ? curmodule->level : program->level); 5189673Slinton find(s, n) where s->level == level and s->class == class endfind(s); 5199673Slinton if (s == nil) { 5209673Slinton isnew = true; 5219673Slinton s = insert(n); 5229673Slinton } else { 5239673Slinton isnew = false; 5249673Slinton } 5259673Slinton } else { 5269673Slinton isnew = true; 5279673Slinton s = insert(n); 5289673Slinton } 5299673Slinton 5309673Slinton /* 5319673Slinton * Default attributes. 5329673Slinton */ 5339673Slinton s->language = curlang; 5349673Slinton s->class = VAR; 5359673Slinton s->block = curblock; 5369673Slinton s->level = curlevel; 5379673Slinton s->symvalue.offset = np->n_value; 5389673Slinton curchar = p + 2; 5399673Slinton knowtype = false; 5409673Slinton switch (c) { 5419673Slinton case 't': /* type name */ 5429673Slinton s->class = TYPE; 5439673Slinton i = getint(); 5449673Slinton if (i == 0) { 5459673Slinton panic("bad input on type \"%s\" at \"%s\"", symname(s), 5469673Slinton curchar); 5479673Slinton } else if (i >= NTYPES) { 5489673Slinton panic("too many types in file \"%s\"", curfilename()); 5499673Slinton } 5509673Slinton /* 5519673Slinton * A hack for C typedefs that don't create new types, 5529673Slinton * e.g. typedef unsigned int Hashvalue; 5539673Slinton */ 5549673Slinton if (*curchar == '\0') { 5559673Slinton s->type = typetable[i]; 5569673Slinton if (s->type == nil) { 5579673Slinton panic("nil type for %d", i); 5589673Slinton } 5599673Slinton knowtype = true; 5609673Slinton } else { 5619673Slinton typetable[i] = s; 5629673Slinton skipchar(curchar, '='); 5639673Slinton } 5649673Slinton break; 5659673Slinton 5669673Slinton case 'T': /* tag */ 5679673Slinton s->class = TAG; 5689673Slinton i = getint(); 5699673Slinton if (i == 0) { 5709673Slinton panic("bad input on tag \"%s\" at \"%s\"", symname(s), 5719673Slinton curchar); 5729673Slinton } else if (i >= NTYPES) { 5739673Slinton panic("too many types in file \"%s\"", curfilename()); 5749673Slinton } 5759673Slinton if (typetable[i] != nil) { 5769673Slinton typetable[i]->language = curlang; 5779673Slinton typetable[i]->class = TYPE; 5789673Slinton typetable[i]->type = s; 5799673Slinton } else { 5809673Slinton typetable[i] = s; 5819673Slinton } 5829673Slinton skipchar(curchar, '='); 5839673Slinton break; 5849673Slinton 5859673Slinton case 'F': /* public function */ 5869673Slinton case 'f': /* private function */ 5879673Slinton s->class = FUNC; 5889673Slinton if (curblock->class == FUNC or curblock->class == PROC) { 5899673Slinton exitblock(); 5909673Slinton } 5919673Slinton enterblock(s); 5929673Slinton if (c == 'F') { 5939673Slinton s->level = program->level; 5949673Slinton isnew = false; 5959673Slinton } 5969673Slinton curparam = s; 5979673Slinton if (isnew) { 5989673Slinton s->symvalue.funcv.beginaddr = np->n_value; 5999673Slinton newfunc(s); 6009673Slinton findbeginning(s); 6019673Slinton } 6029673Slinton break; 6039673Slinton 6049673Slinton case 'G': /* public variable */ 6059673Slinton s->level = program->level; 6069673Slinton break; 6079673Slinton 6089673Slinton case 'S': /* private variable */ 6099673Slinton s->level = curmodule->level; 6109673Slinton s->block = curmodule; 6119673Slinton break; 6129673Slinton 6139673Slinton case 'V': /* own variable */ 6149673Slinton s->level = 2; 6159673Slinton break; 6169673Slinton 6179673Slinton case 'r': /* register variable */ 6189673Slinton s->level = -(s->level); 6199673Slinton break; 6209673Slinton 6219673Slinton case 'p': /* parameter variable */ 6229673Slinton curparam->chain = s; 6239673Slinton curparam = s; 6249673Slinton break; 6259673Slinton 6269673Slinton case 'v': /* varies parameter */ 6279673Slinton s->class = REF; 6289673Slinton s->symvalue.offset = np->n_value; 6299673Slinton curparam->chain = s; 6309673Slinton curparam = s; 6319673Slinton break; 6329673Slinton 6339673Slinton default: /* local variable */ 6349673Slinton --curchar; 6359673Slinton break; 6369673Slinton } 6379673Slinton if (not knowtype) { 6389673Slinton s->type = constype(nil); 6399673Slinton if (s->class == TAG) { 6409673Slinton addtag(s); 6419673Slinton } 6429673Slinton } 6439673Slinton if (tracesyms) { 6449673Slinton printdecl(s); 6459673Slinton fflush(stdout); 6469673Slinton } 6479673Slinton } 6489673Slinton 6499673Slinton /* 6509673Slinton * Construct a type out of a string encoding. 6519673Slinton * 6529673Slinton * The forms of the string are 6539673Slinton * 6549673Slinton * <number> 6559673Slinton * <number>=<type> 6569673Slinton * r<type>;<number>;<number> $ subrange 6579673Slinton * a<type>;<type> $ array[index] of element 6589673Slinton * s{<name>:<type>;<number>;<number>} $ record 6599673Slinton * *<type> $ pointer 6609673Slinton */ 6619673Slinton 6629673Slinton private Symbol constype(type) 6639673Slinton Symbol type; 6649673Slinton { 6659673Slinton register Symbol t, u; 6669673Slinton register Char *p, *cur; 6679673Slinton register Integer n; 6689673Slinton Integer b; 6699673Slinton Name name; 6709673Slinton Char class; 6719673Slinton 6729673Slinton b = curlevel; 6739673Slinton if (isdigit(*curchar)) { 6749673Slinton n = getint(); 6759673Slinton if (n == 0) { 6769673Slinton panic("bad type number at \"%s\"", curchar); 6779673Slinton } else if (n >= NTYPES) { 6789673Slinton panic("too many types in file \"%s\"", curfilename()); 6799673Slinton } 6809673Slinton if (*curchar == '=') { 6819673Slinton if (typetable[n] != nil) { 6829673Slinton t = typetable[n]; 6839673Slinton } else { 6849673Slinton t = symbol_alloc(); 6859673Slinton typetable[n] = t; 6869673Slinton } 6879673Slinton ++curchar; 6889673Slinton constype(t); 6899673Slinton } else { 6909673Slinton t = typetable[n]; 6919673Slinton if (t == nil) { 6929673Slinton t = symbol_alloc(); 6939673Slinton typetable[n] = t; 6949673Slinton } 6959673Slinton } 6969673Slinton } else { 6979673Slinton if (type == nil) { 6989673Slinton t = symbol_alloc(); 6999673Slinton } else { 7009673Slinton t = type; 7019673Slinton } 7029673Slinton t->language = curlang; 7039673Slinton t->level = b; 7049673Slinton class = *curchar++; 7059673Slinton switch (class) { 7069673Slinton case 'r': 7079673Slinton t->class = RANGE; 7089673Slinton t->type = constype(nil); 7099673Slinton skipchar(curchar, ';'); 7109673Slinton t->symvalue.rangev.lower = getint(); 7119673Slinton skipchar(curchar, ';'); 7129673Slinton t->symvalue.rangev.upper = getint(); 7139673Slinton break; 7149673Slinton 7159673Slinton case 'a': 7169673Slinton t->class = ARRAY; 7179673Slinton t->chain = constype(nil); 7189673Slinton skipchar(curchar, ';'); 7199673Slinton t->type = constype(nil); 7209673Slinton break; 7219673Slinton 7229673Slinton case 's': 7239673Slinton case 'u': 7249673Slinton t->class = (class == 's') ? RECORD : VARNT; 7259673Slinton t->symvalue.offset = getint(); 7269673Slinton u = t; 7279673Slinton cur = curchar; 7289673Slinton while (*cur != ';' and *cur != '\0') { 7299673Slinton p = index(cur, ':'); 7309673Slinton if (p == nil) { 7319673Slinton panic("index(\"%s\", ':') failed", curchar); 7329673Slinton } 7339673Slinton *p = '\0'; 7349673Slinton name = identname(cur, true); 7359673Slinton u->chain = newSymbol(name, b, FIELD, nil, nil); 7369673Slinton cur = p + 1; 7379673Slinton u = u->chain; 7389673Slinton u->language = curlang; 7399673Slinton curchar = cur; 7409673Slinton u->type = constype(nil); 7419673Slinton skipchar(curchar, ','); 7429673Slinton u->symvalue.field.offset = getint(); 7439673Slinton skipchar(curchar, ','); 7449673Slinton u->symvalue.field.length = getint(); 7459673Slinton skipchar(curchar, ';'); 7469673Slinton cur = curchar; 7479673Slinton } 7489673Slinton if (*cur == ';') { 7499673Slinton ++cur; 7509673Slinton } 7519673Slinton curchar = cur; 7529673Slinton break; 7539673Slinton 7549673Slinton case 'e': 7559673Slinton t->class = SCAL; 7569673Slinton u = t; 7579673Slinton while (*curchar != ';' and *curchar != '\0') { 7589673Slinton p = index(curchar, ':'); 7599673Slinton assert(p != nil); 7609673Slinton *p = '\0'; 7619673Slinton u->chain = insert(identname(curchar, true)); 7629673Slinton curchar = p + 1; 7639673Slinton u = u->chain; 7649673Slinton u->language = curlang; 7659673Slinton u->class = CONST; 7669673Slinton u->level = b; 7679673Slinton u->block = curblock; 7689673Slinton u->type = t; 7699673Slinton u->symvalue.iconval = getint(); 7709673Slinton skipchar(curchar, ','); 7719673Slinton } 7729673Slinton break; 7739673Slinton 7749673Slinton case '*': 7759673Slinton t->class = PTR; 7769673Slinton t->type = constype(nil); 7779673Slinton break; 7789673Slinton 7799673Slinton case 'f': 7809673Slinton t->class = FUNC; 7819673Slinton t->type = constype(nil); 7829673Slinton break; 7839673Slinton 7849673Slinton default: 7859673Slinton badcaseval(class); 7869673Slinton } 7879673Slinton } 7889673Slinton return t; 7899673Slinton } 7909673Slinton 7919673Slinton /* 7929673Slinton * Read an integer from the current position in the type string. 7939673Slinton */ 7949673Slinton 7959673Slinton private Integer getint() 7969673Slinton { 7979673Slinton register Integer n; 7989673Slinton register char *p; 7999673Slinton register Boolean isneg; 8009673Slinton 8019673Slinton n = 0; 8029673Slinton p = curchar; 8039673Slinton if (*p == '-') { 8049673Slinton isneg = true; 8059673Slinton ++p; 8069673Slinton } else { 8079673Slinton isneg = false; 8089673Slinton } 8099673Slinton while (isdigit(*p)) { 8109673Slinton n = 10*n + (*p - '0'); 8119673Slinton ++p; 8129673Slinton } 8139673Slinton curchar = p; 8149673Slinton return isneg ? (-n) : n; 8159673Slinton } 8169673Slinton 8179673Slinton /* 8189673Slinton * Add a tag name. This is a kludge to be able to refer 8199673Slinton * to tags that have the same name as some other symbol 8209673Slinton * in the same block. 8219673Slinton */ 8229673Slinton 8239673Slinton private addtag(s) 8249673Slinton register Symbol s; 8259673Slinton { 8269673Slinton register Symbol t; 8279673Slinton char buf[100]; 8289673Slinton 8299673Slinton sprintf(buf, "$$%.90s", ident(s->name)); 8309673Slinton t = insert(identname(buf, false)); 8319673Slinton t->language = s->language; 8329673Slinton t->class = TAG; 8339673Slinton t->type = s->type; 8349673Slinton t->block = s->block; 8359673Slinton } 8369673Slinton 8379673Slinton /* 8389673Slinton * Allocate file and line tables and initialize indices. 8399673Slinton */ 8409673Slinton 8419673Slinton private allocmaps(nf, nl) 8429673Slinton Integer nf, nl; 8439673Slinton { 8449673Slinton if (filetab != nil) { 8459673Slinton dispose(filetab); 8469673Slinton } 8479673Slinton if (linetab != nil) { 8489673Slinton dispose(linetab); 8499673Slinton } 8509673Slinton filetab = newarr(Filetab, nf); 8519673Slinton linetab = newarr(Linetab, nl); 8529673Slinton filep = filetab; 8539673Slinton linep = linetab; 8549673Slinton } 8559673Slinton 8569673Slinton /* 8579673Slinton * Add a file to the file table. 8589673Slinton */ 8599673Slinton 8609673Slinton private enterfile(filename, addr) 8619673Slinton String filename; 8629673Slinton Address addr; 8639673Slinton { 8649673Slinton if (addr != curfaddr) { 8659673Slinton filep->addr = addr; 8669673Slinton filep->filename = filename; 8679673Slinton filep->lineindex = linep - linetab; 8689673Slinton ++filep; 8699673Slinton curfaddr = addr; 8709673Slinton } 8719673Slinton } 8729673Slinton 8739673Slinton /* 8749673Slinton * Since we only estimated the number of lines (and it was a poor 8759673Slinton * estimation) and since we need to know the exact number of lines 8769673Slinton * to do a binary search, we set it when we're done. 8779673Slinton */ 8789673Slinton 8799673Slinton private setnlines() 8809673Slinton { 8819673Slinton nlhdr.nlines = linep - linetab; 8829673Slinton } 8839673Slinton 8849673Slinton /* 8859673Slinton * Similarly for nfiles ... 8869673Slinton */ 8879673Slinton 8889673Slinton private setnfiles() 8899673Slinton { 8909673Slinton nlhdr.nfiles = filep - filetab; 8919673Slinton setsource(filetab[0].filename); 8929673Slinton } 893