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