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