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