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