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