BSD 4_1c_2 release
[unix-history] / usr / src / lib / pcc / stab.c
/*
* Symbolic debugging info interface.
*
* Here we generate pseudo-ops that cause the assembler to put
* symbolic debugging information into the object file.
*/
static char *sccsid ="@(#)stab.c 1.4 (Berkeley) 2/2/83";
#include "mfile1"
#include <sys/types.h>
#include <a.out.h>
#include <stab.h>
#define private static
#define and &&
#define or ||
#define not !
#define div /
#define mod %
#define nil 0
#define bytes(bits) ((bits) / SZCHAR)
#define bsize(p) bytes(dimtab[p->sizoff]) /* size in bytes of a symbol */
#define NILINDEX -1
#define FORWARD -2
typedef int Boolean;
#define false 0
#define true 1
extern int ddebug;
extern int gdebug;
extern char *malloc();
int stabLCSYM;
/*
* Flag for producing either sdb or dbx symbol information.
*/
int oldway = false;
/*
* Generate debugging info for a parameter.
* The offset isn't known when it is first entered into the symbol table
* since the types are read later.
*/
fixarg(p)
struct symtab *p;
{
if (oldway) {
old_fixarg(p);
} else if (gdebug) {
printf("\t.stabs\t\"%s:p", p->sname);
gentype(p);
printf("\",0x%x,0,%d,%d\n", N_PSYM, bsize(p), bytes(argoff));
}
}
/*
* Generate debugging info for a given symbol.
*/
outstab(sym)
struct symtab *sym;
{
register struct symtab *p;
char *classname;
int offset;
Boolean ignore;
static Boolean firsttime = true;
if (oldway) {
old_outstab(sym);
} else if (gdebug) {
if (firsttime) {
firsttime = false;
inittypes();
}
ignore = false;
p = sym;
offset = bytes(p->offset);
switch (p->sclass) {
case REGISTER:
classname = "r";
offset = p->offset;
break;
/*
* Locals are the default class.
*/
case AUTO:
classname = "";
break;
case STATIC:
if (ISFTN(p->stype)) {
ignore = true;
} else if (p->slevel <= 1) {
classname = "S";
} else {
classname = "V";
}
break;
case EXTDEF:
case EXTERN:
if (ISFTN(p->stype)) {
ignore = true;
} else {
classname = "G";
}
break;
case TYPEDEF:
classname = "t";
break;
case PARAM:
case MOS:
case MOU:
case MOE:
ignore = true;
break;
case ENAME:
case UNAME:
case STNAME:
entertype(p->stype, NILINDEX, FORWARD, dimtab[p->sizoff + 3]);
ignore = true;
break;
default:
if ((p->sclass&FIELD) == 0) {
printf("/* no info for %s (%d) */\n", p->sname, p->sclass);
}
ignore = true;
break;
}
if (not ignore) {
printf("\t.stabs\t\"%s:%s", p->sname, classname);
gentype(p);
geninfo(p);
}
}
}
/*
* Since type names are lost in the travels and because C has
* structural type equivalence we keep a table of type words that
* we've already seen. The first time we see a type, it is assigned
* (inline) a number and future references just list that number.
* Structures, unions, enums, and arrays must be handled carefully
* since not all the necessary information is in the type word.
*/
typedef struct Typeid *Typeid;
struct Typeid {
TWORD tword;
int tarray;
int tstruct;
int tstrtag;
int tnum;
Typeid chain;
};
#define TABLESIZE 2003
private int tcount = 1;
private int t_int, t_char;
private Typeid typetable[TABLESIZE];
/*
* Look for the given type word in the type table.
*/
private Typeid typelookup(type, arrindex, strindex, strtag)
TWORD type;
int arrindex;
int strindex;
int strtag;
{
register TWORD tword;
register int i1, i2;
Typeid t;
t = typetable[type mod TABLESIZE];
while (t != nil) {
if (t->tword == type and
strindex == t->tstruct and strtag == t->tstrtag) {
if (arrindex == NILINDEX) {
break;
} else {
tword = type >> TSHIFT;
i1 = arrindex;
i2 = t->tarray;
while (ISARY(tword) and dimtab[i1] == dimtab[i2]) {
++i1;
++i2;
tword >>= TSHIFT;
}
if (!ISARY(tword)) {
break;
}
}
}
t = t->chain;
}
return t;
}
/*
* Enter a type word and associated symtab indices into the type table.
*/
private int entertype(type, arrindex, strindex, strtag)
TWORD type;
int arrindex;
int strindex;
int strtag;
{
register Typeid t;
register int i;
t = (Typeid) malloc(sizeof(struct Typeid));
t->tword = type;
t->tarray = arrindex;
t->tstruct = strindex;
t->tstrtag = strtag;
t->tnum = tcount;
++tcount;
i = type mod TABLESIZE;
t->chain = typetable[i];
typetable[i] = t;
return t->tnum;
}
/*
* Change the information associated with a type table entry.
* Since I'm lazy this just creates a new entry with the number
* as the old one.
*/
private reentertype(typeid, type, arrindex, strindex, strtag)
Typeid typeid;
TWORD type;
int arrindex;
int strindex;
int strtag;
{
register Typeid t;
register int i;
t = (Typeid) malloc(sizeof(struct Typeid));
t->tword = type;
t->tarray = arrindex;
t->tstruct = strindex;
t->tstrtag = strtag;
t->tnum = typeid->tnum;
i = type mod TABLESIZE;
t->chain = typetable[i];
typetable[i] = t;
}
/*
* Initialize type table with predefined types.
*/
#define builtintype(type) entertype(type, NILINDEX, NILINDEX, NILINDEX)
private inittypes()
{
int t;
t_int = builtintype(INT);
t_char = builtintype(CHAR);
maketype("int", t_int, t_int, 0x80000000L, 0x7fffffffL);
maketype("char", t_char, t_char, 0L, 127L);
maketype("long", builtintype(LONG), t_int, 0x80000000L, 0x7fffffffL);
maketype("short", builtintype(SHORT), t_int, 0xffff8000L, 0x7fffL);
maketype("unsigned char", builtintype(UCHAR), t_int, 0L, 255L);
maketype("unsigned short", builtintype(USHORT), t_int, 0L, 0xffffL);
maketype("unsigned long", builtintype(ULONG), t_int, 0L, 0xffffffffL);
maketype("unsigned int", builtintype(UNSIGNED), t_int, 0L, 0xffffffffL);
maketype("float", builtintype(FLOAT), t_int, 4L, 0L);
maketype("double", builtintype(DOUBLE), t_int, 8L, 0L);
t = builtintype(UNDEF);
printf("\t.stabs\t\"void:t%d=%d", t, t);
geninfo(nil);
t = builtintype(FARG);
printf("\t.stabs\t\"???:t%d=%d", t, t_int);
geninfo(nil);
}
/*
* Generate info for a new range type.
*/
private maketype(name, tnum, eqtnum, lower, upper)
char *name;
int tnum, eqtnum;
long lower, upper;
{
printf("\t.stabs\t\"%s:t%d=r%d;%d;%d;", name, tnum, eqtnum, lower, upper);
geninfo(nil);
}
/*
* Generate debugging information for the given type of the given symbol.
*/
private gentype(sym)
struct symtab *sym;
{
register struct symtab *p;
register TWORD t;
register TWORD basictype;
register Typeid typeid;
int i, arrindex, strindex, strtag;
p = sym;
t = p->stype;
if (ISFTN(t)) {
t = DECREF(t);
}
basictype = BTYPE(t);
if (ISARY(t)) {
arrindex = p->dimoff;
} else {
arrindex = NILINDEX;
}
if (basictype == STRTY or basictype == UNIONTY or basictype == ENUMTY) {
strindex = dimtab[p->sizoff + 1];
if (strindex == -1) {
strindex = FORWARD;
strtag = dimtab[p->sizoff + 3];
} else {
strtag = NILINDEX;
}
} else {
strindex = NILINDEX;
strtag = NILINDEX;
}
i = arrindex;
typeid = typelookup(t, arrindex, strindex, strtag);
while (t != basictype and typeid == nil) {
printf("%d=", entertype(t, i, strindex, strtag));
switch (t&TMASK) {
case PTR:
printf("*");
break;
case FTN:
printf("f");
break;
case ARY:
printf("ar%d;0;%d;", t_int, dimtab[i++] - 1);
break;
}
t = DECREF(t);
if (t == basictype) {
typeid = typelookup(t, NILINDEX, strindex, strtag);
} else {
typeid = typelookup(t, i, strindex, strtag);
}
}
if (typeid == nil) {
if (strindex == FORWARD) {
typeid = typelookup(t, NILINDEX, FORWARD, dimtab[p->sizoff + 3]);
if (typeid == nil) {
cerror("unbelievable forward reference");
}
printf("%d", typeid->tnum);
} else {
genstruct(t, NILINDEX, strindex, p->sname, bsize(p));
}
} else {
printf("%d", typeid->tnum);
}
}
/*
* Generate type information for structures, unions, and enumerations.
*/
private genstruct(t, structid, index, name, size)
TWORD t;
int structid;
int index;
char *name;
int size;
{
register int i;
register struct symtab *field;
int id;
if (structid == NILINDEX) {
id = entertype(t, NILINDEX, index, NILINDEX);
} else {
id = structid;
}
switch (t) {
case STRTY:
case UNIONTY:
printf("%d=%c%d", id, t == STRTY ? 's' : 'u', size);
i = index;
while (dimtab[i] != -1) {
field = &stab[dimtab[i]];
printf("%s:", field->sname);
gentype(field);
if (field->sclass > FIELD) {
printf(",%d,%d;", field->offset, field->sclass - FIELD);
} else {
printf(",%d,%d;", field->offset,
tsize(field->stype, field->dimoff, field->sizoff));
}
++i;
}
putchar(';');
break;
case ENUMTY:
printf("%d=e", id);
i = index;
while (dimtab[i] != -1) {
field = &stab[dimtab[i]];
printf("%s:%d,", field->sname, field->offset);
i++;
}
break;
default:
cerror("couldn't find basic type %d for %s\n", t, name);
break;
}
}
/*
* Generate offset and size info.
*/
private geninfo(p)
register struct symtab *p;
{
if (p == nil) {
printf("\",0x%x,0,0,0\n", N_LSYM);
} else {
switch (p->sclass) {
case EXTERN:
case EXTDEF:
if (ISFTN(p->stype)) {
printf("\",0x%x,0,%d,_%s\n", N_FUN, bsize(p), p->sname);
} else {
printf("\",0x%x,0,%d,0\n", N_GSYM, bsize(p));
}
break;
case STATIC:
if (ISFTN(p->stype)) {
printf("\",0x%x,0,%d,_%s\n", N_FUN, bsize(p), p->sname);
} else if (p->slevel > 1) {
printf("\",0x%x,0,%d,L%d\n", N_STSYM, bsize(p), p->offset);
} else {
printf("\",0x%x,0,%d,_%s\n", N_LCSYM, bsize(p), p->sname);
}
break;
case REGISTER:
printf("\",0x%x,0,%d,%d\n", N_RSYM, bsize(p), p->offset);
break;
case PARAM:
printf("\",0x%x,0,%d,%d\n", N_PSYM, bsize(p), bytes(argoff));
break;
default:
printf("\",0x%x,0,%d,%d\n", N_LSYM, bsize(p), bytes(p->offset));
break;
}
}
}
/*
* Generate information for a newly-defined structure.
*/
outstruct(szindex, paramindex)
int szindex, paramindex;
{
register Typeid typeid;
register struct symtab *p;
register int i, t, strindex;
if (oldway) {
/* do nothing */;
} else if (gdebug) {
i = dimtab[szindex + 3];
p = &stab[i];
if (p->sname != nil) {
strindex = dimtab[p->sizoff + 1];
typeid = typelookup(p->stype, NILINDEX, FORWARD, i);
if (typeid == nil) {
t = 0;
} else {
t = typeid->tnum;
reentertype(typeid, p->stype, NILINDEX, strindex, NILINDEX);
}
printf("\t.stabs\t\"%s:T", p->sname);
genstruct(p->stype, t, strindex, p->sname, bsize(p));
geninfo(p);
}
}
}
pstab(name, type)
char *name;
int type;
{
register int i;
register char c;
if (!gdebug) {
return;
} else if (oldway) {
old_pstab(name, type);
return;
}
/* locctr(PROG); /* .stabs must appear in .text for c2 */
#ifdef ASSTRINGS
if ( name[0] == '\0')
printf("\t.stabn\t");
else
#ifndef FLEXNAMES
printf("\t.stabs\t\"%.8s\",", name);
#else
printf("\t.stabs\t\"%s\",", name);
#endif
#else
printf(" .stab ");
for(i=0; i<8; i++)
if (c = name[i]) printf("'%c,", c);
else printf("0,");
#endif
printf("0%o,", type);
}
#ifdef STABDOT
pstabdot(type, value)
int type;
int value;
{
if ( ! gdebug) {
return;
} else if (oldway) {
old_pstabdot(type, value);
return;
}
/* locctr(PROG); /* .stabs must appear in .text for c2 */
printf("\t.stabd\t");
printf("0%o,0,0%o\n",type, value);
}
#endif
extern char NULLNAME[8];
extern int labelno;
extern int fdefflag;
psline()
{
static int lastlineno;
register char *cp, *cq;
register int i;
if (!gdebug) {
return;
} else if (oldway) {
old_psline();
return;
}
cq = ititle;
cp = ftitle;
while ( *cq ) if ( *cp++ != *cq++ ) goto neq;
if ( *cp == '\0' ) goto eq;
neq: for (i=0; i<100; i++)
ititle[i] = '\0';
cp = ftitle;
cq = ititle;
while ( *cp )
*cq++ = *cp++;
*cq = '\0';
*--cq = '\0';
#ifndef FLEXNAMES
for ( cp = ititle+1; *(cp-1); cp += 8 ) {
pstab(cp, N_SOL);
if (gdebug) printf("0,0,LL%d\n", labelno);
}
#else
pstab(ititle+1, N_SOL);
if (gdebug) printf("0,0,LL%d\n", labelno);
#endif
*cq = '"';
printf("LL%d:\n", labelno++);
eq: if (lineno == lastlineno) return;
lastlineno = lineno;
if (fdefflag) {
#ifdef STABDOT
pstabdot(N_SLINE, lineno);
#else
pstab(NULLNAME, N_SLINE);
printf("0,%d,LL%d\n", lineno, labelno);
printf("LL%d:\n", labelno++);
#endif
}
}
plcstab(level)
int level;
{
if (!gdebug) {
return;
} else if (oldway) {
old_plcstab(level);
return;
}
#ifdef STABDOT
pstabdot(N_LBRAC, level);
#else
pstab(NULLNAME, N_LBRAC);
printf("0,%d,LL%d\n", level, labelno);
printf("LL%d:\n", labelno++);
#endif
}
prcstab(level)
int level;
{
if (!gdebug) {
return;
} else if (oldway) {
old_prcstab(level);
return;
}
#ifdef STABDOT
pstabdot(N_RBRAC, level);
#else
pstab(NULLNAME, N_RBRAC);
printf("0,%d,LL%d\n", level, labelno);
printf("LL%d:\n", labelno++);
#endif
}
pfstab(sname)
char *sname;
{
register struct symtab *p;
if (gdebug) {
if (oldway) {
old_pfstab(sname);
} else {
p = &stab[lookup(sname, 0)];
printf("\t.stabs\t\"%s:", p->sname);
putchar((p->sclass == STATIC) ? 'f' : 'F');
gentype(p);
geninfo(p);
}
}
}
/*
* Old way of doing things.
*/
private old_fixarg(p)
struct symtab *p; {
if (gdebug) {
old_pstab(p->sname, N_PSYM);
if (gdebug) printf("0,%d,%d\n", p->stype, argoff/SZCHAR);
old_poffs(p);
}
}
private old_outstab(p)
struct symtab *p; {
register TWORD ptype;
register char *pname;
register char pclass;
register int poffset;
if (!gdebug) return;
ptype = p->stype;
pname = p->sname;
pclass = p->sclass;
poffset = p->offset;
if (ISFTN(ptype)) {
return;
}
switch (pclass) {
case AUTO:
old_pstab(pname, N_LSYM);
printf("0,%d,%d\n", ptype, (-poffset)/SZCHAR);
old_poffs(p);
return;
case EXTDEF:
case EXTERN:
old_pstab(pname, N_GSYM);
printf("0,%d,0\n", ptype);
old_poffs(p);
return;
case STATIC:
#ifdef LCOMM
/* stabLCSYM is 1 during nidcl so we can get stab type right */
old_pstab(pname, stabLCSYM ? N_LCSYM : N_STSYM);
#else
old_pstab(pname, N_STSYM);
#endif
if (p->slevel > 1) {
printf("0,%d,L%d\n", ptype, poffset);
} else {
printf("0,%d,%s\n", ptype, exname(pname));
}
old_poffs(p);
return;
case REGISTER:
old_pstab(pname, N_RSYM);
printf("0,%d,%d\n", ptype, poffset);
old_poffs(p);
return;
case MOS:
case MOU:
old_pstab(pname, N_SSYM);
printf("0,%d,%d\n", ptype, poffset/SZCHAR);
old_poffs(p);
return;
case PARAM:
/* parameter stab entries are processed in dclargs() */
return;
default:
#ifndef FLEXNAMES
if (ddebug) printf(" No .stab for %.8s\n", pname);
#else
if (ddebug) printf(" No .stab for %s\n", pname);
#endif
}
}
private old_pstab(name, type)
char *name;
int type; {
register int i;
register char c;
if (!gdebug) return;
/* locctr(PROG); /* .stabs must appear in .text for c2 */
#ifdef ASSTRINGS
if ( name[0] == '\0')
printf("\t.stabn\t");
else
#ifndef FLEXNAMES
printf("\t.stabs\t\"%.8s\", ", name);
#else
printf("\t.stabs\t\"%s\", ", name);
#endif
#else
printf(" .stab ");
for(i=0; i<8; i++)
if (c = name[i]) printf("'%c,", c);
else printf("0,");
#endif
printf("0%o,", type);
}
#ifdef STABDOT
private old_pstabdot(type, value)
int type;
int value;
{
if ( ! gdebug) return;
/* locctr(PROG); /* .stabs must appear in .text for c2 */
printf("\t.stabd\t");
printf("0%o,0,0%o\n",type, value);
}
#endif
private old_poffs(p)
register struct symtab *p; {
int s;
if (!gdebug) return;
if ((s = dimtab[p->sizoff]/SZCHAR) > 1) {
old_pstab(p->sname, N_LENG);
printf("1,0,%d\n", s);
}
}
private old_psline() {
static int lastlineno;
register char *cp, *cq;
register int i;
if (!gdebug) return;
cq = ititle;
cp = ftitle;
while ( *cq ) if ( *cp++ != *cq++ ) goto neq;
if ( *cp == '\0' ) goto eq;
neq: for (i=0; i<100; i++)
ititle[i] = '\0';
cp = ftitle;
cq = ititle;
while ( *cp )
*cq++ = *cp++;
*cq = '\0';
*--cq = '\0';
#ifndef FLEXNAMES
for ( cp = ititle+1; *(cp-1); cp += 8 ) {
old_pstab(cp, N_SOL);
if (gdebug) printf("0,0,LL%d\n", labelno);
}
#else
old_pstab(ititle+1, N_SOL);
if (gdebug) printf("0,0,LL%d\n", labelno);
#endif
*cq = '"';
printf("LL%d:\n", labelno++);
eq: if (lineno == lastlineno) return;
lastlineno = lineno;
if (fdefflag) {
#ifdef STABDOT
old_pstabdot(N_SLINE, lineno);
#else
old_pstab(NULLNAME, N_SLINE);
printf("0,%d,LL%d\n", lineno, labelno);
printf("LL%d:\n", labelno++);
#endif
}
}
private old_plcstab(level) {
if (!gdebug) return;
#ifdef STABDOT
old_pstabdot(N_LBRAC, level);
#else
old_pstab(NULLNAME, N_LBRAC);
printf("0,%d,LL%d\n", level, labelno);
printf("LL%d:\n", labelno++);
#endif
}
private old_prcstab(level) {
if (!gdebug) return;
#ifdef STABDOT
pstabdot(N_RBRAC, level);
#else
pstab(NULLNAME, N_RBRAC);
printf("0,%d,LL%d\n", level, labelno);
printf("LL%d:\n", labelno++);
#endif
}
private old_pfstab(sname)
char *sname; {
if (!gdebug) return;
pstab(sname, N_FUN);
#ifndef FLEXNAMES
printf("0,%d,_%.7s\n", lineno, sname);
#else
printf("0,%d,_%s\n", lineno, sname);
#endif
}