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