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