xref: /original-bsd/old/dbx/iris.c (revision a141c157)
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[] = "@(#)iris.c	5.1 (Berkeley) 01/12/88";
9 #endif not lint
10 
11 static char rcsid[] = "$Header: machine.c,v 1.2 87/03/26 14:54:55 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 /*
38  * On the 68000, the pc isn't in a register, but we make believe
39  * so there's one more register.
40  *
41  * Note that there's also no argument pointer, this means code
42  * involving "ARGP" should always be #ifdef'd.
43  *
44  * The address corresponding to the beginning of a function is recorded
45  * as the address + FUNCOFFSET (skip the link instruction so that
46  * local information is available).
47  */
48 
49 #define NREG 17
50 
51 #define FRP 14
52 #define STKP 15
53 #define PROGCTR 16
54 
55 #define CALL_RETADDR	0x800c		/* Return address for 'call' command */
56 #define FUNCOFFSET 4
57 
58 #ifdef sun
59 #    define CODESTART 0x8000
60 #else /* IRIS */
61 #   define CODESTART 0x1000
62 #endif
63 
64 #define optab_init()
65 
66 #define BITSPERBYTE 8
67 #define BITSPERWORD (BITSPERBYTE * sizeof(Word))
68 
69 /*
70  * This magic macro enables us to look at the process' registers
71  * in its user structure.
72  */
73 
74 #define regloc(reg)	(ctob(UPAGES) + (sizeof(Word) * ((reg) - PC)) - 10)
75 
76 #include "source.h"
77 #include "symbols.h"
78 #include <signal.h>
79 #include <sys/param.h>
80 #include <sys/dir.h>
81 #include <machine/psl.h>
82 #include <machine/pte.h>
83 #include <sys/user.h>
84 #undef DELETE /* XXX */
85 #include <sys/vm.h>
86 #include <machine/reg.h>
87 
88 Address pc;
89 Address prtaddr;
90 
91 #endif
92 
93 /*
94  * Indices into u. for use in collecting registers values.
95  */
96 public int rloc[] ={
97 #ifdef sun
98     R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5, AR6, AR7, PC
99 #else /* IRIS */
100     R0, R1, R2, R3, R4, R5, R6, R7, AR0, AR1, AR2, AR3, AR4, AR5, AR6, AR7, 16
101 #endif
102 };
103 
104 private Address printop();
105 
106 /*
107  * Decode and print the instructions within the given address range.
108  */
109 
110 public printinst(lowaddr, highaddr)
111 Address lowaddr;
112 Address highaddr;
113 {
114     register Address addr;
115 
116     for (addr = lowaddr; addr <= highaddr; ) {
117 	addr = printop(addr);
118     }
119     prtaddr = addr;
120 }
121 
122 /*
123  * Another approach:  print n instructions starting at the given address.
124  */
125 
126 public printninst(count, addr)
127 int count;
128 Address addr;
129 {
130     register Integer i;
131     register Address newaddr;
132 
133     if (count <= 0) {
134 	error("non-positive repetition count");
135     } else {
136 	newaddr = addr;
137 	for (i = 0; i < count; i++) {
138 	    newaddr = printop(newaddr);
139 	}
140 	prtaddr = newaddr;
141     }
142 }
143 
144 /*
145  * Print the contents of the addresses within the given range
146  * according to the given format.
147  */
148 
149 typedef struct {
150     String name;
151     String printfstring;
152     int length;
153 } Format;
154 
155 private Format fmt[] = {
156     { "d", " %d", sizeof(short) },
157     { "D", " %ld", sizeof(long) },
158     { "o", " %o", sizeof(short) },
159     { "O", " %lo", sizeof(long) },
160     { "x", " %04x", sizeof(short) },
161     { "X", " %08x", sizeof(long) },
162     { "b", " \\%o", sizeof(char) },
163     { "c", " '%c'", sizeof(char) },
164     { "s", "%c", sizeof(char) },
165     { "f", " %f", sizeof(float) },
166     { "g", " %g", sizeof(double) },
167     { nil, nil, 0 }
168 };
169 
170 private Format *findformat(s)
171 String s;
172 {
173     register Format *f;
174 
175     f = &fmt[0];
176     while (f->name != nil and not streq(f->name, s)) {
177 	++f;
178     }
179     if (f->name == nil) {
180 	error("bad print format \"%s\"", s);
181     }
182     return f;
183 }
184 
185 /*
186  * Retrieve and print out the appropriate data in the given format.
187  * Floats have to be handled specially to allow the compiler to
188  * convert them to doubles when passing to printf.
189  */
190 
191 private printformat (f, addr)
192 Format *f;
193 Address addr;
194 {
195     union {
196 	char charv;
197 	short shortv;
198 	int intv;
199 	float floatv;
200 	double doublev;
201     } value;
202 
203     value.intv = 0;
204     dread(&value, addr, f->length);
205     if (streq(f->name, "f")) {
206 	printf(f->printfstring, value.floatv);
207     } else {
208 	printf(f->printfstring, value);
209     }
210 }
211 
212 public Address printdata(lowaddr, highaddr, format)
213 Address lowaddr;
214 Address highaddr;
215 String format;
216 {
217     int n;
218     register Address addr;
219     Format *f;
220 
221     if (lowaddr > highaddr) {
222 	error("first address larger than second");
223     }
224     f = findformat(format);
225     n = 0;
226     for (addr = lowaddr; addr <= highaddr; addr += f->length) {
227 	if (n == 0) {
228 	    printf("%08x: ", addr);
229 	}
230 	printformat(f, addr);
231 	++n;
232 	if (n >= (16 div f->length)) {
233 	    printf("\n");
234 	    n = 0;
235 	}
236     }
237     if (n != 0) {
238 	printf("\n");
239     }
240     prtaddr = addr;
241     return addr;
242 }
243 
244 /*
245  * The other approach is to print n items starting with a given address.
246  */
247 
248 public printndata(count, startaddr, format)
249 int count;
250 Address startaddr;
251 String format;
252 {
253     int i, n;
254     Address addr;
255     Format *f;
256     Boolean isstring;
257     char c;
258 
259     if (count <= 0) {
260 	error("non-positive repetition count");
261     }
262     f = findformat(format);
263     isstring = (Boolean) streq(f->name, "s");
264     n = 0;
265     addr = startaddr;
266     for (i = 0; i < count; i++) {
267 	if (n == 0) {
268 	    printf("%08x: ", addr);
269 	}
270 	if (isstring) {
271 	    printf("\"");
272 	    dread(&c, addr, sizeof(char));
273 	    while (c != '\0') {
274 		printchar(c);
275 		++addr;
276 		dread(&c, addr, sizeof(char));
277 	    }
278 	    printf("\"\n");
279 	    n = 0;
280 	    addr += sizeof(String);
281 	} else {
282 	    printformat(f, addr);
283 	    ++n;
284 	    if (n >= (16 div f->length)) {
285 		printf("\n");
286 		n = 0;
287 	    }
288 	    addr += f->length;
289 	}
290     }
291     if (n != 0) {
292 	printf("\n");
293     }
294     prtaddr = addr;
295 }
296 
297 /*
298  * Print out a value according to the given format.
299  */
300 
301 public printvalue(v, format)
302 long v;
303 String format;
304 {
305     Format *f;
306     char *p, *q;
307 
308     f = findformat(format);
309     if (streq(f->name, "s")) {
310 	putchar('"');
311 	p = (char *) &v;
312 	q = p + sizeof(v);
313 	while (p < q) {
314 	    printchar(*p);
315 	    ++p;
316 	}
317 	putchar('"');
318     } else {
319 	printf(f->printfstring, v);
320     }
321     putchar('\n');
322 }
323 
324 /*
325  * Print out an execution time error.
326  * Assumes the source position of the error has been calculated.
327  *
328  * Have to check if the -r option was specified; if so then
329  * the object file information hasn't been read in yet.
330  */
331 
332 public printerror()
333 {
334     extern Integer sys_nsig;
335     extern String sys_siglist[];
336     integer err;
337 
338     if (isfinished(process)) {
339 	err = exitcode(process);
340 	if (err == 0) {
341 	    printf("\"%s\" terminated normally\n", objname);
342 	} else {
343 	    printf("\"%s\" terminated abnormally (exit code %d)\n",
344 		objname, err
345 	    );
346 	}
347 	erecover();
348     }
349     err = errnum(process);
350     putchar('\n');
351     printsig(err);
352     putchar(' ');
353     printloc();
354     putchar('\n');
355     if (curline > 0) {
356 	printlines(curline, curline);
357     } else {
358 	printinst(pc, pc);
359     }
360     erecover();
361 }
362 
363 /*
364  * Print out a signal.
365  */
366 
367 private String illinames[] = {
368     "reserved addressing fault",
369     "privileged instruction fault",
370     "reserved operand fault"
371 };
372 
373 private String fpenames[] = {
374     nil,
375     "integer overflow trap",
376     "integer divide by zero trap",
377     "floating overflow trap",
378     "floating/decimal divide by zero trap",
379     "floating underflow trap",
380     "decimal overflow trap",
381     "subscript out of range trap",
382     "floating overflow fault",
383     "floating divide by zero fault",
384     "floating underflow fault"
385 };
386 
387 public printsig (signo)
388 integer signo;
389 {
390     integer code;
391 
392     if (signo < 0 or signo > sys_nsig) {
393 	printf("[signal %d]", signo);
394     } else {
395 	printf("%s", sys_siglist[signo]);
396     }
397     code = errcode(process);
398     if (signo == SIGILL) {
399 	if (code >= 0 and code < sizeof(illinames) / sizeof(illinames[0])) {
400 	    printf(" (%s)", illinames[code]);
401 	}
402     } else if (signo == SIGFPE) {
403 	if (code > 0 and code < sizeof(fpenames) / sizeof(fpenames[0])) {
404 	    printf(" (%s)", fpenames[code]);
405 	}
406     }
407 }
408 
409 /*
410  * Note the termination of the program.  We do this so as to avoid
411  * having the process exit, which would make the values of variables
412  * inaccessible.  We do want to flush all output buffers here,
413  * otherwise it'll never get done.
414  */
415 
416 public endprogram()
417 {
418     Integer exitcode;
419 
420     stepto(nextaddr(pc, true));
421     printnews();
422     exitcode = argn(1, nil);
423     if (exitcode != 0) {
424 	printf("\nexecution completed (exit code %d)\n", exitcode);
425     } else {
426 	printf("\nexecution completed\n");
427     }
428     getsrcpos();
429     erecover();
430 }
431 
432 /*
433  * Single step the machine a source line (or instruction if "inst_tracing"
434  * is true).  If "isnext" is true, skip over procedure calls.
435  */
436 
437 private Address getcall();
438 
439 public dostep(isnext)
440 Boolean isnext;
441 {
442     register Address addr;
443     register Lineno line;
444     String filename;
445     Address startaddr;
446 
447     startaddr = pc;
448     addr = nextaddr(pc, isnext);
449     if (not inst_tracing and nlhdr.nlines != 0) {
450 	line = linelookup(addr);
451 	while (line == 0) {
452 	    addr = nextaddr(addr, isnext);
453 	    line = linelookup(addr);
454 	}
455 	curline = line;
456     } else {
457 	curline = 0;
458     }
459     stepto(addr);
460     filename = srcfilename(addr);
461     setsource(filename);
462 }
463 
464 typedef short Bpinst;
465 
466 extern Bpinst BP_OP;
467 #ifdef sun
468 	asm("_BP_OP: trap #15");
469 #else /* IRIS */
470 	asm("_BP_OP: trap #1");
471 #endif
472 
473 #define BP_ERRNO    SIGTRAP     /* signal received at a breakpoint */
474 
475 /*
476  * Setting a breakpoint at a location consists of saving
477  * the word at the location and poking a BP_OP there.
478  *
479  * We save the locations and words on a list for use in unsetting.
480  */
481 
482 typedef struct Savelist *Savelist;
483 
484 struct Savelist {
485     Address location;
486     Bpinst save;
487     short refcount;
488     Savelist link;
489 };
490 
491 private Savelist savelist;
492 
493 /*
494  * Set a breakpoint at the given address.  Only save the word there
495  * if it's not already a breakpoint.
496  */
497 
498 public setbp(addr)
499 Address addr;
500 {
501     Bpinst w, save;
502     register Savelist newsave, s;
503 
504     for (s = savelist; s != nil; s = s->link) {
505 	if (s->location == addr) {
506 	    s->refcount++;
507 	    return;
508 	}
509     }
510     iread(&save, addr, sizeof(save));
511     newsave = new(Savelist);
512     newsave->location = addr;
513     newsave->save = save;
514     newsave->refcount = 1;
515     newsave->link = savelist;
516     savelist = newsave;
517     w = BP_OP;
518     iwrite(&w, addr, sizeof(w));
519 }
520 
521 /*
522  * Unset a breakpoint; unfortunately we have to search the SAVELIST
523  * to find the saved value.  The assumption is that the SAVELIST will
524  * usually be quite small.
525  */
526 
527 public unsetbp(addr)
528 Address addr;
529 {
530     register Savelist s, prev;
531 
532     prev = nil;
533     for (s = savelist; s != nil; s = s->link) {
534 	if (s->location == addr) {
535 	    iwrite(&s->save, addr, sizeof(s->save));
536 	    s->refcount--;
537 	    if (s->refcount == 0) {
538 		if (prev == nil) {
539 		    savelist = s->link;
540 		} else {
541 		    prev->link = s->link;
542 		}
543 		dispose(s);
544 	    }
545 	    return;
546 	}
547 	prev = s;
548     }
549     panic("unsetbp: couldn't find address %d", addr);
550 }
551 
552 /*
553  * Instruction decoding routines for 68000, derived from adb.
554  *
555  * The shared boolean variable "printing" is true if the decoded
556  * instruction is to be printed, false if not.  In either case,
557  * the address of the next instruction after the given one is returned.
558  */
559 
560 private Boolean printing;
561 private Boolean following;
562 private Boolean followcalls;
563 private Address instaddr;
564 
565 #define instread(var) \
566 { \
567     iread(&var, instaddr, sizeof(var)); \
568     instaddr += sizeof(var); \
569 }
570 
571 private Optab *decode(inst, addr)
572 Word inst;
573 Address addr;
574 {
575     register Optab *o;
576 
577     o = &optab[0];
578     while (o->mask != 0 and (inst&o->mask) != o->match) {
579 	++o;
580     }
581     return o;
582 }
583 
584 private Address printop(addr)
585 Address addr;
586 {
587     Optab *o;
588     short inst;
589 
590     printf("%08x  ", addr);
591     iread(&inst, addr, sizeof(inst));
592     o = decode(inst, addr);
593     if (o->mask == 0) {
594 	printf("\tbadop");
595 	instaddr = addr + sizeof(inst);
596     } else {
597 	printing = true;
598 	following = false;
599 	instaddr = addr + sizeof(inst);
600 	(*o->opfun)(inst, o->farg);
601 	printing = false;
602     }
603     printf("\n");
604     return instaddr;
605 }
606 
607 /*
608  * Quickly find the return address of the current procedure or function
609  * while single stepping.  Just get the word pointed at by sp.
610  */
611 
612 private Address currtnaddr ()
613 {
614     Address retaddr;
615 
616     dread(&retaddr, reg(STKP), sizeof(retaddr));
617     return retaddr;
618 }
619 
620 /*
621  * Print out the effective address for the given parameters.
622  */
623 
624 private printea(mode, reg, size)
625 long mode, reg;
626 int size;
627 {
628     long index, disp;
629     static char *aregs[] = { "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp" };
630     Byte b;
631     short w;
632     long l;
633 
634     switch ((int)(mode)) {
635 	case 0:
636 	    if (printing) {
637 		printf("d%D", reg);
638 	    }
639 	    break;
640 
641 	case 1:
642 	    if (printing) {
643 		printf("%s", aregs[reg]);
644 	    }
645 	    break;
646 
647 	case 2:
648 	    if (printing) {
649 		printf("%s@", aregs[reg]);
650 	    }
651 	    break;
652 
653 	case 3:
654 	    if (printing) {
655 		printf("%s@+", aregs[reg]);
656 	    }
657 	    break;
658 
659 	case 4:
660 	    if (printing) {
661 		printf("%s@-", aregs[reg]);
662 	    }
663 	    break;
664 
665 	case 5:
666 	    instread(w);
667 	    if (printing) {
668 		printf("%s@(%D)", aregs[reg], w);
669 	    }
670 	    break;
671 
672 	case 6:
673 	    instread(w);
674 	    if (printing) {
675 		index = w;
676 		disp = (char)(index&0377);
677 		printf("%s@(%d,%c%D:%c)", aregs[reg], disp,
678 		    (index&0100000)?'a':'d',(index>>12)&07,
679 		    (index&04000)?'l':'w');
680 	    }
681 	    break;
682 
683 	case 7:
684 	    switch ((int)(reg)) {
685 		case 0:
686 		    instread(w);
687 		    if (printing) {
688 			index = w;
689 			psymoff(index);
690 		    }
691 		    break;
692 
693 		case 1:
694 		    instread(l);
695 		    if (printing) {
696 			index = l;
697 			psymoff(index);
698 		    }
699 		    break;
700 
701 		case 2:
702 		    instread(w);
703 		    if (printing) {
704 			disp = w;
705 			psymoff(disp + instaddr);
706 		    }
707 		    break;
708 
709 		case 3:
710 		    instread(w);
711 		    if (printing) {
712 			index = w;
713 			disp = (char)(index&0377);
714 			printf("pc@(%D,%c%D:%c)", disp,
715 			    (index&0100000)?'a':'d',(index>>12)&07,
716 			    (index&04000)?'l':'w');
717 		    }
718 		    break;
719 
720 		case 4:
721 		    switch (size) {
722 			case sizeof(b):
723 			    instread(w);
724 			    index = (w&0xff);
725 			    break;
726 
727 			case sizeof(w):
728 			    instread(w);
729 			    index = w;
730 			    break;
731 
732 			case sizeof(l):
733 			    instread(l);
734 			    index = l;
735 			    break;
736 
737 			default:
738 			    if (printing) {
739 			    	printf("unexpected size %d in printea\n", size);
740 			    }
741 			    instread(l);
742 			    index = l;
743 			    break;
744 		    }
745 		    if (printing) {
746 			printf(IMDF, index);
747 		    }
748 		    break;
749 
750 		default:
751 		    if (printing) {
752 			printf("???");
753 		    }
754 		    break;
755 	    }
756 	    break;
757 
758 	default:
759 	    if (printing) {
760 		printf("???");
761 	    }
762 	    break;
763     }
764 }
765 
766 private printEA(ea, size)
767 long ea;
768 int size;
769 {
770     printea((ea>>3)&07, ea&07, size);
771 }
772 
773 private mapsize(inst)
774 register long inst;
775 {
776     int m;
777 
778     inst >>= 6;
779     inst &= 03;
780     switch (inst) {
781 	case 0:
782 	    m = 1;
783 	    break;
784 
785 	case 1:
786 	    m = 2;
787 	    break;
788 
789 	case 2:
790 	    m = 4;
791 	    break;
792 
793 	default:
794 	    m = -1;
795 	    break;
796     }
797     return m;
798 }
799 
800 private char suffix(size)
801 int size;
802 {
803     char c;
804 
805     switch (size) {
806 	case 1:
807 	    c = 'b';
808 	    break;
809 
810 	case 2:
811 	    c = 'w';
812 	    break;
813 
814 	case 4:
815 	    c = 'l';
816 	    break;
817 
818 	default:
819 	    panic("bad size %d in suffix", size);
820     }
821     return c;
822 }
823 
824 /*
825  * Print an address offset.  Eventually this should attempt to be symbolic,
826  * but for now its just printed in hex.
827  */
828 
829 private psymoff (off)
830 Word off;
831 {
832     Symbol f;
833 
834     f = whatblock((Address) (off + FUNCOFFSET));
835     if (codeloc(f) == off + FUNCOFFSET) {
836 	printf("%s", symname(f));
837     } else {
838 	printf("0x%x", off);
839     }
840 }
841 
842 /*
843  * Instruction class specific routines.
844  */
845 
846 public omove(inst, s)
847 long inst;
848 String s;
849 {
850     register int c;
851     int size;
852 
853     c = s[0];
854     if (printing) {
855 	printf("\tmov%c\t", c);
856     }
857     size = ((c == 'b') ? 1 : (c == 'w') ? 2 : 4);
858     printea((inst>>3)&07, inst&07, size);
859     if (printing) {
860 	printf(",");
861     }
862     printea((inst>>6)&07, (inst>>9)&07, size);
863 }
864 
865 /*
866  * Two types: bsr (4 bytes) and bsrs (2 bytes)
867  */
868 
869 public obranch(inst, dummy)
870 long inst;
871 {
872     long disp;
873     String s;
874     short w;
875     Address startingaddr;	/* address of branch instruction */
876     int branchtype;		/* type of branch (0 = unconditional) */
877     Address dest;
878     Address retaddr;		/* for bsr instruction */
879 
880     startingaddr = instaddr - 2;
881     disp = inst&0377;
882     s = "s ";
883     if (disp == 0) {
884 	retaddr = startingaddr + 4;
885     } else {
886 	retaddr = startingaddr + 2;
887     }
888     if (disp > 127) {
889 	disp |= ~0377;
890     } else if (disp == 0){
891 	s = " ";
892 	instread(w);
893 	disp = w;
894     }
895     branchtype = (int)((inst>>8)&017);
896     dest = startingaddr + 2 + disp;
897     if (printing) {
898 	printf("\tb%s%s\t", bname[branchtype], s);
899 	psymoff(dest);
900     }
901     if (following) {
902 	/*
903 	 * If we're to follow the dynamic flow of instructions,
904 	 * we must see where the branch leads.  A branchtype of 0
905 	 * indicates an unconditional branch which we simply take
906 	 * as the new instruction address.  For a conditional branch,
907 	 * we continue execution up to the current address, single step,
908 	 * and keep going.
909 	 */
910 	if (branchtype == 0) {
911 	    instaddr = dest;
912 	} else if (branchtype == 01) {		/* bsr */
913 	    if (followcalls) {
914 		steppast(startingaddr);
915 		curfunc = whatblock(pc, true);
916 		if (not isbperr()) {
917 		    printstatus();
918 		    /* NOTREACHED */
919 		}
920 		bpact();
921 		if (nosource(curfunc) and canskip(curfunc) and
922 		  nlhdr.nlines != 0) {
923 		    stepto(retaddr);
924 		    instaddr = pc;
925 		    bpact();
926 		} else {
927 		    callnews(/* iscall = */ true);
928 		}
929 	    }
930 	} else {
931 	    steppast(startingaddr);
932 	}
933     }
934 }
935 
936 public odbcc(inst, form)
937 long inst;
938 String form;
939 {
940     long disp;
941     short w;
942 
943     instread(w);
944     if (printing) {
945     	printf(form, dbname[(int)((inst>>8)&017)], inst&07);
946 	psymoff(w + sizeof(w));
947     }
948 }
949 
950 public oscc(inst, dummy)
951 long inst;
952 long dummy;
953 {
954     if (printing) {
955 	printf("\ts%s\t", cname[(int)((inst>>8)&017)]);
956     }
957     printea((inst>>3)&07, inst&07, 1);
958 }
959 
960 public biti(inst, dummy)
961 long inst;
962 long dummy;
963 {
964     short w;
965 
966     if (printing) {
967 	printf("\t%s\t", bit[(int)((inst>>6)&03)]);
968     }
969     if (inst&0x0100) {
970 	if (printing) {
971 	    printf("d%D,", inst>>9);
972 	}
973     } else {
974 	instread(w);
975 	if (printing) {
976 	    printf(IMDF, w);
977 	    printf(",");
978 	}
979     }
980     printEA(inst);
981 }
982 
983 public opmode(inst, opcode)
984 long inst;
985 long opcode;
986 {
987     register int opmode;
988     register int reg;
989     int size;
990 
991     opmode = (int)((inst>>6) & 07);
992     reg = (int)((inst>>9) & 07);
993     if (opmode == 0 or opmode == 4) {
994 	size = 1;
995     } else if (opmode == 1 or opmode == 3 or opmode == 5) {
996 	size = 2;
997     } else {
998 	size = 4;
999     }
1000     if (printing) {
1001 	printf("\t%s%c\t", opcode, suffix(size));
1002     }
1003     if (opmode >= 4 and opmode <= 6) {
1004 	if (printing) {
1005 	    printf("d%d,", reg);
1006 	}
1007 	printea((inst>>3)&07, inst&07, size);
1008     } else {
1009 	printea((inst>>3)&07, inst&07, size);
1010 	if (printing) {
1011 	    printf(",%c%d",(opmode<=2) ? 'd' : 'a', reg);
1012 	}
1013     }
1014 }
1015 
1016 public shroi(inst, ds)
1017 long inst;
1018 String ds;
1019 {
1020     int rx, ry;
1021     String opcode;
1022 
1023     if ((inst & 0xC0) == 0xC0) {
1024 	opcode = shro[(int)((inst>>9)&03)];
1025 	if (printing) {
1026 	    printf("\t%s%s\t", opcode, ds);
1027 	}
1028 	printEA(inst);
1029     } else {
1030 	if (printing) {
1031 	    opcode = shro[(int)((inst>>3)&03)];
1032 	    printf("\t%s%s%c\t", opcode, ds, suffix(mapsize(inst)));
1033 	    rx = (int)((inst>>9)&07); ry = (int)(inst&07);
1034 	    if ((inst>>5)&01) {
1035 		printf("d%d,d%d", rx, ry);
1036 	    } else {
1037 		printf(IMDF, (rx ? rx : 8));
1038 		printf(",d%d", ry);
1039 	    }
1040 	}
1041     }
1042 }
1043 
1044 public oimmed(inst, opcode)
1045 long inst;
1046 register String opcode;
1047 {
1048     register int size;
1049     long const;
1050     short w;
1051 
1052     size = mapsize(inst);
1053     if (size > 0) {
1054 	if (size == 4) {
1055 	    instread(const);
1056 	} else {
1057 	    instread(w);
1058 	    const = w;
1059 	}
1060 	if (printing) {
1061 	    printf("\t%s%c\t", opcode, suffix(size));
1062 	    printf(IMDF, const);
1063 	    printf(",");
1064 	}
1065 	printEA(inst, size);
1066     } else {
1067 	if (printing) {
1068 	    printf("\tbadop");
1069 	}
1070     }
1071 }
1072 
1073 public oreg(inst, opcode)
1074 long inst;
1075 register String opcode;
1076 {
1077     if (printing) {
1078 	printf(opcode, (inst & 07));
1079     }
1080 }
1081 
1082 public extend(inst, opcode)
1083 long inst;
1084 String opcode;
1085 {
1086     register int size;
1087     int ry, rx;
1088     char c;
1089 
1090     if (printing) {
1091 	size = mapsize(inst);
1092 	ry = (inst&07);
1093 	rx = ((inst>>9)&07);
1094 	c = ((inst & 0x1000) ? suffix(size) : ' ');
1095 	printf("\t%s%c\t", opcode, c);
1096 	if (opcode[0] == 'e') {
1097 	    if (inst & 0x0080) {
1098 		printf("d%D,a%D", rx, ry);
1099 	    } else if (inst & 0x0008) {
1100 		printf("a%D,a%D", rx, ry);
1101 	    } else {
1102 		printf("d%D,d%D", rx, ry);
1103 	    }
1104 	} else if ((inst & 0xF000) == 0xB000) {
1105 	    printf("a%D@+,a%D@+", ry, rx);
1106 	} else if (inst & 0x8) {
1107 	    printf("a%D@-,a%D@-", ry, rx);
1108 	} else {
1109 	    printf("d%D,d%D", ry, rx);
1110 	}
1111     }
1112 }
1113 
1114 public olink(inst, dummy)
1115 long inst;
1116 long dummy;
1117 {
1118     short w;
1119 
1120     instread(w);
1121     if (printing) {
1122 	printf("\tlink\ta%D,", inst&07);
1123 	printf(IMDF, w);
1124     }
1125 }
1126 
1127 public otrap(inst, dummy)
1128 long inst;
1129 {
1130     if (printing) {
1131 	printf("\ttrap\t");
1132 	printf(IMDF, inst&017);
1133     }
1134 }
1135 
1136 public oneop(inst, opcode)
1137 long inst;
1138 register String opcode;
1139 {
1140     if (printing) {
1141 	printf("\t%s",opcode);
1142     }
1143     printEA(inst);
1144 }
1145 
1146 public jsrop(inst, opcode)
1147 long inst;
1148 register String opcode;
1149 {
1150     Address startingaddr;	/* beginning of jsr instruction */
1151     Address retaddr; /* can't call return_addr (frame not set up yet) */
1152 
1153     startingaddr = instaddr - 2;
1154     switch ((inst >> 3) & 07) {
1155 	case 2:
1156 	    retaddr = instaddr;		/* two byte instruction */
1157 	    break;
1158 	case 5:
1159 	case 6:
1160 	    retaddr = instaddr + 2;	/* four byte instruction */
1161 	    break;
1162 	case 7:
1163 	default:
1164 	    switch (inst & 07) {
1165 		case 0:
1166 		case 2:
1167 		case 3:
1168 		    retaddr = instaddr + 2;
1169 		    break;
1170 		case 1:
1171 		default:
1172 		    retaddr = instaddr + 4;	/* six byte instruction */
1173 		    break;
1174 	    }
1175 	    break;
1176     }
1177     if (printing) {
1178 	printf("\t%s",opcode);
1179     }
1180     printEA(inst);
1181     if (following and followcalls) {
1182 	steppast(startingaddr);
1183 	curfunc = whatblock(pc, true);
1184 	if (not isbperr()) {
1185 	    printstatus();
1186 	    /* NOTREACHED */
1187 	}
1188 	bpact();
1189 	if (nosource(curfunc) and canskip(curfunc) and nlhdr.nlines != 0) {
1190 	    stepto(retaddr);
1191 	    instaddr = pc;
1192 	    bpact();
1193 	} else {
1194 	    callnews(/* iscall = */ true);
1195 	}
1196     }
1197 }
1198 
1199 public jmpop(inst, opcode)
1200 long inst;
1201 register String opcode;
1202 {
1203     Address startingaddr;	/* beginning of jump instruction */
1204 
1205     startingaddr = instaddr - 2;
1206     if (printing) {
1207 	printf("\t%s",opcode);
1208     }
1209     printEA(inst);
1210     if (following) {
1211 	steppast(startingaddr);
1212     }
1213 }
1214 
1215 public pregmask(mask)
1216 register int mask;
1217 {
1218     register int i;
1219     register int flag = 0;
1220 
1221     if (printing) {
1222 	printf("#<");
1223 	for (i=0; i<16; i++) {
1224 	    if (mask&1) {
1225 		if (flag) {
1226 		    printf(",");
1227 		} else {
1228 		    ++flag;
1229 		}
1230 		printf("%c%d",(i<8) ? 'd' : 'a', i&07);
1231 	    }
1232 	    mask >>= 1;
1233 	}
1234 	printf(">");
1235     }
1236 }
1237 
1238 public omovem(inst, dummy)
1239 long inst;
1240 long dummy;
1241 {
1242     register int i, list, mask;
1243     register int reglist;
1244     short w;
1245 
1246     i = 0;
1247     list = 0;
1248     mask = 0100000;
1249     instread(w);
1250     reglist = w;
1251     if ((inst & 070) == 040) {	/* predecrement */
1252 	for (i = 15; i > 0; i -= 2) {
1253 	    list |= ((mask & reglist) >> i);
1254 	    mask >>= 1;
1255 	}
1256 	for (i = 1; i < 16; i += 2) {
1257 	    list |= ((mask & reglist) << i);
1258 	    mask >>= 1;
1259 	}
1260 	reglist = list;
1261     }
1262     if (printing) {
1263 	printf("\tmovem%c\t",(inst&100)?'l':'w');
1264     }
1265     if (inst&02000) {
1266 	printEA(inst);
1267 	if (printing) {
1268 	    printf(",");
1269 	}
1270 	pregmask(reglist);
1271     } else {
1272 	pregmask(reglist);
1273 	if (printing) {
1274 	    printf(",");
1275 	}
1276 	printEA(inst);
1277     }
1278 }
1279 
1280 public ochk(inst, opcode)
1281 long inst;
1282 register String opcode;
1283 {
1284     if (printing) {
1285 	printf("\t%s\t", opcode);
1286     }
1287     printEA(inst, sizeof(Byte));
1288     if (printing) {
1289 	printf(",%c%D", (opcode[0] == 'l') ? 'a' : 'd', (inst>>9)&07);
1290     }
1291 }
1292 
1293 public soneop(inst, opcode)
1294 long inst;
1295 register String opcode;
1296 {
1297     register int size;
1298 
1299     size = mapsize(inst);
1300     if (size > 0) {
1301 	if (printing) {
1302 	    printf("\t%s%c\t", opcode, suffix(size));
1303 	}
1304 	printEA(inst);
1305     } else {
1306 	if (printing) {
1307 	    printf("\tbadop");
1308 	}
1309     }
1310 }
1311 
1312 public oquick(inst, opcode)
1313 long inst;
1314 register String opcode;
1315 {
1316     register int size;
1317     register int data;
1318 
1319     size = mapsize(inst);
1320     data = (int)((inst>>9) & 07);
1321     if (data == 0) {
1322 	data = 8;
1323     }
1324     if (size > 0) {
1325 	if (printing) {
1326 	    printf("\t%s%c\t", opcode, suffix(size));
1327 	    printf(IMDF, data);
1328 	    printf(",");
1329 	}
1330 	printEA(inst);
1331     } else {
1332 	if (printing) {
1333 	    printf("\tbadop");
1334 	}
1335     }
1336 }
1337 
1338 public omoveq(inst, dummy)
1339 long inst;
1340 long dummy;
1341 {
1342     register int data;
1343 
1344     if (printing) {
1345 	data = (int)(inst & 0377);
1346 	if (data > 127) {
1347 	    data |= ~0377;
1348 	}
1349 	printf("\tmoveq\t");
1350 	printf(IMDF, data);
1351 	printf(",d%D", (inst>>9)&07);
1352     }
1353 }
1354 
1355 public oprint(inst, opcode)
1356 long inst;
1357 register String opcode;
1358 {
1359     if (printing) {
1360 	printf("\t%s",opcode);
1361     }
1362 }
1363 
1364 public ostop(inst, opcode)
1365 long inst;
1366 register String opcode;
1367 {
1368     short w;
1369 
1370     instread(w);
1371     if (printing) {
1372 	printf(opcode, w);
1373     }
1374 }
1375 
1376 public orts(inst, opcode)
1377 long inst;
1378 register String opcode;
1379 {
1380     Address addr;
1381 
1382     if (following) {
1383 	callnews(/* iscall = */ false);
1384     	if (inst_tracing) {
1385 	    addr = currtnaddr();
1386     	} else {
1387 	    addr = return_addr();
1388 	    if (addr == 0) {
1389 		stepto(instaddr - 2);
1390 		addr = currtnaddr();
1391 	    }
1392 	}
1393 	stepto(addr);
1394 	instaddr = pc;
1395     }
1396     if (printing) {
1397 	printf("\t%s",opcode);
1398     }
1399 }
1400 
1401 /*
1402  * Not used by C compiler; does an rts but before doing so, pops
1403  * arg bytes from the stack.
1404  */
1405 
1406 public ortspop(inst, opcode)
1407 long inst;
1408 register String opcode;
1409 {
1410     Address addr;
1411     short w;
1412 
1413     instread(w);
1414     if (following) {
1415 	callnews(/* iscall = */ false);
1416     	if (inst_tracing) {
1417 	    addr = currtnaddr();
1418     	} else {
1419 	    addr = return_addr();
1420 	}
1421 	stepto(addr);
1422 	instaddr = pc;
1423     }
1424     if (printing) {
1425 	printf(opcode, w);
1426     }
1427 }
1428 
1429 public omovs(inst, opcode)
1430 long inst;
1431 String opcode;
1432 {
1433     register int size;
1434     register unsigned int controlword;
1435     short w;
1436 
1437     size = mapsize(inst);
1438     instread(w);
1439     controlword = w >> 11;
1440     if (printing) {
1441 	printf("\t%s%c\t", opcode, suffix(size));
1442     }
1443     if (controlword & 1){
1444 	controlword >>= 1;
1445 	if (printing) {
1446 	    printf((controlword&0x8) ? "a%D," : "d%D,", controlword&7 );
1447 	}
1448 	printEA(inst&0xff, size);
1449     } else {
1450 	controlword >>= 1;
1451 	printEA(inst&0xff, size);
1452 	if (printing) {
1453 	    printf((controlword&0x8) ? ",a%D" : ",d%D", controlword&7);
1454 	}
1455     }
1456 }
1457 
1458 public omovc(inst, opcode)
1459 long inst;
1460 String opcode;
1461 {
1462     register unsigned int controlword;
1463     String creg;
1464     short w;
1465 
1466     instread(w);
1467     if (printing) {
1468 	controlword = w;
1469 	switch (controlword & 0xfff) {
1470 	    case 0:
1471 		creg = "sfc";
1472 		break;
1473 
1474 	    case 1:
1475 		creg = "dfc";
1476 		break;
1477 
1478 	    case 0x800:
1479 		creg = "usp";
1480 		break;
1481 
1482 	    case 0x801:
1483 		creg = "vbr";
1484 		break;
1485 
1486 	    default:
1487 		creg = "???";
1488 		break;
1489 	}
1490 	controlword >>= 12;
1491 	if (inst & 1){
1492 	    printf((controlword&0x8) ? "%sa%D,%s" : "%sd%D,%s",
1493 		opcode, controlword&7, creg );
1494 	} else {
1495 	    printf((controlword&0x8) ? "%s%s,a%D" : "%s%s,d%D",
1496 		opcode, creg, controlword&7 );
1497 	}
1498     }
1499 }
1500 
1501 /*
1502  * Compute the next address that will be executed from the given one.
1503  * If "isnext" is true then consider a procedure call as straight line code.
1504  *
1505  * Unconditional branches we just follow, for conditional branches
1506  * we continue execution to the current location and then single step
1507  * the machine.
1508  */
1509 
1510 public Address nextaddr(startaddr, isnext)
1511 Address startaddr;
1512 Boolean isnext;
1513 {
1514     Optab *o;
1515     short inst;
1516 
1517     instaddr = usignal(process);
1518     if (instaddr == 0 or instaddr == 1) {
1519 	following = true;
1520 	followcalls = (Boolean) (not isnext);
1521 	printing = false;
1522 	iread(&inst, startaddr, sizeof(inst));
1523 	instaddr = startaddr + sizeof(inst);
1524 	o = decode(inst, startaddr);
1525 	if (o->mask == 0) {
1526 	    fprintf(stderr,
1527 		"[internal error: undecodable op at 0x%x]\n", startaddr);
1528 	    fflush(stderr);
1529 	} else {
1530 	    (*o->opfun)(inst, o->farg);
1531 	}
1532 	following = false;
1533     }
1534     return instaddr;
1535 }
1536 
1537 /*
1538  * Step to the given address and then execute one instruction past it.
1539  * Set instaddr to the new instruction address.
1540  */
1541 
1542 private steppast(addr)
1543 Address addr;
1544 {
1545     stepto(addr);
1546     pstep(process, DEFSIG);
1547     pc = reg(PROGCTR);
1548     instaddr = pc;
1549 }
1550 
1551 /*
1552  * Enter a procedure by creating and executing a call instruction.
1553  */
1554 
1555 #define CALLSIZE 6	/* size of call instruction */
1556 
1557 public beginproc(p)
1558 Symbol p;
1559 {
1560     char save[CALLSIZE];
1561     struct {
1562 	short op;
1563 	char addr[sizeof(long)];	/* unaligned long */
1564     } call;
1565     long dest;
1566 
1567     pc = CODESTART + 6;
1568     iread(save, pc, sizeof(save));
1569     call.op = 0x4eb9;			/* jsr */
1570     dest = codeloc(p) - FUNCOFFSET;
1571     mov(&dest, call.addr, sizeof(call.addr));
1572     iwrite(&call, pc, sizeof(call));
1573     setreg(PROGCTR, pc);
1574     pstep(process, DEFSIG);
1575     iwrite(save, pc, sizeof(save));
1576     pc = reg(PROGCTR);
1577     if (not isbperr()) {
1578 	printstatus();
1579     }
1580     /*
1581      * Execute link instruction so the return addr is visible.
1582      */
1583     pstep(process, DEFSIG);
1584     pc = reg(PROGCTR);
1585     if (not isbperr()) {
1586 	printstatus();
1587     }
1588 }
1589 
1590 /*
1591  * Special variables for debugging the kernel.
1592  */
1593 
1594 public integer masterpcbb;
1595 public integer slr;
1596 public struct pte *sbr;
1597 private struct pcb pcb;
1598 
1599 public getpcb ()
1600 {
1601     integer i;
1602 
1603     fseek(corefile, masterpcbb & ~0x80000000, 0);
1604     get(corefile, pcb);
1605     pcb.pcb_p0lr &= ~AST_CLR;
1606     printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n",
1607 	pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr
1608     );
1609 #   ifdef sun
1610     for (i = 0; i < 14; i++) {
1611 	setreg(i, pcb.pcb_regs.val[i]);
1612     }
1613 #   else /* IRIS */
1614     for (i = 0; i < 14; i++) {
1615 	setreg(i, pcb.pcb_regs[i]);
1616     }
1617 #   endif
1618 }
1619 
1620 public copyregs (savreg, reg)
1621 Word savreg[], reg[];
1622 {
1623     reg[0] = savreg[R0];
1624     reg[1] = savreg[R1];
1625     reg[2] = savreg[R2];
1626     reg[3] = savreg[R3];
1627     reg[4] = savreg[R4];
1628     reg[5] = savreg[R5];
1629     reg[6] = savreg[R6];
1630     reg[7] = savreg[R7];
1631     reg[8] = savreg[AR0];
1632     reg[9] = savreg[AR1];
1633     reg[10] = savreg[AR2];
1634     reg[11] = savreg[AR3];
1635     reg[12] = savreg[AR4];
1636     reg[13] = savreg[AR5];
1637     reg[14] = savreg[AR6];
1638     reg[15] = savreg[AR7];
1639     reg[PROGCTR] = savreg[PC];
1640 }
1641 
1642 /*
1643  * Map a virtual address to a physical address.
1644  * XXX THIS CAN'T BE RIGHT... XXX
1645  */
1646 
1647 public Address vmap (addr)
1648 Address addr;
1649 {
1650     Address r;
1651     integer v, n;
1652     struct pte pte;
1653 
1654     r = addr & ~0xc0000000;
1655     v = btop(r);
1656     switch (addr&0xc0000000) {
1657 	case 0xc0000000:
1658 	case 0x80000000:
1659 	    /*
1660 	     * In system space, so get system pte.
1661 	     * If it is valid or reclaimable then the physical address
1662 	     * is the combination of its page number and the page offset
1663 	     * of the original address.
1664 	     */
1665 	    if (v >= slr) {
1666 		error("address %x out of segment", addr);
1667 	    }
1668 	    r = ((long) (sbr + v)) & ~0x80000000;
1669 	    goto simple;
1670 
1671 	case 0x40000000:
1672 	    /*
1673 	     * In p1 space, must not be in shadow region.
1674 	     */
1675 	    if (v < pcb.pcb_p1lr) {
1676 		error("address %x out of segment", addr);
1677 	    }
1678 	    r = (Address) (pcb.pcb_p1br + v);
1679 	    break;
1680 
1681 	case 0x00000000:
1682 	    /*
1683 	     * In p0 space, must not be off end of region.
1684 	     */
1685 	    if (v >= pcb.pcb_p0lr) {
1686 		error("address %x out of segment", addr);
1687 	    }
1688 	    r = (Address) (pcb.pcb_p0br + v);
1689 	    break;
1690 
1691 	default:
1692 	    /* do nothing */
1693 	    break;
1694     }
1695     /*
1696      * For p0/p1 address, user-level page table should be in
1697      * kernel virtual memory.  Do second-level indirect by recursing.
1698      */
1699     if ((r & 0x80000000) == 0) {
1700 	error("bad p0br or p1br in pcb");
1701     }
1702     r = vmap(r);
1703 simple:
1704     /*
1705      * "r" is now the address of the pte of the page
1706      * we are interested in; get the pte and paste up the physical address.
1707      */
1708     fseek(corefile, r, 0);
1709     n = fread(&pte, sizeof(pte), 1, corefile);
1710     if (n != 1) {
1711 	error("page table botch (fread at %x returns %d)", r, n);
1712     }
1713     if (pte.pg_v == 0 and (pte.pg_fod != 0 or pte.pg_pfnum == 0)) {
1714 	error("page no valid or reclamable");
1715     }
1716     return (addr&PGOFSET) + ((Address) ptob(pte.pg_pfnum));
1717 }
1718 
1719 /*
1720  * Extract a bit field from an integer.
1721  */
1722 
1723 public integer extractField (s)
1724 Symbol s;
1725 {
1726     integer nbytes, nbits, n, r, off, len;
1727 
1728     off = s->symvalue.field.offset;
1729     len = s->symvalue.field.length;
1730     nbytes = size(s);
1731     n = 0;
1732     if (nbytes > sizeof(n)) {
1733 	printf("[bad size in extractField -- word assumed]\n");
1734 	nbytes = sizeof(n);
1735     }
1736     popn(nbytes, ((char *) &n) + (sizeof(Word) - nbytes));
1737     nbits = nbytes * BITSPERBYTE;
1738     r = n >> (nbits - ((off mod nbits) + len));
1739     r &= ((1 << len) - 1);
1740     return r;
1741 }
1742 
1743 /*
1744  * Change the length of a value in memory according to a given difference
1745  * in the lengths of its new and old types.
1746  */
1747 
1748 public loophole (oldlen, newlen)
1749 integer oldlen, newlen;
1750 {
1751     integer i, n;
1752     Stack *oldsp;
1753 
1754     n = newlen - oldlen;
1755     oldsp = sp - oldlen;
1756     if (n > 0) {
1757 	for (i = oldlen - 1; i >= 0; i--) {
1758 	    oldsp[n + i] = oldsp[i];
1759 	}
1760 	for (i = 0; i < n; i++) {
1761 	    oldsp[i] = '\0';
1762 	}
1763     } else {
1764 	for (i = 0; i < newlen; i++) {
1765 	    oldsp[i] = oldsp[i - n];
1766 	}
1767     }
1768     sp += n;
1769 }
1770