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