xref: /titanic_52/usr/src/cmd/mdb/sparc/mdb/proc_isadep.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * User Process Target SPARC v7 and v9 component
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * This file provides the ISA-dependent portion of the user process target
33*7c478bd9Sstevel@tonic-gate  * for both the sparcv7 and sparcv9 ISAs.  For more details on the
34*7c478bd9Sstevel@tonic-gate  * implementation refer to mdb_proc.c.
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
38*7c478bd9Sstevel@tonic-gate #define	__sparcv9cpu
39*7c478bd9Sstevel@tonic-gate #endif
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_proc.h>
42*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_kreg.h>
43*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
44*7c478bd9Sstevel@tonic-gate #include <mdb/mdb_stdlib.h>
45*7c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate #include <sys/elf_SPARC.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/stack.h>
49*7c478bd9Sstevel@tonic-gate #include <libproc.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #ifndef STACK_BIAS
52*7c478bd9Sstevel@tonic-gate #define	STACK_BIAS	0
53*7c478bd9Sstevel@tonic-gate #endif
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t pt_regdesc[] = {
56*7c478bd9Sstevel@tonic-gate 	{ "g0", R_G0, MDB_TGT_R_EXPORT },
57*7c478bd9Sstevel@tonic-gate 	{ "g1", R_G1, MDB_TGT_R_EXPORT },
58*7c478bd9Sstevel@tonic-gate 	{ "g2", R_G2, MDB_TGT_R_EXPORT },
59*7c478bd9Sstevel@tonic-gate 	{ "g3", R_G3, MDB_TGT_R_EXPORT },
60*7c478bd9Sstevel@tonic-gate 	{ "g4", R_G4, MDB_TGT_R_EXPORT },
61*7c478bd9Sstevel@tonic-gate 	{ "g5", R_G5, MDB_TGT_R_EXPORT },
62*7c478bd9Sstevel@tonic-gate 	{ "g6", R_G6, MDB_TGT_R_EXPORT },
63*7c478bd9Sstevel@tonic-gate 	{ "g7", R_G7, MDB_TGT_R_EXPORT },
64*7c478bd9Sstevel@tonic-gate 	{ "o0", R_O0, MDB_TGT_R_EXPORT },
65*7c478bd9Sstevel@tonic-gate 	{ "o1", R_O1, MDB_TGT_R_EXPORT },
66*7c478bd9Sstevel@tonic-gate 	{ "o2", R_O2, MDB_TGT_R_EXPORT },
67*7c478bd9Sstevel@tonic-gate 	{ "o3", R_O3, MDB_TGT_R_EXPORT },
68*7c478bd9Sstevel@tonic-gate 	{ "o4", R_O4, MDB_TGT_R_EXPORT },
69*7c478bd9Sstevel@tonic-gate 	{ "o5", R_O5, MDB_TGT_R_EXPORT },
70*7c478bd9Sstevel@tonic-gate 	{ "o6", R_O6, MDB_TGT_R_EXPORT },
71*7c478bd9Sstevel@tonic-gate 	{ "o7", R_O7, MDB_TGT_R_EXPORT },
72*7c478bd9Sstevel@tonic-gate 	{ "l0", R_L0, MDB_TGT_R_EXPORT },
73*7c478bd9Sstevel@tonic-gate 	{ "l1", R_L1, MDB_TGT_R_EXPORT },
74*7c478bd9Sstevel@tonic-gate 	{ "l2", R_L2, MDB_TGT_R_EXPORT },
75*7c478bd9Sstevel@tonic-gate 	{ "l3", R_L3, MDB_TGT_R_EXPORT },
76*7c478bd9Sstevel@tonic-gate 	{ "l4", R_L4, MDB_TGT_R_EXPORT },
77*7c478bd9Sstevel@tonic-gate 	{ "l5", R_L5, MDB_TGT_R_EXPORT },
78*7c478bd9Sstevel@tonic-gate 	{ "l6", R_L6, MDB_TGT_R_EXPORT },
79*7c478bd9Sstevel@tonic-gate 	{ "l7", R_L7, MDB_TGT_R_EXPORT },
80*7c478bd9Sstevel@tonic-gate 	{ "i0", R_I0, MDB_TGT_R_EXPORT },
81*7c478bd9Sstevel@tonic-gate 	{ "i1", R_I1, MDB_TGT_R_EXPORT },
82*7c478bd9Sstevel@tonic-gate 	{ "i2", R_I2, MDB_TGT_R_EXPORT },
83*7c478bd9Sstevel@tonic-gate 	{ "i3", R_I3, MDB_TGT_R_EXPORT },
84*7c478bd9Sstevel@tonic-gate 	{ "i4", R_I4, MDB_TGT_R_EXPORT },
85*7c478bd9Sstevel@tonic-gate 	{ "i5", R_I5, MDB_TGT_R_EXPORT },
86*7c478bd9Sstevel@tonic-gate 	{ "i6", R_I6, MDB_TGT_R_EXPORT },
87*7c478bd9Sstevel@tonic-gate 	{ "i7", R_I7, MDB_TGT_R_EXPORT },
88*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
89*7c478bd9Sstevel@tonic-gate 	{ "ccr", R_CCR, MDB_TGT_R_EXPORT },
90*7c478bd9Sstevel@tonic-gate #else
91*7c478bd9Sstevel@tonic-gate 	{ "psr", R_PSR, MDB_TGT_R_EXPORT },
92*7c478bd9Sstevel@tonic-gate #endif
93*7c478bd9Sstevel@tonic-gate 	{ "pc", R_PC, MDB_TGT_R_EXPORT },
94*7c478bd9Sstevel@tonic-gate 	{ "npc", R_nPC, MDB_TGT_R_EXPORT },
95*7c478bd9Sstevel@tonic-gate 	{ "y", R_Y, 0 },
96*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
97*7c478bd9Sstevel@tonic-gate 	{ "asi", R_ASI, MDB_TGT_R_EXPORT },
98*7c478bd9Sstevel@tonic-gate 	{ "fprs", R_FPRS, MDB_TGT_R_EXPORT },
99*7c478bd9Sstevel@tonic-gate #else
100*7c478bd9Sstevel@tonic-gate 	{ "wim", R_WIM, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
101*7c478bd9Sstevel@tonic-gate 	{ "tbr", R_TBR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
102*7c478bd9Sstevel@tonic-gate #endif
103*7c478bd9Sstevel@tonic-gate 	{ "sp", R_SP, MDB_TGT_R_EXPORT | MDB_TGT_R_ALIAS },
104*7c478bd9Sstevel@tonic-gate 	{ "fp", R_FP, MDB_TGT_R_EXPORT | MDB_TGT_R_ALIAS },
105*7c478bd9Sstevel@tonic-gate 	{ NULL, 0, 0 }
106*7c478bd9Sstevel@tonic-gate };
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate #define	FPU_FSR		0	/* fake register number for %fsr */
109*7c478bd9Sstevel@tonic-gate #define	FPU_FPRS	1	/* fake register number for %fprs */
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /*
112*7c478bd9Sstevel@tonic-gate  * We cannot rely on pr_instr, because if we hit a breakpoint or the user has
113*7c478bd9Sstevel@tonic-gate  * artifically modified memory, it will no longer be correct.
114*7c478bd9Sstevel@tonic-gate  */
115*7c478bd9Sstevel@tonic-gate static uint32_t
116*7c478bd9Sstevel@tonic-gate pt_read_instr(mdb_tgt_t *t)
117*7c478bd9Sstevel@tonic-gate {
118*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
119*7c478bd9Sstevel@tonic-gate 	uint32_t ret = 0;
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	(void) mdb_tgt_vread(t, &ret, sizeof (ret), psp->pr_reg[R_PC]);
122*7c478bd9Sstevel@tonic-gate 
123*7c478bd9Sstevel@tonic-gate 	return (ret);
124*7c478bd9Sstevel@tonic-gate }
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
127*7c478bd9Sstevel@tonic-gate int
128*7c478bd9Sstevel@tonic-gate pt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
129*7c478bd9Sstevel@tonic-gate {
130*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
131*7c478bd9Sstevel@tonic-gate 	mdb_tgt_tid_t tid;
132*7c478bd9Sstevel@tonic-gate 	prgregset_t grs;
133*7c478bd9Sstevel@tonic-gate 	uint64_t xgregs[8];
134*7c478bd9Sstevel@tonic-gate 	uint64_t xoregs[8];
135*7c478bd9Sstevel@tonic-gate 	int rwidth, i;
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32)
138*7c478bd9Sstevel@tonic-gate 	static const uint32_t zero[8] = { 0 };
139*7c478bd9Sstevel@tonic-gate 	prxregset_t xrs;
140*7c478bd9Sstevel@tonic-gate #endif
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate #define	GETREG2(x) ((uintptr_t)grs[(x)]), ((uintptr_t)grs[(x)])
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	if (argc != 0)
145*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) {
148*7c478bd9Sstevel@tonic-gate 		mdb_warn("no process active\n");
149*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
150*7c478bd9Sstevel@tonic-gate 	}
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	if (Pstate(t->t_pshandle) == PS_LOST) {
153*7c478bd9Sstevel@tonic-gate 		mdb_warn("debugger has lost control of process\n");
154*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
155*7c478bd9Sstevel@tonic-gate 	}
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC)
158*7c478bd9Sstevel@tonic-gate 		tid = (mdb_tgt_tid_t)addr;
159*7c478bd9Sstevel@tonic-gate 	else
160*7c478bd9Sstevel@tonic-gate 		tid = PTL_TID(t);
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if (PTL_GETREGS(t, tid, grs) != 0) {
163*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to get current register set");
164*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
165*7c478bd9Sstevel@tonic-gate 	}
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
168*7c478bd9Sstevel@tonic-gate 		xgregs[i] = (ulong_t)grs[R_G0 + i];
169*7c478bd9Sstevel@tonic-gate 		xoregs[i] = (ulong_t)grs[R_O0 + i];
170*7c478bd9Sstevel@tonic-gate 	}
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 	if (Pstatus(t->t_pshandle)->pr_dmodel == PR_MODEL_LP64)
173*7c478bd9Sstevel@tonic-gate 		rwidth = 16;
174*7c478bd9Sstevel@tonic-gate 	else
175*7c478bd9Sstevel@tonic-gate 		rwidth = 8;
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate #if defined(__sparc) && defined(_ILP32)
178*7c478bd9Sstevel@tonic-gate 	/*
179*7c478bd9Sstevel@tonic-gate 	 * If we are debugging a 32-bit SPARC process on an UltraSPARC CPU,
180*7c478bd9Sstevel@tonic-gate 	 * the globals and outs can have 32 upper bits hiding in the xregs.
181*7c478bd9Sstevel@tonic-gate 	 */
182*7c478bd9Sstevel@tonic-gate 	if (PTL_GETXREGS(t, tid, &xrs) == 0 && xrs.pr_type == XR_TYPE_V8P) {
183*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 8; i++) {
184*7c478bd9Sstevel@tonic-gate 			xgregs[i] |= (uint64_t)
185*7c478bd9Sstevel@tonic-gate 			    xrs.pr_un.pr_v8p.pr_xg[XR_G0 + i] << 32;
186*7c478bd9Sstevel@tonic-gate 			xoregs[i] |= (uint64_t)
187*7c478bd9Sstevel@tonic-gate 			    xrs.pr_un.pr_v8p.pr_xo[XR_O0 + i] << 32;
188*7c478bd9Sstevel@tonic-gate 		}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 		if (bcmp(xrs.pr_un.pr_v8p.pr_xg, zero, sizeof (zero)) ||
191*7c478bd9Sstevel@tonic-gate 		    bcmp(xrs.pr_un.pr_v8p.pr_xo, zero, sizeof (zero)))
192*7c478bd9Sstevel@tonic-gate 			rwidth = 16; /* one or more have upper bits set */
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate #endif	/* __sparc && _ILP32 */
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
197*7c478bd9Sstevel@tonic-gate 		mdb_printf("%%g%d = 0x%0*llx %15llA %%l%d = 0x%0?p %A\n",
198*7c478bd9Sstevel@tonic-gate 		    i, rwidth, xgregs[i], xgregs[i], i, GETREG2(R_L0 + i));
199*7c478bd9Sstevel@tonic-gate 	}
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
202*7c478bd9Sstevel@tonic-gate 		mdb_printf("%%o%d = 0x%0*llx %15llA %%i%d = 0x%0?p %A\n",
203*7c478bd9Sstevel@tonic-gate 		    i, rwidth, xoregs[i], xoregs[i], i, GETREG2(R_I0 + i));
204*7c478bd9Sstevel@tonic-gate 	}
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
209*7c478bd9Sstevel@tonic-gate 	mdb_printf(" %%ccr = 0x%02x xcc=%c%c%c%c icc=%c%c%c%c\n", grs[R_CCR],
210*7c478bd9Sstevel@tonic-gate 	    (grs[R_CCR] & KREG_CCR_XCC_N_MASK) ? 'N' : 'n',
211*7c478bd9Sstevel@tonic-gate 	    (grs[R_CCR] & KREG_CCR_XCC_Z_MASK) ? 'Z' : 'z',
212*7c478bd9Sstevel@tonic-gate 	    (grs[R_CCR] & KREG_CCR_XCC_V_MASK) ? 'V' : 'v',
213*7c478bd9Sstevel@tonic-gate 	    (grs[R_CCR] & KREG_CCR_XCC_C_MASK) ? 'C' : 'c',
214*7c478bd9Sstevel@tonic-gate 	    (grs[R_CCR] & KREG_CCR_ICC_N_MASK) ? 'N' : 'n',
215*7c478bd9Sstevel@tonic-gate 	    (grs[R_CCR] & KREG_CCR_ICC_Z_MASK) ? 'Z' : 'z',
216*7c478bd9Sstevel@tonic-gate 	    (grs[R_CCR] & KREG_CCR_ICC_V_MASK) ? 'V' : 'v',
217*7c478bd9Sstevel@tonic-gate 	    (grs[R_CCR] & KREG_CCR_ICC_C_MASK) ? 'C' : 'c');
218*7c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
219*7c478bd9Sstevel@tonic-gate 	mdb_printf(" %%psr = 0x%08x impl=0x%x ver=0x%x icc=%c%c%c%c\n"
220*7c478bd9Sstevel@tonic-gate 	    "                   ec=%u ef=%u pil=%u s=%u ps=%u et=%u cwp=0x%x\n",
221*7c478bd9Sstevel@tonic-gate 	    grs[R_PSR],
222*7c478bd9Sstevel@tonic-gate 	    (grs[R_PSR] & KREG_PSR_IMPL_MASK) >> KREG_PSR_IMPL_SHIFT,
223*7c478bd9Sstevel@tonic-gate 	    (grs[R_PSR] & KREG_PSR_VER_MASK) >> KREG_PSR_VER_SHIFT,
224*7c478bd9Sstevel@tonic-gate 	    (grs[R_PSR] & KREG_PSR_ICC_N_MASK) ? 'N' : 'n',
225*7c478bd9Sstevel@tonic-gate 	    (grs[R_PSR] & KREG_PSR_ICC_Z_MASK) ? 'Z' : 'z',
226*7c478bd9Sstevel@tonic-gate 	    (grs[R_PSR] & KREG_PSR_ICC_V_MASK) ? 'V' : 'v',
227*7c478bd9Sstevel@tonic-gate 	    (grs[R_PSR] & KREG_PSR_ICC_C_MASK) ? 'C' : 'c',
228*7c478bd9Sstevel@tonic-gate 	    grs[R_PSR] & KREG_PSR_EC_MASK, grs[R_PSR] & KREG_PSR_EF_MASK,
229*7c478bd9Sstevel@tonic-gate 	    (grs[R_PSR] & KREG_PSR_PIL_MASK) >> KREG_PSR_PIL_SHIFT,
230*7c478bd9Sstevel@tonic-gate 	    grs[R_PSR] & KREG_PSR_S_MASK, grs[R_PSR] & KREG_PSR_PS_MASK,
231*7c478bd9Sstevel@tonic-gate 	    grs[R_PSR] & KREG_PSR_ET_MASK,
232*7c478bd9Sstevel@tonic-gate 	    (grs[R_PSR] & KREG_PSR_CWP_MASK) >> KREG_PSR_CWP_SHIFT);
233*7c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
234*7c478bd9Sstevel@tonic-gate 
235*7c478bd9Sstevel@tonic-gate 	mdb_printf("   %%y = 0x%0?p\n", grs[R_Y]);
236*7c478bd9Sstevel@tonic-gate 
237*7c478bd9Sstevel@tonic-gate 	mdb_printf("  %%pc = 0x%0?p %A\n", GETREG2(R_PC));
238*7c478bd9Sstevel@tonic-gate 	mdb_printf(" %%npc = 0x%0?p %A\n", GETREG2(R_nPC));
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	mdb_printf("  %%sp = 0x%0?p\n", grs[R_SP]);
241*7c478bd9Sstevel@tonic-gate 	mdb_printf("  %%fp = 0x%0?p\n\n", grs[R_FP]);
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
244*7c478bd9Sstevel@tonic-gate 	mdb_printf(" %%asi = 0x%02lx\n", grs[R_ASI]);
245*7c478bd9Sstevel@tonic-gate 	mdb_printf("%%fprs = 0x%02lx\n", grs[R_FPRS]);
246*7c478bd9Sstevel@tonic-gate #else	/* __sparcv9 */
247*7c478bd9Sstevel@tonic-gate 	mdb_printf(" %%wim = 0x%08x\n", grs[R_WIM]);
248*7c478bd9Sstevel@tonic-gate 	mdb_printf(" %%tbr = 0x%08x\n", grs[R_TBR]);
249*7c478bd9Sstevel@tonic-gate #endif	/* __sparcv9 */
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
252*7c478bd9Sstevel@tonic-gate }
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
255*7c478bd9Sstevel@tonic-gate int
256*7c478bd9Sstevel@tonic-gate pt_fpregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
257*7c478bd9Sstevel@tonic-gate {
258*7c478bd9Sstevel@tonic-gate 	mdb_tgt_t *t = mdb.m_target;
259*7c478bd9Sstevel@tonic-gate 	mdb_tgt_tid_t tid;
260*7c478bd9Sstevel@tonic-gate 	int is_v8plus, is_v9, i;
261*7c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
262*7c478bd9Sstevel@tonic-gate 	prgregset_t grs;
263*7c478bd9Sstevel@tonic-gate #endif
264*7c478bd9Sstevel@tonic-gate 	prfpregset_t fprs;
265*7c478bd9Sstevel@tonic-gate 	prxregset_t xrs;
266*7c478bd9Sstevel@tonic-gate 	uint32_t *regs;
267*7c478bd9Sstevel@tonic-gate 	int ns, nd, nq;
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	enum {
270*7c478bd9Sstevel@tonic-gate 		FPR_MIXED	= 0x0, /* show single, double, and status */
271*7c478bd9Sstevel@tonic-gate 		FPR_SINGLE	= 0x1, /* show single-precision only */
272*7c478bd9Sstevel@tonic-gate 		FPR_DOUBLE	= 0x2, /* show double-precision only */
273*7c478bd9Sstevel@tonic-gate 		FPR_QUAD	= 0x4  /* show quad-precision only */
274*7c478bd9Sstevel@tonic-gate 	};
275*7c478bd9Sstevel@tonic-gate 
276*7c478bd9Sstevel@tonic-gate 	uint_t opts = FPR_MIXED;
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 	/*
279*7c478bd9Sstevel@tonic-gate 	 * The prfpregset structure only provides us with the FPU in the form
280*7c478bd9Sstevel@tonic-gate 	 * of 32-bit integers, doubles, or quads.  We use this union of the
281*7c478bd9Sstevel@tonic-gate 	 * various types to display floats, doubles, and long doubles.
282*7c478bd9Sstevel@tonic-gate 	 */
283*7c478bd9Sstevel@tonic-gate 	union {
284*7c478bd9Sstevel@tonic-gate 		struct {
285*7c478bd9Sstevel@tonic-gate 			uint32_t i1;
286*7c478bd9Sstevel@tonic-gate 			uint32_t i2;
287*7c478bd9Sstevel@tonic-gate 			uint32_t i3;
288*7c478bd9Sstevel@tonic-gate 			uint32_t i4;
289*7c478bd9Sstevel@tonic-gate 		} ip;
290*7c478bd9Sstevel@tonic-gate 		float f;
291*7c478bd9Sstevel@tonic-gate 		double d;
292*7c478bd9Sstevel@tonic-gate 		long double ld;
293*7c478bd9Sstevel@tonic-gate 	} fpu;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
296*7c478bd9Sstevel@tonic-gate 	    's', MDB_OPT_SETBITS, FPR_SINGLE, &opts,
297*7c478bd9Sstevel@tonic-gate 	    'd', MDB_OPT_SETBITS, FPR_DOUBLE, &opts,
298*7c478bd9Sstevel@tonic-gate 	    'q', MDB_OPT_SETBITS, FPR_QUAD, &opts, NULL) != argc)
299*7c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) {
302*7c478bd9Sstevel@tonic-gate 		mdb_warn("no process active\n");
303*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
304*7c478bd9Sstevel@tonic-gate 	}
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	if (Pstate(t->t_pshandle) == PS_LOST) {
307*7c478bd9Sstevel@tonic-gate 		mdb_warn("debugger has lost control of process\n");
308*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	if (flags & DCMD_ADDRSPEC)
312*7c478bd9Sstevel@tonic-gate 		tid = (mdb_tgt_tid_t)addr;
313*7c478bd9Sstevel@tonic-gate 	else
314*7c478bd9Sstevel@tonic-gate 		tid = PTL_TID(t);
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	is_v9 = Pstatus(t->t_pshandle)->pr_dmodel == PR_MODEL_LP64;
317*7c478bd9Sstevel@tonic-gate 	is_v8plus = is_v9 == 0 && PTL_GETXREGS(t, tid, &xrs) == 0 &&
318*7c478bd9Sstevel@tonic-gate 	    xrs.pr_type == XR_TYPE_V8P;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate #ifdef	__sparcv9
321*7c478bd9Sstevel@tonic-gate 	if (is_v9 && opts == FPR_MIXED) {
322*7c478bd9Sstevel@tonic-gate 		if (PTL_GETREGS(t, tid, grs) == 0)
323*7c478bd9Sstevel@tonic-gate 			mdb_printf("fprs %lx\n", grs[R_FPRS]);
324*7c478bd9Sstevel@tonic-gate 		else
325*7c478bd9Sstevel@tonic-gate 			mdb_warn("failed to read fprs register");
326*7c478bd9Sstevel@tonic-gate 	}
327*7c478bd9Sstevel@tonic-gate #endif
328*7c478bd9Sstevel@tonic-gate 	if (is_v8plus && opts == FPR_MIXED)
329*7c478bd9Sstevel@tonic-gate 		mdb_printf("fprs %x\n", xrs.pr_un.pr_v8p.pr_fprs);
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	if (PTL_GETFPREGS(t, tid, &fprs) != 0) {
332*7c478bd9Sstevel@tonic-gate 		mdb_warn("failed to get floating point registers");
333*7c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	if (opts == FPR_MIXED) {
337*7c478bd9Sstevel@tonic-gate 		uint64_t fsr = fprs.pr_fsr;
338*7c478bd9Sstevel@tonic-gate 		if (is_v8plus)
339*7c478bd9Sstevel@tonic-gate 			fsr |= (uint64_t)xrs.pr_un.pr_v8p.pr_xfsr << 32;
340*7c478bd9Sstevel@tonic-gate 		mdb_printf("fsr  %llx\n", fsr);
341*7c478bd9Sstevel@tonic-gate 	}
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	/*
344*7c478bd9Sstevel@tonic-gate 	 * Set up the regs pointer to be a pointer to a contiguous chunk of
345*7c478bd9Sstevel@tonic-gate 	 * memory containing all the floating pointer register data.  Set
346*7c478bd9Sstevel@tonic-gate 	 * ns, nd, and nq to indicate the number of registers of each type.
347*7c478bd9Sstevel@tonic-gate 	 */
348*7c478bd9Sstevel@tonic-gate 	if (is_v9) {
349*7c478bd9Sstevel@tonic-gate 		regs = fprs.pr_fr.pr_regs;
350*7c478bd9Sstevel@tonic-gate 		ns = 64;
351*7c478bd9Sstevel@tonic-gate 		nd = 32;
352*7c478bd9Sstevel@tonic-gate 		nq = 16;
353*7c478bd9Sstevel@tonic-gate 	} else if (is_v8plus) {
354*7c478bd9Sstevel@tonic-gate 		regs = mdb_alloc(sizeof (uint32_t) * 64, UM_SLEEP | UM_GC);
355*7c478bd9Sstevel@tonic-gate 		bcopy(fprs.pr_fr.pr_regs, regs, sizeof (uint32_t) * 32);
356*7c478bd9Sstevel@tonic-gate 		bcopy(xrs.pr_un.pr_v8p.pr_xfr.pr_regs, regs + 32,
357*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t) * 32);
358*7c478bd9Sstevel@tonic-gate 		ns = 64;
359*7c478bd9Sstevel@tonic-gate 		nd = 32;
360*7c478bd9Sstevel@tonic-gate 		nq = 16;
361*7c478bd9Sstevel@tonic-gate 	} else {
362*7c478bd9Sstevel@tonic-gate 		regs = fprs.pr_fr.pr_regs;
363*7c478bd9Sstevel@tonic-gate 		ns = 32;
364*7c478bd9Sstevel@tonic-gate 		nd = 16;
365*7c478bd9Sstevel@tonic-gate 		nq = 0;
366*7c478bd9Sstevel@tonic-gate 	}
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	if (opts == FPR_MIXED) {
369*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ns; i++) {
370*7c478bd9Sstevel@tonic-gate 			fpu.ip.i1 = regs[i];
371*7c478bd9Sstevel@tonic-gate 			mdb_printf("f%-3d %08x   %e", i, fpu.ip.i1, fpu.f);
372*7c478bd9Sstevel@tonic-gate 			if (i & 1) {
373*7c478bd9Sstevel@tonic-gate 				fpu.ip.i1 = regs[i - 1];
374*7c478bd9Sstevel@tonic-gate 				fpu.ip.i2 = regs[i];
375*7c478bd9Sstevel@tonic-gate 				mdb_printf("   %g", fpu.d);
376*7c478bd9Sstevel@tonic-gate 			}
377*7c478bd9Sstevel@tonic-gate 			mdb_printf("\n");
378*7c478bd9Sstevel@tonic-gate 		}
379*7c478bd9Sstevel@tonic-gate 	}
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 	if (opts & FPR_SINGLE) {
382*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ns; i++) {
383*7c478bd9Sstevel@tonic-gate 			fpu.ip.i1 = regs[i];
384*7c478bd9Sstevel@tonic-gate 			mdb_printf("f%-3d %08x   %e\n", i, fpu.ip.i1, fpu.f);
385*7c478bd9Sstevel@tonic-gate 		}
386*7c478bd9Sstevel@tonic-gate 	}
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	if (opts & FPR_DOUBLE) {
389*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nd; i++) {
390*7c478bd9Sstevel@tonic-gate 			fpu.ip.i1 = regs[i * 2 + 0];
391*7c478bd9Sstevel@tonic-gate 			fpu.ip.i2 = regs[i * 2 + 1];
392*7c478bd9Sstevel@tonic-gate 			mdb_printf("f%-3d %08x.%08x   %g\n", i * 2,
393*7c478bd9Sstevel@tonic-gate 			    fpu.ip.i1, fpu.ip.i2, fpu.d);
394*7c478bd9Sstevel@tonic-gate 		}
395*7c478bd9Sstevel@tonic-gate 	}
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	if (opts & FPR_QUAD) {
398*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < nq; i++) {
399*7c478bd9Sstevel@tonic-gate 			fpu.ip.i1 = regs[i * 4 + 0];
400*7c478bd9Sstevel@tonic-gate 			fpu.ip.i2 = regs[i * 4 + 1];
401*7c478bd9Sstevel@tonic-gate 			fpu.ip.i3 = regs[i * 4 + 2];
402*7c478bd9Sstevel@tonic-gate 			fpu.ip.i4 = regs[i * 4 + 3];
403*7c478bd9Sstevel@tonic-gate 			mdb_printf("f%-3d %08x.%08x.%08x.%08x   %s\n", i * 4,
404*7c478bd9Sstevel@tonic-gate 			    fpu.ip.i1, fpu.ip.i2, fpu.ip.i3, fpu.ip.i4,
405*7c478bd9Sstevel@tonic-gate 			    longdoubletos(&fpu.ld, 16, 'e'));
406*7c478bd9Sstevel@tonic-gate 		}
407*7c478bd9Sstevel@tonic-gate 	}
408*7c478bd9Sstevel@tonic-gate 
409*7c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
410*7c478bd9Sstevel@tonic-gate }
411*7c478bd9Sstevel@tonic-gate 
412*7c478bd9Sstevel@tonic-gate /*
413*7c478bd9Sstevel@tonic-gate  * Read a single floating-point register.  If it's a v8 or v9 register, then
414*7c478bd9Sstevel@tonic-gate  * we get its value from prfpregset_t.  If it's a v8+ register, look in xregs.
415*7c478bd9Sstevel@tonic-gate  */
416*7c478bd9Sstevel@tonic-gate int
417*7c478bd9Sstevel@tonic-gate pt_getfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num,
418*7c478bd9Sstevel@tonic-gate     ushort_t rd_flags, mdb_tgt_reg_t *rp)
419*7c478bd9Sstevel@tonic-gate {
420*7c478bd9Sstevel@tonic-gate 	mdb_tgt_reg_t rval;
421*7c478bd9Sstevel@tonic-gate 	prfpregset_t fprs;
422*7c478bd9Sstevel@tonic-gate 	prxregset_t xrs;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	if (PTL_GETFPREGS(t, tid, &fprs) != 0)
425*7c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	if ((rd_flags & MDB_TGT_R_XREG) && PTL_GETXREGS(t, tid, &xrs) != 0)
428*7c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	if (rd_flags & MDB_TGT_R_FPU) {
431*7c478bd9Sstevel@tonic-gate 		switch (rd_num) {
432*7c478bd9Sstevel@tonic-gate 		case FPU_FSR:
433*7c478bd9Sstevel@tonic-gate 			rval = fprs.pr_fsr;
434*7c478bd9Sstevel@tonic-gate 			if (rd_flags & MDB_TGT_R_XREG)
435*7c478bd9Sstevel@tonic-gate 				rval |= (uint64_t)
436*7c478bd9Sstevel@tonic-gate 				    xrs.pr_un.pr_v8p.pr_xfsr << 32;
437*7c478bd9Sstevel@tonic-gate 			break;
438*7c478bd9Sstevel@tonic-gate 		case FPU_FPRS:
439*7c478bd9Sstevel@tonic-gate 			if (rd_flags & MDB_TGT_R_XREG)
440*7c478bd9Sstevel@tonic-gate 				rval = xrs.pr_un.pr_v8p.pr_fprs;
441*7c478bd9Sstevel@tonic-gate 			break;
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	} else if (rd_flags & MDB_TGT_R_FPS) {
445*7c478bd9Sstevel@tonic-gate 		if (rd_flags & MDB_TGT_R_XREG)
446*7c478bd9Sstevel@tonic-gate 			rval = xrs.pr_un.pr_v8p.pr_xfr.pr_regs[rd_num - 32];
447*7c478bd9Sstevel@tonic-gate 		else
448*7c478bd9Sstevel@tonic-gate 			rval = fprs.pr_fr.pr_regs[rd_num];
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	} else if (rd_flags & MDB_TGT_R_FPD) {
451*7c478bd9Sstevel@tonic-gate 		if (rd_flags & MDB_TGT_R_XREG)
452*7c478bd9Sstevel@tonic-gate 			rval = ((uint64_t *)
453*7c478bd9Sstevel@tonic-gate 			    xrs.pr_un.pr_v8p.pr_xfr.pr_dregs)[rd_num - 16];
454*7c478bd9Sstevel@tonic-gate 		else
455*7c478bd9Sstevel@tonic-gate 			rval = ((uint64_t *)fprs.pr_fr.pr_dregs)[rd_num];
456*7c478bd9Sstevel@tonic-gate 	}
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	*rp = rval;
459*7c478bd9Sstevel@tonic-gate 	return (0);
460*7c478bd9Sstevel@tonic-gate }
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate /*
463*7c478bd9Sstevel@tonic-gate  * Write a single floating-point register.  If it's a v8 or v9 register, then
464*7c478bd9Sstevel@tonic-gate  * we set its value in prfpregset_t.  If it's a v8+ register, modify the xregs.
465*7c478bd9Sstevel@tonic-gate  */
466*7c478bd9Sstevel@tonic-gate int
467*7c478bd9Sstevel@tonic-gate pt_putfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num,
468*7c478bd9Sstevel@tonic-gate     ushort_t rd_flags, mdb_tgt_reg_t rval)
469*7c478bd9Sstevel@tonic-gate {
470*7c478bd9Sstevel@tonic-gate 	prfpregset_t fprs;
471*7c478bd9Sstevel@tonic-gate 	prxregset_t xrs;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	if (PTL_GETFPREGS(t, tid, &fprs) != 0)
474*7c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	if ((rd_flags & MDB_TGT_R_XREG) && PTL_GETXREGS(t, tid, &xrs) != 0)
477*7c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	if (rd_flags & MDB_TGT_R_FPU) {
480*7c478bd9Sstevel@tonic-gate 		switch (rd_num) {
481*7c478bd9Sstevel@tonic-gate 		case FPU_FSR:
482*7c478bd9Sstevel@tonic-gate 			fprs.pr_fsr = (uint32_t)rval;
483*7c478bd9Sstevel@tonic-gate 			if (rd_flags & MDB_TGT_R_XREG)
484*7c478bd9Sstevel@tonic-gate 				xrs.pr_un.pr_v8p.pr_xfsr = rval >> 32;
485*7c478bd9Sstevel@tonic-gate 			break;
486*7c478bd9Sstevel@tonic-gate 		case FPU_FPRS:
487*7c478bd9Sstevel@tonic-gate 			if (rd_flags & MDB_TGT_R_XREG)
488*7c478bd9Sstevel@tonic-gate 				xrs.pr_un.pr_v8p.pr_fprs = rval;
489*7c478bd9Sstevel@tonic-gate 			break;
490*7c478bd9Sstevel@tonic-gate 		}
491*7c478bd9Sstevel@tonic-gate 
492*7c478bd9Sstevel@tonic-gate 	} else if (rd_flags & MDB_TGT_R_FPS) {
493*7c478bd9Sstevel@tonic-gate 		if (rd_flags & MDB_TGT_R_XREG)
494*7c478bd9Sstevel@tonic-gate 			xrs.pr_un.pr_v8p.pr_xfr.pr_regs[rd_num - 32] = rval;
495*7c478bd9Sstevel@tonic-gate 		else
496*7c478bd9Sstevel@tonic-gate 			fprs.pr_fr.pr_regs[rd_num] = rval;
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 	} else if (rd_flags & MDB_TGT_R_FPD) {
499*7c478bd9Sstevel@tonic-gate 		if (rd_flags & MDB_TGT_R_XREG)
500*7c478bd9Sstevel@tonic-gate 			((uint64_t *)xrs.pr_un.pr_v8p.pr_xfr.pr_dregs)
501*7c478bd9Sstevel@tonic-gate 			    [rd_num - 16] = rval;
502*7c478bd9Sstevel@tonic-gate 		else
503*7c478bd9Sstevel@tonic-gate 			((uint64_t *)fprs.pr_fr.pr_dregs)[rd_num] = rval;
504*7c478bd9Sstevel@tonic-gate 	}
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	if (PTL_SETFPREGS(t, tid, &fprs) != 0)
507*7c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	if ((rd_flags & MDB_TGT_R_XREG) && PTL_SETXREGS(t, tid, &xrs) != 0)
510*7c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
511*7c478bd9Sstevel@tonic-gate 
512*7c478bd9Sstevel@tonic-gate 	return (0);
513*7c478bd9Sstevel@tonic-gate }
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate /*
516*7c478bd9Sstevel@tonic-gate  * Utility function for inserting a floating-point register description into
517*7c478bd9Sstevel@tonic-gate  * the p_regs hash table of register descriptions.
518*7c478bd9Sstevel@tonic-gate  */
519*7c478bd9Sstevel@tonic-gate static void
520*7c478bd9Sstevel@tonic-gate pt_addfpreg(mdb_nv_t *nvp, uint_t rnum, uint_t rnam, char pref, ushort_t flags)
521*7c478bd9Sstevel@tonic-gate {
522*7c478bd9Sstevel@tonic-gate 	uintmax_t nval = MDB_TGT_R_NVAL(rnum, flags | MDB_TGT_R_EXPORT);
523*7c478bd9Sstevel@tonic-gate 	char name[8]; /* enough for "[fdq][0-9][0-9]\0" */
524*7c478bd9Sstevel@tonic-gate 
525*7c478bd9Sstevel@tonic-gate 	(void) mdb_iob_snprintf(name, sizeof (name), "%c%u", pref, rnam);
526*7c478bd9Sstevel@tonic-gate 	(void) mdb_nv_insert(nvp, name, NULL, nval, MDB_NV_RDONLY);
527*7c478bd9Sstevel@tonic-gate }
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate /*
530*7c478bd9Sstevel@tonic-gate  * Determine the ISA of the target and then insert the appropriate register
531*7c478bd9Sstevel@tonic-gate  * description entries into p_regs.  If the target is v8plus or v9, add the
532*7c478bd9Sstevel@tonic-gate  * entire v9 floating-point model; otherwise just add the v8 registers.
533*7c478bd9Sstevel@tonic-gate  */
534*7c478bd9Sstevel@tonic-gate void
535*7c478bd9Sstevel@tonic-gate pt_addfpregs(mdb_tgt_t *t)
536*7c478bd9Sstevel@tonic-gate {
537*7c478bd9Sstevel@tonic-gate 	pt_data_t *pt = t->t_data;
538*7c478bd9Sstevel@tonic-gate 	struct ps_prochandle *P = t->t_pshandle;
539*7c478bd9Sstevel@tonic-gate 	prxregset_t xrs;
540*7c478bd9Sstevel@tonic-gate 	uint_t i;
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	uint_t fpuflag = MDB_TGT_R_FPU | MDB_TGT_R_EXPORT;
543*7c478bd9Sstevel@tonic-gate 	uint_t e_mach = pt->p_file ? pt->p_file->gf_ehdr.e_machine : EM_NONE;
544*7c478bd9Sstevel@tonic-gate 	uint_t model = P ? Pstatus(P)->pr_dmodel : PR_MODEL_UNKNOWN;
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 	/*
547*7c478bd9Sstevel@tonic-gate 	 * If the ELF file is SPARCv9 or the process or core is 64-bit, then
548*7c478bd9Sstevel@tonic-gate 	 * add the SPARCv9 floating-point descriptions.  Otherwise use v7/v8.
549*7c478bd9Sstevel@tonic-gate 	 */
550*7c478bd9Sstevel@tonic-gate 	if (e_mach == EM_SPARCV9 || model == PR_MODEL_LP64) {
551*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 64; i++)
552*7c478bd9Sstevel@tonic-gate 			pt_addfpreg(&pt->p_regs, i, i, 'f', MDB_TGT_R_FPS);
553*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 32; i++)
554*7c478bd9Sstevel@tonic-gate 			pt_addfpreg(&pt->p_regs, i, i * 2, 'd', MDB_TGT_R_FPD);
555*7c478bd9Sstevel@tonic-gate 	} else {
556*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 32; i++)
557*7c478bd9Sstevel@tonic-gate 			pt_addfpreg(&pt->p_regs, i, i, 'f', MDB_TGT_R_FPS);
558*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < 16; i++)
559*7c478bd9Sstevel@tonic-gate 			pt_addfpreg(&pt->p_regs, i, i * 2, 'd', MDB_TGT_R_FPD);
560*7c478bd9Sstevel@tonic-gate 	}
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	/*
563*7c478bd9Sstevel@tonic-gate 	 * If the ELF file is SPARCv8+ or the process or core has v8+ xregs,
564*7c478bd9Sstevel@tonic-gate 	 * then include the additional v8plus register descriptions.
565*7c478bd9Sstevel@tonic-gate 	 */
566*7c478bd9Sstevel@tonic-gate 	if (e_mach == EM_SPARC32PLUS || (P != NULL && PTL_GETXREGS(t,
567*7c478bd9Sstevel@tonic-gate 	    PTL_TID(t), &xrs) == 0 && xrs.pr_type == XR_TYPE_V8P)) {
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 		for (i = 32; i < 64; i++) {
570*7c478bd9Sstevel@tonic-gate 			pt_addfpreg(&pt->p_regs, i, i, 'f',
571*7c478bd9Sstevel@tonic-gate 			    MDB_TGT_R_FPS | MDB_TGT_R_XREG);
572*7c478bd9Sstevel@tonic-gate 		}
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 		for (i = 16; i < 32; i++) {
575*7c478bd9Sstevel@tonic-gate 			pt_addfpreg(&pt->p_regs, i, i * 2, 'd',
576*7c478bd9Sstevel@tonic-gate 			    MDB_TGT_R_FPD | MDB_TGT_R_XREG);
577*7c478bd9Sstevel@tonic-gate 		}
578*7c478bd9Sstevel@tonic-gate 
579*7c478bd9Sstevel@tonic-gate 		fpuflag |= MDB_TGT_R_XREG; /* fpu status regs are in xregs */
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 		(void) mdb_nv_insert(&pt->p_regs, "fsr", NULL,
582*7c478bd9Sstevel@tonic-gate 		    MDB_TGT_R_NVAL(FPU_FSR, fpuflag), MDB_NV_RDONLY);
583*7c478bd9Sstevel@tonic-gate 
584*7c478bd9Sstevel@tonic-gate 		(void) mdb_nv_insert(&pt->p_regs, "fprs", NULL,
585*7c478bd9Sstevel@tonic-gate 		    MDB_TGT_R_NVAL(FPU_FPRS, fpuflag), MDB_NV_RDONLY);
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 	} else {
588*7c478bd9Sstevel@tonic-gate 		(void) mdb_nv_insert(&pt->p_regs, "fsr", NULL,
589*7c478bd9Sstevel@tonic-gate 		    MDB_TGT_R_NVAL(FPU_FSR, fpuflag), MDB_NV_RDONLY);
590*7c478bd9Sstevel@tonic-gate 	}
591*7c478bd9Sstevel@tonic-gate }
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate int
594*7c478bd9Sstevel@tonic-gate pt_frameregs(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
595*7c478bd9Sstevel@tonic-gate     const mdb_tgt_gregset_t *gregs, boolean_t pc_faked)
596*7c478bd9Sstevel@tonic-gate {
597*7c478bd9Sstevel@tonic-gate 	char buf[BUFSIZ];
598*7c478bd9Sstevel@tonic-gate 	const prgreg_t *pregs = &gregs->gregs[0];
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	argc = MIN(argc, (uint_t)(uintptr_t)arglim);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	if (pc_faked)
603*7c478bd9Sstevel@tonic-gate 		mdb_printf("%<b>%0?lr %s%</b>(", pregs[R_SP], "?");
604*7c478bd9Sstevel@tonic-gate 	else
605*7c478bd9Sstevel@tonic-gate 		mdb_printf("%<b>%0?lr %a%</b>(", pregs[R_SP], pc);
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if (argc != 0) {
608*7c478bd9Sstevel@tonic-gate 		mdb_printf("%lr", *argv++);
609*7c478bd9Sstevel@tonic-gate 		for (argc--; argc != 0; argc--)
610*7c478bd9Sstevel@tonic-gate 			mdb_printf(", %lr", *argv++);
611*7c478bd9Sstevel@tonic-gate 	}
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	mdb_printf(")\n");
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	(void) mdb_inc_indent(2);
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	mdb_printf("%%l0-%%l3: %?lr %?lr %?lr %?lr\n",
618*7c478bd9Sstevel@tonic-gate 	    pregs[R_L0], pregs[R_L1], pregs[R_L2], pregs[R_L3]);
619*7c478bd9Sstevel@tonic-gate 
620*7c478bd9Sstevel@tonic-gate 	mdb_printf("%%l4-%%l7: %?lr %?lr %?lr %?lr\n",
621*7c478bd9Sstevel@tonic-gate 	    pregs[R_L4], pregs[R_L5], pregs[R_L6], pregs[R_L7]);
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 	if (pregs[R_FP] != 0 && (pregs[R_FP] + STACK_BIAS) != 0)
624*7c478bd9Sstevel@tonic-gate 		if (mdb_dis_ins2str(mdb.m_disasm, mdb.m_target, MDB_TGT_AS_VIRT,
625*7c478bd9Sstevel@tonic-gate 		    buf, sizeof (buf), pregs[R_I7]) != pregs[R_I7])
626*7c478bd9Sstevel@tonic-gate 			mdb_printf("%-#25a%s\n", pregs[R_I7], buf);
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate 	(void) mdb_dec_indent(2);
629*7c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	return (0);
632*7c478bd9Sstevel@tonic-gate }
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate const char *
635*7c478bd9Sstevel@tonic-gate pt_disasm(const GElf_Ehdr *ehp)
636*7c478bd9Sstevel@tonic-gate {
637*7c478bd9Sstevel@tonic-gate #ifdef __sparcv9
638*7c478bd9Sstevel@tonic-gate 	const char *disname = "v9plus";
639*7c478bd9Sstevel@tonic-gate #else
640*7c478bd9Sstevel@tonic-gate 	const char *disname = "v8";
641*7c478bd9Sstevel@tonic-gate #endif
642*7c478bd9Sstevel@tonic-gate 	/*
643*7c478bd9Sstevel@tonic-gate 	 * If e_machine is SPARC32+, the program has been compiled v8plus or
644*7c478bd9Sstevel@tonic-gate 	 * v8plusa and we need to allow v9 and potentially VIS opcodes.
645*7c478bd9Sstevel@tonic-gate 	 */
646*7c478bd9Sstevel@tonic-gate 	if (ehp != NULL && ehp->e_machine == EM_SPARC32PLUS) {
647*7c478bd9Sstevel@tonic-gate 		if (ehp->e_flags & (EF_SPARC_SUN_US1 | EF_SPARC_SUN_US3))
648*7c478bd9Sstevel@tonic-gate 			disname = "v9plus";
649*7c478bd9Sstevel@tonic-gate 		else
650*7c478bd9Sstevel@tonic-gate 			disname = "v9";
651*7c478bd9Sstevel@tonic-gate 	}
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 	return (disname);
654*7c478bd9Sstevel@tonic-gate }
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate /*
657*7c478bd9Sstevel@tonic-gate  * Macros and #defines for extracting and interpreting SPARC instruction set,
658*7c478bd9Sstevel@tonic-gate  * used in pt_step_out() and pt_next() below.
659*7c478bd9Sstevel@tonic-gate  */
660*7c478bd9Sstevel@tonic-gate #define	OP(machcode)	((machcode) >> 30)
661*7c478bd9Sstevel@tonic-gate #define	OP2(machcode)	(((machcode) >> 22) & 0x07)
662*7c478bd9Sstevel@tonic-gate #define	OP3(machcode)	(((machcode) >> 19) & 0x3f)
663*7c478bd9Sstevel@tonic-gate #define	RD(machcode)	(((machcode) >> 25) & 0x1f)
664*7c478bd9Sstevel@tonic-gate #define	RS1(machcode)	(((machcode) >> 14) & 0x1f)
665*7c478bd9Sstevel@tonic-gate #define	RS2(machcode)	((machcode) & 0x1f)
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate #define	OP_BRANCH	0x0
668*7c478bd9Sstevel@tonic-gate #define	OP_ARITH	0x2
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate #define	OP2_ILLTRAP	0x0
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate #define	OP3_OR		0x02
673*7c478bd9Sstevel@tonic-gate #define	OP3_SAVE	0x3c
674*7c478bd9Sstevel@tonic-gate #define	OP3_RESTORE	0x3d
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate /*
677*7c478bd9Sstevel@tonic-gate  * If we are stopped on a save instruction or at the first instruction of a
678*7c478bd9Sstevel@tonic-gate  * known function, return %o7 as the step-out address; otherwise return the
679*7c478bd9Sstevel@tonic-gate  * current frame's return address (%i7).  Significantly better handling of
680*7c478bd9Sstevel@tonic-gate  * step out in leaf routines could be accomplished by implementing more
681*7c478bd9Sstevel@tonic-gate  * complex decoding of the current function and our current state.
682*7c478bd9Sstevel@tonic-gate  */
683*7c478bd9Sstevel@tonic-gate int
684*7c478bd9Sstevel@tonic-gate pt_step_out(mdb_tgt_t *t, uintptr_t *p)
685*7c478bd9Sstevel@tonic-gate {
686*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
687*7c478bd9Sstevel@tonic-gate 	uintptr_t pc = psp->pr_reg[R_PC];
688*7c478bd9Sstevel@tonic-gate 	uint32_t instr;
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 	char buf[1];
691*7c478bd9Sstevel@tonic-gate 	GElf_Sym s;
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 	if (Pstate(t->t_pshandle) != PS_STOP)
694*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGTBUSY));
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate 	instr = pt_read_instr(t);
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
699*7c478bd9Sstevel@tonic-gate 	    buf, sizeof (buf), &s, NULL) == 0 && s.st_value == pc)
700*7c478bd9Sstevel@tonic-gate 		*p = psp->pr_reg[R_O7] + 2 * sizeof (instr_t);
701*7c478bd9Sstevel@tonic-gate 	else if (OP(instr) == OP_ARITH &&
702*7c478bd9Sstevel@tonic-gate 	    OP3(instr) == OP3_SAVE)
703*7c478bd9Sstevel@tonic-gate 		*p = psp->pr_reg[R_O7] + 2 * sizeof (instr_t);
704*7c478bd9Sstevel@tonic-gate 	else
705*7c478bd9Sstevel@tonic-gate 		*p = psp->pr_reg[R_I7] + 2 * sizeof (instr_t);
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	return (0);
708*7c478bd9Sstevel@tonic-gate }
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate /*
711*7c478bd9Sstevel@tonic-gate  * Step over call and jmpl by returning the address of the position where a
712*7c478bd9Sstevel@tonic-gate  * temporary breakpoint can be set to catch return from the control transfer.
713*7c478bd9Sstevel@tonic-gate  * This function does not currently provide advancing decoding of DCTI
714*7c478bd9Sstevel@tonic-gate  * couples or any other complex special case; we just fall back to single-step.
715*7c478bd9Sstevel@tonic-gate  */
716*7c478bd9Sstevel@tonic-gate int
717*7c478bd9Sstevel@tonic-gate pt_next(mdb_tgt_t *t, uintptr_t *p)
718*7c478bd9Sstevel@tonic-gate {
719*7c478bd9Sstevel@tonic-gate 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
720*7c478bd9Sstevel@tonic-gate 	uintptr_t pc;
721*7c478bd9Sstevel@tonic-gate 	uintptr_t npc;
722*7c478bd9Sstevel@tonic-gate 	GElf_Sym func;
723*7c478bd9Sstevel@tonic-gate 	char name[1];
724*7c478bd9Sstevel@tonic-gate 	instr_t instr;
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	if (Pstate(t->t_pshandle) != PS_STOP)
727*7c478bd9Sstevel@tonic-gate 		return (set_errno(EMDB_TGTBUSY));
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	pc = psp->pr_reg[R_PC];
730*7c478bd9Sstevel@tonic-gate 	npc = psp->pr_reg[R_nPC];
731*7c478bd9Sstevel@tonic-gate 	instr = pt_read_instr(t);
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
734*7c478bd9Sstevel@tonic-gate 	    name, sizeof (name), &func, NULL) != 0)
735*7c478bd9Sstevel@tonic-gate 		return (-1);
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	if (npc < func.st_value || func.st_value + func.st_size <= npc) {
738*7c478bd9Sstevel@tonic-gate 		uint_t reg;
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 		/*
741*7c478bd9Sstevel@tonic-gate 		 * We're about to transfer control outside this function,
742*7c478bd9Sstevel@tonic-gate 		 * so we want to stop when control returns from the other
743*7c478bd9Sstevel@tonic-gate 		 * function. Normally the return address will be in %o7,
744*7c478bd9Sstevel@tonic-gate 		 * tail-calls being the exception. We try to discover
745*7c478bd9Sstevel@tonic-gate 		 * if this is a tail-call and compute the return address
746*7c478bd9Sstevel@tonic-gate 		 * in that case.
747*7c478bd9Sstevel@tonic-gate 		 */
748*7c478bd9Sstevel@tonic-gate 		if (OP(instr) == OP_ARITH &&
749*7c478bd9Sstevel@tonic-gate 		    OP3(instr) == OP3_RESTORE) {
750*7c478bd9Sstevel@tonic-gate 			reg = R_I7;
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 		} else if (OP(instr) == OP_ARITH &&
753*7c478bd9Sstevel@tonic-gate 		    OP3(instr) == OP3_OR &&
754*7c478bd9Sstevel@tonic-gate 		    RD(instr) == R_O7) {
755*7c478bd9Sstevel@tonic-gate 
756*7c478bd9Sstevel@tonic-gate 			if (RS1(instr) != R_G0)
757*7c478bd9Sstevel@tonic-gate 				return (set_errno(EAGAIN));
758*7c478bd9Sstevel@tonic-gate 			reg = RS2(instr);
759*7c478bd9Sstevel@tonic-gate 
760*7c478bd9Sstevel@tonic-gate 		} else {
761*7c478bd9Sstevel@tonic-gate 			reg = R_O7;
762*7c478bd9Sstevel@tonic-gate 		}
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 		*p = psp->pr_reg[reg] + 2 * sizeof (instr_t);
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 		/*
767*7c478bd9Sstevel@tonic-gate 		 * If a function returns a structure, the caller may place
768*7c478bd9Sstevel@tonic-gate 		 * an illtrap whose const22 field represents the size of
769*7c478bd9Sstevel@tonic-gate 		 * the structure immediately after the delay slot of the
770*7c478bd9Sstevel@tonic-gate 		 * call (or jmpl) instruction. To handle this case, we
771*7c478bd9Sstevel@tonic-gate 		 * check the instruction that we think we're going to
772*7c478bd9Sstevel@tonic-gate 		 * return to, and advance past it if it's an illtrap
773*7c478bd9Sstevel@tonic-gate 		 * instruction. Note that this applies to SPARC v7 and v8,
774*7c478bd9Sstevel@tonic-gate 		 * but not v9.
775*7c478bd9Sstevel@tonic-gate 		 */
776*7c478bd9Sstevel@tonic-gate 		if (mdb_tgt_vread(t, &instr, sizeof (instr_t), *p) ==
777*7c478bd9Sstevel@tonic-gate 		    sizeof (instr_t) &&
778*7c478bd9Sstevel@tonic-gate 		    OP(instr) == OP_BRANCH && OP2(instr) == OP2_ILLTRAP)
779*7c478bd9Sstevel@tonic-gate 			*p += sizeof (instr_t);
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 		return (0);
782*7c478bd9Sstevel@tonic-gate 	}
783*7c478bd9Sstevel@tonic-gate 
784*7c478bd9Sstevel@tonic-gate 	return (set_errno(EAGAIN));
785*7c478bd9Sstevel@tonic-gate }
786