1 2 /* Copyright (c) 1982 Regents of the University of California */ 3 4 static char sccsid[] = "@(#)runtime.c 1.8 8/10/83"; 5 6 static char rcsid[] = "$Header: runtime.c,v 1.3 84/03/27 10:23:40 linton Exp $"; 7 8 /* 9 * Runtime organization dependent routines, mostly dealing with 10 * activation records. 11 */ 12 13 #include "defs.h" 14 #include "runtime.h" 15 #include "process.h" 16 #include "machine.h" 17 #include "events.h" 18 #include "mappings.h" 19 #include "symbols.h" 20 #include "tree.h" 21 #include "eval.h" 22 #include "operators.h" 23 #include "object.h" 24 #include <sys/param.h> 25 26 #ifndef public 27 typedef struct Frame *Frame; 28 29 #include "machine.h" 30 #endif 31 32 #define NSAVEREG 12 33 34 struct Frame { 35 Integer condition_handler; 36 Integer mask; 37 Address save_ap; /* argument pointer */ 38 Address save_fp; /* frame pointer */ 39 Address save_pc; /* program counter */ 40 Word save_reg[NSAVEREG]; /* not necessarily there */ 41 }; 42 43 private Frame curframe = nil; 44 private struct Frame curframerec; 45 private Boolean walkingstack = false; 46 47 #define frameeq(f1, f2) ((f1)->save_fp == (f2)->save_fp) 48 49 /* 50 * Set a frame to the current activation record. 51 */ 52 53 private getcurframe(frp) 54 register Frame frp; 55 { 56 register int i; 57 58 checkref(frp); 59 frp->mask = reg(NREG); 60 frp->save_ap = reg(ARGP); 61 frp->save_fp = reg(FRP); 62 frp->save_pc = reg(PROGCTR) + 1; 63 for (i = 0; i < NSAVEREG; i++) { 64 frp->save_reg[i] = reg(i); 65 } 66 } 67 68 /* 69 * Return a pointer to the next activation record up the stack. 70 * Return nil if there is none. 71 * Writes over space pointed to by given argument. 72 */ 73 74 #define bis(b, n) ((b & (1 << (n))) != 0) 75 76 private Frame nextframe(frp) 77 Frame frp; 78 { 79 register Frame newfrp; 80 struct Frame frame; 81 register Integer i, j, mask; 82 Address prev_frame, callpc; 83 static Integer ntramp = 0; 84 85 newfrp = frp; 86 prev_frame = frp->save_fp; 87 88 /* 89 * The check for interrupt generated frames is taken from adb with only 90 * partial understanding. If you're in "sub" and on a sigxxx "sigsub" 91 * gets control, then the stack does NOT look like <main, sub, sigsub>. 92 * 93 * As best I can make out it looks like: 94 * 95 * <main, (machine check exception block + sub), sysframe, sigsub>. 96 * 97 * When the signal occurs an exception block and a frame for the routine 98 * in which it occured are pushed on the user stack. Then another frame 99 * is pushed corresponding to a call from the kernel to sigsub. 100 * 101 * The addr in sub at which the exception occured is not in sub.save_pc 102 * but in the machine check exception block. It is at the magic address 103 * fp + 84. 104 * 105 * The current approach ignores the sys_frame (what adb reports as sigtramp) 106 * and takes the pc for sub from the exception block. This allows the 107 * "where" command to report <main, sub, sigsub>, which seems reasonable. 108 */ 109 110 nextf: 111 dread(&frame, prev_frame, sizeof(struct Frame)); 112 if (ntramp == 1) { 113 dread(&callpc, prev_frame + 84, sizeof(callpc)); 114 } else { 115 callpc = frame.save_pc; 116 } 117 if (frame.save_fp == nil) { 118 newfrp = nil; 119 } else if (callpc > 0x80000000 - 0x200 * UPAGES ) { 120 ntramp++; 121 prev_frame = frame.save_fp; 122 goto nextf; 123 } else { 124 frame.save_pc = callpc; 125 ntramp = 0; 126 mask = ((frame.mask >> 16) & 0x0fff); 127 j = 0; 128 for (i = 0; i < NSAVEREG; i++) { 129 if (bis(mask, i)) { 130 newfrp->save_reg[i] = frame.save_reg[j]; 131 ++j; 132 } 133 } 134 newfrp->condition_handler = frame.condition_handler; 135 newfrp->mask = mask; 136 newfrp->save_ap = frame.save_ap; 137 newfrp->save_fp = frame.save_fp; 138 newfrp->save_pc = frame.save_pc; 139 } 140 return newfrp; 141 } 142 143 /* 144 * Get the current frame information in the given Frame and store the 145 * associated function in the given value-result parameter. 146 */ 147 148 private getcurfunc (frp, fp) 149 Frame frp; 150 Symbol *fp; 151 { 152 getcurframe(frp); 153 *fp = whatblock(frp->save_pc); 154 } 155 156 /* 157 * Return the frame associated with the next function up the call stack, or 158 * nil if there is none. The function is returned in a value-result parameter. 159 * For "inline" functions the statically outer function and same frame 160 * are returned. 161 */ 162 163 private Frame nextfunc (frp, fp) 164 Frame frp; 165 Symbol *fp; 166 { 167 Symbol t; 168 Frame nfrp; 169 170 t = *fp; 171 checkref(t); 172 if (isinline(t)) { 173 t = container(t); 174 nfrp = frp; 175 } else { 176 nfrp = nextframe(frp); 177 if (nfrp == nil) { 178 t = nil; 179 } else { 180 t = whatblock(nfrp->save_pc); 181 } 182 } 183 *fp = t; 184 return nfrp; 185 } 186 187 /* 188 * Return the frame associated with the given function. 189 * If the function is nil, return the most recently activated frame. 190 * 191 * Static allocation for the frame. 192 */ 193 194 public Frame findframe(f) 195 Symbol f; 196 { 197 register Frame frp; 198 static struct Frame frame; 199 Symbol p; 200 Boolean done; 201 202 frp = &frame; 203 getcurframe(frp); 204 if (f != nil) { 205 if (f == curfunc and curframe != nil) { 206 *frp = *curframe; 207 } else { 208 done = false; 209 p = whatblock(frp->save_pc); 210 do { 211 if (p == f) { 212 done = true; 213 } else if (p == program) { 214 done = true; 215 frp = nil; 216 } else { 217 frp = nextfunc(frp, &p); 218 if (frp == nil) { 219 done = true; 220 } 221 } 222 } while (not done); 223 } 224 } 225 return frp; 226 } 227 228 /* 229 * Find the return address of the current procedure/function. 230 */ 231 232 public Address return_addr() 233 { 234 Frame frp; 235 Address addr; 236 struct Frame frame; 237 238 frp = &frame; 239 getcurframe(frp); 240 frp = nextframe(frp); 241 if (frp == nil) { 242 addr = 0; 243 } else { 244 addr = frp->save_pc; 245 } 246 return addr; 247 } 248 249 /* 250 * Push the value associated with the current function. 251 */ 252 253 public pushretval(len, isindirect) 254 Integer len; 255 Boolean isindirect; 256 { 257 Word r0; 258 259 r0 = reg(0); 260 if (isindirect) { 261 rpush((Address) r0, len); 262 } else { 263 switch (len) { 264 case sizeof(char): 265 push(char, r0); 266 break; 267 268 case sizeof(short): 269 push(short, r0); 270 break; 271 272 default: 273 if (len == sizeof(Word)) { 274 push(Word, r0); 275 } else if (len == 2*sizeof(Word)) { 276 push(Word, r0); 277 push(Word, reg(1)); 278 } else { 279 panic("not indirect in pushretval?"); 280 } 281 break; 282 } 283 } 284 } 285 286 /* 287 * Return the base address for locals in the given frame. 288 */ 289 290 public Address locals_base(frp) 291 register Frame frp; 292 { 293 return (frp == nil) ? reg(FRP) : frp->save_fp; 294 } 295 296 /* 297 * Return the base address for arguments in the given frame. 298 */ 299 300 public Address args_base(frp) 301 register Frame frp; 302 { 303 return (frp == nil) ? reg(ARGP) : frp->save_ap; 304 } 305 306 /* 307 * Return saved register n from the given frame. 308 */ 309 310 public Word savereg(n, frp) 311 register Integer n; 312 register Frame frp; 313 { 314 register Word w; 315 316 if (frp == nil) { 317 w = reg(n); 318 } else { 319 switch (n) { 320 case ARGP: 321 w = frp->save_ap; 322 break; 323 324 case FRP: 325 w = frp->save_fp; 326 break; 327 328 case STKP: 329 w = reg(STKP); 330 break; 331 332 case PROGCTR: 333 w = frp->save_pc; 334 break; 335 336 default: 337 assert(n >= 0 and n < NSAVEREG); 338 w = frp->save_reg[n]; 339 break; 340 } 341 } 342 return w; 343 } 344 345 /* 346 * Return the nth argument to the current procedure. 347 */ 348 349 public Word argn(n, frp) 350 Integer n; 351 Frame frp; 352 { 353 Word w; 354 355 dread(&w, args_base(frp) + (n * sizeof(Word)), sizeof(w)); 356 return w; 357 } 358 359 /* 360 * Calculate the entry address for a procedure or function parameter, 361 * given the address of the descriptor. 362 */ 363 364 public Address fparamaddr(a) 365 Address a; 366 { 367 Address r; 368 369 dread(&r, a, sizeof(r)); 370 return r; 371 } 372 373 /* 374 * Print a list of currently active blocks starting with most recent. 375 */ 376 377 public wherecmd() 378 { 379 walkstack(false); 380 } 381 382 /* 383 * Dump the world to the given file. 384 * Like "where", but variables are dumped also. 385 */ 386 387 public dump() 388 { 389 walkstack(true); 390 } 391 392 /* 393 * Walk the stack of active procedures printing information 394 * about each active procedure. 395 */ 396 397 private walkstack(dumpvariables) 398 Boolean dumpvariables; 399 { 400 register Frame frp; 401 register Boolean save; 402 register Lineno line; 403 Symbol f; 404 struct Frame frame; 405 406 if (notstarted(process)) { 407 error("program is not active"); 408 } else { 409 save = walkingstack; 410 walkingstack = true; 411 frp = &frame; 412 getcurfunc(frp, &f); 413 do { 414 printf("%s", symname(f)); 415 if (not isinline(f)) { 416 printparams(f, frp); 417 } 418 line = srcline(frp->save_pc - 1); 419 if (line != 0) { 420 printf(", line %d", line); 421 printf(" in \"%s\"\n", srcfilename(frp->save_pc - 1)); 422 } else { 423 printf(" at 0x%x\n", frp->save_pc); 424 } 425 if (dumpvariables) { 426 dumpvars(f, frp); 427 putchar('\n'); 428 } 429 frp = nextfunc(frp, &f); 430 } while (frp != nil and f != program); 431 if (dumpvariables) { 432 printf("in \"%s\":\n", symname(program)); 433 dumpvars(program, nil); 434 putchar('\n'); 435 } 436 walkingstack = save; 437 } 438 } 439 440 /* 441 * Set the current function to the given symbol. 442 * We must adjust "curframe" so that subsequent operations are 443 * not confused; for simplicity we simply clear it. 444 */ 445 446 public setcurfunc (f) 447 Symbol f; 448 { 449 curfunc = f; 450 curframe = nil; 451 } 452 453 /* 454 * Set curfunc to be N up/down the stack from its current value. 455 */ 456 457 public up (n) 458 integer n; 459 { 460 integer i; 461 Symbol f; 462 Frame frp; 463 boolean done; 464 465 if (not isactive(program)) { 466 error("program is not active"); 467 } else if (curfunc == nil) { 468 error("no current function"); 469 } else { 470 i = 0; 471 f = curfunc; 472 if (curframe != nil) { 473 frp = curframe; 474 } else { 475 frp = findframe(f); 476 } 477 done = false; 478 do { 479 if (frp == nil) { 480 done = true; 481 error("not that many levels"); 482 } else if (i >= n) { 483 done = true; 484 curfunc = f; 485 curframe = &curframerec; 486 *curframe = *frp; 487 } else if (f == program) { 488 done = true; 489 error("not that many levels"); 490 } else { 491 frp = nextfunc(frp, &f); 492 } 493 ++i; 494 } while (not done); 495 } 496 } 497 498 public down (n) 499 integer n; 500 { 501 integer i, depth; 502 register Frame frp; 503 Symbol f; 504 struct Frame frame; 505 506 if (not isactive(program)) { 507 error("program is not active"); 508 } else if (curfunc == nil) { 509 error("no current function"); 510 } else { 511 depth = 0; 512 frp = &frame; 513 getcurfunc(frp, &f); 514 if (curframe == nil) { 515 curframe = &curframerec; 516 *curframe = *(findframe(curfunc)); 517 } 518 while ((f != curfunc or !frameeq(frp, curframe)) and f != nil) { 519 frp = nextfunc(frp, &f); 520 ++depth; 521 } 522 if (f == nil or n > depth) { 523 error("not that many levels"); 524 } else { 525 depth -= n; 526 frp = &frame; 527 getcurfunc(frp, &f); 528 for (i = 0; i < depth; i++) { 529 frp = nextfunc(frp, &f); 530 assert(frp != nil); 531 } 532 curfunc = f; 533 *curframe = *frp; 534 } 535 } 536 } 537 538 /* 539 * Find the entry point of a procedure or function. 540 */ 541 542 public findbeginning(f) 543 Symbol f; 544 { 545 if (isinternal(f)) { 546 f->symvalue.funcv.beginaddr += 15; 547 } else { 548 f->symvalue.funcv.beginaddr += 2; 549 } 550 } 551 552 /* 553 * Return the address corresponding to the first line in a function. 554 */ 555 556 public Address firstline(f) 557 Symbol f; 558 { 559 Address addr; 560 561 addr = codeloc(f); 562 while (linelookup(addr) == 0 and addr < objsize) { 563 ++addr; 564 } 565 if (addr == objsize) { 566 addr = -1; 567 } 568 return addr; 569 } 570 571 /* 572 * Catcher drops strike three ... 573 */ 574 575 public runtofirst() 576 { 577 Address addr; 578 579 addr = pc; 580 while (linelookup(addr) == 0 and addr < objsize) { 581 ++addr; 582 } 583 if (addr < objsize) { 584 stepto(addr); 585 } 586 } 587 588 /* 589 * Return the address corresponding to the end of the program. 590 * 591 * We look for the entry to "exit". 592 */ 593 594 public Address lastaddr() 595 { 596 register Symbol s; 597 598 s = lookup(identname("exit", true)); 599 if (s == nil) { 600 panic("can't find exit"); 601 } 602 return codeloc(s); 603 } 604 605 /* 606 * Decide if the given function is currently active. 607 * 608 * We avoid calls to "findframe" during a stack trace for efficiency. 609 * Presumably information evaluated while walking the stack is active. 610 */ 611 612 public Boolean isactive(f) 613 Symbol f; 614 { 615 register Boolean b; 616 617 if (isfinished(process)) { 618 b = false; 619 } else { 620 if (walkingstack or f == program or 621 (ismodule(f) and isactive(container(f)))) { 622 b = true; 623 } else { 624 b = (Boolean) (findframe(f) != nil); 625 } 626 } 627 return b; 628 } 629 630 /* 631 * Evaluate a call to a procedure. 632 */ 633 634 public callproc(procnode, arglist) 635 Node procnode; 636 Node arglist; 637 { 638 Symbol proc; 639 Integer argc; 640 641 if (procnode->op != O_SYM) { 642 beginerrmsg(); 643 fprintf(stderr, "can't call \""); 644 prtree(stderr, procnode); 645 fprintf(stderr, "\""); 646 enderrmsg(); 647 } 648 assert(procnode->op == O_SYM); 649 proc = procnode->value.sym; 650 if (not isblock(proc)) { 651 error("\"%s\" is not a procedure or function", symname(proc)); 652 } 653 pushenv(); 654 pc = codeloc(proc); 655 argc = pushargs(proc, arglist); 656 beginproc(proc, argc); 657 isstopped = true; 658 event_once(build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)), 659 buildcmdlist(build(O_PROCRTN, proc))); 660 cont(0); 661 /* NOTREACHED */ 662 } 663 664 /* 665 * Push the arguments on the process' stack. We do this by first 666 * evaluating them on the "eval" stack, then copying into the process' 667 * space. 668 */ 669 670 private Integer pushargs(proc, arglist) 671 Symbol proc; 672 Node arglist; 673 { 674 Stack *savesp; 675 int argc, args_size; 676 677 savesp = sp; 678 argc = evalargs(proc, arglist); 679 args_size = sp - savesp; 680 setreg(STKP, reg(STKP) - args_size); 681 dwrite(savesp, reg(STKP), args_size); 682 sp = savesp; 683 return argc; 684 } 685 686 /* 687 * Check to see if an expression is correct for a given parameter. 688 * If the given parameter is false, don't worry about type inconsistencies. 689 * 690 * Return whether or not it is ok. 691 */ 692 693 private boolean chkparam (actual, formal, chk) 694 Node actual; 695 Symbol formal; 696 boolean chk; 697 { 698 boolean b; 699 700 b = true; 701 if (chk) { 702 if (formal == nil) { 703 beginerrmsg(); 704 fprintf(stderr, "too many parameters"); 705 b = false; 706 } else if (not compatible(formal->type, actual->nodetype)) { 707 beginerrmsg(); 708 fprintf(stderr, "type mismatch for %s", symname(formal)); 709 b = false; 710 } 711 } 712 if (b and formal != nil and isvarparam(formal) and 713 not isopenarray(formal->type) and actual->op != O_RVAL) 714 { 715 beginerrmsg(); 716 fprintf(stderr, "expected variable, found \""); 717 prtree(stderr, actual); 718 fprintf(stderr, "\""); 719 b = false; 720 } 721 return b; 722 } 723 724 /* 725 * Pass an expression to a particular parameter. 726 * 727 * Normally we pass either the address or value, but in some cases 728 * (such as C strings) we want to copy the value onto the stack and 729 * pass its address. 730 */ 731 732 private passparam (actual, formal) 733 Node actual; 734 Symbol formal; 735 { 736 boolean b; 737 Address addr; 738 Stack *savesp; 739 integer paramsize; 740 741 if (isvarparam(formal) and not isopenarray(formal->type)) { 742 addr = lval(actual->value.arg[0]); 743 push(Address, addr); 744 } else if (passaddr(formal, actual->nodetype)) { 745 savesp = sp; 746 eval(actual); 747 paramsize = sp - savesp; 748 setreg(STKP, reg(STKP) - paramsize); 749 dwrite(savesp, reg(STKP), paramsize); 750 sp = savesp; 751 push(Address, reg(STKP)); 752 if (formal != nil and isopenarray(formal->type)) { 753 push(integer, paramsize div size(formal->type->type)); 754 } 755 } else { 756 eval(actual); 757 } 758 } 759 760 /* 761 * Evaluate an argument list left-to-right. 762 */ 763 764 private Integer evalargs(proc, arglist) 765 Symbol proc; 766 Node arglist; 767 { 768 Node p, actual; 769 Symbol formal; 770 Stack *savesp; 771 Integer count; 772 boolean chk; 773 774 savesp = sp; 775 count = 0; 776 formal = proc->chain; 777 chk = (boolean) (not nosource(proc)); 778 for (p = arglist; p != nil; p = p->value.arg[1]) { 779 assert(p->op == O_COMMA); 780 actual = p->value.arg[0]; 781 if (not chkparam(actual, formal, chk)) { 782 fprintf(stderr, " in call to %s", symname(proc)); 783 sp = savesp; 784 enderrmsg(); 785 } 786 passparam(actual, formal); 787 if (formal != nil) { 788 formal = formal->chain; 789 } 790 ++count; 791 } 792 if (chk) { 793 if (formal != nil) { 794 sp = savesp; 795 error("not enough parameters to %s", symname(proc)); 796 } 797 } 798 return count; 799 } 800 801 public procreturn(f) 802 Symbol f; 803 { 804 flushoutput(); 805 putchar('\n'); 806 printname(stdout, f); 807 printf(" returns successfully\n", symname(f)); 808 popenv(); 809 erecover(); 810 } 811 812 /* 813 * Push the current environment. 814 */ 815 816 private pushenv() 817 { 818 push(Address, pc); 819 push(Lineno, curline); 820 push(String, cursource); 821 push(Boolean, isstopped); 822 push(Symbol, curfunc); 823 push(Frame, curframe); 824 push(struct Frame, curframerec); 825 push(Word, reg(PROGCTR)); 826 push(Word, reg(STKP)); 827 } 828 829 /* 830 * Pop back to the real world. 831 */ 832 833 public popenv() 834 { 835 register String filename; 836 837 setreg(STKP, pop(Word)); 838 setreg(PROGCTR, pop(Word)); 839 curframerec = pop(struct Frame); 840 curframe = pop(Frame); 841 curfunc = pop(Symbol); 842 isstopped = pop(Boolean); 843 filename = pop(String); 844 curline = pop(Lineno); 845 pc = pop(Address); 846 setsource(filename); 847 } 848 849 /* 850 * Flush the debuggee's standard output. 851 * 852 * This is VERY dependent on the use of stdio. 853 */ 854 855 public flushoutput() 856 { 857 register Symbol p, iob; 858 register Stack *savesp; 859 860 p = lookup(identname("fflush", true)); 861 while (p != nil and not isblock(p)) { 862 p = p->next_sym; 863 } 864 if (p != nil) { 865 iob = lookup(identname("_iob", true)); 866 if (iob != nil) { 867 pushenv(); 868 pc = codeloc(p); 869 savesp = sp; 870 push(long, address(iob, nil) + sizeof(struct _iobuf)); 871 setreg(STKP, reg(STKP) - sizeof(long)); 872 dwrite(savesp, reg(STKP), sizeof(long)); 873 sp = savesp; 874 beginproc(p, 1); 875 stepto(return_addr()); 876 popenv(); 877 } 878 } 879 } 880