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 /*
23  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright (c) 2013 by Delphix. All rights reserved.
25  */
26 
27 #include <mdb/mdb_modapi.h>
28 #include <mdb/mdb_module.h>
29 #include <mdb/mdb_string.h>
30 #include <mdb/mdb_debug.h>
31 #include <mdb/mdb_callb.h>
32 #include <mdb/mdb_dump.h>
33 #include <mdb/mdb_err.h>
34 #include <mdb/mdb_io.h>
35 #include <mdb/mdb_lex.h>
36 #include <mdb/mdb_frame.h>
37 #include <mdb/mdb.h>
38 
39 /*
40  * Private callback structure for implementing mdb_walk_dcmd, below.
41  */
42 typedef struct {
43 	mdb_idcmd_t *dw_dcmd;
44 	mdb_argvec_t dw_argv;
45 	uint_t dw_flags;
46 } dcmd_walk_arg_t;
47 
48 /*
49  * Global properties which modules are allowed to look at.  These are
50  * re-initialized by the target activation callbacks.
51  */
52 int mdb_prop_postmortem = FALSE;	/* Are we examining a dump? */
53 int mdb_prop_kernel = FALSE;		/* Are we examining a kernel? */
54 int mdb_prop_datamodel = 0;		/* Data model (see mdb_target_impl.h) */
55 
56 ssize_t
57 mdb_vread(void *buf, size_t nbytes, uintptr_t addr)
58 {
59 	ssize_t rbytes = mdb_tgt_vread(mdb.m_target, buf, nbytes, addr);
60 
61 	if (rbytes > 0 && rbytes < nbytes)
62 		return (set_errbytes(rbytes, nbytes));
63 
64 	return (rbytes);
65 }
66 
67 ssize_t
68 mdb_vwrite(const void *buf, size_t nbytes, uintptr_t addr)
69 {
70 	return (mdb_tgt_vwrite(mdb.m_target, buf, nbytes, addr));
71 }
72 
73 ssize_t
74 mdb_fread(void *buf, size_t nbytes, uintptr_t addr)
75 {
76 	ssize_t rbytes = mdb_tgt_fread(mdb.m_target, buf, nbytes, addr);
77 
78 	if (rbytes > 0 && rbytes < nbytes)
79 		return (set_errbytes(rbytes, nbytes));
80 
81 	return (rbytes);
82 }
83 
84 ssize_t
85 mdb_fwrite(const void *buf, size_t nbytes, uintptr_t addr)
86 {
87 	return (mdb_tgt_fwrite(mdb.m_target, buf, nbytes, addr));
88 }
89 
90 ssize_t
91 mdb_pread(void *buf, size_t nbytes, physaddr_t addr)
92 {
93 	ssize_t rbytes = mdb_tgt_pread(mdb.m_target, buf, nbytes, addr);
94 
95 	if (rbytes > 0 && rbytes < nbytes)
96 		return (set_errbytes(rbytes, nbytes));
97 
98 	return (rbytes);
99 }
100 
101 ssize_t
102 mdb_pwrite(const void *buf, size_t nbytes, physaddr_t addr)
103 {
104 	return (mdb_tgt_pwrite(mdb.m_target, buf, nbytes, addr));
105 }
106 
107 ssize_t
108 mdb_readstr(char *buf, size_t nbytes, uintptr_t addr)
109 {
110 	return (mdb_tgt_readstr(mdb.m_target, MDB_TGT_AS_VIRT,
111 	    buf, nbytes, addr));
112 }
113 
114 ssize_t
115 mdb_writestr(const char *buf, uintptr_t addr)
116 {
117 	return (mdb_tgt_writestr(mdb.m_target, MDB_TGT_AS_VIRT, buf, addr));
118 }
119 
120 ssize_t
121 mdb_readsym(void *buf, size_t nbytes, const char *name)
122 {
123 	ssize_t rbytes = mdb_tgt_readsym(mdb.m_target, MDB_TGT_AS_VIRT,
124 	    buf, nbytes, MDB_TGT_OBJ_EVERY, name);
125 
126 	if (rbytes > 0 && rbytes < nbytes)
127 		return (set_errbytes(rbytes, nbytes));
128 
129 	return (rbytes);
130 }
131 
132 ssize_t
133 mdb_writesym(const void *buf, size_t nbytes, const char *name)
134 {
135 	return (mdb_tgt_writesym(mdb.m_target, MDB_TGT_AS_VIRT,
136 	    buf, nbytes, MDB_TGT_OBJ_EVERY, name));
137 }
138 
139 ssize_t
140 mdb_readvar(void *buf, const char *name)
141 {
142 	GElf_Sym sym;
143 
144 	if (mdb_tgt_lookup_by_name(mdb.m_target, MDB_TGT_OBJ_EVERY,
145 	    name, &sym, NULL))
146 		return (-1);
147 
148 	if (mdb_tgt_vread(mdb.m_target, buf, sym.st_size,
149 	    (uintptr_t)sym.st_value) == sym.st_size)
150 		return ((ssize_t)sym.st_size);
151 
152 	return (-1);
153 }
154 
155 ssize_t
156 mdb_writevar(const void *buf, const char *name)
157 {
158 	GElf_Sym sym;
159 
160 	if (mdb_tgt_lookup_by_name(mdb.m_target, MDB_TGT_OBJ_EVERY,
161 	    name, &sym, NULL))
162 		return (-1);
163 
164 	if (mdb_tgt_vwrite(mdb.m_target, buf, sym.st_size,
165 	    (uintptr_t)sym.st_value) == sym.st_size)
166 		return ((ssize_t)sym.st_size);
167 
168 	return (-1);
169 }
170 
171 int
172 mdb_lookup_by_name(const char *name, GElf_Sym *sym)
173 {
174 	return (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, name, sym));
175 }
176 
177 int
178 mdb_lookup_by_obj(const char *obj, const char *name, GElf_Sym *sym)
179 {
180 	return (mdb_tgt_lookup_by_name(mdb.m_target, obj, name, sym, NULL));
181 }
182 
183 int
184 mdb_lookup_by_addr(uintptr_t addr, uint_t flags, char *buf,
185 	size_t nbytes, GElf_Sym *sym)
186 {
187 	return (mdb_tgt_lookup_by_addr(mdb.m_target, addr, flags,
188 	    buf, nbytes, sym, NULL));
189 }
190 
191 int
192 mdb_getareg(mdb_tid_t tid, const char *rname, mdb_reg_t *rp)
193 {
194 	return (mdb_tgt_getareg(mdb.m_target, tid, rname, rp));
195 }
196 
197 u_longlong_t
198 mdb_strtoull(const char *s)
199 {
200 	int radix = mdb.m_radix;
201 
202 	if (s[0] == '0') {
203 		switch (s[1]) {
204 		case 'I':
205 		case 'i':
206 			radix = 2;
207 			s += 2;
208 			break;
209 		case 'O':
210 		case 'o':
211 			radix = 8;
212 			s += 2;
213 			break;
214 		case 'T':
215 		case 't':
216 			radix = 10;
217 			s += 2;
218 			break;
219 		case 'X':
220 		case 'x':
221 			radix = 16;
222 			s += 2;
223 			break;
224 		}
225 	}
226 
227 	return (strtonum(s, radix));
228 }
229 
230 size_t
231 mdb_snprintf(char *buf, size_t nbytes, const char *format, ...)
232 {
233 	va_list alist;
234 
235 	va_start(alist, format);
236 	nbytes = mdb_iob_vsnprintf(buf, nbytes, format, alist);
237 	va_end(alist);
238 
239 	return (nbytes);
240 }
241 
242 void
243 mdb_printf(const char *format, ...)
244 {
245 	va_list alist;
246 
247 	va_start(alist, format);
248 	mdb_iob_vprintf(mdb.m_out, format, alist);
249 	va_end(alist);
250 }
251 
252 void
253 mdb_warn(const char *format, ...)
254 {
255 	va_list alist;
256 
257 	va_start(alist, format);
258 	vwarn(format, alist);
259 	va_end(alist);
260 }
261 
262 void
263 mdb_flush(void)
264 {
265 	mdb_iob_flush(mdb.m_out);
266 }
267 
268 /*
269  * Convert an object of len bytes pointed to by srcraw between
270  * network-order and host-order and store in dstraw.  The length len must
271  * be the actual length of the objects pointed to by srcraw and dstraw (or
272  * zero) or the results are undefined.  srcraw and dstraw may be the same,
273  * in which case the object is converted in-place.  Note that this routine
274  * will convert from host-order to network-order or network-order to
275  * host-order, since the conversion is the same in either case.
276  */
277 /* ARGSUSED */
278 void
279 mdb_nhconvert(void *dstraw, const void *srcraw, size_t len)
280 {
281 #ifdef	_LITTLE_ENDIAN
282 	uint8_t	b1, b2;
283 	uint8_t *dst, *src;
284 	size_t i;
285 
286 	dst = (uint8_t *)dstraw;
287 	src = (uint8_t *)srcraw;
288 	for (i = 0; i < len / 2; i++) {
289 		b1 = src[i];
290 		b2 = src[len - i - 1];
291 		dst[i] = b2;
292 		dst[len - i - 1] = b1;
293 	}
294 #else
295 	if (dstraw != srcraw)
296 		bcopy(srcraw, dstraw, len);
297 #endif
298 }
299 
300 
301 /*
302  * Bit formatting functions: Note the interesting use of UM_GC here to
303  * allocate a buffer for the caller which will be automatically freed
304  * when the dcmd completes or is forcibly aborted.
305  */
306 
307 #define	NBNB			(NBBY / 2)	/* number of bits per nibble */
308 #define	SETBIT(buf, j, c) { \
309 	if (((j) + 1) % (NBNB + 1) == 0) \
310 		(buf)[(j)++] = ' '; \
311 	(buf)[(j)++] = (c); \
312 }
313 
314 const char *
315 mdb_one_bit(int width, int bit, int on)
316 {
317 	int i, j = 0;
318 	char *buf;
319 
320 	buf = mdb_zalloc(width + (width / NBNB) + 2, UM_GC | UM_SLEEP);
321 
322 	for (i = --width; i > bit; i--)
323 		SETBIT(buf, j, '.');
324 
325 	SETBIT(buf, j, on ? '1' : '0');
326 
327 	for (i = bit - 1; i >= 0; i--)
328 		SETBIT(buf, j, '.');
329 
330 	return (buf);
331 }
332 
333 const char *
334 mdb_inval_bits(int width, int start, int stop)
335 {
336 	int i, j = 0;
337 	char *buf;
338 
339 	buf = mdb_zalloc(width + (width / NBNB) + 2, UM_GC | UM_SLEEP);
340 
341 	for (i = --width; i > stop; i--)
342 		SETBIT(buf, j, '.');
343 
344 	for (i = stop; i >= start; i--)
345 		SETBIT(buf, j, 'x');
346 
347 	for (; i >= 0; i--)
348 		SETBIT(buf, j, '.');
349 
350 	return (buf);
351 }
352 
353 ulong_t
354 mdb_inc_indent(ulong_t i)
355 {
356 	if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT) {
357 		ulong_t margin = mdb_iob_getmargin(mdb.m_out);
358 		mdb_iob_margin(mdb.m_out, margin + i);
359 		return (margin);
360 	}
361 
362 	mdb_iob_margin(mdb.m_out, i);
363 	mdb_iob_setflags(mdb.m_out, MDB_IOB_INDENT);
364 	return (0);
365 }
366 
367 ulong_t
368 mdb_dec_indent(ulong_t i)
369 {
370 	if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_INDENT) {
371 		ulong_t margin = mdb_iob_getmargin(mdb.m_out);
372 
373 		if (margin < i || margin - i == 0) {
374 			mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
375 			mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN);
376 		} else
377 			mdb_iob_margin(mdb.m_out, margin - i);
378 
379 		return (margin);
380 	}
381 
382 	return (0);
383 }
384 
385 int
386 mdb_eval(const char *s)
387 {
388 	mdb_frame_t *ofp = mdb.m_fmark;
389 	mdb_frame_t *fp = mdb.m_frame;
390 	int err;
391 
392 	if (s == NULL)
393 		return (set_errno(EINVAL));
394 
395 	/*
396 	 * Push m_in down onto the input stack, then set m_in to point to the
397 	 * i/o buffer for our command string, and reset the frame marker.
398 	 * The mdb_run() function returns when the new m_in iob reaches EOF.
399 	 */
400 	mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
401 	mdb.m_in = mdb_iob_create(mdb_strio_create(s), MDB_IOB_RDONLY);
402 
403 	mdb.m_fmark = NULL;
404 	err = mdb_run();
405 	mdb.m_fmark = ofp;
406 
407 	/*
408 	 * Now pop the old standard input stream and restore mdb.m_in and
409 	 * the parser's saved current line number.
410 	 */
411 	mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
412 	yylineno = mdb_iob_lineno(mdb.m_in);
413 
414 	/*
415 	 * If mdb_run() returned an error, propagate this backward
416 	 * up the stack of debugger environment frames.
417 	 */
418 	if (MDB_ERR_IS_FATAL(err))
419 		longjmp(fp->f_pcb, err);
420 
421 	if (err == MDB_ERR_PAGER || err == MDB_ERR_SIGINT)
422 		return (set_errno(EMDB_CANCEL));
423 
424 	if (err != 0)
425 		return (set_errno(EMDB_EVAL));
426 
427 	return (0);
428 }
429 
430 void
431 mdb_set_dot(uintmax_t addr)
432 {
433 	mdb_nv_set_value(mdb.m_dot, addr);
434 	mdb.m_incr = 0;
435 }
436 
437 uintmax_t
438 mdb_get_dot(void)
439 {
440 	return (mdb_nv_get_value(mdb.m_dot));
441 }
442 
443 static int
444 walk_step(mdb_wcb_t *wcb)
445 {
446 	mdb_wcb_t *nwcb = wcb->w_lyr_head;
447 	int status;
448 
449 	/*
450 	 * If the control block has no layers, we just invoke the walker's
451 	 * step function and return status indicating whether to continue
452 	 * or stop.  If the control block has layers, we need to invoke
453 	 * ourself recursively for the next layer, until eventually we
454 	 * percolate down to an unlayered walk.
455 	 */
456 	if (nwcb == NULL)
457 		return (wcb->w_walker->iwlk_step(&wcb->w_state));
458 
459 	if ((status = walk_step(nwcb)) != WALK_NEXT) {
460 		wcb->w_lyr_head = nwcb->w_lyr_link;
461 		nwcb->w_lyr_link = NULL;
462 		mdb_wcb_destroy(nwcb);
463 	}
464 
465 	if (status == WALK_DONE && wcb->w_lyr_head != NULL)
466 		return (WALK_NEXT);
467 
468 	return (status);
469 }
470 
471 static int
472 walk_common(mdb_wcb_t *wcb)
473 {
474 	int status, rval = 0;
475 	mdb_frame_t *pfp;
476 
477 	/*
478 	 * Enter the control block in the active list so that mdb can clean
479 	 * up after it in case we abort out of the current command.
480 	 */
481 	if ((pfp = mdb_list_prev(mdb.m_frame)) != NULL && pfp->f_pcmd != NULL)
482 		mdb_wcb_insert(wcb, pfp);
483 	else
484 		mdb_wcb_insert(wcb, mdb.m_frame);
485 
486 	/*
487 	 * The per-walk constructor performs private buffer initialization
488 	 * and locates whatever symbols are necessary.
489 	 */
490 	if ((status = wcb->w_walker->iwlk_init(&wcb->w_state)) != WALK_NEXT) {
491 		if (status != WALK_DONE)
492 			rval = set_errno(EMDB_WALKINIT);
493 		goto done;
494 	}
495 
496 	/*
497 	 * Mark wcb to indicate that walk_init has been called (which means
498 	 * we can call walk_fini if the walk is aborted at this point).
499 	 */
500 	wcb->w_inited = TRUE;
501 
502 	while (walk_step(wcb) == WALK_NEXT)
503 		continue;
504 done:
505 	if ((pfp = mdb_list_prev(mdb.m_frame)) != NULL && pfp->f_pcmd != NULL)
506 		mdb_wcb_delete(wcb, pfp);
507 	else
508 		mdb_wcb_delete(wcb, mdb.m_frame);
509 
510 	mdb_wcb_destroy(wcb);
511 	return (rval);
512 }
513 
514 typedef struct pwalk_step {
515 	mdb_walk_cb_t ps_cb;
516 	void *ps_private;
517 } pwalk_step_t;
518 
519 static int
520 pwalk_step(uintptr_t addr, const void *data, void *private)
521 {
522 	pwalk_step_t *psp = private;
523 	int ret;
524 
525 	mdb.m_frame->f_cbactive = B_TRUE;
526 	ret = psp->ps_cb(addr, data, psp->ps_private);
527 	mdb.m_frame->f_cbactive = B_FALSE;
528 
529 	return (ret);
530 }
531 
532 int
533 mdb_pwalk(const char *name, mdb_walk_cb_t func, void *private, uintptr_t addr)
534 {
535 	mdb_iwalker_t *iwp = mdb_walker_lookup(name);
536 	pwalk_step_t p;
537 
538 	if (func == NULL)
539 		return (set_errno(EINVAL));
540 
541 	p.ps_cb = func;
542 	p.ps_private = private;
543 
544 	if (iwp != NULL) {
545 		int ret;
546 		int cbactive = mdb.m_frame->f_cbactive;
547 		mdb.m_frame->f_cbactive = B_FALSE;
548 		ret = walk_common(mdb_wcb_create(iwp, pwalk_step, &p, addr));
549 		mdb.m_frame->f_cbactive = cbactive;
550 		return (ret);
551 	}
552 
553 	return (-1); /* errno is set for us */
554 }
555 
556 int
557 mdb_walk(const char *name, mdb_walk_cb_t func, void *data)
558 {
559 	return (mdb_pwalk(name, func, data, NULL));
560 }
561 
562 /*ARGSUSED*/
563 static int
564 walk_dcmd(uintptr_t addr, const void *ignored, dcmd_walk_arg_t *dwp)
565 {
566 	int status = mdb_call_idcmd(dwp->dw_dcmd, addr, 1, dwp->dw_flags,
567 	    &dwp->dw_argv, NULL, NULL);
568 
569 	if (status == DCMD_USAGE || status == DCMD_ABORT)
570 		return (WALK_ERR);
571 
572 	dwp->dw_flags &= ~DCMD_LOOPFIRST;
573 	return (WALK_NEXT);
574 }
575 
576 int
577 mdb_pwalk_dcmd(const char *wname, const char *dcname,
578     int argc, const mdb_arg_t *argv, uintptr_t addr)
579 {
580 	mdb_argvec_t args;
581 	dcmd_walk_arg_t dw;
582 	mdb_iwalker_t *iwp;
583 	mdb_wcb_t *wcb;
584 	int status;
585 
586 	if (wname == NULL || dcname == NULL)
587 		return (set_errno(EINVAL));
588 
589 	if ((dw.dw_dcmd = mdb_dcmd_lookup(dcname)) == NULL)
590 		return (-1); /* errno is set for us */
591 
592 	if ((iwp = mdb_walker_lookup(wname)) == NULL)
593 		return (-1); /* errno is set for us */
594 
595 	args.a_data = (mdb_arg_t *)argv;
596 	args.a_nelems = args.a_size = argc;
597 
598 	mdb_argvec_create(&dw.dw_argv);
599 	mdb_argvec_copy(&dw.dw_argv, &args);
600 	dw.dw_flags = DCMD_LOOP | DCMD_LOOPFIRST | DCMD_ADDRSPEC;
601 
602 	wcb = mdb_wcb_create(iwp, (mdb_walk_cb_t)walk_dcmd, &dw, addr);
603 	status = walk_common(wcb);
604 
605 	mdb_argvec_zero(&dw.dw_argv);
606 	mdb_argvec_destroy(&dw.dw_argv);
607 
608 	return (status);
609 }
610 
611 int
612 mdb_walk_dcmd(const char *wname, const char *dcname,
613     int argc, const mdb_arg_t *argv)
614 {
615 	return (mdb_pwalk_dcmd(wname, dcname, argc, argv, NULL));
616 }
617 
618 /*ARGSUSED*/
619 static int
620 layered_walk_step(uintptr_t addr, const void *data, mdb_wcb_t *wcb)
621 {
622 	/*
623 	 * Prior to calling the top-level walker's step function, reset its
624 	 * mdb_walk_state_t walk_addr and walk_layer members to refer to the
625 	 * target virtual address and data buffer of the underlying object.
626 	 */
627 	wcb->w_state.walk_addr = addr;
628 	wcb->w_state.walk_layer = data;
629 
630 	return (wcb->w_walker->iwlk_step(&wcb->w_state));
631 }
632 
633 int
634 mdb_layered_walk(const char *wname, mdb_walk_state_t *wsp)
635 {
636 	mdb_wcb_t *cwcb, *wcb;
637 	mdb_iwalker_t *iwp;
638 
639 	if (wname == NULL || wsp == NULL)
640 		return (set_errno(EINVAL));
641 
642 	if ((iwp = mdb_walker_lookup(wname)) == NULL)
643 		return (-1); /* errno is set for us */
644 
645 	if ((cwcb = mdb_wcb_from_state(wsp)) == NULL)
646 		return (set_errno(EMDB_BADWCB));
647 
648 	if (cwcb->w_walker == iwp)
649 		return (set_errno(EMDB_WALKLOOP));
650 
651 	wcb = mdb_wcb_create(iwp, (mdb_walk_cb_t)layered_walk_step,
652 	    cwcb, wsp->walk_addr);
653 
654 	if (iwp->iwlk_init(&wcb->w_state) != WALK_NEXT) {
655 		mdb_wcb_destroy(wcb);
656 		return (set_errno(EMDB_WALKINIT));
657 	}
658 
659 	wcb->w_inited = TRUE;
660 
661 	mdb_dprintf(MDB_DBG_WALK, "added %s`%s as %s`%s layer\n",
662 	    iwp->iwlk_modp->mod_name, iwp->iwlk_name,
663 	    cwcb->w_walker->iwlk_modp->mod_name, cwcb->w_walker->iwlk_name);
664 
665 	if (cwcb->w_lyr_head != NULL) {
666 		for (cwcb = cwcb->w_lyr_head; cwcb->w_lyr_link != NULL; )
667 			cwcb = cwcb->w_lyr_link;
668 		cwcb->w_lyr_link = wcb;
669 	} else
670 		cwcb->w_lyr_head = wcb;
671 
672 	return (0);
673 }
674 
675 int
676 mdb_call_dcmd(const char *name, uintptr_t dot, uint_t flags,
677     int argc, const mdb_arg_t *argv)
678 {
679 	mdb_idcmd_t *idcp;
680 	mdb_argvec_t args;
681 	int status;
682 
683 	if (name == NULL || argc < 0)
684 		return (set_errno(EINVAL));
685 
686 	if ((idcp = mdb_dcmd_lookup(name)) == NULL)
687 		return (-1); /* errno is set for us */
688 
689 	args.a_data = (mdb_arg_t *)argv;
690 	args.a_nelems = args.a_size = argc;
691 	status = mdb_call_idcmd(idcp, dot, 1, flags, &args, NULL, NULL);
692 
693 	if (status == DCMD_ERR || status == DCMD_ABORT)
694 		return (set_errno(EMDB_DCFAIL));
695 
696 	if (status == DCMD_USAGE)
697 		return (set_errno(EMDB_DCUSAGE));
698 
699 	return (0);
700 }
701 
702 int
703 mdb_add_walker(const mdb_walker_t *wp)
704 {
705 	mdb_module_t *mp;
706 
707 	if (mdb.m_lmod == NULL) {
708 		mdb_cmd_t *cp = mdb.m_frame->f_cp;
709 		mp = cp->c_dcmd->idc_modp;
710 	} else
711 		mp = mdb.m_lmod;
712 
713 	return (mdb_module_add_walker(mp, wp, 0));
714 }
715 
716 int
717 mdb_remove_walker(const char *name)
718 {
719 	mdb_module_t *mp;
720 
721 	if (mdb.m_lmod == NULL) {
722 		mdb_cmd_t *cp = mdb.m_frame->f_cp;
723 		mp = cp->c_dcmd->idc_modp;
724 	} else
725 		mp = mdb.m_lmod;
726 
727 	return (mdb_module_remove_walker(mp, name));
728 }
729 
730 void
731 mdb_get_pipe(mdb_pipe_t *p)
732 {
733 	mdb_cmd_t *cp = mdb.m_frame->f_cp;
734 	mdb_addrvec_t *adp = &cp->c_addrv;
735 
736 	if (p == NULL) {
737 		warn("dcmd failure: mdb_get_pipe invoked with NULL pointer\n");
738 		longjmp(mdb.m_frame->f_pcb, MDB_ERR_API);
739 	}
740 
741 	if (adp->ad_nelems != 0) {
742 		ASSERT(adp->ad_ndx != 0);
743 		p->pipe_data = &adp->ad_data[adp->ad_ndx - 1];
744 		p->pipe_len = adp->ad_nelems - adp->ad_ndx + 1;
745 		adp->ad_ndx = adp->ad_nelems;
746 	} else {
747 		p->pipe_data = NULL;
748 		p->pipe_len = 0;
749 	}
750 }
751 
752 void
753 mdb_set_pipe(const mdb_pipe_t *p)
754 {
755 	mdb_cmd_t *cp = mdb.m_frame->f_pcmd;
756 
757 	if (p == NULL) {
758 		warn("dcmd failure: mdb_set_pipe invoked with NULL pointer\n");
759 		longjmp(mdb.m_frame->f_pcb, MDB_ERR_API);
760 	}
761 
762 	if (cp != NULL) {
763 		size_t nbytes = sizeof (uintptr_t) * p->pipe_len;
764 
765 		mdb_cmd_reset(cp);
766 		cp->c_addrv.ad_data = mdb_alloc(nbytes, UM_SLEEP);
767 		bcopy(p->pipe_data, cp->c_addrv.ad_data, nbytes);
768 		cp->c_addrv.ad_nelems = p->pipe_len;
769 		cp->c_addrv.ad_size = p->pipe_len;
770 	}
771 }
772 
773 ssize_t
774 mdb_get_xdata(const char *name, void *buf, size_t nbytes)
775 {
776 	return (mdb_tgt_getxdata(mdb.m_target, name, buf, nbytes));
777 }
778 
779 /*
780  * Private callback structure for implementing mdb_object_iter, below.
781  */
782 typedef struct {
783 	mdb_object_cb_t oi_cb;
784 	void *oi_arg;
785 	int oi_rval;
786 } object_iter_arg_t;
787 
788 /*ARGSUSED*/
789 static int
790 mdb_object_cb(void *data, const mdb_map_t *map, const char *fullname)
791 {
792 	object_iter_arg_t *arg = data;
793 	mdb_object_t obj;
794 
795 	if (arg->oi_rval != 0)
796 		return (0);
797 
798 	bzero(&obj, sizeof (obj));
799 	obj.obj_base = map->map_base;
800 	obj.obj_name = strbasename(map->map_name);
801 	obj.obj_size = map->map_size;
802 	obj.obj_fullname = fullname;
803 
804 	arg->oi_rval = arg->oi_cb(&obj, arg->oi_arg);
805 
806 	return (0);
807 }
808 
809 int
810 mdb_object_iter(mdb_object_cb_t cb, void *data)
811 {
812 	object_iter_arg_t arg;
813 
814 	arg.oi_cb = cb;
815 	arg.oi_arg = data;
816 	arg.oi_rval = 0;
817 
818 	if (mdb_tgt_object_iter(mdb.m_target, mdb_object_cb, &arg) != 0)
819 		return (-1);
820 
821 	return (arg.oi_rval);
822 }
823 
824 /*
825  * Private structure and function for implementing mdb_dumpptr on top
826  * of mdb_dump_internal
827  */
828 typedef struct dptrdat {
829 	mdb_dumpptr_cb_t func;
830 	void *arg;
831 } dptrdat_t;
832 
833 static ssize_t
834 mdb_dump_aux_ptr(void *buf, size_t nbyte, uint64_t offset, void *arg)
835 {
836 	dptrdat_t *dat = arg;
837 
838 	return (dat->func(buf, nbyte, offset, dat->arg));
839 }
840 
841 /*
842  * Private structure and function for handling callbacks which return
843  * EMDB_PARTIAL
844  */
845 typedef struct d64dat {
846 	mdb_dump64_cb_t func;
847 	void *arg;
848 } d64dat_t;
849 
850 static ssize_t
851 mdb_dump_aux_partial(void *buf, size_t nbyte, uint64_t offset, void *arg)
852 {
853 	d64dat_t *dat = arg;
854 	int result;
855 	int count;
856 
857 	result = dat->func(buf, nbyte, offset, dat->arg);
858 	if (result == -1 && errno == EMDB_PARTIAL) {
859 		count = 0;
860 		do {
861 			result = dat->func((char *)buf + count, 1,
862 			    offset + count, dat->arg);
863 			if (result == 1)
864 				count++;
865 		} while (count < nbyte && result == 1);
866 		if (count)
867 			result = count;
868 	}
869 
870 	return (result);
871 }
872 
873 int
874 mdb_dumpptr(uintptr_t addr, size_t len, uint_t flags, mdb_dumpptr_cb_t fp,
875     void *arg)
876 {
877 	dptrdat_t dat;
878 	d64dat_t dat64;
879 
880 	dat.func = fp;
881 	dat.arg = arg;
882 	dat64.func = mdb_dump_aux_ptr;
883 	dat64.arg = &dat;
884 	return (mdb_dump_internal(addr, len, flags, mdb_dump_aux_partial,
885 	    &dat64, sizeof (uintptr_t)));
886 }
887 
888 int
889 mdb_dump64(uint64_t addr, uint64_t len, uint_t flags, mdb_dump64_cb_t fp,
890     void *arg)
891 {
892 	d64dat_t dat64;
893 
894 	dat64.func = fp;
895 	dat64.arg = arg;
896 	return (mdb_dump_internal(addr, len, flags, mdb_dump_aux_partial,
897 	    &dat64, sizeof (uint64_t)));
898 }
899 
900 int
901 mdb_get_state(void)
902 {
903 	mdb_tgt_status_t ts;
904 
905 	(void) mdb_tgt_status(mdb.m_target, &ts);
906 
907 	return (ts.st_state);
908 }
909 
910 void *
911 mdb_callback_add(int class, mdb_callback_f fp, void *arg)
912 {
913 	mdb_module_t *m;
914 
915 	if (class != MDB_CALLBACK_STCHG && class != MDB_CALLBACK_PROMPT) {
916 		(void) set_errno(EINVAL);
917 		return (NULL);
918 	}
919 
920 	if (mdb.m_lmod != NULL)
921 		m = mdb.m_lmod;
922 	else
923 		m = mdb.m_frame->f_cp->c_dcmd->idc_modp;
924 
925 	return (mdb_callb_add(m, class, fp, arg));
926 }
927 
928 void
929 mdb_callback_remove(void *hdl)
930 {
931 	mdb_callb_remove(hdl);
932 }
933