summaryrefslogtreecommitdiff
path: root/sys/arch/mvme88k/ddb
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 10:54:29 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1995-10-18 10:54:29 +0000
commitebb22450a0f6bd0357a6727bae293b3ed7a8d5e2 (patch)
tree03ceebb5ca61ef2d13f65051a6c5222e92816689 /sys/arch/mvme88k/ddb
parent77b048c5ca1ef345d036f981ff0b954c647efd7a (diff)
initial 88k import; code by nivas and based on mach luna88k
Diffstat (limited to 'sys/arch/mvme88k/ddb')
-rw-r--r--sys/arch/mvme88k/ddb/db_disasm.c777
-rw-r--r--sys/arch/mvme88k/ddb/db_interface.c834
-rw-r--r--sys/arch/mvme88k/ddb/db_sstep.c256
-rw-r--r--sys/arch/mvme88k/ddb/db_trace.c1221
4 files changed, 3088 insertions, 0 deletions
diff --git a/sys/arch/mvme88k/ddb/db_disasm.c b/sys/arch/mvme88k/ddb/db_disasm.c
new file mode 100644
index 00000000000..17733167572
--- /dev/null
+++ b/sys/arch/mvme88k/ddb/db_disasm.c
@@ -0,0 +1,777 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * m88k disassembler for use in ddb
+ */
+
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h> /* DB_STGY_PROC, db_printsym() */
+#include <ddb/db_access.h> /* db_get_value() */
+#include <ddb/db_output.h> /* db_printf() */
+
+static char *instwidth[4] = {
+ ".d", " ", ".h", ".b"
+};
+
+static char *condname[6] = {
+ "gt0 ", "eq0 ", "ge0 ", "lt0 ", "ne0 ", "le0 "
+};
+
+static char *ctrlreg[64] = {
+ "cr0(PID) ",
+ "cr1(PSR) ",
+ "cr2(EPSR) ",
+ "cr3(SSBR) ",
+ "cr4(SXIP) ",
+ "cr5(SNIP) ",
+ "cr6(SFIP) ",
+ "cr7(VBR) ",
+ "cr8(DMT0) ",
+ "cr9(DMD0) ",
+ "cr10(DMA0) ",
+ "cr11(DMT1) ",
+ "cr12(DMD1) ",
+ "cr13(DMA1) ",
+ "cr14(DMT2) ",
+ "cr15(DMD2) ",
+ "cr16(DMA2) ",
+ "cr17(SR0) ",
+ "cr18(SR1) ",
+ "cr19(SR2) ",
+ "cr20(SR3) ",
+ "fcr0(FPECR)",
+ "fcr1(FPHS1)",
+ "fcr2(FPLS1)",
+ "fcr3(FPHS2)",
+ "fcr4(FPLS2)",
+ "fcr5(FPPT) ",
+ "fcr6(FPRH) ",
+ "fcr7(FPRL) ",
+ "fcr8(FPIT) ",
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ "fcr62(FPSR)",
+ "fcr63(FPCR)"
+};
+#define printval(x) if (x<0) db_printf ("-0x%X", -x); else db_printf("0x%X",x)
+
+/* Handlers immediate integer arithmetic instructions */
+static void
+oimmed(long inst, char *opcode, long iadr)
+{
+ register int Linst = inst & 0177777;
+ register int Hinst = inst >> 16;
+ register int H6inst = Hinst >> 10;
+ register int rs1 = Hinst & 037;
+ register int rd = (Hinst >> 5) & 037;
+
+ if ((H6inst > 017) && (H6inst < 030) && (H6inst & 01) == 1)
+ db_printf("\t%s.u", opcode);
+ else {
+ db_printf("\t%s", opcode);
+ db_printf(" ");
+ }
+ db_printf("\t\tr%-3d,r%-3d,", rd, rs1);
+ printval(Linst);
+}
+
+
+/* Handles instructions dealing with control registers */
+static void
+ctrlregs(long inst, char *opcode, long iadr)
+{
+ register int L6inst = (inst >> 11) & 037;
+ register int creg = (inst >> 5) & 077;
+ register int rd = (inst >> 21) & 037;
+ register int rs1 = (inst >> 16) & 037;
+
+ db_printf("\t%s", opcode);
+
+ if (L6inst == 010 || L6inst == 011)
+ db_printf("\t\tr%-3d,%s", rd, ctrlreg[creg]);
+ else
+ if (L6inst == 020 || L6inst == 021)
+ db_printf("\t\tr%-3d,%s", rs1, ctrlreg[creg]);
+ else
+ db_printf("\t\tr%-3d,r%-3d,%s", rd, rs1, ctrlreg[creg]);
+}
+
+
+static void
+printsod(int t)
+{
+ if (t == 0)
+ db_printf("s");
+ else
+ db_printf("d");
+}
+/* Handles floating point instructions */
+static void
+sindou(int inst, char *opcode, long iadr)
+{
+ register int rs2 = inst & 037;
+ register int td = (inst >> 5) & 03;
+ register int t2 = (inst >> 7) & 03;
+ register int t1 = (inst >> 9) & 03;
+ register int rs1 = (inst >> 16) & 037;
+ register int rd = (inst >> 21) & 037;
+ register int checkbits = (inst >> 11) & 037;
+
+ db_printf("\t%s.", opcode);
+ printsod(td);
+ if ((checkbits > 010 && checkbits < 014) || (checkbits == 04)) {
+ printsod(t2);
+ db_printf(" ");
+ if (checkbits == 012 || checkbits == 013)
+ db_printf("\t\tr%-3d,r%-3d", rd, rs2);
+ else
+ db_printf("\t\tr%-3d,r%-3d", rd, rs2);
+ } else {
+ printsod(t1);
+ printsod(t2);
+ db_printf("\t\tr%-3d,r%-3d,r%-3d", rd, rs1, rs2);
+ }
+}
+
+
+static void
+jump(long inst, char *opcode, long iadr)
+{
+ register int rs2 = inst & 037;
+ register int Nbit = (inst >> 10) & 01;
+
+ db_printf("\t%s", opcode);
+ if (Nbit == 1)
+ db_printf(".n");
+ else
+ db_printf(" ");
+ db_printf("\t\tr%-3d", rs2);
+}
+
+
+/* Handles ff1, ff0, tbnd and rte instructions */
+static void
+instset(long inst, char *opcode, long iadr)
+{
+ register int rs2 = inst & 037;
+ register int rs1 = (inst >> 16) & 037;
+ register int rd = (inst >> 21) & 037;
+ register int checkbits = (inst >> 10) & 077;
+ register int H6inst = (inst >> 26) & 077;
+
+ db_printf("\t%s", opcode);
+ if (H6inst == 076) {
+ db_printf("\t\tr%-3d,", rs1);
+ printval(inst & 0177777);
+ } else
+ if ((checkbits == 072) || (checkbits == 073))
+ db_printf("\t\tr%-3d,r%-3d", rd, rs2);
+ else
+ if (checkbits == 076)
+ db_printf("\t\tr%-3d,r%-3d", rs1, rs2);
+}
+
+static void
+symofset(int disp, int bit, int iadr)
+{
+ long addr;
+
+ if (disp & (1 << (bit - 1))) {
+ /* negative value */
+ addr = iadr + ((disp << 2) | (~0 << bit));
+ } else {
+ addr = iadr + (disp << 2);
+ }
+ db_printsym(addr, DB_STGY_PROC);
+ return;
+}
+
+static void
+obranch(int inst, char *opcode, long iadr)
+{
+ int cond = (inst >> 26) & 01;
+ int disp = inst & 0377777777;
+
+ if (cond == 0) {
+ db_printf("\t%s\t\t", opcode);
+ symofset(disp, 26, iadr);
+ } else {
+ db_printf("\t%s.n\t\t", opcode);
+ symofset(disp, 26, iadr);
+ }
+}
+
+
+/* Handles branch on conditions instructions */
+static void
+brcond(int inst, char *opcode, long iadr)
+{
+ int cond = (inst >> 26) & 1;
+ int match = (inst >> 21) & 037;
+ int rs = (inst >> 16) & 037;
+ int disp = (inst & 0177777);
+
+ if (cond == 0)
+ db_printf("\t%s\t\t", opcode);
+ else
+ db_printf("\t%s.n\t\t", opcode);
+ if (((inst >> 27) & 03) == 1)
+ switch (match) {
+ case 1:
+ db_printf("%s,", condname[0]);
+ break;
+ case 2:
+ db_printf("%s,", condname[1]);
+ break;
+ case 3:
+ db_printf("%s,", condname[2]);
+ break;
+ case 12:
+ db_printf("%s,", condname[3]);
+ break;
+ case 13:
+ db_printf("%s,", condname[4]);
+ break;
+ case 14:
+ db_printf("%s,", condname[5]);
+ break;
+ default:
+ printval(match);
+ db_printf(",");
+ }
+ else {
+ printval(match);
+ db_printf(",");
+ }
+
+ db_printf("r%-3d,", rs);
+ symofset(disp, 16, iadr);
+}
+
+
+static void
+otrap(int inst, char *opcode, long iadr)
+{
+ int vecno = inst & 0777;
+ int match = (inst >> 21) & 037;
+ int rs = (inst >> 16) & 037;
+
+ db_printf("\t%s\t", opcode);
+ if (((inst >> 12) & 017) == 0xe)
+ switch (match) {
+ case 1:
+ db_printf("%s,", condname[0]);
+ break;
+ case 2:
+ db_printf("%s,", condname[1]);
+ break;
+ case 3:
+ db_printf("%s,", condname[2]);
+ break;
+ case 12:
+ db_printf("%s,", condname[3]);
+ break;
+ case 13:
+ db_printf("%s,", condname[4]);
+ break;
+ case 14:
+ db_printf("%s,", condname[5]);
+ break;
+ default:
+ printval(match);
+ db_printf(",");
+ }
+ else {
+ printval(match);
+ db_printf(",");
+ }
+ db_printf("\tr%-3d,", rs);
+ printval(vecno);
+}
+
+
+/* Handles 10 bit immediate bit field operations */
+static void
+obit(int inst, char *opcode, long iadr)
+{
+ int rs = (inst >> 16) & 037;
+ int rd = (inst >> 21) & 037;
+ int width = (inst >> 5) & 037;
+ int offset = (inst & 037);
+
+ db_printf("\t%s\t\tr%-3d,r%-3d,", opcode, rd, rs);
+ if (((inst >> 10) & 077) == 052) {
+ db_printf("<");
+ printval(offset);
+ db_printf(">");
+ } else {
+ printval(width);
+ db_printf("<");
+ printval(offset);
+ db_printf(">");
+ }
+}
+
+
+/* Handles triadic mode bit field instructions */
+static void
+bitman(int inst, char *opcode, long iadr)
+{
+
+ int rs1 = (inst >> 16) & 037;
+ int rd = (inst >> 21) & 037;
+ int rs2 = inst & 037;
+
+ db_printf("\t%s\t\tr%-3d,r%-3d,r%-3d", opcode, rd, rs1, rs2);
+}
+
+
+/* Handles immediate load/store/exchange instructions */
+static void
+immem(int inst, char *opcode, long iadr)
+{
+ register int immed = inst & 0xFFFF;
+ register int rd = (inst >> 21) & 037;
+ register int rs = (inst >> 16) & 037;
+ register int st_lda = (inst >> 28) & 03;
+ register int aryno = (inst >> 26) & 03;
+ char c = ' ';
+
+ if (!st_lda) {
+ if ((aryno == 0) || (aryno == 01))
+ opcode = "xmem";
+ else
+ opcode = "ld";
+ if (aryno == 0)
+ aryno = 03;
+ if (!(aryno == 01))
+ c = 'u';
+ } else
+ if (st_lda == 01)
+ opcode = "ld";
+
+ db_printf("\t%s%s%c\t\tr%-3d,r%-3d,", opcode, instwidth[aryno],
+ c, rd, rs);
+ printval(immed);
+}
+
+
+/* Handles triadic mode load/store/exchange instructions */
+static void
+nimmem(int inst, char *opcode, long iadr)
+{
+ register int scaled = (inst >> 9) & 01;
+ register int rd = (inst >> 21) & 037;
+ register int rs1 = (inst >> 16) & 037;
+ register int rs2 = inst & 037;
+ register int st_lda = (inst >> 12) & 03;
+ register int aryno = (inst >> 10) & 03;
+ register int user_bit = 0;
+ int signed_fg = 1;
+ char *user = " ";
+ char c = ' ';
+
+ if (!st_lda) {
+ if ((aryno == 0) || (aryno == 01))
+ opcode = "xmem";
+ else
+ opcode = "ld";
+ if (aryno == 0)
+ aryno = 03;
+ if (!(aryno == 01)) {
+ c = 'u';
+ signed_fg = 0;
+ }
+ } else
+ if (st_lda == 01)
+ opcode = "ld";
+
+ if (!(st_lda == 03)) {
+ user_bit = (inst >> 8) & 01;
+ if (user_bit)
+ user = ".usr";
+ }
+ if (user_bit && signed_fg && (aryno == 01)) {
+ if (st_lda)
+ db_printf("\t%s%s\tr%-3d,r%-3d", opcode,
+ user, rd, rs1);
+ else
+ db_printf("\t%s%s\tr%-3d,r%-3d", opcode,
+ user, rd, rs1);
+ } else
+ if (user_bit && signed_fg)
+ db_printf("\t%s%s%s\tr%-3d,r%-3d", opcode,
+ instwidth[aryno], user, rd, rs1);
+ else
+ db_printf("\t%s%s%c%s\tr%-3d,r%-3d", opcode,
+ instwidth[aryno], c, user, rd, rs1);
+
+ if (scaled)
+ db_printf("[r%-3d]", rs2);
+ else
+ db_printf(",r%-3d", rs2);
+}
+
+
+/* Handles triadic mode logical instructions */
+static void
+lognim(int inst, char *opcode, long iadr)
+{
+ register int rd = (inst >> 21) & 037;
+ register int rs1 = (inst >> 16) & 037;
+ register int rs2 = inst & 037;
+ register int complemt = (inst >> 10) & 01;
+ char *c = " ";
+
+ if (complemt)
+ c = ".c";
+
+ db_printf("\t%s%s\t\tr%-3d,r%-3d,r%-3d", opcode, c, rd, rs1, rs2);
+}
+
+
+/* Handles triadic mode arithmetic instructions */
+static void
+onimmed(int inst, char *opcode, long iadr)
+{
+ register int rd = (inst >> 21) & 037;
+ register int rs1 = (inst >> 16) & 037;
+ register int rs2 = inst & 037;
+ register int carry = (inst >> 8) & 03;
+ register int nochar = (inst >> 10) & 07;
+ register int nodecode = (inst >> 11) & 01;
+ char *tab, *c;
+
+ if (nochar > 02)
+ tab = "\t\t";
+ else
+ tab = "\t";
+
+ if (!nodecode) {
+ if (carry == 01)
+ c = ".co ";
+ else
+ if (carry == 02)
+ c = ".ci ";
+ else
+ if (carry == 03)
+ c = ".cio";
+ else
+ c = " ";
+ } else
+ c = " ";
+
+ db_printf("\t%s%s%sr%-3d,r%-3d,r%-3d", opcode, c,
+ tab, rd, rs1, rs2);
+}
+
+static struct opdesc {
+ unsigned mask, match;
+ void (*opfun) ();
+ char *farg;
+} opdecode[] = {
+ /* ORDER IS IMPORTANT BELOW */
+
+ {
+ 0xF0000000 U, 0x00000000 U, immem, 0,
+ } ,
+ {
+ 0xF0000000 U, 0x10000000 U, immem, 0,
+ } ,
+ {
+ 0xF0000000 U, 0x20000000 U, immem, "st"
+ } ,
+ {
+ 0xF0000000 U, 0x30000000 U, immem, "lda"
+ } ,
+
+ {
+ 0xF8000000 U, 0x40000000 U, oimmed, "and"
+ } ,
+ {
+ 0xF8000000 U, 0x48000000 U, oimmed, "mask"
+ } ,
+ {
+ 0xF8000000 U, 0x50000000 U, oimmed, "xor"
+ } ,
+ {
+ 0xF8000000 U, 0x58000000 U, oimmed, "or"
+ } ,
+ {
+ 0xFC000000 U, 0x60000000 U, oimmed, "addu"
+ } ,
+ {
+ 0xFC000000 U, 0x64000000 U, oimmed, "subu"
+ } ,
+ {
+ 0xFC000000 U, 0x68000000 U, oimmed, "divu"
+ } ,
+ {
+ 0xFC000000 U, 0x6C000000 U, oimmed, "mul"
+ } ,
+ {
+ 0xFC000000 U, 0x70000000 U, oimmed, "add"
+ } ,
+ {
+ 0xFC000000 U, 0x74000000 U, oimmed, "sub"
+ } ,
+ {
+ 0xFC000000 U, 0x78000000 U, oimmed, "div"
+ } ,
+ {
+ 0xFC000000 U, 0x7C000000 U, oimmed, "cmp"
+ } ,
+
+ {
+ 0xFC00F800 U, 0x80004000 U, ctrlregs, "ldcr"
+ } ,
+ {
+ 0xFC00F800 U, 0x80004800 U, ctrlregs, "fldcr"
+ } ,
+ {
+ 0xFC00F800 U, 0x80008000 U, ctrlregs, "stcr"
+ } ,
+ {
+ 0xFC00F800 U, 0x80008800 U, ctrlregs, "fstcr"
+ } ,
+ {
+ 0xFC00F800 U, 0x8000C000 U, ctrlregs, "xcr"
+ } ,
+ {
+ 0xFC00F800 U, 0x8000C800 U, ctrlregs, "fxcr"
+ } ,
+
+ {
+ 0xFC00F800 U, 0x84000000 U, sindou, "fmul"
+ } ,
+ {
+ 0xFC1FFF80 U, 0x84002000 U, sindou, "flt"
+ } ,
+ {
+ 0xFC00F800 U, 0x84002800 U, sindou, "fadd"
+ } ,
+ {
+ 0xFC00F800 U, 0x84003000 U, sindou, "fsub"
+ } ,
+ {
+ 0xFC00F860 U, 0x84003800 U, sindou, "fcmp"
+ } ,
+ {
+ 0xFC1FFE60 U, 0x84004800 U, sindou, "int"
+ } ,
+ {
+ 0xFC1FFE60 U, 0x84005000 U, sindou, "nint"
+ } ,
+ {
+ 0xFC1FFE60 U, 0x84005800 U, sindou, "trnc"
+ } ,
+ {
+ 0xFC00F800 U, 0x84007000 U, sindou, "fdiv"
+ } ,
+
+ {
+ 0xF8000000 U, 0xC0000000 U, obranch, "br"
+ } ,
+ {
+ 0xF8000000 U, 0xC8000000 U, obranch, "bsr"
+ } ,
+
+ {
+ 0xF8000000 U, 0xD0000000 U, brcond, "bb0"
+ } ,
+ {
+ 0xF8000000 U, 0xD8000000 U, brcond, "bb1"
+ } ,
+ {
+ 0xF8000000 U, 0xE8000000 U, brcond, "bcnd"
+ } ,
+
+ {
+ 0xFC00FC00 U, 0xF0008000 U, obit, "clr"
+ } ,
+ {
+ 0xFC00FC00 U, 0xF0008800 U, obit, "set"
+ } ,
+ {
+ 0xFC00FC00 U, 0xF0009000 U, obit, "ext"
+ } ,
+ {
+ 0xFC00FC00 U, 0xF0009800 U, obit, "extu"
+ } ,
+ {
+ 0xFC00FC00 U, 0xF000A000 U, obit, "mak"
+ } ,
+ {
+ 0xFC00FC00 U, 0xF000A800 U, obit, "rot"
+ } ,
+
+ {
+ 0xFC00FE00 U, 0xF000D000 U, otrap, "tb0"
+ } ,
+ {
+ 0xFC00FE00 U, 0xF000D800 U, otrap, "tb1"
+ } ,
+ {
+ 0xFC00FE00 U, 0xF000E800 U, otrap, "tcnd"
+ } ,
+
+ {
+ 0xFC00F2E0 U, 0xF4000000 U, nimmem, 0,
+ } ,
+ {
+ 0xFC00F2E0 U, 0xF4000200 U, nimmem, 0,
+ } ,
+ {
+ 0xFC00F2E0 U, 0xF4001000 U, nimmem, 0,
+ } ,
+ {
+ 0xFC00F2E0 U, 0xF4001200 U, nimmem, 0,
+ } ,
+ {
+ 0xFC00F2E0 U, 0xF4002000 U, nimmem, "st"
+ } ,
+ {
+ 0xFC00F2E0 U, 0xF4002200 U, nimmem, "st"
+ } ,
+ {
+ 0xFC00F2E0 U, 0xF4003000 U, nimmem, "lda"
+ } ,
+ {
+ 0xFC00F2E0 U, 0xF4003200 U, nimmem, "lda"
+ } ,
+
+ {
+ 0xFC00FBE0 U, 0xF4004000 U, lognim, "and"
+ } ,
+ {
+ 0xFC00FBE0 U, 0xF4005000 U, lognim, "xor"
+ } ,
+ {
+ 0xFC00FBE0 U, 0xF4005800 U, lognim, "or"
+ } ,
+
+ {
+ 0xFC00FCE0 U, 0xF4006000 U, onimmed, "addu"
+ } ,
+ {
+ 0xFC00FCE0 U, 0xF4006400 U, onimmed, "subu"
+ } ,
+ {
+ 0xFC00FCE0 U, 0xF4006800 U, onimmed, "divu"
+ } ,
+ {
+ 0xFC00FCE0 U, 0xF4006C00 U, onimmed, "mul"
+ } ,
+ {
+ 0xFC00FCE0 U, 0xF4007000 U, onimmed, "add"
+ } ,
+ {
+ 0xFC00FCE0 U, 0xF4007400 U, onimmed, "sub"
+ } ,
+ {
+ 0xFC00FCE0 U, 0xF4007800 U, onimmed, "div"
+ } ,
+ {
+ 0xFC00FCE0 U, 0xF4007C00 U, onimmed, "cmp"
+ } ,
+
+ {
+ 0xFC00FFE0 U, 0xF4008000 U, bitman, "clr"
+ } ,
+ {
+ 0xFC00FFE0 U, 0xF4008800 U, bitman, "set"
+ } ,
+ {
+ 0xFC00FFE0 U, 0xF4009000 U, bitman, "ext"
+ } ,
+ {
+ 0xFC00FFE0 U, 0xF4009800 U, bitman, "extu"
+ } ,
+ {
+ 0xFC00FFE0 U, 0xF400A000 U, bitman, "mak"
+ } ,
+ {
+ 0xFC00FFE0 U, 0xF400A800 U, bitman, "rot"
+ } ,
+
+ {
+ 0xFC00FBE0 U, 0xF400C000 U, jump, "jmp"
+ } ,
+ {
+ 0xFC00FBE0 U, 0xF400C800 U, jump, "jsr"
+ } ,
+
+ {
+ 0xFC00FFE0 U, 0xF400E800 U, instset, "ff1"
+ } ,
+ {
+ 0xFC00FFE0 U, 0xF400EC00 U, instset, "ff0"
+ } ,
+ {
+ 0xFC00FFE0 U, 0xF400F800 U, instset, "tbnd"
+ } ,
+ {
+ 0xFC00FFE0 U, 0xF400FC00 U, instset, "rte"
+ } ,
+ {
+ 0xFC000000 U, 0xF8000000 U, instset, "tbnd"
+ } ,
+ {
+ 0, 0, 0, 0
+ }
+};
+
+static char *badop = "\t???";
+
+int
+m88k_print_instruction(unsigned iadr, long inst)
+{
+ register struct opdesc *p;
+
+ /* this messes up "orb" instructions ever so slightly, */
+ /* but keeps us in sync between routines... */
+ if (inst == 0) {
+ db_printf("\t.word 0");
+ } else {
+ for (p = opdecode; p->mask; p++)
+ if ((inst & p->mask) == p->match) {
+ (*p->opfun) (inst, p->farg, iadr);
+ break;
+ }
+ if (!p->mask)
+ db_printf(badop);
+ }
+
+ return iadr + 4;
+}
+db_addr_t
+db_disasm(db_addr_t loc, boolean_t altfmt)
+{
+ m88k_print_instruction(loc, db_get_value(loc, 4, FALSE));
+ db_printf("\n");
+ return loc + 4;
+}
diff --git a/sys/arch/mvme88k/ddb/db_interface.c b/sys/arch/mvme88k/ddb/db_interface.c
new file mode 100644
index 00000000000..6c18e1503d4
--- /dev/null
+++ b/sys/arch/mvme88k/ddb/db_interface.c
@@ -0,0 +1,834 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * m88k interface to ddb debugger
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/reboot.h>
+#include <sys/systm.h> /* just for boothowto --eichin */
+#include <setjmp.h>
+
+#include <vm/vm.h>
+
+#include <machine/m882xx.h> /* CMMU defs */
+#include <machine/trap.h> /* current_thread() */
+#include <machine/db_machdep.h> /* local ddb stuff */
+#include <machine/bug.h> /* bug routines */
+#include <machine/mmu.h>
+
+#include <ddb/db_command.h>
+#include <ddb/db_sym.h>
+
+extern jmp_buf *db_recover;
+extern unsigned int db_maxoff;
+
+int db_active = 0;
+int db_noisy = 0;
+int quiet_db_read_bytes = 0;
+
+/*
+ * Received keyboard interrupt sequence.
+ */
+kdb_kintr(regs)
+ register struct m88100_saved_state *regs;
+{
+ if (db_active == 0 && (boothowto & RB_KDB)) {
+ printf("\n\nkernel: keyboard interrupt\n");
+ m88k_db_trap(-1, regs);
+ }
+}
+/************************/
+/* PRINTING *************/
+/************************/
+
+static void
+m88k_db_str(char *str)
+{
+ db_printf(str);
+}
+
+static void
+m88k_db_str1(char *str, int arg1)
+{
+ db_printf(str, arg1);
+}
+
+static void
+m88k_db_str2(char *str, int arg1, int arg2)
+{
+ db_printf(str, arg1, arg2);
+}
+/************************/
+/* DB_REGISTERS ****/
+/************************/
+
+/*
+ *
+ * If you really feel like understanding the following procedure and
+ * macros, see pages 6-22 to 6-30 (Section 6.7.3) of
+ *
+ * MC881000 RISC Microprocessor User's Manual Second Edition
+ * (Motorola Order: MC88100UM/AD REV 1)
+ *
+ * and ERRATA-5 (6-23, 6-24, 6-24) of
+ *
+ * Errata to MC88100 User's Manual Second Edition MC88100UM/AD Rev 1
+ * (Oct 2, 1990)
+ * (Motorola Order: MC88100UMAD/AD)
+ *
+ */
+
+/* macros for decoding dmt registers */
+
+#define XMEM(x) ((x) & (1<<12))
+#define XMEM_MODE(x) ((((x)>>2 & 0xf) == 0xf) ? "" : ".bu")
+#define MODE(x) ((x)>>2 & 0xf)
+#define DOUB(x) ((x) & (1<<13))
+#define SIGN(x) ((x) & (1<<6))
+#define DAS(x) (((x) & (1<<14)) ? "" : ".usr")
+#define REG(x) (((x)>>7) & 0x1f)
+#define STORE(x) ((x) & 0x2)
+
+/*
+ * return 1 if the printing of the next stage should be surpressed
+ */
+static int
+m88k_dmx_print(unsigned t, unsigned d, unsigned a, unsigned no)
+{
+ static unsigned addr_mod[16] = {0, 3, 2, 2, 1, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0};
+ static char *mode[16] = {"?", ".b", ".b", ".h", ".b", "?", "?", "?",
+ ".b", ".h", "?", "?", "?", "?", "?", ""};
+ static unsigned mask[16] = {0, 0xff, 0xff00, 0xffff,
+ 0xff0000, 0, 0, 0,
+ 0xff000000 U, 0xffff0000 U, 0, 0,
+ 0, 0, 0, 0xffffffff U};
+ static unsigned shift[16] = {0, 0, 8, 0, 16, 0, 0, 0,
+ 24, 16, 0, 0, 0, 0, 0, 0};
+ int reg = REG(t);
+
+ if (XMEM(t)) {
+ db_printf("xmem%s%s r%d(0x%x) <-> mem(0x%x),",
+ XMEM_MODE(t), DAS(t), reg,
+ (((t) >> 2 & 0xf) == 0xf) ? d : (d & 0xff), a);
+ return 1;
+ } else {
+ if (MODE(t) == 0xf) {
+ /* full or double word */
+ if (STORE(t))
+ if (DOUB(t) && no == 2)
+ db_printf("st.d%s -> mem(0x%x) (** restart sxip **)",
+ DAS(t), a);
+ else
+ db_printf("st%s (0x%x) -> mem(0x%x)", DAS(t), d, a);
+ else /* load */
+ if (DOUB(t) && no == 2)
+ db_printf("ld.d%s r%d <- mem(0x%x), r%d <- mem(0x%x)",
+ DAS(t), reg, a, reg + 1, a + 4);
+ else
+ db_printf("ld%s r%d <- mem(0x%x)", DAS(t), reg, a);
+ } else {
+ /* fractional word - check if load or store */
+ a += addr_mod[MODE(t)];
+ if (STORE(t))
+ db_printf("st%s%s (0x%x) -> mem(0x%x)", mode[MODE(t)], DAS(t),
+ (d & mask[MODE(t)]) >> shift[MODE(t)], a);
+ else
+ db_printf("ld%s%s%s r%d <- mem(0x%x)",
+ mode[MODE(t)], SIGN(t) ? "" : "u", DAS(t), reg, a);
+ }
+ }
+ return 0;
+}
+
+static void
+m88k_db_print_frame(
+ db_expr_t addr,
+ boolean_t have_addr,
+ int count,
+ char *modif)
+{
+ struct m88100_saved_state *s = (struct m88100_saved_state *) addr;
+ char *name;
+ db_expr_t offset;
+ int surpress1 = 0, surpress2 = 0;
+ int c, force = 0, help = 0;
+
+ if (!have_addr) {
+ db_printf("requires address of frame\n");
+ help = 1;
+ }
+ while (modif && *modif) {
+ switch (c = *modif++, c) {
+ case 'f':
+ force = 1;
+ break;
+ case 'h':
+ help = 1;
+ break;
+ default:
+ db_printf("unknown modifier [%c]\n", c);
+ help = 1;
+ break;
+ }
+ }
+
+ if (help) {
+ db_printf("usage: mach frame/[f] ADDRESS\n");
+ db_printf(" /f force printing of insane frames.\n");
+ return;
+ }
+ if (badwordaddr((vm_offset_t) s) ||
+ badwordaddr((vm_offset_t) (&((db_regs_t *) s)->mode))) {
+ db_printf("frame at 0x%08x is unreadable\n", s);
+ return;
+ }
+ if (!frame_is_sane(s)) {/* see db_trace.c */
+ db_printf("frame seems insane (");
+
+ if (force)
+ db_printf("forging ahead anyway...)\n");
+ else {
+ db_printf("use /f to force)\n");
+ return;
+ }
+ }
+#define R(i) s->r[i]
+#define IPMASK(x) ((x) & ~(3))
+ db_printf("R00-05: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(0), R(1), R(2), R(3), R(4), R(5));
+ db_printf("R06-11: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(6), R(7), R(8), R(9), R(10), R(11));
+ db_printf("R12-17: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(12), R(13), R(14), R(15), R(16), R(17));
+ db_printf("R18-23: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(18), R(19), R(20), R(21), R(22), R(23));
+ db_printf("R24-29: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ R(24), R(25), R(26), R(27), R(28), R(29));
+ db_printf("R30-31: 0x%08x 0x%08x\n", R(30), R(31));
+
+ db_printf("sxip: 0x%08x ", s->sxip);
+ db_find_xtrn_sym_and_offset((db_addr_t) IPMASK(s->sxip), &name, &offset);
+ if (name != 0 && (unsigned) offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned) offset);
+ db_printf("\n");
+ if (s->snip != s->sxip + 4) {
+ db_printf("snip: 0x%08x ", s->snip);
+ db_find_xtrn_sym_and_offset((db_addr_t) IPMASK(s->snip), &name, &offset);
+ if (name != 0 && (unsigned) offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned) offset);
+ db_printf("\n");
+ }
+ if (s->sfip != s->snip + 4) {
+ db_printf("sfip: 0x%08x ", s->sfip);
+ db_find_xtrn_sym_and_offset((db_addr_t) IPMASK(s->sfip), &name, &offset);
+ if (name != 0 && (unsigned) offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned) offset);
+ db_printf("\n");
+ }
+ db_printf("vector: 0x%02x interrupt mask: 0x%08x\n",
+ s->vector, s->mask >> 8);
+ db_printf("epsr: 0x%08x current process: 0x%x\n",
+ s->epsr, curproc);
+
+ /*
+ * If the vector indicates trap, instead of an exception or
+ * interrupt, skip the check of dmt and fp regs.
+ *
+ * Interrupt and exceptions are vectored at 0-10 and 114-127.
+ */
+
+ if (!(s->vector <= 10 || (114 <= s->vector && s->vector <= 127))) {
+ db_printf("\n\n");
+ return;
+ }
+ if (s->vector == /* data */ 3 || s->dmt0 & 1) {
+ db_printf("dmt,d,a0: 0x%08x 0x%08x 0x%08x ", s->dmt0, s->dmd0, s->dma0);
+ db_find_xtrn_sym_and_offset((db_addr_t) s->dma0, &name, &offset);
+ if (name != 0 && (unsigned) offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned) offset);
+ db_printf("\n ");
+ surpress1 = m88k_dmx_print(s->dmt0 | 0x01, s->dmd0, s->dma0, 0);
+ db_printf("\n");
+
+ if ((s->dmt1 & 1) && (!surpress1)) {
+ db_printf("dmt,d,a1: 0x%08x 0x%08x 0x%08x ", s->dmt1, s->dmd1, s->dma1);
+ db_find_xtrn_sym_and_offset((db_addr_t) s->dma1, &name, &offset);
+ if (name != 0 && (unsigned) offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned) offset);
+ db_printf("\n ");
+ surpress2 = m88k_dmx_print(s->dmt1, s->dmd1, s->dma1, 1);
+ db_printf("\n");
+
+ if ((s->dmt2 & 1) && (!surpress2)) {
+ db_printf("dmt,d,a2: 0x%08x 0x%08x 0x%08x ", s->dmt2, s->dmd2, s->dma2);
+ db_find_xtrn_sym_and_offset((db_addr_t) s->dma2, &name, &offset);
+ if (name != 0 && (unsigned) offset <= db_maxoff)
+ db_printf("%s+0x%08x", name, (unsigned) offset);
+ db_printf("\n ");
+ (void) m88k_dmx_print(s->dmt2, s->dmd2, s->dma2, 2);
+ db_printf("\n");
+ }
+ }
+ }
+ if (s->fpecr & 255) { /* floating point error occured */
+ db_printf("fpecr: 0x%08x fpsr: 0x%08x fpcr: 0x%08x\n",
+ s->fpecr, s->fpsr, s->fpcr);
+ db_printf("fcr1-4: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ s->fphs1, s->fpls1, s->fphs2, s->fpls2);
+ db_printf("fcr5-8: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ s->fppt, s->fprh, s->fprl, s->fpit);
+ }
+ db_printf("\n\n");
+}
+
+static void
+m88k_db_registers(
+ db_expr_t addr,
+ boolean_t have_addr,
+ int count,
+ char *modif)
+{
+ if (modif && *modif) {
+ db_printf("usage: mach regs\n");
+ return;
+ }
+ m88k_db_print_frame((db_expr_t) DDB_REGS, TRUE, 0, 0);
+ return;
+}
+/************************/
+/* PAUSE ****************/
+/************************/
+
+/*
+ * pause for 2*ticks many cycles
+ */
+static void
+m88k_db_pause(unsigned volatile ticks)
+{
+ while (ticks)
+ ticks -= 1;
+ return;
+}
+/*
+ * m88k_db_trap - field a TRACE or BPT trap
+ */
+
+m88k_db_trap(
+ int type,
+ register struct m88100_saved_state * regs)
+{
+
+ int i;
+
+#if 0
+ if ((i = db_spl()) != 7)
+ m88k_db_str1("WARNING: spl is not high in m88k_db_trap (spl=%x)\n", i);
+#endif /* 0 */
+
+ if (db_are_interrupts_disabled())
+ m88k_db_str("WARNING: entered debugger with interrupts disabled\n");
+
+ switch (type) {
+
+ case T_KDB_BREAK:
+ case T_KDB_TRACE:
+ case T_KDB_ENTRY:
+ break;
+ case -1:
+ break;
+ default:
+ kdbprinttrap(type, 0);
+ if (db_recover != 0) {
+ db_error("Caught exception in ddb.\n");
+ /* NOTREACHED */
+ }
+ }
+
+ ddb_regs = *regs;
+
+ db_active++;
+ cnpollc(TRUE);
+ db_trap(type, 0);
+ cnpollc(FALSE);
+ db_active--;
+
+ *regs = ddb_regs;
+
+#if 0
+ (void) spl7();
+#endif
+ return (1);
+}
+
+extern char *trap_type[];
+extern int trap_types;
+
+/*
+ * Print trap reason.
+ */
+kdbprinttrap(type, code)
+ int type, code;
+{
+ printf("kernel: ");
+ if (type >= trap_types || type < 0)
+ printf("type %d", type);
+ else
+ printf("%s", trap_type[type]);
+ printf(" trap\n");
+}
+
+int
+Debugger()
+{
+ asm(ENTRY_ASM); /* entry trap */
+ /* ends up at ddb_entry_trap below */
+}
+
+/* gimmeabreak - drop execute the ENTRY trap */
+void
+gimmeabreak(void)
+{
+ asm(ENTRY_ASM); /* entry trap */
+ /* ends up at ddb_entry_trap below */
+}
+
+/* fielded a non maskable interrupt */
+int
+ddb_nmi_trap(int level, db_regs_t * eframe)
+{
+ NOISY(m88k_db_str("kernel: nmi interrupt\n");)
+ m88k_db_trap(T_KDB_ENTRY, eframe);
+ return 0;
+}
+
+/*
+ * When the below routine is entered interrupts should be on
+ * but spl should be high
+ *
+ * The following routine is for breakpoint and watchpoint entry.
+ */
+
+/* breakpoint/watchpoint entry */
+int
+ddb_break_trap(type, eframe)
+ int type;
+ db_regs_t *eframe;
+{
+ m88k_db_trap(type, eframe);
+
+ if (type == T_KDB_BREAK) {
+ /* back up an instruction and retry the instruction at the
+ * breakpoint address */
+ eframe->sfip = eframe->snip;
+ eframe->snip = eframe->sxip;
+ }
+ return 0;
+}
+
+/* enter at splhigh */
+int
+ddb_entry_trap(level, eframe)
+ int level;
+ db_regs_t *eframe;
+{
+ m88k_db_trap(T_KDB_ENTRY, eframe);
+ return 0;
+}
+
+/*
+ * When the below routine is entered interrupts should be on
+ * but spl should be high
+ */
+/* error trap - unreturnable */
+void
+ddb_error_trap(error, eframe)
+ char *error;
+ db_regs_t *eframe;
+{
+ m88k_db_str1("KERNEL: terminal error [%s]\n", (int) error);
+ m88k_db_str("KERNEL: Exiting debugger will cause abort to rom\n");
+ m88k_db_str1("at 0x%x ", eframe->sxip & ~3);
+ m88k_db_str2("dmt0 0x%x dma0 0x%x", eframe->dmt0, eframe->dma0);
+ m88k_db_pause(1000000);
+ m88k_db_trap(T_KDB_BREAK, eframe);
+}
+
+/*
+ * Read bytes from kernel address space for debugger.
+ */
+void
+db_read_bytes(addr, size, data)
+ vm_offset_t addr;
+ register int size;
+ register char *data;
+{
+ register char *src;
+
+ src = (char *) addr;
+
+ while (--size >= 0)
+ *data++ = *src++;
+}
+
+/*
+ * Write bytes to kernel address space for debugger.
+ * This should make a text page writable to be able
+ * to plant a break point (right now text is mapped with
+ * write access in pmap_bootstrap()). XXX nivas
+ */
+void
+db_write_bytes(addr, size, data)
+ char *addr;
+ int size;
+ char *data;
+{
+
+ register char *dst;
+ int i = size;
+ vm_offset_t physaddr;
+ pte_template_t *pte;
+
+ dst = (char *) addr;
+
+ while (--size >= 0) {
+#if 0
+ db_printf("byte %x\n", *data);
+#endif /* 0 */
+ *dst++ = *data++;
+ }
+ physaddr = pmap_extract(kernel_pmap, (vm_offset_t) addr);
+ cmmu_flush_cache(physaddr, i);
+}
+
+/* to print a character to the console */
+void
+db_putc(int c)
+{
+ bugoutchr(c & 0xff);
+}
+
+/* to peek at the console; returns -1 if no character is there */
+int
+db_getc(void)
+{
+ if (buginstat())
+ return (buginchr());
+ else
+ return -1;
+}
+
+/* display where all the cpus are stopped at */
+static void
+m88k_db_where(void)
+{
+ struct m88100_saved_state *s;
+ char *name;
+ int *offset;
+ int i;
+ int l;
+
+ s = DDB_REGS;
+
+ l = m88k_pc(s); /* clear low bits */
+
+ db_find_xtrn_sym_and_offset((db_addr_t) l, &name, (db_expr_t *) & offset);
+ if (name && (unsigned) offset <= db_maxoff)
+ db_printf("stopped at 0x%x (%s+0x%x)\n",
+ l, name, offset);
+ else
+ db_printf("stopped at 0x%x\n", l);
+}
+
+/*
+ * Walk back a stack, looking for exception frames.
+ * These frames are recognized by the routine frame_is_sane. Frames
+ * only start with zero, so we only call frame_is_sane if the
+ * current address contains zero.
+ *
+ * If addr is given, it is assumed to an address on the stack to be
+ * searched. Otherwise, r31 of the current cpu is used.
+ */
+static void
+m88k_db_frame_search(db_expr_t addr, boolean_t have_addr)
+{
+#if 1
+ db_printf("sorry, frame search currently disabled.\n");
+#else
+ if (have_addr)
+ addr &= ~3; /* round to word */
+ else
+ addr = (DDB_REGS->r[31]);
+
+ /* walk back up stack until 8k boundry, looking for 0 */
+ while (addr & ((8 * 1024) - 1)) {
+ int i;
+ db_read_bytes(addr, 4, &i);
+ if (i == 0 && frame_is_sane(i))
+ db_printf("frame found at 0x%x\n", i);
+ addr += 4;
+ }
+
+ db_printf("(Walked back until 0x%x)\n", addr);
+#endif
+}
+/* flush icache */
+static void
+m88k_db_iflush(db_expr_t addr, boolean_t have_addr)
+{
+ addr = 0;
+ cmmu_remote_set(addr, CMMU_SCR, 0, CMMU_FLUSH_CACHE_CBI_ALL);
+}
+/* flush dcache */
+
+static void
+m88k_db_dflush(db_expr_t addr, boolean_t have_addr)
+{
+ addr = 0;
+
+ cmmu_remote_set(addr, CMMU_SCR, 1, CMMU_FLUSH_CACHE_CBI_ALL);
+}
+/* probe my cache */
+static void
+m88k_db_peek(
+ db_expr_t addr,
+ boolean_t have_addr,
+ int count,
+ char *modif)
+{
+ int pa12;
+ int valmask;
+
+ pa12 = addr & ~((1 << 12) - 1);
+
+ /* probe dcache */
+ cmmu_remote_set(0, CMMU_SAR, 1, addr);
+
+ valmask = cmmu_remote_get(0, CMMU_CSSP, 1);
+ db_printf("dcache valmask 0x%x\n", (unsigned) valmask);
+ db_printf("dcache tag ports 0x%x 0x%x 0x%x 0x%x\n",
+ (unsigned) cmmu_remote_get(0, CMMU_CTP0, 1),
+ (unsigned) cmmu_remote_get(0, CMMU_CTP1, 1),
+ (unsigned) cmmu_remote_get(0, CMMU_CTP2, 1),
+ (unsigned) cmmu_remote_get(0, CMMU_CTP3, 1));
+
+ /* probe icache */
+ cmmu_remote_set(0, CMMU_SAR, 0, addr);
+
+ valmask = cmmu_remote_get(0, CMMU_CSSP, 0);
+ db_printf("icache valmask 0x%x\n", (unsigned) valmask);
+ db_printf("icache tag ports 0x%x 0x%x 0x%x 0x%x\n",
+ (unsigned) cmmu_remote_get(0, CMMU_CTP0, 0),
+ (unsigned) cmmu_remote_get(0, CMMU_CTP1, 0),
+ (unsigned) cmmu_remote_get(0, CMMU_CTP2, 0),
+ (unsigned) cmmu_remote_get(0, CMMU_CTP3, 0));
+
+}
+
+
+/*
+ * control how much info the debugger prints about itself
+ */
+static void
+m88k_db_noise(db_expr_t addr, boolean_t have_addr)
+{
+ if (!have_addr) {
+ /* if off make noisy; if noisy or very noisy turn off */
+ if (db_noisy) {
+ db_printf("changing debugger status from %s to quiet\n",
+ db_noisy == 1 ? "noisy" :
+ db_noisy == 2 ? "very noisy" : "violent");
+ db_noisy = 0;
+ } else {
+ db_printf("changing debugger status from quiet to noisy\n");
+ db_noisy = 1;
+ }
+ } else
+ if (addr < 0 || addr > 3)
+ db_printf("invalid noise level to m88k_db_noisy; should be 0, 1, 2, or 3\n");
+ else {
+ db_noisy = addr;
+ db_printf("debugger noise level set to %s\n",
+ db_noisy == 0 ? "quiet" :
+ (db_noisy == 1 ? "noisy" :
+ db_noisy == 2 ? "very noisy" : "violent"));
+ }
+}
+/*
+ * See how a virtual address translates.
+ * Must have an address.
+ */
+static void
+m88k_db_translate(
+ db_expr_t addr,
+ boolean_t have_addr,
+ unsigned count,
+ char *modif)
+{
+#if 0
+ char c;
+ int verbose_flag = 0;
+ int supervisor_flag = 1;
+ int wanthelp = 0;
+
+ if (!have_addr)
+ wanthelp = 1;
+ else {
+ while (c = *modif++, c != 0) {
+ switch (c) {
+ default:
+ db_printf("bad modifier [%c]\n", c);
+ wanthelp = 1;
+ break;
+ case 'h':
+ wanthelp = 1;
+ break;
+ case 'v':
+ verbose_flag++;
+ break;
+ case 's':
+ supervisor_flag = 1;
+ break;
+ case 'u':
+ supervisor_flag = 0;
+ break;
+ }
+ }
+ }
+ if (wanthelp) {
+ db_printf("usage: translate[/vvsu] address\n");
+ db_printf("flags: v - be verbose (vv - be very verbose)\n");
+ db_printf(" s - use cmmu's supervisor area pointer (default)\n");
+ db_printf(" u - use cmmu's user area pointer\n");
+ return;
+ }
+ cmmu_show_translation(addr, supervisor_flag, verbose_flag);
+#endif /* 0 */
+}
+
+void
+cpu_interrupt_to_db(int cpu_no)
+{
+}
+
+
+/************************/
+/* COMMAND TABLE / INIT */
+/************************/
+
+static struct db_command m88k_cache_cmds[] =
+{
+ {"iflush", m88k_db_iflush, 0, 0},
+ {"dflush", m88k_db_dflush, 0, 0},
+ {"peek", m88k_db_peek, 0, 0},
+ {(char *) 0,}
+};
+
+struct db_command db_machine_cmds[] =
+{
+ {"cache", 0, 0, m88k_cache_cmds},
+ {"frame", m88k_db_print_frame, 0, 0},
+ {"noise", m88k_db_noise, 0, 0},
+ {"regs", m88k_db_registers, 0, 0},
+ {"searchframe", m88k_db_frame_search, 0, 0},
+ {"translate", m88k_db_translate, 0, 0},
+ {"where", m88k_db_where, 0, 0},
+ {(char *) 0,}
+};
+/*
+ * Called from "m88k/m1x7_init.c"
+ */
+void
+kdb_init(void)
+{
+#ifdef DB_MACHINE_COMMANDS
+ db_machine_commands_install(db_machine_cmds);
+#endif
+ ddb_init();
+
+ db_printf("ddb enabled\n");
+}
+/*
+ * Attempt to figure out the UX name of the task.
+ * This is kludgy at best... we can't even be sure the task is a UX task...
+ */
+#define TOP_OF_USER_STACK USRSTACK
+#define MAX_DISTANCE_TO_LOOK (1024 * 10)
+
+#define DB_TASK_NAME_LEN 50
+
+char
+ *
+db_task_name()
+{
+ static unsigned buffer[(DB_TASK_NAME_LEN + 5) / sizeof(unsigned)];
+ unsigned ptr = (vm_offset_t) (TOP_OF_USER_STACK - 4);
+ unsigned limit = ptr - MAX_DISTANCE_TO_LOOK;
+ unsigned word;
+ int i;
+
+ /* skip zeros at the end */
+ while (ptr > limit &&
+ (i = db_trace_get_val((vm_offset_t) ptr, &word))
+ && (word == 0)) {
+ ptr -= 4; /* continue looking for a non-null word */
+ }
+
+ if (ptr <= limit) {
+ db_printf("bad name at line %d\n", __LINE__);
+ return "<couldn't find 1>";
+ } else
+ if (i != 1) {
+ return "<nostack>";
+ }
+ /* skip looking for null before all the text */
+ while (ptr > limit
+ && (i = db_trace_get_val(ptr, &word))
+ && (word != 0)) {
+ ptr -= 4; /* continue looking for a null word */
+ }
+
+ if (ptr <= limit) {
+ db_printf("bad name at line %d\n", __LINE__);
+ return "<couldn't find 2>";
+ } else
+ if (i != 1) {
+ db_printf("bad name read of %x "
+ "at line %d\n", ptr, __LINE__);
+ return "<bad read 2>";
+ }
+ ptr += 4; /* go back to the non-null word after this one */
+
+ for (i = 0; i < sizeof(buffer); i++, ptr += 4) {
+ buffer[i] = 0; /* just in case it's not read */
+ db_trace_get_val((vm_offset_t) ptr, &buffer[i]);
+ }
+ return (char *) buffer;
+}
diff --git a/sys/arch/mvme88k/ddb/db_sstep.c b/sys/arch/mvme88k/ddb/db_sstep.c
new file mode 100644
index 00000000000..373ff40c109
--- /dev/null
+++ b/sys/arch/mvme88k/ddb/db_sstep.c
@@ -0,0 +1,256 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <machine/db_machdep.h>
+#include <ddb/db_access.h> /* db_get_value() */
+
+/*
+ * Support routines for software single step.
+ *
+ * Author: Daniel Stodolsky (danner@cs.cmu.edu)
+ *
+ */
+
+/* is the instruction a branch or jump instruction (br, bb0, bb1, bcnd, jmp)
+ but not a function call (bsr or jsr) */
+
+boolean_t
+inst_branch(unsigned ins)
+{
+ /* check high five bits */
+
+ switch (ins >> (32 - 5)) {
+ case 0x18: /* br */
+ case 0x1a: /* bb0 */
+ case 0x1b: /* bb1 */
+ case 0x1d: /* bcnd */
+ return TRUE;
+ break;
+ case 0x1e: /* could be jmp */
+ if ((ins & 0xfffffbe0 U) == 0xf400c000 U)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+/* inst_load(ins) - returns the number of words the instruction loads. byte,
+ half and word count as 1; double word as 2 */
+
+unsigned
+inst_load(unsigned ins)
+{
+ /* look at the top six bits, for starters */
+
+ switch (ins >> (32 - 6)) {
+ case 0x0: /* xmem byte imm */
+ case 0x1: /* xmem word imm */
+
+ case 0x2: /* unsigned half-word load imm */
+ case 0x3: /* unsigned byte load imm */
+ case 0x5: /* signed word load imm */
+ case 0x6: /* signed half-word load imm */
+ case 0x7: /* signed byte load imm */
+ return 1;
+
+ case 0x4: /* signed double word load imm */
+ return 2;
+
+ case 0x3d: /* load/store/xmem scaled/unscaled instruction */
+ if ((ins & 0xf400c0e0 U) == 0xf4000000 U) /* is load/xmem */
+ switch ((ins & 0x0000fce0) >> 5) { /* look at bits 15-5,
+ * but mask bits 8-9 */
+ case 0x0: /* xmem byte */
+ case 0x1: /* xmem word */
+ case 0x2: /* unsigned half word */
+ case 0x3: /* unsigned byte load */
+ case 0x5: /* signed word load */
+ case 0x6: /* signed half-word load */
+ case 0x7: /* signed byte load */
+ return 1;
+
+ case 0x4: /* signed double word load */
+ return 2;
+ } /* end switch load/xmem */
+ break;
+ } /* end switch 32-6 */
+
+ return 0;
+}
+/* inst_store - like inst_load, except for store instructions. */
+
+unsigned
+inst_store(unsigned ins)
+{
+ /* decode top 6 bits again */
+ switch (ins >> (32 - 6)) {
+ case 0x0: /* xmem byte imm */
+ case 0x1: /* xmem word imm */
+ case 0x9: /* store word imm */
+ case 0xa: /* store half-word imm */
+ case 0xb: /* store byte imm */
+ return 1;
+
+ case 0x8: /* store double word */
+ return 2;
+ case 0x3d: /* load/store/xmem scaled/unscaled instruction */
+ /* check bits 15,14,12,7,6,5 are all 0 */
+ if ((ins & 0x0000d0e0 U) == 0)
+ switch ((ins & 0x00003c00 U) >> 10) { /* decode bits 10-13 */
+ case 0x0: /* xmem byte imm */
+ case 0x1: /* xmem word imm */
+ case 0x9: /* store word */
+ case 0xa: /* store half-word */
+ case 0xb: /* store byte */
+ return 1;
+
+ case 0x8: /* store double word */
+ return 2;
+ } /* end switch store/xmem */
+ break;
+ } /* end switch 32-6 */
+
+ return 0;
+}
+/* inst_delayed - this instruction is followed by a delay slot. Could be
+ br.n, bsr.n bb0.n, bb1.n, bcnd.n or jmp.n or jsr.n */
+
+boolean_t
+inst_delayed(unsigned ins)
+{
+ /* check the br, bsr, bb0, bb1, bcnd cases */
+ switch ((ins & 0xfc000000 U) >> (32 - 6)) {
+ case 0x31: /* br */
+ case 0x33: /* bsr */
+ case 0x35: /* bb0 */
+ case 0x37: /* bb1 */
+ case 0x3b: /* bcnd */
+ return TRUE;
+ }
+
+ /* check the jmp, jsr cases */
+ /* mask out bits 0-4, bit 11 */
+ return ((ins & 0xfffff7e0 U) == 0xf400c400 U) ? TRUE : FALSE;
+}
+
+
+/*
+ * next_instr_address(pc,delay_slot,task) has the following semantics.
+ * Let inst be the instruction at pc.
+ * If delay_slot = 1, next_instr_address should return
+ * the address of the instruction in the delay slot; if this instruction
+ * does not have a delay slot, it should return pc.
+ * If delay_slot = 0, next_instr_address should return the
+ * address of next sequential instruction, or pc if the instruction is
+ * followed by a delay slot.
+ *
+ * 91-11-28 jfriedl: I think the above is wrong. I think it should be:
+ * if delay_slot true, return address of the delay slot if there is one,
+ * return pc otherwise.
+ * if delay_slot false, return (pc + 4) regardless.
+ *
+ */
+db_addr_t
+next_instr_address(db_addr_t pc, unsigned delay_slot)
+{
+ if (delay_slot == 0)
+ return pc + 4;
+ else {
+ if (inst_delayed(db_get_value(pc, sizeof(int), FALSE)))
+ return pc + 4;
+ else
+ return pc;
+ }
+}
+
+
+/*
+ * branch_taken(instruction, program counter, func, func_data)
+ *
+ * instruction will be a control flow instruction location at address pc.
+ * Branch taken is supposed to return the address to which the instruction
+ * would jump if the branch is taken. Func can be used to get the current
+ * register values when invoked with a register number and func_data as
+ * arguments.
+ *
+ * If the instruction is not a control flow instruction, panic.
+ */
+unsigned
+branch_taken(
+ unsigned inst,
+ unsigned pc,
+ db_expr_t(*func) (unsigned int, db_regs_t *),
+ db_regs_t * func_data)
+{ /* 'opaque' */
+
+ /* check if br/bsr */
+ if ((inst & 0xf0000000 U) == 0xc0000000 U) {
+ /* signed 26 bit pc relative displacement, shift left two bits */
+ inst = (inst & 0x03ffffff U) << 2;
+ /* check if sign extension is needed */
+ if (inst & 0x08000000 U)
+ inst |= 0xf0000000 U;
+ return pc + inst;
+ }
+ /* check if bb0/bb1/bcnd case */
+ switch ((inst & 0xf8000000 U)) {
+ case 0xd0000000 U: /* bb0 */
+ case 0xd8000000 U: /* bb1 */
+ case 0xe8000000 U: /* bcnd */
+ /* signed 16 bit pc relative displacement, shift left two bits */
+ inst = (inst & 0x0000ffff U) << 2;
+ /* check if sign extension is needed */
+ if (inst & 0x00020000 U)
+ inst |= 0xfffc0000 U;
+ return pc + inst;
+ }
+
+ /* check jmp/jsr case */
+ /* check bits 5-31, skipping 10 & 11 */
+ if ((inst & 0xfffff3e0 U) == 0xf400c000 U)
+ return (*func) (inst & 0x1f, func_data); /* the register value */
+
+ panic("branch_taken");
+ return 0; /* keeps compiler happy */
+}
+/*
+ * getreg_val - handed a register number and an exception frame.
+ * Returns the value of the register in the specified
+ * frame. Only makes sense for general registers.
+ */
+db_expr_t
+getreg_val(unsigned regno, db_regs_t * frame)
+{
+ if (regno == 0)
+ return 0;
+ else
+ if (regno < 31)
+ return frame->r[regno];
+ else {
+ panic("bad register number to getreg_val.");
+ return 0; /* to make compiler happy */
+ }
+}
diff --git a/sys/arch/mvme88k/ddb/db_trace.c b/sys/arch/mvme88k/ddb/db_trace.c
new file mode 100644
index 00000000000..70336eeedab
--- /dev/null
+++ b/sys/arch/mvme88k/ddb/db_trace.c
@@ -0,0 +1,1221 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993-1991 Carnegie Mellon University
+ * Copyright (c) 1991 OMRON Corporation
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+union instruction {
+ unsigned rawbits;
+
+ struct {
+ unsigned int:5;
+ unsigned int n:1;
+ signed int d26:26;
+ } br;
+
+ struct {
+ unsigned int:4;
+ unsigned int isbb1:1; /* isbb1==0 means bb0, isbb1==1 means
+ * bb1 */
+ unsigned int n:1;
+ unsigned int b5:5;
+ unsigned int s1:5;
+ signed int d16:16;
+ } bb; /* bcnd too, except "isbb1" makes no sense for
+ * bcnd */
+
+ struct {
+ unsigned int:6;
+ unsigned int b5:5;
+ unsigned int s1:5;
+ unsigned int:7;
+ unsigned int vec9:9;
+ } tb; /* tcnd too */
+
+ struct {
+ unsigned int:21;
+ unsigned int n:1;
+ unsigned int:5;
+ unsigned int s2:5;
+ } jump; /* jmp, jsr */
+
+ struct {
+ unsigned int:6;
+ unsigned int d:5;
+ unsigned int s1:5;
+ unsigned int i16:16;
+ } diatic; /* general reg/reg/i16 instructions */
+
+ struct {
+ unsigned int:6;
+ unsigned int d:5;
+ unsigned int s1:5;
+ unsigned int:11;
+ unsigned int s2:5;
+ } triatic; /* general reg/reg/reg instructions */
+
+};
+
+static inline unsigned
+br_dest(unsigned addr, union instruction inst)
+{
+ return addr + inst.br.d26 * 4;
+}
+
+
+#define TRACE_DEBUG /* undefine to disable debugging */
+
+#include <machine/db_machdep.h> /* lots of stuff */
+#include <setjmp.h> /* jmp_buf, etc. */
+#include <ddb/db_variables.h> /* db_variable, DB_VAR_GET, etc. */
+#include <ddb/db_output.h> /* db_printf */
+#include <ddb/db_sym.h> /* DB_STGY_PROC, etc. */
+#include <ddb/db_command.h> /* db_recover */
+
+/*
+ * Some macros to tell if the given text is the instruction.
+ */
+#define JMPN_R1(I) ( (I) == 0xf400c401U) /* jmp.n r1 */
+#define JMP_R1(I) ( (I) == 0xf400c001U) /* jmp r1 */
+
+/* gets the IMM16 value from an instruction */
+#define IMM16VAL(I) (((union instruction)(I)).diatic.i16)
+
+/* subu r31, r31, IMM */
+#define SUBU_R31_R31_IMM(I) (((I) & 0xffff0000U) == 0x67ff0000U)
+
+/* st r1, r31, IMM */
+#define ST_R1_R31_IMM(I) (((I) & 0xffff0000U) == 0x243f0000U)
+
+static trace_flags = 0;
+#define TRACE_DEBUG_FLAG 0x01
+#define TRACE_SHOWCALLPRESERVED_FLAG 0x02
+#define TRACE_SHOWADDRESS_FLAG 0x04
+#define TRACE_SHOWFRAME_FLAG 0x08
+#define TRACE_USER_FLAG 0x10
+
+#ifdef TRACE_DEBUG
+#define DEBUGGING_ON (trace_flags & TRACE_DEBUG_FLAG)
+#endif
+
+#ifndef TRACE_DEBUG
+#define SHOW_INSTRUCTION(Addr, Inst, Note) { /*nothing*/ }
+#else
+#define SHOW_INSTRUCTION(Addr, Inst, Note) if (DEBUGGING_ON) { \
+ db_printf("%s0x%x: (0x%08x) ", Note, (unsigned)(Addr), (Inst)); \
+ m88k_print_instruction((unsigned)(Addr), (Inst)); \
+ db_printf("\n"); \
+ }
+#endif
+
+extern jmp_buf *db_recover;
+extern int quiet_db_read_bytes;
+/*
+ * m88k trace/register state interface for ddb.
+ */
+
+/* lifted from mips */
+static int
+db_setf_regs(
+ struct db_variable * vp,
+ db_expr_t * valuep,
+ int op)
+{ /* read/write */
+ register int *regp = (int *) ((char *) DDB_REGS + (int) (vp->valuep));
+
+ if (op == DB_VAR_GET)
+ *valuep = *regp;
+ else
+ if (op == DB_VAR_SET)
+ *regp = *valuep;
+}
+#define N(s, x) {s, (int *)&(((db_regs_t *) 0)->x), db_setf_regs}
+
+struct db_variable db_regs[] = {
+ N("r1", r[1]), N("r2", r[2]), N("r3", r[3]), N("r4", r[4]),
+ N("r5", r[5]), N("r6", r[6]), N("r7", r[7]), N("r8", r[8]),
+ N("r9", r[9]), N("r10", r[10]), N("r11", r[11]), N("r12", r[12]),
+ N("r13", r[13]), N("r14", r[14]), N("r15", r[15]), N("r16", r[16]),
+ N("r17", r[17]), N("r18", r[18]), N("r19", r[19]), N("r20", r[20]),
+ N("r21", r[21]), N("r22", r[22]), N("r23", r[23]), N("r24", r[24]),
+ N("r25", r[25]), N("r26", r[26]), N("r27", r[27]), N("r28", r[28]),
+ N("r29", r[29]), N("r30", r[30]), N("r31", r[31]), N("epsr", epsr),
+ N("sxip", sxip), N("snip", snip), N("sfip", sfip), N("ssbr", ssbr),
+ N("dmt0", dmt0), N("dmd0", dmd0), N("dma0", dma0), N("dmt1", dmt1),
+ N("dmd1", dmd1), N("dma1", dma1), N("dmt2", dmt2), N("dmd2", dmd2),
+ N("dma2", dma2), N("fpecr", fpecr), N("fphs1", fphs1), N("fpls1", fpls1),
+ N("fphs2", fphs2), N("fpls2", fpls2), N("fppt", fppt), N("fprh", fprh),
+ N("fprl", fprl), N("fpit", fpit), N("fpsr", fpsr), N("fpcr", fpcr),
+ N("mask", mask), /* interrupt mask */
+ N("mode", mode), /* interrupt mode */
+ N("exvc", vector), /* exception vector */
+};
+#undef N
+
+struct db_variable *db_eregs = db_regs + sizeof(db_regs) / sizeof(db_regs[0]);
+
+
+#define TRASHES 0x001 /* clobbers instruction field D */
+#define STORE 0x002 /* does a store to S1+IMM16 */
+#define LOAD 0x004 /* does a load from S1+IMM16 */
+#define DOUBLE 0x008 /* double-register */
+#define FLOW_CTRL 0x010 /* flow-control instruction */
+#define DELAYED 0x020 /* delayed flow control */
+#define JSR 0x040 /* flow-control is a jsr[.n] */
+#define BSR 0x080 /* flow-control is a bsr[.n] */
+
+/*
+ * Given a word of instruction text, return some flags about that
+ * instruction (flags defined above).
+ */
+static unsigned
+m88k_instruction_info(unsigned instruction)
+{
+ static struct {
+ unsigned mask, value, flags;
+ } *ptr, control[] =
+ {
+ /* runs in the same order as 2nd Ed 88100 manual Table 3-14 */
+ {
+ 0xf0000000 U, 0x00000000 U, /* xmem */ TRASHES | STORE | LOAD
+ } ,
+ {
+ 0xec000000 U, 0x00000000 U, /* ld.d */ TRASHES | LOAD | DOUBLE
+ } ,
+ {
+ 0xe0000000 U, 0x00000000 U, /* load */ TRASHES | LOAD
+ } ,
+ {
+ 0xfc000000 U, 0x20000000 U, /* st.d */ STORE | DOUBLE
+ } ,
+ {
+ 0xf0000000 U, 0x20000000 U, /* store */ STORE
+ } ,
+ {
+ 0xc0000000 U, 0x40000000 U, /* arith */ TRASHES
+ } ,
+ {
+ 0xfc004000 U, 0x80004000 U, /* ld cr */ TRASHES
+ } ,
+ {
+ 0xfc004000 U, 0x80000000 U, /* st cr */ 0
+ } ,
+ {
+ 0xfc008060 U, 0x84000000 U, /* f */ TRASHES
+ } ,
+ {
+ 0xfc008060 U, 0x84000020 U, /* f.d */ TRASHES | DOUBLE
+ } ,
+ {
+ 0xfc000000 U, 0xcc000000 U, /* bsr.n */ FLOW_CTRL | DELAYED | BSR
+ } ,
+ {
+ 0xfc000000 U, 0xc8000000 U, /* bsr */ FLOW_CTRL | BSR
+ } ,
+ {
+ 0xe4000000 U, 0xc4000000 U, /* br/bb.n */ FLOW_CTRL | DELAYED
+ } ,
+ {
+ 0xe4000000 U, 0xc0000000 U, /* br/bb */ FLOW_CTRL
+ } ,
+ {
+ 0xfc000000 U, 0xec000000 U, /* bcnd.n */ FLOW_CTRL | DELAYED
+ } ,
+ {
+ 0xfc000000 U, 0xe8000000 U, /* bcnd */ FLOW_CTRL
+ } ,
+ {
+ 0xfc00c000 U, 0xf0008000 U, /* bits */ TRASHES
+ } ,
+ {
+ 0xfc00c000 U, 0xf000c000 U, /* trap */ 0
+ } ,
+ {
+ 0xfc00f0e0 U, 0xf4002000 U, /* st */ 0
+ } ,
+ {
+ 0xfc00cce0 U, 0xf4000000 U, /* ld.d */ TRASHES | DOUBLE
+ } ,
+ {
+ 0xfc00c0e0 U, 0xf4000000 U, /* ld */ TRASHES
+ } ,
+ {
+ 0xfc00c0e0 U, 0xf4004000 U, /* arith */ TRASHES
+ } ,
+ {
+ 0xfc00c3e0 U, 0xf4008000 U, /* bits */ TRASHES
+ } ,
+ {
+ 0xfc00ffe0 U, 0xf400cc00 U, /* jsr.n */ FLOW_CTRL | DELAYED | JSR
+ } ,
+ {
+ 0xfc00ffe0 U, 0xf400c800 U, /* jsr */ FLOW_CTRL | JSR
+ } ,
+ {
+ 0xfc00ffe0 U, 0xf400c400 U, /* jmp.n */ FLOW_CTRL | DELAYED
+ } ,
+ {
+ 0xfc00ffe0 U, 0xf400c000 U, /* jmp */ FLOW_CTRL
+ } ,
+ {
+ 0xfc00fbe0 U, 0xf400e800 U, /* ff */ TRASHES
+ } ,
+ {
+ 0xfc00ffe0 U, 0xf400f800 U, /* tbnd */ 0
+ } ,
+ {
+ 0xfc00ffe0 U, 0xf400fc00 U, /* rte */ FLOW_CTRL
+ } ,
+ {
+ 0xfc000000 U, 0xf8000000 U, /* tbnd */ 0
+ } ,
+ };
+#define ctrl_count (sizeof(control)/sizeof(control[0]))
+ for (ptr = &control[0]; ptr < &control[ctrl_count]; ptr++)
+ if ((instruction & ptr->mask) == ptr->value)
+ return ptr->flags;
+ SHOW_INSTRUCTION(0, instruction, "bad m88k_instruction_info");
+ return 0;
+}
+
+static int
+hex_value_needs_0x(unsigned value)
+{
+ int i;
+ unsigned last = 0;
+ unsigned char c;
+ unsigned have_a_hex_digit = 0;
+
+ if (value <= 9)
+ return 0;
+
+ for (i = 0; i < 8; i++) {
+ c = value & 0xf;
+ value >>= 4;
+ if (c)
+ last = c;
+ if (c > 9)
+ have_a_hex_digit = 1;
+ }
+ if (have_a_hex_digit == 0)
+ return 1;
+ if (last > 9)
+ return 1;
+ return 0;
+}
+
+
+/*
+ * returns
+ * 1 if regs seems to be a reasonable kernel exception frame.
+ * 2 if regs seems to be a reasonable user exception frame
+ * (in the current task).
+ * 0 if this looks like neither.
+ */
+int
+frame_is_sane(db_regs_t * regs)
+{
+ /* no good if we can't read the whole frame */
+ if (badwordaddr((vm_offset_t) regs) || badwordaddr((vm_offset_t) & regs->mode))
+ return 0;
+
+#ifndef DIAGNOSTIC
+ /* disabled for now -- see fpu_enable in luna88k/eh.s */
+ /* r0 must be 0 (obviously) */
+ if (regs->r[0] != 0)
+ return 0;
+#endif
+
+ /* stack sanity ... r31 must be nonzero, but must be word aligned */
+ if (regs->r[31] == 0 || (regs->r[31] & 3) != 0)
+ return 0;
+
+ /* sxip is reasonable */
+#if 0
+ if ((regs->sxip & 1) == 1)
+ return 0;
+#endif
+ /* snip is reasonable */
+ if ((regs->snip & 3) != 2)
+ return 0;
+ /* sfip is reasonable */
+ if ((regs->sfip & 3) != 2)
+ return 0;
+
+ /* epsr sanity */
+ if ((regs->epsr & 0x8FFFFFF5 U) == 0x800003f0 U) { /* kernel mode */
+ if (regs->epsr & 0x40000000)
+ db_printf("[WARNING: byte order in kernel frame at %x "
+ "is little-endian!]\n", regs);
+ return 1;
+ }
+ if ((regs->epsr & 0x8FFFFFFF U) == 0x000003f0 U) { /* user mode */
+ if (regs->epsr & 0x40000000)
+ db_printf("[WARNING: byte order in user frame at %x "
+ "is little-endian!]\n", regs);
+ return 2;
+ }
+ return 0;
+}
+
+char
+ *
+m88k_exception_name(unsigned vector)
+{
+ switch (vector) {
+ default:
+ case 0:return "Reset";
+ case 1:
+ return "Interrupt";
+ case 2:
+ return "Instruction Access Exception";
+ case 3:
+ return "Data Access Exception";
+ case 4:
+ return "Misaligned Access Exception";
+ case 5:
+ return "Unimplemented Opcode Exception";
+ case 6:
+ return "Privilege Violation";
+ case 7:
+ return "Bounds Check";
+ case 8:
+ return "Integer Divide Exception";
+ case 9:
+ return "Integer Overflow Exception";
+ case 10:
+ return "Error Exception";
+ case 114:
+ return "FPU precise";
+ case 115:
+ return "FPU imprecise";
+ case 130:
+ return "Ddb break";
+ case 131:
+ return "Ddb trace";
+ case 132:
+ return "Ddb trap";
+ case 451:
+ return "Syscall";
+ }
+}
+/*
+ * Read a word at address addr.
+ * Return 1 if was able to read, 0 otherwise.
+ */
+unsigned
+db_trace_get_val(vm_offset_t addr, unsigned *ptr)
+{
+ jmp_buf db_jmpbuf;
+ jmp_buf *prev = db_recover;
+ boolean_t old_quiet_db_read_bytes = quiet_db_read_bytes;
+
+ quiet_db_read_bytes = 1;
+
+ if (setjmp(*(db_recover = &db_jmpbuf)) != 0) {
+ db_recover = prev;
+ quiet_db_read_bytes = old_quiet_db_read_bytes;
+ return 0;
+ } else {
+ db_read_bytes((char *) addr, 4, (char *) ptr);
+ db_recover = prev;
+ quiet_db_read_bytes = old_quiet_db_read_bytes;
+ return 1;
+ }
+}
+
+
+#define FIRST_CALLPRESERVED_REG 14
+#define LAST_CALLPRESERVED_REG 29
+#define FIRST_ARG_REG 2
+#define LAST_ARG_REG 9
+#define RETURN_VAL_REG 1
+
+static unsigned global_saved_list = 0x0; /* one bit per register */
+static unsigned local_saved_list = 0x0; /* one bit per register */
+static unsigned trashed_list = 0x0; /* one bit per register */
+static unsigned saved_reg[32]; /* one value per register */
+
+#define reg_bit(reg) (1<<((reg)%32))
+
+static void
+save_reg(int reg, unsigned value)
+{
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("save_reg(%d, %x)\n", reg, value);
+#endif
+ if (trashed_list & reg_bit(reg)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("<trashed>\n");
+#endif
+ return; /* don't save trashed registers */
+ }
+ saved_reg[(reg % 32)] = value;
+ global_saved_list |= reg_bit(reg);
+ local_saved_list |= reg_bit(reg);
+}
+#define mark_reg_trashed(reg) (trashed_list |= reg_bit(reg))
+
+#define have_global_reg(reg) (global_saved_list & (1<<(reg)))
+#define have_local_reg(reg) (local_saved_list & (1<<(reg)))
+
+#define clear_local_saved_regs() { local_saved_list = trashed_list = 0; }
+#define clear_global_saved_regs() { local_saved_list = global_saved_list = 0; }
+
+#define saved_reg_value(reg) (saved_reg[(reg)])
+
+/*
+ * Show any arguments that we might have been able to determine.
+ */
+static void
+print_args(void)
+{
+ int reg, last_arg;
+
+ /* find the highest argument register saved */
+ for (last_arg = LAST_ARG_REG; last_arg >= FIRST_ARG_REG; last_arg--)
+ if (have_local_reg(last_arg))
+ break;
+ if (last_arg < FIRST_ARG_REG)
+ return; /* none were saved */
+
+ db_printf("(");
+
+ /* print each one, up to the highest */
+ for (reg = FIRST_ARG_REG; /* nothing */ ; reg++) {
+ if (!have_local_reg(reg))
+ db_printf("?");
+ else {
+ unsigned value = saved_reg_value(reg);
+ db_printf("%s%x", hex_value_needs_0x(value) ? "0x" : "", value);
+ }
+ if (reg == last_arg)
+ break;
+ else
+ db_printf(", ");
+ }
+ db_printf(")");
+}
+
+
+#define JUMP_SOURCE_IS_BAD 0
+#define JUMP_SOURCE_IS_OK 1
+#define JUMP_SOURCE_IS_UNLIKELY 2
+
+/*
+ * Give an address to where we return, and an address to where we'd jumped,
+ * Decided if it all makes sense.
+ *
+ * Gcc sometimes optimized something like
+ * if (condition)
+ * func1();
+ * else
+ * OtherStuff...
+ * to
+ * bcnd !condition mark
+ * bsr.n func1
+ * or r1, r0, mark2
+ * mark:
+ * OtherStuff...
+ * mark2:
+ *
+ * So RETURN_TO will be MARK2, even though we really did branch via
+ * 'bsr.n func1', so this makes it difficult to be certaian about being
+ * wrong.
+ */
+static int
+is_jump_source_ok(unsigned return_to, unsigned jump_to)
+{
+ unsigned flags;
+ union instruction instruction;
+
+ /*
+ * Delayed branches are most common... look two instructions before
+ * where we were going to return to to see if it's a delayed branch.
+ */
+ if (!db_trace_get_val(return_to - 8, &instruction.rawbits))
+ return JUMP_SOURCE_IS_BAD;
+ flags = m88k_instruction_info(instruction.rawbits);
+
+ if ((flags & FLOW_CTRL) && (flags & DELAYED) && (flags & (JSR | BSR))) {
+ if (flags & JSR)
+ return JUMP_SOURCE_IS_OK; /* have to assume it's
+ * correct */
+ /* calculate the offset */
+ if (br_dest(return_to - 8, instruction) == jump_to)
+ return JUMP_SOURCE_IS_OK; /* exactamundo! */
+ else
+ return JUMP_SOURCE_IS_UNLIKELY; /* seems wrong */
+ }
+ /*
+ * Try again, looking for a non-delayed jump one back.
+ */
+ if (!db_trace_get_val(return_to - 4, &instruction.rawbits))
+ return JUMP_SOURCE_IS_BAD;
+ flags = m88k_instruction_info(instruction.rawbits);
+
+ if ((flags & FLOW_CTRL) && !(flags & DELAYED) && (flags & (JSR | BSR))) {
+ if (flags & JSR)
+ return JUMP_SOURCE_IS_OK; /* have to assume it's
+ * correct */
+ /* calculate the offset */
+ if (br_dest(return_to - 4, instruction) == jump_to)
+ return JUMP_SOURCE_IS_OK; /* exactamundo! */
+ else
+ return JUMP_SOURCE_IS_UNLIKELY; /* seems wrong */
+ }
+ return JUMP_SOURCE_IS_UNLIKELY;
+}
+
+static char *note = 0;
+static int next_address_likely_wrong = 0;
+
+/* How much slop we expect in the stack trace */
+#define FRAME_PLAY 8
+
+/*
+ * Stack decode -
+ * unsigned addr; program counter
+ * unsigned *stack; IN/OUT stack pointer
+ *
+ * given an address within a function and a stack pointer,
+ * try to find the function from which this one was called
+ * and the stack pointer for that function.
+ *
+ * The return value is zero (if we get confused) or
+ * we determine that the return address has not yet
+ * been saved (early in the function prologue). Otherwise
+ * the return value is the address from which this function
+ * was called.
+ *
+ * Note that even is zero is returned (the second case) the
+ * stack pointer can be adjusted.
+ *
+ */
+static int
+stack_decode(unsigned addr, unsigned *stack)
+{
+ db_sym_t proc;
+ unsigned offset_from_proc;
+ unsigned instructions_to_search;
+ unsigned check_addr;
+ unsigned function_addr; /* start of function */
+ unsigned r31 = *stack; /* the r31 of the function */
+ unsigned inst; /* text of an instruction */
+ unsigned ret_addr; /* address to which we return */
+ unsigned tried_to_save_r1 = 0;
+
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("\n>>>stack_decode(addr=%x, stack=%x)\n",
+ addr, *stack);
+#endif
+
+ /* get what we hope will be the db_sym_t for the function name */
+ proc = db_search_symbol(addr, DB_STGY_PROC, &offset_from_proc);
+ if (offset_from_proc == addr) /* i.e. no symbol found */
+ proc = DB_SYM_NULL;
+
+ /*
+ * Somehow, find the start of this function.
+ * If we found a symbol above, it'll have the address.
+ * Otherwise, we've got to search for it....
+ */
+ if (proc != DB_SYM_NULL) {
+ char *names;
+ db_symbol_values(proc, &names, &function_addr);
+ if (names == 0)
+ return 0;
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("name %s address 0x%x\n",
+ names, function_addr);
+#endif
+ } else {
+ int instructions_to_check = 400;
+ /*
+ * hmm - unable to find symbol. Search back
+ * looking for a function prolog.
+ */
+ for (check_addr = addr; instructions_to_check-- > 0; check_addr -= 4) {
+ if (!db_trace_get_val(check_addr, &inst))
+ break;
+
+ if (SUBU_R31_R31_IMM(inst)) {
+#if 0
+ /*
+ * If the next instruction is "st r1, r31, ####"
+ * then we can feel safe we have the start of
+ * a function.
+ */
+ if (!db_trace_get_val(check_addr + 4, &inst))
+ continue;
+ if (ST_R1_R31_IMM(instr))
+ break; /* sucess */
+#else
+ /*
+ * Latest GCC optimizer is just too good... the store
+ * of r1 might come much later... so we'll have to
+ * settle for just the "subr r31, r31, ###" to mark
+ * the start....
+ */
+ break;
+#endif
+ }
+ /*
+ * if we come across a [jmp r1] or [jmp.n r1] assume we have hit
+ * the previous functions epilogue and stop our search.
+ * Since we know we would have hit the "subr r31, r31" if it was
+ * right in front of us, we know this doesn't have one so
+ * we just return failure....
+ */
+ if (JMP_R1(inst) || JMPN_R1(inst)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("ran into a [jmp r1] at %x (addr=%x)\n",
+ check_addr, addr);
+#endif
+ return 0;
+ }
+ }
+ if (instructions_to_check < 0) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("couldn't find func start (addr=%x)\n", addr);
+#endif
+ return 0; /* bummer, couldn't find it */
+ }
+ function_addr = check_addr;
+ }
+
+ /*
+ * We now know the start of the function (function_addr).
+ * If we're stopped right there, or if it's not a
+ * subu r31, r31, ####
+ * then we're done.
+ */
+ if (addr == function_addr) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("at start of func\n");
+#endif
+ return 0;
+ }
+ if (!db_trace_get_val(function_addr, &inst)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("couldn't read %x at line %d\n",
+ function_addr, __LINE__);
+#endif
+ return 0;
+ }
+ SHOW_INSTRUCTION(function_addr, inst, "start of function: ");
+ if (!SUBU_R31_R31_IMM(inst)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("<not subu,r31,r31,imm>\n");
+#endif
+ return 0;
+ }
+ /* add the size of this frame to the stack (for the next frame) */
+ *stack += IMM16VAL(inst);
+
+ /*
+ * Search from the beginning of the function (funstart) to where we are
+ * in the function (addr) looking to see what kind of registers have
+ * been saved on the stack.
+ *
+ * We'll stop looking before we get to ADDR if we hit a branch.
+ */
+ clear_local_saved_regs();
+ check_addr = function_addr + 4; /* we know the first inst isn't a
+ * store */
+
+ for (instructions_to_search = (addr - check_addr) / sizeof(long);
+ instructions_to_search-- > 0;
+ check_addr += 4) {
+ union instruction instruction;
+ unsigned flags;
+
+ /* read the instruction */
+ if (!db_trace_get_val(check_addr, &instruction.rawbits)) {
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("couldn't read %x at line %d\n",
+ check_addr, __LINE__);
+#endif
+ break;
+ }
+ SHOW_INSTRUCTION(check_addr, instruction.rawbits, "prolog: ");
+
+ /* find out the particulars about this instruction */
+ flags = m88k_instruction_info(instruction.rawbits);
+
+ /* if a store to something off the stack pointer, note the
+ * value */
+ if ((flags & STORE) && instruction.diatic.s1 == /* stack pointer */ 31) {
+ unsigned value;
+ if (!have_local_reg(instruction.diatic.d)) {
+ if (instruction.diatic.d == 1)
+ tried_to_save_r1 = r31 + instruction.diatic.i16;
+ if (db_trace_get_val(r31 + instruction.diatic.i16, &value))
+ save_reg(instruction.diatic.d, value);
+ }
+ if ((flags & DOUBLE) && !have_local_reg(instruction.diatic.d + 1)) {
+ if (instruction.diatic.d == 0)
+ tried_to_save_r1 = r31 + instruction.diatic.i16 + 4;
+ if (db_trace_get_val(r31 + instruction.diatic.i16 + 4, &value))
+ save_reg(instruction.diatic.d + 1, value);
+ }
+ }
+ /* if an inst that kills D (and maybe D+1), note that */
+ if (flags & TRASHES) {
+ mark_reg_trashed(instruction.diatic.d);
+ if (flags & DOUBLE)
+ mark_reg_trashed(instruction.diatic.d + 1);
+ }
+ /* if a flow control instruction, stop now (or next if
+ * delayed) */
+ if ((flags & FLOW_CTRL) && instructions_to_search != 0)
+ instructions_to_search = (flags & DELAYED) ? 1 : 0;
+ }
+
+ /*
+ * If we didn't save r1 at some point, we're hosed.
+ */
+ if (!have_local_reg(1)) {
+ if (tried_to_save_r1) {
+ db_printf(" <return value of next fcn unreadable in %08x>\n",
+ tried_to_save_r1);
+ }
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("didn't save r1\n");
+#endif
+ return 0;
+ }
+ ret_addr = saved_reg_value(1);
+
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("Return value is = %x, function_addr is %x.\n",
+ ret_addr, function_addr);
+#endif
+
+ /*
+ * In support of this, continuation.s puts the low bit on the
+ * return address for continuations (the return address will never
+ * be used, so it's ok to do anything you want to it).
+ */
+ if (ret_addr & 1) {
+ note = "<<can not trace past a continuation>>";
+ ret_addr = 0;
+ } else
+ if (ret_addr != 0x00) {
+ switch (is_jump_source_ok(ret_addr, function_addr)) {
+ case JUMP_SOURCE_IS_OK:
+ break; /* excellent */
+
+ case JUMP_SOURCE_IS_BAD:
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("jump is bad\n");
+#endif
+ return 0; /* bummer */
+
+ case JUMP_SOURCE_IS_UNLIKELY:
+ next_address_likely_wrong = 1;;
+ break;
+ }
+ }
+ return ret_addr;
+}
+
+static void
+db_stack_trace_cmd2(db_regs_t * regs)
+{
+ unsigned stack;
+ unsigned depth = 1;
+ unsigned where;
+ unsigned ft;
+ unsigned pair[2];
+ int i;
+
+ /*
+ * Frame_is_sane returns:
+ * 1 if regs seems to be a reasonable kernel exception frame.
+ * 2 if regs seems to be a reasonable user exception frame
+ * (in the current task).
+ * 0 if this looks like neither.
+ */
+ if (ft = frame_is_sane(regs), ft == 0) {
+ db_printf("Register frame 0x%x is suspicous; skipping trace\n", regs);
+ return;
+ }
+ /* if user space and no user space trace specified, puke */
+ if (ft == 2 && !(trace_flags & TRACE_USER_FLAG))
+ return;
+
+ /* fetch address */
+ /* use sxip if valid, otherwise try snip or sfip */
+ where = ((regs->sxip & 2) ? regs->sxip :
+ ((regs->snip & 2) ? regs->snip :
+ regs->sfip)) & ~3;
+ stack = regs->r[31];
+ db_printf("stack base = 0x%x\n", stack);
+ db_printf("(0) "); /* depth of trace */
+ if (trace_flags & TRACE_SHOWADDRESS_FLAG)
+ db_printf("%08x ", where);
+ db_printsym(where, DB_STGY_PROC);
+ clear_global_saved_regs();
+
+ /* see if this routine had a stack frame */
+ if ((where = stack_decode(where, &stack)) == 0) {
+ where = regs->r[1];
+ db_printf("(stackless)");
+ } else {
+ print_args();
+ if (trace_flags & TRACE_SHOWFRAME_FLAG)
+ db_printf(" [frame 0x%x]", stack);
+ }
+ db_printf("\n");
+ if (note) {
+ db_printf(" %s\n", note);
+ note = 0;
+ }
+ do {
+ /*
+ * If requested, show preserved registers at the time
+ * the next-shown call was made. Only registers known to have
+ * changed from the last exception frame are shown, as others
+ * can be gotten at by looking at the exception frame.
+ */
+ if (trace_flags & TRACE_SHOWCALLPRESERVED_FLAG) {
+ int r, title_printed = 0;
+
+ for (r = FIRST_CALLPRESERVED_REG; r <= LAST_CALLPRESERVED_REG; r++) {
+ if (have_global_reg(r)) {
+ unsigned value = saved_reg_value(r);
+ if (title_printed == 0) {
+ title_printed = 1;
+ db_printf("[in next func:");
+ }
+ if (value == 0)
+ db_printf(" r%d", r);
+ else
+ if (value <= 9)
+ db_printf(" r%d=%x", r, value);
+ else
+ db_printf(" r%d=x%x", r, value);
+ }
+ }
+ if (title_printed)
+ db_printf("]\n");
+ }
+ db_printf("(%d)%c", depth++, next_address_likely_wrong ? '?' : ' ');
+ next_address_likely_wrong = 0;
+
+ if (trace_flags & TRACE_SHOWADDRESS_FLAG)
+ db_printf("%08x ", where);
+ db_printsym(where, DB_STGY_PROC);
+ where = stack_decode(where, &stack);
+ print_args();
+ if (trace_flags & TRACE_SHOWFRAME_FLAG)
+ db_printf(" [frame 0x%x]", stack);
+ db_printf("\n");
+ if (note) {
+ db_printf(" %s\n", note);
+ note = 0;
+ }
+ } while (where);
+
+ /* try to trace back over trap/exception */
+
+ stack &= ~7; /* double word aligned */
+ /* take last top of stack, and try to find an exception frame near it */
+
+ i = FRAME_PLAY;
+
+#ifdef TRACE_DEBUG
+ if (DEBUGGING_ON)
+ db_printf("(searching for exception frame at 0x%x)\n", stack);
+#endif
+
+ while (i) {
+ /*
+ * On the stack, a pointer to the exception frame is written
+ * in two adjacent words. In the case of a fault from the kernel,
+ * this should point to the frame right above them:
+ *
+ * Exception Frame Top
+ * ..
+ * Exception Frame Bottom <-- frame addr
+ * frame addr
+ * frame addr <-- stack pointer
+ *
+ * In the case of a fault from user mode, the top of stack
+ * will just have the address of the frame
+ * replicated twice.
+ *
+ * frame addr <-- top of stack
+ * frame addr
+ *
+ * Here we are just looking for kernel exception frames.
+ */
+
+ if (badwordaddr((vm_offset_t) stack) ||
+ badwordaddr((vm_offset_t) (stack + 4)))
+ break;
+
+ db_read_bytes((char *) stack, 2 * sizeof(int), (char *) pair);
+
+ /* the pairs should match and equal stack+8 */
+ if (pair[0] == pair[1]) {
+ if (pair[0] != stack + 8) {
+ /*
+ if (!badwordaddr((vm_offset_t)pair[0]) && (pair[0]!=0))
+ db_printf("stack_trace:found pair 0x%x but != to stack+8\n",
+ pair[0]);
+ */
+ } else
+ if (frame_is_sane((db_regs_t *) pair[0])) {
+ db_regs_t *frame = (db_regs_t *) pair[0];
+ char *cause = m88k_exception_name(frame->vector);
+
+ db_printf("-------------- %s [EF: 0x%x] -------------\n",
+ cause, frame);
+ db_stack_trace_cmd2(frame);
+ return;
+ }
+#ifdef TRACE_DEBUG
+ else
+ if (DEBUGGING_ON)
+ db_printf("pair matched, but frame at 0x%x looks insane\n",
+ stack + 8);
+#endif
+ }
+ stack += 8;
+ i--;
+ }
+
+ /*
+ * If we go here, crawling back on the stack failed to find us
+ * a previous exception frame. Look for a user frame pointer
+ * pointed to by a word 8 bytes off of the top of the stack
+ * if the "u" option was specified.
+ */
+ if (trace_flags & TRACE_USER_FLAG) {
+ db_regs_t *user;
+
+ /* Make sure we are back on the right page */
+ stack -= 4 * FRAME_PLAY;
+ stack = stack & ~(KERNEL_STACK_SIZE - 1); /* point to the bottom */
+ stack += KERNEL_STACK_SIZE - 8;
+
+ if (badwordaddr((vm_offset_t) stack) ||
+ badwordaddr((vm_offset_t) stack))
+ return;
+
+ db_read_bytes((char *) stack, 2 * sizeof(int), (char *) pair);
+ if (pair[0] != pair[1])
+ return;
+
+ /* have a hit */
+ user = *((db_regs_t **) stack);
+
+ if (frame_is_sane(user) == 2) {
+ db_printf("---------------- %s [EF : 0x%x] -------------\n",
+ m88k_exception_name(user->vector), user);
+ db_stack_trace_cmd2(user);
+ }
+ }
+}
+/*
+ * stack trace - needs a pointer to a m88k saved state.
+ *
+ * If argument f is given, the stack pointer of each call frame is
+ * printed.
+ */
+void
+db_stack_trace_cmd(
+ db_regs_t * addr,
+ int have_addr,
+ db_expr_t count,
+ char *modif)
+{
+ enum {
+ Default, Stack, Proc, Frame
+ } style = Default;
+ db_regs_t frame; /* a m88100_saved_state */
+ db_regs_t *regs;
+ union {
+ db_regs_t *frame;
+ struct proc *proc;
+ unsigned num;
+ } arg;
+ arg.frame = addr;
+
+ trace_flags = 0; /* flags will be set via modifers */
+
+ while (modif && *modif) {
+ switch (*modif++) {
+ case 'd':
+#ifdef TRACE_DEBUG
+ trace_flags |= TRACE_DEBUG_FLAG;
+#else
+ db_printtf("<debug trace not compiled in, ignoring>\n");
+#endif
+ break;
+
+ case 's':
+ style = Stack;
+ break;
+ case 'f':
+ style = Frame;
+ break;
+ case 'p':
+ trace_flags |= TRACE_SHOWCALLPRESERVED_FLAG;
+ break;
+ case 'a':
+ trace_flags |= TRACE_SHOWADDRESS_FLAG;
+ break;
+ case 'F':
+ trace_flags |= TRACE_SHOWFRAME_FLAG;
+ break;
+ case 'u':
+ trace_flags |= TRACE_USER_FLAG;
+ break;
+ default:
+ db_printf("unknown trace modifier [%c]\n", modif[-1]);
+ /* FALLTHROUGH */
+ case 'h':
+ db_printf("usage: trace/[MODIFIER] [ARG]\n");
+ db_printf(" u = include user trace\n");
+ db_printf(" F = print stack frames\n");
+ db_printf(" a = show return addresses\n");
+ db_printf(" p = show call-preserved registers\n");
+ db_printf(" s = ARG is a stack pointer\n");
+ db_printf(" f = ARG is a frame pointer\n");
+#ifdef TRACE_DEBUG
+ db_printf(" d = trace-debugging output\n");
+#endif
+ return;
+ }
+ }
+
+ if (!have_addr && style != Default) {
+ db_printf("expecting argument with /s or /f\n");
+ return;
+ }
+ if (have_addr && style == Default)
+ style = Proc;
+
+ switch (style) {
+ case Default:
+ regs = DDB_REGS;
+ break;
+
+ case Frame:
+ regs = arg.frame;
+ break;
+
+ case Stack:
+ {
+ unsigned val1, val2, sxip;
+ unsigned ptr;
+ bzero((void *) &frame, sizeof(frame));
+#define REASONABLE_FRAME_DISTANCE 2048
+
+ /*
+ * We've got to find the top of a stack frame so we can get both
+ * a PC and and real SP.
+ */
+ for (ptr = arg.num; /**/ ; ptr += 4) {
+ /* Read a word from the named stack */
+ if (db_trace_get_val(ptr, &val1) == 0) {
+ db_printf("can't read from %x, aborting.\n", ptr);
+ return;
+ }
+ /*
+ * See if it's a frame pointer.... if so it will be larger than
+ * the address it was taken from (i.e. point back up the stack)
+ * and we'll be able to read where it points.
+ */
+ if (val1 <= ptr ||
+ (val1 & 3) ||
+ val1 > (ptr + REASONABLE_FRAME_DISTANCE))
+ continue;
+
+ /* peek at the next word to see if it could be
+ * a return address */
+ if (db_trace_get_val(ptr, &sxip) == 0) {
+ db_printf("can't read from %x, aborting.\n", ptr);
+ return;
+ }
+ if (sxip == 0 || !db_trace_get_val(sxip, &val2))
+ continue;
+
+ if (db_trace_get_val(val1, &val2) == 0) {
+ db_printf("can't read from %x, aborting.\n", val1);
+ continue;
+ }
+ /*
+ * The value we've just read will be either another frame pointer,
+ * or the start of another exception frame.
+ */
+ if (
+#ifdef JEFF_DEBUG
+ val2 == 0
+#else
+ val2 == 0x12345678
+#endif
+ && db_trace_get_val(val1 - 4, &val2) && val2 == val1
+ && db_trace_get_val(val1 - 8, &val2) && val2 == val1) {
+ /* we've found a frame, so the stack
+ * must have been good */
+ db_printf("%x looks like a frame, accepting %x\n", val1, ptr);
+ break;
+ }
+ if (val2 > val1 && (val2 & 3) == 0) {
+ /* well, looks close enough to be
+ * another frame pointer */
+ db_printf("*%x = %x looks like a stack frame pointer, accepting %x\n", val1, val2, ptr);
+ break;
+ }
+ }
+
+ frame.r[31] = ptr;
+ frame.epsr = 0x800003f0 U;
+ frame.sxip = sxip | 2;
+ frame.snip = frame.sxip + 4;
+ frame.sfip = frame.snip + 4;
+ db_printf("[r31=%x, sxip=%x]\n", frame.r[31], frame.sxip);
+ regs = &frame;
+ }
+ }
+
+ db_stack_trace_cmd2(regs);
+}