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