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