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 /*
28  * MDB developer support module.  This module is loaded automatically when the
29  * proc target is initialized and the target is mdb itself.  In the future, we
30  * should document these facilities in the answerbook to aid module developers.
31  */
32 
33 #define	_MDB
34 #include <mdb/mdb_modapi.h>
35 #include <mdb/mdb_frame.h>
36 #include <mdb/mdb_io_impl.h>
37 #include <mdb/mdb_target_impl.h>
38 #include <kmdb/kmdb_wr_impl.h>
39 #include <mdb/mdb.h>
40 
41 static const mdb_t *
get_mdb(void)42 get_mdb(void)
43 {
44 	static mdb_t m;
45 
46 	if (mdb_readvar(&m, "mdb") == -1)
47 		mdb_warn("failed to read mdb_t state");
48 
49 	return (&m);
50 }
51 
52 static int
cmd_stack(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)53 cmd_stack(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
54 {
55 	const char sep[] =
56 	    "-----------------------------------------------------------------";
57 
58 	if (flags & DCMD_ADDRSPEC) {
59 		char buf[MDB_NV_NAMELEN + 1];
60 		uintptr_t sp, pc;
61 		mdb_idcmd_t idc;
62 		mdb_frame_t f;
63 		mdb_cmd_t c;
64 		mdb_arg_t *ap;
65 		size_t i;
66 
67 		if (mdb_vread(&f, sizeof (f), addr) == -1) {
68 			mdb_warn("failed to read frame at %p", addr);
69 			return (DCMD_ERR);
70 		}
71 
72 		bzero(&c, sizeof (mdb_cmd_t));
73 
74 		if (mdb_vread(&c, sizeof (c), (uintptr_t)f.f_cp) < 0 ||
75 		    mdb_vread(&idc, sizeof (idc), (uintptr_t)c.c_dcmd) < 0 ||
76 		    mdb_readstr(buf, sizeof (buf), (uintptr_t)idc.idc_name) < 1)
77 			(void) strcpy(buf, "?");
78 
79 		mdb_printf("+>\tframe <%u> %p (%s", f.f_id, addr, buf);
80 		ap = mdb_alloc(c.c_argv.a_nelems * sizeof (mdb_arg_t), UM_GC);
81 
82 		if (ap != NULL && mdb_vread(ap, c.c_argv.a_nelems *
83 		    sizeof (mdb_arg_t), (uintptr_t)c.c_argv.a_data) > 0) {
84 			for (i = 0; i < c.c_argv.a_nelems; i++) {
85 				switch (ap[i].a_type) {
86 				case MDB_TYPE_STRING:
87 					if (mdb_readstr(buf, sizeof (buf),
88 					    (uintptr_t)ap[i].a_un.a_str) > 0)
89 						mdb_printf(" %s", buf);
90 					else
91 						mdb_printf(" <str=%a>",
92 						    ap[i].a_un.a_str);
93 					break;
94 				case MDB_TYPE_IMMEDIATE:
95 					mdb_printf(" $[ 0x%llx ]",
96 					    ap[i].a_un.a_val);
97 					break;
98 				case MDB_TYPE_CHAR:
99 					mdb_printf(" '%c'", ap[i].a_un.a_char);
100 					break;
101 				default:
102 					mdb_printf(" <type=%d>", ap[i].a_type);
103 				}
104 			}
105 		}
106 
107 		mdb_printf(")\n\tf_list = %-?p\tf_cmds = %p\n",
108 		    addr + OFFSETOF(mdb_frame_t, f_list),
109 		    addr + OFFSETOF(mdb_frame_t, f_cmds));
110 		mdb_printf("\tf_istk = %-?p\tf_ostk = %p\n",
111 		    addr + OFFSETOF(mdb_frame_t, f_istk),
112 		    addr + OFFSETOF(mdb_frame_t, f_ostk));
113 		mdb_printf("\tf_wcbs = %-?p\tf_mblks = %p\n",
114 		    f.f_wcbs, f.f_mblks);
115 		mdb_printf("\tf_pcmd = %-?p\tf_pcb = %p\n",
116 		    f.f_pcmd, addr + OFFSETOF(mdb_frame_t, f_pcb));
117 		mdb_printf("\tf_cp = %-?p\t\tf_flags = 0x%x\n\n",
118 		    f.f_cp, f.f_flags);
119 
120 #if defined(__sparc)
121 		sp = ((uintptr_t *)f.f_pcb)[1];
122 		pc = ((uintptr_t *)f.f_pcb)[2];
123 #elif defined(__amd64)
124 		sp = ((uintptr_t *)f.f_pcb)[5];
125 		pc = ((uintptr_t *)f.f_pcb)[7];
126 #elif defined(__i386)
127 		sp = ((uintptr_t *)f.f_pcb)[3];
128 		pc = ((uintptr_t *)f.f_pcb)[5];
129 #else
130 #error	Unknown ISA
131 #endif
132 		if (pc != 0)
133 			mdb_printf("      [ %0?lr %a() ]\n", sp, pc);
134 
135 		mdb_set_dot(sp);
136 		mdb_inc_indent(8);
137 		mdb_eval("<.$C0");
138 		mdb_dec_indent(8);
139 		mdb_printf("%s\n", sep);
140 
141 	} else {
142 		mdb_printf("%s\n", sep);
143 		(void) mdb_walk_dcmd("mdb_frame", "mdb_stack", argc, argv);
144 	}
145 
146 	return (DCMD_OK);
147 }
148 
149 static int
cmd_frame(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)150 cmd_frame(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
151 {
152 	if ((flags & DCMD_ADDRSPEC) && argc == 0)
153 		return (cmd_stack(addr, flags, argc, argv));
154 
155 	return (DCMD_USAGE);
156 }
157 
158 /*ARGSUSED*/
159 static int
cmd_iob(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)160 cmd_iob(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
161 {
162 	mdb_iob_t iob;
163 	mdb_io_t io;
164 
165 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
166 		return (DCMD_USAGE);
167 
168 	if (DCMD_HDRSPEC(flags)) {
169 		mdb_printf("%?s %6s %6s %?s %s\n",
170 		    "IOB", "NBYTES", "FLAGS", "IOP", "OPS");
171 	}
172 
173 	if (mdb_vread(&iob, sizeof (iob), addr) == -1 ||
174 	    mdb_vread(&io, sizeof (io), (uintptr_t)iob.iob_iop) == -1) {
175 		mdb_warn("failed to read iob at %p", addr);
176 		return (DCMD_ERR);
177 	}
178 
179 	mdb_printf("%?p %6lu %6x %?p %a\n", addr, (ulong_t)iob.iob_nbytes,
180 	    iob.iob_flags, iob.iob_iop, io.io_ops);
181 
182 	return (DCMD_OK);
183 }
184 
185 /*ARGSUSED*/
186 static int
cmd_in(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)187 cmd_in(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
188 {
189 	mdb_printf("%p\n", get_mdb()->m_in);
190 	return (DCMD_OK);
191 }
192 
193 /*ARGSUSED*/
194 static int
cmd_out(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)195 cmd_out(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
196 {
197 	mdb_printf("%p\n", get_mdb()->m_out);
198 	return (DCMD_OK);
199 }
200 
201 /*ARGSUSED*/
202 static int
cmd_err(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)203 cmd_err(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
204 {
205 	mdb_printf("%p\n", get_mdb()->m_err);
206 	return (DCMD_OK);
207 }
208 
209 /*ARGSUSED*/
210 static int
cmd_target(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)211 cmd_target(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
212 {
213 	mdb_tgt_t t;
214 
215 	if (argc != 0)
216 		return (DCMD_USAGE);
217 
218 	if (!(flags & DCMD_ADDRSPEC))
219 		addr = (uintptr_t)get_mdb()->m_target;
220 
221 	if (mdb_vread(&t, sizeof (t), addr) != sizeof (t)) {
222 		mdb_warn("failed to read target at %p", addr);
223 		return (DCMD_ERR);
224 	}
225 
226 	mdb_printf("+>\ttarget %p (%a)\n", addr, t.t_ops);
227 
228 	mdb_printf("\tt_active = %-?p\tt_idle = %p\n",
229 	    addr + OFFSETOF(mdb_tgt_t, t_active),
230 	    addr + OFFSETOF(mdb_tgt_t, t_idle));
231 	mdb_printf("\tt_xdlist = %-?p\tt_module = %a\n",
232 	    addr + OFFSETOF(mdb_tgt_t, t_xdlist), t.t_module);
233 	mdb_printf("\tt_pshandle = %-?p\tt_data = %p\n",
234 	    t.t_pshandle, t.t_data);
235 	mdb_printf("\tt_status = %-?p\tt_matched = %p\n",
236 	    addr + OFFSETOF(mdb_tgt_t, t_status), t.t_matched);
237 	mdb_printf("\tt_flags = %-?x\tt_vecnt = 0t%u\n", t.t_flags, t.t_vecnt);
238 	mdb_printf("\tt_vepos = %-?d\tt_veneg = %d\n\n", t.t_vepos, t.t_veneg);
239 
240 	return (DCMD_OK);
241 }
242 
243 /*ARGSUSED*/
244 static int
cmd_sespec(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)245 cmd_sespec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
246 {
247 	mdb_sespec_t se;
248 
249 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
250 		return (DCMD_USAGE);
251 
252 	if (mdb_vread(&se, sizeof (se), addr) != sizeof (se)) {
253 		mdb_warn("failed to read sespec at %p", addr);
254 		return (DCMD_ERR);
255 	}
256 
257 	mdb_printf("+>\tsespec %p (%a)\n", addr, se.se_ops);
258 
259 	mdb_printf("\tse_selist = %-?p\tse_velist = %p\n",
260 	    addr + OFFSETOF(mdb_sespec_t, se_selist),
261 	    addr + OFFSETOF(mdb_sespec_t, se_velist));
262 
263 	mdb_printf("\tse_data = %-?p\tse_refs = %u\n",
264 	    se.se_data, se.se_refs);
265 	mdb_printf("\tse_state = %-?d\tse_errno = %d\n\n",
266 	    se.se_state, se.se_errno);
267 
268 	return (DCMD_OK);
269 }
270 
271 /*ARGSUSED*/
272 static int
cmd_vespec(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)273 cmd_vespec(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
274 {
275 	mdb_vespec_t ve;
276 
277 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
278 		return (DCMD_USAGE);
279 
280 	if (mdb_vread(&ve, sizeof (ve), addr) != sizeof (ve)) {
281 		mdb_warn("failed to read vespec at %p", addr);
282 		return (DCMD_ERR);
283 	}
284 
285 	mdb_printf("+>\tvespec %p (id %d)\n", addr, ve.ve_id);
286 	mdb_printf("\tve_list = %-?p\tve_flags = 0x%x\n",
287 	    addr + OFFSETOF(mdb_vespec_t, ve_list), ve.ve_flags);
288 	mdb_printf("\tve_se = %-?p\tve_refs = %u\n", ve.ve_se, ve.ve_refs);
289 	mdb_printf("\tve_hits = %-?u\tve_lim = %u\n", ve.ve_hits, ve.ve_limit);
290 	mdb_printf("\tve_data = %-?p\tve_callback = %a\n",
291 	    ve.ve_data, ve.ve_callback);
292 	mdb_printf("\tve_args = %-?p\tve_dtor = %a\n\n",
293 	    ve.ve_args, ve.ve_dtor);
294 
295 	return (DCMD_OK);
296 }
297 
298 /*ARGSUSED*/
299 static int
cmd_wr(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)300 cmd_wr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
301 {
302 	char path[MAXPATHLEN];
303 	kmdb_wr_t wn;
304 	char dir;
305 
306 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
307 		return (DCMD_USAGE);
308 
309 	if (mdb_vread(&wn, sizeof (wn), addr) != sizeof (wn)) {
310 		mdb_warn("failed to read wr node at %p", addr);
311 		return (DCMD_ERR);
312 	}
313 
314 	if (DCMD_HDRSPEC(flags)) {
315 		mdb_printf("%-9s %3s %?s %s\n",
316 		    "COMMAND", "ERR", "MODCTL", "NAME");
317 	}
318 
319 	dir = "><"[WR_ISACK(&wn) != 0];
320 	switch (WR_TASK(&wn)) {
321 	case WNTASK_DMOD_LOAD: {
322 		kmdb_wr_load_t dlr;
323 
324 		if (mdb_vread(&dlr, sizeof (dlr), addr) != sizeof (dlr)) {
325 			mdb_warn("failed to read kmdb_wr_load_t at %p", addr);
326 			return (DCMD_ERR);
327 		}
328 
329 		if (mdb_readstr(path, sizeof (path),
330 		    (uintptr_t)dlr.dlr_fname) < 0) {
331 			mdb_warn("failed to read path name at %p",
332 			    dlr.dlr_fname);
333 			*path = '\0';
334 		}
335 
336 		mdb_printf("%cload     %3d %?p %s\n", dir, dlr.dlr_errno,
337 		    dlr.dlr_modctl, path);
338 		break;
339 	}
340 
341 	case WNTASK_DMOD_LOAD_ALL:
342 		mdb_printf("%cload all %3d\n", dir, wn.wn_errno);
343 		break;
344 
345 	case WNTASK_DMOD_UNLOAD: {
346 		kmdb_wr_unload_t dur;
347 
348 		if (mdb_vread(&dur, sizeof (dur), addr) != sizeof (dur)) {
349 			mdb_warn("failed to read kmdb_wr_unload_t at %p", addr);
350 			return (DCMD_ERR);
351 		}
352 
353 		if (mdb_readstr(path, sizeof (path),
354 		    (uintptr_t)dur.dur_modname) < 0) {
355 			mdb_warn("failed to read module name at %p",
356 			    dur.dur_modname);
357 			*path = '\0';
358 		}
359 
360 		mdb_printf("%cunload   %3d %?p %s\n", dir, dur.dur_errno,
361 		    dur.dur_modctl, path);
362 		break;
363 	}
364 
365 	case WNTASK_DMOD_PATH_CHANGE: {
366 		kmdb_wr_path_t dpth;
367 		uintptr_t pathp;
368 		int first = 1;
369 
370 		if (mdb_vread(&dpth, sizeof (dpth), addr) != sizeof (dpth)) {
371 			mdb_warn("failed to read kmdb_wr_path_t at %p", addr);
372 			return (DCMD_ERR);
373 		}
374 
375 		mdb_printf("%cpath chg %3d ", dir, dpth.dpth_errno);
376 		for (;;) {
377 			if (mdb_vread(&pathp, sizeof (pathp),
378 			    (uintptr_t)dpth.dpth_path) != sizeof (pathp)) {
379 				mdb_warn("failed to read path pointer at %p",
380 				    dpth.dpth_path);
381 				break;
382 			}
383 
384 			dpth.dpth_path++;
385 
386 			if (pathp == 0)
387 				break;
388 
389 			if (mdb_readstr(path, sizeof (path), pathp) < 0) {
390 				mdb_warn("failed to read path at %p", pathp);
391 				*path = '\0';
392 			}
393 
394 			mdb_printf("%s%s", (first ? "" : "\n             "),
395 			    path);
396 			first = 0;
397 		}
398 		mdb_printf("\n");
399 		break;
400 	}
401 
402 	default:
403 		mdb_warn("unknown task type %d\n", wn.wn_task);
404 		return (DCMD_ERR);
405 	}
406 
407 	return (DCMD_OK);
408 }
409 
410 static int
iob_stack_walk_init(mdb_walk_state_t * wsp)411 iob_stack_walk_init(mdb_walk_state_t *wsp)
412 {
413 	mdb_iob_stack_t stk;
414 
415 	if (mdb_vread(&stk, sizeof (stk), wsp->walk_addr) == -1) {
416 		mdb_warn("failed to read iob_stack at %p", wsp->walk_addr);
417 		return (WALK_ERR);
418 	}
419 
420 	wsp->walk_addr = (uintptr_t)stk.stk_top;
421 	return (WALK_NEXT);
422 }
423 
424 static int
iob_stack_walk_step(mdb_walk_state_t * wsp)425 iob_stack_walk_step(mdb_walk_state_t *wsp)
426 {
427 	uintptr_t addr = wsp->walk_addr;
428 	mdb_iob_t iob;
429 
430 	if (addr == 0)
431 		return (WALK_DONE);
432 
433 	if (mdb_vread(&iob, sizeof (iob), addr) == -1) {
434 		mdb_warn("failed to read iob at %p", addr);
435 		return (WALK_ERR);
436 	}
437 
438 	wsp->walk_addr = (uintptr_t)iob.iob_next;
439 	return (wsp->walk_callback(addr, &iob, wsp->walk_cbdata));
440 }
441 
442 static int
frame_walk_init(mdb_walk_state_t * wsp)443 frame_walk_init(mdb_walk_state_t *wsp)
444 {
445 	if (wsp->walk_addr == 0)
446 		wsp->walk_addr = (uintptr_t)get_mdb()->m_flist.ml_prev;
447 
448 	return (WALK_NEXT);
449 }
450 
451 static int
frame_walk_step(mdb_walk_state_t * wsp)452 frame_walk_step(mdb_walk_state_t *wsp)
453 {
454 	uintptr_t addr = wsp->walk_addr;
455 	mdb_frame_t f;
456 
457 	if (addr == 0)
458 		return (WALK_DONE);
459 
460 	if (mdb_vread(&f, sizeof (f), addr) == -1) {
461 		mdb_warn("failed to read frame at %p", addr);
462 		return (WALK_ERR);
463 	}
464 
465 	wsp->walk_addr = (uintptr_t)f.f_list.ml_prev;
466 	return (wsp->walk_callback(addr, &f, wsp->walk_cbdata));
467 }
468 
469 static int
target_walk_init(mdb_walk_state_t * wsp)470 target_walk_init(mdb_walk_state_t *wsp)
471 {
472 	if (wsp->walk_addr == 0)
473 		wsp->walk_addr = (uintptr_t)get_mdb()->m_target;
474 
475 	return (WALK_NEXT);
476 }
477 
478 static int
target_walk_step(mdb_walk_state_t * wsp)479 target_walk_step(mdb_walk_state_t *wsp)
480 {
481 	uintptr_t addr = wsp->walk_addr;
482 	mdb_tgt_t t;
483 
484 	if (addr == 0)
485 		return (WALK_DONE);
486 
487 	if (mdb_vread(&t, sizeof (t), addr) == -1) {
488 		mdb_warn("failed to read target at %p", addr);
489 		return (WALK_ERR);
490 	}
491 
492 	wsp->walk_addr = (uintptr_t)t.t_tgtlist.ml_next;
493 	return (wsp->walk_callback(addr, &t, wsp->walk_cbdata));
494 }
495 
496 static int
sespec_walk_step(mdb_walk_state_t * wsp)497 sespec_walk_step(mdb_walk_state_t *wsp)
498 {
499 	uintptr_t addr = wsp->walk_addr;
500 	mdb_sespec_t s;
501 
502 	if (addr == 0)
503 		return (WALK_DONE);
504 
505 	if (mdb_vread(&s, sizeof (s), addr) == -1) {
506 		mdb_warn("failed to read sespec at %p", addr);
507 		return (WALK_ERR);
508 	}
509 
510 	wsp->walk_addr = (uintptr_t)s.se_selist.ml_next;
511 	return (wsp->walk_callback(addr, &s, wsp->walk_cbdata));
512 }
513 
514 static int
vespec_walk_step(mdb_walk_state_t * wsp)515 vespec_walk_step(mdb_walk_state_t *wsp)
516 {
517 	uintptr_t addr = wsp->walk_addr;
518 	mdb_vespec_t v;
519 
520 	if (addr == 0)
521 		return (WALK_DONE);
522 
523 	if (mdb_vread(&v, sizeof (v), addr) == -1) {
524 		mdb_warn("failed to read vespec at %p", addr);
525 		return (WALK_ERR);
526 	}
527 
528 	wsp->walk_addr = (uintptr_t)v.ve_list.ml_next;
529 	return (wsp->walk_callback(addr, &v, wsp->walk_cbdata));
530 }
531 
532 static int
se_matched_walk_step(mdb_walk_state_t * wsp)533 se_matched_walk_step(mdb_walk_state_t *wsp)
534 {
535 	uintptr_t addr = wsp->walk_addr;
536 	mdb_sespec_t s;
537 
538 	if (addr == 0)
539 		return (WALK_DONE);
540 
541 	if (mdb_vread(&s, sizeof (s), addr) == -1) {
542 		mdb_warn("failed to read sespec at %p", addr);
543 		return (WALK_ERR);
544 	}
545 
546 	wsp->walk_addr = (uintptr_t)s.se_matched;
547 	return (wsp->walk_callback(addr, &s, wsp->walk_cbdata));
548 }
549 
550 static const mdb_dcmd_t dcmds[] = {
551 	{ "mdb_stack", "?", "print debugger stack", cmd_stack },
552 	{ "mdb_frame", ":", "print debugger frame", cmd_frame },
553 	{ "mdb_iob", ":", "print i/o buffer information", cmd_iob },
554 	{ "mdb_in", NULL, "print stdin iob", cmd_in },
555 	{ "mdb_out", NULL, "print stdout iob", cmd_out },
556 	{ "mdb_err", NULL, "print stderr iob", cmd_err },
557 	{ "mdb_tgt", "?", "print current target", cmd_target },
558 	{ "mdb_sespec", ":", "print software event specifier", cmd_sespec },
559 	{ "mdb_vespec", ":", "print virtual event specifier", cmd_vespec },
560 	{ "kmdb_wr", NULL, "print a work queue entry", cmd_wr },
561 	{ NULL }
562 };
563 
564 static const mdb_walker_t walkers[] = {
565 	{ "mdb_frame", "iterate over mdb_frame stack",
566 		frame_walk_init, frame_walk_step, NULL },
567 	{ "mdb_iob_stack", "iterate over mdb_iob_stack elements",
568 		iob_stack_walk_init, iob_stack_walk_step, NULL },
569 	{ "mdb_tgt", "iterate over active targets",
570 		target_walk_init, target_walk_step, NULL },
571 	{ "mdb_sespec", "iterate over software event specifiers",
572 		NULL, sespec_walk_step, NULL },
573 	{ "mdb_vespec", "iterate over virtual event specifiers",
574 		NULL, vespec_walk_step, NULL },
575 	{ "se_matched", "iterate over matched software event specifiers",
576 		NULL, se_matched_walk_step, NULL },
577 	{ NULL }
578 };
579 
580 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
581 
582 const mdb_modinfo_t *
_mdb_init(void)583 _mdb_init(void)
584 {
585 	char buf[256];
586 	uintptr_t addr;
587 	int rcount;
588 	GElf_Sym sym;
589 
590 	if (mdb_lookup_by_name("mdb", &sym) == -1) {
591 		mdb_warn("failed to read mdb state structure");
592 		return (NULL);
593 	}
594 
595 	if (sym.st_size != sizeof (mdb_t)) {
596 		mdb_printf("mdb: WARNING: mdb_ds may not match mdb "
597 		    "implementation (mdb_t mismatch)\n");
598 	}
599 
600 	if (mdb_readvar(&addr, "_mdb_abort_str") != -1 && addr != 0 &&
601 	    mdb_readstr(buf, sizeof (buf), addr) > 0)
602 		mdb_printf("mdb: debugger failed with error: %s\n", buf);
603 
604 	if (mdb_readvar(&rcount, "_mdb_abort_rcount") != -1 && rcount != 0)
605 		mdb_printf("mdb: WARNING: resume executed %d times\n", rcount);
606 
607 	return (&modinfo);
608 }
609