1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)printsym.c 5.4 (Berkeley) 09/01/86"; 9 #endif not lint 10 11 static char rcsid[] = "$Header: printsym.c,v 1.5 84/12/26 10:41:28 linton Exp $"; 12 13 /* 14 * Printing of symbolic information. 15 */ 16 17 #include "defs.h" 18 #include "symbols.h" 19 #include "languages.h" 20 #include "printsym.h" 21 #include "tree.h" 22 #include "eval.h" 23 #include "mappings.h" 24 #include "process.h" 25 #include "runtime.h" 26 #include "machine.h" 27 #include "names.h" 28 #include "keywords.h" 29 #include "main.h" 30 #include <ctype.h> 31 32 #ifndef public 33 #endif 34 35 /* 36 * Maximum number of arguments to a function. 37 * This is used as a check for the possibility that the stack has been 38 * overwritten and therefore a saved argument pointer might indicate 39 * to an absurdly large number of arguments. 40 */ 41 42 #define MAXARGSPASSED 20 43 44 /* 45 * Return a pointer to the string for the name of the class that 46 * the given symbol belongs to. 47 */ 48 49 private String clname[] = { 50 "bad use", "constant", "type", "variable", "array", "@dynarray", 51 "@subarray", "fileptr", "record", "field", 52 "procedure", "function", "funcvar", 53 "ref", "pointer", "file", "set", "range", "label", "withptr", 54 "scalar", "string", "program", "improper", "variant", 55 "procparam", "funcparam", "module", "tag", "common", "extref", "typeref" 56 }; 57 58 public String classname(s) 59 Symbol s; 60 { 61 return clname[ord(s->class)]; 62 } 63 64 /* 65 * Note the entry of the given block, unless it's the main program. 66 */ 67 68 public printentry(s) 69 Symbol s; 70 { 71 if (s != program) { 72 printf("\nentering %s ", classname(s)); 73 printname(stdout, s); 74 printf("\n"); 75 } 76 } 77 78 /* 79 * Note the exit of the given block 80 */ 81 82 public printexit(s) 83 Symbol s; 84 { 85 if (s != program) { 86 printf("leaving %s ", classname(s)); 87 printname(stdout, s); 88 printf("\n\n"); 89 } 90 } 91 92 /* 93 * Note the call of s from t. 94 */ 95 96 public printcall(s, t) 97 Symbol s, t; 98 { 99 printf("calling "); 100 printname(stdout, s); 101 printparams(s, nil); 102 printf(" from %s ", classname(t)); 103 printname(stdout, t); 104 printf("\n"); 105 } 106 107 /* 108 * Note the return from s. If s is a function, print the value 109 * it is returning. This is somewhat painful, since the function 110 * has actually just returned. 111 */ 112 113 public printrtn(s) 114 Symbol s; 115 { 116 register Symbol t; 117 register int len; 118 Boolean isindirect; 119 120 printf("returning "); 121 if (s->class == FUNC && (!istypename(s->type,"void"))) { 122 len = size(s->type); 123 if (canpush(len)) { 124 t = rtype(s->type); 125 isindirect = (Boolean) (t->class == RECORD or t->class == VARNT); 126 pushretval(len, isindirect); 127 printval(s->type); 128 putchar(' '); 129 } else { 130 printf("(value too large) "); 131 } 132 } 133 printf("from "); 134 printname(stdout, s); 135 printf("\n"); 136 } 137 138 /* 139 * Print the values of the parameters of the given procedure or function. 140 * The frame distinguishes recursive instances of a procedure. 141 * 142 * If the procedure or function is internal, the argument count is 143 * not valid so we ignore it. 144 */ 145 146 public printparams(f, frame) 147 Symbol f; 148 Frame frame; 149 { 150 Symbol param; 151 int n, m, s; 152 153 n = nargspassed(frame); 154 if (isinternal(f)) { 155 n = 0; 156 } 157 printf("("); 158 param = f->chain; 159 if (param != nil or n > 0) { 160 m = n; 161 if (param != nil) { 162 for (;;) { 163 s = psize(param) div sizeof(Word); 164 if (s == 0) { 165 s = 1; 166 } 167 m -= s; 168 if (showaggrs) { 169 printv(param, frame); 170 } else { 171 printparamv(param, frame); 172 } 173 param = param->chain; 174 if (param == nil) break; 175 printf(", "); 176 } 177 } 178 if (m > 0) { 179 if (m > MAXARGSPASSED) { 180 m = MAXARGSPASSED; 181 } 182 if (f->chain != nil) { 183 printf(", "); 184 } 185 for (;;) { 186 --m; 187 printf("0x%x", argn(n - m, frame)); 188 if (m <= 0) break; 189 printf(", "); 190 } 191 } 192 } 193 printf(")"); 194 } 195 196 /* 197 * Test if a symbol should be printed. We don't print files, 198 * for example, simply because there's no good way to do it. 199 * The symbol must be within the given function. 200 */ 201 202 public Boolean should_print(s) 203 Symbol s; 204 { 205 Boolean b; 206 register Symbol t; 207 208 switch (s->class) { 209 case VAR: 210 case FVAR: 211 if (isparam(s)) { 212 b = false; 213 } else { 214 t = rtype(s->type); 215 if (t == nil) { 216 b = false; 217 } else { 218 switch (t->class) { 219 case FILET: 220 case SET: 221 case BADUSE: 222 b = false; 223 break; 224 225 default: 226 b = true; 227 break; 228 } 229 } 230 } 231 break; 232 233 default: 234 b = false; 235 break; 236 } 237 return b; 238 } 239 240 /* 241 * Print out a parameter value. 242 * 243 * Since this is intended to be printed on a single line with other information 244 * aggregate values are not printed. 245 */ 246 247 public printparamv (p, frame) 248 Symbol p; 249 Frame frame; 250 { 251 Symbol t; 252 253 t = rtype(p->type); 254 switch (t->class) { 255 case ARRAY: 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->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 if (s->level >= 3) { 432 printf("address\t0x%x\n", s->symvalue.offset); 433 } else { 434 printf("offset\t%d\n", s->symvalue.offset); 435 } 436 printf("size\t%d\n", size(s)); 437 break; 438 439 case RECORD: 440 case VARNT: 441 printf("size\t%d\n", s->symvalue.offset); 442 break; 443 444 case FIELD: 445 printf("offset\t%d\n", s->symvalue.field.offset); 446 printf("size\t%d\n", s->symvalue.field.length); 447 break; 448 449 case PROG: 450 case PROC: 451 case FUNC: 452 printf("address\t0x%x\n", s->symvalue.funcv.beginaddr); 453 if (isinline(s)) { 454 printf("inline procedure\n"); 455 } 456 if (nosource(s)) { 457 printf("does not have source information\n"); 458 } else { 459 printf("has source information\n"); 460 } 461 break; 462 463 case RANGE: 464 prangetype(s->symvalue.rangev.lowertype); 465 printf("lower\t%d\n", s->symvalue.rangev.lower); 466 prangetype(s->symvalue.rangev.uppertype); 467 printf("upper\t%d\n", s->symvalue.rangev.upper); 468 break; 469 470 default: 471 /* do nothing */ 472 break; 473 } 474 } 475 476 private prangetype(r) 477 Rangetype r; 478 { 479 switch (r) { 480 case R_CONST: 481 printf("CONST"); 482 break; 483 484 case R_ARG: 485 printf("ARG"); 486 break; 487 488 case R_TEMP: 489 printf("TEMP"); 490 break; 491 492 case R_ADJUST: 493 printf("ADJUST"); 494 break; 495 } 496 } 497 498 /* 499 * Print out the value on top of the stack according to the given type. 500 */ 501 502 public printval(t) 503 Symbol t; 504 { 505 Symbol s; 506 507 checkref(t); 508 if (t->class == TYPEREF) { 509 resolveRef(t); 510 } 511 switch (t->class) { 512 case PROC: 513 case FUNC: 514 s = pop(Symbol); 515 printf("%s", symname(s)); 516 break; 517 518 default: 519 if (t->language == nil or t->language == primlang) { 520 (*language_op(findlanguage(".c"), L_PRINTVAL))(t); 521 } else { 522 (*language_op(t->language, L_PRINTVAL))(t); 523 } 524 break; 525 } 526 } 527 528 /* 529 * Print out the value of a record, field by field. 530 */ 531 532 public printrecord(s) 533 Symbol s; 534 { 535 Symbol f; 536 537 if (s->chain == nil) { 538 error("record has no fields"); 539 } 540 printf("("); 541 sp -= size(s); 542 f = s->chain; 543 if (f != nil) { 544 for (;;) { 545 printfield(f); 546 f = f->chain; 547 if (f == nil) break; 548 printf(", "); 549 } 550 } 551 printf(")"); 552 } 553 554 /* 555 * Print out a field. 556 */ 557 558 private printfield(f) 559 Symbol f; 560 { 561 Stack *savesp; 562 register int off, len; 563 564 printf("%s = ", symname(f)); 565 savesp = sp; 566 off = f->symvalue.field.offset; 567 len = f->symvalue.field.length; 568 sp += ((off + len + BITSPERBYTE - 1) div BITSPERBYTE); 569 printval(f); 570 sp = savesp; 571 } 572 573 /* 574 * Print out the contents of an array. 575 * Haven't quite figured out what the best format is. 576 * 577 * This is rather inefficient. 578 * 579 * The "2*elsize" is there since "printval" drops the stack by elsize. 580 */ 581 582 public printarray(a) 583 Symbol a; 584 { 585 Stack *savesp, *newsp; 586 Symbol eltype; 587 long elsize; 588 String sep; 589 590 savesp = sp; 591 sp -= (size(a)); 592 newsp = sp; 593 eltype = rtype(a->type); 594 elsize = size(eltype); 595 printf("("); 596 if (eltype->class == RECORD or eltype->class == ARRAY or 597 eltype->class == VARNT) { 598 sep = "\n"; 599 putchar('\n'); 600 } else { 601 sep = ", "; 602 } 603 for (sp += elsize; sp <= savesp; sp += 2*elsize) { 604 if (sp - elsize != newsp) { 605 fputs(sep, stdout); 606 } 607 printval(eltype); 608 } 609 sp = newsp; 610 if (streq(sep, "\n")) { 611 putchar('\n'); 612 } 613 printf(")"); 614 } 615 616 /* 617 * Print out the value of a real number in Pascal notation. 618 * This is, unfortunately, different than what one gets 619 * from "%g" in printf. 620 */ 621 622 public prtreal(r) 623 double r; 624 { 625 extern char *index(); 626 char buf[256]; 627 628 sprintf(buf, "%g", r); 629 if (buf[0] == '.') { 630 printf("0%s", buf); 631 } else if (buf[0] == '-' and buf[1] == '.') { 632 printf("-0%s", &buf[1]); 633 } else { 634 printf("%s", buf); 635 } 636 if (index(buf, '.') == nil) { 637 printf(".0"); 638 } 639 } 640 641 /* 642 * Print out a character using ^? notation for unprintables. 643 */ 644 645 public printchar(c) 646 char c; 647 { 648 if (c == 0) { 649 putchar('\\'); 650 putchar('0'); 651 } else if (c == '\n') { 652 putchar('\\'); 653 putchar('n'); 654 } else if (c > 0 and c < ' ') { 655 putchar('^'); 656 putchar(c - 1 + 'A'); 657 } else if (c >= ' ' && c <= '~') { 658 putchar(c); 659 } else { 660 printf("\\0%o",c&0xff); 661 } 662 } 663 664 /* 665 * Print out a value for a range type (integer, char, or boolean). 666 */ 667 668 public printRangeVal (val, t) 669 long val; 670 Symbol t; 671 { 672 if (t == t_boolean->type or istypename(t->type, "boolean")) { 673 if ((boolean) val) { 674 printf("true"); 675 } else { 676 printf("false"); 677 } 678 } else if (t == t_char->type or istypename(t->type, "char")) { 679 if (varIsSet("$hexchars")) { 680 printf("0x%lx", val); 681 } else { 682 putchar('\''); 683 printchar(val); 684 putchar('\''); 685 } 686 } else if (varIsSet("$hexints")) { 687 printf("0x%lx", val); 688 } else if (t->symvalue.rangev.lower >= 0) { 689 printf("%lu", val); 690 } else { 691 printf("%ld", val); 692 } 693 } 694 695 /* 696 * Print out an enumerated value by finding the corresponding 697 * name in the enumeration list. 698 */ 699 700 public printEnum (i, t) 701 integer i; 702 Symbol t; 703 { 704 register Symbol e; 705 706 e = t->chain; 707 while (e != nil and e->symvalue.constval->value.lcon != i) { 708 e = e->chain; 709 } 710 if (e != nil) { 711 printf("%s", symname(e)); 712 } else { 713 printf("%d", i); 714 } 715 } 716 717 /* 718 * Print out a null-terminated string (pointer to char) 719 * starting at the given address. 720 */ 721 722 public printString (addr, quotes) 723 Address addr; 724 boolean quotes; 725 { 726 register Address a; 727 register integer i, len; 728 register boolean endofstring; 729 register int unprintables; 730 #define MAXGARBAGE 4 731 union { 732 char ch[sizeof(Word)]; 733 int word; 734 } u; 735 736 if (varIsSet("$hexstrings")) { 737 printf("0x%x", addr); 738 } else { 739 if (quotes) { 740 putchar('"'); 741 } 742 a = addr; 743 unprintables = 0; 744 endofstring = false; 745 while (not endofstring) { 746 dread(&u, a, sizeof(u)); 747 i = 0; 748 do { 749 if (u.ch[i] == '\0') { 750 endofstring = true; 751 } else { 752 printchar(u.ch[i]); 753 if (!isascii(u.ch[i]) and ++unprintables > MAXGARBAGE) { 754 endofstring = true; 755 printf("..."); 756 } 757 } 758 ++i; 759 } while (i < sizeof(Word) and not endofstring); 760 a += sizeof(Word); 761 } 762 if (quotes) { 763 putchar('"'); 764 } 765 } 766 } 767