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