1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)vax.c 1.13 (Berkeley) 03/01/85"; 4 5 static char rcsid[] = "$Header: machine.c,v 1.5 84/12/26 10:40:05 linton Exp $"; 6 7 /* 8 * Target machine dependent stuff. 9 */ 10 11 #include "defs.h" 12 #include "machine.h" 13 #include "process.h" 14 #include "runtime.h" 15 #include "events.h" 16 #include "main.h" 17 #include "symbols.h" 18 #include "source.h" 19 #include "mappings.h" 20 #include "object.h" 21 #include "keywords.h" 22 #include "ops.h" 23 #include <signal.h> 24 25 #ifndef public 26 typedef unsigned int Address; 27 typedef unsigned char Byte; 28 typedef unsigned int Word; 29 30 #define NREG 16 31 32 #define ARGP 12 33 #define FRP 13 34 #define STKP 14 35 #define PROGCTR 15 36 37 #define BITSPERBYTE 8 38 #define BITSPERWORD (BITSPERBYTE * sizeof(Word)) 39 40 #define nargspassed(frame) argn(0, frame) 41 42 #include "source.h" 43 #include "symbols.h" 44 45 Address pc; 46 Address prtaddr; 47 48 #endif 49 50 private Address printop(); 51 52 /* 53 * Decode and print the instructions within the given address range. 54 */ 55 56 public printinst(lowaddr, highaddr) 57 Address lowaddr; 58 Address highaddr; 59 { 60 register Address addr; 61 62 for (addr = lowaddr; addr <= highaddr; ) { 63 addr = printop(addr); 64 } 65 prtaddr = addr; 66 } 67 68 /* 69 * Another approach: print n instructions starting at the given address. 70 */ 71 72 public printninst(count, addr) 73 int count; 74 Address addr; 75 { 76 register Integer i; 77 register Address newaddr; 78 79 if (count <= 0) { 80 error("non-positive repetition count"); 81 } else { 82 newaddr = addr; 83 for (i = 0; i < count; i++) { 84 newaddr = printop(newaddr); 85 } 86 prtaddr = newaddr; 87 } 88 } 89 90 /* 91 * Hacked version of adb's VAX instruction decoder. 92 */ 93 94 private Address printop(addr) 95 Address addr; 96 { 97 Optab op; 98 VaxOpcode ins; 99 unsigned char mode; 100 int argtype, amode, argno, argval; 101 String reg; 102 Boolean indexf; 103 short offset; 104 105 argval = 0; 106 indexf = false; 107 printf("%08x ", addr); 108 iread(&ins, addr, sizeof(ins)); 109 addr += 1; 110 op = optab[ins]; 111 printf("%s", op.iname); 112 for (argno = 0; argno < op.numargs; argno++) { 113 if (indexf == true) { 114 indexf = false; 115 } else if (argno == 0) { 116 printf("\t"); 117 } else { 118 printf(","); 119 } 120 argtype = op.argtype[argno]; 121 if (is_branch_disp(argtype)) { 122 mode = 0xAF + (typelen(argtype) << 5); 123 } else { 124 iread(&mode, addr, sizeof(mode)); 125 addr += 1; 126 } 127 reg = regname[regnm(mode)]; 128 amode = addrmode(mode); 129 switch (amode) { 130 case LITSHORT: 131 case LITUPTO31: 132 case LITUPTO47: 133 case LITUPTO63: 134 if (typelen(argtype) == TYPF || typelen(argtype) ==TYPD) 135 printf("$%s", fltimm[mode]); 136 else 137 printf("$%x", mode); 138 argval = mode; 139 break; 140 141 case INDEX: 142 printf("[%s]", reg); 143 indexf = true; 144 argno--; 145 break; 146 147 case REG: 148 printf("%s", reg); 149 break; 150 151 case REGDEF: 152 printf("(%s)", reg); 153 break; 154 155 case AUTODEC: 156 printf("-(%s)", reg); 157 break; 158 159 case AUTOINC: 160 if (reg != regname[PROGCTR]) { 161 printf("(%s)+", reg); 162 } else { 163 printf("$"); 164 switch (typelen(argtype)) { 165 case TYPB: 166 argval = printdisp(addr, 1, reg, amode); 167 addr += 1; 168 break; 169 170 case TYPW: 171 argval = printdisp(addr, 2, reg, amode); 172 addr += 2; 173 break; 174 175 case TYPL: 176 argval = printdisp(addr, 4, reg, amode); 177 addr += 4; 178 break; 179 180 case TYPF: 181 iread(&argval, addr, sizeof(argval)); 182 printf("%06x", argval); 183 addr += 4; 184 break; 185 186 case TYPQ: 187 case TYPD: 188 iread(&argval, addr, sizeof(argval)); 189 printf("%06x", argval); 190 iread(&argval, addr+4, sizeof(argval)); 191 printf("%06x", argval); 192 addr += 8; 193 break; 194 } 195 } 196 break; 197 198 case AUTOINCDEF: 199 if (reg == regname[PROGCTR]) { 200 printf("*$"); 201 argval = printdisp(addr, 4, reg, amode); 202 addr += 4; 203 } else { 204 printf("*(%s)+", reg); 205 } 206 break; 207 208 case BYTEDISP: 209 argval = printdisp(addr, 1, reg, amode); 210 addr += 1; 211 break; 212 213 case BYTEDISPDEF: 214 printf("*"); 215 argval = printdisp(addr, 1, reg, amode); 216 addr += 1; 217 break; 218 219 case WORDDISP: 220 argval = printdisp(addr, 2, reg, amode); 221 addr += 2; 222 break; 223 224 case WORDDISPDEF: 225 printf("*"); 226 argval = printdisp(addr, 2, reg, amode); 227 addr += 2; 228 break; 229 230 case LONGDISP: 231 argval = printdisp(addr, 4, reg, amode); 232 addr += 4; 233 break; 234 235 case LONGDISPDEF: 236 printf("*"); 237 argval = printdisp(addr, 4, reg, amode); 238 addr += 4; 239 break; 240 } 241 } 242 if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) { 243 for (argno = 0; argno <= argval; argno++) { 244 iread(&offset, addr, sizeof(offset)); 245 printf("\n\t\t%d", offset); 246 addr += 2; 247 } 248 } 249 printf("\n"); 250 return addr; 251 } 252 253 /* 254 * Print the displacement of an instruction that uses displacement 255 * addressing. 256 */ 257 258 private int printdisp(addr, nbytes, reg, mode) 259 Address addr; 260 int nbytes; 261 char *reg; 262 int mode; 263 { 264 char byte; 265 short hword; 266 int argval; 267 Symbol f; 268 269 switch (nbytes) { 270 case 1: 271 iread(&byte, addr, sizeof(byte)); 272 argval = byte; 273 break; 274 275 case 2: 276 iread(&hword, addr, sizeof(hword)); 277 argval = hword; 278 break; 279 280 case 4: 281 iread(&argval, addr, sizeof(argval)); 282 break; 283 } 284 if (reg == regname[PROGCTR] && mode >= BYTEDISP) { 285 argval += addr + nbytes; 286 } 287 if (reg == regname[PROGCTR]) { 288 f = whatblock((Address) argval + 2); 289 if (codeloc(f) == argval + 2) { 290 printf("%s", symname(f)); 291 } else { 292 printf("%x", argval); 293 } 294 } else { 295 if (varIsSet("$hexoffsets")) { 296 if (argval < 0) { 297 printf("-%x(%s)", -(argval), reg); 298 } else { 299 printf("%x(%s)", argval, reg); 300 } 301 } else { 302 printf("%d(%s)", argval, reg); 303 } 304 } 305 return argval; 306 } 307 308 /* 309 * Print the contents of the addresses within the given range 310 * according to the given format. 311 */ 312 313 typedef struct { 314 String name; 315 String printfstring; 316 int length; 317 } Format; 318 319 private Format fmt[] = { 320 { "d", " %d", sizeof(short) }, 321 { "D", " %ld", sizeof(long) }, 322 { "o", " %o", sizeof(short) }, 323 { "O", " %lo", sizeof(long) }, 324 { "x", " %04x", sizeof(short) }, 325 { "X", " %08x", sizeof(long) }, 326 { "b", " \\%o", sizeof(char) }, 327 { "c", " '%c'", sizeof(char) }, 328 { "s", "%c", sizeof(char) }, 329 { "f", " %f", sizeof(float) }, 330 { "g", " %g", sizeof(double) }, 331 { nil, nil, 0 } 332 }; 333 334 private Format *findformat(s) 335 String s; 336 { 337 register Format *f; 338 339 f = &fmt[0]; 340 while (f->name != nil and not streq(f->name, s)) { 341 ++f; 342 } 343 if (f->name == nil) { 344 error("bad print format \"%s\"", s); 345 } 346 return f; 347 } 348 349 public Address printdata(lowaddr, highaddr, format) 350 Address lowaddr; 351 Address highaddr; 352 String format; 353 { 354 register int n; 355 register Address addr; 356 register Format *f; 357 int value; 358 359 if (lowaddr > highaddr) { 360 error("first address larger than second"); 361 } 362 f = findformat(format); 363 n = 0; 364 value = 0; 365 for (addr = lowaddr; addr <= highaddr; addr += f->length) { 366 if (n == 0) { 367 printf("%08x: ", addr); 368 } 369 dread(&value, addr, f->length); 370 printf(f->printfstring, value); 371 ++n; 372 if (n >= (16 div f->length)) { 373 putchar('\n'); 374 n = 0; 375 } 376 } 377 if (n != 0) { 378 putchar('\n'); 379 } 380 prtaddr = addr; 381 return addr; 382 } 383 384 /* 385 * The other approach is to print n items starting with a given address. 386 */ 387 388 public printndata(count, startaddr, format) 389 int count; 390 Address startaddr; 391 String format; 392 { 393 register int i, n; 394 register Address addr; 395 register Format *f; 396 register Boolean isstring; 397 char c; 398 union { 399 char charv; 400 short shortv; 401 int intv; 402 float floatv; 403 double doublev; 404 } value; 405 406 if (count <= 0) { 407 error("non-positive repetition count"); 408 } 409 f = findformat(format); 410 isstring = (Boolean) streq(f->name, "s"); 411 n = 0; 412 addr = startaddr; 413 value.intv = 0; 414 for (i = 0; i < count; i++) { 415 if (n == 0) { 416 printf("%08x: ", addr); 417 } 418 if (isstring) { 419 putchar('"'); 420 dread(&c, addr, sizeof(char)); 421 while (c != '\0') { 422 printchar(c); 423 ++addr; 424 dread(&c, addr, sizeof(char)); 425 } 426 putchar('"'); 427 putchar('\n'); 428 n = 0; 429 addr += sizeof(String); 430 } else { 431 dread(&value, addr, f->length); 432 printf(f->printfstring, value); 433 ++n; 434 if (n >= (16 div f->length)) { 435 putchar('\n'); 436 n = 0; 437 } 438 addr += f->length; 439 } 440 } 441 if (n != 0) { 442 putchar('\n'); 443 } 444 prtaddr = addr; 445 } 446 447 /* 448 * Print out a value according to the given format. 449 */ 450 451 public printvalue(v, format) 452 long v; 453 String format; 454 { 455 Format *f; 456 char *p, *q; 457 458 f = findformat(format); 459 if (streq(f->name, "s")) { 460 putchar('"'); 461 p = (char *) &v; 462 q = p + sizeof(v); 463 while (p < q) { 464 printchar(*p); 465 ++p; 466 } 467 putchar('"'); 468 } else { 469 printf(f->printfstring, v); 470 } 471 putchar('\n'); 472 } 473 474 /* 475 * Print out an execution time error. 476 * Assumes the source position of the error has been calculated. 477 * 478 * Have to check if the -r option was specified; if so then 479 * the object file information hasn't been read in yet. 480 */ 481 482 public printerror() 483 { 484 extern Integer sys_nsig; 485 extern String sys_siglist[]; 486 integer err; 487 488 if (isfinished(process)) { 489 err = exitcode(process); 490 if (err == 0) { 491 printf("\"%s\" terminated normally\n", objname); 492 } else { 493 printf("\"%s\" terminated abnormally (exit code %d)\n", 494 objname, err 495 ); 496 } 497 erecover(); 498 } 499 if (runfirst) { 500 fprintf(stderr, "Entering debugger ...\n"); 501 init(); 502 } 503 err = errnum(process); 504 putchar('\n'); 505 printsig(err); 506 putchar(' '); 507 printloc(); 508 putchar('\n'); 509 if (curline > 0) { 510 printlines(curline, curline); 511 } else { 512 printinst(pc, pc); 513 } 514 erecover(); 515 } 516 517 /* 518 * Print out a signal. 519 */ 520 521 private String illinames[] = { 522 "reserved addressing fault", 523 "priviliged instruction fault", 524 "reserved operand fault" 525 }; 526 527 private String fpenames[] = { 528 nil, 529 "integer overflow trap", 530 "integer divide by zero trap", 531 "floating overflow trap", 532 "floating/decimal divide by zero trap", 533 "floating underflow trap", 534 "decimal overflow trap", 535 "subscript out of range trap", 536 "floating overflow fault", 537 "floating divide by zero fault", 538 "floating undeflow fault" 539 }; 540 541 public printsig (signo) 542 integer signo; 543 { 544 integer code; 545 546 if (signo < 0 or signo > sys_nsig) { 547 printf("[signal %d]", signo); 548 } else { 549 printf("%s", sys_siglist[signo]); 550 } 551 code = errcode(process); 552 if (signo == SIGILL) { 553 if (code >= 0 and code < sizeof(illinames) / sizeof(illinames[0])) { 554 printf(" (%s)", illinames[code]); 555 } 556 } else if (signo == SIGFPE) { 557 if (code > 0 and code < sizeof(fpenames) / sizeof(fpenames[0])) { 558 printf(" (%s)", fpenames[code]); 559 } 560 } 561 } 562 563 /* 564 * Note the termination of the program. We do this so as to avoid 565 * having the process exit, which would make the values of variables 566 * inaccessible. We do want to flush all output buffers here, 567 * otherwise it'll never get done. 568 */ 569 570 public endprogram() 571 { 572 Integer exitcode; 573 574 stepto(nextaddr(pc, true)); 575 printnews(); 576 exitcode = argn(1, nil); 577 if (exitcode != 0) { 578 printf("\nexecution completed (exit code %d)\n", exitcode); 579 } else { 580 printf("\nexecution completed\n"); 581 } 582 getsrcpos(); 583 erecover(); 584 } 585 586 /* 587 * Single step the machine a source line (or instruction if "inst_tracing" 588 * is true). If "isnext" is true, skip over procedure calls. 589 */ 590 591 private Address getcall(); 592 593 public dostep(isnext) 594 Boolean isnext; 595 { 596 register Address addr; 597 register Lineno line; 598 String filename; 599 Address startaddr; 600 601 startaddr = pc; 602 addr = nextaddr(pc, isnext); 603 if (not inst_tracing and nlhdr.nlines != 0) { 604 line = linelookup(addr); 605 while (line == 0) { 606 addr = nextaddr(addr, isnext); 607 line = linelookup(addr); 608 } 609 curline = line; 610 } else { 611 curline = 0; 612 } 613 stepto(addr); 614 filename = srcfilename(addr); 615 setsource(filename); 616 } 617 618 /* 619 * Compute the next address that will be executed from the given one. 620 * If "isnext" is true then consider a procedure call as straight line code. 621 * 622 * We must unfortunately do much of the same work that is necessary 623 * to print instructions. In addition we have to deal with branches. 624 * Unconditional branches we just follow, for conditional branches 625 * we continue execution to the current location and then single step 626 * the machine. We assume that the last argument in an instruction 627 * that branches is the branch address (or relative offset). 628 */ 629 630 private Address findnextaddr(); 631 632 public Address nextaddr(startaddr, isnext) 633 Address startaddr; 634 boolean isnext; 635 { 636 Address addr; 637 638 addr = usignal(process); 639 if (addr == 0 or addr == 1) { 640 addr = findnextaddr(startaddr, isnext); 641 } 642 return addr; 643 } 644 645 /* 646 * Determine if it's ok to skip function f entered by instruction ins. 647 * If so, we're going to compute the return address and step to it. 648 * Therefore we cannot skip over a function entered by a jsb or bsb, 649 * since the return address is not easily computed for them. 650 */ 651 652 private boolean skipfunc (ins, f) 653 VaxOpcode ins; 654 Symbol f; 655 { 656 boolean b; 657 658 b = (boolean) ( 659 ins != O_JSB and ins != O_BSBB and ins != O_BSBW and 660 not inst_tracing and nlhdr.nlines != 0 and 661 nosource(curfunc) and canskip(curfunc) 662 ); 663 return b; 664 } 665 666 private Address findnextaddr(startaddr, isnext) 667 Address startaddr; 668 Boolean isnext; 669 { 670 register Address addr; 671 Optab op; 672 VaxOpcode ins; 673 unsigned char mode; 674 int argtype, amode, argno, argval; 675 String r; 676 Boolean indexf; 677 enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus; 678 679 argval = 0; 680 indexf = false; 681 addr = startaddr; 682 iread(&ins, addr, sizeof(ins)); 683 switch (ins) { 684 /* 685 * It used to be that unconditional jumps and branches were handled 686 * by taking their destination address as the next address. While 687 * saving the cost of starting up the process, this approach 688 * doesn't work when jumping indirect (since the value in the 689 * register might not yet have been set). 690 * 691 * So unconditional jumps and branches are now handled the same way 692 * as conditional jumps and branches. 693 * 694 case O_BRB: 695 case O_BRW: 696 addrstatus = BRANCH; 697 break; 698 * 699 */ 700 701 case O_BSBB: 702 case O_BSBW: 703 case O_JSB: 704 case O_CALLG: 705 case O_CALLS: 706 addrstatus = KNOWN; 707 stepto(addr); 708 pstep(process, DEFSIG); 709 addr = reg(PROGCTR); 710 pc = addr; 711 setcurfunc(whatblock(pc)); 712 if (not isbperr()) { 713 printstatus(); 714 /* NOTREACHED */ 715 } 716 bpact(); 717 if (isnext or skipfunc(ins, curfunc)) { 718 addrstatus = KNOWN; 719 addr = return_addr(); 720 stepto(addr); 721 bpact(); 722 } else { 723 callnews(/* iscall = */ true); 724 } 725 break; 726 727 case O_RSB: 728 case O_RET: 729 addrstatus = KNOWN; 730 stepto(addr); 731 callnews(/* iscall = */ false); 732 pstep(process, DEFSIG); 733 addr = reg(PROGCTR); 734 pc = addr; 735 if (not isbperr()) { 736 printstatus(); 737 } 738 bpact(); 739 break; 740 741 case O_BRB: case O_BRW: 742 case O_JMP: /* because it may be jmp (r1) */ 743 case O_BNEQ: case O_BEQL: case O_BGTR: 744 case O_BLEQ: case O_BGEQ: case O_BLSS: 745 case O_BGTRU: case O_BLEQU: case O_BVC: 746 case O_BVS: case O_BCC: case O_BCS: 747 case O_CASEB: case O_CASEW: case O_CASEL: 748 case O_BBS: case O_BBC: case O_BBSS: case O_BBCS: 749 case O_BBSC: case O_BBCC: case O_BBSSI: 750 case O_BBCCI: case O_BLBS: case O_BLBC: 751 case O_ACBL: case O_AOBLSS: case O_AOBLEQ: 752 case O_SOBGEQ: case O_SOBGTR: 753 addrstatus = KNOWN; 754 stepto(addr); 755 pstep(process, DEFSIG); 756 addr = reg(PROGCTR); 757 pc = addr; 758 if (not isbperr()) { 759 printstatus(); 760 } 761 break; 762 763 default: 764 addrstatus = SEQUENTIAL; 765 break; 766 } 767 if (addrstatus != KNOWN) { 768 addr += 1; 769 op = optab[ins]; 770 for (argno = 0; argno < op.numargs; argno++) { 771 if (indexf == true) { 772 indexf = false; 773 } 774 argtype = op.argtype[argno]; 775 if (is_branch_disp(argtype)) { 776 mode = 0xAF + (typelen(argtype) << 5); 777 } else { 778 iread(&mode, addr, sizeof(mode)); 779 addr += 1; 780 } 781 r = regname[regnm(mode)]; 782 amode = addrmode(mode); 783 switch (amode) { 784 case LITSHORT: 785 case LITUPTO31: 786 case LITUPTO47: 787 case LITUPTO63: 788 argval = mode; 789 break; 790 791 case INDEX: 792 indexf = true; 793 --argno; 794 break; 795 796 case REG: 797 case REGDEF: 798 case AUTODEC: 799 break; 800 801 case AUTOINC: 802 if (r == regname[PROGCTR]) { 803 switch (typelen(argtype)) { 804 case TYPB: 805 argval = getdisp(addr, 1, r, amode); 806 addr += 1; 807 break; 808 809 case TYPW: 810 argval = getdisp(addr, 2, r, amode); 811 addr += 2; 812 break; 813 814 case TYPL: 815 argval = getdisp(addr, 4, r, amode); 816 addr += 4; 817 break; 818 819 case TYPF: 820 iread(&argval, addr, sizeof(argval)); 821 addr += 4; 822 break; 823 824 case TYPQ: 825 case TYPD: 826 iread(&argval, addr+4, sizeof(argval)); 827 addr += 8; 828 break; 829 } 830 } 831 break; 832 833 case AUTOINCDEF: 834 if (r == regname[PROGCTR]) { 835 argval = getdisp(addr, 4, r, amode); 836 addr += 4; 837 } 838 break; 839 840 case BYTEDISP: 841 case BYTEDISPDEF: 842 argval = getdisp(addr, 1, r, amode); 843 addr += 1; 844 break; 845 846 case WORDDISP: 847 case WORDDISPDEF: 848 argval = getdisp(addr, 2, r, amode); 849 addr += 2; 850 break; 851 852 case LONGDISP: 853 case LONGDISPDEF: 854 argval = getdisp(addr, 4, r, amode); 855 addr += 4; 856 break; 857 } 858 } 859 if (ins == O_CALLS or ins == O_CALLG) { 860 argval += 2; 861 } 862 if (addrstatus == BRANCH) { 863 addr = argval; 864 } 865 } 866 return addr; 867 } 868 869 /* 870 * Get the displacement of an instruction that uses displacement addressing. 871 */ 872 873 private int getdisp(addr, nbytes, reg, mode) 874 Address addr; 875 int nbytes; 876 String reg; 877 int mode; 878 { 879 char byte; 880 short hword; 881 int argval; 882 883 switch (nbytes) { 884 case 1: 885 iread(&byte, addr, sizeof(byte)); 886 argval = byte; 887 break; 888 889 case 2: 890 iread(&hword, addr, sizeof(hword)); 891 argval = hword; 892 break; 893 894 case 4: 895 iread(&argval, addr, sizeof(argval)); 896 break; 897 } 898 if (reg == regname[PROGCTR] && mode >= BYTEDISP) { 899 argval += addr + nbytes; 900 } 901 return argval; 902 } 903 904 #define BP_OP O_BPT /* breakpoint trap */ 905 #define BP_ERRNO SIGTRAP /* signal received at a breakpoint */ 906 907 /* 908 * Setting a breakpoint at a location consists of saving 909 * the word at the location and poking a BP_OP there. 910 * 911 * We save the locations and words on a list for use in unsetting. 912 */ 913 914 typedef struct Savelist *Savelist; 915 916 struct Savelist { 917 Address location; 918 Byte save; 919 Byte refcount; 920 Savelist link; 921 }; 922 923 private Savelist savelist; 924 925 /* 926 * Set a breakpoint at the given address. Only save the word there 927 * if it's not already a breakpoint. 928 */ 929 930 public setbp(addr) 931 Address addr; 932 { 933 Byte w; 934 Byte save; 935 register Savelist newsave, s; 936 937 for (s = savelist; s != nil; s = s->link) { 938 if (s->location == addr) { 939 s->refcount++; 940 return; 941 } 942 } 943 iread(&save, addr, sizeof(save)); 944 newsave = new(Savelist); 945 newsave->location = addr; 946 newsave->save = save; 947 newsave->refcount = 1; 948 newsave->link = savelist; 949 savelist = newsave; 950 w = BP_OP; 951 iwrite(&w, addr, sizeof(w)); 952 } 953 954 /* 955 * Unset a breakpoint; unfortunately we have to search the SAVELIST 956 * to find the saved value. The assumption is that the SAVELIST will 957 * usually be quite small. 958 */ 959 960 public unsetbp(addr) 961 Address addr; 962 { 963 register Savelist s, prev; 964 965 prev = nil; 966 for (s = savelist; s != nil; s = s->link) { 967 if (s->location == addr) { 968 iwrite(&s->save, addr, sizeof(s->save)); 969 s->refcount--; 970 if (s->refcount == 0) { 971 if (prev == nil) { 972 savelist = s->link; 973 } else { 974 prev->link = s->link; 975 } 976 dispose(s); 977 } 978 return; 979 } 980 prev = s; 981 } 982 panic("unsetbp: couldn't find address %d", addr); 983 } 984 985 /* 986 * Enter a procedure by creating and executing a call instruction. 987 */ 988 989 #define CALLSIZE 7 /* size of call instruction */ 990 991 public beginproc(p, argc) 992 Symbol p; 993 Integer argc; 994 { 995 char save[CALLSIZE]; 996 struct { 997 VaxOpcode op; 998 unsigned char numargs; 999 unsigned char mode; 1000 char addr[sizeof(long)]; /* unaligned long */ 1001 } call; 1002 long dest; 1003 1004 pc = 2; 1005 iread(save, pc, sizeof(save)); 1006 call.op = O_CALLS; 1007 call.numargs = argc; 1008 call.mode = 0xef; 1009 dest = codeloc(p) - 2 - (pc + 7); 1010 mov(&dest, call.addr, sizeof(call.addr)); 1011 iwrite(&call, pc, sizeof(call)); 1012 setreg(PROGCTR, pc); 1013 pstep(process, DEFSIG); 1014 iwrite(save, pc, sizeof(save)); 1015 pc = reg(PROGCTR); 1016 if (not isbperr()) { 1017 printstatus(); 1018 } 1019 } 1020