1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/reg.h> 31*0Sstevel@tonic-gate #include <sys/privregs.h> 32*0Sstevel@tonic-gate #include <sys/stack.h> 33*0Sstevel@tonic-gate #include <sys/frame.h> 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gate #include <mdb/mdb_target_impl.h> 36*0Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h> 37*0Sstevel@tonic-gate #include <mdb/mdb_debug.h> 38*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 39*0Sstevel@tonic-gate #include <mdb/mdb_amd64util.h> 40*0Sstevel@tonic-gate #include <mdb/mdb_err.h> 41*0Sstevel@tonic-gate #include <mdb/mdb.h> 42*0Sstevel@tonic-gate 43*0Sstevel@tonic-gate /* 44*0Sstevel@tonic-gate * This array is used by the getareg and putareg entry points, and also by our 45*0Sstevel@tonic-gate * register variable discipline. 46*0Sstevel@tonic-gate */ 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate const mdb_tgt_regdesc_t mdb_amd64_kregs[] = { 49*0Sstevel@tonic-gate { "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT }, 50*0Sstevel@tonic-gate { "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT }, 51*0Sstevel@tonic-gate { "rdi", KREG_RDI, MDB_TGT_R_EXPORT }, 52*0Sstevel@tonic-gate { "rsi", KREG_RSI, MDB_TGT_R_EXPORT }, 53*0Sstevel@tonic-gate { "rdx", KREG_RDX, MDB_TGT_R_EXPORT }, 54*0Sstevel@tonic-gate { "rcx", KREG_RCX, MDB_TGT_R_EXPORT }, 55*0Sstevel@tonic-gate { "r8", KREG_R8, MDB_TGT_R_EXPORT }, 56*0Sstevel@tonic-gate { "r9", KREG_R9, MDB_TGT_R_EXPORT }, 57*0Sstevel@tonic-gate { "rax", KREG_RAX, MDB_TGT_R_EXPORT }, 58*0Sstevel@tonic-gate { "rbx", KREG_RBX, MDB_TGT_R_EXPORT }, 59*0Sstevel@tonic-gate { "rbp", KREG_RBP, MDB_TGT_R_EXPORT }, 60*0Sstevel@tonic-gate { "r10", KREG_R10, MDB_TGT_R_EXPORT }, 61*0Sstevel@tonic-gate { "r11", KREG_R11, MDB_TGT_R_EXPORT }, 62*0Sstevel@tonic-gate { "r12", KREG_R12, MDB_TGT_R_EXPORT }, 63*0Sstevel@tonic-gate { "r13", KREG_R13, MDB_TGT_R_EXPORT }, 64*0Sstevel@tonic-gate { "r14", KREG_R14, MDB_TGT_R_EXPORT }, 65*0Sstevel@tonic-gate { "r15", KREG_R15, MDB_TGT_R_EXPORT }, 66*0Sstevel@tonic-gate { "fsbase", KREG_FSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 67*0Sstevel@tonic-gate { "gsbase", KREG_GSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 68*0Sstevel@tonic-gate { "kgsbase", KREG_KGSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 69*0Sstevel@tonic-gate { "ds", KREG_DS, MDB_TGT_R_EXPORT }, 70*0Sstevel@tonic-gate { "es", KREG_ES, MDB_TGT_R_EXPORT }, 71*0Sstevel@tonic-gate { "fs", KREG_FS, MDB_TGT_R_EXPORT }, 72*0Sstevel@tonic-gate { "gs", KREG_GS, MDB_TGT_R_EXPORT }, 73*0Sstevel@tonic-gate { "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 74*0Sstevel@tonic-gate { "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 75*0Sstevel@tonic-gate { "rip", KREG_RIP, MDB_TGT_R_EXPORT }, 76*0Sstevel@tonic-gate { "cs", KREG_CS, MDB_TGT_R_EXPORT }, 77*0Sstevel@tonic-gate { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT }, 78*0Sstevel@tonic-gate { "rsp", KREG_RSP, MDB_TGT_R_EXPORT }, 79*0Sstevel@tonic-gate { "ss", KREG_SS, MDB_TGT_R_EXPORT }, 80*0Sstevel@tonic-gate { NULL, 0, 0 } 81*0Sstevel@tonic-gate }; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate void 84*0Sstevel@tonic-gate mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs) 85*0Sstevel@tonic-gate { 86*0Sstevel@tonic-gate const kreg_t *kregs = &gregs->kregs[0]; 87*0Sstevel@tonic-gate kreg_t rflags = kregs[KREG_RFLAGS]; 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate #define GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)]) 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate mdb_printf("%%rax = 0x%0?p %15A %%r9 = 0x%0?p %A\n", 92*0Sstevel@tonic-gate GETREG2(KREG_RAX), GETREG2(KREG_R9)); 93*0Sstevel@tonic-gate mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n", 94*0Sstevel@tonic-gate GETREG2(KREG_RBX), GETREG2(KREG_R10)); 95*0Sstevel@tonic-gate mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n", 96*0Sstevel@tonic-gate GETREG2(KREG_RCX), GETREG2(KREG_R11)); 97*0Sstevel@tonic-gate mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n", 98*0Sstevel@tonic-gate GETREG2(KREG_RDX), GETREG2(KREG_R12)); 99*0Sstevel@tonic-gate mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n", 100*0Sstevel@tonic-gate GETREG2(KREG_RSI), GETREG2(KREG_R13)); 101*0Sstevel@tonic-gate mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n", 102*0Sstevel@tonic-gate GETREG2(KREG_RDI), GETREG2(KREG_R14)); 103*0Sstevel@tonic-gate mdb_printf("%%r8 = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n", 104*0Sstevel@tonic-gate GETREG2(KREG_R8), GETREG2(KREG_R15)); 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP)); 107*0Sstevel@tonic-gate mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]); 108*0Sstevel@tonic-gate mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]); 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate mdb_printf("%%rflags = 0x%08x\n", rflags); 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gate mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n", 113*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT, 114*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT, 115*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT, 116*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT, 117*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT, 118*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT, 119*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT, 120*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT); 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n", 123*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of", 124*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df", 125*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if", 126*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf", 127*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf", 128*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf", 129*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af", 130*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf", 131*0Sstevel@tonic-gate (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf"); 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n", 134*0Sstevel@tonic-gate " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\tfsbase = 0x%0?p\n", 137*0Sstevel@tonic-gate kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff), kregs[KREG_FSBASE]); 138*0Sstevel@tonic-gate mdb_printf(" %%err = 0x%x\t\t%%gs = 0x%04x\tgsbase = 0x%0?p\n", 139*0Sstevel@tonic-gate kregs[KREG_ERR], (kregs[KREG_GS] & 0xffff), kregs[KREG_GSBASE]); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate int 143*0Sstevel@tonic-gate mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, 144*0Sstevel@tonic-gate mdb_tgt_stack_f *func, void *arg) 145*0Sstevel@tonic-gate { 146*0Sstevel@tonic-gate mdb_tgt_gregset_t gregs; 147*0Sstevel@tonic-gate kreg_t *kregs = &gregs.kregs[0]; 148*0Sstevel@tonic-gate int got_pc = (gsp->kregs[KREG_RIP] != 0); 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate struct { 151*0Sstevel@tonic-gate uintptr_t fr_savfp; 152*0Sstevel@tonic-gate uintptr_t fr_savpc; 153*0Sstevel@tonic-gate } fr; 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate uintptr_t fp = gsp->kregs[KREG_RBP]; 156*0Sstevel@tonic-gate uintptr_t pc = gsp->kregs[KREG_RIP]; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate bcopy(gsp, &gregs, sizeof (gregs)); 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate while (fp != 0) { 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gate if (fp & (STACK_ALIGN - 1)) 163*0Sstevel@tonic-gate return (set_errno(EMDB_STKALIGN)); 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate bzero(&fr, sizeof (fr)); 166*0Sstevel@tonic-gate (void) mdb_tgt_vread(t, &fr, sizeof (fr), fp); 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate if (got_pc && func(arg, pc, 0, NULL, &gregs) != 0) 169*0Sstevel@tonic-gate break; 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate kregs[KREG_RSP] = kregs[KREG_RBP]; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate kregs[KREG_RBP] = fp = fr.fr_savfp; 174*0Sstevel@tonic-gate kregs[KREG_RIP] = pc = fr.fr_savpc; 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate got_pc = (pc != 0); 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate return (0); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate /* 183*0Sstevel@tonic-gate * Determine the return address for the current frame. Typically this is the 184*0Sstevel@tonic-gate * fr_savpc value from the current frame, but we also perform some special 185*0Sstevel@tonic-gate * handling to see if we are stopped on one of the first two instructions of 186*0Sstevel@tonic-gate * a typical function prologue, in which case %rbp will not be set up yet. 187*0Sstevel@tonic-gate */ 188*0Sstevel@tonic-gate int 189*0Sstevel@tonic-gate mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp, 190*0Sstevel@tonic-gate mdb_instr_t curinstr) 191*0Sstevel@tonic-gate { 192*0Sstevel@tonic-gate struct frame fr; 193*0Sstevel@tonic-gate GElf_Sym s; 194*0Sstevel@tonic-gate char buf[1]; 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate enum { 197*0Sstevel@tonic-gate M_PUSHQ_RBP = 0x55, /* pushq %rbp */ 198*0Sstevel@tonic-gate M_REX_W = 0x48, /* REX prefix with only W set */ 199*0Sstevel@tonic-gate M_MOVL_RBP = 0x8b /* movq %rsp, %rbp with prefix */ 200*0Sstevel@tonic-gate }; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY, 203*0Sstevel@tonic-gate buf, 0, &s, NULL) == 0) { 204*0Sstevel@tonic-gate if (pc == s.st_value && curinstr == M_PUSHQ_RBP) 205*0Sstevel@tonic-gate fp = sp - 8; 206*0Sstevel@tonic-gate else if (pc == s.st_value + 1 && curinstr == M_REX_W) { 207*0Sstevel@tonic-gate if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), 208*0Sstevel@tonic-gate pc + 1) == sizeof (curinstr) && curinstr == 209*0Sstevel@tonic-gate M_MOVL_RBP) 210*0Sstevel@tonic-gate fp = sp; 211*0Sstevel@tonic-gate } 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) { 215*0Sstevel@tonic-gate *p = fr.fr_savpc; 216*0Sstevel@tonic-gate return (0); 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate /*ARGSUSED*/ 223*0Sstevel@tonic-gate int 224*0Sstevel@tonic-gate mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr) 225*0Sstevel@tonic-gate { 226*0Sstevel@tonic-gate mdb_tgt_addr_t npc; 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate enum { 229*0Sstevel@tonic-gate M_CALL_REL = 0xe8, /* call near with relative displacement */ 230*0Sstevel@tonic-gate M_CALL_REG = 0xff, /* call near indirect or call far register */ 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate M_REX_LO = 0x40, 233*0Sstevel@tonic-gate M_REX_HI = 0x4f 234*0Sstevel@tonic-gate }; 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate /* 237*0Sstevel@tonic-gate * If the opcode is a near call with relative displacement, assume the 238*0Sstevel@tonic-gate * displacement is a rel32 from the next instruction. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate if (curinstr == M_CALL_REL) { 241*0Sstevel@tonic-gate *p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t); 242*0Sstevel@tonic-gate return (0); 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate /* Skip the rex prefix, if any */ 246*0Sstevel@tonic-gate if (curinstr >= M_REX_LO && curinstr <= M_REX_HI && 247*0Sstevel@tonic-gate mdb_tgt_vread(t, &curinstr, sizeof (curinstr), pc) != 248*0Sstevel@tonic-gate sizeof (curinstr)) 249*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 250*0Sstevel@tonic-gate 251*0Sstevel@tonic-gate if (curinstr != M_CALL_REG) { 252*0Sstevel@tonic-gate /* It's not a call */ 253*0Sstevel@tonic-gate return (set_errno(EAGAIN)); 254*0Sstevel@tonic-gate } 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc) 257*0Sstevel@tonic-gate return (-1); /* errno is set for us */ 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate *p = npc; 260*0Sstevel@tonic-gate return (0); 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate /*ARGSUSED*/ 264*0Sstevel@tonic-gate int 265*0Sstevel@tonic-gate mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 266*0Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 267*0Sstevel@tonic-gate { 268*0Sstevel@tonic-gate argc = MIN(argc, (uintptr_t)arglim); 269*0Sstevel@tonic-gate mdb_printf("%a(", pc); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate if (argc != 0) { 272*0Sstevel@tonic-gate mdb_printf("%lr", *argv++); 273*0Sstevel@tonic-gate for (argc--; argc != 0; argc--) 274*0Sstevel@tonic-gate mdb_printf(", %lr", *argv++); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate mdb_printf(")\n"); 278*0Sstevel@tonic-gate return (0); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate int 282*0Sstevel@tonic-gate mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 283*0Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 284*0Sstevel@tonic-gate { 285*0Sstevel@tonic-gate argc = MIN(argc, (uintptr_t)arglim); 286*0Sstevel@tonic-gate mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc); 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate if (argc != 0) { 289*0Sstevel@tonic-gate mdb_printf("%lr", *argv++); 290*0Sstevel@tonic-gate for (argc--; argc != 0; argc--) 291*0Sstevel@tonic-gate mdb_printf(", %lr", *argv++); 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate mdb_printf(")\n"); 295*0Sstevel@tonic-gate return (0); 296*0Sstevel@tonic-gate } 297