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