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