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