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
kmdb_kdi_mods_changed(void)70 kmdb_kdi_mods_changed(void)
71 {
72 return (mdb.m_kdi->kdi_mods_changed());
73 }
74
75 static int
kmdb_kdi_mod_interp(struct modctl * mp,void * arg)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
kmdb_kdi_mod_iter(int (* cb)(struct modctl *,void *),void * arg)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
kmdb_kdi_mod_isloaded(struct modctl * modp)122 kmdb_kdi_mod_isloaded(struct modctl *modp)
123 {
124 return (mdb.m_kdi->kdi_mod_isloaded(modp));
125 }
126
127 int
kmdb_kdi_mod_haschanged(struct modctl * mc1,struct module * mp1,struct modctl * mc2,struct module * mp2)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
kdi_prw(void * buf,size_t nbytes,physaddr_t addr,int (* rw)(caddr_t,size_t,physaddr_t,size_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
kmdb_kdi_pread(void * buf,size_t nbytes,physaddr_t addr)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
kmdb_kdi_pwrite(void * buf,size_t nbytes,physaddr_t addr)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
kmdb_kdi_flush_caches(void)161 kmdb_kdi_flush_caches(void)
162 {
163 mdb.m_kdi->kdi_flush_caches();
164 }
165
166 int
kmdb_kdi_get_unload_request(void)167 kmdb_kdi_get_unload_request(void)
168 {
169 return (kdi_unload_request);
170 }
171
172 void
kmdb_kdi_set_unload_request(void)173 kmdb_kdi_set_unload_request(void)
174 {
175 kdi_unload_request = 1;
176 }
177
178 int
kmdb_kdi_get_flags(void)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
kmdb_kdi_range_is_nontoxic(uintptr_t va,size_t sz,int write)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
kmdb_kdi_system_claim(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
kmdb_kdi_system_release(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 *
kmdb_kdi_get_polled_io(void)216 kmdb_kdi_get_polled_io(void)
217 {
218 return (mdb.m_kdi->kdi_get_polled_io());
219 }
220
221 void
kmdb_kdi_kmdb_enter(void)222 kmdb_kdi_kmdb_enter(void)
223 {
224 mdb.m_kdi->kdi_kmdb_enter();
225 }
226
227 int
kmdb_kdi_vtop(uintptr_t va,physaddr_t * pap)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
kmdb_kdi_dtrace_get_state(void)251 kmdb_kdi_dtrace_get_state(void)
252 {
253 return (mdb.m_kdi->kdi_dtrace_get_state());
254 }
255
256 int
kmdb_kdi_dtrace_set(int state)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
kmdb_kdi_lookup_by_name(char * modname,char * symname)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
kmdb_kdi_init(kdi_t * kdi,kmdb_auxv_t * kav)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
kmdb_kdi_end_init(void)293 kmdb_kdi_end_init(void)
294 {
295 kdi_auxv = NULL;
296 }
297