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