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