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