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