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
pt_read_instr(mdb_tgt_t * 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
pt_regs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
pt_fpregs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
pt_getfpreg(mdb_tgt_t * t,mdb_tgt_tid_t tid,ushort_t rd_num,ushort_t rd_flags,mdb_tgt_reg_t * rp)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
pt_putfpreg(mdb_tgt_t * t,mdb_tgt_tid_t tid,ushort_t rd_num,ushort_t rd_flags,mdb_tgt_reg_t rval)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
pt_addfpreg(mdb_nv_t * nvp,uint_t rnum,uint_t rnam,char pref,ushort_t flags)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
pt_addfpregs(mdb_tgt_t * t)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
pt_frameregs(void * arglim,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs,boolean_t pc_faked)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 *
pt_disasm(const GElf_Ehdr * ehp)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
pt_step_out(mdb_tgt_t * t,uintptr_t * p)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
pt_next(mdb_tgt_t * t,uintptr_t * p)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