code:
/*	$OpenBSD: db_disasm.c,v 1.6 2004/01/15 17:22:28 miod Exp $	*/
/*	$NetBSD: db_disasm.c,v 1.9 2000/08/16 11:29:42 pk Exp $ */

/*
 * Copyright (c) 1994 David S. Miller, davem@nadzieja.rutgers.edu
 * Copyright (c) 1995 Paul Kranenburg
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by David Miller.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/param.h>
#include <machine/db_machdep.h>
#include <machine/instr.h>
#include <ddb/db_sym.h>
#include <ddb/db_interface.h>
#include <ddb/db_extern.h>
#include <ddb/db_output.h>
#include <ddb/db_access.h>

#ifndef V9
#define V9
#endif

/* Sign extend values */
#ifdef	V9
#define	SIGNEX(v,width)		((((long long)(v))<<(64-width))>>(64-width))
#else
#define	SIGNEX(v,width)		((((int)(v))<<(32-width))>>(32-width))
#endif
#define SIGN(v)			(((v)<0)?"-":"")

/*
 * All Sparc instructions are 32-bits, with the one exception being
 * the set instruction which is actually a macro which expands into
 * two instructions...
 *
 * There are 5 different fields that can be used to identify which
 * operation is encoded into a particular 32-bit insn. There are 3
 * formats for instructions, which one being used is determined by
 * bits 30-31 of the insn. Here are the bit fields and their names:
 *
 * 1100 0000 0000 0000 0000 0000 0000 0000 op field, determines format
 * 0000 0001 1100 0000 0000 0000 0000 0000 op2 field, format 2 only
 * 0000 0001 1111 1000 0000 0000 0000 0000 op3 field, format 3 only
 * 0000 0000 0000 0000 0010 0000 0000 0000 f3i bit, format 3 only
 * 0000 0000 0000 0000 0001 0000 0000 0000 X bit, format 3 only
 */

#define OP(x)	(((x) & 0x3) << 30)
#define OP2(x)	(((x) & 0x7) << 22)
#define OP3(x)	(((x) & 0x3f) << 19)
#define OPF(x)	(((x) & 0x1ff) << 5)
#define F3I(x)	(((x) & 0x1) << 13)

/* various other fields */

#define A(x)		(((x) & 0x1) << 29)
#define P(x)		(((x) & 0x1) << 19)
#define X(x)		(((x) & 0x1) << 12)
#define FCN(x)		(((x) & 0x1f) << 25)
#define RCOND2(x)	(((x) & 0x7) << 25)
#define RCOND34(x)	(((x) & 0x7) << 10)
#define COND(x)		(((x) & 0xf) << 25)
#define SW_TRAP(x)	((x) & 0x7f)
#define SHCNT32(x)	((x) & 0x1f)
#define SHCNT64(x)	((x) & 0x3f)
#define IMM11(x)	((x) & 0x7ff)
#define IMM22(x)	((x) & 0x3fffff)
#define DISP19(x)	((x) & 0x7ffff)
#define DISP22(x)	((x) & 0x3fffff)
#define DISP30(x)	((x) & 0x3fffffffL)

/* Register Operand Fields */
#define RS1(x)		(((x) & 0x1f) << 14)
#define RS2(x)		((x) & 0x1f)
#define RD(x)		(((x) & 0x1f) << 25)

/* FORMAT macros used in sparc_i table to decode each opcode */
#define FORMAT1(a)	(OP(a))
#define FORMAT2(a,b)	(OP(a) | OP2(b))
#define FORMAT3(a,b,c)	(OP(a) | OP3(b) | F3I(c))
#define FORMAT3F(a,b,c)	(OP(a) | OP3(b) | OPF(c))

/* Helper macros to construct OP3 & OPF */
#define OP3_X(x,y)	((((x) & 3) << 4) | ((y) & 0xf))
#define OPF_X(x,y)	((((x) & 0x1f) << 4) | ((y) & 0xf))

/* COND condition codes field... */
#define COND2(y,x)	(((((y)<<4) & 1)|((x) & 0xf)) << 14)

struct sparc_insn {
	  unsigned int match;
	  char *name;
	  char *format;
};

char *regs[] = {
	"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
	"o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
	"l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
	"i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7"
};

char *priv_regs[] = {
	"tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
	"pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
	"wstate", "fq",
	"", "", "", "", "", "", "", "",
	"", "", "", "", "", "", "", "ver"
};

char *state_regs[] = {
	"y", "", "ccr", "asi", "tick", "pc", "fprs", "asr",
	"", "", "", "", "", "", "", "",
	"pcr", "pic", "dcr", "gsr", "set_softint", "clr_softint", "softint", "tick_cmpr", "",
	"", "", "", "", "", "", "", ""
};

char *ccodes[] = {
	"fcc0", "fcc1", "fcc2", "fcc3", "icc", "", "xcc", ""
};

char *prefetch[] = {
	"n_reads", "one_read", "n_writes", "one_write", "page"
};

/* The sparc instruction table has a format field which tells what
   the operand structure for this instruction is. Here are the codes:

Modifiers (nust be first):
	a -- opcode has annul bit
	p -- opcode has branch prediction bit

Codes:
        1 -- source register operand stored in rs1
	2 -- source register operand stored in rs2
	d -- destination register operand stored in rd
	3 -- floating source register in rs1
	4 -- floating source register in rs2
	e -- floating destination register in rd
	i -- 13-bit immediate value stored in simm13
	j -- 11-bit immediate value stored in simm11
	l -- displacement using d16lo and d16hi
	m -- 22-bit fcc displacement value
	n -- 30-bit displacement used in call insns
	o -- %fcc number specified in cc1 and cc0 fields
	p -- address computed by the contents of rs1+rs2
	q -- address computed by the contents of rs1+simm13
	r -- prefetch
	s -- %asi is implicit in the insn, rs1 value not used
	t -- immediate 8-bit asi value
	u -- 19-bit fcc displacement value
	5 -- hard register, %fsr lower-half
	6 -- hard register, %fsr all
	7 -- [reg_addr rs1+rs2] imm_asi
	8 -- [reg_addr rs1+simm13] %asi
	9 -- logical or of the cmask and mmask fields (membar insn)
	0 -- icc or xcc condition codes register
	. -- %fcc, %icc, or %xcc in opf_cc field
	r -- prefection function stored in fcn field
	A -- privileged register encoded in rs1
	B -- state register encoded in rs1
	C -- %hi(value) where value is stored in imm22 field
	D -- 32-bit shift count in shcnt32
	E -- 64-bit shift count in shcnt64
	F -- software trap number stored in sw_trap
	G -- privileged register encoded in rd
	H -- state register encoded in rd

V8 only:
	Y -- write y register
	P -- write psr register
	T -- write tbr register
	W -- write wim register
*/

struct sparc_insn sparc_i[] = {

	/*
	 * Format 1: Call
	 */
	{(FORMAT1(1)), "call", "n"},

	/*
	 * Format 0: Sethi & Branches
	 */
	/* Illegal Instruction Trap */
	{(FORMAT2(0, 0)), "illtrap", "m"},

	/* Note: if imm22 is zero then this is actually a "nop" grrr... */
	{(FORMAT2(0, 0x4)), "sethi", "Cd"},

	/* Branch on Integer Co`ndition Codes "Bicc" */
	{(FORMAT2(0, 2) | COND(8)), "ba", "a,m"},
	{(FORMAT2(0, 2) | COND(0)), "bn", "a,m"},
	{(FORMAT2(0, 2) | COND(9)), "bne", "a,m"},
	{(FORMAT2(0, 2) | COND(1)), "be", "a,m"},
	{(FORMAT2(0, 2) | COND(10)), "bg", "a,m"},
	{(FORMAT2(0, 2) | COND(2)), "ble", "a,m"},
	{(FORMAT2(0, 2) | COND(11)), "bge", "a,m"},
	{(FORMAT2(0, 2) | COND(3)), "bl", "a,m"},
	{(FORMAT2(0, 2) | COND(12)), "bgu", "a,m"},
	{(FORMAT2(0, 2) | COND(4)), "bleu", "a,m"},
	{(FORMAT2(0, 2) | COND(13)), "bcc", "a,m"},
	{(FORMAT2(0, 2) | COND(5)), "bcs", "a,m"},
	{(FORMAT2(0, 2) | COND(14)), "bpos", "a,m"},
	{(FORMAT2(0, 2) | COND(6)), "bneg", "a,m"},
	{(FORMAT2(0, 2) | COND(15)), "bvc", "a,m"},
	{(FORMAT2(0, 2) | COND(7)), "bvs", "a,m"},

	/* Branch on Integer Condition Codes with Prediction "BPcc" */
	{(FORMAT2(0, 1) | COND(8)), "ba", "ap,u"},
	{(FORMAT2(0, 1) | COND(0)), "bn", "ap,u"},
	{(FORMAT2(0, 1) | COND(9)), "bne", "ap,u"},
	{(FORMAT2(0, 1) | COND(1)), "be", "ap,u"},
	{(FORMAT2(0, 1) | COND(10)), "bg", "ap,u"},
	{(FORMAT2(0, 1) | COND(2)), "ble", "ap,u"},
	{(FORMAT2(0, 1) | COND(11)), "bge", "ap,u"},
	{(FORMAT2(0, 1) | COND(3)), "bl", "ap,u"},
	{(FORMAT2(0, 1) | COND(12)), "bgu", "ap,u"},
	{(FORMAT2(0, 1) | COND(4)), "bleu", "ap,u"},
	{(FORMAT2(0, 1) | COND(13)), "bcc", "ap,u"},
	{(FORMAT2(0, 1) | COND(5)), "bcs", "ap,u"},
	{(FORMAT2(0, 1) | COND(14)), "bpos", "ap,u"},
	{(FORMAT2(0, 1) | COND(6)), "bneg", "ap,u"},
	{(FORMAT2(0, 1) | COND(15)), "bvc", "ap,u"},
	{(FORMAT2(0, 1) | COND(7)), "bvs", "ap,u"},

	/* Branch on Integer Register with Prediction "BPr" */
	{(FORMAT2(0, 3) | RCOND2(1)), "brz", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(2)), "brlez", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(3)), "brlz", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(5)), "brnz", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(6)), "brgz", "ap,1l"},
	{(FORMAT2(0, 3) | RCOND2(7)), "brgez", "ap,1l"},

	/* Branch on Floating-Point Condition Codes with Prediction "FBPfcc" */
	{(FORMAT2(0, 5) | COND(8)), "fba", "ap,m"},
	{(FORMAT2(0, 5) | COND(0)), "fbn", "ap,m"},
	{(FORMAT2(0, 5) | COND(7)), "fbu", "ap,m"},
	{(FORMAT2(0, 5) | COND(6)), "fbg", "ap,m"},
	{(FORMAT2(0, 5) | COND(5)), "fbug", "ap,m"},
	{(FORMAT2(0, 5) | COND(4)), "fbl", "ap,m"},
	{(FORMAT2(0, 5) | COND(3)), "fbul", "ap,m"},
	{(FORMAT2(0, 5) | COND(2)), "fblg", "ap,m"},
	{(FORMAT2(0, 5) | COND(1)), "fbne", "ap,m"},
	{(FORMAT2(0, 5) | COND(9)), "fbe", "ap,m"},
	{(FORMAT2(0, 5) | COND(10)), "fbue", "ap,m"},
	{(FORMAT2(0, 5) | COND(11)), "fbge", "ap,m"},
	{(FORMAT2(0, 5) | COND(12)), "fbuge", "ap,m"},
	{(FORMAT2(0, 5) | COND(13)), "fble", "ap,m"},
	{(FORMAT2(0, 5) | COND(14)), "fbule", "ap,m"},
	{(FORMAT2(0, 5) | COND(15)), "fbo", "ap,m"},

	/* Branch on Floating-Point Condition Codes "FBfcc" */
	{(FORMAT2(0, 6) | COND(8)), "fba", "a,m"},
	{(FORMAT2(0, 6) | COND(0)), "fbn", "a,m"},
	{(FORMAT2(0, 6) | COND(7)), "fbu", "a,m"},
	{(FORMAT2(0, 6) | COND(6)), "fbg", "a,m"},
	{(FORMAT2(0, 6) | COND(5)), "fbug", "a,m"},
	{(FORMAT2(0, 6) | COND(4)), "fbl", "a,m"},
	{(FORMAT2(0, 6) | COND(3)), "fbul", "a,m"},
	{(FORMAT2(0, 6) | COND(2)), "fblg", "a,m"},
	{(FORMAT2(0, 6) | COND(1)), "fbne", "a,m"},
	{(FORMAT2(0, 6) | COND(9)), "fbe", "a,m"},
	{(FORMAT2(0, 6) | COND(10)), "fbue", "a,m"},
	{(FORMAT2(0, 6) | COND(11)), "fbge", "a,m"},
	{(FORMAT2(0, 6) | COND(12)), "fbuge", "a,m"},
	{(FORMAT2(0, 6) | COND(13)), "fble", "a,m"},
	{(FORMAT2(0, 6) | COND(14)), "fbule", "a,m"},
	{(FORMAT2(0, 6) | COND(15)), "fbo", "a,m"},

	/*
	 * Format 3/2: Arithmetic & misc (table 32, appendix E)
	 */
	{FORMAT3(2, OP3_X(0,0), 0), "add", "12d"},
	{FORMAT3(2, OP3_X(0,0), 1), "add", "1id"},
	{FORMAT3(2, OP3_X(1,0), 0), "addcc", "12d"},
	{FORMAT3(2, OP3_X(1,0), 1), "addcc", "1id"},
	{FORMAT3(2, OP3_X(2,0), 0), "taddcc", "12d"},
	{FORMAT3(2, OP3_X(2,0), 1), "taddcc", "1id"},
#ifdef V9
	{(FORMAT3(2, 0x30, 1) | RD(0xf)), "sir", "i"},
	{FORMAT3(2, OP3_X(3,0), 0), "wr", "12H"},
	{FORMAT3(2, OP3_X(3,0), 1), "wr", "1iH"},
#else
	{FORMAT3(2, OP3_X(3,0), 0), "wr", "12Y"}, /* wr 1, 2, %y  */
	{FORMAT3(2, OP3_X(3,0), 1), "wr", "1iY"}, /* wr 1, i, %y */
#endif

	{FORMAT3(2, OP3_X(0,1), 0), "and", "12d"},
	{FORMAT3(2, OP3_X(0,1), 1), "and", "1id"},
	{FORMAT3(2, OP3_X(1,1), 0), "andcc", "12d"},
	{FORMAT3(2, OP3_X(1,1), 1), "andcc", "1id"},
	{FORMAT3(2, OP3_X(2,1), 0), "tsubcc", "12d"},
	{FORMAT3(2, OP3_X(2,1), 1), "tsubcc", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(3,1), 0), "saved", ""},
	{FORMAT3(2, OP3_X(3,1), 0)|FCN(1), "restored", ""},
#else
	{FORMAT3(2, OP3_X(3,1), 0), "wr", "12P"}, /* wr 1, 2, %psr  */
	{FORMAT3(2, OP3_X(3,1), 1), "wr", "1iP"}, /* wr 1, i, %psr */
#endif

	{FORMAT3(2, OP3_X(0,2), 0), "or", "12d"},
	{FORMAT3(2, OP3_X(0,2), 1), "or", "1id"},
	{FORMAT3(2, OP3_X(1,2), 0), "orcc", "12d"},
	{FORMAT3(2, OP3_X(1,2), 1), "orcc", "1id"},
	{FORMAT3(2, OP3_X(2,2), 0), "taddcctv", "12d"},
	{FORMAT3(2, OP3_X(2,2), 1), "taddcctv", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(3,2), 0), "wrpr", "12G"},
	{FORMAT3(2, OP3_X(3,2), 1), "wrpr", "1iG"},
#else
	{FORMAT3(2, OP3_X(3,2), 0), "wr", "12W"}, /* wr 1, 2, %wim */
	{FORMAT3(2, OP3_X(3,2), 1), "wr", "1iW"}, /* wr 1, i, %wim */
#endif

	{FORMAT3(2, OP3_X(0,3), 0), "xor", "12d"},
	{FORMAT3(2, OP3_X(0,3), 1), "xor", "1id"},
	{FORMAT3(2, OP3_X(1,3), 0), "xorcc", "12d"},
	{FORMAT3(2, OP3_X(1,3), 1), "xorcc", "1id"},
	{FORMAT3(2, OP3_X(2,3), 0), "tsubcctv", "12d"},
	{FORMAT3(2, OP3_X(2,3), 1), "tsubcctv", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(3,3), 0), "UNDEFINED", ""},
#else
	{FORMAT3(2, OP3_X(3,3), 0), "wr", "12T"}, /* wr 1, 2, %tbr */
	{FORMAT3(2, OP3_X(3,3), 1), "wr", "1iT"}, /* wr 1, i, %tbr */
#endif

	{FORMAT3(2, OP3_X(0,4), 0), "sub", "12d"},
	{FORMAT3(2, OP3_X(0,4), 1), "sub", "1id"},
	{FORMAT3(2, OP3_X(1,4), 0), "subcc", "12d"},
	{FORMAT3(2, OP3_X(1,4), 1), "subcc", "1id"},
	{FORMAT3(2, OP3_X(2,4), 0), "mulscc", "12d"},
	{FORMAT3(2, OP3_X(2,4), 1), "mulscc", "1id"},
	{FORMAT3(2, OP3_X(3,4), 1), "FPop1", ""},	/* see below */

	{FORMAT3(2, OP3_X(0,5), 0), "andn", "12d"},
	{FORMAT3(2, OP3_X(0,5), 1), "andn", "1id"},
	{FORMAT3(2, OP3_X(1,5), 0), "andncc", "12d"},
	{FORMAT3(2, OP3_X(1,5), 1), "andncc", "1id"},
	{FORMAT3(2, OP3_X(2,5), 0), "sll", "12d"},
	{FORMAT3(2, OP3_X(2,5), 1), "sll", "1Dd"},
	{FORMAT3(2, OP3_X(2,5), 0)|X(1), "sllx", "12d"},
	{FORMAT3(2, OP3_X(2,5), 1)|X(1), "sllx", "1Ed"},
	{FORMAT3(2, OP3_X(3,5), 1), "FPop2", ""},	/* see below */

	{FORMAT3(2, OP3_X(0,6), 0), "orn", "12d"},
	{FORMAT3(2, OP3_X(0,6), 1), "orn", "1id"},
	{FORMAT3(2, OP3_X(1,6), 0), "orncc", "12d"},
	{FORMAT3(2, OP3_X(1,6), 1), "orncc", "1id"},
	{FORMAT3(2, OP3_X(2,6), 0), "srl", "12d"},
	{FORMAT3(2, OP3_X(2,6), 1), "srl", "1Dd"},
	{FORMAT3(2, OP3_X(2,6), 0)|X(1), "srlx", "12d"},
	{FORMAT3(2, OP3_X(2,6), 1)|X(1), "srlx", "1Ed"},
	{FORMAT3(2, OP3_X(3,6), 1), "impdep1", ""},

	{FORMAT3(2, OP3_X(0,7), 0), "xorn", "12d"},
	{FORMAT3(2, OP3_X(0,7), 1), "xorn", "1id"},
	{FORMAT3(2, OP3_X(1,7), 0), "xorncc", "12d"},
	{FORMAT3(2, OP3_X(1,7), 1), "xorncc", "1id"},
	{FORMAT3(2, OP3_X(2,7), 0), "sra", "12d"},
	{FORMAT3(2, OP3_X(2,7), 1), "sra", "1Dd"},
	{FORMAT3(2, OP3_X(2,7), 0)|X(1), "srax", "12d"},
	{FORMAT3(2, OP3_X(2,7), 1)|X(1), "srax", "1Ed"},
	{FORMAT3(2, OP3_X(3,7), 1), "impdep2", ""},

	{FORMAT3(2, OP3_X(0,8), 0), "addc", "12d"},
	{FORMAT3(2, OP3_X(0,8), 1), "addc", "1id"},
	{FORMAT3(2, OP3_X(1,8), 0), "addccc", "12d"},
	{FORMAT3(2, OP3_X(1,8), 1), "addccc", "1id"},
#ifdef V9
	{(FORMAT3(2, 0x28, 1) | RS1(15)), "membar", "9"},
	{(FORMAT3(2, 0x28, 0) | RS1(15)), "stbar", ""},
	{FORMAT3(2, OP3_X(2,8), 0), "rd", "Bd"},
#else
	{FORMAT3(2, OP3_X(2,8), 0), "rd", "Yd"},
#endif

	{FORMAT3(2, OP3_X(3,8), 0), "jmpl", "pd"},
	{FORMAT3(2, OP3_X(3,8), 1), "jmpl", "qd"},

	{FORMAT3(2, OP3_X(0,9), 0), "mulx", "12d"},
	{FORMAT3(2, OP3_X(0,9), 1), "mulx", "1id"},
	{FORMAT3(2, OP3_X(1,9), 0), "UNDEFINED", ""},
#ifdef V9
	{FORMAT3(2, OP3_X(2,9), 0), "UNDEFINED", ""},
#else
	{FORMAT3(2, OP3_X(2,9), 0), "rd", "Pd"},
#endif
	{FORMAT3(2, OP3_X(3,9), 0), "return", "p"},
	{FORMAT3(2, OP3_X(3,9), 1), "return", "q"},

	{FORMAT3(2, OP3_X(0,10), 0), "umul", "12d"},
	{FORMAT3(2, OP3_X(0,10), 1), "umul", "1id"},
	{FORMAT3(2, OP3_X(1,10), 0), "umulcc", "12d"},
	{FORMAT3(2, OP3_X(1,10), 1), "umulcc", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(2,10), 0), "rdpr", "Ad"},
#else
	{FORMAT3(2, OP3_X(2,10), 0), "rd", "Wd"},
#endif
		/*
		 * OP3 = (3,10): TCC: Trap on Integer Condition Codes
		 */
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x8)), "ta", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x8)), "ta", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x0)), "tn", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x0)), "tn", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x9)), "tne", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x9)), "tne", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x1)), "te", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x1)), "te", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xa)), "tg", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xa)), "tg", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x2)), "tle", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x2)), "tle", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xb)), "tge", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xb)), "tge", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x3)), "tl", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x3)), "tl", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xc)), "tgu", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xc)), "tgu", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x4)), "tleu", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x4)), "tleu", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xd)), "tcc", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xd)), "tcc", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x5)), "tcs", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x5)), "tcs", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xe)), "tpos", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xe)), "tpos", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x6)), "tneg", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x6)), "tneg", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0xf)), "tvc", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0xf)), "tvc", "0F"},
		{(FORMAT3(2, OP3_X(3,10), 0) | COND(0x7)), "tvs", "12F"},
		{(FORMAT3(2, OP3_X(3,10), 1) | COND(0x7)), "tvs", "0F"},

	{FORMAT3(2, OP3_X(0,11), 0), "smul", "12d"},
	{FORMAT3(2, OP3_X(0,11), 1), "smul", "1id"},
	{FORMAT3(2, OP3_X(1,11), 0), "smulcc", "12d"},
	{FORMAT3(2, OP3_X(1,11), 1), "smulcc", "1id"},
#ifdef V9
	{FORMAT3(2, OP3_X(2,11), 0), "flushw", ""},
#else
	{FORMAT3(2, OP3_X(2,11), 0), "rd", "Td"},
#endif
	{FORMAT3(2, OP3_X(3,11), 0), "flush", "p"},
	{FORMAT3(2, OP3_X(3,11), 1), "flush", "q"},

	{FORMAT3(2, OP3_X(0,12), 0), "subc", "12d"},
	{FORMAT3(2, OP3_X(0,12), 1), "subc", "1id"},
	{FORMAT3(2, OP3_X(1,12), 0), "subccc", "12d"},
	{FORMAT3(2, OP3_X(1,12), 1), "subccc", "1id"},
		/*
		 * OP3 = (2,12): MOVcc, Move Integer Register on Condition
		 */
		/* For Integer Condition Codes */
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,8)), "mova", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,8)), "mova", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,0)), "movn", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,0)), "movn", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,9)), "movne", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,9)), "movne", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,1)), "move", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,1)), "move", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,10)), "movg", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,10)), "movg", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,2)), "movle", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,2)), "movle", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,11)), "movge", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,11)), "movge", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,3)), "movl", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,3)), "movl", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,12)), "movgu", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,12)), "movgu", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,4)), "movleu", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,4)), "movleu", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,13)), "movcc", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,13)), "movcc", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,5)), "movcs", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,5)), "movcs", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,14)), "movpos", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,14)), "movpos", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,6)), "movneg", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,6)), "movneg", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,15)), "movvc", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,15)), "movvc", "02d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(1,7)), "movvs", "0jd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(1,7)), "movvs", "02d"},

		/* For Floating-Point Condition Codes */
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,8)), "mova", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,8)), "mova", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,0)), "movn", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,0)), "movn", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,7)), "movu", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,7)), "movu", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,6)), "movg", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,6)), "movg", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,5)), "movug", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,5)), "movug", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,4)), "movl", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,4)), "movl", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,3)), "movul", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,3)), "movul", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,2)), "movlg", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,2)), "movlg", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,1)), "movne", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,1)), "movne", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,9)), "move", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,9)), "move", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,10)), "movue", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,10)), "movue", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,11)), "movge", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,11)), "movge", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,12)), "movuge", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,12)), "movuge", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,13)), "movle", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,13)), "movle", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,14)), "movule", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,14)), "movule", "o2d"},
		{(FORMAT3(2, OP3_X(2,12), 1) | COND2(0,15)), "movo", "ojd"},
		{(FORMAT3(2, OP3_X(2,12), 0) | COND2(0,15)), "movo", "o2d"},

	{FORMAT3(2, OP3_X(3,12), 0), "save", "12d"},
	{FORMAT3(2, OP3_X(3,12), 1), "save", "1id"},

	{FORMAT3(2, OP3_X(0,13), 0), "udivx", "12d"},
	{FORMAT3(2, OP3_X(0,13), 1), "udivx", "1id"},
	{FORMAT3(2, OP3_X(1,13), 0), "UNDEFINED", ""},
	{FORMAT3(2, OP3_X(2,13), 0), "sdivx", "12d"},
	{FORMAT3(2, OP3_X(2,13), 1), "sdivx", "1id"},
	{FORMAT3(2, OP3_X(3,13), 0), "restore", "12d"},
	{FORMAT3(2, OP3_X(3,13), 1), "restore", "1id"},

	{FORMAT3(2, OP3_X(0,14), 0), "udiv", "12d"},
	{FORMAT3(2, OP3_X(0,14), 1), "udiv", "1id"},
	{FORMAT3(2, OP3_X(1,14), 0), "udivcc", "12d"},
	{FORMAT3(2, OP3_X(1,14), 1), "udivcc", "1id"},
	{FORMAT3(2, OP3_X(2,14), 0), "popc", "2d"},
	{FORMAT3(2, OP3_X(2,14), 1), "popc", "id"},

	{FORMAT3(2, OP3_X(3,14), 0), "done", ""},
	{FORMAT3(2, OP3_X(3,14), 0)|FCN(1), "retry", ""},

	{FORMAT3(2, OP3_X(0,15), 0), "sdiv", "12d"},
	{FORMAT3(2, OP3_X(0,15), 1), "sdiv", "1id"},
	{FORMAT3(2, OP3_X(1,15), 0), "sdivcc", "12d"},
	{FORMAT3(2, OP3_X(1,15), 1), "sdivcc", "1id"},
		/*
		 * OP3 = (2,15): MOVr:
		 * 	Move Integer Register on Register Condition
		 */
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(1)), "movrz", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(1)), "movrz", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(2)), "movrlez", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(2)), "movrlez", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(3)), "movrlz", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(3)), "movrlz", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(5)), "movrnz", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(5)), "movrnz", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(6)), "movrgz", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(6)), "movrgz", "12d"},
		{(FORMAT3(2, OP3_X(2,15), 1) | RCOND34(7)), "movrgez", "1jd"},
		{(FORMAT3(2, OP3_X(2,15), 0) | RCOND34(7)), "movrgez", "12d"},

	{FORMAT3(2, OP3_X(3,15), 0), "UNDEFINED", ""},

	/*
	 * Format 3/3: Load and store (appendix E, table 33)
	 */

	/* Loads */
	{(FORMAT3(3, OP3_X(0,0), 0)), "ld", "pd"},	/* officially: lduw */
	{(FORMAT3(3, OP3_X(0,0), 1)), "ld", "qd"},
	{(FORMAT3(3, OP3_X(1,0), 0)), "lda", "7d"},	/* officially: lduwa */
	{(FORMAT3(3, OP3_X(1,0), 1)), "lda", "8d"},
	{(FORMAT3(3, OP3_X(2,0), 0)), "ldf", "pe"},
	{(FORMAT3(3, OP3_X(2,0), 1)), "ldf", "qe"},
	{(FORMAT3(3, OP3_X(3,0), 0)), "ldfa", "7e"},
	{(FORMAT3(3, OP3_X(3,0), 1)), "ldfa", "8e"},

	{(FORMAT3(3, OP3_X(0,1), 0)), "ldub", "pd"},
	{(FORMAT3(3, OP3_X(0,1), 1)), "ldub", "qd"},
	{(FORMAT3(3, OP3_X(1,1), 0)), "lduba", "7d"},
	{(FORMAT3(3, OP3_X(1,1), 1)), "lduba", "8d"},
	{(FORMAT3(3, OP3_X(2,1), 0) | RD(0)), "ld", "p5"},
	{(FORMAT3(3, OP3_X(2,1), 1) | RD(0)), "ld", "q5"},
	{(FORMAT3(3, OP3_X(2,1), 0) | RD(1)), "ldx", "p6"},
	{(FORMAT3(3, OP3_X(2,1), 1) | RD(1)), "ldx", "q6"},

	{(FORMAT3(3, OP3_X(0,2), 0)), "lduh", "pd"},
	{(FORMAT3(3, OP3_X(0,2), 1)), "lduh", "qd"},
	{(FORMAT3(3, OP3_X(1,2), 0)), "lduha", "7d"},
	{(FORMAT3(3, OP3_X(1,2), 1)), "lduha", "8d"},
	{(FORMAT3(3, OP3_X(2,2), 0)), "ldq", "pe"},
	{(FORMAT3(3, OP3_X(2,2), 1)), "ldq", "qe"},
	{(FORMAT3(3, OP3_X(3,2), 0)), "ldqa", "7e"},
	{(FORMAT3(3, OP3_X(3,2), 1)), "ldqa", "8e"},

	{(FORMAT3(3, OP3_X(0,3), 0)), "ldd", "pd"},
	{(FORMAT3(3, OP3_X(0,3), 1)), "ldd", "qd"},
	{(FORMAT3(3, OP3_X(1,3), 0)), "ldda", "7d"},
	{(FORMAT3(3, OP3_X(1,3), 1)), "ldda", "8d"},
	{(FORMAT3(3, OP3_X(2,3), 0)), "ldd", "pe"},
	{(FORMAT3(3, OP3_X(2,3), 1)), "ldd", "qe"},
	{(FORMAT3(3, OP3_X(3,3), 0)), "ldda", "7e"},
	{(FORMAT3(3, OP3_X(3,3), 1)), "ldda", "8e"},

	{(FORMAT3(3, OP3_X(0,4), 0)), "st", "dp"},	/* officially: stw */
	{(FORMAT3(3, OP3_X(0,4), 1)), "st", "dq"},
	{(FORMAT3(3, OP3_X(1,4), 0)), "sta", "d7"},	/* officially: stwa */
	{(FORMAT3(3, OP3_X(1,4), 1)), "sta", "d8"},
	{(FORMAT3(3, OP3_X(2,4), 0)), "st", "ep"},
	{(FORMAT3(3, OP3_X(2,4), 1)), "st", "eq"},
	{(FORMAT3(3, OP3_X(3,4), 0)), "sta", "e7"},
	{(FORMAT3(3, OP3_X(3,4), 1)), "sta", "e8"},

	{(FORMAT3(3, OP3_X(0,5), 0)), "stb", "dp"},
	{(FORMAT3(3, OP3_X(0,5), 1)), "stb", "dq"},
	{(FORMAT3(3, OP3_X(1,5), 0)), "stba", "d7"},
	{(FORMAT3(3, OP3_X(1,5), 1)), "stba", "d8"},
	{(FORMAT3(3, OP3_X(2,5), 0)), "st", "5p"},
	{(FORMAT3(3, OP3_X(2,5), 1)), "st", "5q"},
	{(FORMAT3(3, OP3_X(2,5), 0)|RD(1)), "stx", "6p"},
	{(FORMAT3(3, OP3_X(2,5), 1)|RD(1)), "stx", "6q"},

	{(FORMAT3(3, OP3_X(0,6), 0)), "sth", "dp"},
	{(FORMAT3(3, OP3_X(0,6), 1)), "sth", "dq"},
	{(FORMAT3(3, OP3_X(1,6), 0)), "stha", "d7"},
	{(FORMAT3(3, OP3_X(1,6), 1)), "stha", "d8"},
	{(FORMAT3(3, OP3_X(2,6), 0)), "stq", "ep"},
	{(FORMAT3(3, OP3_X(2,6), 1)), "stq", "eq"},
	{(FORMAT3(3, OP3_X(3,6), 0)), "stqa", "e7"},
	{(FORMAT3(3, OP3_X(3,6), 1)), "stqa", "e8"},

	{(FORMAT3(3, OP3_X(0,7), 0)), "std", "dp"},
	{(FORMAT3(3, OP3_X(0,7), 1)), "std", "dq"},
	{(FORMAT3(3, OP3_X(1,7), 0)), "stda", "d7"},
	{(FORMAT3(3, OP3_X(1,7), 1)), "stda", "d8"},
	{(FORMAT3(3, OP3_X(2,7), 0)), "std", "ep"},
	{(FORMAT3(3, OP3_X(2,7), 1)), "std", "eq"},
	{(FORMAT3(3, OP3_X(3,7), 0)), "stda", "e7"},
	{(FORMAT3(3, OP3_X(3,7), 1)), "stda", "e8"},

	{(FORMAT3(3, OP3_X(0,8), 0)), "ldsw", "pd"},
	{(FORMAT3(3, OP3_X(0,8), 1)), "ldsw", "qd"},
	{(FORMAT3(3, OP3_X(1,8), 0)), "ldswa", "7d"},
	{(FORMAT3(3, OP3_X(1,8), 1)), "ldswa", "8d"},

	{(FORMAT3(3, OP3_X(0,9), 0)), "ldsb", "pd"},
	{(FORMAT3(3, OP3_X(0,9), 1)), "ldsb", "qd"},
	{(FORMAT3(3, OP3_X(1,9), 0)), "ldsba", "7d"},
	{(FORMAT3(3, OP3_X(1,9), 1)), "ldsba", "8d"},

	{(FORMAT3(3, OP3_X(0,10), 0)), "ldsh", "pd"},
	{(FORMAT3(3, OP3_X(0,10), 1)), "ldsh", "qd"},
	{(FORMAT3(3, OP3_X(1,10), 0)), "ldsha", "7d"},
	{(FORMAT3(3, OP3_X(1,10), 1)), "ldsha", "8d"},

	{(FORMAT3(3, OP3_X(0,11), 0)), "ldx", "pd"},
	{(FORMAT3(3, OP3_X(0,11), 1)), "ldx", "qd"},
	{(FORMAT3(3, OP3_X(1,11), 0)), "ldxa", "7d"},
	{(FORMAT3(3, OP3_X(1,11), 1)), "ldxa", "8d"},

	{(FORMAT3(3, OP3_X(3,12), 1)), "casa", "s2d"},
	{(FORMAT3(3, OP3_X(3,12), 0)), "casa", "t2d"},

	{(FORMAT3(3, OP3_X(0,13), 0)), "ldstub", "7d"},
	{(FORMAT3(3, OP3_X(0,13), 1)), "ldstub", "8d"},
	{(FORMAT3(3, OP3_X(1,13), 0)), "ldstuba", "pd"},
	{(FORMAT3(3, OP3_X(1,13), 1)), "ldstuba", "qd"},
	{(FORMAT3(3, OP3_X(2,13), 0)), "prefetch", "pr"},
	{(FORMAT3(3, OP3_X(2,13), 1)), "prefetch", "qr"},
	{(FORMAT3(3, OP3_X(3,13), 0)), "prefetcha", "7r"},
	{(FORMAT3(3, OP3_X(3,13), 1)), "prefetcha", "8r"},

	{(FORMAT3(3, OP3_X(0,14), 0)), "stx", "dp"},
	{(FORMAT3(3, OP3_X(0,14), 1)), "stx", "dq"},
	{(FORMAT3(3, OP3_X(1,14), 0)), "stwa", "d7"},
	{(FORMAT3(3, OP3_X(1,14), 1)), "stwa", "d8"},
	{(FORMAT3(3, OP3_X(3,14), 0)), "casxa", "t2d"},
	{(FORMAT3(3, OP3_X(3,14), 1)), "casxa", "s2d"},

	/* Swap Register */
	{(FORMAT3(3, OP3_X(0,15), 0)), "swap", "pd"},
	{(FORMAT3(3, OP3_X(0,15), 1)), "swap", "qd"},
	{(FORMAT3(3, OP3_X(1,15), 0)), "swapa", "7d"},
	{(FORMAT3(3, OP3_X(1,15), 1)), "swapa", "8d"},

	/*
	 * OP3 = (3,4): FPop1 (table 34)
	 */
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,1))), "fmovs", ".4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,2))), "fmovd", ".4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,3))), "fmovq", ".4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,5))), "fnegs", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,6))), "fnegd", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,7))), "fnegq", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,9))), "fabss", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,10))), "fabsd", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(0,11))), "fabsq", "4e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(2,9))), "fsqrts", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(2,10))), "fsqrtd", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(2,11))), "fsqrtq", "4e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,1))), "fadds", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,2))), "faddd", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,3))), "faddq", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,5))), "fsubs", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,6))), "fsubd", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,7))), "fsubq", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,9))), "fmuls", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,10))), "fmuld", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,11))), "fmulq", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,13))), "fdivs", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,14))), "fdivd", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(4,15))), "fdivq", "34e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(6,9))), "fsmuld", "34e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(6,14))), "fdmulq", "34e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,1))), "fstox", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,2))), "fdtox", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,3))), "fqtox", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,4))), "fxtos", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,8))), "fxtod", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(8,12))), "fxtoq", "4e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,4))), "fitos", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,6))), "fdtos", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,7))), "fqtos", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,8))), "fitod", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,9))), "fstod", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,11))), "fqtod", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,12))), "fitoq", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,13))), "fstoq", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(12,14))), "fdtoq", "4e"},

	{(FORMAT3F(2, OP3_X(3,4), OPF_X(13,1))), "fstoi", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(13,2))), "fdtoi", "4e"},
	{(FORMAT3F(2, OP3_X(3,4), OPF_X(13,3))), "fqtoi", "4e"},

#ifdef xxx
	/*
	 * OP3 =(3,5): FPop2 (table 35)
	 */
	{(FORMAT3F(2, OP3_X(3,5), 81)), "fcmps", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 82)), "fcmpd", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 83)), "fcmpq", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 85)), "fcmpes", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 86)), "fcmped", "o34"},
	{(FORMAT3F(2, OP3_X(3,5), 87)), "fcmpeq", "o34"},

	/* Move Floating-Point Register on Condition "FMOVcc" */
	/* FIXME should check for single, double, and quad movements */
	/* Integer Condition Codes */
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,8)), "fmova", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,0)), "fmovn", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,9)), "fmovne", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,1)), "fmove", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,10)), "fmovg", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,2)), "fmovle", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,11)), "fmovge", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,3)), "fmovl", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,12)), "fmovgu", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,4)), "fmovleu", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,13)), "fmovcc", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,5)), "fmovcs", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,14)), "fmovpos", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,6)), "fmovneg", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,15)), "fmovvc", "04e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,7)), "fmovvs", "04e"},

	/* Floating-Point Condition Codes */
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,8)), "fmova", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,0)), "fmovn", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,7)), "fmovu", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,6)), "fmovg", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,5)), "fmovug", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,4)), "fmovk", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,3)), "fmovul", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,2)), "fmovlg", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,1)), "fmovne", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,9)), "fmove", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,10)), "fmovue", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,11)), "fmovge", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,12)), "fmovuge", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,13)), "fmovle", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,14)), "fmovule", "o4e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | COND2(0,15)), "fmovo", "o4e"},

	/* Move F-P Register on Integer Register Condition "FMOVr" */
	/* FIXME: check for short, double, and quad's */
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(1)), "fmovre", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(2)), "fmovrlez", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(3)), "fmovrlz", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(5)), "fmovrne", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(6)), "fmovrgz", "14e"},
	{(FORMAT3(2, OP3_X(3,5), 0) | RCOND34(7)), "fmovrgez", "14e"},
#endif
	/* FP logical insns -- UltraSPARC extens */
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,0))), "fzero", "e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,1))), "fzeros", "e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,14))), "fone", "e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,15))), "fones", "e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,4))), "fsrc1", "3e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,5))), "fsrc1s", "3e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,8))), "fsrc2", "4e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,9))), "fsrc2s", "4e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,10))), "fnot1", "3e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,11))), "fnot1s", "3e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,6))), "fnot2", "4e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,7))), "fnot2s", "4e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,12))), "for", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,13))), "fors", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,2))), "fnor", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,3))), "fnors", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,0))), "fand", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,1))), "fands", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,14))), "fnand", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,15))), "fnands", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,12))), "fxor", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,13))), "fxors", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,2))), "fxnor", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,3))), "fxnors", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,10))), "fornot1", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,11))), "fornot1s", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,6))), "fornot2", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(7,7))), "fornot2s", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,8))), "fandnot1", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,9))), "fandnot1s", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,4))), "fandnot2", "34e"},
	{(FORMAT3F(2, OP3_X(3,6), OPF_X(6,5))), "fandnot2s", "34e"},

	/* grrrr.... */
	{0, 0, 0}

};

db_addr_t
db_disasm(loc, altfmt)
	vaddr_t loc;
	boolean_t altfmt;
{
	struct sparc_insn*	i_ptr = (struct sparc_insn *)&sparc_i;

	unsigned int insn, you_lose, bitmask;
	int matchp;
	char *f_ptr, *cp;

	you_lose = 0;
	matchp = 0;
	insn = db_get_value(loc, 4, 0);

	if (insn == 0x01000000) {
		db_printf("nop\n");
		return loc + 4;
	}

	while (i_ptr->name) {
		/* calculate YOU_LOSE value */
		bitmask= (i_ptr->match);
		you_lose = (~bitmask);

		if (((bitmask>>30) & 0x3) == 0x1) {
			/* Call */
			you_lose = ((~0x1)<<30);
		} else if (((bitmask>>30) & 0x3) == 0x0) {
			if (((bitmask>>22) & 0x7) == 0x4) {
				/* Sethi */
				you_lose &= (FORMAT2(0x3,0x7));
			} else {
				/* Branches */
				you_lose &= (FORMAT2(0x3,0x7)|COND(0xf));
			}
		} else if (((bitmask>>30) & 0x3) == 0x2 &&
			   ((bitmask>>19) & 0x3f) == 0x34) /* XXX */ {
			/* FPop1 */
			you_lose &= (FORMAT3(0x3,0x3f,0x1) | OPF(0x1ff));
		} else if (((bitmask>>30) & 0x3) == 0x2 &&
			   ((bitmask>>19) & 0x3f) == 0x3a) /* XXX */ {
			/* Tcc */
			you_lose &= (FORMAT3(0x3,0x3f,0x1) | COND(0xf));
		} else if (((bitmask>>30) & 0x3) == 0x2 &&
			   ((bitmask>>21) & 0xf) == 0x9 &&
			   ((bitmask>>19) & 0x3) != 0) /* XXX */ {
			/* shifts */
			you_lose &= (FORMAT3(0x3,0x3f,0x1))|X(1);
		} else if (((bitmask>>30) & 0x3) == 0x2 &&
			   ((bitmask>>19) & 0x3f) == 0x2c) /* XXX */ {
			/* cmov */
			you_lose &= (FORMAT3(0x3,0x3f,0x1) | COND2(1,0xf));
		} else if (((bitmask>>30) & 0x3) == 0x2 &&
			   ((bitmask>>19) & 0x3f) == 0x35) /* XXX */ {
			/* fmov */
			you_lose &= (FORMAT3(0x3,0x3f,0x1) | COND2(1,0xf));
		} else if (((bitmask>>30) & 0x3) == 0x2 &&
			   ((bitmask>>13) & 0x1) == 0 &&
			   ((((bitmask>>19) & 0x3f) == OP3_X(3,1)) ||
			   (((bitmask>>19) & 0x3f) == OP3_X(3,14)))) /* XXX */ {
			/* saved/done/retry/restored */
			you_lose &= (FORMAT3(0x3,0x3f,0x1)) | FCN(0x1f);
		} else {
			you_lose &= (FORMAT3(0x3,0x3f,0x1));
		}

		if (((bitmask & insn) == bitmask) && ((you_lose & insn) == 0)) {
			matchp = 1;
			break;
		}
		i_ptr++;
	};

	if (!matchp) {
		db_printf("undefined\n");
		return loc + 4;
	}

	db_printf("%s", i_ptr->name);

	f_ptr = i_ptr->format;

	for (cp = f_ptr; *cp; cp++) {
		if (*cp == ',') {
			for (;f_ptr < cp; f_ptr++)
				switch (*f_ptr) {
				case 'a':
					if (insn & A(1))
						db_printf(",a");
					break;
				case 'p':
					if (insn & P(1))
						db_printf(",pt");
					else
						db_printf(",pn");
					break;
				}
			f_ptr++;
			break;
		}
	}
	db_printf("      \t");

	while (*f_ptr) {
		switch (*f_ptr) {
			int64_t val;
		case '1':
			db_printf("%%%s", regs[((insn >> 14) & 0x1f)]);
			break;
		case '2':
			db_printf("%%%s", regs[(insn & 0x1f)]);
			break;
		case 'd':
			db_printf("%%%s", regs[((insn >> 25) & 0x1f)]);
			break;
		case '3':
			db_printf("%%f%d", ((insn >> 14) & 0x1f));
			break;
		case '4':
			db_printf("%%f%d", (insn & 0x1f));
			break;
		case 'e':
			db_printf("%%f%d", ((insn >> 25) & 0x1f));
			break;
		case 'i':
			/* simm13 -- signed */
			val = SIGNEX(insn, 13);
			db_printf("%s0x%x", SIGN(val), (int)abs(val));
			break;
		case 'j':
			/* simm11 -- signed */
			val = SIGNEX(insn, 11);
			db_printf("%s0x%x", SIGN(val), (int)abs(val));
			break;
		case 'l':
			val = (((insn>>20)&0x3)<<13)|(insn & 0x1fff);
			val = SIGNEX(val, 16);
			db_printsym((db_addr_t)(loc + (4 * val)),
			    DB_STGY_ANY, db_printf);
			break;
		case 'm':
			db_printsym((db_addr_t)(loc + (4 * SIGNEX(insn, 22))),
				DB_STGY_ANY, db_printf);
			break;
		case 'u':
			db_printsym((db_addr_t)(loc + (4 * SIGNEX(insn, 19))),
			    DB_STGY_ANY, db_printf);
			break;
		case 'n':
			db_printsym((db_addr_t)(loc + (4 * SIGNEX(insn, 30))),
			    DB_STGY_PROC, db_printf);
			break;
		case 's':
			db_printf("%%asi");
			break;
		case 't':
			db_printf("0x%-2.2x", ((insn >> 5) & 0xff));
			break;
		case 'o':
			db_printf("%%fcc%d", ((insn >> 25) & 0x3));
			break;
		case 'p':
		case '7':
			db_printf("[%%%s + %%%s]",
				  regs[((insn >> 14) & 0x1f)],
				  regs[(insn & 0x1f)]);
			if (*f_ptr == '7')
				db_printf(" %d", ((insn >> 5) & 0xff));
			break;
		case 'q':
		case '8':
			val = SIGNEX(insn, 13);
			db_printf("[%%%s %c 0x%x]",
				regs[((insn >> 14) & 0x1f)],
				(int)((val<0)?'-':'+'),
				(int)abs(val));
			if (*f_ptr == '8')
				db_printf(" %%asi");
			break;
		case '5':
			db_printf("%%fsr");
			break;
		case '6':
			db_printf("%%fsr");
			break;
		case '9':
			db_printf("0x%xl",
				  ((insn & 0xf) | ((insn >> 4) & 0x7)));
			break;
		case '0':
			db_printf("%%%s", ccodes[((insn >> 11) & 0x3) + 4]);
			break;
		case '.':
			db_printf("%%%s", ccodes[((insn >> 11) & 0x7)]);
			break;
		case 'r':
			db_printf("#%s", prefetch[((insn >> 25) & 0x1f)]);
			break;
		case 'A':
			db_printf("%%%s", priv_regs[((insn >> 14) & 0x1f)]);
			break;
		case 'B':
			db_printf("%%%s", state_regs[((insn >> 14) & 0x1f)]);
			break;
		case 'C':
			db_printf("%%hi(0x%x)", ((insn & 0x3fffff) << 10));
			break;
		case 'D':
			db_printf("0x%x", (insn & 0x1f));
			break;
		case 'E':
			db_printf("%d", (insn & 0x3f));
			break;
		case 'F':
			db_printf("%d", (insn & 0x3f));
			break;
		case 'G':
			db_printf("%%%s", priv_regs[((insn >> 25) & 0x1f)]);
			break;
		case 'H':
			db_printf("%%%s", state_regs[((insn >> 25) & 0x1f)]);
			break;
#ifndef V9
		case 'P':
			db_printf("%%psr");
			break;
		case 'T':
			db_printf("%%tbr");
			break;
		case 'W':
			db_printf("%%wim");
			break;
		case 'Y':
			db_printf("%%y");
			break;
#endif
		default:
			db_printf("(UNKNOWN)");
			break;
		}
		if (*(++f_ptr))
			db_printf(", ");
	};

	db_printf("\n");

	return (loc + 4);
}


code:
/*	$OpenBSD: db_interface.c,v 1.36 2014/07/13 12:11:01 jasper Exp $	*/
/*	$NetBSD: db_interface.c,v 1.61 2001/07/31 06:55:47 eeh Exp $ */

/*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * 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 ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS 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.
 *
 *	From: db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
 */

#include <sys/param.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/reboot.h>
#include <sys/systm.h>
#include <sys/malloc.h>

#include <dev/cons.h>

#include <machine/db_machdep.h>
#include <ddb/db_command.h>
#include <ddb/db_sym.h>
#include <ddb/db_variables.h>
#include <ddb/db_extern.h>
#include <ddb/db_access.h>
#include <ddb/db_output.h>
#include <ddb/db_interface.h>

#include <machine/instr.h>
#include <machine/cpu.h>
#include <machine/openfirm.h>
#include <machine/ctlreg.h>
#include <machine/pmap.h>

#ifdef notyet
#include "fb.h"
#include "esp_sbus.h"
#endif

#include "tda.h"

db_regs_t	ddb_regs;	/* register state */

extern void OF_enter(void);

extern struct traptrace {
	unsigned short tl:3,	/* Trap level */
		ns:4,		/* PCB nsaved */
		tt:9;		/* Trap type */
	unsigned short pid;	/* PID */
	u_int tstate;		/* tstate */
	u_int tsp;		/* sp */
	u_int tpc;		/* pc */
	u_int tfault;		/* MMU tag access */
} trap_trace[], trap_trace_end[];

static long nil;

static int
db__char_value(struct db_variable *var, db_expr_t *expr, int mode)
{

	switch (mode) {
	case DB_VAR_SET:
		*var->valuep = *(char *)expr;
		break;
	case DB_VAR_GET:
		*expr = *(char *)var->valuep;
		break;
#ifdef DIAGNOSTIC
	default:
		printf("db__char_value: mode %d\n", mode);
		break;
#endif
	}

	return 0;
}

#ifdef notdef_yet
static int
db__short_value(struct db_variable *var, db_expr_t *expr, int mode)
{

	switch (mode) {
	case DB_VAR_SET:
		*var->valuep = *(short *)expr;
		break;
	case DB_VAR_GET:
		*expr = *(short *)var->valuep;
		break;
#ifdef DIAGNOSTIC
	default:
		printf("db__short_value: mode %d\n", mode);
		break;
#endif
	}

	return 0;
}
#endif

struct db_variable db_regs[] = {
	{ "tstate", (long *)&DDB_TF->tf_tstate, FCN_NULL, },
	{ "pc", (long *)&DDB_TF->tf_pc, FCN_NULL, },
	{ "npc", (long *)&DDB_TF->tf_npc, FCN_NULL, },
	{ "ipl", (long *)&DDB_TF->tf_oldpil, db__char_value, },
	{ "y", (long *)&DDB_TF->tf_y, db_var_rw_int, },
	{ "g0", (long *)&nil, FCN_NULL, },
	{ "g1", (long *)&DDB_TF->tf_global[1], FCN_NULL, },
	{ "g2", (long *)&DDB_TF->tf_global[2], FCN_NULL, },
	{ "g3", (long *)&DDB_TF->tf_global[3], FCN_NULL, },
	{ "g4", (long *)&DDB_TF->tf_global[4], FCN_NULL, },
	{ "g5", (long *)&DDB_TF->tf_global[5], FCN_NULL, },
	{ "g6", (long *)&DDB_TF->tf_global[6], FCN_NULL, },
	{ "g7", (long *)&DDB_TF->tf_global[7], FCN_NULL, },
	{ "o0", (long *)&DDB_TF->tf_out[0], FCN_NULL, },
	{ "o1", (long *)&DDB_TF->tf_out[1], FCN_NULL, },
	{ "o2", (long *)&DDB_TF->tf_out[2], FCN_NULL, },
	{ "o3", (long *)&DDB_TF->tf_out[3], FCN_NULL, },
	{ "o4", (long *)&DDB_TF->tf_out[4], FCN_NULL, },
	{ "o5", (long *)&DDB_TF->tf_out[5], FCN_NULL, },
	{ "o6", (long *)&DDB_TF->tf_out[6], FCN_NULL, },
	{ "o7", (long *)&DDB_TF->tf_out[7], FCN_NULL, },
	{ "l0", (long *)&DDB_TF->tf_local[0], FCN_NULL, },
	{ "l1", (long *)&DDB_TF->tf_local[1], FCN_NULL, },
	{ "l2", (long *)&DDB_TF->tf_local[2], FCN_NULL, },
	{ "l3", (long *)&DDB_TF->tf_local[3], FCN_NULL, },
	{ "l4", (long *)&DDB_TF->tf_local[4], FCN_NULL, },
	{ "l5", (long *)&DDB_TF->tf_local[5], FCN_NULL, },
	{ "l6", (long *)&DDB_TF->tf_local[6], FCN_NULL, },
	{ "l7", (long *)&DDB_TF->tf_local[7], FCN_NULL, },
	{ "i0", (long *)&DDB_FR->fr_arg[0], FCN_NULL, },
	{ "i1", (long *)&DDB_FR->fr_arg[1], FCN_NULL, },
	{ "i2", (long *)&DDB_FR->fr_arg[2], FCN_NULL, },
	{ "i3", (long *)&DDB_FR->fr_arg[3], FCN_NULL, },
	{ "i4", (long *)&DDB_FR->fr_arg[4], FCN_NULL, },
	{ "i5", (long *)&DDB_FR->fr_arg[5], FCN_NULL, },
	{ "i6", (long *)&DDB_FR->fr_arg[6], FCN_NULL, },
	{ "i7", (long *)&DDB_FR->fr_arg[7], FCN_NULL, },
	{ "f0", (long *)&DDB_FP->fs_regs[0], FCN_NULL, },
	{ "f2", (long *)&DDB_FP->fs_regs[2], FCN_NULL, },
	{ "f4", (long *)&DDB_FP->fs_regs[4], FCN_NULL, },
	{ "f6", (long *)&DDB_FP->fs_regs[6], FCN_NULL, },
	{ "f8", (long *)&DDB_FP->fs_regs[8], FCN_NULL, },
	{ "f10", (long *)&DDB_FP->fs_regs[10], FCN_NULL, },
	{ "f12", (long *)&DDB_FP->fs_regs[12], FCN_NULL, },
	{ "f14", (long *)&DDB_FP->fs_regs[14], FCN_NULL, },
	{ "f16", (long *)&DDB_FP->fs_regs[16], FCN_NULL, },
	{ "f18", (long *)&DDB_FP->fs_regs[18], FCN_NULL, },
	{ "f20", (long *)&DDB_FP->fs_regs[20], FCN_NULL, },
	{ "f22", (long *)&DDB_FP->fs_regs[22], FCN_NULL, },
	{ "f24", (long *)&DDB_FP->fs_regs[24], FCN_NULL, },
	{ "f26", (long *)&DDB_FP->fs_regs[26], FCN_NULL, },
	{ "f28", (long *)&DDB_FP->fs_regs[28], FCN_NULL, },
	{ "f30", (long *)&DDB_FP->fs_regs[30], FCN_NULL, },
	{ "f32", (long *)&DDB_FP->fs_regs[32], FCN_NULL, },
	{ "f34", (long *)&DDB_FP->fs_regs[34], FCN_NULL, },
	{ "f36", (long *)&DDB_FP->fs_regs[36], FCN_NULL, },
	{ "f38", (long *)&DDB_FP->fs_regs[38], FCN_NULL, },
	{ "f40", (long *)&DDB_FP->fs_regs[40], FCN_NULL, },
	{ "f42", (long *)&DDB_FP->fs_regs[42], FCN_NULL, },
	{ "f44", (long *)&DDB_FP->fs_regs[44], FCN_NULL, },
	{ "f46", (long *)&DDB_FP->fs_regs[46], FCN_NULL, },
	{ "f48", (long *)&DDB_FP->fs_regs[48], FCN_NULL, },
	{ "f50", (long *)&DDB_FP->fs_regs[50], FCN_NULL, },
	{ "f52", (long *)&DDB_FP->fs_regs[52], FCN_NULL, },
	{ "f54", (long *)&DDB_FP->fs_regs[54], FCN_NULL, },
	{ "f56", (long *)&DDB_FP->fs_regs[56], FCN_NULL, },
	{ "f58", (long *)&DDB_FP->fs_regs[58], FCN_NULL, },
	{ "f60", (long *)&DDB_FP->fs_regs[60], FCN_NULL, },
	{ "f62", (long *)&DDB_FP->fs_regs[62], FCN_NULL, },
	{ "fsr", (long *)&DDB_FP->fs_fsr, FCN_NULL, },
	{ "gsr", (long *)&DDB_FP->fs_gsr, FCN_NULL, },

};
struct db_variable *db_eregs = db_regs + nitems(db_regs);

extern label_t	*db_recover;

int	db_active = 0;

extern char *trap_type[];

void kdb_kbd_trap(struct trapframe64 *);
void db_prom_cmd(db_expr_t, int, db_expr_t, char *);
void db_proc_cmd(db_expr_t, int, db_expr_t, char *);
void db_ctx_cmd(db_expr_t, int, db_expr_t, char *);
void db_dump_window(db_expr_t, int, db_expr_t, char *);
void db_dump_stack(db_expr_t, int, db_expr_t, char *);
void db_dump_trap(db_expr_t, int, db_expr_t, char *);
void db_dump_fpstate(db_expr_t, int, db_expr_t, char *);
void db_dump_ts(db_expr_t, int, db_expr_t, char *);
void db_dump_pcb(db_expr_t, int, db_expr_t, char *);
void db_dump_pv(db_expr_t, int, db_expr_t, char *);
void db_setpcb(db_expr_t, int, db_expr_t, char *);
void db_dump_dtlb(db_expr_t, int, db_expr_t, char *);
void db_dump_itlb(db_expr_t, int, db_expr_t, char *);
void db_dump_dtsb(db_expr_t, int, db_expr_t, char *);
void db_pmap_kernel(db_expr_t, int, db_expr_t, char *);
void db_pload_cmd(db_expr_t, int, db_expr_t, char *);
void db_pmap_cmd(db_expr_t, int, db_expr_t, char *);
void db_lock(db_expr_t, int, db_expr_t, char *);
void db_traptrace(db_expr_t, int, db_expr_t, char *);
void db_dump_buf(db_expr_t, int, db_expr_t, char *);
void db_dump_espcmd(db_expr_t, int, db_expr_t, char *);
void db_watch(db_expr_t, int, db_expr_t, char *);
void db_xir(db_expr_t, int, db_expr_t, char *);

static void db_dump_pmap(struct pmap*);
static void db_print_trace_entry(struct traptrace *, int);

/*
 * Received keyboard interrupt sequence.
 */
void
kdb_kbd_trap(tf)
	struct trapframe64 *tf;
{
	if (db_active == 0 /* && (boothowto & RB_KDB) */) {
		printf("\n\nkernel: keyboard interrupt tf=%p\n", tf);
		kdb_trap(-1, tf);
	}
}

/*
 *  kdb_trap - field a TRACE or BPT trap
 */
int
kdb_trap(type, tf)
	int	type;
	register struct trapframe64 *tf;
{
	int s, tl;
	struct trapstate *ts = &ddb_regs.ddb_ts[0];
	extern int savetstate(struct trapstate *ts);
	extern void restoretstate(int tl, struct trapstate *ts);
	extern int trap_trace_dis;

	trap_trace_dis++;

#if NTDA > 0
	tda_full_blast();
#endif

	fb_unblank();

	switch (type) {
	case T_BREAKPOINT:	/* breakpoint */
		printf("kdb breakpoint at %llx\n",
		    (unsigned long long)tf->tf_pc);
		break;
	case -1:		/* keyboard interrupt */
		printf("kdb tf=%p\n", tf);
		break;
	default:
		printf("kernel trap %x: %s\n", type, trap_type[type & 0x1ff]);
		if (db_recover != 0) {
			OF_enter();
			db_error("Faulted in DDB; continuing...\n");
			OF_enter();
			/*NOTREACHED*/
		}
		db_recover = (label_t *)1;
	}

	/* Should switch to kdb`s own stack here. */
	write_all_windows();

	ddb_regs.ddb_tf = *tf;
	if (fpproc) {
		savefpstate(fpproc->p_md.md_fpstate);
		ddb_regs.ddb_fpstate = *fpproc->p_md.md_fpstate;
		loadfpstate(fpproc->p_md.md_fpstate);
	}
	/* We should do a proper copyin and xlate 64-bit stack frames, but... */
/*	if (tf->tf_tstate & TSTATE_PRIV) { */

#if 0
	/* make sure this is not causing ddb problems. */
	if (tf->tf_out[6] & 1) {
		if ((unsigned)(tf->tf_out[6] + BIAS) > (unsigned)KERNBASE)
			ddb_regs.ddb_fr = *(struct frame64 *)(tf->tf_out[6] + BIAS);
		else
			copyin((caddr_t)(tf->tf_out[6] + BIAS), &ddb_regs.ddb_fr, sizeof(struct frame64));
	} else {
		struct frame32 tfr;

		/* First get a local copy of the frame32 */
		if ((unsigned)(tf->tf_out[6]) > (unsigned)KERNBASE)
			tfr = *(struct frame32 *)tf->tf_out[6];
		else
			copyin((caddr_t)(tf->tf_out[6]), &tfr, sizeof(struct frame32));
		/* Now copy each field from the 32-bit value to the 64-bit value */
		for (i=0; i<8; i++)
			ddb_regs.ddb_fr.fr_local[i] = tfr.fr_local[i];
		for (i=0; i<6; i++)
			ddb_regs.ddb_fr.fr_arg[i] = tfr.fr_arg[i];
		ddb_regs.ddb_fr.fr_fp = (long)tfr.fr_fp;
		ddb_regs.ddb_fr.fr_pc = tfr.fr_pc;
	}
#endif

	s = splhigh();
	db_active++;
	cnpollc(TRUE);
	/* Need to do spl stuff till cnpollc works */
	tl = ddb_regs.ddb_tl = savetstate(ts);
	db_dump_ts(0, 0, 0, 0);
	db_trap(type, 0/*code*/);
	restoretstate(tl,ts);
	cnpollc(FALSE);
	db_active--;
	splx(s);

	if (fpproc) {
		*fpproc->p_md.md_fpstate = ddb_regs.ddb_fpstate;
		loadfpstate(fpproc->p_md.md_fpstate);
	}
#if 0
	/* We will not alter the machine's running state until we get everything else working */
	*(struct frame *)tf->tf_out[6] = ddb_regs.ddb_fr;
#endif
	*tf = ddb_regs.ddb_tf;
	trap_trace_dis--;

	return (1);
}

/*
 * Read bytes from kernel address space for debugger.
 */
void
db_read_bytes(addr, size, data)
	vaddr_t	addr;
	register size_t	size;
	register char	*data;
{
	register char	*src;

	src = (char *)addr;
	while (size-- > 0) {
		if (src >= (char *)VM_MIN_KERNEL_ADDRESS)
			*data++ = probeget((paddr_t)(u_long)src++, ASI_P, 1);
		else
			copyin(src++, data++, sizeof(u_char));
	}
}

/*
 * Write bytes to kernel address space for debugger.
 */
void
db_write_bytes(addr, size, data)
	vaddr_t	addr;
	register size_t	size;
	register char	*data;
{
	register char	*dst;
	extern vaddr_t ktext;
	extern paddr_t ktextp;

	dst = (char *)addr;
	while (size-- > 0) {
		if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS+0x400000))
			*dst = *data;
		else if ((dst >= (char *)VM_MIN_KERNEL_ADDRESS) &&
			 (dst < (char *)VM_MIN_KERNEL_ADDRESS+0x400000))
			/* Read Only mapping -- need to do a bypass access */
			stba((u_long)dst - ktext + ktextp, ASI_PHYS_CACHED, *data);
		else
			copyout(data, dst, sizeof(char));
		dst++, data++;
	}

}

void
Debugger()
{
	/* We use the breakpoint to trap into DDB */
	asm("ta 1; nop");
}

void
db_prom_cmd(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	OF_enter();
}

#define CHEETAHP (((getver()>>32) & 0x1ff) >= 0x14)
unsigned long db_get_dtlb_data(int entry), db_get_dtlb_tag(int entry),
db_get_itlb_data(int entry), db_get_itlb_tag(int entry);
void db_print_itlb_entry(int entry, int i, int endc);
void db_print_dtlb_entry(int entry, int i, int endc);

extern __inline__ unsigned long db_get_dtlb_data(int entry)
{
	unsigned long r;
	__asm__ volatile("ldxa [%1] %2,%0"
		: "=r" (r)
		: "r" (entry <<3), "i" (ASI_DMMU_TLB_DATA));
	return r;
}
extern __inline__ unsigned long db_get_dtlb_tag(int entry)
{
	unsigned long r;
	__asm__ volatile("ldxa [%1] %2,%0"
		: "=r" (r)
		: "r" (entry <<3), "i" (ASI_DMMU_TLB_TAG));
	return r;
}
extern __inline__ unsigned long db_get_itlb_data(int entry)
{
	unsigned long r;
	__asm__ volatile("ldxa [%1] %2,%0"
		: "=r" (r)
		: "r" (entry <<3), "i" (ASI_IMMU_TLB_DATA));
	return r;
}
extern __inline__ unsigned long db_get_itlb_tag(int entry)
{
	unsigned long r;
	__asm__ volatile("ldxa [%1] %2,%0"
		: "=r" (r)
		: "r" (entry <<3), "i" (ASI_IMMU_TLB_TAG));
	return r;
}

void db_print_dtlb_entry(int entry, int i, int endc)
{
	unsigned long tag, data;
	tag = db_get_dtlb_tag(entry);
	data = db_get_dtlb_data(entry);
	db_printf("%2d:%16.16lx %16.16lx%c", i, tag, data, endc);
}

void db_print_itlb_entry(int entry, int i, int endc)
{
	unsigned long tag, data;
	tag = db_get_itlb_tag(entry);
	data = db_get_itlb_data(entry);
	db_printf("%2d:%16.16lx %16.16lx%c", i, tag, data, endc);
}

void
db_dump_dtlb(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	/* extern void print_dtlb(void); -- locore.s; no longer used here */

	if (have_addr) {
		int i;
		int64_t* p = (int64_t*)addr;
		static int64_t buf[128];
		extern void dump_dtlb(int64_t *);

	if (CHEETAHP) {
		db_printf("DTLB %ld\n", addr);
		switch(addr)
		{
		case 0:
			for (i = 0; i < 16; ++i)
				db_print_dtlb_entry(i, i, (i&1)?'\n':' ');
			break;
		case 2:
			for (i = 0; i < 512; ++i)
				db_print_dtlb_entry(i+16384, i, (i&1)?'\n':' ');
			break;
		}
	} else {
		dump_dtlb(buf);
		p = buf;
		for (i=0; i<64;) {
			db_printf("%2d:%16.16llx %16.16llx ", i++, p[0], p[1]);
			p += 2;
			db_printf("%2d:%16.16llx %16.16llx\n", i++, p[0], p[1]);
			p += 2;
		}
	}
	} else {
printf ("Usage: mach dtlb 0,2\n");
	}
}

void
db_dump_itlb(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	int i;
	if (!have_addr) {
		db_printf("Usage: mach itlb 0,1,2\n");
		return;
	}
	if (CHEETAHP) {
		db_printf("ITLB %ld\n", addr);
		switch(addr)
		{
		case 0:
			for (i = 0; i < 16; ++i)
				db_print_itlb_entry(i, i, (i&1)?'\n':' ');
			break;
		case 2:
			for (i = 0; i < 128; ++i)
				db_print_itlb_entry(i+16384, i, (i&1)?'\n':' ');
			break;
		}
	} else {
		for (i = 0; i < 63; ++i)
			db_print_itlb_entry(i, i, (i&1)?'\n':' ');
	}
}

void
db_pload_cmd(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	static paddr_t oldaddr = -1;
	int asi = ASI_PHYS_CACHED;

	if (!have_addr) {
		addr = oldaddr;
	}
	if (addr == -1) {
		db_printf("no address\n");
		return;
	}
	addr &= ~0x7; /* align */
	{
		register char c, *cp = modif;
		while ((c = *cp++) != 0)
			if (c == 'u')
				asi = ASI_AIUS;
	}
	while (count--) {
		if (db_print_position() == 0) {
			/* Always print the address. */
			db_printf("%16.16lx:\t", addr);
		}
		oldaddr=addr;
		db_printf("%8.8lx\n", (long)ldxa(addr, asi));
		addr += 8;
		if (db_print_position() != 0)
			db_end_line(0);
	}
}

int64_t pseg_get(struct pmap *, vaddr_t);

void
db_dump_pmap(pm)
struct pmap* pm;
{
	/* print all valid pages in the kernel pmap */
	long i, j, k, n;
	paddr_t *pdir, *ptbl;
	/* Almost the same as pmap_collect() */

	n = 0;
	for (i=0; i<STSZ; i++) {
		if((pdir = (paddr_t *)(u_long)ldxa((vaddr_t)&pm->pm_segs[i], ASI_PHYS_CACHED))) {
			db_printf("pdir %ld at %lx:\n", i, (long)pdir);
			for (k=0; k<PDSZ; k++) {
				if ((ptbl = (paddr_t *)(u_long)ldxa((vaddr_t)&pdir[k], ASI_PHYS_CACHED))) {
					db_printf("\tptable %ld:%ld at %lx:\n", i, k, (long)ptbl);
					for (j=0; j<PTSZ; j++) {
						int64_t data0, data1;
						data0 = ldxa((vaddr_t)&ptbl[j], ASI_PHYS_CACHED);
						j++;
						data1 = ldxa((vaddr_t)&ptbl[j], ASI_PHYS_CACHED);
						if (data0 || data1) {
							db_printf("%llx: %llx\t",
								  (unsigned long long)(((u_int64_t)i<<STSHIFT)|(k<<PDSHIFT)|((j-1)<<PTSHIFT)),
								  (unsigned long long)(data0));
							db_printf("%llx: %llx\n",
								  (unsigned long long)(((u_int64_t)i<<STSHIFT)|(k<<PDSHIFT)|(j<<PTSHIFT)),
								  (unsigned long long)(data1));
						}
					}
				}
			}
		}
	}
}

void
db_pmap_kernel(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	extern struct pmap kernel_pmap_;
	int i, j, full = 0;
	u_int64_t data;

	{
		register char c, *cp = modif;
		while ((c = *cp++) != 0)
			if (c == 'f')
				full = 1;
	}
	if (have_addr) {
		/* lookup an entry for this VA */

		if ((data = pseg_get(&kernel_pmap_, (vaddr_t)addr))) {
			db_printf("pmap_kernel(%p)->pm_segs[%lx][%lx][%lx]=>%qx\n",
				  (void *)addr, (u_long)va_to_seg(addr),
				  (u_long)va_to_dir(addr), (u_long)va_to_pte(addr),
				  (unsigned long long)data);
		} else {
			db_printf("No mapping for %p\n", (void *)addr);
		}
		return;
	}

	db_printf("pmap_kernel(%p) psegs %p phys %llx\n",
		  &kernel_pmap_, kernel_pmap_.pm_segs,
		  (unsigned long long)kernel_pmap_.pm_physaddr);
	if (full) {
		db_dump_pmap(&kernel_pmap_);
	} else {
		for (j=i=0; i<STSZ; i++) {
			long seg = (long)ldxa((vaddr_t)&kernel_pmap_.pm_segs[i], ASI_PHYS_CACHED);
			if (seg)
				db_printf("seg %d => %lx%c", i, seg, (j++%4)?'\t':'\n');
		}
	}
}

void
db_pmap_cmd(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	struct pmap* pm=NULL;
	int i, j=0, full = 0;

	{
		register char c, *cp = modif;
		if (modif)
			while ((c = *cp++) != 0)
				if (c == 'f')
					full = 1;
	}
	if (curproc && curproc->p_vmspace)
		pm = curproc->p_vmspace->vm_map.pmap;
	if (have_addr) {
		pm = (struct pmap*)addr;
	}

	db_printf("pmap %p: ctx %x refs %d physaddr %llx psegs %p\n",
		pm, pm->pm_ctx, pm->pm_refs,
		(unsigned long long)pm->pm_physaddr, pm->pm_segs);

	if (full) {
		db_dump_pmap(pm);
	} else {
		for (i=0; i<STSZ; i++) {
			long seg = (long)ldxa((vaddr_t)&kernel_pmap_.pm_segs[i], ASI_PHYS_CACHED);
			if (seg)
				db_printf("seg %d => %lx%c", i, seg, (j++%4)?'\t':'\n');
		}
	}
}

void
db_lock(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
#if 0
	struct lock *l;

	if (!have_addr) {
		db_printf("What lock address?\n");
		return;
	}

	l = (struct lock *)addr;
	db_printf("flags=%x\n waitcount=%x sharecount=%x "
	    "exclusivecount=%x\n wmesg=%s recurselevel=%x\n",
	    l->lk_flags, l->lk_waitcount,
	    l->lk_sharecount, l->lk_exclusivecount, l->lk_wmesg,
	    l->lk_recurselevel);
#else
	db_printf("locks unsupported\n");
#endif
}

void
db_dump_dtsb(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	extern pte_t *tsb_dmmu;
	extern int tsbsize;
#define TSBENTS (512<<tsbsize)
	int i;

	db_printf("TSB:\n");
	for (i=0; i<TSBENTS; i++) {
		db_printf("%4d:%4d:%08x %08x:%08x ", i,
			  (int)((tsb_dmmu[i].tag&TSB_TAG_G)?-1:TSB_TAG_CTX(tsb_dmmu[i].tag)),
			  (int)((i<<13)|TSB_TAG_VA(tsb_dmmu[i].tag)),
			  (int)(tsb_dmmu[i].data>>32), (int)tsb_dmmu[i].data);
		i++;
		db_printf("%4d:%4d:%08x %08x:%08x\n", i,
			  (int)((tsb_dmmu[i].tag&TSB_TAG_G)?-1:TSB_TAG_CTX(tsb_dmmu[i].tag)),
			  (int)((i<<13)|TSB_TAG_VA(tsb_dmmu[i].tag)),
			  (int)(tsb_dmmu[i].data>>32), (int)tsb_dmmu[i].data);
	}
}

void db_page_cmd(db_expr_t, int, db_expr_t, char *);
void
db_page_cmd(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{

	if (!have_addr) {
		db_printf("Need paddr for page\n");
		return;
	}

	db_printf("pa %llx pg %p\n", (unsigned long long)addr,
	    PHYS_TO_VM_PAGE(addr));
}

void
db_proc_cmd(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	struct proc *p;

	p = curproc;
	if (have_addr)
		p = (struct proc*) addr;
	if (p == NULL) {
		db_printf("no current process\n");
		return;
	}
	db_printf("process %p:", p);
	db_printf("pid:%d vmspace:%p pmap:%p ctx:%x wchan:%p pri:%d upri:%d\n",
	    p->p_pid, p->p_vmspace, p->p_vmspace->vm_map.pmap,
	    p->p_vmspace->vm_map.pmap->pm_ctx,
	    p->p_wchan, p->p_priority, p->p_usrpri);
	db_printf("maxsaddr:%p ssiz:%dpg or %llxB\n",
	    p->p_vmspace->vm_maxsaddr, p->p_vmspace->vm_ssize,
	    (unsigned long long)ptoa(p->p_vmspace->vm_ssize));
	db_printf("profile timer: %lld sec %ld usec\n",
	    (long long)p->p_p->ps_timer[ITIMER_PROF].it_value.tv_sec,
	    p->p_p->ps_timer[ITIMER_PROF].it_value.tv_usec);
	db_printf("pcb: %p tf: %p fpstate: %p\n", &p->p_addr->u_pcb,
	    p->p_md.md_tf, p->p_md.md_fpstate);
	return;
}

void
db_ctx_cmd(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	struct proc *p;

	/* XXX LOCKING XXX */
	LIST_FOREACH(p, &allproc, p_list) {
		if (p->p_stat) {
			db_printf("process %p:", p);
			db_printf("pid:%d pmap:%p ctx:%x tf:%p fpstate %p "
				"lastcall:%s\n",
				p->p_pid, p->p_vmspace->vm_map.pmap,
				p->p_vmspace->vm_map.pmap->pm_ctx,
				p->p_md.md_tf, p->p_md.md_fpstate,
				(p->p_addr->u_pcb.lastcall)?
				p->p_addr->u_pcb.lastcall : "Null");
		}
	}
	return;
}

void
db_dump_pcb(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	struct pcb *pcb;
	int i;

	pcb = curpcb;
	if (have_addr)
		pcb = (struct pcb*) addr;

	db_printf("pcb@%p sp:%p pc:%p cwp:%d pil:%d nsaved:%x onfault:%p\nlastcall:%s\nfull windows:\n",
		  pcb, (void *)(long)pcb->pcb_sp, (void *)(long)pcb->pcb_pc, pcb->pcb_cwp,
		  pcb->pcb_pil, pcb->pcb_nsaved, (void *)pcb->pcb_onfault,
		  (pcb->lastcall)?pcb->lastcall:"Null");

	for (i=0; i<pcb->pcb_nsaved; i++) {
		db_printf("win %d: at %llx local, in\n", i,
			  (unsigned long long)pcb->pcb_rwsp[i]);
		db_printf("%16llx %16llx %16llx %16llx\n",
			  (unsigned long long)pcb->pcb_rw[i].rw_local[0],
			  (unsigned long long)pcb->pcb_rw[i].rw_local[1],
			  (unsigned long long)pcb->pcb_rw[i].rw_local[2],
			  (unsigned long long)pcb->pcb_rw[i].rw_local[3]);
		db_printf("%16llx %16llx %16llx %16llx\n",
			  (unsigned long long)pcb->pcb_rw[i].rw_local[4],
			  (unsigned long long)pcb->pcb_rw[i].rw_local[5],
			  (unsigned long long)pcb->pcb_rw[i].rw_local[6],
			  (unsigned long long)pcb->pcb_rw[i].rw_local[7]);
		db_printf("%16llx %16llx %16llx %16llx\n",
			  (unsigned long long)pcb->pcb_rw[i].rw_in[0],
			  (unsigned long long)pcb->pcb_rw[i].rw_in[1],
			  (unsigned long long)pcb->pcb_rw[i].rw_in[2],
			  (unsigned long long)pcb->pcb_rw[i].rw_in[3]);
		db_printf("%16llx %16llx %16llx %16llx\n",
			  (unsigned long long)pcb->pcb_rw[i].rw_in[4],
			  (unsigned long long)pcb->pcb_rw[i].rw_in[5],
			  (unsigned long long)pcb->pcb_rw[i].rw_in[6],
			  (unsigned long long)pcb->pcb_rw[i].rw_in[7]);
	}
}

void
db_setpcb(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	struct proc *p;

	if (!have_addr) {
		db_printf("What PID do you want to map in?\n");
		return;
	}

	LIST_FOREACH(p, &allproc, p_list) {
		if (p->p_stat && p->p_pid == addr) {
			curproc = p;
			curpcb = (struct pcb*)p->p_addr;
			if (p->p_vmspace->vm_map.pmap->pm_ctx) {
				switchtoctx(p->p_vmspace->vm_map.pmap->pm_ctx);
				return;
			}
			db_printf("PID %ld has a null context.\n", addr);
			return;
		}
	}
	db_printf("PID %ld not found.\n", addr);
}

static void
db_print_trace_entry(te, i)
	struct traptrace *te;
	int i;
{
	db_printf("%d:%d p:%d tt:%d:%llx:%llx %llx:%llx ", i,
		  (int)te->tl, (int)te->pid,
		  (int)te->tt, (unsigned long long)te->tstate,
		  (unsigned long long)te->tfault, (unsigned long long)te->tsp,
		  (unsigned long long)te->tpc);
	db_printsym((u_long)te->tpc, DB_STGY_PROC, db_printf);
	db_printf(": ");
	if ((te->tpc && !(te->tpc&0x3)) &&
	    curproc &&
	    (curproc->p_pid == te->pid)) {
		db_disasm((u_long)te->tpc, 0);
	} else db_printf("\n");
}

void
db_traptrace(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	int i, start = 0, full = 0, reverse = 0;
	struct traptrace *end;

	start = 0;
	end = &trap_trace_end[0];

	{
		register char c, *cp = modif;
		if (modif)
			while ((c = *cp++) != 0) {
				if (c == 'f')
					full = 1;
				if (c == 'r')
					reverse = 1;
			}
	}

	if (have_addr) {
		start = addr / (sizeof (struct traptrace));
		if (&trap_trace[start] > &trap_trace_end[0]) {
			db_printf("Address out of range.\n");
			return;
		}
		if (!full) end =  &trap_trace[start+1];
	}

	db_printf("#:tl p:pid tt:tt:tstate:tfault sp:pc\n");
	if (reverse) {
		if (full && start)
			for (i=start; --i;) {
				db_print_trace_entry(&trap_trace[i], i);
			}
		i = (end - &trap_trace[0]);
		while(--i > start) {
			db_print_trace_entry(&trap_trace[i], i);
		}
	} else {
		for (i=start; &trap_trace[i] < end ; i++) {
			db_print_trace_entry(&trap_trace[i], i);
		}
		if (full && start)
			for (i=0; i < start ; i++) {
				db_print_trace_entry(&trap_trace[i], i);
			}
	}
}

/*
 * Use physical or virtual watchpoint registers -- ugh
 */
void
db_watch(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	int phys = 0;

#define WATCH_VR	(1L<<22)
#define WATCH_VW	(1L<<21)
#define WATCH_PR	(1L<<24)
#define WATCH_PW	(1L<<23)
#define WATCH_PM	(((u_int64_t)0xffffL)<<33)
#define WATCH_VM	(((u_int64_t)0xffffL)<<25)

	{
		register char c, *cp = modif;
		if (modif)
			while ((c = *cp++) != 0)
				if (c == 'p')
					phys = 1;
	}
	if (have_addr) {
		/* turn on the watchpoint */
		int64_t tmp = ldxa(0, ASI_MCCR);

		if (phys) {
			tmp &= ~(WATCH_PM|WATCH_PR|WATCH_PW);
			stxa(PHYSICAL_WATCHPOINT, ASI_DMMU, addr);
		} else {
			tmp &= ~(WATCH_VM|WATCH_VR|WATCH_VW);
			stxa(VIRTUAL_WATCHPOINT, ASI_DMMU, addr);
		}
		stxa(0, ASI_MCCR, tmp);
	} else {
		/* turn off the watchpoint */
		int64_t tmp = ldxa(0, ASI_MCCR);
		if (phys) tmp &= ~(WATCH_PM);
		else tmp &= ~(WATCH_VM);
		stxa(0, ASI_MCCR, tmp);
	}
}

/*
 * Provide a way to trigger an External Initiated Reset (XIR).  Some
 * systems can target individual processors, others can only target
 * all processors at once.
 */

struct xirhand {
	void (*xh_fun)(void *, int);
	void *xh_arg;
	SIMPLEQ_ENTRY(xirhand) xh_list;
};

SIMPLEQ_HEAD(, xirhand) db_xh = SIMPLEQ_HEAD_INITIALIZER(db_xh);

void
db_xir(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
{
	struct xirhand *xh;

	if (!have_addr)
		addr = -1;

	SIMPLEQ_FOREACH(xh, &db_xh, xh_list) {
		xh->xh_fun(xh->xh_arg, addr);
	}
}

void
db_register_xir(void (*fun)(void *, int), void *arg)
{
	struct xirhand *xh;

	xh = malloc(sizeof(*xh), M_DEVBUF, M_NOWAIT);
	if (xh == NULL)
		panic("db_register_xir");
	xh->xh_fun = fun;
	xh->xh_arg = arg;
	SIMPLEQ_INSERT_TAIL(&db_xh, xh, xh_list);
}

#if NESP_SBUS
extern void db_esp(db_expr_t, int, db_expr_t, char *);
#endif

struct db_command db_machine_command_table[] = {
	{ "ctx",	db_ctx_cmd,	0,	0 },
	{ "dtlb",	db_dump_dtlb,	0,	0 },
	{ "dtsb",	db_dump_dtsb,	0,	0 },
#if NESP_SBUS
	{ "esp",	db_esp,		0,	0 },
#endif
	{ "fpstate",	db_dump_fpstate,0,	0 },
	{ "itlb",	db_dump_itlb,	0,	0 },
	{ "kmap",	db_pmap_kernel,	0,	0 },
	{ "lock",	db_lock,	0,	0 },
	{ "pcb",	db_dump_pcb,	0,	0 },
	{ "pctx",	db_setpcb,	0,	0 },
	{ "page",	db_page_cmd,	0,	0 },
	{ "phys",	db_pload_cmd,	0,	0 },
	{ "pmap",	db_pmap_cmd,	0,	0 },
	{ "proc",	db_proc_cmd,	0,	0 },
	{ "prom",	db_prom_cmd,	0,	0 },
	{ "pv",		db_dump_pv,	0,	0 },
	{ "stack",	db_dump_stack,	0,	0 },
	{ "tf",		db_dump_trap,	0,	0 },
	{ "ts",		db_dump_ts,	0,	0 },
	{ "traptrace",	db_traptrace,	0,	0 },
	{ "watch",	db_watch,	0,	0 },
	{ "window",	db_dump_window,	0,	0 },
	{ "xir",	db_xir,		0,	0 },
	{ (char *)0, }
};

/*
 * support for SOFTWARE_SSTEP:
 * return the next pc if the given branch is taken.
 *
 * note: in the case of conditional branches with annul,
 * this actually returns the next pc in the "not taken" path,
 * but in that case next_instr_address() will return the
 * next pc in the "taken" path.  so even tho the breakpoints
 * are backwards, everything will still work, and the logic is
 * much simpler this way.
 */
db_addr_t
db_branch_taken(inst, pc, regs)
	int inst;
	db_addr_t pc;
	db_regs_t *regs;
{
    union instr insn;
    db_addr_t npc = ddb_regs.ddb_tf.tf_npc;

    insn.i_int = inst;

    /* the fancy union just gets in the way of this: */
    switch(inst & 0xffc00000) {
    case 0x30400000:	/* branch always, annul, with prediction */
	return pc + ((inst<<(32-19))>>((32-19)-2));
    case 0x30800000:	/* branch always, annul */
	return pc + ((inst<<(32-22))>>((32-22)-2));
    }

    /*
     * if this is not an annulled conditional branch, the next pc is "npc".
     */

    if (insn.i_any.i_op != IOP_OP2 || insn.i_branch.i_annul != 1)
	return npc;

    switch (insn.i_op2.i_op2) {
      case IOP2_Bicc:
      case IOP2_FBfcc:
      case IOP2_BPcc:
      case IOP2_FBPfcc:
      case IOP2_CBccc:
	/* branch on some condition-code */
	switch (insn.i_branch.i_cond)
	{
	  case Icc_A: /* always */
	    return pc + ((inst << 10) >> 8);

	  default: /* all other conditions */
	    return npc + 4;
	}

      case IOP2_BPr:
	/* branch on register, always conditional */
	return npc + 4;

      default:
	/* not a branch */
	panic("branch_taken() on non-branch");
    }
}

boolean_t
db_inst_branch(inst)
	int inst;
{
    union instr insn;

    insn.i_int = inst;

    /* the fancy union just gets in the way of this: */
    switch(inst & 0xffc00000) {
    case 0x30400000:	/* branch always, annul, with prediction */
	return TRUE;
    case 0x30800000:	/* branch always, annul */
	return TRUE;
    }

    if (insn.i_any.i_op != IOP_OP2)
	return FALSE;

    switch (insn.i_op2.i_op2) {
      case IOP2_BPcc:
      case IOP2_Bicc:
      case IOP2_BPr:
      case IOP2_FBPfcc:
      case IOP2_FBfcc:
      case IOP2_CBccc:
	return TRUE;

      default:
	return FALSE;
    }
}

boolean_t
db_inst_call(inst)
	int inst;
{
    union instr insn;

    insn.i_int = inst;

    switch (insn.i_any.i_op) {
      case IOP_CALL:
	return TRUE;

      case IOP_reg:
	return (insn.i_op3.i_op3 == IOP3_JMPL) && !db_inst_return(inst);

      default:
	return FALSE;
    }
}

boolean_t
db_inst_unconditional_flow_transfer(inst)
	int inst;
{
    union instr insn;

    insn.i_int = inst;

    if (db_inst_call(inst))
	return TRUE;

    if (insn.i_any.i_op != IOP_OP2)
	return FALSE;

    switch (insn.i_op2.i_op2)
    {
      case IOP2_BPcc:
      case IOP2_Bicc:
      case IOP2_FBPfcc:
      case IOP2_FBfcc:
      case IOP2_CBccc:
	return insn.i_branch.i_cond == Icc_A;

      default:
	return FALSE;
    }
}

boolean_t
db_inst_return(inst)
	int inst;
{
    return (inst == I_JMPLri(I_G0, I_O7, 8) ||		/* ret */
	    inst == I_JMPLri(I_G0, I_I7, 8));		/* retl */
}

boolean_t
db_inst_trap_return(inst)
	int inst;
{
    union instr insn;

    insn.i_int = inst;

    return (insn.i_any.i_op == IOP_reg &&
	    insn.i_op3.i_op3 == IOP3_RETT);
}

void
db_machine_init()
{
	db_machine_commands_install(db_machine_command_table);
}

license: unknown


code:
/*	$OpenBSD: db_trace.c,v 1.10 2015/02/09 09:21:30 miod Exp $	*/
/*	$NetBSD: db_trace.c,v 1.23 2001/07/10 06:06:16 eeh Exp $ */

/*
 * Mach Operating System
 * Copyright (c) 1991,1990 Carnegie Mellon University
 * 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 ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS 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 <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/user.h>
#include <machine/db_machdep.h>
#include <machine/ctlreg.h>

#include <ddb/db_access.h>
#include <ddb/db_sym.h>
#include <ddb/db_interface.h>
#include <ddb/db_output.h>

void db_dump_fpstate(db_expr_t, int, db_expr_t, char *);
void db_dump_window(db_expr_t, int, db_expr_t, char *);
void db_dump_stack(db_expr_t, int, db_expr_t, char *);
void db_dump_trap(db_expr_t, int, db_expr_t, char *);
void db_dump_ts(db_expr_t, int, db_expr_t, char *);
void db_print_window(u_int64_t);

#if 0
#define INKERNEL(va)	(((vaddr_t)(va)) >= VM_MIN_KERNEL_ADDRESS) /* Not really true, y'know */
#else
#define INKERNEL(va)	1	/* Everything's in the kernel now. 8^) */
#endif

#define	KLOAD(x)	probeget((paddr_t)(u_long)&(x), ASI_PRIMARY, sizeof(x))
#define ULOAD(x)	probeget((paddr_t)(u_long)&(x), ASI_AIUS, sizeof(x))

void
db_stack_trace_print(addr, have_addr, count, modif, pr)
	db_expr_t       addr;
	int             have_addr;
	db_expr_t       count;
	char            *modif;
	int		(*pr)(const char *, ...);
{
	vaddr_t		frame;
	boolean_t	kernel_only = TRUE;
	boolean_t	trace_thread = FALSE;
	char		c, *cp = modif;

	while ((c = *cp++) != 0) {
		if (c == 't')
			trace_thread = TRUE;
		if (c == 'u')
			kernel_only = FALSE;
	}

	if (!have_addr)
		frame = (vaddr_t)DDB_TF->tf_out[6];
	else {
		if (trace_thread) {
			struct proc *p;
			struct user *u;
			(*pr)("trace: pid %d ", (int)addr);
			p = pfind(addr);
			if (p == NULL) {
				(*pr)("not found\n");
				return;
			}
			u = p->p_addr;
			frame = (vaddr_t)u->u_pcb.pcb_sp;
			(*pr)("at %p\n", frame);
		} else {
			frame = (vaddr_t)addr;
		}
	}

	while (count--) {
		int		i;
		db_expr_t	offset;
		char		*name;
		db_addr_t	pc;
		struct frame64	*f64;
		struct frame32  *f32;

		/*
		 * Switch to frame that contains arguments
		 */
		if (frame & 1) {
			f64 = (struct frame64 *)(frame + BIAS);
			pc = (db_addr_t)KLOAD(f64->fr_pc);

			frame = KLOAD(f64->fr_fp);
		} else {
			f32 = (struct frame32 *)(frame);
			pc = (db_addr_t)KLOAD(f32->fr_pc);

			frame = (long)KLOAD(f32->fr_fp);
		}

		if (kernel_only) {
			if (pc < KERNBASE || pc >= KERNEND)
				break;
			if (frame < KERNBASE)
				break;
		} else {
			if (frame == 0 || frame == (vaddr_t)-1)
				break;
		}
#if 0
		if (!INKERNEL(frame))
			break;
#endif

		db_find_sym_and_offset(pc, &name, &offset);
		if (name == NULL)
			name = "?";

		(*pr)("%s(", name);

		/*
		 * Print %i0..%i5; hope these still reflect the
		 * actual arguments somewhat...
		 */
		if (frame & 1) {
			f64 = (struct frame64 *)(frame + BIAS);
			for (i = 0; i < 5; i++)
				(*pr)("%lx, ", (long)KLOAD(f64->fr_arg[i]));
			(*pr)("%lx) at ", (long)KLOAD(f64->fr_arg[i]));
		} else {
			f32 = (struct frame32 *)(frame);
			for (i = 0; i < 5; i++)
				(*pr)("%x, ", (u_int)KLOAD(f32->fr_arg[i]));
			(*pr)("%x) at ", (u_int)KLOAD(f32->fr_arg[i]));
		}
		db_printsym(pc, DB_STGY_PROC, pr);
		(*pr)("\n");
	}
}

void
db_dump_window(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	int i;
	u_int64_t frame = DDB_TF->tf_out[6];

	/* Addr is really window number */
	if (!have_addr)
		addr = 0;

	/* Traverse window stack */
	for (i=0; i<addr && frame; i++) {
		if (frame & 1)
			frame = (u_int64_t)((struct frame64 *)(u_long)(frame + BIAS))->fr_fp;
		else frame = (u_int64_t)((struct frame32 *)(u_long)frame)->fr_fp;
	}

	db_printf("Window %lx ", addr);
	db_print_window(frame);
}

void
db_print_window(frame)
u_int64_t frame;
{
	if (frame & 1) {
		struct frame64* f = (struct frame64*)(u_long)(frame + BIAS);

		db_printf("frame64 %p locals, ins:\n", f);
		if (INKERNEL(f)) {
			db_printf("%llx %llx %llx %llx ",
				  (unsigned long long)f->fr_local[0],
				  (unsigned long long)f->fr_local[1],
				  (unsigned long long)f->fr_local[2],
				  (unsigned long long)f->fr_local[3]);
			db_printf("%llx %llx %llx %llx\n",
				  (unsigned long long)f->fr_local[4],
				  (unsigned long long)f->fr_local[5],
				  (unsigned long long)f->fr_local[6],
				  (unsigned long long)f->fr_local[7]);
			db_printf("%llx %llx %llx %llx ",
				  (unsigned long long)f->fr_arg[0],
				  (unsigned long long)f->fr_arg[1],
				  (unsigned long long)f->fr_arg[2],
				  (unsigned long long)f->fr_arg[3]);
			db_printf("%llx %llx %llx=sp %llx=pc:",
				  (unsigned long long)f->fr_arg[4],
				  (unsigned long long)f->fr_arg[5],
				  (unsigned long long)f->fr_fp,
				  (unsigned long long)f->fr_pc);
			/* Sometimes this don't work.  Dunno why. */
			db_printsym(f->fr_pc, DB_STGY_PROC, db_printf);
			db_printf("\n");
		} else {
			struct frame64 fr;

			if (copyin(f, &fr, sizeof(fr))) return;
			f = &fr;
			db_printf("%llx %llx %llx %llx ",
				  (unsigned long long)f->fr_local[0], (unsigned long long)f->fr_local[1], (unsigned long long)f->fr_local[2], (unsigned long long)f->fr_local[3]);
			db_printf("%llx %llx %llx %llx\n",
				  (unsigned long long)f->fr_local[4], (unsigned long long)f->fr_local[5], (unsigned long long)f->fr_local[6], (unsigned long long)f->fr_local[7]);
			db_printf("%llx %llx %llx %llx ",
				  (unsigned long long)f->fr_arg[0],
				  (unsigned long long)f->fr_arg[1],
				  (unsigned long long)f->fr_arg[2],
				  (unsigned long long)f->fr_arg[3]);
			db_printf("%llx %llx %llx=sp %llx=pc",
				  (unsigned long long)f->fr_arg[4],
				  (unsigned long long)f->fr_arg[5],
				  (unsigned long long)f->fr_fp,
				  (unsigned long long)f->fr_pc);
			db_printf("\n");
		}
	} else {
		struct frame32* f = (struct frame32*)(u_long)frame;

		db_printf("frame %p locals, ins:\n", f);
		if (INKERNEL(f)) {
			db_printf("%8x %8x %8x %8x %8x %8x %8x %8x\n",
				  f->fr_local[0], f->fr_local[1], f->fr_local[2], f->fr_local[3],
				  f->fr_local[4], f->fr_local[5], f->fr_local[6], f->fr_local[7]);
			db_printf("%8x %8x %8x %8x %8x %8x %8x=sp %8x=pc:",
				  f->fr_arg[0], f->fr_arg[1], f->fr_arg[2], f->fr_arg[3],
				  f->fr_arg[4], f->fr_arg[5], f->fr_fp, f->fr_pc);
			db_printsym(f->fr_pc, DB_STGY_PROC, db_printf);
			db_printf("\n");
		} else {
			struct frame32 fr;

			if (copyin(f, &fr, sizeof(fr))) return;
			f = &fr;
			db_printf("%8x %8x %8x %8x %8x %8x %8x %8x\n",
				  f->fr_local[0], f->fr_local[1],
				  f->fr_local[2], f->fr_local[3],
				  f->fr_local[4], f->fr_local[5],
				  f->fr_local[6], f->fr_local[7]);
			db_printf("%8x %8x %8x %8x %8x %8x %8x=sp %8x=pc\n",
				  f->fr_arg[0], f->fr_arg[1],
				  f->fr_arg[2], f->fr_arg[3],
				  f->fr_arg[4], f->fr_arg[5],
				  f->fr_fp, f->fr_pc);
		}
	}
}

void
db_dump_stack(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	int		i;
	u_int64_t	frame, oldframe;
	boolean_t	kernel_only = TRUE;
	char		c, *cp = modif;

	while ((c = *cp++) != 0)
		if (c == 'u')
			kernel_only = FALSE;

	if (count == -1)
		count = 65535;

	if (!have_addr)
		frame = DDB_TF->tf_out[6];
	else
		frame = addr;

	/* Traverse window stack */
	oldframe = 0;
	for (i=0; i<count && frame; i++) {
		if (oldframe == frame) {
			db_printf("WARNING: stack loop at %llx\n",
			    (unsigned long long) frame);
			break;
		}
		oldframe = frame;
		if (frame & 1) {
			frame += BIAS;
			if (!INKERNEL(((struct frame64 *)(u_long)(frame)))
			    && kernel_only) break;
			db_printf("Window %x ", i);
			db_print_window(frame - BIAS);
			if (!INKERNEL(((struct frame64 *)(u_long)(frame))))
				copyin(((caddr_t)&((struct frame64 *)(u_long)frame)->fr_fp), &frame, sizeof(frame));
			else
				frame = ((struct frame64 *)(u_long)frame)->fr_fp;
		} else {
			u_int32_t tmp;
			if (!INKERNEL(((struct frame32 *)(u_long)frame))
			    && kernel_only) break;
			db_printf("Window %x ", i);
			db_print_window(frame);
			if (!INKERNEL(((struct frame32 *)(u_long)frame))) {
				copyin(&((struct frame32 *)(u_long)frame)->fr_fp, &tmp, sizeof(tmp));
				frame = (u_int64_t)tmp;
			} else
				frame = (u_int64_t)((struct frame32 *)(u_long)frame)->fr_fp;
		}
	}

}

void
db_dump_trap(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	struct trapframe64 *tf;

	/* Use our last trapframe? */
	tf = &ddb_regs.ddb_tf;
	{
		/* Or the user trapframe? */
		register char c, *cp = modif;
		while ((c = *cp++) != 0)
			if (c == 'u')
				tf = curproc->p_md.md_tf;
	}
	/* Or an arbitrary trapframe */
	if (have_addr)
		tf = (struct trapframe64 *)addr;

	db_printf("Trapframe %p:\ttstate: %llx\tpc: %llx\tnpc: %llx\n",
		  tf, (unsigned long long)tf->tf_tstate,
		  (unsigned long long)tf->tf_pc,
		  (unsigned long long)tf->tf_npc);
	db_printf("y: %x\tpil: %d\toldpil: %d\tfault: %llx\tkstack: %llx\ttt: %x\nGlobals:\n",
		  (int)tf->tf_y, (int)tf->tf_pil, (int)tf->tf_oldpil,
		  (unsigned long long)tf->tf_fault,
		  (unsigned long long)tf->tf_kstack, (int)tf->tf_tt);
	db_printf("%016llx %016llx %016llx %016llx\n",
		  (unsigned long long)tf->tf_global[0],
		  (unsigned long long)tf->tf_global[1],
		  (unsigned long long)tf->tf_global[2],
		  (unsigned long long)tf->tf_global[3]);
	db_printf("%016llx %016llx %016llx %016llx\nouts:\n",
		  (unsigned long long)tf->tf_global[4],
		  (unsigned long long)tf->tf_global[5],
		  (unsigned long long)tf->tf_global[6],
		  (unsigned long long)tf->tf_global[7]);
	db_printf("%016llx %016llx %016llx %016llx\n",
		  (unsigned long long)tf->tf_out[0],
		  (unsigned long long)tf->tf_out[1],
		  (unsigned long long)tf->tf_out[2],
		  (unsigned long long)tf->tf_out[3]);
	db_printf("%016llx %016llx %016llx %016llx\nlocals:\n",
		  (unsigned long long)tf->tf_out[4],
		  (unsigned long long)tf->tf_out[5],
		  (unsigned long long)tf->tf_out[6],
		  (unsigned long long)tf->tf_out[7]);
	db_printf("%016llx %016llx %016llx %016llx\n",
		  (unsigned long long)tf->tf_local[0],
		  (unsigned long long)tf->tf_local[1],
		  (unsigned long long)tf->tf_local[2],
		  (unsigned long long)tf->tf_local[3]);
	db_printf("%016llx %016llx %016llx %016llx\nins:\n",
		  (unsigned long long)tf->tf_local[4],
		  (unsigned long long)tf->tf_local[5],
		  (unsigned long long)tf->tf_local[6],
		  (unsigned long long)tf->tf_local[7]);
	db_printf("%016llx %016llx %016llx %016llx\n",
		  (unsigned long long)tf->tf_in[0],
		  (unsigned long long)tf->tf_in[1],
		  (unsigned long long)tf->tf_in[2],
		  (unsigned long long)tf->tf_in[3]);
	db_printf("%016llx %016llx %016llx %016llx\n",
		  (unsigned long long)tf->tf_in[4],
		  (unsigned long long)tf->tf_in[5],
		  (unsigned long long)tf->tf_in[6],
		  (unsigned long long)tf->tf_in[7]);
#if 0
	if (tf == curproc->p_md.md_tf) {
		struct rwindow32 *kstack = (struct rwindow32 *)(((caddr_t)tf)+CCFSZ);
		db_printf("ins (from stack):\n%016llx %016llx %016llx %016llx\n",
			  (int64_t)kstack->rw_local[0], (int64_t)kstack->rw_local[1],
			  (int64_t)kstack->rw_local[2], (int64_t)kstack->rw_local[3]);
		db_printf("%016llx %016llx %016llx %016llx\n",
			  (int64_t)kstack->rw_local[4], (int64_t)kstack->rw_local[5],
			  (int64_t)kstack->rw_local[6], (int64_t)kstack->rw_local[7]);
	}
#endif
}

void
db_dump_fpstate(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	struct fpstate64 *fpstate;

	/* Use our last trapframe? */
	fpstate = &ddb_regs.ddb_fpstate;
	/* Or an arbitrary trapframe */
	if (have_addr)
		fpstate = (struct fpstate64 *)addr;

	db_printf("fpstate %p: fsr = %llx gsr = %lx\nfpregs:\n",
		fpstate, (unsigned long long)fpstate->fs_fsr,
		(unsigned long)fpstate->fs_gsr);
	db_printf(" 0: %08x %08x %08x %08x %08x %08x %08x %08x\n",
		(unsigned int)fpstate->fs_regs[0],
		(unsigned int)fpstate->fs_regs[1],
		(unsigned int)fpstate->fs_regs[2],
		(unsigned int)fpstate->fs_regs[3],
		(unsigned int)fpstate->fs_regs[4],
		(unsigned int)fpstate->fs_regs[5],
		(unsigned int)fpstate->fs_regs[6],
		(unsigned int)fpstate->fs_regs[7]);
	db_printf(" 8: %08x %08x %08x %08x %08x %08x %08x %08x\n",
		(unsigned int)fpstate->fs_regs[8],
		(unsigned int)fpstate->fs_regs[9],
		(unsigned int)fpstate->fs_regs[10],
		(unsigned int)fpstate->fs_regs[11],
		(unsigned int)fpstate->fs_regs[12],
		(unsigned int)fpstate->fs_regs[13],
		(unsigned int)fpstate->fs_regs[14],
		(unsigned int)fpstate->fs_regs[15]);
	db_printf("16: %08x %08x %08x %08x %08x %08x %08x %08x\n",
		(unsigned int)fpstate->fs_regs[16],
		(unsigned int)fpstate->fs_regs[17],
		(unsigned int)fpstate->fs_regs[18],
		(unsigned int)fpstate->fs_regs[19],
		(unsigned int)fpstate->fs_regs[20],
		(unsigned int)fpstate->fs_regs[21],
		(unsigned int)fpstate->fs_regs[22],
		(unsigned int)fpstate->fs_regs[23]);
	db_printf("24: %08x %08x %08x %08x %08x %08x %08x %08x\n",
		(unsigned int)fpstate->fs_regs[24],
		(unsigned int)fpstate->fs_regs[25],
		(unsigned int)fpstate->fs_regs[26],
		(unsigned int)fpstate->fs_regs[27],
		(unsigned int)fpstate->fs_regs[28],
		(unsigned int)fpstate->fs_regs[29],
		(unsigned int)fpstate->fs_regs[30],
		(unsigned int)fpstate->fs_regs[31]);
	db_printf("32: %08x%08x %08x%08x %08x%08x %08x%08x\n",
		(unsigned int)fpstate->fs_regs[32],
		(unsigned int)fpstate->fs_regs[33],
		(unsigned int)fpstate->fs_regs[34],
		(unsigned int)fpstate->fs_regs[35],
		(unsigned int)fpstate->fs_regs[36],
		(unsigned int)fpstate->fs_regs[37],
		(unsigned int)fpstate->fs_regs[38],
		(unsigned int)fpstate->fs_regs[39]);
	db_printf("40: %08x%08x %08x%08x %08x%08x %08x%08x\n",
		(unsigned int)fpstate->fs_regs[40],
		(unsigned int)fpstate->fs_regs[41],
		(unsigned int)fpstate->fs_regs[42],
		(unsigned int)fpstate->fs_regs[43],
		(unsigned int)fpstate->fs_regs[44],
		(unsigned int)fpstate->fs_regs[45],
		(unsigned int)fpstate->fs_regs[46],
		(unsigned int)fpstate->fs_regs[47]);
	db_printf("48: %08x%08x %08x%08x %08x%08x %08x%08x\n",
		(unsigned int)fpstate->fs_regs[48],
		(unsigned int)fpstate->fs_regs[49],
		(unsigned int)fpstate->fs_regs[50],
		(unsigned int)fpstate->fs_regs[51],
		(unsigned int)fpstate->fs_regs[52],
		(unsigned int)fpstate->fs_regs[53],
		(unsigned int)fpstate->fs_regs[54],
		(unsigned int)fpstate->fs_regs[55]);
	db_printf("56: %08x%08x %08x%08x %08x%08x %08x%08x\n",
		(unsigned int)fpstate->fs_regs[56],
		(unsigned int)fpstate->fs_regs[57],
		(unsigned int)fpstate->fs_regs[58],
		(unsigned int)fpstate->fs_regs[59],
		(unsigned int)fpstate->fs_regs[60],
		(unsigned int)fpstate->fs_regs[61],
		(unsigned int)fpstate->fs_regs[62],
		(unsigned int)fpstate->fs_regs[63]);
}

void
db_dump_ts(addr, have_addr, count, modif)
	db_expr_t addr;
	int have_addr;
	db_expr_t count;
	char *modif;
{
	struct trapstate	*ts;
	int			i, tl;

	/* Use our last trapframe? */
	ts = &ddb_regs.ddb_ts[0];
	tl = ddb_regs.ddb_tl;
	for (i=0; i<tl; i++) {
		printf("%d tt=%lx tstate=%lx tpc=%p tnpc=%p\n",
		       i+1, (long)ts[i].tt, (u_long)ts[i].tstate,
		       (void *)(u_long)ts[i].tpc, (void *)(u_long)ts[i].tnpc);
	}

}