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