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