xref: /csrg-svn/old/dbx/vax.c (revision 16630)
1 /* Copyright (c) 1982 Regents of the University of California */
2 
3 static	char sccsid[] = "@(#)vax.c	1.10 (Berkeley) 06/23/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 	printf("\"%s\" exits with code %d\n", objname, exitcode(process));
479 	erecover();
480     }
481     if (runfirst) {
482 	fprintf(stderr, "Entering debugger ...");
483 	init();
484 	fprintf(stderr, " type 'help' for help\n");
485     }
486     err = errnum(process);
487     if (err == SIGINT) {
488 	printf("\n\ninterrupt ");
489 	printloc();
490     } else if (err == SIGTRAP) {
491 	printf("\nerror ");
492 	printloc();
493     } else {
494 	if (err < 0 or err > sys_nsig) {
495 	    printf("\nsignal %d ", err);
496 	} else {
497 	    printf("\n%s ", sys_siglist[err]);
498 	}
499 	printloc();
500     }
501     putchar('\n');
502     if (curline > 0) {
503 	printlines(curline, curline);
504     } else {
505 	printinst(pc, pc);
506     }
507     erecover();
508 }
509 
510 /*
511  * Note the termination of the program.  We do this so as to avoid
512  * having the process exit, which would make the values of variables
513  * inaccessible.  We do want to flush all output buffers here,
514  * otherwise it'll never get done.
515  */
516 
517 public endprogram()
518 {
519     Integer exitcode;
520 
521     stepto(nextaddr(pc, true));
522     printnews();
523     exitcode = argn(1, nil);
524     printf("\nexecution completed, exit code is %d\n", exitcode);
525     getsrcpos();
526     erecover();
527 }
528 
529 /*
530  * Single step the machine a source line (or instruction if "inst_tracing"
531  * is true).  If "isnext" is true, skip over procedure calls.
532  */
533 
534 private Address getcall();
535 
536 public dostep(isnext)
537 Boolean isnext;
538 {
539     register Address addr;
540     register Lineno line;
541     String filename;
542     Address startaddr, prevaddr;
543 
544     startaddr = pc;
545     prevaddr = startaddr;
546     addr = nextaddr(pc, isnext);
547     if (not inst_tracing and nlhdr.nlines != 0) {
548 	line = linelookup(addr);
549 	while (line == 0) {
550 	    prevaddr = addr;
551 	    addr = nextaddr(addr, isnext);
552 	    line = linelookup(addr);
553 	}
554 	curline = line;
555     } else {
556 	curline = 0;
557     }
558     if (addr == startaddr) {
559 	stepto(prevaddr);
560     }
561     stepto(addr);
562     filename = srcfilename(addr);
563     setsource(filename);
564 }
565 
566 /*
567  * Compute the next address that will be executed from the given one.
568  * If "isnext" is true then consider a procedure call as straight line code.
569  *
570  * We must unfortunately do much of the same work that is necessary
571  * to print instructions.  In addition we have to deal with branches.
572  * Unconditional branches we just follow, for conditional branches
573  * we continue execution to the current location and then single step
574  * the machine.  We assume that the last argument in an instruction
575  * that branches is the branch address (or relative offset).
576  */
577 
578 private Address findnextaddr();
579 
580 public Address nextaddr(startaddr, isnext)
581 Address startaddr;
582 boolean isnext;
583 {
584     Address addr;
585 
586     addr = usignal(process);
587     if (addr == 0 or addr == 1) {
588 	addr = findnextaddr(startaddr, isnext);
589     }
590     return addr;
591 }
592 
593 private Address findnextaddr(startaddr, isnext)
594 Address startaddr;
595 Boolean isnext;
596 {
597     register Address addr;
598     Optab op;
599     VaxOpcode ins;
600     unsigned char mode;
601     int argtype, amode, argno, argval;
602     String r;
603     Boolean indexf;
604     enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
605 
606     argval = 0;
607     indexf = false;
608     addr = startaddr;
609     iread(&ins, addr, sizeof(ins));
610     switch (ins) {
611 	case O_BRB:
612 	case O_BRW:
613 	    addrstatus = BRANCH;
614 	    break;
615 
616 	case O_BSBB:
617 	case O_BSBW:
618 	case O_JSB:
619 	case O_CALLG:
620 	case O_CALLS:
621 	    if (isnext) {
622 		addrstatus = SEQUENTIAL;
623 	    } else {
624 		addrstatus = KNOWN;
625 		stepto(addr);
626 		pstep(process, DEFSIG);
627 		addr = reg(PROGCTR);
628 		pc = addr;
629 		setcurfunc(whatblock(pc));
630 		if (not isbperr()) {
631 		    printstatus();
632 		    /* NOTREACHED */
633 		}
634 		bpact();
635 		if (nosource(curfunc) and canskip(curfunc) and
636 		  nlhdr.nlines != 0) {
637 		    addrstatus = KNOWN;
638 		    addr = return_addr();
639 		    stepto(addr);
640 		    bpact();
641 		} else {
642 		    callnews(/* iscall = */ true);
643 		}
644 	    }
645 	    break;
646 
647 	case O_RSB:
648 	case O_RET:
649 	    addrstatus = KNOWN;
650 	    callnews(/* iscall = */ false);
651 	    addr = return_addr();
652 	    if (addr == pc) {	/* recursive ret to self */
653 		pstep(process, DEFSIG);
654 	    } else {
655 		stepto(addr);
656 	    }
657 	    bpact();
658 	    break;
659 
660 	case O_JMP: /* because it may be jmp (r1) */
661 	case O_BNEQ: case O_BEQL: case O_BGTR:
662 	case O_BLEQ: case O_BGEQ: case O_BLSS:
663 	case O_BGTRU: case O_BLEQU: case O_BVC:
664 	case O_BVS: case O_BCC: case O_BCS:
665 	case O_CASEB: case O_CASEW: case O_CASEL:
666 	case O_BBS: case O_BBC: case O_BBSS: case O_BBCS:
667 	case O_BBSC: case O_BBCC: case O_BBSSI:
668 	case O_BBCCI: case O_BLBS: case O_BLBC:
669 	case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
670 	case O_SOBGEQ: case O_SOBGTR:
671 	    addrstatus = KNOWN;
672 	    stepto(addr);
673 	    pstep(process, DEFSIG);
674 	    addr = reg(PROGCTR);
675 	    pc = addr;
676 	    if (not isbperr()) {
677 		printstatus();
678 	    }
679 	    break;
680 
681 	default:
682 	    addrstatus = SEQUENTIAL;
683 	    break;
684     }
685     if (addrstatus != KNOWN) {
686 	addr += 1;
687 	op = optab[ins];
688 	for (argno = 0; argno < op.numargs; argno++) {
689 	    if (indexf == true) {
690 		indexf = false;
691 	    }
692 	    argtype = op.argtype[argno];
693 	    if (is_branch_disp(argtype)) {
694 		mode = 0xAF + (typelen(argtype) << 5);
695 	    } else {
696 		iread(&mode, addr, sizeof(mode));
697 		addr += 1;
698 	    }
699 	    r = regname[regnm(mode)];
700 	    amode = addrmode(mode);
701 	    switch (amode) {
702 		case LITSHORT:
703 		case LITUPTO31:
704 		case LITUPTO47:
705 		case LITUPTO63:
706 		    argval = mode;
707 		    break;
708 
709 		case INDEX:
710 		    indexf = true;
711 		    --argno;
712 		    break;
713 
714 		case REG:
715 		case REGDEF:
716 		case AUTODEC:
717 		    break;
718 
719 		case AUTOINC:
720 		    if (r == regname[PROGCTR]) {
721 			switch (typelen(argtype)) {
722 			    case TYPB:
723 				argval = getdisp(addr, 1, r, amode);
724 				addr += 1;
725 				break;
726 
727 			    case TYPW:
728 				argval = getdisp(addr, 2, r, amode);
729 				addr += 2;
730 				break;
731 
732 			    case TYPL:
733 				argval = getdisp(addr, 4, r, amode);
734 				addr += 4;
735 				break;
736 
737 			    case TYPF:
738 				iread(&argval, addr, sizeof(argval));
739 				addr += 4;
740 				break;
741 
742 			    case TYPQ:
743 			    case TYPD:
744 				iread(&argval, addr+4, sizeof(argval));
745 				addr += 8;
746 				break;
747 			}
748 		    }
749 		    break;
750 
751 		case AUTOINCDEF:
752 		    if (r == regname[PROGCTR]) {
753 			argval = getdisp(addr, 4, r, amode);
754 			addr += 4;
755 		    }
756 		    break;
757 
758 		case BYTEDISP:
759 		case BYTEDISPDEF:
760 		    argval = getdisp(addr, 1, r, amode);
761 		    addr += 1;
762 		    break;
763 
764 		case WORDDISP:
765 		case WORDDISPDEF:
766 		    argval = getdisp(addr, 2, r, amode);
767 		    addr += 2;
768 		    break;
769 
770 		case LONGDISP:
771 		case LONGDISPDEF:
772 		    argval = getdisp(addr, 4, r, amode);
773 		    addr += 4;
774 		    break;
775 	    }
776 	}
777 	if (ins == O_CALLS or ins == O_CALLG) {
778 	    argval += 2;
779 	}
780 	if (addrstatus == BRANCH) {
781 	    addr = argval;
782 	}
783     }
784     return addr;
785 }
786 
787 /*
788  * Get the displacement of an instruction that uses displacement addressing.
789  */
790 
791 private int getdisp(addr, nbytes, reg, mode)
792 Address addr;
793 int nbytes;
794 String reg;
795 int mode;
796 {
797     char byte;
798     short hword;
799     int argval;
800 
801     switch (nbytes) {
802 	case 1:
803 	    iread(&byte, addr, sizeof(byte));
804 	    argval = byte;
805 	    break;
806 
807 	case 2:
808 	    iread(&hword, addr, sizeof(hword));
809 	    argval = hword;
810 	    break;
811 
812 	case 4:
813 	    iread(&argval, addr, sizeof(argval));
814 	    break;
815     }
816     if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
817 	argval += addr + nbytes;
818     }
819     return argval;
820 }
821 
822 #define BP_OP       O_BPT       /* breakpoint trap */
823 #define BP_ERRNO    SIGTRAP     /* signal received at a breakpoint */
824 
825 /*
826  * Setting a breakpoint at a location consists of saving
827  * the word at the location and poking a BP_OP there.
828  *
829  * We save the locations and words on a list for use in unsetting.
830  */
831 
832 typedef struct Savelist *Savelist;
833 
834 struct Savelist {
835     Address location;
836     Byte save;
837     Byte refcount;
838     Savelist link;
839 };
840 
841 private Savelist savelist;
842 
843 /*
844  * Set a breakpoint at the given address.  Only save the word there
845  * if it's not already a breakpoint.
846  */
847 
848 public setbp(addr)
849 Address addr;
850 {
851     Byte w;
852     Byte save;
853     register Savelist newsave, s;
854 
855     for (s = savelist; s != nil; s = s->link) {
856 	if (s->location == addr) {
857 	    s->refcount++;
858 	    return;
859 	}
860     }
861     iread(&save, addr, sizeof(save));
862     newsave = new(Savelist);
863     newsave->location = addr;
864     newsave->save = save;
865     newsave->refcount = 1;
866     newsave->link = savelist;
867     savelist = newsave;
868     w = BP_OP;
869     iwrite(&w, addr, sizeof(w));
870 }
871 
872 /*
873  * Unset a breakpoint; unfortunately we have to search the SAVELIST
874  * to find the saved value.  The assumption is that the SAVELIST will
875  * usually be quite small.
876  */
877 
878 public unsetbp(addr)
879 Address addr;
880 {
881     register Savelist s, prev;
882 
883     prev = nil;
884     for (s = savelist; s != nil; s = s->link) {
885 	if (s->location == addr) {
886 	    iwrite(&s->save, addr, sizeof(s->save));
887 	    s->refcount--;
888 	    if (s->refcount == 0) {
889 		if (prev == nil) {
890 		    savelist = s->link;
891 		} else {
892 		    prev->link = s->link;
893 		}
894 		dispose(s);
895 	    }
896 	    return;
897 	}
898 	prev = s;
899     }
900     panic("unsetbp: couldn't find address %d", addr);
901 }
902 
903 /*
904  * Predicate to test if the reason the process stopped was because
905  * of a breakpoint.
906  */
907 
908 public Boolean isbperr()
909 {
910     return (Boolean) (not isfinished(process) and errnum(process) == SIGTRAP);
911 }
912 
913 /*
914  * Enter a procedure by creating and executing a call instruction.
915  */
916 
917 #define CALLSIZE 7	/* size of call instruction */
918 
919 public beginproc(p, argc)
920 Symbol p;
921 Integer argc;
922 {
923     char save[CALLSIZE];
924     struct {
925 	VaxOpcode op;
926 	unsigned char numargs;
927 	unsigned char mode;
928 	char addr[sizeof(long)];	/* unaligned long */
929     } call;
930     long dest;
931 
932     pc = 2;
933     iread(save, pc, sizeof(save));
934     call.op = O_CALLS;
935     call.numargs = argc;
936     call.mode = 0xef;
937     dest = codeloc(p) - 2 - (pc + 7);
938     mov(&dest, call.addr, sizeof(call.addr));
939     iwrite(&call, pc, sizeof(call));
940     setreg(PROGCTR, pc);
941     pstep(process, DEFSIG);
942     iwrite(save, pc, sizeof(save));
943     pc = reg(PROGCTR);
944     if (not isbperr()) {
945 	printstatus();
946     }
947 }
948