/* * Copyright (c) 1983 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[] = "@(#)printsym.c 5.3 (Berkeley) 3/5/86"; #endif not lint static char rcsid[] = "$Header: printsym.c,v 1.5 84/12/26 10:41:28 linton Exp $"; /* * 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 "keywords.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", "@dynarray", "@subarray", "fileptr", "record", "field", "procedure", "function", "funcvar", "ref", "pointer", "file", "set", "range", "label", "withptr", "scalar", "string", "program", "improper", "variant", "procparam", "funcparam", "module", "tag", "common", "extref", "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 ", classname(s)); printname(stdout, s); printf("\n"); } } /* * Note the exit of the given block */ public printexit(s) Symbol s; { if (s != program) { printf("leaving %s ", classname(s)); printname(stdout, s); printf("\n\n"); } } /* * Note the call of s from t. */ public printcall(s, t) Symbol s, t; { printf("calling "); printname(stdout, s); printparams(s, nil); printf(" from %s ", classname(t)); printname(stdout, t); printf("\n"); } /* * 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 "); printname(stdout, s); printf("\n"); } /* * Print the values of the parameters of the given procedure or function. * The frame distinguishes recursive instances of a procedure. * * If the procedure or function is internal, the argument count is * not valid so we ignore it. */ public printparams(f, frame) Symbol f; Frame frame; { Symbol param; int n, m, s; n = nargspassed(frame); if (isinternal(f)) { n = 0; } printf("("); param = f->chain; if (param != nil or n > 0) { m = n; if (param != nil) { for (;;) { s = psize(param) div sizeof(Word); if (s == 0) { s = 1; } m -= s; if (showaggrs) { printv(param, frame); } else { printparamv(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: if (isparam(s)) { b = false; } else { t = rtype(s->type); if (t == nil) { b = false; } else { switch (t->class) { case FILET: case SET: case BADUSE: b = false; break; default: b = true; break; } } } break; default: b = false; break; } return b; } /* * Print out a parameter value. * * Since this is intended to be printed on a single line with other information * aggregate values are not printed. */ public printparamv (p, frame) Symbol p; Frame frame; { Symbol t; t = rtype(p->type); switch (t->class) { case ARRAY: case DYNARRAY: case SUBARRAY: t = rtype(t->type); if (compatible(t, t_char)) { printv(p, frame); } else { printf("%s = (...)", symname(p)); } break; case RECORD: printf("%s = (...)", symname(p)); break; default: printv(p, frame); break; } } /* * 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 (isvarparam(s) and not isopenarray(s)) { rpush(address(s, frame), sizeof(Address)); addr = pop(Address); } else { addr = address(s, frame); } len = size(s); if (not canpush(len)) { printf("*** expression too large ***"); } else if (isreg(s)) { push(Address, addr); printval(s->type); } else { rpush(addr, len); printval(s->type); } } /* * Print out the name of a symbol. */ public printname(f, s) File f; Symbol s; { if (s == nil) { fprintf(f, "(noname)"); } else if (s == program) { fprintf(f, "."); } 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; { Language lang; checkref(s); if (s->language == nil or s->language == primlang) { lang = findlanguage(".s"); } else { lang = s->language; } (*language_op(lang, 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 TYPE: printf("size\t%d\n", size(s)); break; 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 PROG: case PROC: case FUNC: printf("address\t0x%x\n", s->symvalue.funcv.beginaddr); if (isinline(s)) { printf("inline procedure\n"); } if (nosource(s)) { printf("does not have source information\n"); } else { printf("has source information\n"); } break; case RANGE: prangetype(s->symvalue.rangev.lowertype); printf("lower\t%d\n", s->symvalue.rangev.lower); prangetype(s->symvalue.rangev.uppertype); printf("upper\t%d\n", s->symvalue.rangev.upper); break; default: /* do nothing */ break; } } private prangetype(r) Rangetype r; { switch (r) { case R_CONST: printf("CONST"); break; case R_ARG: printf("ARG"); break; case R_TEMP: printf("TEMP"); break; case R_ADJUST: printf("ADJUST"); break; } } /* * Print out the value on top of the stack according to the given type. */ public printval(t) Symbol t; { Symbol s; checkref(t); if (t->class == TYPEREF) { resolveRef(t); } switch (t->class) { case PROC: case FUNC: s = pop(Symbol); printf("%s", symname(s)); break; default: if (t->language == nil or t->language == primlang) { (*language_op(findlanguage(".c"), L_PRINTVAL))(t); } else { (*language_op(t->language, L_PRINTVAL))(t); } break; } } /* * Print out the value of a record, field by field. */ public printrecord(s) Symbol s; { Symbol f; if (s->chain == nil) { error("record has no fields"); } printf("("); sp -= size(s); f = s->chain; if (f != nil) { for (;;) { printfield(f); f = f->chain; if (f == nil) break; printf(", "); } } printf(")"); } /* * Print out a field. */ private printfield(f) Symbol f; { Stack *savesp; register int off, len; printf("%s = ", symname(f)); savesp = sp; off = f->symvalue.field.offset; len = f->symvalue.field.length; sp += ((off + len + BITSPERBYTE - 1) div BITSPERBYTE); printval(f); 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 if (c >= ' ' && c <= '~') { putchar(c); } else { printf("\\0%o",c); } } /* * Print out a value for a range type (integer, char, or boolean). */ public printRangeVal (val, t) long val; Symbol t; { if (t == t_boolean->type or istypename(t->type, "boolean")) { if ((boolean) val) { printf("true"); } else { printf("false"); } } else if (t == t_char->type or istypename(t->type, "char")) { if (varIsSet("$hexchars")) { printf("0x%lx", val); } else { putchar('\''); printchar(val); putchar('\''); } } else if (varIsSet("$hexints")) { printf("0x%lx", val); } else if (t->symvalue.rangev.lower >= 0) { printf("%lu", val); } else { printf("%ld", val); } } /* * Print out an enumerated value by finding the corresponding * name in the enumeration list. */ public printEnum (i, t) integer i; Symbol t; { register Symbol e; e = t->chain; while (e != nil and e->symvalue.constval->value.lcon != i) { e = e->chain; } if (e != nil) { printf("%s", symname(e)); } else { printf("%d", i); } } /* * Print out a null-terminated string (pointer to char) * starting at the given address. */ public printString (addr, quotes) Address addr; boolean quotes; { register Address a; register integer i, len; register boolean endofstring; union { char ch[sizeof(Word)]; int word; } u; if (varIsSet("$hexstrings")) { printf("0x%x", addr); } else { if (quotes) { putchar('"'); } a = addr; endofstring = false; while (not endofstring) { dread(&u, a, sizeof(u)); i = 0; do { if (u.ch[i] == '\0') { endofstring = true; } else { printchar(u.ch[i]); } ++i; } while (i < sizeof(Word) and not endofstring); a += sizeof(Word); } if (quotes) { putchar('"'); } } }