1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)stab.c 5.2 (Berkeley) 10/23/85"; 9: #endif not lint 10: 11: /* 12: * Procedures to put out symbol table information 13: * and stabs for separate compilation type checking. 14: * These use the .stabs, .stabn, and .stabd directives. 15: */ 16: 17: #include "whoami.h" 18: #ifdef PC 19: /* and the rest of the file */ 20: # include "0.h" 21: # include "objfmt.h" 22: # include "yy.h" 23: # include <stab.h> 24: 25: /* 26: * additional symbol definition for <stab.h> 27: * that is used by the separate compilation facility -- 28: * eventually, <stab.h> should be updated to include this 29: */ 30: 31: # include "pstab.h" 32: # include "pc.h" 33: 34: 35: #define private static 36: 37: int oldway = 0; 38: 39: /* 40: * absolute value: line numbers are negative if error recovery. 41: */ 42: #define ABS( x ) ( x < 0 ? -x : x ) 43: long checksum(); 44: 45: /* 46: * Generate information about variables. 47: */ 48: 49: stabgvar (p, length, line) 50: struct nl *p; 51: int length, line; 52: { 53: putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x", 54: 0, p->symbol, N_PC, N_PGVAR, ABS(line) 55: ); 56: if (oldway != 0) { 57: oldstabgvar(p->symbol, p2type(p->type), 0, length, line); 58: } else if (opt('g')) { 59: putprintf("\t.stabs\t\"%s:G", 1, p->symbol); 60: gentype(p->type); 61: putprintf("\",0x%x,0,0x%x,0", 0, N_GSYM, length); 62: } 63: } 64: 65: stablvar (p, offset, length) 66: struct nl *p; 67: int offset, length; 68: { 69: int level; 70: 71: level = (p->nl_block & 037); 72: if (oldway != 0) { 73: oldstablvar(p->symbol, p2type(p->type), level, offset, length); 74: } else if (opt('g')) { 75: putprintf("\t.stabs\t\"%s:", 1, p->symbol); 76: gentype(p->type); 77: putprintf("\",0x%x,0,0x%x,0x%x", 0, N_LSYM, length, offset); 78: } 79: } 80: 81: /* 82: * global variables 83: */ 84: /*ARGSUSED*/ 85: oldstabgvar( name , type , offset , length , line ) 86: char *name; 87: int type; 88: int offset; 89: int length; 90: int line; 91: { 92: if ( ! opt('g') ) { 93: return; 94: } 95: putprintf( " .stabs \"" , 1 ); 96: putprintf( NAMEFORMAT , 1 , (int) name ); 97: putprintf( "\",0x%x,0,0x%x,0" , 0 , N_GSYM , type ); 98: putprintf( " .stabs \"" , 1 ); 99: putprintf( NAMEFORMAT , 1 , (int) name ); 100: putprintf( "\",0x%x,0,0,0x%x" , 0 , N_LENG , length ); 101: } 102: 103: /* 104: * local variables 105: */ 106: /*ARGSUSED*/ 107: oldstablvar( name , type , level , offset , length ) 108: char *name; 109: int type; 110: int level; 111: int offset; 112: int length; 113: { 114: 115: if ( ! opt('g') ) { 116: return; 117: } 118: putprintf( " .stabs \"" , 1 ); 119: putprintf( NAMEFORMAT , 1 , (int) name ); 120: putprintf( "\",0x%x,0,0x%x,0x%x" , 0 , N_LSYM , type , -offset ); 121: putprintf( " .stabs \"" , 1 ); 122: putprintf( NAMEFORMAT , 1 , (int) name ); 123: putprintf( "\",0x%x,0,0,0x%x" , 0 , N_LENG , length ); 124: } 125: 126: 127: stabparam (p, offset, length) 128: struct nl *p; 129: int offset, length; 130: { 131: if (oldway != 0) { 132: oldstabparam(p->symbol, p2type(p->type), offset, length); 133: } else if (opt('g')) { 134: putprintf("\t.stabs\t\"%s:", 1, p->symbol); 135: if (p->class == REF) { 136: putprintf("v", 1); 137: } else { 138: putprintf("p", 1); 139: } 140: gentype((p->class == FPROC || p->class ==FFUNC) ? p : p->type); 141: putprintf("\",0x%x,0,0x%x,0x%x", 0, N_PSYM, length, offset); 142: } 143: } 144: 145: /* 146: * parameters 147: */ 148: oldstabparam( name , type , offset , length ) 149: char *name; 150: int type; 151: int offset; 152: int length; 153: { 154: 155: if ( ! opt('g') ) { 156: return; 157: } 158: putprintf( " .stabs \"" , 1 ); 159: putprintf( NAMEFORMAT , 1 , (int) name ); 160: putprintf( "\",0x%x,0,0x%x,0x%x" , 0 , N_PSYM , type , offset ); 161: putprintf( " .stabs \"" , 1 ); 162: putprintf( NAMEFORMAT , 1 , (int) name ); 163: putprintf( "\",0x%x,0,0,0x%x" , 0 , N_LENG , length ); 164: } 165: 166: /* 167: * fields 168: */ 169: 170: /* 171: * left brackets 172: * (dbx handles module-2 without these, so we won't use them either) 173: */ 174: stablbrac( level ) 175: int level; 176: { 177: 178: if ( ! opt('g') || oldway == 0 ) { 179: return; 180: } 181: putprintf( " .stabd 0x%x,0,0x%x" , 0 , N_LBRAC , level ); 182: } 183: 184: /* 185: * right brackets 186: */ 187: stabrbrac( level ) 188: int level; 189: { 190: 191: if ( ! opt('g') || oldway == 0 ) { 192: return; 193: } 194: putprintf( " .stabd 0x%x,0,0x%x" , 0 , N_RBRAC , level ); 195: } 196: 197: stabfunc (p, name, line, level) 198: struct nl *p; 199: char *name; 200: int line, level; 201: { 202: char extname[BUFSIZ],nestspec[BUFSIZ]; 203: 204: if ( level == 1 ) { 205: if (p->class == FUNC) { 206: putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x" , 207: 0 , name , N_PC , N_PGFUNC , ABS( line ) 208: ); 209: } else if (p->class == PROC) { 210: putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x" , 211: 0 , name , N_PC , N_PGPROC , ABS( line ) 212: ); 213: } 214: } 215: if (oldway != 0) { 216: oldstabfunc(name, p->class, line, level); 217: } else if (opt('g')) { 218: putprintf("\t.stabs\t\"%s:", 1, name); 219: if (p->class == FUNC) { 220: putprintf("F", 1); 221: gentype(p->type); 222: putprintf(",", 1); 223: } else { 224: putprintf("P,", 1); 225: } 226: sextname(extname, name, level); /* set extname to entry label */ 227: putprintf("%s,", 1, &(extname[1])); /* remove initial underbar */ 228: snestspec(nestspec, level); 229: putprintf("%s\",0x%x,0,0,%s", 0, nestspec, N_FUN, extname); 230: } 231: } 232: 233: /* 234: * construct the colon-separated static nesting string into a 235: * caller-supplied buffer 236: */ 237: private snestspec(buffer, level) 238: char buffer[]; 239: int level; 240: { 241: char *starthere; 242: int i; 243: 244: if (level <= 1) { 245: buffer[0] = '\0'; 246: } else { 247: starthere = &buffer[0]; 248: for ( i = 1 ; i < level ; i++ ) { 249: sprintf(starthere, "%s:", enclosing[i]); 250: starthere += strlen(enclosing[i]) + 1; 251: } 252: *--starthere = '\0'; /* remove last colon */ 253: if (starthere >= &buffer[BUFSIZ-1]) { 254: panic("snestspec"); 255: } 256: } 257: } 258: 259: /* 260: * functions 261: */ 262: oldstabfunc( name , typeclass , line , level ) 263: char *name; 264: int typeclass; 265: int line; 266: long level; 267: { 268: char extname[ BUFSIZ ]; 269: 270: /* 271: * for sdb 272: */ 273: if ( ! opt('g') ) { 274: return; 275: } 276: putprintf( " .stabs \"" , 1 ); 277: putprintf( NAMEFORMAT , 1 , (int) name ); 278: sextname( extname , name , (int) level ); 279: putprintf( "\",0x%x,0,0x%x,%s" , 0 , N_FUN , line , (int) extname ); 280: } 281: 282: /* 283: * source line numbers 284: */ 285: stabline( line ) 286: int line; 287: { 288: if ( ! opt('g') ) { 289: return; 290: } 291: putprintf( " .stabd 0x%x,0,0x%x" , 0 , N_SLINE , ABS( line ) ); 292: } 293: 294: /* 295: * source files get none or more of these: 296: * one as they are entered, 297: * and one every time they are returned to from nested #includes 298: */ 299: stabsource(filename, firsttime) 300: char *filename; 301: bool firsttime; 302: { 303: int label; 304: 305: /* 306: * for separate compilation 307: */ 308: putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x", 0, 309: (int) filename, N_PC, N_PSO, N_FLAGCHECKSUM); 310: /* 311: * for debugger 312: */ 313: if ( ! opt('g') ) { 314: return; 315: } 316: if (oldway != 0) { 317: label = (int) getlab(); 318: putprintf( " .stabs \"" , 1 ); 319: putprintf( NAMEFORMAT , 1 , filename ); 320: putprintf( "\",0x%x,0,0," , 1 , N_SO ); 321: putprintf( PREFIXFORMAT , 0 , LLABELPREFIX , label ); 322: putprintf( PREFIXFORMAT , 1 , LLABELPREFIX , label ); 323: putprintf( ":" , 0 ); 324: } else { 325: if (firsttime) { 326: putprintf( " .stabs \"" , 1 ); 327: putprintf( NAMEFORMAT , 1 , filename ); 328: putprintf( "\",0x%x,0,0,0" , 0 , N_SO ); 329: } 330: } 331: } 332: 333: /* 334: * included files get one or more of these: 335: * one as they are entered by a #include, 336: * and one every time they are returned to from nested #includes. 337: */ 338: stabinclude(filename, firsttime) 339: char *filename; 340: bool firsttime; 341: { 342: int label; 343: long check; 344: 345: /* 346: * for separate compilation 347: */ 348: if (firsttime) { 349: check = checksum(filename); 350: } else { 351: check = N_FLAGCHECKSUM; 352: } 353: putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x", 0, 354: (int) filename, N_PC, N_PSOL, check); 355: /* 356: * for sdb 357: */ 358: if ( ! opt('g') ) { 359: return; 360: } 361: if (oldway != 0) { 362: label = (int) getlab(); 363: putprintf( " .stabs \"" , 1 ); 364: putprintf( NAMEFORMAT , 1 , filename ); 365: putprintf( "\",0x%x,0,0," , 1 , N_SOL ); 366: putprintf( PREFIXFORMAT , 0 , LLABELPREFIX , label ); 367: putprintf( PREFIXFORMAT , 1 , LLABELPREFIX , label ); 368: putprintf( ":" , 0 ); 369: } 370: } 371: 372: /* 373: * anyone know a good checksum for ascii files? 374: * this does a rotate-left and then exclusive-or's in the character. 375: * also, it avoids returning checksums of 0. 376: * The rotate is implemented by shifting and adding back the 377: * sign bit when negative. 378: */ 379: long 380: checksum(filename) 381: char *filename; 382: { 383: FILE *filep; 384: register int input; 385: register long check; 386: 387: filep = fopen(filename, "r"); 388: if (filep == NULL) { 389: perror(filename); 390: pexit(DIED); 391: } 392: check = 0; 393: while ((input = getc(filep)) != EOF) { 394: if (check < 0) { 395: check <<= 1; 396: check += 1; 397: } else { 398: check <<= 1; 399: } 400: check ^= input; 401: } 402: (void) fclose(filep); 403: if ((unsigned) check <= N_FLAGCHECKSUM) { 404: return N_FLAGCHECKSUM + 1; 405: } else { 406: return check; 407: } 408: } 409: 410: /* 411: * global Pascal symbols : 412: * labels, types, constants, and external procedure and function names: 413: * These are used by the separate compilation facility 414: * to be able to check for disjoint header files. 415: */ 416: 417: /* 418: * global labels 419: */ 420: stabglabel( label , line ) 421: char *label; 422: int line; 423: { 424: 425: putprintf( " .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0 426: , (int) label , N_PC , N_PGLABEL , ABS( line ) ); 427: } 428: 429: /* 430: * global constants 431: */ 432: stabgconst( const , line ) 433: char *const; 434: int line; 435: { 436: 437: putprintf( " .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0 438: , (int) const , N_PC , N_PGCONST , ABS( line ) ); 439: } 440: 441: /* 442: * Generate symbolic information about a constant. 443: */ 444: 445: stabconst (c) 446: struct nl *c; 447: { 448: if (opt('g') && oldway == 0) { 449: putprintf("\t.stabs\t\"%s:c=", 1, c->symbol); 450: if (c->type == nl + TSTR) { 451: putprintf("s'%s'", 1, c->ptr[0]); 452: } else if (c->type == nl + T1CHAR) { 453: putprintf("c%d", 1, c->range[0]); 454: } else if (isa(c->type, "i")) { 455: putprintf("i%d", 1, c->range[0]); 456: } else if (isa(c->type, "d")) { 457: putprintf("r%g", 1, c->real); 458: } else { 459: putprintf("e", 1); 460: gentype(c->type); 461: putprintf(",%d", 1, c->range[0]); 462: } 463: putprintf("\",0x%x,0,0x%x,0x%x", 0, N_LSYM, 0, 0); 464: } 465: } 466: 467: stabgtype (name, type, line) 468: char *name; 469: struct nl *type; 470: int line; 471: { 472: putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x" , 473: 0, name, N_PC , N_PGTYPE, ABS(line) 474: ); 475: if (oldway == 0) { 476: stabltype(name, type); 477: } 478: } 479: 480: stabltype (name, type) 481: char *name; 482: struct nl *type; 483: { 484: if (opt('g')) { 485: putprintf("\t.stabs\t\"%s:t", 1, name); 486: gentype(type); 487: putprintf("\",0x%x,0,0,0", 0, N_LSYM); 488: } 489: } 490: 491: /* 492: * external functions and procedures 493: */ 494: stabefunc( name , typeclass , line ) 495: char *name; 496: int typeclass; 497: int line; 498: { 499: int type; 500: 501: if ( typeclass == FUNC ) { 502: type = N_PEFUNC; 503: } else if ( typeclass == PROC ) { 504: type = N_PEPROC; 505: } else { 506: return; 507: } 508: putprintf( " .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0 509: , (int) name , N_PC , type , ABS( line ) ); 510: } 511: 512: /* 513: * Generate type information encoded as a string for dbx. 514: * The fwdptrnum field is used only when the type is a pointer 515: * to a type that isn't known when it was entered. When the 516: * type field is filled for some such tptr, fixfwdtype should 517: * be called to output an equivalencing type definition. 518: */ 519: 520: typedef struct TypeDesc *TypeDesc; 521: 522: struct TypeDesc { 523: struct nl *tptr; 524: int tnum; 525: int fwdptrnum; 526: TypeDesc chain; 527: }; 528: 529: #define TABLESIZE 2003 530: 531: #define typehash(t) ( ( ((int) t) >> 2 ) % TABLESIZE ) 532: 533: private int tcount = 1; 534: private TypeDesc typetable[TABLESIZE]; 535: 536: private TypeDesc tdlookup (t) 537: struct nl *t; 538: { 539: register TypeDesc td; 540: 541: td = typetable[typehash(t)]; 542: while (td != NIL && td->tptr != t) { 543: td = td->chain; 544: } 545: return td; 546: } 547: 548: private int typelookup (t) 549: struct nl *t; 550: { 551: register TypeDesc td; 552: int r; 553: 554: td = tdlookup(t); 555: if (td == NIL) { 556: r = 0; 557: } else { 558: r = td->tnum; 559: } 560: return r; 561: } 562: 563: private int entertype (type) 564: struct nl *type; 565: { 566: register TypeDesc td; 567: register int i; 568: 569: td = (TypeDesc) malloc(sizeof(struct TypeDesc)); 570: td->tptr = type; 571: td->tnum = tcount; 572: td->fwdptrnum = 0; 573: ++tcount; 574: i = typehash(type); 575: td->chain = typetable[i]; 576: typetable[i] = td; 577: return td->tnum; 578: } 579: 580: /* 581: * The in_types table currently contains "boolean", "char", "integer", 582: * "real" and "_nil". (See nl.c for definition.) 583: * The lookup call below will give the TYPE class nl entry for these 584: * types. In each case except _nil, the type field of that entry is a RANGE 585: * class nl entry for the type. Sometimes other symbol table entries 586: * point to the TYPE entry (e.g., when there is a range over the base type), 587: * and other entries point to the RANGE entry (e.g., for a variable of the 588: * given type). We don't really want to distinguish between these uses 589: * in dbx, and since it appears that the RANGE entries are not reused if 590: * a range happens to coincide, we will give the two the same identifying 591: * dbx type number. 592: */ 593: 594: private inittypes() 595: { 596: int i; 597: extern char *in_types[]; 598: struct nl *p; 599: 600: for (i = 0; in_types[i] != NIL; i++) { 601: p = lookup(in_types[i]); 602: if (p != NIL) { 603: entertype(p); 604: if (p->type != NIL) { 605: --tcount; /* see comment above */ 606: entertype(p->type); 607: } 608: } 609: } 610: } 611: 612: static genarray (t) 613: struct nl *t; 614: { 615: register struct nl *p; 616: 617: for (p = t->chain; p != NIL; p = p->chain) { 618: putprintf("a", 1); 619: gentype(p); 620: putprintf(";", 1); 621: } 622: gentype(t->type); 623: } 624: 625: /* 626: * Really we should walk through ptr[NL_FIELDLIST] for the fields, 627: * and then do the variant tag and fields separately, but dbx 628: * doesn't support this yet. 629: * So, since all the fields of all the variants are on the chain, 630: * we walk through that. Except that this gives the fields in the 631: * reverse order, so we want to print in reverse order. 632: */ 633: 634: static genrecord (t) 635: struct nl *t; 636: { 637: putprintf("s%d", 1, t->value[NL_OFFS]); 638: if (t->chain != NIL) { 639: genrecfield(t->chain, 1); 640: } 641: putprintf(";", 1); 642: } 643: 644: static genrecfield (t, n) 645: struct nl *t; 646: int n; 647: { 648: if (t->chain != NULL) { 649: genrecfield(t->chain, n + 1); 650: if (n % 2 == 0) { 651: gencontinue(); 652: } 653: } 654: putprintf("%s:", 1, t->symbol); 655: gentype(t->type); 656: putprintf(",%d,%d;", 1, 8*t->value[NL_OFFS], 8*lwidth(t->type)); 657: } 658: 659: static genvarnt (t) 660: struct nl *t; 661: { 662: genrecord(t); 663: } 664: 665: static genptr (t) 666: struct nl *t; 667: { 668: register TypeDesc td; 669: 670: putprintf("*", 1); 671: if (t->type != NIL) { 672: gentype(t->type); 673: } else { 674: /* 675: * unresolved forward pointer: use tcount to represent what is 676: * begin pointed to, to be defined later 677: */ 678: td = tdlookup(t); 679: if (td == NIL) { 680: panic("nil ptr in stab.genptr"); 681: } 682: td->fwdptrnum = tcount; 683: putprintf("%d", 1, tcount); 684: ++tcount; 685: } 686: } 687: 688: /* 689: * The type t is a pointer which has just had its type field filled. 690: * We need to generate a type stab saying that the number saved 691: * in t's fwdptrnum is the same as the t->type's number 692: */ 693: 694: fixfwdtype (t) 695: struct nl *t; 696: { 697: register TypeDesc td; 698: 699: if (opt('g') && oldway == 0) { 700: td = tdlookup(t); 701: if (td != NIL) { 702: putprintf("\t.stabs\t\":t%d=", 1, td->fwdptrnum); 703: gentype(t->type); 704: putprintf("\",0x%x,0,0,0", 0, N_LSYM); 705: } 706: } 707: } 708: 709: static genenum (t) 710: struct nl *t; 711: { 712: register struct nl *e; 713: register int i; 714: 715: putprintf("e", 1); 716: i = 1; 717: e = t->chain; 718: while (e != NULL) { 719: if (i > 2) { 720: gencontinue(); 721: i = 0; 722: } 723: putprintf("%s:%d,", 1, e->symbol, e->range[0]); 724: e = e->chain; 725: ++i; 726: } 727: putprintf(";", 1); 728: } 729: 730: static genset (t) 731: struct nl *t; 732: { 733: putprintf("S", 1); 734: gentype(t->type); 735: } 736: 737: static genrange (t) 738: struct nl *t; 739: { 740: putprintf("r", 1); 741: gentype(t->type); 742: putprintf(";%d;%d", 1, t->range[0], t->range[1]); 743: } 744: 745: static genfparam (t) 746: struct nl *t; 747: { 748: struct nl *p; 749: int count; 750: 751: if (t->type != NULL) { 752: putprintf("f", 1); 753: gentype(t->type); 754: putprintf(",", 1); 755: } else { 756: putprintf("p", 1); 757: } 758: count = 0; 759: for (p = t->ptr[NL_FCHAIN]; p != NULL; p = p->chain) { 760: ++count; 761: } 762: putprintf("%d;", 1, count); 763: for (p = t->ptr[NL_FCHAIN]; p != NULL; p = p->chain) { 764: gentype(p->type); 765: putprintf(",%d;", 1, p->class); 766: } 767: } 768: 769: static genfile (t) 770: struct nl *t; 771: { 772: putprintf("d", 1); 773: gentype(t->type); 774: } 775: 776: static gentype (t) 777: struct nl *t; 778: { 779: int id; 780: 781: if (tcount == 1) { 782: inittypes(); 783: } 784: id = typelookup(t); 785: if (id != 0) { 786: putprintf("%d", 1, id); 787: } else if (t->class == SCAL && t->chain == NULL) { 788: id = typelookup(t->type); 789: if (id != 0) { 790: putprintf("%d", 1, id); 791: } else { 792: genenum(t->type); 793: } 794: } else { 795: id = entertype(t); 796: putprintf("%d=", 1, id); 797: switch (t->class) { 798: case TYPE: 799: gentype(t->type); 800: break; 801: 802: case ARRAY: 803: genarray(t); 804: break; 805: 806: case RECORD: 807: genrecord(t); 808: break; 809: 810: case VARNT: 811: genvarnt(t); 812: break; 813: 814: case REF: 815: gentype(t->type); 816: break; 817: 818: case PTR: 819: genptr(t); 820: break; 821: 822: case SET: 823: genset(t); 824: break; 825: 826: case RANGE: 827: genrange(t); 828: break; 829: 830: case SCAL: 831: genenum(t); 832: break; 833: 834: case FPROC: 835: case FFUNC: 836: genfparam(t); 837: break; 838: 839: case FILET: 840: case PTRFILE: 841: genfile(t); 842: break; 843: 844: default: 845: /* This shouldn't happen */ 846: /* Rather than bomb outright, let debugging go on */ 847: warning(); 848: error("Bad type class found in stab"); 849: putprintf("1", 1, t->class); 850: break; 851: } 852: } 853: } 854: 855: /* 856: * Continue stab information in a namelist new entry. This is necessary 857: * to avoid overflowing putprintf's buffer. 858: */ 859: 860: static gencontinue () 861: { 862: putprintf("?\",0x%x,0,0,0", 0, N_LSYM); 863: putprintf("\t.stabs\t\"", 1); 864: } 865: 866: #endif PC