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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 /* 26 * Copyright (c) 2012, Joyent, Inc. All rights reserved. 27 */ 28 29 /* 30 * Libkvm Kernel Target Intel component 31 * 32 * This file provides the Intel-dependent portion of the libkvm kernel target. 33 * For more details on the implementation refer to mdb_kvm.c. 34 */ 35 36 #include <mdb/mdb_target_impl.h> 37 #include <mdb/mdb_kreg_impl.h> 38 #include <mdb/mdb_errno.h> 39 #include <mdb/mdb_err.h> 40 #include <mdb/mdb_kvm.h> 41 #include <mdb/mdb_ks.h> 42 #include <mdb/mdb.h> 43 #include <mdb/kvm_isadep.h> 44 45 #include <sys/cpuvar.h> 46 #include <sys/privmregs.h> 47 48 int 49 kt_getareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, 50 const char *rname, mdb_tgt_reg_t *rp) 51 { 52 const mdb_tgt_regdesc_t *rdp; 53 kt_data_t *kt = t->t_data; 54 55 if (tid != kt->k_tid) 56 return (set_errno(EMDB_NOREGS)); 57 58 for (rdp = kt->k_rds; rdp->rd_name != NULL; rdp++) { 59 if (strcmp(rname, rdp->rd_name) == 0) { 60 *rp = kt->k_regs->kregs[rdp->rd_num]; 61 if (rdp->rd_flags & MDB_TGT_R_32) 62 *rp &= 0xffffffffULL; 63 else if (rdp->rd_flags & MDB_TGT_R_16) 64 *rp &= 0xffffULL; 65 else if (rdp->rd_flags & MDB_TGT_R_8H) 66 *rp = (*rp & 0xff00ULL) >> 8; 67 else if (rdp->rd_flags & MDB_TGT_R_8L) 68 *rp &= 0xffULL; 69 return (0); 70 } 71 } 72 73 return (set_errno(EMDB_BADREG)); 74 } 75 76 int 77 kt_putareg(mdb_tgt_t *t, mdb_tgt_tid_t tid, const char *rname, mdb_tgt_reg_t r) 78 { 79 const mdb_tgt_regdesc_t *rdp; 80 kt_data_t *kt = t->t_data; 81 82 if (tid != kt->k_tid) 83 return (set_errno(EMDB_NOREGS)); 84 85 for (rdp = kt->k_rds; rdp->rd_name != NULL; rdp++) { 86 if (strcmp(rname, rdp->rd_name) == 0) { 87 if (rdp->rd_flags & MDB_TGT_R_32) 88 r &= 0xffffffffULL; 89 else if (rdp->rd_flags & MDB_TGT_R_16) 90 r &= 0xffffULL; 91 else if (rdp->rd_flags & MDB_TGT_R_8H) 92 r = (r & 0xffULL) << 8; 93 else if (rdp->rd_flags & MDB_TGT_R_8L) 94 r &= 0xffULL; 95 96 kt->k_regs->kregs[rdp->rd_num] = (kreg_t)r; 97 return (0); 98 } 99 } 100 101 return (set_errno(EMDB_BADREG)); 102 } 103 104 int 105 kt_kvmregs(mdb_tgt_t *t, uint_t cpuid, mdb_tgt_gregset_t *kregs) 106 { 107 kt_data_t *kt = t->t_data; 108 privmregs_t mregs; 109 int ret; 110 111 if ((ret = kt->k_kb_ops->kb_getmregs(kt->k_cookie, cpuid, &mregs)) != 0) 112 return (ret); 113 114 kt_regs_to_kregs(&mregs.pm_gregs, kregs); 115 return (0); 116 } 117 118 static int 119 kt_cpu2cpuid(uintptr_t cpup) 120 { 121 cpu_t cpu; 122 123 if (mdb_vread(&cpu, sizeof (cpu_t), cpup) != sizeof (cpu_t)) 124 return (-1); 125 126 return (cpu.cpu_id); 127 } 128 129 int 130 kt_cpustack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 131 { 132 mdb_tgt_t *t = mdb.m_target; 133 mdb_tgt_gregset_t regs; 134 intptr_t cpuid = 0; 135 uint_t verbose = 0; 136 int i; 137 138 if (flags & DCMD_ADDRSPEC) { 139 if ((cpuid = kt_cpu2cpuid(addr)) < 0) { 140 (void) set_errno(EMDB_NOMAP); 141 mdb_warn("failed to find cpuid for cpu at %p", addr); 142 return (DCMD_ERR); 143 } 144 flags &= ~DCMD_ADDRSPEC; 145 } 146 147 148 i = mdb_getopts(argc, argv, 149 'c', MDB_OPT_UINTPTR, &cpuid, 150 'v', MDB_OPT_SETBITS, 1, &verbose, 151 NULL); 152 153 argc -= i; 154 argv += i; 155 156 if (kt_kvmregs(t, cpuid, ®s) != 0) { 157 mdb_warn("failed to get regs for cpu %d\n", cpuid); 158 return (DCMD_ERR); 159 } 160 161 /* 162 * Tell the stack walker that we have regs. 163 */ 164 flags |= DCMD_ADDRSPEC; 165 addr = regs.kregs[KREG_FP]; 166 167 if (verbose) 168 return (kt_stackv(addr, flags, argc, argv)); 169 else 170 return (kt_stack(addr, flags, argc, argv)); 171 } 172 173 /*ARGSUSED*/ 174 int 175 kt_cpuregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 176 { 177 mdb_tgt_t *t = mdb.m_target; 178 mdb_tgt_gregset_t regs; 179 intptr_t cpuid = 0; 180 int i; 181 182 if (flags & DCMD_ADDRSPEC) { 183 if (argc != 0) 184 return (DCMD_USAGE); 185 if ((cpuid = kt_cpu2cpuid(addr)) < 0) { 186 (void) set_errno(EMDB_NOMAP); 187 mdb_warn("failed to find cpuid for cpu at %p", addr); 188 return (DCMD_ERR); 189 } 190 } 191 192 193 i = mdb_getopts(argc, argv, 194 'c', MDB_OPT_UINTPTR, &cpuid, 195 NULL); 196 197 argc -= i; 198 argv += i; 199 200 if (argc != 0) 201 return (DCMD_USAGE); 202 203 if (kt_kvmregs(t, cpuid, ®s) != 0) { 204 mdb_warn("failed to get regs for cpu %d\n", cpuid); 205 return (DCMD_ERR); 206 } 207 208 return (kt_regs((uintptr_t)®s, flags, argc, argv)); 209 } 210