xref: /illumos-gate/usr/src/cmd/mdb/intel/mdb/kvm_isadep.c (revision 0a47c91c)
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, &regs) != 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, &regs) != 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)&regs, flags, argc, argv));
209 }
210