1 /* 2 * Copyright (c) 1983 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)printsym.c 5.7 (Berkeley) 06/01/90"; 10 #endif /* not lint */ 11 12 /* 13 * Printing of symbolic information. 14 */ 15 16 #include "defs.h" 17 #include "symbols.h" 18 #include "languages.h" 19 #include "printsym.h" 20 #include "tree.h" 21 #include "eval.h" 22 #include "mappings.h" 23 #include "process.h" 24 #include "runtime.h" 25 #include "machine.h" 26 #include "names.h" 27 #include "keywords.h" 28 #include "main.h" 29 #include <ctype.h> 30 31 #ifndef public 32 #endif 33 34 /* 35 * Maximum number of arguments to a function. 36 * This is used as a check for the possibility that the stack has been 37 * overwritten and therefore a saved argument pointer might indicate 38 * to an absurdly large number of arguments. 39 */ 40 41 #define MAXARGSPASSED 20 42 43 /* 44 * Return a pointer to the string for the name of the class that 45 * the given symbol belongs to. 46 */ 47 48 private String clname[] = { 49 "bad use", "constant", "type", "variable", "array", "array", 50 "dynarray", "subarray", "fileptr", "record", "field", 51 "procedure", "function", "funcvar", 52 "ref", "pointer", "file", "set", "range", "label", "withptr", 53 "scalar", "string", "program", "improper", "variant", 54 "procparam", "funcparam", "module", "tag", "common", "extref", "typeref" 55 }; 56 57 public String classname(s) 58 Symbol s; 59 { 60 return clname[ord(s->class)]; 61 } 62 63 /* 64 * Note the entry of the given block, unless it's the main program. 65 */ 66 67 public printentry(s) 68 Symbol s; 69 { 70 if (s != program) { 71 printf("\nentering %s ", classname(s)); 72 printname(stdout, s); 73 printf("\n"); 74 } 75 } 76 77 /* 78 * Note the exit of the given block 79 */ 80 81 public printexit(s) 82 Symbol s; 83 { 84 if (s != program) { 85 printf("leaving %s ", classname(s)); 86 printname(stdout, s); 87 printf("\n\n"); 88 } 89 } 90 91 /* 92 * Note the call of s from t. 93 */ 94 95 public printcall(s, t) 96 Symbol s, t; 97 { 98 printf("calling "); 99 printname(stdout, s); 100 printparams(s, nil); 101 printf(" from %s ", classname(t)); 102 printname(stdout, t); 103 printf("\n"); 104 } 105 106 /* 107 * Note the return from s. If s is a function, print the value 108 * it is returning. This is somewhat painful, since the function 109 * has actually just returned. 110 */ 111 112 public printrtn(s) 113 Symbol s; 114 { 115 register Symbol t; 116 register int len; 117 Boolean isindirect; 118 119 printf("returning "); 120 if (s->class == FUNC && (!istypename(s->type,"void"))) { 121 len = size(s->type); 122 if (canpush(len)) { 123 t = rtype(s->type); 124 isindirect = (Boolean) (t->class == RECORD or t->class == VARNT); 125 pushretval(len, isindirect); 126 printval(s->type); 127 putchar(' '); 128 } else { 129 printf("(value too large) "); 130 } 131 } 132 printf("from "); 133 printname(stdout, s); 134 printf("\n"); 135 } 136 137 /* 138 * Print the values of the parameters of the given procedure or function. 139 * The frame distinguishes recursive instances of a procedure. 140 * 141 * If the procedure or function is internal, the argument count is 142 * not valid so we ignore it. 143 */ 144 145 public printparams(f, frame) 146 Symbol f; 147 Frame frame; 148 { 149 Symbol param; 150 int n, m, s; 151 152 n = nargspassed(frame); 153 if (isinternal(f)) { 154 n = 0; 155 } 156 printf("("); 157 param = f->chain; 158 if (param != nil or n > 0) { 159 m = n; 160 if (param != nil) { 161 for (;;) { 162 s = psize(param) div sizeof(Word); 163 if (s == 0) { 164 s = 1; 165 } 166 m -= s; 167 if (showaggrs) { 168 printv(param, frame); 169 } else { 170 printparamv(param, frame); 171 } 172 param = param->chain; 173 if (param == nil) break; 174 printf(", "); 175 } 176 } 177 if (m > 0) { 178 if (m > MAXARGSPASSED) { 179 m = MAXARGSPASSED; 180 } 181 if (f->chain != nil) { 182 printf(", "); 183 } 184 for (;;) { 185 --m; 186 printf("0x%x", argn(n - m, frame)); 187 if (m <= 0) break; 188 printf(", "); 189 } 190 } 191 } 192 printf(")"); 193 } 194 195 /* 196 * Test if a symbol should be printed. We don't print files, 197 * for example, simply because there's no good way to do it. 198 * The symbol must be within the given function. 199 */ 200 201 public Boolean should_print(s) 202 Symbol s; 203 { 204 Boolean b; 205 register Symbol t; 206 207 switch (s->class) { 208 case VAR: 209 case FVAR: 210 if (isparam(s)) { 211 b = false; 212 } else { 213 t = rtype(s->type); 214 if (t == nil) { 215 b = false; 216 } else { 217 switch (t->class) { 218 case FILET: 219 case SET: 220 case BADUSE: 221 b = false; 222 break; 223 224 default: 225 b = true; 226 break; 227 } 228 } 229 } 230 break; 231 232 default: 233 b = false; 234 break; 235 } 236 return b; 237 } 238 239 /* 240 * Print out a parameter value. 241 * 242 * Since this is intended to be printed on a single line with other information 243 * aggregate values are not printed. 244 */ 245 246 public printparamv (p, frame) 247 Symbol p; 248 Frame frame; 249 { 250 Symbol t; 251 252 t = rtype(p->type); 253 switch (t->class) { 254 case ARRAY: 255 case OPENARRAY: 256 case DYNARRAY: 257 case SUBARRAY: 258 t = rtype(t->type); 259 if (compatible(t, t_char)) { 260 printv(p, frame); 261 } else { 262 printf("%s = (...)", symname(p)); 263 } 264 break; 265 266 case RECORD: 267 printf("%s = (...)", symname(p)); 268 break; 269 270 default: 271 printv(p, frame); 272 break; 273 } 274 } 275 276 /* 277 * Print the name and value of a variable. 278 */ 279 280 public printv(s, frame) 281 Symbol s; 282 Frame frame; 283 { 284 Address addr; 285 int len; 286 287 if (isambiguous(s) and ismodule(container(s))) { 288 printname(stdout, s); 289 printf(" = "); 290 } else { 291 printf("%s = ", symname(s)); 292 } 293 if (isvarparam(s) and not isopenarray(s)) { 294 rpush(address(s, frame), sizeof(Address)); 295 addr = pop(Address); 296 } else { 297 addr = address(s, frame); 298 } 299 len = size(s); 300 if (not canpush(len)) { 301 printf("*** expression too large ***"); 302 } else if (isreg(s)) { 303 push(Address, addr); 304 printval(s->type); 305 } else { 306 rpush(addr, len); 307 printval(s->type); 308 } 309 } 310 311 /* 312 * Print out the name of a symbol. 313 */ 314 315 public printname(f, s) 316 File f; 317 Symbol s; 318 { 319 if (s == nil) { 320 fprintf(f, "(noname)"); 321 } else if (s == program) { 322 fprintf(f, "."); 323 } else if (isredirected() or isambiguous(s)) { 324 printwhich(f, s); 325 } else { 326 fprintf(f, "%s", symname(s)); 327 } 328 } 329 330 /* 331 * Print the fully specified variable that is described by the given identifer. 332 */ 333 334 public printwhich(f, s) 335 File f; 336 Symbol s; 337 { 338 printouter(f, container(s)); 339 fprintf(f, "%s", symname(s)); 340 } 341 342 /* 343 * Print the fully qualified name of each symbol that has the same name 344 * as the given symbol. 345 */ 346 347 public printwhereis(f, s) 348 File f; 349 Symbol s; 350 { 351 register Name n; 352 register Symbol t; 353 354 checkref(s); 355 n = s->name; 356 t = lookup(n); 357 printwhich(f, t); 358 t = t->next_sym; 359 while (t != nil) { 360 if (t->name == n) { 361 putc(' ', f); 362 printwhich(f, t); 363 } 364 t = t->next_sym; 365 } 366 putc('\n', f); 367 } 368 369 private printouter(f, s) 370 File f; 371 Symbol s; 372 { 373 Symbol outer; 374 375 if (s != nil) { 376 outer = container(s); 377 if (outer != nil and outer != program) { 378 printouter(f, outer); 379 } 380 fprintf(f, "%s.", symname(s)); 381 } 382 } 383 384 public printdecl(s) 385 Symbol s; 386 { 387 Language lang; 388 389 checkref(s); 390 if (s->language == nil or s->language == primlang) { 391 lang = findlanguage(".s"); 392 } else { 393 lang = s->language; 394 } 395 (*language_op(lang, L_PRINTDECL))(s); 396 } 397 398 /* 399 * Straight dump of symbol information. 400 */ 401 402 public psym(s) 403 Symbol s; 404 { 405 printf("name\t%s\n", symname(s)); 406 printf("lang\t%s\n", language_name(s->language)); 407 printf("level\t%d\n", s->level); 408 printf("class\t%s\n", classname(s)); 409 printf("type\t0x%x", s->type); 410 if (s->type != nil and s->type->name != nil) { 411 printf(" (%s)", symname(s->type)); 412 } 413 printf("\nchain\t0x%x", s->chain); 414 if (s->chain != nil and s->chain->name != nil) { 415 printf(" (%s)", symname(s->chain)); 416 } 417 printf("\nblock\t0x%x", s->block); 418 if (s->block != nil and s->block->name != nil) { 419 printf(" ("); 420 printname(stdout, s->block); 421 putchar(')'); 422 } 423 putchar('\n'); 424 switch (s->class) { 425 case TYPE: 426 printf("size\t%d\n", size(s)); 427 break; 428 429 case VAR: 430 case REF: 431 switch (s->storage) { 432 case INREG: 433 printf("reg\t%d\n", s->symvalue.offset); 434 break; 435 436 case STK: 437 printf("offset\t%d\n", s->symvalue.offset); 438 break; 439 440 case EXT: 441 printf("address\t0x%x\n", s->symvalue.offset); 442 break; 443 } 444 printf("size\t%d\n", size(s)); 445 break; 446 447 case RECORD: 448 case VARNT: 449 printf("size\t%d\n", s->symvalue.offset); 450 break; 451 452 case FIELD: 453 printf("offset\t%d\n", s->symvalue.field.offset); 454 printf("size\t%d\n", s->symvalue.field.length); 455 break; 456 457 case PROG: 458 case PROC: 459 case FUNC: 460 printf("address\t0x%x\n", s->symvalue.funcv.beginaddr); 461 if (isinline(s)) { 462 printf("inline procedure\n"); 463 } 464 if (nosource(s)) { 465 printf("does not have source information\n"); 466 } else { 467 printf("has source information\n"); 468 } 469 break; 470 471 case RANGE: 472 prangetype(s->symvalue.rangev.lowertype); 473 printf("lower\t%d\n", s->symvalue.rangev.lower); 474 prangetype(s->symvalue.rangev.uppertype); 475 printf("upper\t%d\n", s->symvalue.rangev.upper); 476 break; 477 478 default: 479 /* do nothing */ 480 break; 481 } 482 } 483 484 private prangetype(r) 485 Rangetype r; 486 { 487 switch (r) { 488 case R_CONST: 489 printf("CONST"); 490 break; 491 492 case R_ARG: 493 printf("ARG"); 494 break; 495 496 case R_TEMP: 497 printf("TEMP"); 498 break; 499 500 case R_ADJUST: 501 printf("ADJUST"); 502 break; 503 } 504 } 505 506 /* 507 * Print out the value on top of the stack according to the given type. 508 */ 509 510 public printval(t) 511 Symbol t; 512 { 513 Symbol s; 514 515 checkref(t); 516 if (t->class == TYPEREF) { 517 resolveRef(t); 518 } 519 switch (t->class) { 520 case PROC: 521 case FUNC: 522 s = pop(Symbol); 523 printf("%s", symname(s)); 524 break; 525 526 default: 527 if (t->language == nil or t->language == primlang) { 528 (*language_op(findlanguage(".c"), L_PRINTVAL))(t); 529 } else { 530 (*language_op(t->language, L_PRINTVAL))(t); 531 } 532 break; 533 } 534 } 535 536 /* 537 * Print out the value of a record, field by field. 538 */ 539 540 public printrecord(s) 541 Symbol s; 542 { 543 Symbol f; 544 545 if (s->chain == nil) { 546 error("record has no fields"); 547 } 548 printf("("); 549 sp -= size(s); 550 f = s->chain; 551 if (f != nil) { 552 for (;;) { 553 printfield(f); 554 f = f->chain; 555 if (f == nil) break; 556 printf(", "); 557 } 558 } 559 printf(")"); 560 } 561 562 /* 563 * Print out a field. 564 */ 565 566 private printfield(f) 567 Symbol f; 568 { 569 Stack *savesp; 570 register int off, len; 571 572 printf("%s = ", symname(f)); 573 savesp = sp; 574 off = f->symvalue.field.offset; 575 len = f->symvalue.field.length; 576 sp += ((off + len + BITSPERBYTE - 1) div BITSPERBYTE); 577 printval(f); 578 sp = savesp; 579 } 580 581 /* 582 * Print out the contents of an array. 583 * Haven't quite figured out what the best format is. 584 * 585 * This is rather inefficient. 586 * 587 * The "2*elsize" is there since "printval" drops the stack by elsize. 588 */ 589 590 public printarray(a) 591 Symbol a; 592 { 593 Stack *savesp, *newsp; 594 Symbol eltype; 595 long elsize; 596 String sep; 597 598 savesp = sp; 599 sp -= (size(a)); 600 newsp = sp; 601 eltype = rtype(a->type); 602 elsize = size(eltype); 603 printf("("); 604 if (eltype->class == RECORD or eltype->class == ARRAY or 605 eltype->class == VARNT) { 606 sep = "\n"; 607 putchar('\n'); 608 } else { 609 sep = ", "; 610 } 611 for (sp += elsize; sp <= savesp; sp += 2*elsize) { 612 if (sp - elsize != newsp) { 613 fputs(sep, stdout); 614 } 615 printval(eltype); 616 } 617 sp = newsp; 618 if (streq(sep, "\n")) { 619 putchar('\n'); 620 } 621 printf(")"); 622 } 623 624 /* 625 * Print out the value of a real number in Pascal notation. 626 * This is, unfortunately, different than what one gets 627 * from "%g" in printf. 628 */ 629 630 public prtreal(r) 631 double r; 632 { 633 extern char *index(); 634 char buf[256]; 635 636 # ifdef IRIS 637 sprintf(buf, "%lg", r); 638 # else 639 sprintf(buf, "%g", r); 640 # endif 641 if (buf[0] == '.') { 642 printf("0%s", buf); 643 } else if (buf[0] == '-' and buf[1] == '.') { 644 printf("-0%s", &buf[1]); 645 } else { 646 printf("%s", buf); 647 } 648 if (index(buf, '.') == nil) { 649 printf(".0"); 650 } 651 } 652 653 /* 654 * Print out a character using ^? notation for unprintables. 655 */ 656 657 public printchar(c) 658 char c; 659 { 660 if (c == 0) { 661 putchar('\\'); 662 putchar('0'); 663 } else if (c == '\n') { 664 putchar('\\'); 665 putchar('n'); 666 } else if (c > 0 and c < ' ') { 667 putchar('^'); 668 putchar(c - 1 + 'A'); 669 } else if (c >= ' ' && c <= '~') { 670 putchar(c); 671 } else { 672 printf("\\0%o",c&0xff); 673 } 674 } 675 676 /* 677 * Print out a value for a range type (integer, char, or boolean). 678 */ 679 680 public printRangeVal (val, t) 681 long val; 682 Symbol t; 683 { 684 if (t == t_boolean->type or istypename(t->type, "boolean")) { 685 if ((boolean) val) { 686 printf("true"); 687 } else { 688 printf("false"); 689 } 690 } else if (t == t_char->type or istypename(t->type, "char")) { 691 if (varIsSet("$hexchars")) { 692 printf("0x%lx", val); 693 } else { 694 putchar('\''); 695 printchar(val); 696 putchar('\''); 697 } 698 } else if (varIsSet("$hexints")) { 699 printf("0x%lx", val); 700 } else if (t->symvalue.rangev.lower >= 0) { 701 printf("%lu", val); 702 } else { 703 printf("%ld", val); 704 } 705 } 706 707 /* 708 * Print out an enumerated value by finding the corresponding 709 * name in the enumeration list. 710 */ 711 712 public printEnum (i, t) 713 integer i; 714 Symbol t; 715 { 716 register Symbol e; 717 718 e = t->chain; 719 while (e != nil and e->symvalue.constval->value.lcon != i) { 720 e = e->chain; 721 } 722 if (e != nil) { 723 printf("%s", symname(e)); 724 } else { 725 printf("%d", i); 726 } 727 } 728 729 /* 730 * Print out a null-terminated string (pointer to char) 731 * starting at the given address. 732 */ 733 734 public printString (addr, quotes) 735 Address addr; 736 boolean quotes; 737 { 738 register Address a; 739 register integer i, len; 740 register boolean endofstring; 741 register int unprintables; 742 #define MAXGARBAGE 4 743 union { 744 char ch[sizeof(Word)]; 745 int word; 746 } u; 747 748 if (varIsSet("$hexstrings")) { 749 printf("0x%x", addr); 750 } else { 751 if (quotes) { 752 putchar('"'); 753 } 754 a = addr; 755 unprintables = 0; 756 endofstring = false; 757 while (not endofstring) { 758 dread(&u, a, sizeof(u)); 759 i = 0; 760 do { 761 if (u.ch[i] == '\0') { 762 endofstring = true; 763 } else { 764 printchar(u.ch[i]); 765 if (!isascii(u.ch[i]) and ++unprintables > MAXGARBAGE) { 766 endofstring = true; 767 printf("..."); 768 } 769 } 770 ++i; 771 } while (i < sizeof(Word) and not endofstring); 772 a += sizeof(Word); 773 } 774 if (quotes) { 775 putchar('"'); 776 } 777 } 778 } 779