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