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