xref: /illumos-gate/usr/src/cmd/mdb/common/kmdb/kmdb_kdi.c (revision ae115bc7)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * The KDI, or kernel/debugger interface, is used to allow the kernel and the
30  * debugger to communicate.  These communications take two forms:
31  *
32  *  1. kernel to debugger.  Interfaces of this type are used by the kernel to
33  *     inform the debugger of changes in the state of the system that need to
34  *     be noted by the debugger.  For example, the kernel uses one of these
35  *     interfaces to tell debugger that the set of currently-loaded modules
36  *     has changed.
37  *
38  *  2. debugger to kernel.  Interfaces of this type are used by the debugger
39  *     to extract information from the kernel that would otherwise be difficult
40  *     to get, or to perform services that are specific to the machine being
41  *     used.  An example of the former is the module iterator, which is needed
42  *     to allow symbol resolution, but which needs to resolve symbols prior
43  *     to the iteration.  The latter class include machine-specific or
44  *     cpu-type-specific functions, such as the I-cache flusher.  By directly
45  *     using the kernel versions of these functions, we avoid the need to
46  *     include multiple versions of each function - one per cpu and/or machine -
47  *     in kmdb.
48  */
49 
50 #include <sys/kdi_impl.h>
51 
52 #include <kmdb/kmdb_kdi.h>
53 #include <kmdb/kmdb_dpi.h>
54 #include <kmdb/kmdb_kvm.h>
55 #include <kmdb/kmdb_promif.h>
56 #include <mdb/mdb_debug.h>
57 #include <mdb/mdb_err.h>
58 #include <mdb/mdb.h>
59 
60 static int kdi_unload_request;
61 
62 typedef struct mod_interp_data {
63 	int	(*mid_usercb)(struct modctl *, void *);
64 	void	*mid_userarg;
65 	jmp_buf mid_pcb;
66 	jmp_buf *mid_oldpcb;
67 } mod_interp_data_t;
68 
69 static kmdb_auxv_t *kdi_auxv;
70 
71 int
kmdb_kdi_mods_changed(void)72 kmdb_kdi_mods_changed(void)
73 {
74 	return (mdb.m_kdi->kdi_mods_changed());
75 }
76 
77 static int
kmdb_kdi_mod_interp(struct modctl * mp,void * arg)78 kmdb_kdi_mod_interp(struct modctl *mp, void *arg)
79 {
80 	mod_interp_data_t *mid = arg;
81 	int rc;
82 
83 	kmdb_dpi_restore_fault_hdlr(mid->mid_oldpcb);
84 	rc = mid->mid_usercb(mp, mid->mid_userarg);
85 	mid->mid_oldpcb = kmdb_dpi_set_fault_hdlr(&mid->mid_pcb);
86 
87 	return (rc);
88 }
89 
90 /*
91  * We need to protect ourselves against any problems that may occur while
92  * executing the module iterator, currently located in krtld.  If, for
93  * example, one of the next pointers in the module list points to an invalid
94  * address, we don't want kmdb to explode.  As such, we protect ourselves
95  * with the DPI fault-protection routines.  We don't want our fault-protection
96  * callback to protect the callback that the kmdb consumer provided, so we
97  * provide our own interposition callback that removes our fault-protector
98  * before invoking the user's callback.
99  */
100 int
kmdb_kdi_mod_iter(int (* cb)(struct modctl *,void *),void * arg)101 kmdb_kdi_mod_iter(int (*cb)(struct modctl *, void *), void *arg)
102 {
103 	mod_interp_data_t mid;
104 	int rc;
105 
106 	if (setjmp(mid.mid_pcb) != 0) {
107 		/* We took a fault while iterating through the modules */
108 		kmdb_dpi_restore_fault_hdlr(mid.mid_oldpcb);
109 		return (-1);
110 	}
111 
112 	mid.mid_usercb = cb;
113 	mid.mid_userarg = arg;
114 	mid.mid_oldpcb = kmdb_dpi_set_fault_hdlr(&mid.mid_pcb);
115 
116 	rc = mdb.m_kdi->kdi_mod_iter(kmdb_kdi_mod_interp, &mid);
117 
118 	kmdb_dpi_restore_fault_hdlr(mid.mid_oldpcb);
119 
120 	return (rc);
121 }
122 
123 int
kmdb_kdi_mod_isloaded(struct modctl * modp)124 kmdb_kdi_mod_isloaded(struct modctl *modp)
125 {
126 	return (mdb.m_kdi->kdi_mod_isloaded(modp));
127 }
128 
129 int
kmdb_kdi_mod_haschanged(struct modctl * mc1,struct module * mp1,struct modctl * mc2,struct module * mp2)130 kmdb_kdi_mod_haschanged(struct modctl *mc1, struct module *mp1,
131     struct modctl *mc2, struct module *mp2)
132 {
133 	return (mdb.m_kdi->kdi_mod_haschanged(mc1, mp1, mc2, mp2));
134 }
135 
136 static ssize_t
kdi_prw(void * buf,size_t nbytes,physaddr_t addr,int (* rw)(caddr_t,size_t,physaddr_t,size_t *))137 kdi_prw(void *buf, size_t nbytes, physaddr_t addr, int (*rw)(caddr_t, size_t,
138     physaddr_t, size_t *))
139 {
140 	size_t sz;
141 	int rc;
142 
143 	kmdb_dpi_flush_slave_caches();
144 	if ((rc = rw(buf, nbytes, addr, &sz)) != 0)
145 		return (set_errno(rc));
146 
147 	return (sz);
148 }
149 
150 ssize_t
kmdb_kdi_pread(void * buf,size_t nbytes,physaddr_t addr)151 kmdb_kdi_pread(void *buf, size_t nbytes, physaddr_t addr)
152 {
153 	return (kdi_prw(buf, nbytes, addr, mdb.m_kdi->kdi_pread));
154 }
155 
156 ssize_t
kmdb_kdi_pwrite(void * buf,size_t nbytes,physaddr_t addr)157 kmdb_kdi_pwrite(void *buf, size_t nbytes, physaddr_t addr)
158 {
159 	return (kdi_prw(buf, nbytes, addr, mdb.m_kdi->kdi_pwrite));
160 }
161 
162 void
kmdb_kdi_flush_caches(void)163 kmdb_kdi_flush_caches(void)
164 {
165 	mdb.m_kdi->kdi_flush_caches();
166 }
167 
168 int
kmdb_kdi_get_unload_request(void)169 kmdb_kdi_get_unload_request(void)
170 {
171 	return (kdi_unload_request);
172 }
173 
174 void
kmdb_kdi_set_unload_request(void)175 kmdb_kdi_set_unload_request(void)
176 {
177 	kdi_unload_request = 1;
178 }
179 
180 int
kmdb_kdi_get_flags(void)181 kmdb_kdi_get_flags(void)
182 {
183 	uint_t flags = 0;
184 
185 	if (mdb.m_flags & MDB_FL_NOCTF)
186 		flags |= KMDB_KDI_FL_NOCTF;
187 	if (mdb.m_flags & MDB_FL_NOMODS)
188 		flags |= KMDB_KDI_FL_NOMODS;
189 
190 	return (flags);
191 }
192 
193 size_t
kmdb_kdi_range_is_nontoxic(uintptr_t va,size_t sz,int write)194 kmdb_kdi_range_is_nontoxic(uintptr_t va, size_t sz, int write)
195 {
196 	return (mdb.m_kdi->kdi_range_is_nontoxic(va, sz, write));
197 }
198 
199 void
kmdb_kdi_system_claim(void)200 kmdb_kdi_system_claim(void)
201 {
202 	(void) kmdb_dpi_call((uintptr_t)mdb.m_kdi->kdi_system_claim, 0, NULL);
203 	kmdb_prom_debugger_entry();
204 }
205 
206 void
kmdb_kdi_system_release(void)207 kmdb_kdi_system_release(void)
208 {
209 	kmdb_prom_debugger_exit();
210 
211 	if (mdb.m_kdi->kdi_system_release != NULL) {
212 		(void) kmdb_dpi_call((uintptr_t)mdb.m_kdi->kdi_system_release,
213 		    0, NULL);
214 	}
215 }
216 
217 struct cons_polledio *
kmdb_kdi_get_polled_io(void)218 kmdb_kdi_get_polled_io(void)
219 {
220 	return (mdb.m_kdi->kdi_get_polled_io());
221 }
222 
223 void
kmdb_kdi_kmdb_enter(void)224 kmdb_kdi_kmdb_enter(void)
225 {
226 	mdb.m_kdi->kdi_kmdb_enter();
227 }
228 
229 int
kmdb_kdi_vtop(uintptr_t va,physaddr_t * pap)230 kmdb_kdi_vtop(uintptr_t va, physaddr_t *pap)
231 {
232 	jmp_buf pcb, *oldpcb;
233 	int rc = 0;
234 
235 	if (setjmp(pcb) == 0) {
236 		int err;
237 
238 		oldpcb = kmdb_dpi_set_fault_hdlr(&pcb);
239 
240 		if ((err = mdb.m_kdi->kdi_vtop(va, pap)) != 0)
241 			rc = set_errno(err == ENOENT ? EMDB_NOMAP : err);
242 	} else {
243 		/* We faulted during the translation */
244 		rc = set_errno(EMDB_NOMAP);
245 	}
246 
247 	kmdb_dpi_restore_fault_hdlr(oldpcb);
248 
249 	return (rc);
250 }
251 
252 kdi_dtrace_state_t
kmdb_kdi_dtrace_get_state(void)253 kmdb_kdi_dtrace_get_state(void)
254 {
255 	return (mdb.m_kdi->kdi_dtrace_get_state());
256 }
257 
258 int
kmdb_kdi_dtrace_set(int state)259 kmdb_kdi_dtrace_set(int state)
260 {
261 	int err;
262 
263 	if ((err = mdb.m_kdi->kdi_dtrace_set(state)) != 0)
264 		return (set_errno(err));
265 
266 	return (0);
267 }
268 
269 /*
270  * This function is to be called only during kmdb initialization, as it
271  * uses the running kernel for symbol translation facilities.
272  */
273 uintptr_t
kmdb_kdi_lookup_by_name(char * modname,char * symname)274 kmdb_kdi_lookup_by_name(char *modname, char *symname)
275 {
276 	ASSERT(kmdb_dpi_get_state(NULL) == DPI_STATE_INIT);
277 
278 	return (kdi_auxv->kav_lookup_by_name(modname, symname));
279 }
280 
281 void
kmdb_kdi_init(kdi_t * kdi,kmdb_auxv_t * kav)282 kmdb_kdi_init(kdi_t *kdi, kmdb_auxv_t *kav)
283 {
284 	mdb.m_kdi = kdi;
285 	mdb.m_pagesize = kav->kav_pagesize;
286 
287 	kdi_unload_request = 0;
288 
289 	kdi_auxv = kav;
290 
291 	kmdb_kdi_init_isadep(kdi, kav);
292 }
293 
294 void
kmdb_kdi_end_init(void)295 kmdb_kdi_end_init(void)
296 {
297 	kdi_auxv = NULL;
298 }
299