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 == NULL)
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 == NULL)
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 == NULL)
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 == NULL)
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 == NULL)
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 == NULL)
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 == NULL)
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 == NULL)
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 == NULL)
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 != NULL &&
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