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