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