xref: /csrg-svn/old/dbx/vax.c (revision 16612)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)machine.c 1.9 8/5/83";
4 
5 static char rcsid[] = "$Header: machine.c,v 1.3 84/03/27 10:21:26 linton Exp $";
6 
7 /*
8  * Target machine dependent stuff.
9  */
10 
11 #include "defs.h"
12 #include "machine.h"
13 #include "process.h"
14 #include "runtime.h"
15 #include "events.h"
16 #include "main.h"
17 #include "symbols.h"
18 #include "source.h"
19 #include "mappings.h"
20 #include "object.h"
21 #include "ops.h"
22 #include <signal.h>
23 
24 #ifndef public
25 typedef unsigned int Address;
26 typedef unsigned char Byte;
27 typedef 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 
44 Address pc;
45 Address prtaddr;
46 
47 #endif
48 
49 private Address printop();
50 
51 /*
52  * Decode and print the instructions within the given address range.
53  */
54 
55 public printinst(lowaddr, highaddr)
56 Address lowaddr;
57 Address 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 
71 public printninst(count, addr)
72 int count;
73 Address 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 
93 private Address printop(addr)
94 Address 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 
257 private int printdisp(addr, nbytes, reg, mode)
258 Address addr;
259 int nbytes;
260 char *reg;
261 int mode;
262 {
263     char byte;
264     short hword;
265     int argval;
266     Symbol f;
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]) {
287 	f = whatblock((Address) argval + 2);
288 	if (codeloc(f) == argval + 2) {
289 	    printf("%s", symname(f));
290 	} else {
291 	    printf("%x", argval);
292 	}
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 
304 typedef struct {
305     String name;
306     String printfstring;
307     int length;
308 } Format;
309 
310 private 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) },
320     { "f", " %f", sizeof(float) },
321     { "g", " %g", sizeof(double) },
322     { nil, nil, 0 }
323 };
324 
325 private Format *findformat(s)
326 String 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 
340 public Address printdata(lowaddr, highaddr, format)
341 Address lowaddr;
342 Address highaddr;
343 String 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     }
353     f = findformat(format);
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 
379 public printndata(count, startaddr, format)
380 int count;
381 Address startaddr;
382 String format;
383 {
384     register int i, n;
385     register Address addr;
386     register Format *f;
387     register Boolean isstring;
388     char c;
389     union {
390 	char charv;
391 	short shortv;
392 	int intv;
393 	float floatv;
394 	double doublev;
395     } value;
396 
397     if (count <= 0) {
398 	error("non-positive repetition count");
399     }
400     f = findformat(format);
401     isstring = (Boolean) streq(f->name, "s");
402     n = 0;
403     addr = startaddr;
404     value.intv = 0;
405     for (i = 0; i < count; i++) {
406 	if (n == 0) {
407 	    printf("%08x: ", addr);
408 	}
409 	if (isstring) {
410 	    putchar('"');
411 	    dread(&c, addr, sizeof(char));
412 	    while (c != '\0') {
413 		printchar(c);
414 		++addr;
415 		dread(&c, addr, sizeof(char));
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 
438 /*
439  * Print out a value according to the given format.
440  */
441 
442 public printvalue(v, format)
443 long v;
444 String 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 
465 /*
466  * Print out an execution time error.
467  * Assumes the source position of the error has been calculated.
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 
473 public printerror()
474 {
475     extern Integer sys_nsig;
476     extern String sys_siglist[];
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     }
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 
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 
519 public 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"
533  * is true).  If "isnext" is true, skip over procedure calls.
534  */
535 
536 private Address getcall();
537 
538 public dostep(isnext)
539 Boolean isnext;
540 {
541     register Address addr;
542     register Lineno line;
543     String filename;
544     Address startaddr, prevaddr;
545 
546     startaddr = pc;
547     prevaddr = startaddr;
548     addr = nextaddr(pc, isnext);
549     if (not inst_tracing and nlhdr.nlines != 0) {
550 	line = linelookup(addr);
551 	while (line == 0) {
552 	    prevaddr = addr;
553 	    addr = nextaddr(addr, isnext);
554 	    line = linelookup(addr);
555 	}
556 	curline = line;
557     } else {
558 	curline = 0;
559     }
560     if (addr == startaddr) {
561 	stepto(prevaddr);
562     }
563     stepto(addr);
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 
580 private Address findnextaddr();
581 
582 public Address nextaddr(startaddr, isnext)
583 Address startaddr;
584 boolean 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 
595 private Address findnextaddr(startaddr, isnext)
596 Address startaddr;
597 Boolean 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:
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);
628 		pstep(process, DEFSIG);
629 		addr = reg(PROGCTR);
630 		pc = addr;
631 		setcurfunc(whatblock(pc));
632 		if (not isbperr()) {
633 		    printstatus();
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);
642 		    bpact();
643 		} else {
644 		    callnews(/* iscall = */ true);
645 		}
646 	    }
647 	    break;
648 
649 	case O_RSB:
650 	case O_RET:
651 	    addrstatus = KNOWN;
652 	    callnews(/* iscall = */ false);
653 	    addr = return_addr();
654 	    if (addr == pc) {	/* recursive ret to self */
655 		pstep(process, DEFSIG);
656 	    } else {
657 		stepto(addr);
658 	    }
659 	    bpact();
660 	    break;
661 
662 	case O_JMP: /* because it may be jmp (r1) */
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);
675 	    pstep(process, DEFSIG);
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 
793 private int getdisp(addr, nbytes, reg, mode)
794 Address addr;
795 int nbytes;
796 String reg;
797 int 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 
834 typedef struct Savelist *Savelist;
835 
836 struct Savelist {
837     Address location;
838     Byte save;
839     Byte refcount;
840     Savelist link;
841 };
842 
843 private 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 
850 public setbp(addr)
851 Address 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     }
863     iread(&save, addr, sizeof(save));
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 
880 public unsetbp(addr)
881 Address 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 
910 public 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 
921 public beginproc(p, argc)
922 Symbol p;
923 Integer 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);
943     pstep(process, DEFSIG);
944     iwrite(save, pc, sizeof(save));
945     pc = reg(PROGCTR);
946     if (not isbperr()) {
947 	printstatus();
948     }
949 }
950