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