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