* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
static char sccsid
[] = "@(#)stab.c 5.3 (Berkeley) 1/3/88";
* Procedures to put out symbol table information
* and stabs for separate compilation type checking.
* These use the .stabs, .stabn, and .stabd directives.
/* and the rest of the file */
* additional symbol definition for <stab.h>
* that is used by the separate compilation facility --
* eventually, <stab.h> should be updated to include this
* absolute value: line numbers are negative if error recovery.
#define ABS( x ) ( x < 0 ? -x : x )
* Generate information about variables.
stabgvar (p
, length
, line
)
putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x",
0, p
->symbol
, N_PC
, N_PGVAR
, ABS(line
)
oldstabgvar(p
->symbol
, p2type(p
->type
), 0, length
, line
);
putprintf("\t.stabs\t\"%s:G", 1, p
->symbol
);
putprintf("\",0x%x,0,0x%x,0", 0, N_GSYM
, length
);
stablvar (p
, offset
, length
)
level
= (p
->nl_block
& 037);
oldstablvar(p
->symbol
, p2type(p
->type
), level
, offset
, length
);
putprintf("\t.stabs\t\"%s:", 1, p
->symbol
);
putprintf("\",0x%x,0,0x%x,0x%x", 0, N_LSYM
, length
, offset
);
oldstabgvar( name
, type
, offset
, length
, line
)
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
);
oldstablvar( name
, type
, level
, offset
, length
)
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
)
oldstabparam(p
->symbol
, p2type(p
->type
), offset
, length
);
putprintf("\t.stabs\t\"%s:", 1, p
->symbol
);
gentype((p
->class == FPROC
|| p
->class ==FFUNC
) ? p
: p
->type
);
putprintf("\",0x%x,0,0x%x,0x%x", 0, N_PSYM
, length
, offset
);
oldstabparam( name
, type
, offset
, length
)
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
);
* (dbx handles module-2 without these, so we won't use them either)
if ( ! opt('g') || oldway
== 0 ) {
putprintf( " .stabd 0x%x,0,0x%x" , 0 , N_LBRAC
, level
);
if ( ! opt('g') || oldway
== 0 ) {
putprintf( " .stabd 0x%x,0,0x%x" , 0 , N_RBRAC
, level
);
stabfunc (p
, name
, line
, level
)
char extname
[BUFSIZ
],nestspec
[BUFSIZ
];
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
)
oldstabfunc(name
, p
->class, line
, level
);
putprintf("\t.stabs\t\"%s:", 1, name
);
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
private snestspec(buffer
, level
)
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]) {
oldstabfunc( name
, typeclass
, line
, level
)
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
);
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
)
* for separate compilation
putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x", 0,
(int) filename
, N_PC
, N_PSO
, N_FLAGCHECKSUM
);
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( " .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
)
* for separate compilation
check
= checksum(filename
);
putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x", 0,
(int) filename
, N_PC
, N_PSOL
, check
);
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
);
* 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.
filep
= fopen(filename
, "r");
while ((input
= getc(filep
)) != EOF
) {
if ((unsigned) check
<= N_FLAGCHECKSUM
) {
return N_FLAGCHECKSUM
+ 1;
* 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.
stabglabel( label
, line
)
putprintf( " .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0
, (int) label
, N_PC
, N_PGLABEL
, ABS( line
) );
stabgconst( constant
, line
)
putprintf( " .stabs \"%s\",0x%x,0,0x%x,0x%x" , 0
, (int) constant
, N_PC
, N_PGCONST
, ABS( line
) );
* Generate symbolic information about a constant.
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
);
putprintf(",%d", 1, c
->range
[0]);
putprintf("\",0x%x,0,0x%x,0x%x", 0, N_LSYM
, 0, 0);
stabgtype (name
, type
, line
)
putprintf(" .stabs \"%s\",0x%x,0,0x%x,0x%x" ,
0, name
, N_PC
, N_PGTYPE
, ABS(line
)
putprintf("\t.stabs\t\"%s:t", 1, name
);
putprintf("\",0x%x,0,0,0", 0, N_LSYM
);
* external functions and procedures
stabefunc( name
, typeclass
, line
)
if ( typeclass
== FUNC
) {
} else if ( typeclass
== PROC
) {
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
;
#define typehash(t) ( ( ((int) t) >> 2 ) % TABLESIZE )
private TypeDesc typetable
[TABLESIZE
];
private TypeDesc
tdlookup (t
)
td
= typetable
[typehash(t
)];
while (td
!= NIL
&& td
->tptr
!= t
) {
private int typelookup (t
)
private int entertype (type
)
td
= (TypeDesc
) malloc(sizeof(struct TypeDesc
));
td
->chain
= typetable
[i
];
* 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
for (i
= 0; in_types
[i
] != NIL
; i
++) {
--tcount
; /* see comment above */
for (p
= t
->chain
; p
!= NIL
; p
= p
->chain
) {
* 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.
putprintf("s%d", 1, t
->value
[NL_OFFS
]);
genrecfield(t
->chain
, 1);
static genrecfield (t
, n
)
genrecfield(t
->chain
, n
+ 1);
putprintf("%s:", 1, t
->symbol
);
putprintf(",%d,%d;", 1, 8*t
->value
[NL_OFFS
], 8*lwidth(t
->type
));
* unresolved forward pointer: use tcount to represent what is
* begin pointed to, to be defined later
panic("nil ptr in stab.genptr");
putprintf("%d", 1, 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
if (opt('g') && oldway
== 0) {
putprintf("\t.stabs\t\":t%d=", 1, td
->fwdptrnum
);
putprintf("\",0x%x,0,0,0", 0, N_LSYM
);
putprintf("%s:%d,", 1, e
->symbol
, e
->range
[0]);
putprintf(";%d;%d", 1, t
->range
[0], t
->range
[1]);
for (p
= t
->ptr
[NL_FCHAIN
]; p
!= NULL
; p
= p
->chain
) {
putprintf("%d;", 1, count
);
for (p
= t
->ptr
[NL_FCHAIN
]; p
!= NULL
; p
= p
->chain
) {
putprintf(",%d;", 1, p
->class);
} else if (t
->class == SCAL
&& t
->chain
== NULL
) {
id
= typelookup(t
->type
);
/* This shouldn't happen */
/* Rather than bomb outright, let debugging go on */
error("Bad type class found in stab");
putprintf("1", 1, t
->class);
* Continue stab information in a namelist new entry. This is necessary
* to avoid overflowing putprintf's buffer.
putprintf("?\",0x%x,0,0,0", 0, N_LSYM
);
putprintf("\t.stabs\t\"", 1);