1 /* Copyright (c) 1982 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)vax.c 1.11 (Berkeley) 08/12/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 getcall(); 576 577 public dostep(isnext) 578 Boolean isnext; 579 { 580 register Address addr; 581 register Lineno line; 582 String filename; 583 Address startaddr, prevaddr; 584 585 startaddr = pc; 586 prevaddr = startaddr; 587 addr = nextaddr(pc, isnext); 588 if (not inst_tracing and nlhdr.nlines != 0) { 589 line = linelookup(addr); 590 while (line == 0) { 591 prevaddr = addr; 592 addr = nextaddr(addr, isnext); 593 line = linelookup(addr); 594 } 595 curline = line; 596 } else { 597 curline = 0; 598 } 599 if (addr == startaddr) { 600 stepto(prevaddr); 601 } 602 stepto(addr); 603 filename = srcfilename(addr); 604 setsource(filename); 605 } 606 607 /* 608 * Compute the next address that will be executed from the given one. 609 * If "isnext" is true then consider a procedure call as straight line code. 610 * 611 * We must unfortunately do much of the same work that is necessary 612 * to print instructions. In addition we have to deal with branches. 613 * Unconditional branches we just follow, for conditional branches 614 * we continue execution to the current location and then single step 615 * the machine. We assume that the last argument in an instruction 616 * that branches is the branch address (or relative offset). 617 */ 618 619 private Address findnextaddr(); 620 621 public Address nextaddr(startaddr, isnext) 622 Address startaddr; 623 boolean isnext; 624 { 625 Address addr; 626 627 addr = usignal(process); 628 if (addr == 0 or addr == 1) { 629 addr = findnextaddr(startaddr, isnext); 630 } 631 return addr; 632 } 633 634 private Address findnextaddr(startaddr, isnext) 635 Address startaddr; 636 Boolean isnext; 637 { 638 register Address addr; 639 Optab op; 640 VaxOpcode ins; 641 unsigned char mode; 642 int argtype, amode, argno, argval; 643 String r; 644 Boolean indexf; 645 enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus; 646 647 argval = 0; 648 indexf = false; 649 addr = startaddr; 650 iread(&ins, addr, sizeof(ins)); 651 switch (ins) { 652 case O_BRB: 653 case O_BRW: 654 addrstatus = BRANCH; 655 break; 656 657 case O_BSBB: 658 case O_BSBW: 659 case O_JSB: 660 case O_CALLG: 661 case O_CALLS: 662 if (isnext) { 663 addrstatus = SEQUENTIAL; 664 } else { 665 addrstatus = KNOWN; 666 stepto(addr); 667 pstep(process, DEFSIG); 668 addr = reg(PROGCTR); 669 pc = addr; 670 setcurfunc(whatblock(pc)); 671 if (not isbperr()) { 672 printstatus(); 673 /* NOTREACHED */ 674 } 675 bpact(); 676 if (nosource(curfunc) and canskip(curfunc) and 677 nlhdr.nlines != 0) { 678 addrstatus = KNOWN; 679 addr = return_addr(); 680 stepto(addr); 681 bpact(); 682 } else { 683 callnews(/* iscall = */ true); 684 } 685 } 686 break; 687 688 case O_RSB: 689 case O_RET: 690 addrstatus = KNOWN; 691 callnews(/* iscall = */ false); 692 addr = return_addr(); 693 if (addr == pc) { /* recursive ret to self */ 694 pstep(process, DEFSIG); 695 } else { 696 stepto(addr); 697 } 698 bpact(); 699 break; 700 701 case O_JMP: /* because it may be jmp (r1) */ 702 case O_BNEQ: case O_BEQL: case O_BGTR: 703 case O_BLEQ: case O_BGEQ: case O_BLSS: 704 case O_BGTRU: case O_BLEQU: case O_BVC: 705 case O_BVS: case O_BCC: case O_BCS: 706 case O_CASEB: case O_CASEW: case O_CASEL: 707 case O_BBS: case O_BBC: case O_BBSS: case O_BBCS: 708 case O_BBSC: case O_BBCC: case O_BBSSI: 709 case O_BBCCI: case O_BLBS: case O_BLBC: 710 case O_ACBL: case O_AOBLSS: case O_AOBLEQ: 711 case O_SOBGEQ: case O_SOBGTR: 712 addrstatus = KNOWN; 713 stepto(addr); 714 pstep(process, DEFSIG); 715 addr = reg(PROGCTR); 716 pc = addr; 717 if (not isbperr()) { 718 printstatus(); 719 } 720 break; 721 722 default: 723 addrstatus = SEQUENTIAL; 724 break; 725 } 726 if (addrstatus != KNOWN) { 727 addr += 1; 728 op = optab[ins]; 729 for (argno = 0; argno < op.numargs; argno++) { 730 if (indexf == true) { 731 indexf = false; 732 } 733 argtype = op.argtype[argno]; 734 if (is_branch_disp(argtype)) { 735 mode = 0xAF + (typelen(argtype) << 5); 736 } else { 737 iread(&mode, addr, sizeof(mode)); 738 addr += 1; 739 } 740 r = regname[regnm(mode)]; 741 amode = addrmode(mode); 742 switch (amode) { 743 case LITSHORT: 744 case LITUPTO31: 745 case LITUPTO47: 746 case LITUPTO63: 747 argval = mode; 748 break; 749 750 case INDEX: 751 indexf = true; 752 --argno; 753 break; 754 755 case REG: 756 case REGDEF: 757 case AUTODEC: 758 break; 759 760 case AUTOINC: 761 if (r == regname[PROGCTR]) { 762 switch (typelen(argtype)) { 763 case TYPB: 764 argval = getdisp(addr, 1, r, amode); 765 addr += 1; 766 break; 767 768 case TYPW: 769 argval = getdisp(addr, 2, r, amode); 770 addr += 2; 771 break; 772 773 case TYPL: 774 argval = getdisp(addr, 4, r, amode); 775 addr += 4; 776 break; 777 778 case TYPF: 779 iread(&argval, addr, sizeof(argval)); 780 addr += 4; 781 break; 782 783 case TYPQ: 784 case TYPD: 785 iread(&argval, addr+4, sizeof(argval)); 786 addr += 8; 787 break; 788 } 789 } 790 break; 791 792 case AUTOINCDEF: 793 if (r == regname[PROGCTR]) { 794 argval = getdisp(addr, 4, r, amode); 795 addr += 4; 796 } 797 break; 798 799 case BYTEDISP: 800 case BYTEDISPDEF: 801 argval = getdisp(addr, 1, r, amode); 802 addr += 1; 803 break; 804 805 case WORDDISP: 806 case WORDDISPDEF: 807 argval = getdisp(addr, 2, r, amode); 808 addr += 2; 809 break; 810 811 case LONGDISP: 812 case LONGDISPDEF: 813 argval = getdisp(addr, 4, r, amode); 814 addr += 4; 815 break; 816 } 817 } 818 if (ins == O_CALLS or ins == O_CALLG) { 819 argval += 2; 820 } 821 if (addrstatus == BRANCH) { 822 addr = argval; 823 } 824 } 825 return addr; 826 } 827 828 /* 829 * Get the displacement of an instruction that uses displacement addressing. 830 */ 831 832 private int getdisp(addr, nbytes, reg, mode) 833 Address addr; 834 int nbytes; 835 String reg; 836 int mode; 837 { 838 char byte; 839 short hword; 840 int argval; 841 842 switch (nbytes) { 843 case 1: 844 iread(&byte, addr, sizeof(byte)); 845 argval = byte; 846 break; 847 848 case 2: 849 iread(&hword, addr, sizeof(hword)); 850 argval = hword; 851 break; 852 853 case 4: 854 iread(&argval, addr, sizeof(argval)); 855 break; 856 } 857 if (reg == regname[PROGCTR] && mode >= BYTEDISP) { 858 argval += addr + nbytes; 859 } 860 return argval; 861 } 862 863 #define BP_OP O_BPT /* breakpoint trap */ 864 #define BP_ERRNO SIGTRAP /* signal received at a breakpoint */ 865 866 /* 867 * Setting a breakpoint at a location consists of saving 868 * the word at the location and poking a BP_OP there. 869 * 870 * We save the locations and words on a list for use in unsetting. 871 */ 872 873 typedef struct Savelist *Savelist; 874 875 struct Savelist { 876 Address location; 877 Byte save; 878 Byte refcount; 879 Savelist link; 880 }; 881 882 private Savelist savelist; 883 884 /* 885 * Set a breakpoint at the given address. Only save the word there 886 * if it's not already a breakpoint. 887 */ 888 889 public setbp(addr) 890 Address addr; 891 { 892 Byte w; 893 Byte save; 894 register Savelist newsave, s; 895 896 for (s = savelist; s != nil; s = s->link) { 897 if (s->location == addr) { 898 s->refcount++; 899 return; 900 } 901 } 902 iread(&save, addr, sizeof(save)); 903 newsave = new(Savelist); 904 newsave->location = addr; 905 newsave->save = save; 906 newsave->refcount = 1; 907 newsave->link = savelist; 908 savelist = newsave; 909 w = BP_OP; 910 iwrite(&w, addr, sizeof(w)); 911 } 912 913 /* 914 * Unset a breakpoint; unfortunately we have to search the SAVELIST 915 * to find the saved value. The assumption is that the SAVELIST will 916 * usually be quite small. 917 */ 918 919 public unsetbp(addr) 920 Address addr; 921 { 922 register Savelist s, prev; 923 924 prev = nil; 925 for (s = savelist; s != nil; s = s->link) { 926 if (s->location == addr) { 927 iwrite(&s->save, addr, sizeof(s->save)); 928 s->refcount--; 929 if (s->refcount == 0) { 930 if (prev == nil) { 931 savelist = s->link; 932 } else { 933 prev->link = s->link; 934 } 935 dispose(s); 936 } 937 return; 938 } 939 prev = s; 940 } 941 panic("unsetbp: couldn't find address %d", addr); 942 } 943 944 /* 945 * Predicate to test if the reason the process stopped was because 946 * of a breakpoint. 947 */ 948 949 public Boolean isbperr() 950 { 951 return (Boolean) (not isfinished(process) and errnum(process) == SIGTRAP); 952 } 953 954 /* 955 * Enter a procedure by creating and executing a call instruction. 956 */ 957 958 #define CALLSIZE 7 /* size of call instruction */ 959 960 public beginproc(p, argc) 961 Symbol p; 962 Integer argc; 963 { 964 char save[CALLSIZE]; 965 struct { 966 VaxOpcode op; 967 unsigned char numargs; 968 unsigned char mode; 969 char addr[sizeof(long)]; /* unaligned long */ 970 } call; 971 long dest; 972 973 pc = 2; 974 iread(save, pc, sizeof(save)); 975 call.op = O_CALLS; 976 call.numargs = argc; 977 call.mode = 0xef; 978 dest = codeloc(p) - 2 - (pc + 7); 979 mov(&dest, call.addr, sizeof(call.addr)); 980 iwrite(&call, pc, sizeof(call)); 981 setreg(PROGCTR, pc); 982 pstep(process, DEFSIG); 983 iwrite(save, pc, sizeof(save)); 984 pc = reg(PROGCTR); 985 if (not isbperr()) { 986 printstatus(); 987 } 988 } 989