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