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