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[] = "@(#)machine.c 5.1 (Berkeley) 5/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: }