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.2 (Berkeley) 09/05/85"; 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 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", "@dynarray", 50 "@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 DYNARRAY: 256 case SUBARRAY: 257 t = rtype(t->type); 258 if (compatible(t, t_char)) { 259 printv(p, frame); 260 } else { 261 printf("%s = (...)", symname(p)); 262 } 263 break; 264 265 case RECORD: 266 printf("%s = (...)", symname(p)); 267 break; 268 269 default: 270 printv(p, frame); 271 break; 272 } 273 } 274 275 /* 276 * Print the name and value of a variable. 277 */ 278 279 public printv(s, frame) 280 Symbol s; 281 Frame frame; 282 { 283 Address addr; 284 int len; 285 286 if (isambiguous(s) and ismodule(container(s))) { 287 printname(stdout, s); 288 printf(" = "); 289 } else { 290 printf("%s = ", symname(s)); 291 } 292 if (isvarparam(s) and not isopenarray(s)) { 293 rpush(address(s, frame), sizeof(Address)); 294 addr = pop(Address); 295 } else { 296 addr = address(s, frame); 297 } 298 len = size(s); 299 if (not canpush(len)) { 300 printf("*** expression too large ***"); 301 } else if (isreg(s)) { 302 push(Address, addr); 303 printval(s->type); 304 } else { 305 rpush(addr, len); 306 printval(s->type); 307 } 308 } 309 310 /* 311 * Print out the name of a symbol. 312 */ 313 314 public printname(f, s) 315 File f; 316 Symbol s; 317 { 318 if (s == nil) { 319 fprintf(f, "(noname)"); 320 } else if (s == program) { 321 fprintf(f, "."); 322 } else if (isredirected() or isambiguous(s)) { 323 printwhich(f, s); 324 } else { 325 fprintf(f, "%s", symname(s)); 326 } 327 } 328 329 /* 330 * Print the fully specified variable that is described by the given identifer. 331 */ 332 333 public printwhich(f, s) 334 File f; 335 Symbol s; 336 { 337 printouter(f, container(s)); 338 fprintf(f, "%s", symname(s)); 339 } 340 341 /* 342 * Print the fully qualified name of each symbol that has the same name 343 * as the given symbol. 344 */ 345 346 public printwhereis(f, s) 347 File f; 348 Symbol s; 349 { 350 register Name n; 351 register Symbol t; 352 353 checkref(s); 354 n = s->name; 355 t = lookup(n); 356 printwhich(f, t); 357 t = t->next_sym; 358 while (t != nil) { 359 if (t->name == n) { 360 putc(' ', f); 361 printwhich(f, t); 362 } 363 t = t->next_sym; 364 } 365 putc('\n', f); 366 } 367 368 private printouter(f, s) 369 File f; 370 Symbol s; 371 { 372 Symbol outer; 373 374 if (s != nil) { 375 outer = container(s); 376 if (outer != nil and outer != program) { 377 printouter(f, outer); 378 } 379 fprintf(f, "%s.", symname(s)); 380 } 381 } 382 383 public printdecl(s) 384 Symbol s; 385 { 386 Language lang; 387 388 checkref(s); 389 if (s->language == nil or s->language == primlang) { 390 lang = findlanguage(".s"); 391 } else { 392 lang = s->language; 393 } 394 (*language_op(lang, L_PRINTDECL))(s); 395 } 396 397 /* 398 * Straight dump of symbol information. 399 */ 400 401 public psym(s) 402 Symbol s; 403 { 404 printf("name\t%s\n", symname(s)); 405 printf("lang\t%s\n", language_name(s->language)); 406 printf("level\t%d\n", s->level); 407 printf("class\t%s\n", classname(s)); 408 printf("type\t0x%x", s->type); 409 if (s->type != nil and s->type->name != nil) { 410 printf(" (%s)", symname(s->type)); 411 } 412 printf("\nchain\t0x%x", s->chain); 413 if (s->chain != nil and s->chain->name != nil) { 414 printf(" (%s)", symname(s->chain)); 415 } 416 printf("\nblock\t0x%x", s->block); 417 if (s->block->name != nil) { 418 printf(" ("); 419 printname(stdout, s->block); 420 putchar(')'); 421 } 422 putchar('\n'); 423 switch (s->class) { 424 case TYPE: 425 printf("size\t%d\n", size(s)); 426 break; 427 428 case VAR: 429 case REF: 430 if (s->level >= 3) { 431 printf("address\t0x%x\n", s->symvalue.offset); 432 } else { 433 printf("offset\t%d\n", s->symvalue.offset); 434 } 435 printf("size\t%d\n", size(s)); 436 break; 437 438 case RECORD: 439 case VARNT: 440 printf("size\t%d\n", s->symvalue.offset); 441 break; 442 443 case FIELD: 444 printf("offset\t%d\n", s->symvalue.field.offset); 445 printf("size\t%d\n", s->symvalue.field.length); 446 break; 447 448 case PROG: 449 case PROC: 450 case FUNC: 451 printf("address\t0x%x\n", s->symvalue.funcv.beginaddr); 452 if (isinline(s)) { 453 printf("inline procedure\n"); 454 } 455 if (nosource(s)) { 456 printf("does not have source information\n"); 457 } else { 458 printf("has source information\n"); 459 } 460 break; 461 462 case RANGE: 463 prangetype(s->symvalue.rangev.lowertype); 464 printf("lower\t%d\n", s->symvalue.rangev.lower); 465 prangetype(s->symvalue.rangev.uppertype); 466 printf("upper\t%d\n", s->symvalue.rangev.upper); 467 break; 468 469 default: 470 /* do nothing */ 471 break; 472 } 473 } 474 475 private prangetype(r) 476 Rangetype r; 477 { 478 switch (r) { 479 case R_CONST: 480 printf("CONST"); 481 break; 482 483 case R_ARG: 484 printf("ARG"); 485 break; 486 487 case R_TEMP: 488 printf("TEMP"); 489 break; 490 491 case R_ADJUST: 492 printf("ADJUST"); 493 break; 494 } 495 } 496 497 /* 498 * Print out the value on top of the stack according to the given type. 499 */ 500 501 public printval(t) 502 Symbol t; 503 { 504 Symbol s; 505 506 checkref(t); 507 if (t->class == TYPEREF) { 508 resolveRef(t); 509 } 510 switch (t->class) { 511 case PROC: 512 case FUNC: 513 s = pop(Symbol); 514 printf("%s", symname(s)); 515 break; 516 517 default: 518 if (t->language == nil or t->language == primlang) { 519 (*language_op(findlanguage(".s"), L_PRINTVAL))(t); 520 } else { 521 (*language_op(t->language, L_PRINTVAL))(t); 522 } 523 break; 524 } 525 } 526 527 /* 528 * Print out the value of a record, field by field. 529 */ 530 531 public printrecord(s) 532 Symbol s; 533 { 534 Symbol f; 535 536 if (s->chain == nil) { 537 error("record has no fields"); 538 } 539 printf("("); 540 sp -= size(s); 541 f = s->chain; 542 if (f != nil) { 543 for (;;) { 544 printfield(f); 545 f = f->chain; 546 if (f == nil) break; 547 printf(", "); 548 } 549 } 550 printf(")"); 551 } 552 553 /* 554 * Print out a field. 555 */ 556 557 private printfield(f) 558 Symbol f; 559 { 560 Stack *savesp; 561 register int off, len; 562 563 printf("%s = ", symname(f)); 564 savesp = sp; 565 off = f->symvalue.field.offset; 566 len = f->symvalue.field.length; 567 sp += ((off + len + BITSPERBYTE - 1) div BITSPERBYTE); 568 printval(f); 569 sp = savesp; 570 } 571 572 /* 573 * Print out the contents of an array. 574 * Haven't quite figured out what the best format is. 575 * 576 * This is rather inefficient. 577 * 578 * The "2*elsize" is there since "printval" drops the stack by elsize. 579 */ 580 581 public printarray(a) 582 Symbol a; 583 { 584 Stack *savesp, *newsp; 585 Symbol eltype; 586 long elsize; 587 String sep; 588 589 savesp = sp; 590 sp -= (size(a)); 591 newsp = sp; 592 eltype = rtype(a->type); 593 elsize = size(eltype); 594 printf("("); 595 if (eltype->class == RECORD or eltype->class == ARRAY or 596 eltype->class == VARNT) { 597 sep = "\n"; 598 putchar('\n'); 599 } else { 600 sep = ", "; 601 } 602 for (sp += elsize; sp <= savesp; sp += 2*elsize) { 603 if (sp - elsize != newsp) { 604 fputs(sep, stdout); 605 } 606 printval(eltype); 607 } 608 sp = newsp; 609 if (streq(sep, "\n")) { 610 putchar('\n'); 611 } 612 printf(")"); 613 } 614 615 /* 616 * Print out the value of a real number in Pascal notation. 617 * This is, unfortunately, different than what one gets 618 * from "%g" in printf. 619 */ 620 621 public prtreal(r) 622 double r; 623 { 624 extern char *index(); 625 char buf[256]; 626 627 sprintf(buf, "%g", r); 628 if (buf[0] == '.') { 629 printf("0%s", buf); 630 } else if (buf[0] == '-' and buf[1] == '.') { 631 printf("-0%s", &buf[1]); 632 } else { 633 printf("%s", buf); 634 } 635 if (index(buf, '.') == nil) { 636 printf(".0"); 637 } 638 } 639 640 /* 641 * Print out a character using ^? notation for unprintables. 642 */ 643 644 public printchar(c) 645 char c; 646 { 647 if (c == 0) { 648 putchar('\\'); 649 putchar('0'); 650 } else if (c == '\n') { 651 putchar('\\'); 652 putchar('n'); 653 } else if (c > 0 and c < ' ') { 654 putchar('^'); 655 putchar(c - 1 + 'A'); 656 } else if (c >= ' ' && c <= '~') { 657 putchar(c); 658 } else { 659 printf("\\0%o",c); 660 } 661 } 662 663 /* 664 * Print out a value for a range type (integer, char, or boolean). 665 */ 666 667 public printRangeVal (val, t) 668 long val; 669 Symbol t; 670 { 671 if (t == t_boolean->type or istypename(t->type, "boolean")) { 672 if ((boolean) val) { 673 printf("true"); 674 } else { 675 printf("false"); 676 } 677 } else if (t == t_char->type or istypename(t->type, "char")) { 678 if (varIsSet("$hexchars")) { 679 printf("0x%lx", val); 680 } else { 681 putchar('\''); 682 printchar(val); 683 putchar('\''); 684 } 685 } else if (varIsSet("$hexints")) { 686 printf("0x%lx", val); 687 } else if (t->symvalue.rangev.lower >= 0) { 688 printf("%lu", val); 689 } else { 690 printf("%ld", val); 691 } 692 } 693 694 /* 695 * Print out an enumerated value by finding the corresponding 696 * name in the enumeration list. 697 */ 698 699 public printEnum (i, t) 700 integer i; 701 Symbol t; 702 { 703 register Symbol e; 704 705 e = t->chain; 706 while (e != nil and e->symvalue.constval->value.lcon != i) { 707 e = e->chain; 708 } 709 if (e != nil) { 710 printf("%s", symname(e)); 711 } else { 712 printf("%d", i); 713 } 714 } 715 716 /* 717 * Print out a null-terminated string (pointer to char) 718 * starting at the given address. 719 */ 720 721 public printString (addr, quotes) 722 Address addr; 723 boolean quotes; 724 { 725 register Address a; 726 register integer i, len; 727 register boolean endofstring; 728 union { 729 char ch[sizeof(Word)]; 730 int word; 731 } u; 732 733 if (varIsSet("$hexstrings")) { 734 printf("0x%x", addr); 735 } else { 736 if (quotes) { 737 putchar('"'); 738 } 739 a = addr; 740 endofstring = false; 741 while (not endofstring) { 742 dread(&u, a, sizeof(u)); 743 i = 0; 744 do { 745 if (u.ch[i] == '\0') { 746 endofstring = true; 747 } else { 748 printchar(u.ch[i]); 749 } 750 ++i; 751 } while (i < sizeof(Word) and not endofstring); 752 a += sizeof(Word); 753 } 754 if (quotes) { 755 putchar('"'); 756 } 757 } 758 } 759