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 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * The DPI, or debugger/PROM interface, is used to isolate the debugger from the
29 * means by which we use the PROM to control the machine.
30 */
31
32 #include <sys/types.h>
33 #include <setjmp.h>
34
35 #include <kmdb/kmdb_dpi_impl.h>
36 #include <kmdb/kmdb_kdi.h>
37 #include <kmdb/kmdb_auxv.h>
38 #include <kmdb/kmdb_wr_impl.h>
39 #include <kmdb/kmdb_module.h>
40 #include <kmdb/kmdb_start.h>
41 #include <kmdb/kmdb_asmutil.h>
42 #include <mdb/mdb_debug.h>
43 #include <mdb/mdb_err.h>
44 #include <mdb/mdb_string.h>
45 #include <mdb/mdb.h>
46
47 jmp_buf *kmdb_dpi_fault_pcb;
48 jmp_buf kmdb_dpi_resume_pcb;
49 jmp_buf kmdb_dpi_entry_pcb;
50
51 static int kmdb_dpi_state;
52 static int kmdb_dpi_state_why;
53
54 uint_t kmdb_dpi_resume_requested;
55 uint_t kmdb_dpi_switch_target = (uint_t)-1;
56
57 /* Used by the style-specific resume interfaces to signal the driver */
58 void (*kmdb_dpi_wrintr_fire)(void);
59
60 int
kmdb_dpi_init(kmdb_auxv_t * kav)61 kmdb_dpi_init(kmdb_auxv_t *kav)
62 {
63 kmdb_dpi_state = DPI_STATE_INIT;
64 kmdb_dpi_resume_requested = 0;
65 kmdb_dpi_wrintr_fire = kav->kav_wrintr_fire;
66
67 mdb.m_dpi = &kmdb_dpi_ops;
68 return (mdb.m_dpi->dpo_init(kav));
69 }
70
71 /*ARGSUSED1*/
72 void
kmdb_activate(kdi_debugvec_t ** dvecp,uint_t flags)73 kmdb_activate(kdi_debugvec_t **dvecp, uint_t flags)
74 {
75 mdb.m_dpi->dpo_debugger_activate(dvecp, flags);
76 }
77
78 void
kmdb_deactivate(void)79 kmdb_deactivate(void)
80 {
81 mdb.m_dpi->dpo_debugger_deactivate();
82 }
83
84 int
kmdb_dpi_reenter(void)85 kmdb_dpi_reenter(void)
86 {
87 int cmd;
88
89 kmdb_kdi_system_claim();
90
91 if ((cmd = setjmp(kmdb_dpi_entry_pcb)) == 0) {
92 /* Direct entry from the driver */
93 if (kmdb_dpi_resume_requested)
94 longjmp(kmdb_dpi_resume_pcb, 1);
95
96 kmdb_first_start();
97
98 fail("kmdb_first_start returned");
99 /*NOTREACHED*/
100 }
101
102 mdb_dprintf(MDB_DBG_DPI, "returning to driver - cmd %d%s\n", cmd,
103 (kmdb_dpi_work_required() ? " (work required)" : ""));
104
105 kmdb_kdi_system_release();
106
107 membar_producer();
108
109 /*
110 * The debugger wants us to do something - it returned a command
111 * via the setjmp(). The driver will know what to do with the
112 * command.
113 */
114 return (cmd);
115 }
116
117 void
kmdb_dpi_enter_mon(void)118 kmdb_dpi_enter_mon(void)
119 {
120 mdb.m_dpi->dpo_enter_mon();
121 }
122
123 void
kmdb_dpi_modchg_register(void (* func)(struct modctl *,int))124 kmdb_dpi_modchg_register(void (*func)(struct modctl *, int))
125 {
126 mdb.m_dpi->dpo_modchg_register(func);
127 }
128
129 void
kmdb_dpi_modchg_cancel(void)130 kmdb_dpi_modchg_cancel(void)
131 {
132 mdb.m_dpi->dpo_modchg_cancel();
133 }
134
135 int
kmdb_dpi_get_cpu_state(int cpuid)136 kmdb_dpi_get_cpu_state(int cpuid)
137 {
138 return (mdb.m_dpi->dpo_get_cpu_state(cpuid));
139 }
140
141 int
kmdb_dpi_get_master_cpuid(void)142 kmdb_dpi_get_master_cpuid(void)
143 {
144 return (mdb.m_dpi->dpo_get_master_cpuid());
145 }
146
147 const mdb_tgt_gregset_t *
kmdb_dpi_get_gregs(int cpuid)148 kmdb_dpi_get_gregs(int cpuid)
149 {
150 return (mdb.m_dpi->dpo_get_gregs(cpuid));
151 }
152
153 jmp_buf *
kmdb_dpi_set_fault_hdlr(jmp_buf * jb)154 kmdb_dpi_set_fault_hdlr(jmp_buf *jb)
155 {
156 jmp_buf *oldpcb = kmdb_dpi_fault_pcb;
157
158 kmdb_dpi_fault_pcb = jb;
159
160 return (oldpcb);
161 }
162
163 void
kmdb_dpi_restore_fault_hdlr(jmp_buf * jb)164 kmdb_dpi_restore_fault_hdlr(jmp_buf *jb)
165 {
166 (void) kmdb_dpi_set_fault_hdlr(jb);
167 }
168
169 /*
170 * Used to tell the driver that it needs to do work after the resume.
171 *
172 * CAUTION: This routine may be called *after* mdb_destroy
173 */
174 int
kmdb_dpi_work_required(void)175 kmdb_dpi_work_required(void)
176 {
177 return (kmdb_kdi_get_unload_request() ||
178 !kmdb_wr_driver_notify_isempty());
179 }
180
181 void
kmdb_dpi_resume_master(void)182 kmdb_dpi_resume_master(void)
183 {
184 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_MASTER);
185 }
186
187 void
kmdb_dpi_resume(void)188 kmdb_dpi_resume(void)
189 {
190 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_ALL);
191 }
192
193 void
kmdb_dpi_resume_unload(void)194 kmdb_dpi_resume_unload(void)
195 {
196 kmdb_dpi_resume_common(KMDB_DPI_CMD_RESUME_UNLOAD);
197 }
198
199 int
kmdb_dpi_switch_master(int tgt_cpuid)200 kmdb_dpi_switch_master(int tgt_cpuid)
201 {
202 if (kmdb_dpi_get_cpu_state(tgt_cpuid) < 0)
203 return (-1); /* errno is set for us */
204
205 kmdb_dpi_switch_target = tgt_cpuid;
206 kmdb_dpi_resume_common(KMDB_DPI_CMD_SWITCH_CPU);
207
208 return (0);
209 }
210
211 void
kmdb_dpi_flush_slave_caches(void)212 kmdb_dpi_flush_slave_caches(void)
213 {
214 kmdb_dpi_resume_common(KMDB_DPI_CMD_FLUSH_CACHES);
215 }
216
217 typedef struct work_results {
218 mdb_nv_t res_loads;
219 mdb_nv_t res_unloads;
220 } work_results_t;
221
222 static int
kmdb_dbgnotify_cb(kmdb_wr_t * wn,void * arg)223 kmdb_dbgnotify_cb(kmdb_wr_t *wn, void *arg)
224 {
225 work_results_t *res = arg;
226
227 switch (WR_TASK(wn)) {
228 case WNTASK_DMOD_LOAD: {
229 /*
230 * If this is an ack, the driver finished processing a load we
231 * requested. We process it and free the message. If this
232 * isn't an ack, then it's a driver-initiated load. We process
233 * the message, and send it back as an ack so the driver can
234 * free it.
235 */
236 kmdb_wr_load_t *dlr = (kmdb_wr_load_t *)wn;
237
238 mdb_dprintf(MDB_DBG_DPI, "received module load message\n");
239
240 if (kmdb_module_loaded(dlr) && res != NULL) {
241 (void) mdb_nv_insert(&res->res_loads,
242 strbasename(dlr->dlr_fname), NULL, 0, 0);
243 }
244
245 if (WR_ISACK(dlr)) {
246 kmdb_module_load_ack(dlr);
247 return (0);
248 }
249
250 /* Send it back as an ack */
251 mdb_dprintf(MDB_DBG_DPI, "Sending load request for %s back "
252 "as an ack\n", dlr->dlr_fname);
253 WR_ACK(wn);
254 kmdb_wr_driver_notify(wn);
255 return (0);
256 }
257
258 case WNTASK_DMOD_LOAD_ALL:
259 /*
260 * We initiated the load-all, so this must be an ack. The
261 * individual module load messages will arrive separately -
262 * there's no need to do anything further with this message.
263 */
264 ASSERT(WR_ISACK(wn));
265
266 mdb_dprintf(MDB_DBG_DPI, "received module load all ack\n");
267
268 kmdb_module_load_all_ack(wn);
269 return (0);
270
271 case WNTASK_DMOD_UNLOAD: {
272 /*
273 * The debugger received an unload message. The driver isn't
274 * supposed to initiate unloads, so we shouldn't see anything
275 * but acks. We tell the dmod subsystem that the module has
276 * been unloaded, and we free the message.
277 */
278 kmdb_wr_unload_t *dur = (kmdb_wr_unload_t *)wn;
279
280 ASSERT(WR_ISACK(dur));
281
282 mdb_dprintf(MDB_DBG_DPI, "received module unload ack\n");
283
284 if (kmdb_module_unloaded(dur) && res != NULL) {
285 (void) mdb_nv_insert(&res->res_unloads,
286 dur->dur_modname, NULL, 0, 0);
287 }
288
289 /* Done with message */
290 kmdb_module_unload_ack(dur);
291 return (0);
292 }
293
294 case WNTASK_DMOD_PATH_CHANGE: {
295 /*
296 * The debugger received a path change message. The driver
297 * can't initiate these, so it must be an acknowledgement.
298 * There's no processing to be done, so just free the message.
299 */
300 kmdb_wr_path_t *dpth = (kmdb_wr_path_t *)wn;
301
302 ASSERT(WR_ISACK(dpth));
303
304 mdb_dprintf(MDB_DBG_DPI, "received path change ack\n");
305
306 kmdb_module_path_ack(dpth);
307 return (0);
308 }
309
310 default:
311 mdb_warn("Received unknown message type %d from driver\n",
312 wn->wn_task);
313 /* Ignore it */
314 return (0);
315 }
316 }
317
318 static void
print_modules(mdb_nv_t * mods)319 print_modules(mdb_nv_t *mods)
320 {
321 mdb_var_t *v;
322
323 mdb_nv_rewind(mods);
324 while ((v = mdb_nv_advance(mods)) != NULL)
325 mdb_printf(" %s", mdb_nv_get_name(v));
326 }
327
328 void
kmdb_dpi_process_work_queue(void)329 kmdb_dpi_process_work_queue(void)
330 {
331 work_results_t res;
332
333 (void) mdb_nv_create(&res.res_loads, UM_SLEEP);
334 (void) mdb_nv_create(&res.res_unloads, UM_SLEEP);
335
336 mdb_dprintf(MDB_DBG_DPI, "processing work queue\n");
337 (void) kmdb_wr_debugger_process(kmdb_dbgnotify_cb, &res);
338
339 if (mdb_nv_size(&res.res_loads)) {
340 mdb_printf("Loaded modules: [");
341 print_modules(&res.res_loads);
342 mdb_printf(" ]\n");
343 }
344
345 if (mdb_nv_size(&res.res_unloads)) {
346 mdb_printf("Unloaded modules: [");
347 print_modules(&res.res_unloads);
348 mdb_printf(" ]\n");
349 }
350
351 mdb_nv_destroy(&res.res_loads);
352 mdb_nv_destroy(&res.res_unloads);
353 }
354
355 int
kmdb_dpi_step(void)356 kmdb_dpi_step(void)
357 {
358 return (mdb.m_dpi->dpo_step());
359 }
360
361 uintptr_t
kmdb_dpi_call(uintptr_t func,uint_t argc,const uintptr_t * argv)362 kmdb_dpi_call(uintptr_t func, uint_t argc, const uintptr_t *argv)
363 {
364 return (mdb.m_dpi->dpo_call(func, argc, argv));
365 }
366
367 int
kmdb_dpi_brkpt_arm(uintptr_t addr,mdb_instr_t * instrp)368 kmdb_dpi_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
369 {
370 int rc;
371
372 if ((rc = mdb.m_dpi->dpo_brkpt_arm(addr, instrp)) < 0)
373 mdb_warn("failed to arm breakpoint at %a", addr);
374
375 mdb_dprintf(MDB_DBG_DPI, "brkpt armed at %p %A\n", (void *)addr, addr);
376
377 return (rc);
378 }
379
380 int
kmdb_dpi_brkpt_disarm(uintptr_t addr,mdb_instr_t instrp)381 kmdb_dpi_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
382 {
383 int rc;
384
385 if ((rc = mdb.m_dpi->dpo_brkpt_disarm(addr, instrp)) < 0)
386 mdb_warn("failed to disarm breakpoint at %a", addr);
387
388 mdb_dprintf(MDB_DBG_DPI, "brkpt disarmed at %p %A\n", (void *)addr,
389 addr);
390
391 return (rc);
392 }
393
394 int
kmdb_dpi_wapt_validate(kmdb_wapt_t * wp)395 kmdb_dpi_wapt_validate(kmdb_wapt_t *wp)
396 {
397 if (mdb.m_dpi->dpo_wapt_validate(wp) < 0)
398 return (-1); /* errno is set for us */
399
400 return (0);
401 }
402
403 int
kmdb_dpi_wapt_reserve(kmdb_wapt_t * wp)404 kmdb_dpi_wapt_reserve(kmdb_wapt_t *wp)
405 {
406 if (mdb.m_dpi->dpo_wapt_reserve(wp) < 0)
407 return (-1); /* errno is set for us */
408
409 mdb_dprintf(MDB_DBG_DPI, "wapt reserve type %d at %p, priv %p\n",
410 wp->wp_type, (void *)wp->wp_addr, wp->wp_priv);
411
412 return (0);
413 }
414
415 void
kmdb_dpi_wapt_release(kmdb_wapt_t * wp)416 kmdb_dpi_wapt_release(kmdb_wapt_t *wp)
417 {
418 mdb.m_dpi->dpo_wapt_release(wp);
419 }
420
421 void
kmdb_dpi_wapt_arm(kmdb_wapt_t * wp)422 kmdb_dpi_wapt_arm(kmdb_wapt_t *wp)
423 {
424 mdb.m_dpi->dpo_wapt_arm(wp);
425
426 mdb_dprintf(MDB_DBG_DPI, "wapt armed at %p (type %d, priv %p)\n",
427 (void *)wp->wp_addr, wp->wp_type, wp->wp_priv);
428 }
429
430 void
kmdb_dpi_wapt_disarm(kmdb_wapt_t * wp)431 kmdb_dpi_wapt_disarm(kmdb_wapt_t *wp)
432 {
433 mdb.m_dpi->dpo_wapt_disarm(wp);
434
435 mdb_dprintf(MDB_DBG_DPI, "wapt disarmed at %p (type %d, priv %p)\n",
436 (void *)wp->wp_addr, wp->wp_type, wp->wp_priv);
437 }
438
439 int
kmdb_dpi_wapt_match(kmdb_wapt_t * wp)440 kmdb_dpi_wapt_match(kmdb_wapt_t *wp)
441 {
442 return (mdb.m_dpi->dpo_wapt_match(wp));
443 }
444
445 void
kmdb_dpi_set_state(int state,int why)446 kmdb_dpi_set_state(int state, int why)
447 {
448 if (kmdb_dpi_state != DPI_STATE_LOST) {
449 mdb_dprintf(MDB_DBG_DPI, "dpi_set_state %d why %d\n",
450 state, why);
451
452 kmdb_dpi_state = state;
453 kmdb_dpi_state_why = why;
454 }
455 }
456
457 int
kmdb_dpi_get_state(int * whyp)458 kmdb_dpi_get_state(int *whyp)
459 {
460 if (whyp != NULL)
461 *whyp = kmdb_dpi_state_why;
462
463 return (kmdb_dpi_state);
464 }
465
466 void
kmdb_dpi_dump_crumbs(uintptr_t addr,int cpuid)467 kmdb_dpi_dump_crumbs(uintptr_t addr, int cpuid)
468 {
469 mdb.m_dpi->dpo_dump_crumbs(addr, cpuid);
470 }
471