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