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