xref: /original-bsd/old/dbx/vax.c (revision 9d44d164)
1 /*
2  * Copyright (c) 1983 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[] = "@(#)vax.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 "tree.h"
27 #include "eval.h"
28 #include "keywords.h"
29 #include "ops.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 ARGP 12
39 #define FRP 13
40 #define STKP 14
41 #define PROGCTR 15
42 
43 #define CODESTART 0
44 #define FUNCOFFSET 2
45 
46 #define nargspassed(frame) argn(0, frame)
47 
48 #define BITSPERBYTE 8
49 #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
50 
51 /*
52  * This magic macro enables us to look at the process' registers
53  * in its user structure.
54  */
55 
56 #define regloc(reg)	(ctob(UPAGES) + (sizeof(Word) * (reg)))
57 
58 #include "source.h"
59 #include "symbols.h"
60 #include <signal.h>
61 #include <sys/param.h>
62 #include <machine/psl.h>
63 #include <machine/pte.h>
64 #include <sys/user.h>
65 #undef DELETE /* XXX */
66 #include <sys/vm.h>
67 #include <machine/reg.h>
68 
69 Address pc;
70 Address prtaddr;
71 
72 #endif
73 
74 /*
75  * Indices into u. for use in collecting registers values.
76  */
77 public int rloc[] ={
78     R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC
79 };
80 
81 private Address printop();
82 
83 private Optab *ioptab[256];	/* index by opcode to optab */
84 private Optab *esctab[256];	/* for extended opcodes */
85 
86 /*
87  * Initialize the opcode lookup table.
88  */
89 public optab_init()
90 {
91     register Optab *p;
92 
93     for (p = optab; p->iname; p++) {
94 	if (p->format == O_ESCD) {
95 	    esctab[p->val] = p;
96 	} else if (p->format != O_ESCD && p->format != O_ESCE) {
97 	    ioptab[p->val] = p;
98 	}
99     }
100 }
101 
102 /*
103  * Decode and print the instructions within the given address range.
104  */
105 
106 public printinst(lowaddr, highaddr)
107 Address lowaddr;
108 Address highaddr;
109 {
110     register Address addr;
111 
112     for (addr = lowaddr; addr <= highaddr; ) {
113 	addr = printop(addr);
114     }
115     prtaddr = addr;
116 }
117 
118 /*
119  * Another approach:  print n instructions starting at the given address.
120  */
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     } else {
132 	newaddr = addr;
133 	for (i = 0; i < count; i++) {
134 	    newaddr = printop(newaddr);
135 	}
136 	prtaddr = newaddr;
137     }
138 }
139 
140 /*
141  * Print the contents of the addresses within the given range
142  * according to the given format.
143  */
144 
145 typedef struct {
146     String name;
147     String printfstring;
148     int length;
149 } Format;
150 
151 private Format fmt[] = {
152     { "d", " %d", sizeof(short) },
153     { "D", " %ld", sizeof(long) },
154     { "o", " %o", sizeof(short) },
155     { "O", " %lo", sizeof(long) },
156     { "x", " %04x", sizeof(short) },
157     { "X", " %08x", sizeof(long) },
158     { "b", " \\%o", sizeof(char) },
159     { "c", " '%c'", sizeof(char) },
160     { "s", "%c", sizeof(char) },
161     { "f", " %f", sizeof(float) },
162     { "g", " %g", sizeof(double) },
163     { nil, nil, 0 }
164 };
165 
166 private Format *findformat(s)
167 String s;
168 {
169     register Format *f;
170 
171     f = &fmt[0];
172     while (f->name != nil and not streq(f->name, s)) {
173 	++f;
174     }
175     if (f->name == nil) {
176 	error("bad print format \"%s\"", s);
177     }
178     return f;
179 }
180 
181 /*
182  * Retrieve and print out the appropriate data in the given format.
183  * Floats have to be handled specially to allow the compiler to
184  * convert them to doubles when passing to printf.
185  */
186 
187 private printformat (f, addr)
188 Format *f;
189 Address addr;
190 {
191     union {
192 	char charv;
193 	short shortv;
194 	int intv;
195 	float floatv;
196 	double doublev;
197     } value;
198 
199     value.intv = 0;
200     dread(&value, addr, f->length);
201     if (streq(f->name, "f")) {
202 	printf(f->printfstring, value.floatv);
203     } else {
204 	printf(f->printfstring, value);
205     }
206 }
207 
208 public Address printdata(lowaddr, highaddr, format)
209 Address lowaddr;
210 Address highaddr;
211 String format;
212 {
213     int n;
214     register Address addr;
215     Format *f;
216 
217     if (lowaddr > highaddr) {
218 	error("first address larger than second");
219     }
220     f = findformat(format);
221     n = 0;
222     for (addr = lowaddr; addr <= highaddr; addr += f->length) {
223 	if (n == 0) {
224 	    printf("%08x: ", addr);
225 	}
226 	printformat(f, addr);
227 	++n;
228 	if (n >= (16 div f->length)) {
229 	    printf("\n");
230 	    n = 0;
231 	}
232     }
233     if (n != 0) {
234 	printf("\n");
235     }
236     prtaddr = addr;
237     return addr;
238 }
239 
240 /*
241  * The other approach is to print n items starting with a given address.
242  */
243 
244 public printndata(count, startaddr, format)
245 int count;
246 Address startaddr;
247 String format;
248 {
249     int i, n;
250     Address addr;
251     Format *f;
252     Boolean isstring;
253     char c;
254 
255     if (count <= 0) {
256 	error("non-positive repetition count");
257     }
258     f = findformat(format);
259     isstring = (Boolean) streq(f->name, "s");
260     n = 0;
261     addr = startaddr;
262     for (i = 0; i < count; i++) {
263 	if (n == 0) {
264 	    printf("%08x: ", addr);
265 	}
266 	if (isstring) {
267 	    printf("\"");
268 	    dread(&c, addr, sizeof(char));
269 	    while (c != '\0') {
270 		printchar(c);
271 		++addr;
272 		dread(&c, addr, sizeof(char));
273 	    }
274 	    printf("\"\n");
275 	    n = 0;
276 	    addr += sizeof(String);
277 	} else {
278 	    printformat(f, addr);
279 	    ++n;
280 	    if (n >= (16 div f->length)) {
281 		printf("\n");
282 		n = 0;
283 	    }
284 	    addr += f->length;
285 	}
286     }
287     if (n != 0) {
288 	printf("\n");
289     }
290     prtaddr = addr;
291 }
292 
293 /*
294  * Print out a value according to the given format.
295  */
296 
297 public printvalue(v, format)
298 long v;
299 String format;
300 {
301     Format *f;
302     char *p, *q;
303 
304     f = findformat(format);
305     if (streq(f->name, "s")) {
306 	putchar('"');
307 	p = (char *) &v;
308 	q = p + sizeof(v);
309 	while (p < q) {
310 	    printchar(*p);
311 	    ++p;
312 	}
313 	putchar('"');
314     } else {
315 	printf(f->printfstring, v);
316     }
317     putchar('\n');
318 }
319 
320 /*
321  * Print out an execution time error.
322  * Assumes the source position of the error has been calculated.
323  *
324  * Have to check if the -r option was specified; if so then
325  * the object file information hasn't been read in yet.
326  */
327 
328 public printerror()
329 {
330     extern Integer sys_nsig;
331     extern String sys_siglist[];
332     integer err;
333 
334     if (isfinished(process)) {
335 	err = exitcode(process);
336 	if (err == 0) {
337 	    printf("\"%s\" terminated normally\n", objname);
338 	} else {
339 	    printf("\"%s\" terminated abnormally (exit code %d)\n",
340 		objname, err
341 	    );
342 	}
343 	erecover();
344     }
345     err = errnum(process);
346     putchar('\n');
347     printsig(err);
348     putchar(' ');
349     printloc();
350     putchar('\n');
351     if (curline > 0) {
352 	printlines(curline, curline);
353     } else {
354 	printinst(pc, pc);
355     }
356     erecover();
357 }
358 
359 /*
360  * Print out a signal.
361  */
362 
363 private String illinames[] = {
364     "reserved addressing fault",
365     "privileged instruction fault",
366     "reserved operand fault"
367 };
368 
369 private String fpenames[] = {
370     nil,
371     "integer overflow trap",
372     "integer divide by zero trap",
373     "floating overflow trap",
374     "floating/decimal divide by zero trap",
375     "floating underflow trap",
376     "decimal overflow trap",
377     "subscript out of range trap",
378     "floating overflow fault",
379     "floating divide by zero fault",
380     "floating underflow fault"
381 };
382 
383 public printsig (signo)
384 integer signo;
385 {
386     integer code;
387 
388     if (signo < 0 or signo > sys_nsig) {
389 	printf("[signal %d]", signo);
390     } else {
391 	printf("%s", sys_siglist[signo]);
392     }
393     code = errcode(process);
394     if (signo == SIGILL) {
395 	if (code >= 0 and code < sizeof(illinames) / sizeof(illinames[0])) {
396 	    printf(" (%s)", illinames[code]);
397 	}
398     } else if (signo == SIGFPE) {
399 	if (code > 0 and code < sizeof(fpenames) / sizeof(fpenames[0])) {
400 	    printf(" (%s)", fpenames[code]);
401 	}
402     }
403 }
404 
405 /*
406  * Note the termination of the program.  We do this so as to avoid
407  * having the process exit, which would make the values of variables
408  * inaccessible.  We do want to flush all output buffers here,
409  * otherwise it'll never get done.
410  */
411 
412 public endprogram()
413 {
414     Integer exitcode;
415 
416     stepto(nextaddr(pc, true));
417     printnews();
418     exitcode = argn(1, nil);
419     if (exitcode != 0) {
420 	printf("\nexecution completed (exit code %d)\n", exitcode);
421     } else {
422 	printf("\nexecution completed\n");
423     }
424     getsrcpos();
425     erecover();
426 }
427 
428 /*
429  * Single step the machine a source line (or instruction if "inst_tracing"
430  * is true).  If "isnext" is true, skip over procedure calls.
431  */
432 
433 private Address getcall();
434 
435 public dostep(isnext)
436 Boolean isnext;
437 {
438     register Address addr;
439     register Lineno line;
440     String filename;
441     Address startaddr;
442 
443     startaddr = pc;
444     addr = nextaddr(pc, isnext);
445     if (not inst_tracing and nlhdr.nlines != 0) {
446 	line = linelookup(addr);
447 	while (line == 0) {
448 	    addr = nextaddr(addr, isnext);
449 	    line = linelookup(addr);
450 	}
451 	curline = line;
452     } else {
453 	curline = 0;
454     }
455     stepto(addr);
456     filename = srcfilename(addr);
457     setsource(filename);
458 }
459 
460 typedef char Bpinst;
461 
462 #define BP_OP       O_BPT       /* breakpoint trap */
463 
464 #define BP_ERRNO    SIGTRAP     /* signal received at a breakpoint */
465 
466 /*
467  * Setting a breakpoint at a location consists of saving
468  * the word at the location and poking a BP_OP there.
469  *
470  * We save the locations and words on a list for use in unsetting.
471  */
472 
473 typedef struct Savelist *Savelist;
474 
475 struct Savelist {
476     Address location;
477     Bpinst save;
478     short refcount;
479     Savelist link;
480 };
481 
482 private Savelist savelist;
483 
484 /*
485  * Set a breakpoint at the given address.  Only save the word there
486  * if it's not already a breakpoint.
487  */
488 
489 public setbp(addr)
490 Address addr;
491 {
492     Bpinst w, save;
493     register Savelist newsave, s;
494 
495     for (s = savelist; s != nil; s = s->link) {
496 	if (s->location == addr) {
497 	    s->refcount++;
498 	    return;
499 	}
500     }
501     iread(&save, addr, sizeof(save));
502     newsave = new(Savelist);
503     newsave->location = addr;
504     newsave->save = save;
505     newsave->refcount = 1;
506     newsave->link = savelist;
507     savelist = newsave;
508     w = BP_OP;
509     iwrite(&w, addr, sizeof(w));
510 }
511 
512 /*
513  * Unset a breakpoint; unfortunately we have to search the SAVELIST
514  * to find the saved value.  The assumption is that the SAVELIST will
515  * usually be quite small.
516  */
517 
518 public unsetbp(addr)
519 Address addr;
520 {
521     register Savelist s, prev;
522 
523     prev = nil;
524     for (s = savelist; s != nil; s = s->link) {
525 	if (s->location == addr) {
526 	    iwrite(&s->save, addr, sizeof(s->save));
527 	    s->refcount--;
528 	    if (s->refcount == 0) {
529 		if (prev == nil) {
530 		    savelist = s->link;
531 		} else {
532 		    prev->link = s->link;
533 		}
534 		dispose(s);
535 	    }
536 	    return;
537 	}
538 	prev = s;
539     }
540     panic("unsetbp: couldn't find address %d", addr);
541 }
542 
543 /*
544  * VAX instruction decoder, derived from adb.
545  */
546 
547 private Address printop(addr)
548 Address addr;
549 {
550     register Optab *op;
551     VaxOpcode ins;
552     unsigned char mode;
553     int argtype, amode, argno, argval;
554     String reg;
555     Boolean indexf;
556     short offset;
557 
558     argval = 0;
559     indexf = false;
560     printf("%08x  ", addr);
561     iread(&ins, addr, sizeof(ins));
562     addr += 1;
563     if (ins == O_ESCF) {
564 	iread(&ins, addr, sizeof(ins));
565 	addr += 1;
566 	op = ioptab[ins];
567     } else if (ins == O_ESCD) {
568 	iread(&ins, addr, sizeof(ins));
569 	addr += 1;
570 	op = esctab[ins];
571     } else {
572 	op = ioptab[ins];
573     }
574     if (op == nil) {
575 	printf("[unrecognized opcode %#0x]\n", ins);
576 	return addr;
577     }
578     printf("%s", op->iname);
579     for (argno = 0; argno < op->numargs; argno++) {
580 	if (indexf == true) {
581 	    indexf = false;
582 	} else if (argno == 0) {
583 	    printf("\t");
584 	} else {
585 	    printf(",");
586 	}
587 	argtype = op->argtype[argno];
588 	if (is_branch_disp(argtype)) {
589 	    mode = 0xAF + (typelen(argtype) << 5);
590 	} else {
591 	    iread(&mode, addr, sizeof(mode));
592 	    addr += 1;
593 	}
594 	reg = regname[regnm(mode)];
595 	amode = addrmode(mode);
596 	switch (amode) {
597 	    case LITSHORT:
598 	    case LITUPTO31:
599 	    case LITUPTO47:
600 	    case LITUPTO63:
601 		if (typelen(argtype) == TYPF || typelen(argtype) == TYPD ||
602 		    typelen(argtype) == TYPG || typelen(argtype) == TYPH)
603 		    printf("$%s", fltimm[mode]);
604 		else
605 		    printf("$%x", mode);
606 		argval = mode;
607 		break;
608 
609 	    case INDEX:
610 		printf("[%s]", reg);
611 		indexf = true;
612 		argno--;
613 		break;
614 
615 	    case REG:
616 		printf("%s", reg);
617 		break;
618 
619 	    case REGDEF:
620 		printf("(%s)", reg);
621 		break;
622 
623 	    case AUTODEC:
624 		printf("-(%s)", reg);
625 		break;
626 
627 	    case AUTOINC:
628 		if (reg != regname[PROGCTR]) {
629 		    printf("(%s)+", reg);
630 		} else {
631 		    printf("$");
632 		    switch (typelen(argtype)) {
633 			case TYPB:
634 			    argval = printdisp(addr, 1, reg, amode);
635 			    addr += 1;
636 			    break;
637 
638 			case TYPW:
639 			    argval = printdisp(addr, 2, reg, amode);
640 			    addr += 2;
641 			    break;
642 
643 			case TYPL:
644 			    argval = printdisp(addr, 4, reg, amode);
645 			    addr += 4;
646 			    break;
647 
648 			case TYPF:
649 			    iread(&argval, addr, sizeof(argval));
650 			    if ((argval & 0xffff007f) == 0x8000) {
651 				printf("[reserved operand]");
652 			    } else {
653 				printf("%g", *(float *)&argval);
654 			    }
655 			    addr += 4;
656 			    break;
657 
658 			case TYPD:
659 			    /* XXX this bags the low order bits */
660 			    iread(&argval, addr, sizeof(argval));
661 			    if ((argval & 0xffff007f) == 0x8000) {
662 				printf("[reserved operand]");
663 			    } else {
664 				printf("%g", *(float *)&argval);
665 			    }
666 			    addr += 8;
667 			    break;
668 
669 			case TYPG:
670 			case TYPQ:
671 			    iread(&argval, addr+4, sizeof(argval));
672 			    printf("%08x", argval);
673 			    iread(&argval, addr, sizeof(argval));
674 			    printf("%08x", argval);
675 			    addr += 8;
676 			    break;
677 
678 			case TYPH:
679 			case TYPO:
680 			    iread(&argval, addr+12, sizeof(argval));
681 			    printf("%08x", argval);
682 			    iread(&argval, addr+8, sizeof(argval));
683 			    printf("%08x", argval);
684 			    iread(&argval, addr+4, sizeof(argval));
685 			    printf("%08x", argval);
686 			    iread(&argval, addr, sizeof(argval));
687 			    printf("%08x", argval);
688 			    addr += 16;
689 			    break;
690 		    }
691 		}
692 		break;
693 
694 	    case AUTOINCDEF:
695 		if (reg == regname[PROGCTR]) {
696 		    printf("*$");
697 		    argval = printdisp(addr, 4, reg, amode);
698 		    addr += 4;
699 		} else {
700 		    printf("*(%s)+", reg);
701 		}
702 		break;
703 
704 	    case BYTEDISP:
705 		argval = printdisp(addr, 1, reg, amode);
706 		addr += 1;
707 		break;
708 
709 	    case BYTEDISPDEF:
710 		printf("*");
711 		argval = printdisp(addr, 1, reg, amode);
712 		addr += 1;
713 		break;
714 
715 	    case WORDDISP:
716 		argval = printdisp(addr, 2, reg, amode);
717 		addr += 2;
718 		break;
719 
720 	    case WORDDISPDEF:
721 		printf("*");
722 		argval = printdisp(addr, 2, reg, amode);
723 		addr += 2;
724 		break;
725 
726 	    case LONGDISP:
727 		argval = printdisp(addr, 4, reg, amode);
728 		addr += 4;
729 		break;
730 
731 	    case LONGDISPDEF:
732 		printf("*");
733 		argval = printdisp(addr, 4, reg, amode);
734 		addr += 4;
735 		break;
736 	}
737     }
738     if (ins == O_CASEB || ins == O_CASEW || ins == O_CASEL) {
739 	for (argno = 0; argno <= argval; argno++) {
740 	    iread(&offset, addr, sizeof(offset));
741 	    printf("\n\t\t%d", offset);
742 	    addr += 2;
743 	}
744     }
745     printf("\n");
746     return addr;
747 }
748 
749 /*
750  * Print the displacement of an instruction that uses displacement
751  * addressing.
752  */
753 
754 private int printdisp(addr, nbytes, reg, mode)
755 Address addr;
756 int nbytes;
757 char *reg;
758 int mode;
759 {
760     char byte;
761     short hword;
762     int argval;
763     Symbol f;
764 
765     switch (nbytes) {
766 	case 1:
767 	    iread(&byte, addr, sizeof(byte));
768 	    argval = byte;
769 	    break;
770 
771 	case 2:
772 	    iread(&hword, addr, sizeof(hword));
773 	    argval = hword;
774 	    break;
775 
776 	case 4:
777 	    iread(&argval, addr, sizeof(argval));
778 	    break;
779     }
780     if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
781 	argval += addr + nbytes;
782     }
783     if (reg == regname[PROGCTR]) {
784 	f = whatblock((Address) argval + 2);
785 	if (codeloc(f) == argval + 2) {
786 	    printf("%s", symname(f));
787 	} else {
788 	    printf("%x", argval);
789 	}
790     } else {
791 	if (varIsSet("$hexoffsets")) {
792 	    if (argval < 0) {
793 		printf("-%x(%s)", -(argval), reg);
794 	    } else {
795 		printf("%x(%s)", argval, reg);
796 	    }
797 	} else {
798 	    printf("%d(%s)", argval, reg);
799 	}
800     }
801     return argval;
802 }
803 
804 /*
805  * Compute the next address that will be executed from the given one.
806  * If "isnext" is true then consider a procedure call as straight line code.
807  *
808  * We must unfortunately do much of the same work that is necessary
809  * to print instructions.  In addition we have to deal with branches.
810  * Unconditional branches we just follow, for conditional branches
811  * we continue execution to the current location and then single step
812  * the machine.  We assume that the last argument in an instruction
813  * that branches is the branch address (or relative offset).
814  */
815 
816 private Address findnextaddr();
817 
818 public Address nextaddr(startaddr, isnext)
819 Address startaddr;
820 boolean isnext;
821 {
822     Address addr;
823 
824     addr = usignal(process);
825     if (addr == 0 or addr == 1) {
826 	addr = findnextaddr(startaddr, isnext);
827     }
828     return addr;
829 }
830 
831 /*
832  * Determine if it's ok to skip function f entered by instruction ins.
833  * If so, we're going to compute the return address and step to it.
834  * Therefore we cannot skip over a function entered by a jsb or bsb,
835  * since the return address is not easily computed for them.
836  */
837 
838 private boolean skipfunc (ins, f)
839 VaxOpcode ins;
840 Symbol f;
841 {
842     boolean b;
843 
844     b = (boolean) (
845 	ins != O_JSB and ins != O_BSBB and ins != O_BSBW and
846 	not inst_tracing and nlhdr.nlines != 0 and
847 	nosource(curfunc) and canskip(curfunc)
848     );
849     return b;
850 }
851 
852 private Address findnextaddr(startaddr, isnext)
853 Address startaddr;
854 Boolean isnext;
855 {
856     register Address addr;
857     register Optab *op;
858     VaxOpcode ins, ins2;
859     unsigned char mode;
860     int argtype, amode, argno, argval;
861     String r;
862     Boolean indexf;
863     enum { KNOWN, SEQUENTIAL, BRANCH } addrstatus;
864 
865     argval = 0;
866     indexf = false;
867     addr = startaddr;
868     iread(&ins, addr, sizeof(ins));
869     switch (ins) {
870 	/*
871 	 * It used to be that unconditional jumps and branches were handled
872 	 * by taking their destination address as the next address.  While
873 	 * saving the cost of starting up the process, this approach
874 	 * doesn't work when jumping indirect (since the value in the
875 	 * register might not yet have been set).
876 	 *
877 	 * So unconditional jumps and branches are now handled the same way
878 	 * as conditional jumps and branches.
879 	 *
880 	case O_BRB:
881 	case O_BRW:
882 	    addrstatus = BRANCH;
883 	    break;
884 	 *
885 	 */
886 
887 	case O_BSBB:
888 	case O_BSBW:
889 	case O_JSB:
890 	case O_CALLG:
891 	case O_CALLS:
892 	    addrstatus = KNOWN;
893 	    stepto(addr);
894 	    pstep(process, DEFSIG);
895 	    addr = reg(PROGCTR);
896 	    pc = addr;
897 	    setcurfunc(whatblock(pc));
898 	    if (not isbperr()) {
899 		printstatus();
900 		/* NOTREACHED */
901 	    }
902 	    bpact();
903 	    if (isnext or skipfunc(ins, curfunc)) {
904 		addrstatus = KNOWN;
905 		addr = return_addr();
906 		stepto(addr);
907 		bpact();
908 	    } else {
909 		callnews(/* iscall = */ true);
910 	    }
911 	    break;
912 
913 	case O_RSB:
914 	case O_RET:
915 	    addrstatus = KNOWN;
916 	    stepto(addr);
917 	    callnews(/* iscall = */ false);
918 	    pstep(process, DEFSIG);
919 	    addr = reg(PROGCTR);
920 	    pc = addr;
921 	    if (not isbperr()) {
922 		printstatus();
923 	    }
924 	    bpact();
925 	    break;
926 
927 	case O_BRB: case O_BRW:
928 	case O_JMP: /* because it may be jmp (r1) */
929 	case O_BNEQ: case O_BEQL: case O_BGTR:
930 	case O_BLEQ: case O_BGEQ: case O_BLSS:
931 	case O_BGTRU: case O_BLEQU: case O_BVC:
932 	case O_BVS: case O_BCC: case O_BCS:
933 	case O_CASEB: case O_CASEW: case O_CASEL:
934 	case O_BBS: case O_BBC: case O_BBSS: case O_BBCS:
935 	case O_BBSC: case O_BBCC: case O_BBSSI:
936 	case O_BBCCI: case O_BLBS: case O_BLBC:
937 	case O_ACBL: case O_AOBLSS: case O_AOBLEQ:
938 	case O_SOBGEQ: case O_SOBGTR:
939 	case O_ESCF: /* bugchecks */
940 	branches:
941 	    addrstatus = KNOWN;
942 	    stepto(addr);
943 	    pstep(process, DEFSIG);
944 	    addr = reg(PROGCTR);
945 	    pc = addr;
946 	    if (not isbperr()) {
947 		printstatus();
948 	    }
949 	    break;
950 
951 	case O_ESCD:
952 	    iread(&ins2, addr+1, sizeof(ins2));
953 	    if (ins2 == O_ACBF || ins2 == O_ACBD)
954 		/* actually ACBG and ACBH */
955 		goto branches;
956 	    /* fall through */
957 
958 	default:
959 	    addrstatus = SEQUENTIAL;
960 	    break;
961     }
962     if (addrstatus != KNOWN) {
963 	addr += 1;
964 	if (ins == O_ESCD) {
965 	    ins = ins2;
966 	    addr += 1;
967 	    op = esctab[ins];
968 	    if (op == nil) {
969 		printf("[bad extended opcode %#x in findnextaddr]\n", ins);
970 		return addr;
971 	    }
972 	} else {
973 	    op = ioptab[ins];
974 	    if (op == nil) {
975 		printf("[bad opcode %#x in findnextaddr]\n", ins);
976 		return addr;
977 	    }
978 	}
979 	for (argno = 0; argno < op->numargs; argno++) {
980 	    if (indexf == true) {
981 		indexf = false;
982 	    }
983 	    argtype = op->argtype[argno];
984 	    if (is_branch_disp(argtype)) {
985 		mode = 0xAF + (typelen(argtype) << 5);
986 	    } else {
987 		iread(&mode, addr, sizeof(mode));
988 		addr += 1;
989 	    }
990 	    r = regname[regnm(mode)];
991 	    amode = addrmode(mode);
992 	    switch (amode) {
993 		case LITSHORT:
994 		case LITUPTO31:
995 		case LITUPTO47:
996 		case LITUPTO63:
997 		    argval = mode;
998 		    break;
999 
1000 		case INDEX:
1001 		    indexf = true;
1002 		    --argno;
1003 		    break;
1004 
1005 		case REG:
1006 		case REGDEF:
1007 		case AUTODEC:
1008 		    break;
1009 
1010 		case AUTOINC:
1011 		    if (r == regname[PROGCTR]) {
1012 			switch (typelen(argtype)) {
1013 			    case TYPB:
1014 				argval = getdisp(addr, 1, r, amode);
1015 				addr += 1;
1016 				break;
1017 
1018 			    case TYPW:
1019 				argval = getdisp(addr, 2, r, amode);
1020 				addr += 2;
1021 				break;
1022 
1023 			    case TYPL:
1024 				argval = getdisp(addr, 4, r, amode);
1025 				addr += 4;
1026 				break;
1027 
1028 			    case TYPF:
1029 				iread(&argval, addr, sizeof(argval));
1030 				addr += 4;
1031 				break;
1032 
1033 			    case TYPQ:
1034 			    case TYPD:
1035 			    case TYPG:
1036 				iread(&argval, addr+4, sizeof(argval));
1037 				addr += 8;
1038 				break;
1039 
1040 			    case TYPO:
1041 			    case TYPH:
1042 				iread(&argval, addr+12, sizeof(argval));
1043 				addr += 16;
1044 				break;
1045 			}
1046 		    }
1047 		    break;
1048 
1049 		case AUTOINCDEF:
1050 		    if (r == regname[PROGCTR]) {
1051 			argval = getdisp(addr, 4, r, amode);
1052 			addr += 4;
1053 		    }
1054 		    break;
1055 
1056 		case BYTEDISP:
1057 		case BYTEDISPDEF:
1058 		    argval = getdisp(addr, 1, r, amode);
1059 		    addr += 1;
1060 		    break;
1061 
1062 		case WORDDISP:
1063 		case WORDDISPDEF:
1064 		    argval = getdisp(addr, 2, r, amode);
1065 		    addr += 2;
1066 		    break;
1067 
1068 		case LONGDISP:
1069 		case LONGDISPDEF:
1070 		    argval = getdisp(addr, 4, r, amode);
1071 		    addr += 4;
1072 		    break;
1073 	    }
1074 	}
1075 	if (ins == O_CALLS or ins == O_CALLG) {
1076 	    argval += 2;
1077 	}
1078 	if (addrstatus == BRANCH) {
1079 	    addr = argval;
1080 	}
1081     }
1082     return addr;
1083 }
1084 
1085 /*
1086  * Get the displacement of an instruction that uses displacement addressing.
1087  */
1088 
1089 private int getdisp(addr, nbytes, reg, mode)
1090 Address addr;
1091 int nbytes;
1092 String reg;
1093 int mode;
1094 {
1095     char byte;
1096     short hword;
1097     int argval;
1098 
1099     switch (nbytes) {
1100 	case 1:
1101 	    iread(&byte, addr, sizeof(byte));
1102 	    argval = byte;
1103 	    break;
1104 
1105 	case 2:
1106 	    iread(&hword, addr, sizeof(hword));
1107 	    argval = hword;
1108 	    break;
1109 
1110 	case 4:
1111 	    iread(&argval, addr, sizeof(argval));
1112 	    break;
1113     }
1114     if (reg == regname[PROGCTR] && mode >= BYTEDISP) {
1115 	argval += addr + nbytes;
1116     }
1117     return argval;
1118 }
1119 
1120 /*
1121  * Enter a procedure by creating and executing a call instruction.
1122  */
1123 
1124 #define CALLSIZE 7	/* size of call instruction */
1125 
1126 public beginproc(p, argc)
1127 Symbol p;
1128 Integer argc;
1129 {
1130     char save[CALLSIZE];
1131     struct {
1132 	VaxOpcode op;
1133 	unsigned char numargs;
1134 	unsigned char mode;
1135 	char addr[sizeof(long)];	/* unaligned long */
1136     } call;
1137     long dest;
1138 
1139     pc = 2;
1140     iread(save, pc, sizeof(save));
1141     call.op = O_CALLS;
1142     call.numargs = argc;
1143     call.mode = 0xef;
1144     dest = codeloc(p) - 2 - (pc + 7);
1145     mov(&dest, call.addr, sizeof(call.addr));
1146     iwrite(&call, pc, sizeof(call));
1147     setreg(PROGCTR, pc);
1148     pstep(process, DEFSIG);
1149     iwrite(save, pc, sizeof(save));
1150     pc = reg(PROGCTR);
1151     if (not isbperr()) {
1152 	printstatus();
1153     }
1154 }
1155 
1156 /*
1157  * Special variables for debugging the kernel.
1158  */
1159 
1160 public integer masterpcbb;
1161 public integer slr;
1162 public struct pte *sbr;
1163 private struct pcb pcb;
1164 
1165 public getpcb ()
1166 {
1167     integer i;
1168 
1169     fseek(corefile, masterpcbb & ~0x80000000, 0);
1170     get(corefile, pcb);
1171     pcb.pcb_p0lr &= ~AST_CLR;
1172     printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n",
1173 	pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr
1174     );
1175     setreg(0, pcb.pcb_r0);
1176     setreg(1, pcb.pcb_r1);
1177     setreg(2, pcb.pcb_r2);
1178     setreg(3, pcb.pcb_r3);
1179     setreg(4, pcb.pcb_r4);
1180     setreg(5, pcb.pcb_r5);
1181     setreg(6, pcb.pcb_r6);
1182     setreg(7, pcb.pcb_r7);
1183     setreg(8, pcb.pcb_r8);
1184     setreg(9, pcb.pcb_r9);
1185     setreg(10, pcb.pcb_r10);
1186     setreg(11, pcb.pcb_r11);
1187     setreg(ARGP, pcb.pcb_ap);
1188     setreg(FRP, pcb.pcb_fp);
1189     setreg(STKP, pcb.pcb_ksp);
1190     setreg(PROGCTR, pcb.pcb_pc);
1191 }
1192 
1193 public copyregs (savreg, reg)
1194 Word savreg[], reg[];
1195 {
1196     reg[0] = savreg[R0];
1197     reg[1] = savreg[R1];
1198     reg[2] = savreg[R2];
1199     reg[3] = savreg[R3];
1200     reg[4] = savreg[R4];
1201     reg[5] = savreg[R5];
1202     reg[6] = savreg[R6];
1203     reg[7] = savreg[R7];
1204     reg[8] = savreg[R8];
1205     reg[9] = savreg[R9];
1206     reg[10] = savreg[R10];
1207     reg[11] = savreg[R11];
1208     reg[ARGP] = savreg[AP];
1209     reg[FRP] = savreg[FP];
1210     reg[STKP] = savreg[SP];
1211     reg[PROGCTR] = savreg[PC];
1212 }
1213 
1214 /*
1215  * Map a virtual address to a physical address.
1216  */
1217 
1218 public Address vmap (addr)
1219 Address addr;
1220 {
1221     Address r;
1222     integer v, n;
1223     struct pte pte;
1224 
1225     r = addr & ~0xc0000000;
1226     v = btop(r);
1227     switch (addr&0xc0000000) {
1228 	case 0xc0000000:
1229 	case 0x80000000:
1230 	    /*
1231 	     * In system space, so get system pte.
1232 	     * If it is valid or reclaimable then the physical address
1233 	     * is the combination of its page number and the page offset
1234 	     * of the original address.
1235 	     */
1236 	    if (v >= slr) {
1237 		error("address %x out of segment", addr);
1238 	    }
1239 	    r = ((long) (sbr + v)) & ~0x80000000;
1240 	    goto simple;
1241 
1242 	case 0x40000000:
1243 	    /*
1244 	     * In p1 space, must not be in shadow region.
1245 	     */
1246 	    if (v < pcb.pcb_p1lr) {
1247 		error("address %x out of segment", addr);
1248 	    }
1249 	    r = (Address) (pcb.pcb_p1br + v);
1250 	    break;
1251 
1252 	case 0x00000000:
1253 	    /*
1254 	     * In p0 space, must not be off end of region.
1255 	     */
1256 	    if (v >= pcb.pcb_p0lr) {
1257 		error("address %x out of segment", addr);
1258 	    }
1259 	    r = (Address) (pcb.pcb_p0br + v);
1260 	    break;
1261 
1262 	default:
1263 	    /* do nothing */
1264 	    break;
1265     }
1266     /*
1267      * For p0/p1 address, user-level page table should be in
1268      * kernel virtual memory.  Do second-level indirect by recursing.
1269      */
1270     if ((r & 0x80000000) == 0) {
1271 	error("bad p0br or p1br in pcb");
1272     }
1273     r = vmap(r);
1274 simple:
1275     /*
1276      * "r" is now the address of the pte of the page
1277      * we are interested in; get the pte and paste up the physical address.
1278      */
1279     fseek(corefile, r, 0);
1280     n = fread(&pte, sizeof(pte), 1, corefile);
1281     if (n != 1) {
1282 	error("page table botch (fread at %x returns %d)", r, n);
1283     }
1284     if (pte.pg_v == 0 and (pte.pg_fod != 0 or pte.pg_pfnum == 0)) {
1285 	error("page no valid or reclamable");
1286     }
1287     return (addr&PGOFSET) + ((Address) ptob(pte.pg_pfnum));
1288 }
1289 
1290 /*
1291  * Extract a bit field from an integer.
1292  */
1293 
1294 public integer extractField (s)
1295 Symbol s;
1296 {
1297     integer n, nbytes, r;
1298 
1299     n = 0;
1300     nbytes = size(s);
1301     if (nbytes > sizeof(n)) {
1302 	printf("[bad size in extractField -- word assumed]\n");
1303 	nbytes = sizeof(n);
1304     }
1305     popn(nbytes, &n);
1306     r = n >> (s->symvalue.field.offset mod BITSPERBYTE);
1307     r &= ((1 << s->symvalue.field.length) - 1);
1308     return r;
1309 }
1310 
1311 /*
1312  * Change the length of a value in memory according to a given difference
1313  * in the lengths of its new and old types.
1314  */
1315 
1316 public loophole (oldlen, newlen)
1317 integer oldlen, newlen;
1318 {
1319     integer n, i;
1320 
1321     n = newlen - oldlen;
1322     if (n > 0) {
1323 	for (i = 0; i < n; i++) {
1324 	    sp[i] = '\0';
1325 	}
1326     }
1327     sp += n;
1328 }
1329