/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)stab.c 5.2 (Berkeley) 10/23/85"; #endif not lint /* * Procedures to put out symbol table information * and stabs for separate compilation type checking. * These use the .stabs, .stabn, and .stabd directives. */ #include "whoami.h" #ifdef PC /* and the rest of the file */ # include "0.h" # include "objfmt.h" # include "yy.h" # include /* * additional symbol definition for * that is used by the separate compilation facility -- * eventually, should be updated to include this */ # include "pstab.h" # include "pc.h" #define private static int oldway = 0; /* * absolute value: line numbers are negative if error recovery. */ #define ABS( x ) ( x < 0 ? -x : x ) long checksum(); /* * Generate information about variables. */ stabgvar (p, length, line) struct nl *p; int length, line; { putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x", 0, p->symbol, N_PC, N_PGVAR, ABS(line) ); if (oldway != 0) { oldstabgvar(p->symbol, p2type(p->type), 0, length, line); } else if (opt('g')) { putprintf("\t.stabs\t\"%s:G", 1, p->symbol); gentype(p->type); putprintf("\",0x%x,0,0x%x,0", 0, N_GSYM, length); } } stablvar (p, offset, length) struct nl *p; int offset, length; { int level; level = (p->nl_block & 037); if (oldway != 0) { oldstablvar(p->symbol, p2type(p->type), level, offset, length); } else if (opt('g')) { putprintf("\t.stabs\t\"%s:", 1, p->symbol); gentype(p->type); putprintf("\",0x%x,0,0x%x,0x%x", 0, N_LSYM, length, offset); } } /* * global variables */ /*ARGSUSED*/ oldstabgvar( name , type , offset , length , line ) char *name; int type; int offset; int length; int line; { if ( ! opt('g') ) { return; } putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , (int) name ); putprintf( "\",0x%x,0,0x%x,0" , 0 , N_GSYM , type ); putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , (int) name ); putprintf( "\",0x%x,0,0,0x%x" , 0 , N_LENG , length ); } /* * local variables */ /*ARGSUSED*/ oldstablvar( name , type , level , offset , length ) char *name; int type; int level; int offset; int length; { if ( ! opt('g') ) { return; } putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , (int) name ); putprintf( "\",0x%x,0,0x%x,0x%x" , 0 , N_LSYM , type , -offset ); putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , (int) name ); putprintf( "\",0x%x,0,0,0x%x" , 0 , N_LENG , length ); } stabparam (p, offset, length) struct nl *p; int offset, length; { if (oldway != 0) { oldstabparam(p->symbol, p2type(p->type), offset, length); } else if (opt('g')) { putprintf("\t.stabs\t\"%s:", 1, p->symbol); if (p->class == REF) { putprintf("v", 1); } else { putprintf("p", 1); } gentype((p->class == FPROC || p->class ==FFUNC) ? p : p->type); putprintf("\",0x%x,0,0x%x,0x%x", 0, N_PSYM, length, offset); } } /* * parameters */ oldstabparam( name , type , offset , length ) char *name; int type; int offset; int length; { if ( ! opt('g') ) { return; } putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , (int) name ); putprintf( "\",0x%x,0,0x%x,0x%x" , 0 , N_PSYM , type , offset ); putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , (int) name ); putprintf( "\",0x%x,0,0,0x%x" , 0 , N_LENG , length ); } /* * fields */ /* * left brackets * (dbx handles module-2 without these, so we won't use them either) */ stablbrac( level ) int level; { if ( ! opt('g') || oldway == 0 ) { return; } putprintf( " .stabd 0x%x,0,0x%x" , 0 , N_LBRAC , level ); } /* * right brackets */ stabrbrac( level ) int level; { if ( ! opt('g') || oldway == 0 ) { return; } putprintf( " .stabd 0x%x,0,0x%x" , 0 , N_RBRAC , level ); } stabfunc (p, name, line, level) struct nl *p; char *name; int line, level; { char extname[BUFSIZ],nestspec[BUFSIZ]; if ( level == 1 ) { if (p->class == FUNC) { putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0 , name , N_PC , N_PGFUNC , ABS( line ) ); } else if (p->class == PROC) { putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0 , name , N_PC , N_PGPROC , ABS( line ) ); } } if (oldway != 0) { oldstabfunc(name, p->class, line, level); } else if (opt('g')) { putprintf("\t.stabs\t\"%s:", 1, name); if (p->class == FUNC) { putprintf("F", 1); gentype(p->type); putprintf(",", 1); } else { putprintf("P,", 1); } sextname(extname, name, level); /* set extname to entry label */ putprintf("%s,", 1, &(extname[1])); /* remove initial underbar */ snestspec(nestspec, level); putprintf("%s\",0x%x,0,0,%s", 0, nestspec, N_FUN, extname); } } /* * construct the colon-separated static nesting string into a * caller-supplied buffer */ private snestspec(buffer, level) char buffer[]; int level; { char *starthere; int i; if (level <= 1) { buffer[0] = '\0'; } else { starthere = &buffer[0]; for ( i = 1 ; i < level ; i++ ) { sprintf(starthere, "%s:", enclosing[i]); starthere += strlen(enclosing[i]) + 1; } *--starthere = '\0'; /* remove last colon */ if (starthere >= &buffer[BUFSIZ-1]) { panic("snestspec"); } } } /* * functions */ oldstabfunc( name , typeclass , line , level ) char *name; int typeclass; int line; long level; { char extname[ BUFSIZ ]; /* * for sdb */ if ( ! opt('g') ) { return; } putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , (int) name ); sextname( extname , name , (int) level ); putprintf( "\",0x%x,0,0x%x,%s" , 0 , N_FUN , line , (int) extname ); } /* * source line numbers */ stabline( line ) int line; { if ( ! opt('g') ) { return; } putprintf( " .stabd 0x%x,0,0x%x" , 0 , N_SLINE , ABS( line ) ); } /* * source files get none or more of these: * one as they are entered, * and one every time they are returned to from nested #includes */ stabsource(filename, firsttime) char *filename; bool firsttime; { int label; /* * for separate compilation */ putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x", 0, (int) filename, N_PC, N_PSO, N_FLAGCHECKSUM); /* * for debugger */ if ( ! opt('g') ) { return; } if (oldway != 0) { label = (int) getlab(); putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , filename ); putprintf( "\",0x%x,0,0," , 1 , N_SO ); putprintf( PREFIXFORMAT , 0 , LLABELPREFIX , label ); putprintf( PREFIXFORMAT , 1 , LLABELPREFIX , label ); putprintf( ":" , 0 ); } else { if (firsttime) { putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , filename ); putprintf( "\",0x%x,0,0,0" , 0 , N_SO ); } } } /* * included files get one or more of these: * one as they are entered by a #include, * and one every time they are returned to from nested #includes. */ stabinclude(filename, firsttime) char *filename; bool firsttime; { int label; long check; /* * for separate compilation */ if (firsttime) { check = checksum(filename); } else { check = N_FLAGCHECKSUM; } putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x", 0, (int) filename, N_PC, N_PSOL, check); /* * for sdb */ if ( ! opt('g') ) { return; } if (oldway != 0) { label = (int) getlab(); putprintf( " .stabs \"" , 1 ); putprintf( NAMEFORMAT , 1 , filename ); putprintf( "\",0x%x,0,0," , 1 , N_SOL ); putprintf( PREFIXFORMAT , 0 , LLABELPREFIX , label ); putprintf( PREFIXFORMAT , 1 , LLABELPREFIX , label ); putprintf( ":" , 0 ); } } /* * anyone know a good checksum for ascii files? * this does a rotate-left and then exclusive-or's in the character. * also, it avoids returning checksums of 0. * The rotate is implemented by shifting and adding back the * sign bit when negative. */ long checksum(filename) char *filename; { FILE *filep; register int input; register long check; filep = fopen(filename, "r"); if (filep == NULL) { perror(filename); pexit(DIED); } check = 0; while ((input = getc(filep)) != EOF) { if (check < 0) { check <<= 1; check += 1; } else { check <<= 1; } check ^= input; } (void) fclose(filep); if ((unsigned) check <= N_FLAGCHECKSUM) { return N_FLAGCHECKSUM + 1; } else { return check; } } /* * global Pascal symbols : * labels, types, constants, and external procedure and function names: * These are used by the separate compilation facility * to be able to check for disjoint header files. */ /* * global labels */ stabglabel( label , line ) char *label; int line; { putprintf( " .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0 , (int) label , N_PC , N_PGLABEL , ABS( line ) ); } /* * global constants */ stabgconst( const , line ) char *const; int line; { putprintf( " .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0 , (int) const , N_PC , N_PGCONST , ABS( line ) ); } /* * Generate symbolic information about a constant. */ stabconst (c) struct nl *c; { if (opt('g') && oldway == 0) { putprintf("\t.stabs\t\"%s:c=", 1, c->symbol); if (c->type == nl + TSTR) { putprintf("s'%s'", 1, c->ptr[0]); } else if (c->type == nl + T1CHAR) { putprintf("c%d", 1, c->range[0]); } else if (isa(c->type, "i")) { putprintf("i%d", 1, c->range[0]); } else if (isa(c->type, "d")) { putprintf("r%g", 1, c->real); } else { putprintf("e", 1); gentype(c->type); putprintf(",%d", 1, c->range[0]); } putprintf("\",0x%x,0,0x%x,0x%x", 0, N_LSYM, 0, 0); } } stabgtype (name, type, line) char *name; struct nl *type; int line; { putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0, name, N_PC , N_PGTYPE, ABS(line) ); if (oldway == 0) { stabltype(name, type); } } stabltype (name, type) char *name; struct nl *type; { if (opt('g')) { putprintf("\t.stabs\t\"%s:t", 1, name); gentype(type); putprintf("\",0x%x,0,0,0", 0, N_LSYM); } } /* * external functions and procedures */ stabefunc( name , typeclass , line ) char *name; int typeclass; int line; { int type; if ( typeclass == FUNC ) { type = N_PEFUNC; } else if ( typeclass == PROC ) { type = N_PEPROC; } else { return; } putprintf( " .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0 , (int) name , N_PC , type , ABS( line ) ); } /* * Generate type information encoded as a string for dbx. * The fwdptrnum field is used only when the type is a pointer * to a type that isn't known when it was entered. When the * type field is filled for some such tptr, fixfwdtype should * be called to output an equivalencing type definition. */ typedef struct TypeDesc *TypeDesc; struct TypeDesc { struct nl *tptr; int tnum; int fwdptrnum; TypeDesc chain; }; #define TABLESIZE 2003 #define typehash(t) ( ( ((int) t) >> 2 ) % TABLESIZE ) private int tcount = 1; private TypeDesc typetable[TABLESIZE]; private TypeDesc tdlookup (t) struct nl *t; { register TypeDesc td; td = typetable[typehash(t)]; while (td != NIL && td->tptr != t) { td = td->chain; } return td; } private int typelookup (t) struct nl *t; { register TypeDesc td; int r; td = tdlookup(t); if (td == NIL) { r = 0; } else { r = td->tnum; } return r; } private int entertype (type) struct nl *type; { register TypeDesc td; register int i; td = (TypeDesc) malloc(sizeof(struct TypeDesc)); td->tptr = type; td->tnum = tcount; td->fwdptrnum = 0; ++tcount; i = typehash(type); td->chain = typetable[i]; typetable[i] = td; return td->tnum; } /* * The in_types table currently contains "boolean", "char", "integer", * "real" and "_nil". (See nl.c for definition.) * The lookup call below will give the TYPE class nl entry for these * types. In each case except _nil, the type field of that entry is a RANGE * class nl entry for the type. Sometimes other symbol table entries * point to the TYPE entry (e.g., when there is a range over the base type), * and other entries point to the RANGE entry (e.g., for a variable of the * given type). We don't really want to distinguish between these uses * in dbx, and since it appears that the RANGE entries are not reused if * a range happens to coincide, we will give the two the same identifying * dbx type number. */ private inittypes() { int i; extern char *in_types[]; struct nl *p; for (i = 0; in_types[i] != NIL; i++) { p = lookup(in_types[i]); if (p != NIL) { entertype(p); if (p->type != NIL) { --tcount; /* see comment above */ entertype(p->type); } } } } static genarray (t) struct nl *t; { register struct nl *p; for (p = t->chain; p != NIL; p = p->chain) { putprintf("a", 1); gentype(p); putprintf(";", 1); } gentype(t->type); } /* * Really we should walk through ptr[NL_FIELDLIST] for the fields, * and then do the variant tag and fields separately, but dbx * doesn't support this yet. * So, since all the fields of all the variants are on the chain, * we walk through that. Except that this gives the fields in the * reverse order, so we want to print in reverse order. */ static genrecord (t) struct nl *t; { putprintf("s%d", 1, t->value[NL_OFFS]); if (t->chain != NIL) { genrecfield(t->chain, 1); } putprintf(";", 1); } static genrecfield (t, n) struct nl *t; int n; { if (t->chain != NULL) { genrecfield(t->chain, n + 1); if (n % 2 == 0) { gencontinue(); } } putprintf("%s:", 1, t->symbol); gentype(t->type); putprintf(",%d,%d;", 1, 8*t->value[NL_OFFS], 8*lwidth(t->type)); } static genvarnt (t) struct nl *t; { genrecord(t); } static genptr (t) struct nl *t; { register TypeDesc td; putprintf("*", 1); if (t->type != NIL) { gentype(t->type); } else { /* * unresolved forward pointer: use tcount to represent what is * begin pointed to, to be defined later */ td = tdlookup(t); if (td == NIL) { panic("nil ptr in stab.genptr"); } td->fwdptrnum = tcount; putprintf("%d", 1, tcount); ++tcount; } } /* * The type t is a pointer which has just had its type field filled. * We need to generate a type stab saying that the number saved * in t's fwdptrnum is the same as the t->type's number */ fixfwdtype (t) struct nl *t; { register TypeDesc td; if (opt('g') && oldway == 0) { td = tdlookup(t); if (td != NIL) { putprintf("\t.stabs\t\":t%d=", 1, td->fwdptrnum); gentype(t->type); putprintf("\",0x%x,0,0,0", 0, N_LSYM); } } } static genenum (t) struct nl *t; { register struct nl *e; register int i; putprintf("e", 1); i = 1; e = t->chain; while (e != NULL) { if (i > 2) { gencontinue(); i = 0; } putprintf("%s:%d,", 1, e->symbol, e->range[0]); e = e->chain; ++i; } putprintf(";", 1); } static genset (t) struct nl *t; { putprintf("S", 1); gentype(t->type); } static genrange (t) struct nl *t; { putprintf("r", 1); gentype(t->type); putprintf(";%d;%d", 1, t->range[0], t->range[1]); } static genfparam (t) struct nl *t; { struct nl *p; int count; if (t->type != NULL) { putprintf("f", 1); gentype(t->type); putprintf(",", 1); } else { putprintf("p", 1); } count = 0; for (p = t->ptr[NL_FCHAIN]; p != NULL; p = p->chain) { ++count; } putprintf("%d;", 1, count); for (p = t->ptr[NL_FCHAIN]; p != NULL; p = p->chain) { gentype(p->type); putprintf(",%d;", 1, p->class); } } static genfile (t) struct nl *t; { putprintf("d", 1); gentype(t->type); } static gentype (t) struct nl *t; { int id; if (tcount == 1) { inittypes(); } id = typelookup(t); if (id != 0) { putprintf("%d", 1, id); } else if (t->class == SCAL && t->chain == NULL) { id = typelookup(t->type); if (id != 0) { putprintf("%d", 1, id); } else { genenum(t->type); } } else { id = entertype(t); putprintf("%d=", 1, id); switch (t->class) { case TYPE: gentype(t->type); break; case ARRAY: genarray(t); break; case RECORD: genrecord(t); break; case VARNT: genvarnt(t); break; case REF: gentype(t->type); break; case PTR: genptr(t); break; case SET: genset(t); break; case RANGE: genrange(t); break; case SCAL: genenum(t); break; case FPROC: case FFUNC: genfparam(t); break; case FILET: case PTRFILE: genfile(t); break; default: /* This shouldn't happen */ /* Rather than bomb outright, let debugging go on */ warning(); error("Bad type class found in stab"); putprintf("1", 1, t->class); break; } } } /* * Continue stab information in a namelist new entry. This is necessary * to avoid overflowing putprintf's buffer. */ static gencontinue () { putprintf("?\",0x%x,0,0,0", 0, N_LSYM); putprintf("\t.stabs\t\"", 1); } #endif PC