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