special cased printrtn for voids and printv for arrays
[unix-history] / usr / src / old / dbx / printsym.c
/* Copyright (c) 1982 Regents of the University of California */
static char sccsid[] = "@(#)printsym.c 1.7 %G%";
/*
* Printing of symbolic information.
*/
#include "defs.h"
#include "symbols.h"
#include "languages.h"
#include "printsym.h"
#include "tree.h"
#include "eval.h"
#include "mappings.h"
#include "process.h"
#include "runtime.h"
#include "machine.h"
#include "names.h"
#include "main.h"
#ifndef public
#endif
/*
* Maximum number of arguments to a function.
* This is used as a check for the possibility that the stack has been
* overwritten and therefore a saved argument pointer might indicate
* to an absurdly large number of arguments.
*/
#define MAXARGSPASSED 20
/*
* Return a pointer to the string for the name of the class that
* the given symbol belongs to.
*/
private String clname[] = {
"bad use", "constant", "type", "variable", "array", "fileptr",
"record", "field", "procedure", "function", "funcvar",
"ref", "pointer", "file", "set", "range", "label", "withptr",
"scalar", "string", "program", "improper", "variant",
"procparam", "funcparam", "module", "tag", "common", "typeref"
};
public String classname(s)
Symbol s;
{
return clname[ord(s->class)];
}
/*
* Note the entry of the given block, unless it's the main program.
*/
public printentry(s)
Symbol s;
{
if (s != program) {
printf("\nentering %s %s\n", classname(s), symname(s));
}
}
/*
* Note the exit of the given block
*/
public printexit(s)
Symbol s;
{
if (s != program) {
printf("leaving %s %s\n\n", classname(s), symname(s));
}
}
/*
* Note the call of s from t.
*/
public printcall(s, t)
Symbol s, t;
{
printf("calling %s", symname(s));
printparams(s, nil);
printf(" from %s %s\n", classname(t), symname(t));
}
/*
* Note the return from s. If s is a function, print the value
* it is returning. This is somewhat painful, since the function
* has actually just returned.
*/
public printrtn(s)
Symbol s;
{
register Symbol t;
register int len;
Boolean isindirect;
printf("returning ");
if (s->class == FUNC && (!istypename(s->type,"void"))) {
len = size(s->type);
if (canpush(len)) {
t = rtype(s->type);
isindirect = (Boolean) (t->class == RECORD or t->class == VARNT);
pushretval(len, isindirect);
printval(s->type);
putchar(' ');
} else {
printf("(value too large) ");
}
}
printf("from %s\n", symname(s));
}
/*
* Print the values of the parameters of the given procedure or function.
* The frame distinguishes recursive instances of a procedure.
*/
public printparams(f, frame)
Symbol f;
Frame frame;
{
Symbol param;
int n, m, s;
n = nargspassed(frame);
param = f->chain;
if (param != nil or n > 0) {
printf("(");
m = n;
if (param != nil) {
for (;;) {
s = size(param) div sizeof(Word);
if (s == 0) {
s = 1;
}
m -= s;
printv(param, frame);
param = param->chain;
if (param == nil) break;
printf(", ");
}
}
if (m > 0) {
if (m > MAXARGSPASSED) {
m = MAXARGSPASSED;
}
if (f->chain != nil) {
printf(", ");
}
for (;;) {
--m;
printf("0x%x", argn(n - m, frame));
if (m <= 0) break;
printf(", ");
}
}
printf(")");
}
}
/*
* Test if a symbol should be printed. We don't print files,
* for example, simply because there's no good way to do it.
* The symbol must be within the given function.
*/
public Boolean should_print(s)
Symbol s;
{
Boolean b;
register Symbol t;
switch (s->class) {
case VAR:
case FVAR:
t = rtype(s->type);
b = (Boolean) (
not isparam(s) and
t != nil and t->class != FILET and t->class != SET
);
break;
default:
b = false;
break;
}
return b;
}
/*
* Print the name and value of a variable.
*/
public printv(s, frame)
Symbol s;
Frame frame;
{
Address addr;
int len;
if (isambiguous(s) and ismodule(container(s))) {
printname(stdout, s);
printf(" = ");
} else {
printf("%s = ", symname(s));
}
if(s->type->class == ARRAY && (! istypename(s->type->type,"char")) ) {
printf(" ARRAY ");
} else {
if (isvarparam(s)) {
rpush(address(s, frame), sizeof(Address));
addr = pop(Address);
len = size(s->type);
} else {
addr = address(s, frame);
len = size(s);
}
if (canpush(len)) {
rpush(addr, len);
printval(s->type);
} else {
printf("*** expression too large ***");
}
}
}
/*
* Print out the name of a symbol.
*/
public printname(f, s)
File f;
Symbol s;
{
if (s == nil) {
fprintf(f, "(noname)");
} else if (isredirected() or isambiguous(s)) {
printwhich(f, s);
} else {
fprintf(f, "%s", symname(s));
}
}
/*
* Print the fully specified variable that is described by the given identifer.
*/
public printwhich(f, s)
File f;
Symbol s;
{
printouter(f, container(s));
fprintf(f, "%s", symname(s));
}
/*
* Print the fully qualified name of each symbol that has the same name
* as the given symbol.
*/
public printwhereis(f, s)
File f;
Symbol s;
{
register Name n;
register Symbol t;
checkref(s);
n = s->name;
t = lookup(n);
printwhich(f, t);
t = t->next_sym;
while (t != nil) {
if (t->name == n) {
putc(' ', f);
printwhich(f, t);
}
t = t->next_sym;
}
putc('\n', f);
}
private printouter(f, s)
File f;
Symbol s;
{
Symbol outer;
if (s != nil) {
outer = container(s);
if (outer != nil and outer != program) {
printouter(f, outer);
}
fprintf(f, "%s.", symname(s));
}
}
public printdecl(s)
Symbol s;
{
checkref(s);
(*language_op(s->language, L_PRINTDECL))(s);
}
/*
* Straight dump of symbol information.
*/
public psym(s)
Symbol s;
{
printf("name\t%s\n", symname(s));
printf("lang\t%s\n", language_name(s->language));
printf("level\t%d\n", s->level);
printf("class\t%s\n", classname(s));
printf("type\t0x%x", s->type);
if (s->type != nil and s->type->name != nil) {
printf(" (%s)", symname(s->type));
}
printf("\nchain\t0x%x", s->chain);
if (s->chain != nil and s->chain->name != nil) {
printf(" (%s)", symname(s->chain));
}
printf("\nblock\t0x%x", s->block);
if (s->block->name != nil) {
printf(" (");
printname(stdout, s->block);
putchar(')');
}
putchar('\n');
switch (s->class) {
case VAR:
case REF:
if (s->level >= 3) {
printf("address\t0x%x\n", s->symvalue.offset);
} else {
printf("offset\t%d\n", s->symvalue.offset);
}
printf("size\t%d\n", size(s));
break;
case RECORD:
case VARNT:
printf("size\t%d\n", s->symvalue.offset);
break;
case FIELD:
printf("offset\t%d\n", s->symvalue.field.offset);
printf("size\t%d\n", s->symvalue.field.length);
break;
case PROC:
case FUNC:
printf("address\t0x%x\n", s->symvalue.funcv.beginaddr);
if (nosource(s)) {
printf("does not have source information\n");
} else {
printf("has source information\n");
}
break;
case RANGE:
switch(s->symvalue.rangev.lowertype) {
case R_CONST : printf("CONST");
break;
case R_ARG : printf("ARG");
break;
case R_TEMP : printf("TEMP");
break;
case R_ADJUST : printf("ADJUST");
break;
}
printf("lower\t%d\n", s->symvalue.rangev.lower);
switch(s->symvalue.rangev.uppertype) {
case R_CONST : printf("CONST");
break;
case R_ARG : printf("ARG");
break;
case R_TEMP : printf("TEMP");
break;
case R_ADJUST : printf("ADJUST");
break;
}
printf("upper\t%d\n", s->symvalue.rangev.upper);
break;
default:
/* do nothing */
break;
}
}
/*
* Print out the value on top of the stack according to the given type.
*/
public printval(t)
Symbol t;
{
Symbol s;
checkref(t);
switch (t->class) {
case PROC:
case FUNC:
s = pop(Symbol);
printf("%s", symname(s));
break;
default:
if (t->language == nil) {
error("unknown language");
} else {
(*language_op(t->language, L_PRINTVAL))(t);
}
break;
}
}
/*
* Print out the value of a record, field by field.
*/
public printrecord(s)
Symbol s;
{
if (s->chain == nil) {
error("record has no fields");
}
printf("(");
sp -= size(s);
printfield(s->chain);
printf(")");
}
/*
* Print out a field, first printing out other fields.
* This is done because the fields are chained together backwards.
*/
private printfield(s)
Symbol s;
{
Stack *savesp;
if (s->chain != nil) {
printfield(s->chain);
printf(", ");
}
printf("%s = ", symname(s));
savesp = sp;
sp += ((s->symvalue.field.offset div BITSPERBYTE) + size(s->type));
printval(s);
sp = savesp;
}
/*
* Print out the contents of an array.
* Haven't quite figured out what the best format is.
*
* This is rather inefficient.
*
* The "2*elsize" is there since "printval" drops the stack by elsize.
*/
public printarray(a)
Symbol a;
{
Stack *savesp, *newsp;
Symbol eltype;
long elsize;
String sep;
savesp = sp;
sp -= (size(a));
newsp = sp;
eltype = rtype(a->type);
elsize = size(eltype);
printf("(");
if (eltype->class == RECORD or eltype->class == ARRAY or
eltype->class == VARNT) {
sep = "\n";
putchar('\n');
} else {
sep = ", ";
}
for (sp += elsize; sp <= savesp; sp += 2*elsize) {
if (sp - elsize != newsp) {
fputs(sep, stdout);
}
printval(eltype);
}
sp = newsp;
if (streq(sep, "\n")) {
putchar('\n');
}
printf(")");
}
/*
* Print out the value of a real number in Pascal notation.
* This is, unfortunately, different than what one gets
* from "%g" in printf.
*/
public prtreal(r)
double r;
{
extern char *index();
char buf[256];
sprintf(buf, "%g", r);
if (buf[0] == '.') {
printf("0%s", buf);
} else if (buf[0] == '-' and buf[1] == '.') {
printf("-0%s", &buf[1]);
} else {
printf("%s", buf);
}
if (index(buf, '.') == nil) {
printf(".0");
}
}
/*
* Print out a character using ^? notation for unprintables.
*/
public printchar(c)
char c;
{
if (c == 0) {
putchar('\\');
putchar('0');
} else if (c == '\n') {
putchar('\\');
putchar('n');
} else if (c > 0 and c < ' ') {
putchar('^');
putchar(c - 1 + 'A');
} else {
putchar(c);
}
}