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.3 (Berkeley) 04/06/87"; 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 if (varIsSet("$unsafecall")) { 805 argc = unsafe_evalargs(proc, arglist); 806 } else { 807 argc = evalargs(proc, arglist); 808 } 809 args_size = sp - savesp; 810 setreg(STKP, reg(STKP) - args_size); 811 dwrite(savesp, reg(STKP), args_size); 812 sp = savesp; 813 return argc; 814 } 815 816 /* 817 * Check to see if an expression is correct for a given parameter. 818 * If the given parameter is false, don't worry about type inconsistencies. 819 * 820 * Return whether or not it is ok. 821 */ 822 823 private boolean chkparam (actual, formal, chk) 824 Node actual; 825 Symbol formal; 826 boolean chk; 827 { 828 boolean b; 829 830 b = true; 831 if (chk) { 832 if (formal == nil) { 833 beginerrmsg(); 834 fprintf(stderr, "too many parameters"); 835 b = false; 836 } else if (not compatible(formal->type, actual->nodetype)) { 837 beginerrmsg(); 838 fprintf(stderr, "type mismatch for %s", symname(formal)); 839 b = false; 840 } 841 } 842 if (b and formal != nil and 843 isvarparam(formal) and not isopenarray(formal->type) and 844 not ( 845 actual->op == O_RVAL or actual->nodetype == t_addr or 846 ( 847 actual->op == O_TYPERENAME and 848 ( 849 actual->value.arg[0]->op == O_RVAL or 850 actual->value.arg[0]->nodetype == t_addr 851 ) 852 ) 853 ) 854 ) { 855 beginerrmsg(); 856 fprintf(stderr, "expected variable, found \""); 857 prtree(stderr, actual); 858 fprintf(stderr, "\""); 859 b = false; 860 } 861 return b; 862 } 863 864 /* 865 * Pass an expression to a particular parameter. 866 * 867 * Normally we pass either the address or value, but in some cases 868 * (such as C strings) we want to copy the value onto the stack and 869 * pass its address. 870 * 871 * Another special case raised by strings is the possibility that 872 * the actual parameter will be larger than the formal, even with 873 * appropriate type-checking. This occurs because we assume during 874 * evaluation that strings are null-terminated, whereas some languages, 875 * notably Pascal, do not work under that assumption. 876 */ 877 878 private passparam (actual, formal) 879 Node actual; 880 Symbol formal; 881 { 882 boolean b; 883 Address addr; 884 Stack *savesp; 885 integer actsize, formsize; 886 887 if (formal != nil and isvarparam(formal) and 888 (not isopenarray(formal->type)) 889 ) { 890 addr = lval(actual->value.arg[0]); 891 push(Address, addr); 892 } else if (passaddr(formal, actual->nodetype)) { 893 savesp = sp; 894 eval(actual); 895 actsize = sp - savesp; 896 setreg(STKP, 897 reg(STKP) - ((actsize + sizeof(Word) - 1) & ~(sizeof(Word) - 1)) 898 ); 899 dwrite(savesp, reg(STKP), actsize); 900 sp = savesp; 901 push(Address, reg(STKP)); 902 if (formal != nil and isopenarray(formal->type)) { 903 push(integer, actsize div size(formal->type->type)); 904 } 905 } else if (formal != nil) { 906 formsize = size(formal); 907 savesp = sp; 908 eval(actual); 909 actsize = sp - savesp; 910 if (actsize > formsize) { 911 sp -= (actsize - formsize); 912 } 913 } else { 914 eval(actual); 915 } 916 } 917 918 /* 919 * Evaluate an argument list left-to-right. 920 */ 921 922 private integer evalargs(proc, arglist) 923 Symbol proc; 924 Node arglist; 925 { 926 Node p, actual; 927 Symbol formal; 928 Stack *savesp; 929 integer count; 930 boolean chk; 931 932 savesp = sp; 933 count = 0; 934 formal = proc->chain; 935 chk = (boolean) (not nosource(proc)); 936 for (p = arglist; p != nil; p = p->value.arg[1]) { 937 assert(p->op == O_COMMA); 938 actual = p->value.arg[0]; 939 if (not chkparam(actual, formal, chk)) { 940 fprintf(stderr, " in call to %s", symname(proc)); 941 sp = savesp; 942 enderrmsg(); 943 } 944 passparam(actual, formal); 945 if (formal != nil) { 946 formal = formal->chain; 947 } 948 ++count; 949 } 950 if (chk) { 951 if (formal != nil) { 952 sp = savesp; 953 error("not enough parameters to %s", symname(proc)); 954 } 955 } 956 return count; 957 } 958 959 /* 960 * Evaluate an argument list without concern for matching the formal 961 * parameters of a function in type or quantity. Useful for functions 962 * like C's printf(). 963 */ 964 965 private integer unsafe_evalargs(proc, arglist) 966 Symbol proc; 967 Node arglist; 968 { 969 Node p; 970 Integer count; 971 972 count = 0; 973 for (p = arglist; p != nil; p = p->value.arg[1]) { 974 assert(p->op == O_COMMA); 975 eval(p->value.arg[0]); 976 ++count; 977 } 978 return count; 979 } 980 981 public procreturn(f) 982 Symbol f; 983 { 984 integer retvalsize; 985 Node tmp; 986 char *copy; 987 988 flushoutput(); 989 popenv(); 990 if (endproc.isfunc) { 991 retvalsize = size(f->type); 992 if (retvalsize > sizeof(long)) { 993 pushretval(retvalsize, true); 994 copy = newarr(char, retvalsize); 995 popn(retvalsize, copy); 996 tmp = build(O_SCON, copy); 997 } else { 998 tmp = build(O_LCON, (long) (reg(0))); 999 } 1000 tmp->nodetype = f->type; 1001 tfree(endproc.callnode); 1002 *(endproc.callnode) = *(tmp); 1003 dispose(tmp); 1004 eval(endproc.cmdnode); 1005 } else { 1006 putchar('\n'); 1007 printname(stdout, f); 1008 printf("%s returns successfully\n", symname(f)); 1009 } 1010 erecover(); 1011 } 1012 1013 /* 1014 * Push the current environment. 1015 */ 1016 1017 private pushenv() 1018 { 1019 push(Address, pc); 1020 push(Lineno, curline); 1021 push(String, cursource); 1022 push(Boolean, isstopped); 1023 push(Symbol, curfunc); 1024 push(Frame, curframe); 1025 push(struct Frame, curframerec); 1026 push(CallEnv, endproc); 1027 push(Word, reg(PROGCTR)); 1028 push(Word, reg(STKP)); 1029 } 1030 1031 /* 1032 * Pop back to the real world. 1033 */ 1034 1035 public popenv() 1036 { 1037 String filename; 1038 1039 setreg(STKP, pop(Word)); 1040 setreg(PROGCTR, pop(Word)); 1041 endproc = pop(CallEnv); 1042 curframerec = pop(struct Frame); 1043 curframe = pop(Frame); 1044 curfunc = pop(Symbol); 1045 isstopped = pop(Boolean); 1046 filename = pop(String); 1047 curline = pop(Lineno); 1048 pc = pop(Address); 1049 setsource(filename); 1050 } 1051 1052 /* 1053 * Flush the debuggee's standard output. 1054 * 1055 * This is VERY dependent on the use of stdio. 1056 */ 1057 1058 public flushoutput() 1059 { 1060 Symbol p, iob; 1061 Stack *savesp; 1062 1063 p = lookup(identname("fflush", true)); 1064 while (p != nil and not isblock(p)) { 1065 p = p->next_sym; 1066 } 1067 if (p != nil) { 1068 iob = lookup(identname("_iob", true)); 1069 if (iob != nil) { 1070 pushenv(); 1071 pc = codeloc(p); 1072 savesp = sp; 1073 push(long, address(iob, nil) + sizeof(struct _iobuf)); 1074 setreg(STKP, reg(STKP) - sizeof(long)); 1075 dwrite(savesp, reg(STKP), sizeof(long)); 1076 sp = savesp; 1077 beginproc(p, 1); 1078 stepto(return_addr()); 1079 popenv(); 1080 } 1081 } 1082 } 1083