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