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