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