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