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