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
kt_getareg(mdb_tgt_t * t,mdb_tgt_tid_t tid,const char * rname,mdb_tgt_reg_t * rp)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
kt_putareg(mdb_tgt_t * t,mdb_tgt_tid_t tid,const char * rname,mdb_tgt_reg_t r)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
kt_kvmregs(mdb_tgt_t * t,uint_t cpuid,mdb_tgt_gregset_t * kregs)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
kt_cpu2cpuid(uintptr_t cpup)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
kt_cpustack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
kt_cpuregs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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