xref: /illumos-gate/usr/src/cmd/mdb/common/modules/dtrace/dtrace.c (revision 0f1d7ad6f691d02be262fe5a16f0edd3762a68e8)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * explicitly define DTRACE_ERRDEBUG to pull in definition of dtrace_errhash_t
29  * explicitly define _STDARG_H to avoid stdarg.h/varargs.h u/k defn conflict
30  */
31 #define	DTRACE_ERRDEBUG
32 #define	_STDARG_H
33 
34 #include <mdb/mdb_param.h>
35 #include <mdb/mdb_modapi.h>
36 #include <mdb/mdb_ks.h>
37 #include <sys/dtrace_impl.h>
38 #include <sys/vmem_impl.h>
39 #include <sys/ddi_impldefs.h>
40 #include <sys/sysmacros.h>
41 #include <sys/kobj.h>
42 #include <dtrace.h>
43 #include <alloca.h>
44 #include <ctype.h>
45 #include <errno.h>
46 #include <math.h>
47 
48 /*ARGSUSED*/
49 int
50 id2probe(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
51 {
52 	uintptr_t probe = NULL;
53 	uintptr_t probes;
54 
55 	if (!(flags & DCMD_ADDRSPEC))
56 		return (DCMD_USAGE);
57 
58 	if (addr == DTRACE_IDNONE || addr > UINT32_MAX)
59 		goto out;
60 
61 	if (mdb_readvar(&probes, "dtrace_probes") == -1) {
62 		mdb_warn("failed to read 'dtrace_probes'");
63 		return (DCMD_ERR);
64 	}
65 
66 	probes += (addr - 1) * sizeof (dtrace_probe_t *);
67 
68 	if (mdb_vread(&probe, sizeof (uintptr_t), probes) == -1) {
69 		mdb_warn("failed to read dtrace_probes[%d]", addr - 1);
70 		return (DCMD_ERR);
71 	}
72 
73 out:
74 	mdb_printf("%p\n", probe);
75 	return (DCMD_OK);
76 }
77 
78 void
79 dtrace_help(void)
80 {
81 
82 	mdb_printf("Given a dtrace_state_t structure that represents a "
83 	    "DTrace consumer, prints\n"
84 	    "dtrace(1M)-like output for in-kernel DTrace data.  (The "
85 	    "dtrace_state_t\n"
86 	    "structures for all DTrace consumers may be obtained by running "
87 	    "the \n"
88 	    "::dtrace_state dcmd.)   When data is present on multiple CPUs, "
89 	    "data are\n"
90 	    "presented in CPU order, with records within each CPU ordered "
91 	    "oldest to \n"
92 	    "youngest.  Options:\n\n"
93 	    "-c cpu     Only provide output for specified CPU.\n");
94 }
95 
96 static int
97 dtracemdb_eprobe(dtrace_state_t *state, dtrace_eprobedesc_t *epd)
98 {
99 	dtrace_epid_t epid = epd->dtepd_epid;
100 	dtrace_probe_t probe;
101 	dtrace_ecb_t ecb;
102 	uintptr_t addr, paddr, ap;
103 	dtrace_action_t act;
104 	int nactions, nrecs;
105 
106 	addr = (uintptr_t)state->dts_ecbs +
107 	    (epid - 1) * sizeof (dtrace_ecb_t *);
108 
109 	if (mdb_vread(&addr, sizeof (addr), addr) == -1) {
110 		mdb_warn("failed to read ecb for epid %d", epid);
111 		return (-1);
112 	}
113 
114 	if (addr == NULL) {
115 		mdb_warn("epid %d doesn't match an ecb\n", epid);
116 		return (-1);
117 	}
118 
119 	if (mdb_vread(&ecb, sizeof (ecb), addr) == -1) {
120 		mdb_warn("failed to read ecb at %p", addr);
121 		return (-1);
122 	}
123 
124 	paddr = (uintptr_t)ecb.dte_probe;
125 
126 	if (mdb_vread(&probe, sizeof (probe), paddr) == -1) {
127 		mdb_warn("failed to read probe for ecb %p", addr);
128 		return (-1);
129 	}
130 
131 	/*
132 	 * This is a little painful:  in order to find the number of actions,
133 	 * we need to first walk through them.
134 	 */
135 	for (ap = (uintptr_t)ecb.dte_action, nactions = 0; ap != NULL; ) {
136 		if (mdb_vread(&act, sizeof (act), ap) == -1) {
137 			mdb_warn("failed to read action %p on ecb %p",
138 			    ap, addr);
139 			return (-1);
140 		}
141 
142 		if (!DTRACEACT_ISAGG(act.dta_kind) && !act.dta_intuple)
143 			nactions++;
144 
145 		ap = (uintptr_t)act.dta_next;
146 	}
147 
148 	nrecs = epd->dtepd_nrecs;
149 	epd->dtepd_nrecs = nactions;
150 	epd->dtepd_probeid = probe.dtpr_id;
151 	epd->dtepd_uarg = ecb.dte_uarg;
152 	epd->dtepd_size = ecb.dte_size;
153 
154 	for (ap = (uintptr_t)ecb.dte_action, nactions = 0; ap != NULL; ) {
155 		if (mdb_vread(&act, sizeof (act), ap) == -1) {
156 			mdb_warn("failed to read action %p on ecb %p",
157 			    ap, addr);
158 			return (-1);
159 		}
160 
161 		if (!DTRACEACT_ISAGG(act.dta_kind) && !act.dta_intuple) {
162 			if (nrecs-- == 0)
163 				break;
164 
165 			epd->dtepd_rec[nactions++] = act.dta_rec;
166 		}
167 
168 		ap = (uintptr_t)act.dta_next;
169 	}
170 
171 	return (0);
172 }
173 
174 /*ARGSUSED*/
175 static int
176 dtracemdb_probe(dtrace_state_t *state, dtrace_probedesc_t *pd)
177 {
178 	uintptr_t base, addr, paddr, praddr;
179 	int nprobes, i;
180 	dtrace_probe_t probe;
181 	dtrace_provider_t prov;
182 
183 	if (pd->dtpd_id == DTRACE_IDNONE)
184 		pd->dtpd_id++;
185 
186 	if (mdb_readvar(&base, "dtrace_probes") == -1) {
187 		mdb_warn("failed to read 'dtrace_probes'");
188 		return (-1);
189 	}
190 
191 	if (mdb_readvar(&nprobes, "dtrace_nprobes") == -1) {
192 		mdb_warn("failed to read 'dtrace_nprobes'");
193 		return (-1);
194 	}
195 
196 	for (i = pd->dtpd_id; i <= nprobes; i++) {
197 		addr = base + (i - 1) * sizeof (dtrace_probe_t *);
198 
199 		if (mdb_vread(&paddr, sizeof (paddr), addr) == -1) {
200 			mdb_warn("couldn't read probe pointer at %p", addr);
201 			return (-1);
202 		}
203 
204 		if (paddr != NULL)
205 			break;
206 	}
207 
208 	if (paddr == NULL) {
209 		errno = ESRCH;
210 		return (-1);
211 	}
212 
213 	if (mdb_vread(&probe, sizeof (probe), paddr) == -1) {
214 		mdb_warn("couldn't read probe at %p", paddr);
215 		return (-1);
216 	}
217 
218 	pd->dtpd_id = probe.dtpr_id;
219 
220 	if (mdb_vread(pd->dtpd_name, DTRACE_NAMELEN,
221 	    (uintptr_t)probe.dtpr_name) == -1) {
222 		mdb_warn("failed to read probe name for probe %p", paddr);
223 		return (-1);
224 	}
225 
226 	if (mdb_vread(pd->dtpd_func, DTRACE_FUNCNAMELEN,
227 	    (uintptr_t)probe.dtpr_func) == -1) {
228 		mdb_warn("failed to read function name for probe %p", paddr);
229 		return (-1);
230 	}
231 
232 	if (mdb_vread(pd->dtpd_mod, DTRACE_MODNAMELEN,
233 	    (uintptr_t)probe.dtpr_mod) == -1) {
234 		mdb_warn("failed to read module name for probe %p", paddr);
235 		return (-1);
236 	}
237 
238 	praddr = (uintptr_t)probe.dtpr_provider;
239 
240 	if (mdb_vread(&prov, sizeof (prov), praddr) == -1) {
241 		mdb_warn("failed to read provider for probe %p", paddr);
242 		return (-1);
243 	}
244 
245 	if (mdb_vread(pd->dtpd_provider, DTRACE_PROVNAMELEN,
246 	    (uintptr_t)prov.dtpv_name) == -1) {
247 		mdb_warn("failed to read provider name for probe %p", paddr);
248 		return (-1);
249 	}
250 
251 	return (0);
252 }
253 
254 /*ARGSUSED*/
255 static int
256 dtracemdb_aggdesc(dtrace_state_t *state, dtrace_aggdesc_t *agd)
257 {
258 	dtrace_aggid_t aggid = agd->dtagd_id;
259 	dtrace_aggregation_t agg;
260 	dtrace_ecb_t ecb;
261 	uintptr_t addr, eaddr, ap, last;
262 	dtrace_action_t act;
263 	dtrace_recdesc_t *lrec;
264 	int nactions, nrecs;
265 
266 	addr = (uintptr_t)state->dts_aggregations +
267 	    (aggid - 1) * sizeof (dtrace_aggregation_t *);
268 
269 	if (mdb_vread(&addr, sizeof (addr), addr) == -1) {
270 		mdb_warn("failed to read aggregation for aggid %d", aggid);
271 		return (-1);
272 	}
273 
274 	if (addr == NULL) {
275 		mdb_warn("aggid %d doesn't match an aggregation\n", aggid);
276 		return (-1);
277 	}
278 
279 	if (mdb_vread(&agg, sizeof (agg), addr) == -1) {
280 		mdb_warn("failed to read aggregation at %p", addr);
281 		return (-1);
282 	}
283 
284 	eaddr = (uintptr_t)agg.dtag_ecb;
285 
286 	if (mdb_vread(&ecb, sizeof (ecb), eaddr) == -1) {
287 		mdb_warn("failed to read ecb for aggregation %p", addr);
288 		return (-1);
289 	}
290 
291 	last = (uintptr_t)addr + offsetof(dtrace_aggregation_t, dtag_action);
292 
293 	/*
294 	 * This is a little painful:  in order to find the number of actions,
295 	 * we need to first walk through them.
296 	 */
297 	ap = (uintptr_t)agg.dtag_first;
298 	nactions = 0;
299 
300 	for (;;) {
301 		if (mdb_vread(&act, sizeof (act), ap) == -1) {
302 			mdb_warn("failed to read action %p on aggregation %p",
303 			    ap, addr);
304 			return (-1);
305 		}
306 
307 		nactions++;
308 
309 		if (ap == last)
310 			break;
311 
312 		ap = (uintptr_t)act.dta_next;
313 	}
314 
315 	lrec = &act.dta_rec;
316 	agd->dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - agg.dtag_base;
317 
318 	nrecs = agd->dtagd_nrecs;
319 	agd->dtagd_nrecs = nactions;
320 	agd->dtagd_epid = ecb.dte_epid;
321 
322 	ap = (uintptr_t)agg.dtag_first;
323 	nactions = 0;
324 
325 	for (;;) {
326 		dtrace_recdesc_t rec;
327 
328 		if (mdb_vread(&act, sizeof (act), ap) == -1) {
329 			mdb_warn("failed to read action %p on aggregation %p",
330 			    ap, addr);
331 			return (-1);
332 		}
333 
334 		if (nrecs-- == 0)
335 			break;
336 
337 		rec = act.dta_rec;
338 		rec.dtrd_offset -= agg.dtag_base;
339 		rec.dtrd_uarg = 0;
340 		agd->dtagd_rec[nactions++] = rec;
341 
342 		if (ap == last)
343 			break;
344 
345 		ap = (uintptr_t)act.dta_next;
346 	}
347 
348 	return (0);
349 }
350 
351 static int
352 dtracemdb_bufsnap(dtrace_buffer_t *which, dtrace_bufdesc_t *desc)
353 {
354 	uintptr_t addr;
355 	size_t bufsize;
356 	dtrace_buffer_t buf;
357 	caddr_t data = desc->dtbd_data;
358 	processorid_t max_cpuid, cpu = desc->dtbd_cpu;
359 
360 	if (mdb_readvar(&max_cpuid, "max_cpuid") == -1) {
361 		mdb_warn("failed to read 'max_cpuid'");
362 		errno = EIO;
363 		return (-1);
364 	}
365 
366 	if (cpu < 0 || cpu > max_cpuid) {
367 		errno = EINVAL;
368 		return (-1);
369 	}
370 
371 	addr = (uintptr_t)which + cpu * sizeof (dtrace_buffer_t);
372 
373 	if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
374 		mdb_warn("failed to read buffer description at %p", addr);
375 		errno = EIO;
376 		return (-1);
377 	}
378 
379 	if (buf.dtb_tomax == NULL) {
380 		errno = ENOENT;
381 		return (-1);
382 	}
383 
384 	if (buf.dtb_flags & DTRACEBUF_WRAPPED) {
385 		bufsize = buf.dtb_size;
386 	} else {
387 		bufsize = buf.dtb_offset;
388 	}
389 
390 	if (mdb_vread(data, bufsize, (uintptr_t)buf.dtb_tomax) == -1) {
391 		mdb_warn("couldn't read buffer for CPU %d", cpu);
392 		errno = EIO;
393 		return (-1);
394 	}
395 
396 	if (buf.dtb_offset > buf.dtb_size) {
397 		mdb_warn("buffer for CPU %d has corrupt offset\n", cpu);
398 		errno = EIO;
399 		return (-1);
400 	}
401 
402 	if (buf.dtb_flags & DTRACEBUF_WRAPPED) {
403 		if (buf.dtb_xamot_offset > buf.dtb_size) {
404 			mdb_warn("ringbuffer for CPU %d has corrupt "
405 			    "wrapped offset\n", cpu);
406 			errno = EIO;
407 			return (-1);
408 		}
409 
410 		/*
411 		 * If the ring buffer has wrapped, it needs to be polished.
412 		 * See the comment in dtrace_buffer_polish() for details.
413 		 */
414 		if (buf.dtb_offset < buf.dtb_xamot_offset) {
415 			bzero(data + buf.dtb_offset,
416 			    buf.dtb_xamot_offset - buf.dtb_offset);
417 		}
418 
419 		if (buf.dtb_offset > buf.dtb_xamot_offset) {
420 			bzero(data + buf.dtb_offset,
421 			    buf.dtb_size - buf.dtb_offset);
422 			bzero(data, buf.dtb_xamot_offset);
423 		}
424 
425 		desc->dtbd_oldest = buf.dtb_xamot_offset;
426 	} else {
427 		desc->dtbd_oldest = 0;
428 	}
429 
430 	desc->dtbd_size = bufsize;
431 	desc->dtbd_drops = buf.dtb_drops;
432 	desc->dtbd_errors = buf.dtb_errors;
433 
434 	return (0);
435 }
436 
437 /*
438  * This is essentially identical to its cousin in the kernel.
439  */
440 static dof_hdr_t *
441 dtracemdb_dof_create(dtrace_state_t *state)
442 {
443 	dof_hdr_t *dof;
444 	dof_sec_t *sec;
445 	dof_optdesc_t *opt;
446 	int i, len = sizeof (dof_hdr_t) +
447 	    roundup(sizeof (dof_sec_t), sizeof (uint64_t)) +
448 	    sizeof (dof_optdesc_t) * DTRACEOPT_MAX;
449 
450 	dof = mdb_zalloc(len, UM_SLEEP);
451 	dof->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0;
452 	dof->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1;
453 	dof->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2;
454 	dof->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3;
455 
456 	dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE;
457 	dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE;
458 	dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION;
459 	dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION;
460 	dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS;
461 	dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS;
462 
463 	dof->dofh_flags = 0;
464 	dof->dofh_hdrsize = sizeof (dof_hdr_t);
465 	dof->dofh_secsize = sizeof (dof_sec_t);
466 	dof->dofh_secnum = 1;	/* only DOF_SECT_OPTDESC */
467 	dof->dofh_secoff = sizeof (dof_hdr_t);
468 	dof->dofh_loadsz = len;
469 	dof->dofh_filesz = len;
470 	dof->dofh_pad = 0;
471 
472 	/*
473 	 * Fill in the option section header...
474 	 */
475 	sec = (dof_sec_t *)((uintptr_t)dof + sizeof (dof_hdr_t));
476 	sec->dofs_type = DOF_SECT_OPTDESC;
477 	sec->dofs_align = sizeof (uint64_t);
478 	sec->dofs_flags = DOF_SECF_LOAD;
479 	sec->dofs_entsize = sizeof (dof_optdesc_t);
480 
481 	opt = (dof_optdesc_t *)((uintptr_t)sec +
482 	    roundup(sizeof (dof_sec_t), sizeof (uint64_t)));
483 
484 	sec->dofs_offset = (uintptr_t)opt - (uintptr_t)dof;
485 	sec->dofs_size = sizeof (dof_optdesc_t) * DTRACEOPT_MAX;
486 
487 	for (i = 0; i < DTRACEOPT_MAX; i++) {
488 		opt[i].dofo_option = i;
489 		opt[i].dofo_strtab = DOF_SECIDX_NONE;
490 		opt[i].dofo_value = state->dts_options[i];
491 	}
492 
493 	return (dof);
494 }
495 
496 static int
497 dtracemdb_format(dtrace_state_t *state, dtrace_fmtdesc_t *desc)
498 {
499 	uintptr_t addr, faddr;
500 	char c;
501 	int len = 0;
502 
503 	if (desc->dtfd_format == 0 || desc->dtfd_format > state->dts_nformats) {
504 		errno = EINVAL;
505 		return (-1);
506 	}
507 
508 	faddr = (uintptr_t)state->dts_formats +
509 	    (desc->dtfd_format - 1) * sizeof (char *);
510 
511 	if (mdb_vread(&addr, sizeof (addr), faddr) == -1) {
512 		mdb_warn("failed to read format string pointer at %p", faddr);
513 		return (-1);
514 	}
515 
516 	do {
517 		if (mdb_vread(&c, sizeof (c), addr + len++) == -1) {
518 			mdb_warn("failed to read format string at %p", addr);
519 			return (-1);
520 		}
521 	} while (c != '\0');
522 
523 	if (len > desc->dtfd_length) {
524 		desc->dtfd_length = len;
525 		return (0);
526 	}
527 
528 	if (mdb_vread(desc->dtfd_string, len, addr) == -1) {
529 		mdb_warn("failed to reread format string at %p", addr);
530 		return (-1);
531 	}
532 
533 	return (0);
534 }
535 
536 static int
537 dtracemdb_status(dtrace_state_t *state, dtrace_status_t *status)
538 {
539 	dtrace_dstate_t *dstate;
540 	int i, j;
541 	uint64_t nerrs;
542 	uintptr_t addr;
543 	int ncpu;
544 
545 	if (mdb_readvar(&ncpu, "_ncpu") == -1) {
546 		mdb_warn("failed to read '_ncpu'");
547 		return (DCMD_ERR);
548 	}
549 
550 	bzero(status, sizeof (dtrace_status_t));
551 
552 	if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) {
553 		errno = ENOENT;
554 		return (-1);
555 	}
556 
557 	/*
558 	 * For the MDB backend, we never set dtst_exiting or dtst_filled.  This
559 	 * is by design:  we don't want the library to try to stop tracing,
560 	 * because it doesn't particularly mean anything.
561 	 */
562 	nerrs = state->dts_errors;
563 	dstate = &state->dts_vstate.dtvs_dynvars;
564 
565 	for (i = 0; i < ncpu; i++) {
566 		dtrace_dstate_percpu_t dcpu;
567 		dtrace_buffer_t buf;
568 
569 		addr = (uintptr_t)&dstate->dtds_percpu[i];
570 
571 		if (mdb_vread(&dcpu, sizeof (dcpu), addr) == -1) {
572 			mdb_warn("failed to read per-CPU dstate at %p", addr);
573 			return (-1);
574 		}
575 
576 		status->dtst_dyndrops += dcpu.dtdsc_drops;
577 		status->dtst_dyndrops_dirty += dcpu.dtdsc_dirty_drops;
578 		status->dtst_dyndrops_rinsing += dcpu.dtdsc_rinsing_drops;
579 
580 		addr = (uintptr_t)&state->dts_buffer[i];
581 
582 		if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
583 			mdb_warn("failed to read per-CPU buffer at %p", addr);
584 			return (-1);
585 		}
586 
587 		nerrs += buf.dtb_errors;
588 
589 		for (j = 0; j < state->dts_nspeculations; j++) {
590 			dtrace_speculation_t spec;
591 
592 			addr = (uintptr_t)&state->dts_speculations[j];
593 
594 			if (mdb_vread(&spec, sizeof (spec), addr) == -1) {
595 				mdb_warn("failed to read "
596 				    "speculation at %p", addr);
597 				return (-1);
598 			}
599 
600 			addr = (uintptr_t)&spec.dtsp_buffer[i];
601 
602 			if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
603 				mdb_warn("failed to read "
604 				    "speculative buffer at %p", addr);
605 				return (-1);
606 			}
607 
608 			status->dtst_specdrops += buf.dtb_xamot_drops;
609 		}
610 	}
611 
612 	status->dtst_specdrops_busy = state->dts_speculations_busy;
613 	status->dtst_specdrops_unavail = state->dts_speculations_unavail;
614 	status->dtst_errors = nerrs;
615 
616 	return (0);
617 }
618 
619 typedef struct dtracemdb_data {
620 	dtrace_state_t *dtmd_state;
621 	char *dtmd_symstr;
622 	char *dtmd_modstr;
623 	uintptr_t dtmd_addr;
624 } dtracemdb_data_t;
625 
626 static int
627 dtracemdb_ioctl(void *varg, int cmd, void *arg)
628 {
629 	dtracemdb_data_t *data = varg;
630 	dtrace_state_t *state = data->dtmd_state;
631 
632 	switch (cmd) {
633 	case DTRACEIOC_CONF: {
634 		dtrace_conf_t *conf = arg;
635 
636 		bzero(conf, sizeof (conf));
637 		conf->dtc_difversion = DIF_VERSION;
638 		conf->dtc_difintregs = DIF_DIR_NREGS;
639 		conf->dtc_diftupregs = DIF_DTR_NREGS;
640 		conf->dtc_ctfmodel = CTF_MODEL_NATIVE;
641 
642 		return (0);
643 	}
644 
645 	case DTRACEIOC_DOFGET: {
646 		dof_hdr_t *hdr = arg, *dof;
647 
648 		dof = dtracemdb_dof_create(state);
649 		bcopy(dof, hdr, MIN(hdr->dofh_loadsz, dof->dofh_loadsz));
650 		mdb_free(dof, dof->dofh_loadsz);
651 
652 		return (0);
653 	}
654 
655 	case DTRACEIOC_BUFSNAP:
656 		return (dtracemdb_bufsnap(state->dts_buffer, arg));
657 
658 	case DTRACEIOC_AGGSNAP:
659 		return (dtracemdb_bufsnap(state->dts_aggbuffer, arg));
660 
661 	case DTRACEIOC_AGGDESC:
662 		return (dtracemdb_aggdesc(state, arg));
663 
664 	case DTRACEIOC_EPROBE:
665 		return (dtracemdb_eprobe(state, arg));
666 
667 	case DTRACEIOC_PROBES:
668 		return (dtracemdb_probe(state, arg));
669 
670 	case DTRACEIOC_FORMAT:
671 		return (dtracemdb_format(state, arg));
672 
673 	case DTRACEIOC_STATUS:
674 		return (dtracemdb_status(state, arg));
675 
676 	case DTRACEIOC_GO:
677 		*(processorid_t *)arg = -1;
678 		return (0);
679 
680 	case DTRACEIOC_ENABLE:
681 		errno = ENOTTY; /* see dt_open.c:dtrace_go() */
682 		return (-1);
683 
684 	case DTRACEIOC_PROVIDER:
685 	case DTRACEIOC_PROBEMATCH:
686 		errno = ESRCH;
687 		return (-1);
688 
689 	default:
690 		mdb_warn("unexpected ioctl 0x%x (%s)\n", cmd,
691 		    cmd == DTRACEIOC_PROVIDER	? "DTRACEIOC_PROVIDER" :
692 		    cmd == DTRACEIOC_PROBES	? "DTRACEIOC_PROBES" :
693 		    cmd == DTRACEIOC_BUFSNAP	? "DTRACEIOC_BUFSNAP" :
694 		    cmd == DTRACEIOC_PROBEMATCH	? "DTRACEIOC_PROBEMATCH" :
695 		    cmd == DTRACEIOC_ENABLE	? "DTRACEIOC_ENABLE" :
696 		    cmd == DTRACEIOC_AGGSNAP	? "DTRACEIOC_AGGSNAP" :
697 		    cmd == DTRACEIOC_EPROBE	? "DTRACEIOC_EPROBE" :
698 		    cmd == DTRACEIOC_PROBEARG	? "DTRACEIOC_PROBEARG" :
699 		    cmd == DTRACEIOC_CONF	? "DTRACEIOC_CONF" :
700 		    cmd == DTRACEIOC_STATUS	? "DTRACEIOC_STATUS" :
701 		    cmd == DTRACEIOC_GO		? "DTRACEIOC_GO" :
702 		    cmd == DTRACEIOC_STOP	? "DTRACEIOC_STOP" :
703 		    cmd == DTRACEIOC_AGGDESC	? "DTRACEIOC_AGGDESC" :
704 		    cmd == DTRACEIOC_FORMAT	? "DTRACEIOC_FORMAT" :
705 		    cmd == DTRACEIOC_DOFGET	? "DTRACEIOC_DOFGET" :
706 		    cmd == DTRACEIOC_REPLICATE	? "DTRACEIOC_REPLICATE" :
707 		    "???");
708 		errno = ENXIO;
709 		return (-1);
710 	}
711 }
712 
713 static int
714 dtracemdb_modctl(uintptr_t addr, const struct modctl *m, dtracemdb_data_t *data)
715 {
716 	struct module mod;
717 
718 	if (m->mod_mp == NULL)
719 		return (WALK_NEXT);
720 
721 	if (mdb_vread(&mod, sizeof (mod), (uintptr_t)m->mod_mp) == -1) {
722 		mdb_warn("couldn't read modctl %p's module", addr);
723 		return (WALK_NEXT);
724 	}
725 
726 	if ((uintptr_t)mod.text > data->dtmd_addr)
727 		return (WALK_NEXT);
728 
729 	if ((uintptr_t)mod.text + mod.text_size <= data->dtmd_addr)
730 		return (WALK_NEXT);
731 
732 	if (mdb_readstr(data->dtmd_modstr, MDB_SYM_NAMLEN,
733 	    (uintptr_t)m->mod_modname) == -1)
734 		return (WALK_ERR);
735 
736 	return (WALK_DONE);
737 }
738 
739 static int
740 dtracemdb_lookup_by_addr(void *varg, GElf_Addr addr, GElf_Sym *symp,
741     dtrace_syminfo_t *sip)
742 {
743 	dtracemdb_data_t *data = varg;
744 
745 	if (data->dtmd_symstr == NULL) {
746 		data->dtmd_symstr = mdb_zalloc(MDB_SYM_NAMLEN,
747 		    UM_SLEEP | UM_GC);
748 	}
749 
750 	if (data->dtmd_modstr == NULL) {
751 		data->dtmd_modstr = mdb_zalloc(MDB_SYM_NAMLEN,
752 		    UM_SLEEP | UM_GC);
753 	}
754 
755 	if (symp != NULL) {
756 		if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY, data->dtmd_symstr,
757 		    MDB_SYM_NAMLEN, symp) == -1)
758 			return (-1);
759 	}
760 
761 	if (sip != NULL) {
762 		data->dtmd_addr = addr;
763 
764 		(void) strcpy(data->dtmd_modstr, "???");
765 
766 		if (mdb_walk("modctl",
767 		    (mdb_walk_cb_t)dtracemdb_modctl, varg) == -1) {
768 			mdb_warn("couldn't walk 'modctl'");
769 			return (-1);
770 		}
771 
772 		sip->dts_object = data->dtmd_modstr;
773 		sip->dts_id = 0;
774 		sip->dts_name = symp != NULL ? data->dtmd_symstr : NULL;
775 	}
776 
777 	return (0);
778 }
779 
780 /*ARGSUSED*/
781 static int
782 dtracemdb_stat(void *varg, processorid_t cpu)
783 {
784 	GElf_Sym sym;
785 	cpu_t c;
786 	uintptr_t caddr, addr;
787 
788 	if (mdb_lookup_by_name("cpu", &sym) == -1) {
789 		mdb_warn("failed to find symbol for 'cpu'");
790 		return (-1);
791 	}
792 
793 	if (cpu * sizeof (uintptr_t) > sym.st_size)
794 		return (-1);
795 
796 	addr = (uintptr_t)sym.st_value + cpu * sizeof (uintptr_t);
797 
798 	if (mdb_vread(&caddr, sizeof (caddr), addr) == -1) {
799 		mdb_warn("failed to read cpu[%d]", cpu);
800 		return (-1);
801 	}
802 
803 	if (caddr == NULL)
804 		return (-1);
805 
806 	if (mdb_vread(&c, sizeof (c), caddr) == -1) {
807 		mdb_warn("failed to read cpu at %p", caddr);
808 		return (-1);
809 	}
810 
811 	if (c.cpu_flags & CPU_POWEROFF) {
812 		return (P_POWEROFF);
813 	} else if (c.cpu_flags & CPU_SPARE) {
814 		return (P_SPARE);
815 	} else if (c.cpu_flags & CPU_FAULTED) {
816 		return (P_FAULTED);
817 	} else if ((c.cpu_flags & (CPU_READY | CPU_OFFLINE)) != CPU_READY) {
818 		return (P_OFFLINE);
819 	} else if (c.cpu_flags & CPU_ENABLE) {
820 		return (P_ONLINE);
821 	} else {
822 		return (P_NOINTR);
823 	}
824 }
825 
826 /*ARGSUSED*/
827 static long
828 dtracemdb_sysconf(void *varg, int name)
829 {
830 	int max_ncpus;
831 	processorid_t max_cpuid;
832 
833 	switch (name) {
834 	case _SC_CPUID_MAX:
835 		if (mdb_readvar(&max_cpuid, "max_cpuid") == -1) {
836 			mdb_warn("failed to read 'max_cpuid'");
837 			return (-1);
838 		}
839 
840 		return (max_cpuid);
841 
842 	case _SC_NPROCESSORS_MAX:
843 		if (mdb_readvar(&max_ncpus, "max_ncpus") == -1) {
844 			mdb_warn("failed to read 'max_ncpus'");
845 			return (-1);
846 		}
847 
848 		return (max_ncpus);
849 
850 	default:
851 		mdb_warn("unexpected sysconf code %d\n", name);
852 		return (-1);
853 	}
854 }
855 
856 const dtrace_vector_t dtrace_mdbops = {
857 	dtracemdb_ioctl,
858 	dtracemdb_lookup_by_addr,
859 	dtracemdb_stat,
860 	dtracemdb_sysconf
861 };
862 
863 typedef struct dtrace_dcmddata {
864 	dtrace_hdl_t *dtdd_dtp;
865 	int dtdd_cpu;
866 	int dtdd_quiet;
867 	int dtdd_flowindent;
868 	int dtdd_heading;
869 } dtrace_dcmddata_t;
870 
871 /*ARGSUSED*/
872 static int
873 dtrace_dcmdrec(const dtrace_probedata_t *data,
874     const dtrace_recdesc_t *rec, void *arg)
875 {
876 	dtrace_dcmddata_t *dd = arg;
877 
878 	if (rec == NULL) {
879 		/*
880 		 * We have processed the final record; output the newline if
881 		 * we're not in quiet mode.
882 		 */
883 		if (!dd->dtdd_quiet)
884 			mdb_printf("\n");
885 
886 		return (DTRACE_CONSUME_NEXT);
887 	}
888 
889 	return (DTRACE_CONSUME_THIS);
890 }
891 
892 /*ARGSUSED*/
893 static int
894 dtrace_dcmdprobe(const dtrace_probedata_t *data, void *arg)
895 {
896 	dtrace_probedesc_t *pd = data->dtpda_pdesc;
897 	processorid_t cpu = data->dtpda_cpu;
898 	dtrace_dcmddata_t *dd = arg;
899 	char name[DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 2];
900 
901 	if (dd->dtdd_cpu != -1UL && dd->dtdd_cpu != cpu)
902 		return (DTRACE_CONSUME_NEXT);
903 
904 	if (dd->dtdd_heading == 0) {
905 		if (!dd->dtdd_flowindent) {
906 			if (!dd->dtdd_quiet) {
907 				mdb_printf("%3s %6s %32s\n",
908 				    "CPU", "ID", "FUNCTION:NAME");
909 			}
910 		} else {
911 			mdb_printf("%3s %-41s\n", "CPU", "FUNCTION");
912 		}
913 		dd->dtdd_heading = 1;
914 	}
915 
916 	if (!dd->dtdd_flowindent) {
917 		if (!dd->dtdd_quiet) {
918 			(void) mdb_snprintf(name, sizeof (name), "%s:%s",
919 			    pd->dtpd_func, pd->dtpd_name);
920 
921 			mdb_printf("%3d %6d %32s ", cpu, pd->dtpd_id, name);
922 		}
923 	} else {
924 		int indent = data->dtpda_indent;
925 
926 		if (data->dtpda_flow == DTRACEFLOW_NONE) {
927 			(void) mdb_snprintf(name, sizeof (name), "%*s%s%s:%s",
928 			    indent, "", data->dtpda_prefix, pd->dtpd_func,
929 			    pd->dtpd_name);
930 		} else {
931 			(void) mdb_snprintf(name, sizeof (name), "%*s%s%s",
932 			    indent, "", data->dtpda_prefix, pd->dtpd_func);
933 		}
934 
935 		mdb_printf("%3d %-41s ", cpu, name);
936 	}
937 
938 	return (DTRACE_CONSUME_THIS);
939 }
940 
941 /*ARGSUSED*/
942 static int
943 dtrace_dcmderr(const dtrace_errdata_t *data, void *arg)
944 {
945 	mdb_warn(data->dteda_msg);
946 	return (DTRACE_HANDLE_OK);
947 }
948 
949 /*ARGSUSED*/
950 static int
951 dtrace_dcmddrop(const dtrace_dropdata_t *data, void *arg)
952 {
953 	mdb_warn(data->dtdda_msg);
954 	return (DTRACE_HANDLE_OK);
955 }
956 
957 /*ARGSUSED*/
958 static int
959 dtrace_dcmdbuffered(const dtrace_bufdata_t *bufdata, void *arg)
960 {
961 	mdb_printf("%s", bufdata->dtbda_buffered);
962 	return (DTRACE_HANDLE_OK);
963 }
964 
965 /*ARGSUSED*/
966 int
967 dtrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
968 {
969 	dtrace_state_t state;
970 	dtrace_hdl_t *dtp;
971 	int ncpu, err;
972 	uintptr_t c = -1UL;
973 	dtrace_dcmddata_t dd;
974 	dtrace_optval_t val;
975 	dtracemdb_data_t md;
976 	int rval = DCMD_ERR;
977 
978 	if (!(flags & DCMD_ADDRSPEC))
979 		return (DCMD_USAGE);
980 
981 	if (mdb_getopts(argc, argv, 'c', MDB_OPT_UINTPTR, &c, NULL) != argc)
982 		return (DCMD_USAGE);
983 
984 	if (mdb_readvar(&ncpu, "_ncpu") == -1) {
985 		mdb_warn("failed to read '_ncpu'");
986 		return (DCMD_ERR);
987 	}
988 
989 	if (mdb_vread(&state, sizeof (state), addr) == -1) {
990 		mdb_warn("couldn't read dtrace_state_t at %p", addr);
991 		return (DCMD_ERR);
992 	}
993 
994 	bzero(&md, sizeof (md));
995 	md.dtmd_state = &state;
996 
997 	if ((dtp = dtrace_vopen(DTRACE_VERSION, DTRACE_O_NOSYS, &err,
998 	    &dtrace_mdbops, &md)) == NULL) {
999 		mdb_warn("failed to initialize dtrace: %s\n",
1000 		    dtrace_errmsg(NULL, err));
1001 		return (DCMD_ERR);
1002 	}
1003 
1004 	if (dtrace_go(dtp) != 0) {
1005 		mdb_warn("failed to initialize dtrace: %s\n",
1006 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1007 		goto err;
1008 	}
1009 
1010 	bzero(&dd, sizeof (dd));
1011 	dd.dtdd_dtp = dtp;
1012 	dd.dtdd_cpu = c;
1013 
1014 	if (dtrace_getopt(dtp, "flowindent", &val) == -1) {
1015 		mdb_warn("couldn't get 'flowindent' option: %s\n",
1016 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1017 		goto err;
1018 	}
1019 
1020 	dd.dtdd_flowindent = (val != DTRACEOPT_UNSET);
1021 
1022 	if (dtrace_getopt(dtp, "quiet", &val) == -1) {
1023 		mdb_warn("couldn't get 'quiet' option: %s\n",
1024 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1025 		goto err;
1026 	}
1027 
1028 	dd.dtdd_quiet = (val != DTRACEOPT_UNSET);
1029 
1030 	if (dtrace_handle_err(dtp, dtrace_dcmderr, NULL) == -1) {
1031 		mdb_warn("couldn't add err handler: %s\n",
1032 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1033 		goto err;
1034 	}
1035 
1036 	if (dtrace_handle_drop(dtp, dtrace_dcmddrop, NULL) == -1) {
1037 		mdb_warn("couldn't add drop handler: %s\n",
1038 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1039 		goto err;
1040 	}
1041 
1042 	if (dtrace_handle_buffered(dtp, dtrace_dcmdbuffered, NULL) == -1) {
1043 		mdb_warn("couldn't add buffered handler: %s\n",
1044 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1045 		goto err;
1046 	}
1047 
1048 	if (dtrace_status(dtp) == -1) {
1049 		mdb_warn("couldn't get status: %s\n",
1050 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1051 		goto err;
1052 	}
1053 
1054 	if (dtrace_aggregate_snap(dtp) == -1) {
1055 		mdb_warn("couldn't snapshot aggregation: %s\n",
1056 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1057 		goto err;
1058 	}
1059 
1060 	if (dtrace_consume(dtp, NULL,
1061 	    dtrace_dcmdprobe, dtrace_dcmdrec, &dd) == -1) {
1062 		mdb_warn("couldn't consume DTrace buffers: %s\n",
1063 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1064 	}
1065 
1066 	if (dtrace_aggregate_print(dtp, NULL, NULL) == -1) {
1067 		mdb_warn("couldn't print aggregation: %s\n",
1068 		    dtrace_errmsg(dtp, dtrace_errno(dtp)));
1069 		goto err;
1070 	}
1071 
1072 	rval = DCMD_OK;
1073 err:
1074 	dtrace_close(dtp);
1075 	return (rval);
1076 }
1077 
1078 static int
1079 dtrace_errhash_cmp(const void *l, const void *r)
1080 {
1081 	uintptr_t lhs = *((uintptr_t *)l);
1082 	uintptr_t rhs = *((uintptr_t *)r);
1083 	dtrace_errhash_t lerr, rerr;
1084 	char lmsg[256], rmsg[256];
1085 
1086 	(void) mdb_vread(&lerr, sizeof (lerr), lhs);
1087 	(void) mdb_vread(&rerr, sizeof (rerr), rhs);
1088 
1089 	if (lerr.dter_msg == NULL)
1090 		return (-1);
1091 
1092 	if (rerr.dter_msg == NULL)
1093 		return (1);
1094 
1095 	(void) mdb_readstr(lmsg, sizeof (lmsg), (uintptr_t)lerr.dter_msg);
1096 	(void) mdb_readstr(rmsg, sizeof (rmsg), (uintptr_t)rerr.dter_msg);
1097 
1098 	return (strcmp(lmsg, rmsg));
1099 }
1100 
1101 int
1102 dtrace_errhash_init(mdb_walk_state_t *wsp)
1103 {
1104 	GElf_Sym sym;
1105 	uintptr_t *hash, addr;
1106 	int i;
1107 
1108 	if (wsp->walk_addr != NULL) {
1109 		mdb_warn("dtrace_errhash walk only supports global walks\n");
1110 		return (WALK_ERR);
1111 	}
1112 
1113 	if (mdb_lookup_by_name("dtrace_errhash", &sym) == -1) {
1114 		mdb_warn("couldn't find 'dtrace_errhash' (non-DEBUG kernel?)");
1115 		return (WALK_ERR);
1116 	}
1117 
1118 	addr = (uintptr_t)sym.st_value;
1119 	hash = mdb_alloc(DTRACE_ERRHASHSZ * sizeof (uintptr_t),
1120 	    UM_SLEEP | UM_GC);
1121 
1122 	for (i = 0; i < DTRACE_ERRHASHSZ; i++)
1123 		hash[i] = addr + i * sizeof (dtrace_errhash_t);
1124 
1125 	qsort(hash, DTRACE_ERRHASHSZ, sizeof (uintptr_t), dtrace_errhash_cmp);
1126 
1127 	wsp->walk_addr = 0;
1128 	wsp->walk_data = hash;
1129 
1130 	return (WALK_NEXT);
1131 }
1132 
1133 int
1134 dtrace_errhash_step(mdb_walk_state_t *wsp)
1135 {
1136 	int ndx = (int)wsp->walk_addr;
1137 	uintptr_t *hash = wsp->walk_data;
1138 	dtrace_errhash_t err;
1139 	uintptr_t addr;
1140 
1141 	if (ndx >= DTRACE_ERRHASHSZ)
1142 		return (WALK_DONE);
1143 
1144 	wsp->walk_addr = ndx + 1;
1145 	addr = hash[ndx];
1146 
1147 	if (mdb_vread(&err, sizeof (err), addr) == -1) {
1148 		mdb_warn("failed to read dtrace_errhash_t at %p", addr);
1149 		return (WALK_DONE);
1150 	}
1151 
1152 	if (err.dter_msg == NULL)
1153 		return (WALK_NEXT);
1154 
1155 	return (wsp->walk_callback(addr, &err, wsp->walk_cbdata));
1156 }
1157 
1158 /*ARGSUSED*/
1159 int
1160 dtrace_errhash(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1161 {
1162 	dtrace_errhash_t err;
1163 	char msg[256];
1164 
1165 	if (!(flags & DCMD_ADDRSPEC)) {
1166 		if (mdb_walk_dcmd("dtrace_errhash", "dtrace_errhash",
1167 		    argc, argv) == -1) {
1168 			mdb_warn("can't walk 'dtrace_errhash'");
1169 			return (DCMD_ERR);
1170 		}
1171 
1172 		return (DCMD_OK);
1173 	}
1174 
1175 	if (DCMD_HDRSPEC(flags))
1176 		mdb_printf("%8s %s\n", "COUNT", "ERROR");
1177 
1178 	if (mdb_vread(&err, sizeof (err), addr) == -1) {
1179 		mdb_warn("failed to read dtrace_errhash_t at %p", addr);
1180 		return (DCMD_ERR);
1181 	}
1182 
1183 	addr = (uintptr_t)err.dter_msg;
1184 
1185 	if (mdb_readstr(msg, sizeof (msg), addr) == -1) {
1186 		mdb_warn("failed to read error msg at %p", addr);
1187 		return (DCMD_ERR);
1188 	}
1189 
1190 	mdb_printf("%8d %s", err.dter_count, msg);
1191 
1192 	/*
1193 	 * Some error messages include a newline -- only print the newline
1194 	 * if the message doesn't have one.
1195 	 */
1196 	if (msg[strlen(msg) - 1] != '\n')
1197 		mdb_printf("\n");
1198 
1199 	return (DCMD_OK);
1200 }
1201 
1202 int
1203 dtrace_helptrace_init(mdb_walk_state_t *wsp)
1204 {
1205 	uint32_t next;
1206 	int enabled;
1207 
1208 	if (wsp->walk_addr != NULL) {
1209 		mdb_warn("dtrace_helptrace only supports global walks\n");
1210 		return (WALK_ERR);
1211 	}
1212 
1213 	if (mdb_readvar(&enabled, "dtrace_helptrace_enabled") == -1) {
1214 		mdb_warn("couldn't read 'dtrace_helptrace_enabled'");
1215 		return (WALK_ERR);
1216 	}
1217 
1218 	if (!enabled) {
1219 		mdb_warn("helper tracing is not enabled\n");
1220 		return (WALK_ERR);
1221 	}
1222 
1223 	if (mdb_readvar(&next, "dtrace_helptrace_next") == -1) {
1224 		mdb_warn("couldn't read 'dtrace_helptrace_next'");
1225 		return (WALK_ERR);
1226 	}
1227 
1228 	wsp->walk_addr = next;
1229 
1230 	return (WALK_NEXT);
1231 }
1232 
1233 int
1234 dtrace_helptrace_step(mdb_walk_state_t *wsp)
1235 {
1236 	uint32_t next, size, nlocals, bufsize;
1237 	uintptr_t buffer, addr;
1238 	dtrace_helptrace_t *ht;
1239 	int rval;
1240 
1241 	if (mdb_readvar(&next, "dtrace_helptrace_next") == -1) {
1242 		mdb_warn("couldn't read 'dtrace_helptrace_next'");
1243 		return (WALK_ERR);
1244 	}
1245 
1246 	if (mdb_readvar(&bufsize, "dtrace_helptrace_bufsize") == -1) {
1247 		mdb_warn("couldn't read 'dtrace_helptrace_bufsize'");
1248 		return (WALK_ERR);
1249 	}
1250 
1251 	if (mdb_readvar(&buffer, "dtrace_helptrace_buffer") == -1) {
1252 		mdb_warn("couldn't read 'dtrace_helptrace_buffer'");
1253 		return (WALK_ERR);
1254 	}
1255 
1256 	if (mdb_readvar(&nlocals, "dtrace_helptrace_nlocals") == -1) {
1257 		mdb_warn("couldn't read 'dtrace_helptrace_nlocals'");
1258 		return (WALK_ERR);
1259 	}
1260 
1261 	size = sizeof (dtrace_helptrace_t) +
1262 	    nlocals * sizeof (uint64_t) - sizeof (uint64_t);
1263 
1264 	if (wsp->walk_addr + size > bufsize) {
1265 		if (next == 0)
1266 			return (WALK_DONE);
1267 
1268 		wsp->walk_addr = 0;
1269 	}
1270 
1271 	addr = buffer + wsp->walk_addr;
1272 	ht = alloca(size);
1273 
1274 	if (mdb_vread(ht, size, addr) == -1) {
1275 		mdb_warn("couldn't read entry at %p", addr);
1276 		return (WALK_ERR);
1277 	}
1278 
1279 	if (ht->dtht_helper != NULL) {
1280 		rval = wsp->walk_callback(addr, ht, wsp->walk_cbdata);
1281 
1282 		if (rval != WALK_NEXT)
1283 			return (rval);
1284 	}
1285 
1286 	if (wsp->walk_addr < next && wsp->walk_addr + size >= next)
1287 		return (WALK_DONE);
1288 
1289 	wsp->walk_addr += size;
1290 	return (WALK_NEXT);
1291 }
1292 
1293 int
1294 dtrace_helptrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1295 {
1296 	dtrace_helptrace_t help;
1297 	dtrace_helper_action_t helper;
1298 	char where[30];
1299 	uint_t opt_v = FALSE;
1300 	uintptr_t haddr;
1301 
1302 	if (!(flags & DCMD_ADDRSPEC)) {
1303 		if (mdb_walk_dcmd("dtrace_helptrace", "dtrace_helptrace",
1304 		    argc, argv) == -1) {
1305 			mdb_warn("can't walk 'dtrace_helptrace'");
1306 			return (DCMD_ERR);
1307 		}
1308 
1309 		return (DCMD_OK);
1310 	}
1311 
1312 	if (mdb_getopts(argc, argv, 'v',
1313 	    MDB_OPT_SETBITS, TRUE, &opt_v, NULL) != argc)
1314 		return (DCMD_USAGE);
1315 
1316 	if (DCMD_HDRSPEC(flags)) {
1317 		mdb_printf(" %?s %?s %12s %s\n",
1318 		    "ADDR", "HELPER", "WHERE", "DIFO");
1319 	}
1320 
1321 	if (mdb_vread(&help, sizeof (help), addr) == -1) {
1322 		mdb_warn("failed to read dtrace_helptrace_t at %p", addr);
1323 		return (DCMD_ERR);
1324 	}
1325 
1326 	switch (help.dtht_where) {
1327 	case 0:
1328 		(void) mdb_snprintf(where, sizeof (where), "predicate");
1329 		break;
1330 
1331 	case DTRACE_HELPTRACE_NEXT:
1332 		(void) mdb_snprintf(where, sizeof (where), "next");
1333 		break;
1334 
1335 	case DTRACE_HELPTRACE_DONE:
1336 		(void) mdb_snprintf(where, sizeof (where), "done");
1337 		break;
1338 
1339 	case DTRACE_HELPTRACE_ERR:
1340 		(void) mdb_snprintf(where, sizeof (where), "err");
1341 		break;
1342 
1343 	default:
1344 		(void) mdb_snprintf(where, sizeof (where),
1345 		    "action #%d", help.dtht_where);
1346 		break;
1347 	}
1348 
1349 	mdb_printf(" %?p %?p %12s ", addr, help.dtht_helper, where);
1350 
1351 	haddr = (uintptr_t)help.dtht_helper;
1352 
1353 	if (mdb_vread(&helper, sizeof (helper), haddr) == -1) {
1354 		/*
1355 		 * We're not going to warn in this case -- we're just not going
1356 		 * to print anything exciting.
1357 		 */
1358 		mdb_printf("???\n");
1359 	} else {
1360 		switch (help.dtht_where) {
1361 		case 0:
1362 			mdb_printf("%p\n", helper.dtha_predicate);
1363 			break;
1364 
1365 		case DTRACE_HELPTRACE_NEXT:
1366 		case DTRACE_HELPTRACE_DONE:
1367 		case DTRACE_HELPTRACE_ERR:
1368 			mdb_printf("-\n");
1369 			break;
1370 
1371 		default:
1372 			haddr = (uintptr_t)helper.dtha_actions +
1373 			    (help.dtht_where - 1) * sizeof (uintptr_t);
1374 
1375 			if (mdb_vread(&haddr, sizeof (haddr), haddr) == -1) {
1376 				mdb_printf("???\n");
1377 			} else {
1378 				mdb_printf("%p\n", haddr);
1379 			}
1380 		}
1381 	}
1382 
1383 	if (opt_v) {
1384 		int i;
1385 
1386 		if (help.dtht_where == DTRACE_HELPTRACE_ERR) {
1387 			int f = help.dtht_fault;
1388 
1389 			mdb_printf("%?s| %?s %10s |\n", "", "", "");
1390 			mdb_printf("%?s| %?s %10s +->  fault: %s\n", "", "", "",
1391 			    f == DTRACEFLT_BADADDR ? "BADADDR" :
1392 			    f == DTRACEFLT_BADALIGN ? "BADALIGN" :
1393 			    f == DTRACEFLT_ILLOP ? "ILLOP" :
1394 			    f == DTRACEFLT_DIVZERO ? "DIVZERO" :
1395 			    f == DTRACEFLT_NOSCRATCH ? "NOSCRATCH" :
1396 			    f == DTRACEFLT_KPRIV ? "KPRIV" :
1397 			    f == DTRACEFLT_UPRIV ? "UPRIV" :
1398 			    f == DTRACEFLT_TUPOFLOW ? "TUPOFLOW" :
1399 			    f == DTRACEFLT_BADSTACK ? "BADSTACK" :
1400 			    "DTRACEFLT_UNKNOWN");
1401 			mdb_printf("%?s| %?s %12s     addr: 0x%x\n", "", "", "",
1402 			    help.dtht_illval);
1403 			mdb_printf("%?s| %?s %12s   offset: %d\n", "", "", "",
1404 			    help.dtht_fltoffs);
1405 		}
1406 
1407 		mdb_printf("%?s|\n%?s+--> %?s %4s %s\n", "", "",
1408 		    "ADDR", "NDX", "VALUE");
1409 		addr += sizeof (help) - sizeof (uint64_t);
1410 
1411 		for (i = 0; i < help.dtht_nlocals; i++) {
1412 			uint64_t val;
1413 
1414 			if (mdb_vread(&val, sizeof (val), addr) == -1) {
1415 				mdb_warn("couldn't read local at %p", addr);
1416 				continue;
1417 			}
1418 
1419 			mdb_printf("%?s     %?p %4d %p\n", "", addr, i, val);
1420 			addr += sizeof (uint64_t);
1421 		}
1422 
1423 		mdb_printf("\n");
1424 	}
1425 
1426 	return (DCMD_OK);
1427 }
1428 
1429 /*ARGSUSED*/
1430 static int
1431 dtrace_state_walk(uintptr_t addr, const vmem_seg_t *seg, minor_t *highest)
1432 {
1433 	if (seg->vs_end > *highest)
1434 		*highest = seg->vs_end;
1435 
1436 	return (WALK_NEXT);
1437 }
1438 
1439 typedef struct dtrace_state_walk {
1440 	uintptr_t dtsw_softstate;
1441 	minor_t dtsw_max;
1442 	minor_t dtsw_current;
1443 } dtrace_state_walk_t;
1444 
1445 int
1446 dtrace_state_init(mdb_walk_state_t *wsp)
1447 {
1448 	uintptr_t dtrace_minor;
1449 	minor_t max = 0;
1450 	dtrace_state_walk_t *dw;
1451 
1452 	if (wsp->walk_addr != NULL) {
1453 		mdb_warn("dtrace_state only supports global walks\n");
1454 		return (WALK_ERR);
1455 	}
1456 
1457 	/*
1458 	 * Find the dtrace_minor vmem arena and walk it to get the maximum
1459 	 * minor number.
1460 	 */
1461 	if (mdb_readvar(&dtrace_minor, "dtrace_minor") == -1) {
1462 		mdb_warn("failed to read 'dtrace_minor'");
1463 		return (WALK_ERR);
1464 	}
1465 
1466 	if (mdb_pwalk("vmem_alloc", (mdb_walk_cb_t)dtrace_state_walk,
1467 	    &max, dtrace_minor) == -1) {
1468 		mdb_warn("couldn't walk 'vmem_alloc'");
1469 		return (WALK_ERR);
1470 	}
1471 
1472 	dw = mdb_zalloc(sizeof (dtrace_state_walk_t), UM_SLEEP | UM_GC);
1473 	dw->dtsw_current = 0;
1474 	dw->dtsw_max = max;
1475 
1476 	if (mdb_readvar(&dw->dtsw_softstate, "dtrace_softstate") == -1) {
1477 		mdb_warn("failed to read 'dtrace_softstate'");
1478 		return (DCMD_ERR);
1479 	}
1480 
1481 	wsp->walk_data = dw;
1482 
1483 	return (WALK_NEXT);
1484 }
1485 
1486 int
1487 dtrace_state_step(mdb_walk_state_t *wsp)
1488 {
1489 	dtrace_state_walk_t *dw = wsp->walk_data;
1490 	uintptr_t statep;
1491 	dtrace_state_t state;
1492 	int rval;
1493 
1494 	while (mdb_get_soft_state_byaddr(dw->dtsw_softstate, dw->dtsw_current,
1495 	    &statep, NULL, 0) == -1) {
1496 		if (dw->dtsw_current >= dw->dtsw_max)
1497 			return (WALK_DONE);
1498 
1499 		dw->dtsw_current++;
1500 	}
1501 
1502 	if (mdb_vread(&state, sizeof (state), statep) == -1) {
1503 		mdb_warn("couldn't read dtrace_state_t at %p", statep);
1504 		return (WALK_NEXT);
1505 	}
1506 
1507 	rval = wsp->walk_callback(statep, &state, wsp->walk_cbdata);
1508 	dw->dtsw_current++;
1509 
1510 	return (rval);
1511 }
1512 
1513 typedef struct dtrace_state_data {
1514 	int dtsd_major;
1515 	uintptr_t dtsd_proc;
1516 	uintptr_t dtsd_softstate;
1517 	uintptr_t dtsd_state;
1518 } dtrace_state_data_t;
1519 
1520 static int
1521 dtrace_state_file(uintptr_t addr, struct file *f, dtrace_state_data_t *data)
1522 {
1523 	vnode_t vnode;
1524 	proc_t proc;
1525 	minor_t minor;
1526 	uintptr_t statep;
1527 
1528 	if (mdb_vread(&vnode, sizeof (vnode), (uintptr_t)f->f_vnode) == -1) {
1529 		mdb_warn("couldn't read vnode at %p", (uintptr_t)f->f_vnode);
1530 		return (WALK_NEXT);
1531 	}
1532 
1533 	if (getmajor(vnode.v_rdev) != data->dtsd_major)
1534 		return (WALK_NEXT);
1535 
1536 	minor = getminor(vnode.v_rdev);
1537 
1538 	if (mdb_vread(&proc, sizeof (proc), data->dtsd_proc) == -1) {
1539 		mdb_warn("failed to read proc at %p", data->dtsd_proc);
1540 		return (WALK_NEXT);
1541 	}
1542 
1543 	if (mdb_get_soft_state_byaddr(data->dtsd_softstate, minor,
1544 	    &statep, NULL, 0) == -1) {
1545 		mdb_warn("failed to read softstate for minor %d", minor);
1546 		return (WALK_NEXT);
1547 	}
1548 
1549 	if (statep != data->dtsd_state)
1550 		return (WALK_NEXT);
1551 
1552 	mdb_printf("%?p %5d %?p %-*s %?p\n", statep, minor,
1553 	    data->dtsd_proc, MAXCOMLEN, proc.p_user.u_comm, addr);
1554 
1555 	return (WALK_NEXT);
1556 }
1557 
1558 /*ARGSUSED*/
1559 static int
1560 dtrace_state_proc(uintptr_t addr, void *ignored, dtrace_state_data_t *data)
1561 {
1562 	data->dtsd_proc = addr;
1563 
1564 	if (mdb_pwalk("file",
1565 	    (mdb_walk_cb_t)dtrace_state_file, data, addr) == -1) {
1566 		mdb_warn("couldn't walk 'file' for proc %p", addr);
1567 		return (WALK_ERR);
1568 	}
1569 
1570 	return (WALK_NEXT);
1571 }
1572 
1573 void
1574 dtrace_state_help(void)
1575 {
1576 	mdb_printf("Given a dtrace_state_t structure, displays all "
1577 	    /*CSTYLED*/
1578 	    "consumers, or \"<anonymous>\"\nif the consumer is anonymous.  If "
1579 	    "no state structure is provided, iterates\nover all state "
1580 	    "structures.\n\n"
1581 	    "Addresses in ADDR column may be provided to ::dtrace to obtain\n"
1582 	    "dtrace(1M)-like output for in-kernel DTrace data.\n");
1583 }
1584 
1585 int
1586 dtrace_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1587 {
1588 	uintptr_t devi;
1589 	struct dev_info info;
1590 	dtrace_state_data_t data;
1591 	dtrace_anon_t anon;
1592 	dtrace_state_t state;
1593 
1594 	if (!(flags & DCMD_ADDRSPEC)) {
1595 		if (mdb_walk_dcmd("dtrace_state",
1596 		    "dtrace_state", argc, argv) == -1) {
1597 			mdb_warn("can't walk dtrace_state");
1598 			return (DCMD_ERR);
1599 		}
1600 		return (DCMD_OK);
1601 	}
1602 
1603 	if (DCMD_HDRSPEC(flags)) {
1604 		mdb_printf("%?s %5s %?s %-*s %?s\n", "ADDR", "MINOR", "PROC",
1605 		    MAXCOMLEN, "NAME", "FILE");
1606 	}
1607 
1608 	/*
1609 	 * First determine if this is anonymous state.
1610 	 */
1611 	if (mdb_readvar(&anon, "dtrace_anon") == -1) {
1612 		mdb_warn("failed to read 'dtrace_anon'");
1613 		return (DCMD_ERR);
1614 	}
1615 
1616 	if ((uintptr_t)anon.dta_state == addr) {
1617 		if (mdb_vread(&state, sizeof (state), addr) == -1) {
1618 			mdb_warn("failed to read anon at %p", addr);
1619 			return (DCMD_ERR);
1620 		}
1621 
1622 		mdb_printf("%?p %5d %?s %-*s %?s\n", addr,
1623 		    getminor(state.dts_dev), "-", MAXCOMLEN,
1624 		    "<anonymous>", "-");
1625 
1626 		return (DCMD_OK);
1627 	}
1628 
1629 	if (mdb_readvar(&devi, "dtrace_devi") == -1) {
1630 		mdb_warn("failed to read 'dtrace_devi'");
1631 		return (DCMD_ERR);
1632 	}
1633 
1634 	if (mdb_vread(&info, sizeof (struct dev_info), devi) == -1) {
1635 		mdb_warn("failed to read 'dev_info'");
1636 		return (DCMD_ERR);
1637 	}
1638 
1639 	data.dtsd_major = info.devi_major;
1640 
1641 	if (mdb_readvar(&data.dtsd_softstate, "dtrace_softstate") == -1) {
1642 		mdb_warn("failed to read 'dtrace_softstate'");
1643 		return (DCMD_ERR);
1644 	}
1645 
1646 	data.dtsd_state = addr;
1647 
1648 	/*
1649 	 * Walk through all processes and all open files looking for this
1650 	 * state.  It must be open somewhere...
1651 	 */
1652 	if (mdb_walk("proc", (mdb_walk_cb_t)dtrace_state_proc, &data) == -1) {
1653 		mdb_warn("couldn't walk 'proc'");
1654 		return (DCMD_ERR);
1655 	}
1656 
1657 	return (DCMD_OK);
1658 }
1659 
1660 typedef struct dtrace_aggkey_data {
1661 	uintptr_t *dtakd_hash;
1662 	uintptr_t dtakd_hashsize;
1663 	uintptr_t dtakd_next;
1664 	uintptr_t dtakd_ndx;
1665 } dtrace_aggkey_data_t;
1666 
1667 int
1668 dtrace_aggkey_init(mdb_walk_state_t *wsp)
1669 {
1670 	dtrace_buffer_t buf;
1671 	uintptr_t addr;
1672 	dtrace_aggbuffer_t agb;
1673 	dtrace_aggkey_data_t *data;
1674 	size_t hsize;
1675 
1676 	if ((addr = wsp->walk_addr) == NULL) {
1677 		mdb_warn("dtrace_aggkey walk needs aggregation buffer\n");
1678 		return (WALK_ERR);
1679 	}
1680 
1681 	if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
1682 		mdb_warn("failed to read aggregation buffer at %p", addr);
1683 		return (WALK_ERR);
1684 	}
1685 
1686 	addr = (uintptr_t)buf.dtb_tomax +
1687 	    buf.dtb_size - sizeof (dtrace_aggbuffer_t);
1688 
1689 	if (mdb_vread(&agb, sizeof (agb), addr) == -1) {
1690 		mdb_warn("failed to read dtrace_aggbuffer_t at %p", addr);
1691 		return (WALK_ERR);
1692 	}
1693 
1694 	data = mdb_zalloc(sizeof (dtrace_aggkey_data_t), UM_SLEEP);
1695 
1696 	data->dtakd_hashsize = agb.dtagb_hashsize;
1697 	hsize = agb.dtagb_hashsize * sizeof (dtrace_aggkey_t *);
1698 	data->dtakd_hash = mdb_alloc(hsize, UM_SLEEP);
1699 
1700 	if (mdb_vread(data->dtakd_hash, hsize,
1701 	    (uintptr_t)agb.dtagb_hash) == -1) {
1702 		mdb_warn("failed to read hash at %p",
1703 		    (uintptr_t)agb.dtagb_hash);
1704 		mdb_free(data->dtakd_hash, hsize);
1705 		mdb_free(data, sizeof (dtrace_aggkey_data_t));
1706 		return (WALK_ERR);
1707 	}
1708 
1709 	wsp->walk_data = data;
1710 	return (WALK_NEXT);
1711 }
1712 
1713 int
1714 dtrace_aggkey_step(mdb_walk_state_t *wsp)
1715 {
1716 	dtrace_aggkey_data_t *data = wsp->walk_data;
1717 	dtrace_aggkey_t key;
1718 	uintptr_t addr;
1719 
1720 	while ((addr = data->dtakd_next) == NULL) {
1721 		if (data->dtakd_ndx == data->dtakd_hashsize)
1722 			return (WALK_DONE);
1723 
1724 		data->dtakd_next = data->dtakd_hash[data->dtakd_ndx++];
1725 	}
1726 
1727 	if (mdb_vread(&key, sizeof (key), addr) == -1) {
1728 		mdb_warn("failed to read dtrace_aggkey_t at %p", addr);
1729 		return (WALK_ERR);
1730 	}
1731 
1732 	data->dtakd_next = (uintptr_t)key.dtak_next;
1733 
1734 	return (wsp->walk_callback(addr, &key, wsp->walk_cbdata));
1735 }
1736 
1737 void
1738 dtrace_aggkey_fini(mdb_walk_state_t *wsp)
1739 {
1740 	dtrace_aggkey_data_t *data = wsp->walk_data;
1741 	size_t hsize;
1742 
1743 	hsize = data->dtakd_hashsize * sizeof (dtrace_aggkey_t *);
1744 	mdb_free(data->dtakd_hash, hsize);
1745 	mdb_free(data, sizeof (dtrace_aggkey_data_t));
1746 }
1747 
1748 typedef struct dtrace_dynvar_data {
1749 	dtrace_dynhash_t *dtdvd_hash;
1750 	uintptr_t dtdvd_hashsize;
1751 	uintptr_t dtdvd_next;
1752 	uintptr_t dtdvd_ndx;
1753 } dtrace_dynvar_data_t;
1754 
1755 int
1756 dtrace_dynvar_init(mdb_walk_state_t *wsp)
1757 {
1758 	uintptr_t addr;
1759 	dtrace_dstate_t dstate;
1760 	dtrace_dynvar_data_t *data;
1761 	size_t hsize;
1762 
1763 	if ((addr = wsp->walk_addr) == NULL) {
1764 		mdb_warn("dtrace_dynvar walk needs dtrace_dstate_t\n");
1765 		return (WALK_ERR);
1766 	}
1767 
1768 	if (mdb_vread(&dstate, sizeof (dstate), addr) == -1) {
1769 		mdb_warn("failed to read dynamic state at %p", addr);
1770 		return (WALK_ERR);
1771 	}
1772 
1773 	data = mdb_zalloc(sizeof (dtrace_dynvar_data_t), UM_SLEEP);
1774 
1775 	data->dtdvd_hashsize = dstate.dtds_hashsize;
1776 	hsize = dstate.dtds_hashsize * sizeof (dtrace_dynhash_t);
1777 	data->dtdvd_hash = mdb_alloc(hsize, UM_SLEEP);
1778 
1779 	if (mdb_vread(data->dtdvd_hash, hsize,
1780 	    (uintptr_t)dstate.dtds_hash) == -1) {
1781 		mdb_warn("failed to read hash at %p",
1782 		    (uintptr_t)dstate.dtds_hash);
1783 		mdb_free(data->dtdvd_hash, hsize);
1784 		mdb_free(data, sizeof (dtrace_dynvar_data_t));
1785 		return (WALK_ERR);
1786 	}
1787 
1788 	wsp->walk_data = data;
1789 	return (WALK_NEXT);
1790 }
1791 
1792 int
1793 dtrace_dynvar_step(mdb_walk_state_t *wsp)
1794 {
1795 	dtrace_dynvar_data_t *data = wsp->walk_data;
1796 	dtrace_dynvar_t dynvar, *dvar;
1797 	size_t dvarsize;
1798 	uintptr_t addr;
1799 	int nkeys;
1800 
1801 	while ((addr = data->dtdvd_next) == NULL) {
1802 		if (data->dtdvd_ndx == data->dtdvd_hashsize)
1803 			return (WALK_DONE);
1804 
1805 		data->dtdvd_next =
1806 		    (uintptr_t)data->dtdvd_hash[data->dtdvd_ndx++].dtdh_chain;
1807 	}
1808 
1809 	if (mdb_vread(&dynvar, sizeof (dynvar), addr) == -1) {
1810 		mdb_warn("failed to read dtrace_dynvar_t at %p", addr);
1811 		return (WALK_ERR);
1812 	}
1813 
1814 	/*
1815 	 * Now we need to allocate the correct size.
1816 	 */
1817 	nkeys = dynvar.dtdv_tuple.dtt_nkeys;
1818 	dvarsize = (uintptr_t)&dynvar.dtdv_tuple.dtt_key[nkeys] -
1819 	    (uintptr_t)&dynvar;
1820 
1821 	dvar = alloca(dvarsize);
1822 
1823 	if (mdb_vread(dvar, dvarsize, addr) == -1) {
1824 		mdb_warn("failed to read dtrace_dynvar_t at %p", addr);
1825 		return (WALK_ERR);
1826 	}
1827 
1828 	data->dtdvd_next = (uintptr_t)dynvar.dtdv_next;
1829 
1830 	return (wsp->walk_callback(addr, dvar, wsp->walk_cbdata));
1831 }
1832 
1833 void
1834 dtrace_dynvar_fini(mdb_walk_state_t *wsp)
1835 {
1836 	dtrace_dynvar_data_t *data = wsp->walk_data;
1837 	size_t hsize;
1838 
1839 	hsize = data->dtdvd_hashsize * sizeof (dtrace_dynvar_t *);
1840 	mdb_free(data->dtdvd_hash, hsize);
1841 	mdb_free(data, sizeof (dtrace_dynvar_data_t));
1842 }
1843 
1844 typedef struct dtrace_hashstat_data {
1845 	size_t *dthsd_counts;
1846 	size_t dthsd_hashsize;
1847 	char *dthsd_data;
1848 	size_t dthsd_size;
1849 	int dthsd_header;
1850 } dtrace_hashstat_data_t;
1851 
1852 typedef void (*dtrace_hashstat_func_t)(dtrace_hashstat_data_t *);
1853 
1854 static void
1855 dtrace_hashstat_additive(dtrace_hashstat_data_t *data)
1856 {
1857 	int i;
1858 	int hval = 0;
1859 
1860 	for (i = 0; i < data->dthsd_size; i++)
1861 		hval += data->dthsd_data[i];
1862 
1863 	data->dthsd_counts[hval % data->dthsd_hashsize]++;
1864 }
1865 
1866 static void
1867 dtrace_hashstat_shifty(dtrace_hashstat_data_t *data)
1868 {
1869 	uint64_t hval = 0;
1870 	int i;
1871 
1872 	if (data->dthsd_size < sizeof (uint64_t)) {
1873 		dtrace_hashstat_additive(data);
1874 		return;
1875 	}
1876 
1877 	for (i = 0; i < data->dthsd_size; i += sizeof (uint64_t)) {
1878 		/* LINTED - alignment */
1879 		uint64_t val = *((uint64_t *)&data->dthsd_data[i]);
1880 
1881 		hval += (val & ((1 << NBBY) - 1)) +
1882 		    ((val >> NBBY) & ((1 << NBBY) - 1)) +
1883 		    ((val >> (NBBY << 1)) & ((1 << NBBY) - 1)) +
1884 		    ((val >> (NBBY << 2)) & ((1 << NBBY) - 1)) +
1885 		    (val & USHRT_MAX) + (val >> (NBBY << 1) & USHRT_MAX);
1886 	}
1887 
1888 	data->dthsd_counts[hval % data->dthsd_hashsize]++;
1889 }
1890 
1891 static void
1892 dtrace_hashstat_knuth(dtrace_hashstat_data_t *data)
1893 {
1894 	int i;
1895 	int hval = data->dthsd_size;
1896 
1897 	for (i = 0; i < data->dthsd_size; i++)
1898 		hval = (hval << 4) ^ (hval >> 28) ^ data->dthsd_data[i];
1899 
1900 	data->dthsd_counts[hval % data->dthsd_hashsize]++;
1901 }
1902 
1903 static void
1904 dtrace_hashstat_oneatatime(dtrace_hashstat_data_t *data)
1905 {
1906 	int i;
1907 	uint32_t hval = 0;
1908 
1909 	for (i = 0; i < data->dthsd_size; i++) {
1910 		hval += data->dthsd_data[i];
1911 		hval += (hval << 10);
1912 		hval ^= (hval >> 6);
1913 	}
1914 
1915 	hval += (hval << 3);
1916 	hval ^= (hval >> 11);
1917 	hval += (hval << 15);
1918 
1919 	data->dthsd_counts[hval % data->dthsd_hashsize]++;
1920 }
1921 
1922 static void
1923 dtrace_hashstat_fnv(dtrace_hashstat_data_t *data)
1924 {
1925 	static const uint32_t prime = 0x01000193;
1926 	uint32_t hval = 0;
1927 	int i;
1928 
1929 	for (i = 0; i < data->dthsd_size; i++) {
1930 		hval *= prime;
1931 		hval ^= data->dthsd_data[i];
1932 	}
1933 
1934 	data->dthsd_counts[hval % data->dthsd_hashsize]++;
1935 }
1936 
1937 static void
1938 dtrace_hashstat_stats(char *name, dtrace_hashstat_data_t *data)
1939 {
1940 	size_t nz = 0, i;
1941 	int longest = 0;
1942 	size_t ttl = 0;
1943 	double sum = 0.0;
1944 	double avg;
1945 	uint_t util, stddev;
1946 
1947 	if (!data->dthsd_header) {
1948 		mdb_printf("%15s %11s %11s %11s %11s %11s\n", "NAME",
1949 		    "HASHSIZE", "%UTIL", "LONGEST", "AVERAGE", "STDDEV");
1950 		data->dthsd_header = 1;
1951 	}
1952 
1953 	for (i = 0; i < data->dthsd_hashsize; i++) {
1954 		if (data->dthsd_counts[i] != 0) {
1955 			nz++;
1956 
1957 			if (data->dthsd_counts[i] > longest)
1958 				longest = data->dthsd_counts[i];
1959 
1960 			ttl += data->dthsd_counts[i];
1961 		}
1962 	}
1963 
1964 	if (nz == 0) {
1965 		mdb_printf("%15s %11d %11s %11s %11s %11s\n", name,
1966 		    data->dthsd_hashsize, "-", "-", "-", "-");
1967 		return;
1968 	}
1969 
1970 	avg = (double)ttl / (double)nz;
1971 
1972 	for (i = 0; i < data->dthsd_hashsize; i++) {
1973 		double delta = (double)data->dthsd_counts[i] - avg;
1974 
1975 		if (data->dthsd_counts[i] == 0)
1976 			continue;
1977 
1978 		sum += delta * delta;
1979 	}
1980 
1981 	util = (nz * 1000) / data->dthsd_hashsize;
1982 	stddev = (uint_t)sqrt(sum / (double)nz) * 10;
1983 
1984 	mdb_printf("%15s %11d %9u.%1u %11d %11d %9u.%1u\n", name,
1985 	    data->dthsd_hashsize, util / 10, util % 10, longest, ttl / nz,
1986 	    stddev / 10, stddev % 10);
1987 }
1988 
1989 static struct dtrace_hashstat {
1990 	char *dths_name;
1991 	dtrace_hashstat_func_t dths_func;
1992 } _dtrace_hashstat[] = {
1993 	{ "<actual>", NULL },
1994 	{ "additive", dtrace_hashstat_additive },
1995 	{ "shifty", dtrace_hashstat_shifty },
1996 	{ "knuth", dtrace_hashstat_knuth },
1997 	{ "one-at-a-time", dtrace_hashstat_oneatatime },
1998 	{ "fnv", dtrace_hashstat_fnv },
1999 	{ NULL, 0 }
2000 };
2001 
2002 typedef struct dtrace_aggstat_data {
2003 	dtrace_hashstat_data_t dtagsd_hash;
2004 	dtrace_hashstat_func_t dtagsd_func;
2005 } dtrace_aggstat_data_t;
2006 
2007 static int
2008 dtrace_aggstat_walk(uintptr_t addr, dtrace_aggkey_t *key,
2009     dtrace_aggstat_data_t *data)
2010 {
2011 	dtrace_hashstat_data_t *hdata = &data->dtagsd_hash;
2012 	size_t size;
2013 
2014 	if (data->dtagsd_func == NULL) {
2015 		size_t bucket = key->dtak_hashval % hdata->dthsd_hashsize;
2016 
2017 		hdata->dthsd_counts[bucket]++;
2018 		return (WALK_NEXT);
2019 	}
2020 
2021 	/*
2022 	 * We need to read the data.
2023 	 */
2024 	size = key->dtak_size - sizeof (dtrace_aggid_t);
2025 	addr = (uintptr_t)key->dtak_data + sizeof (dtrace_aggid_t);
2026 	hdata->dthsd_data = alloca(size);
2027 	hdata->dthsd_size = size;
2028 
2029 	if (mdb_vread(hdata->dthsd_data, size, addr) == -1) {
2030 		mdb_warn("couldn't read data at %p", addr);
2031 		return (WALK_ERR);
2032 	}
2033 
2034 	data->dtagsd_func(hdata);
2035 
2036 	return (WALK_NEXT);
2037 }
2038 
2039 /*ARGSUSED*/
2040 int
2041 dtrace_aggstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2042 {
2043 	dtrace_buffer_t buf;
2044 	uintptr_t aaddr;
2045 	dtrace_aggbuffer_t agb;
2046 	size_t hsize, i, actual, prime, evenpow;
2047 	dtrace_aggstat_data_t data;
2048 	dtrace_hashstat_data_t *hdata = &data.dtagsd_hash;
2049 
2050 	bzero(&data, sizeof (data));
2051 
2052 	if (!(flags & DCMD_ADDRSPEC))
2053 		return (DCMD_USAGE);
2054 
2055 	if (mdb_vread(&buf, sizeof (buf), addr) == -1) {
2056 		mdb_warn("failed to read aggregation buffer at %p", addr);
2057 		return (DCMD_ERR);
2058 	}
2059 
2060 	aaddr = (uintptr_t)buf.dtb_tomax +
2061 	    buf.dtb_size - sizeof (dtrace_aggbuffer_t);
2062 
2063 	if (mdb_vread(&agb, sizeof (agb), aaddr) == -1) {
2064 		mdb_warn("failed to read dtrace_aggbuffer_t at %p", aaddr);
2065 		return (DCMD_ERR);
2066 	}
2067 
2068 	hsize = (actual = agb.dtagb_hashsize) * sizeof (size_t);
2069 	hdata->dthsd_counts = mdb_alloc(hsize, UM_SLEEP | UM_GC);
2070 
2071 	/*
2072 	 * Now pick the largest prime smaller than the hash size.  (If the
2073 	 * existing size is prime, we'll pick a smaller prime just for the
2074 	 * hell of it.)
2075 	 */
2076 	for (prime = agb.dtagb_hashsize - 1; prime > 7; prime--) {
2077 		size_t limit = prime / 7;
2078 
2079 		for (i = 2; i < limit; i++) {
2080 			if ((prime % i) == 0)
2081 				break;
2082 		}
2083 
2084 		if (i == limit)
2085 			break;
2086 	}
2087 
2088 	/*
2089 	 * And now we want to pick the largest power of two smaller than the
2090 	 * hashsize.
2091 	 */
2092 	for (i = 0; (1 << i) < agb.dtagb_hashsize; i++)
2093 		continue;
2094 
2095 	evenpow = (1 << (i - 1));
2096 
2097 	for (i = 0; _dtrace_hashstat[i].dths_name != NULL; i++) {
2098 		data.dtagsd_func = _dtrace_hashstat[i].dths_func;
2099 
2100 		hdata->dthsd_hashsize = actual;
2101 		hsize = hdata->dthsd_hashsize * sizeof (size_t);
2102 		bzero(hdata->dthsd_counts, hsize);
2103 
2104 		if (mdb_pwalk("dtrace_aggkey",
2105 		    (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) {
2106 			mdb_warn("failed to walk dtrace_aggkey at %p", addr);
2107 			return (DCMD_ERR);
2108 		}
2109 
2110 		dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2111 
2112 		/*
2113 		 * If we were just printing the actual value, we won't try
2114 		 * any of the sizing experiments.
2115 		 */
2116 		if (data.dtagsd_func == NULL)
2117 			continue;
2118 
2119 		hdata->dthsd_hashsize = prime;
2120 		hsize = hdata->dthsd_hashsize * sizeof (size_t);
2121 		bzero(hdata->dthsd_counts, hsize);
2122 
2123 		if (mdb_pwalk("dtrace_aggkey",
2124 		    (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) {
2125 			mdb_warn("failed to walk dtrace_aggkey at %p", addr);
2126 			return (DCMD_ERR);
2127 		}
2128 
2129 		dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2130 
2131 		hdata->dthsd_hashsize = evenpow;
2132 		hsize = hdata->dthsd_hashsize * sizeof (size_t);
2133 		bzero(hdata->dthsd_counts, hsize);
2134 
2135 		if (mdb_pwalk("dtrace_aggkey",
2136 		    (mdb_walk_cb_t)dtrace_aggstat_walk, &data, addr) == -1) {
2137 			mdb_warn("failed to walk dtrace_aggkey at %p", addr);
2138 			return (DCMD_ERR);
2139 		}
2140 
2141 		dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2142 	}
2143 
2144 	return (DCMD_OK);
2145 }
2146 
2147 /*ARGSUSED*/
2148 static int
2149 dtrace_dynstat_walk(uintptr_t addr, dtrace_dynvar_t *dynvar,
2150     dtrace_aggstat_data_t *data)
2151 {
2152 	dtrace_hashstat_data_t *hdata = &data->dtagsd_hash;
2153 	dtrace_tuple_t *tuple = &dynvar->dtdv_tuple;
2154 	dtrace_key_t *key = tuple->dtt_key;
2155 	size_t size = 0, offs = 0;
2156 	int i, nkeys = tuple->dtt_nkeys;
2157 	char *buf;
2158 
2159 	if (data->dtagsd_func == NULL) {
2160 		size_t bucket = dynvar->dtdv_hashval % hdata->dthsd_hashsize;
2161 
2162 		hdata->dthsd_counts[bucket]++;
2163 		return (WALK_NEXT);
2164 	}
2165 
2166 	/*
2167 	 * We want to hand the hashing algorithm a contiguous buffer.  First
2168 	 * run through the tuple and determine the size.
2169 	 */
2170 	for (i = 0; i < nkeys; i++) {
2171 		if (key[i].dttk_size == 0) {
2172 			size += sizeof (uint64_t);
2173 		} else {
2174 			size += key[i].dttk_size;
2175 		}
2176 	}
2177 
2178 	buf = alloca(size);
2179 
2180 	/*
2181 	 * Now go back through the tuple and copy the data into the buffer.
2182 	 */
2183 	for (i = 0; i < nkeys; i++) {
2184 		if (key[i].dttk_size == 0) {
2185 			bcopy(&key[i].dttk_value, &buf[offs],
2186 			    sizeof (uint64_t));
2187 			offs += sizeof (uint64_t);
2188 		} else {
2189 			if (mdb_vread(&buf[offs], key[i].dttk_size,
2190 			    key[i].dttk_value) == -1) {
2191 				mdb_warn("couldn't read tuple data at %p",
2192 				    key[i].dttk_value);
2193 				return (WALK_ERR);
2194 			}
2195 
2196 			offs += key[i].dttk_size;
2197 		}
2198 	}
2199 
2200 	hdata->dthsd_data = buf;
2201 	hdata->dthsd_size = size;
2202 
2203 	data->dtagsd_func(hdata);
2204 
2205 	return (WALK_NEXT);
2206 }
2207 
2208 /*ARGSUSED*/
2209 int
2210 dtrace_dynstat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2211 {
2212 	dtrace_dstate_t dstate;
2213 	size_t hsize, i, actual, prime;
2214 	dtrace_aggstat_data_t data;
2215 	dtrace_hashstat_data_t *hdata = &data.dtagsd_hash;
2216 
2217 	bzero(&data, sizeof (data));
2218 
2219 	if (!(flags & DCMD_ADDRSPEC))
2220 		return (DCMD_USAGE);
2221 
2222 	if (mdb_vread(&dstate, sizeof (dstate), addr) == -1) {
2223 		mdb_warn("failed to read dynamic variable state at %p", addr);
2224 		return (DCMD_ERR);
2225 	}
2226 
2227 	hsize = (actual = dstate.dtds_hashsize) * sizeof (size_t);
2228 	hdata->dthsd_counts = mdb_alloc(hsize, UM_SLEEP | UM_GC);
2229 
2230 	/*
2231 	 * Now pick the largest prime smaller than the hash size.  (If the
2232 	 * existing size is prime, we'll pick a smaller prime just for the
2233 	 * hell of it.)
2234 	 */
2235 	for (prime = dstate.dtds_hashsize - 1; prime > 7; prime--) {
2236 		size_t limit = prime / 7;
2237 
2238 		for (i = 2; i < limit; i++) {
2239 			if ((prime % i) == 0)
2240 				break;
2241 		}
2242 
2243 		if (i == limit)
2244 			break;
2245 	}
2246 
2247 	for (i = 0; _dtrace_hashstat[i].dths_name != NULL; i++) {
2248 		data.dtagsd_func = _dtrace_hashstat[i].dths_func;
2249 
2250 		hdata->dthsd_hashsize = actual;
2251 		hsize = hdata->dthsd_hashsize * sizeof (size_t);
2252 		bzero(hdata->dthsd_counts, hsize);
2253 
2254 		if (mdb_pwalk("dtrace_dynvar",
2255 		    (mdb_walk_cb_t)dtrace_dynstat_walk, &data, addr) == -1) {
2256 			mdb_warn("failed to walk dtrace_dynvar at %p", addr);
2257 			return (DCMD_ERR);
2258 		}
2259 
2260 		dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2261 
2262 		/*
2263 		 * If we were just printing the actual value, we won't try
2264 		 * any of the sizing experiments.
2265 		 */
2266 		if (data.dtagsd_func == NULL)
2267 			continue;
2268 
2269 		hdata->dthsd_hashsize = prime;
2270 		hsize = hdata->dthsd_hashsize * sizeof (size_t);
2271 		bzero(hdata->dthsd_counts, hsize);
2272 
2273 		if (mdb_pwalk("dtrace_dynvar",
2274 		    (mdb_walk_cb_t)dtrace_dynstat_walk, &data, addr) == -1) {
2275 			mdb_warn("failed to walk dtrace_aggkey at %p", addr);
2276 			return (DCMD_ERR);
2277 		}
2278 
2279 		dtrace_hashstat_stats(_dtrace_hashstat[i].dths_name, hdata);
2280 	}
2281 
2282 	return (DCMD_OK);
2283 }
2284 
2285 typedef struct dtrace_ecb_walk {
2286 	dtrace_ecb_t **dtew_ecbs;
2287 	int dtew_necbs;
2288 	int dtew_curecb;
2289 } dtrace_ecb_walk_t;
2290 
2291 static int
2292 dtrace_ecb_init(mdb_walk_state_t *wsp)
2293 {
2294 	uintptr_t addr;
2295 	dtrace_state_t state;
2296 	dtrace_ecb_walk_t *ecbwp;
2297 
2298 	if ((addr = wsp->walk_addr) == NULL) {
2299 		mdb_warn("dtrace_ecb walk needs dtrace_state_t\n");
2300 		return (WALK_ERR);
2301 	}
2302 
2303 	if (mdb_vread(&state, sizeof (state), addr) == -1) {
2304 		mdb_warn("failed to read dtrace state pointer at %p", addr);
2305 		return (WALK_ERR);
2306 	}
2307 
2308 	ecbwp = mdb_zalloc(sizeof (dtrace_ecb_walk_t), UM_SLEEP | UM_GC);
2309 
2310 	ecbwp->dtew_ecbs = state.dts_ecbs;
2311 	ecbwp->dtew_necbs = state.dts_necbs;
2312 	ecbwp->dtew_curecb = 0;
2313 
2314 	wsp->walk_data = ecbwp;
2315 
2316 	return (WALK_NEXT);
2317 }
2318 
2319 static int
2320 dtrace_ecb_step(mdb_walk_state_t *wsp)
2321 {
2322 	uintptr_t ecbp, addr;
2323 	dtrace_ecb_walk_t *ecbwp = wsp->walk_data;
2324 
2325 	addr = (uintptr_t)ecbwp->dtew_ecbs +
2326 	    ecbwp->dtew_curecb * sizeof (dtrace_ecb_t *);
2327 
2328 	if (ecbwp->dtew_curecb++ == ecbwp->dtew_necbs)
2329 		return (WALK_DONE);
2330 
2331 	if (mdb_vread(&ecbp, sizeof (addr), addr) == -1) {
2332 		mdb_warn("failed to read ecb at entry %d\n",
2333 		    ecbwp->dtew_curecb);
2334 		return (WALK_ERR);
2335 	}
2336 
2337 	if (ecbp == NULL)
2338 		return (WALK_NEXT);
2339 
2340 	return (wsp->walk_callback(ecbp, NULL, wsp->walk_cbdata));
2341 }
2342 
2343 static void
2344 dtrace_options_numtostr(uint64_t num, char *buf, size_t len)
2345 {
2346 	uint64_t n = num;
2347 	int index = 0;
2348 	char u;
2349 
2350 	while (n >= 1024) {
2351 		n = (n + (1024 / 2)) / 1024; /* Round up or down */
2352 		index++;
2353 	}
2354 
2355 	u = " KMGTPE"[index];
2356 
2357 	if (index == 0) {
2358 		(void) mdb_snprintf(buf, len, "%llu", (u_longlong_t)n);
2359 	} else if (n < 10 && (num & (num - 1)) != 0) {
2360 		(void) mdb_snprintf(buf, len, "%.2f%c",
2361 		    (double)num / (1ULL << 10 * index), u);
2362 	} else if (n < 100 && (num & (num - 1)) != 0) {
2363 		(void) mdb_snprintf(buf, len, "%.1f%c",
2364 		    (double)num / (1ULL << 10 * index), u);
2365 	} else {
2366 		(void) mdb_snprintf(buf, len, "%llu%c", (u_longlong_t)n, u);
2367 	}
2368 }
2369 
2370 static void
2371 dtrace_options_numtohz(uint64_t num, char *buf, size_t len)
2372 {
2373 	(void) mdb_snprintf(buf, len, "%dhz", NANOSEC/num);
2374 }
2375 
2376 static void
2377 dtrace_options_numtobufpolicy(uint64_t num, char *buf, size_t len)
2378 {
2379 	char *policy = "unknown";
2380 
2381 	switch (num) {
2382 		case DTRACEOPT_BUFPOLICY_RING:
2383 			policy = "ring";
2384 			break;
2385 
2386 		case DTRACEOPT_BUFPOLICY_FILL:
2387 			policy = "fill";
2388 			break;
2389 
2390 		case DTRACEOPT_BUFPOLICY_SWITCH:
2391 			policy = "switch";
2392 			break;
2393 	}
2394 
2395 	(void) mdb_snprintf(buf, len, "%s", policy);
2396 }
2397 
2398 static void
2399 dtrace_options_numtocpu(uint64_t cpu, char *buf, size_t len)
2400 {
2401 	if (cpu == DTRACE_CPUALL)
2402 		(void) mdb_snprintf(buf, len, "%7s", "unbound");
2403 	else
2404 		(void) mdb_snprintf(buf, len, "%d", cpu);
2405 }
2406 
2407 typedef void (*dtrace_options_func_t)(uint64_t, char *, size_t);
2408 
2409 static struct dtrace_options {
2410 	char *dtop_optstr;
2411 	dtrace_options_func_t dtop_func;
2412 } _dtrace_options[] = {
2413 	{ "bufsize", dtrace_options_numtostr },
2414 	{ "bufpolicy", dtrace_options_numtobufpolicy },
2415 	{ "dynvarsize", dtrace_options_numtostr },
2416 	{ "aggsize", dtrace_options_numtostr },
2417 	{ "specsize", dtrace_options_numtostr },
2418 	{ "nspec", dtrace_options_numtostr },
2419 	{ "strsize", dtrace_options_numtostr },
2420 	{ "cleanrate", dtrace_options_numtohz },
2421 	{ "cpu", dtrace_options_numtocpu },
2422 	{ "bufresize", dtrace_options_numtostr },
2423 	{ "grabanon", dtrace_options_numtostr },
2424 	{ "flowindent", dtrace_options_numtostr },
2425 	{ "quiet", dtrace_options_numtostr },
2426 	{ "stackframes", dtrace_options_numtostr },
2427 	{ "ustackframes", dtrace_options_numtostr },
2428 	{ "aggrate", dtrace_options_numtohz },
2429 	{ "switchrate", dtrace_options_numtohz },
2430 	{ "statusrate", dtrace_options_numtohz },
2431 	{ "destructive", dtrace_options_numtostr },
2432 	{ "stackindent", dtrace_options_numtostr },
2433 	{ "rawbytes", dtrace_options_numtostr },
2434 	{ "jstackframes", dtrace_options_numtostr },
2435 	{ "jstackstrsize", dtrace_options_numtostr },
2436 	{ "aggsortkey", dtrace_options_numtostr },
2437 	{ "aggsortrev", dtrace_options_numtostr },
2438 	{ "aggsortpos", dtrace_options_numtostr },
2439 	{ "aggsortkeypos", dtrace_options_numtostr }
2440 };
2441 
2442 static void
2443 dtrace_options_help(void)
2444 {
2445 	mdb_printf("Given a dtrace_state_t structure, displays the "
2446 	    "current tunable option\nsettings.\n");
2447 }
2448 
2449 /*ARGSUSED*/
2450 static int
2451 dtrace_options(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2452 {
2453 	dtrace_state_t state;
2454 	int i = 0;
2455 	dtrace_optval_t *options;
2456 	char val[32];
2457 
2458 	if (!(flags & DCMD_ADDRSPEC))
2459 		return (DCMD_USAGE);
2460 
2461 	if (mdb_vread(&state, sizeof (dtrace_state_t), (uintptr_t)addr) == -1) {
2462 		mdb_warn("failed to read state pointer at %p\n", addr);
2463 		return (DCMD_ERR);
2464 	}
2465 
2466 	options = &state.dts_options[0];
2467 
2468 	mdb_printf("%<u>%-25s %s%</u>\n", "OPTION", "VALUE");
2469 	for (i = 0; i < DTRACEOPT_MAX; i++) {
2470 		if (options[i] == DTRACEOPT_UNSET) {
2471 			mdb_printf("%-25s %s\n",
2472 			    _dtrace_options[i].dtop_optstr, "UNSET");
2473 		} else {
2474 			(void) _dtrace_options[i].dtop_func(options[i],
2475 			    val, 32);
2476 			mdb_printf("%-25s %s\n",
2477 			    _dtrace_options[i].dtop_optstr, val);
2478 		}
2479 	}
2480 
2481 	return (DCMD_OK);
2482 }
2483 
2484 static int
2485 pid2state_init(mdb_walk_state_t *wsp)
2486 {
2487 	dtrace_state_data_t *data;
2488 	uintptr_t devi;
2489 	uintptr_t proc;
2490 	struct dev_info info;
2491 	pid_t pid = (pid_t)wsp->walk_addr;
2492 
2493 	if (wsp->walk_addr == NULL) {
2494 		mdb_warn("pid2state walk requires PID\n");
2495 		return (WALK_ERR);
2496 	}
2497 
2498 	data = mdb_zalloc(sizeof (dtrace_state_data_t), UM_SLEEP | UM_GC);
2499 
2500 	if (mdb_readvar(&data->dtsd_softstate, "dtrace_softstate") == -1) {
2501 		mdb_warn("failed to read 'dtrace_softstate'");
2502 		return (DCMD_ERR);
2503 	}
2504 
2505 	if ((proc = mdb_pid2proc(pid, NULL)) == NULL) {
2506 		mdb_warn("PID 0t%d not found\n", pid);
2507 		return (DCMD_ERR);
2508 	}
2509 
2510 	if (mdb_readvar(&devi, "dtrace_devi") == -1) {
2511 		mdb_warn("failed to read 'dtrace_devi'");
2512 		return (DCMD_ERR);
2513 	}
2514 
2515 	if (mdb_vread(&info, sizeof (struct dev_info), devi) == -1) {
2516 		mdb_warn("failed to read 'dev_info'");
2517 		return (DCMD_ERR);
2518 	}
2519 
2520 	data->dtsd_major = info.devi_major;
2521 	data->dtsd_proc = proc;
2522 
2523 	wsp->walk_data = data;
2524 
2525 	return (WALK_NEXT);
2526 }
2527 
2528 /*ARGSUSED*/
2529 static int
2530 pid2state_file(uintptr_t addr, struct file *f, dtrace_state_data_t *data)
2531 {
2532 	vnode_t vnode;
2533 	minor_t minor;
2534 	uintptr_t statep;
2535 
2536 	/* Get the vnode for this file */
2537 	if (mdb_vread(&vnode, sizeof (vnode), (uintptr_t)f->f_vnode) == -1) {
2538 		mdb_warn("couldn't read vnode at %p", (uintptr_t)f->f_vnode);
2539 		return (WALK_NEXT);
2540 	}
2541 
2542 
2543 	/* Is this the dtrace device? */
2544 	if (getmajor(vnode.v_rdev) != data->dtsd_major)
2545 		return (WALK_NEXT);
2546 
2547 	/* Get the minor number for this device entry */
2548 	minor = getminor(vnode.v_rdev);
2549 
2550 	if (mdb_get_soft_state_byaddr(data->dtsd_softstate, minor,
2551 	    &statep, NULL, 0) == -1) {
2552 		mdb_warn("failed to read softstate for minor %d", minor);
2553 		return (WALK_NEXT);
2554 	}
2555 
2556 	mdb_printf("%p\n", statep);
2557 
2558 	return (WALK_NEXT);
2559 }
2560 
2561 static int
2562 pid2state_step(mdb_walk_state_t *wsp)
2563 {
2564 	dtrace_state_data_t *ds = wsp->walk_data;
2565 
2566 	if (mdb_pwalk("file",
2567 	    (mdb_walk_cb_t)pid2state_file, ds, ds->dtsd_proc) == -1) {
2568 		mdb_warn("couldn't walk 'file' for proc %p", ds->dtsd_proc);
2569 		return (WALK_ERR);
2570 	}
2571 
2572 	return (WALK_DONE);
2573 }
2574 
2575 /*ARGSUSED*/
2576 static int
2577 dtrace_probes_walk(uintptr_t addr, void *ignored, uintptr_t *target)
2578 {
2579 	dtrace_ecb_t ecb;
2580 	dtrace_probe_t probe;
2581 	dtrace_probedesc_t pd;
2582 
2583 	if (addr == NULL)
2584 		return (WALK_ERR);
2585 
2586 	if (mdb_vread(&ecb, sizeof (dtrace_ecb_t), addr) == -1) {
2587 		mdb_warn("failed to read ecb %p\n", addr);
2588 		return (WALK_ERR);
2589 	}
2590 
2591 	if (ecb.dte_probe == NULL)
2592 		return (WALK_ERR);
2593 
2594 	if (mdb_vread(&probe, sizeof (dtrace_probe_t),
2595 	    (uintptr_t)ecb.dte_probe) == -1) {
2596 		mdb_warn("failed to read probe %p\n", ecb.dte_probe);
2597 		return (WALK_ERR);
2598 	}
2599 
2600 	pd.dtpd_id = probe.dtpr_id;
2601 	dtracemdb_probe(NULL, &pd);
2602 
2603 	mdb_printf("%5d %10s %17s %33s %s\n", pd.dtpd_id, pd.dtpd_provider,
2604 	    pd.dtpd_mod, pd.dtpd_func, pd.dtpd_name);
2605 
2606 	return (WALK_NEXT);
2607 }
2608 
2609 static void
2610 dtrace_probes_help(void)
2611 {
2612 	mdb_printf("Given a dtrace_state_t structure, displays all "
2613 	    "its active enablings.  If no\nstate structure is provided, "
2614 	    "all available probes are listed.\n");
2615 }
2616 
2617 /*ARGSUSED*/
2618 static int
2619 dtrace_probes(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2620 {
2621 	dtrace_probedesc_t pd;
2622 	uintptr_t caddr, base, paddr;
2623 	int nprobes, i;
2624 
2625 	mdb_printf("%5s %10s %17s %33s %s\n",
2626 	    "ID", "PROVIDER", "MODULE", "FUNCTION", "NAME");
2627 
2628 	if (!(flags & DCMD_ADDRSPEC)) {
2629 		/*
2630 		 * If no argument is provided just display all available
2631 		 * probes.
2632 		 */
2633 		if (mdb_readvar(&base, "dtrace_probes") == -1) {
2634 			mdb_warn("failed to read 'dtrace_probes'");
2635 			return (-1);
2636 		}
2637 
2638 		if (mdb_readvar(&nprobes, "dtrace_nprobes") == -1) {
2639 			mdb_warn("failed to read 'dtrace_nprobes'");
2640 			return (-1);
2641 		}
2642 
2643 		for (i = 0; i < nprobes; i++) {
2644 			caddr = base + i  * sizeof (dtrace_probe_t *);
2645 
2646 			if (mdb_vread(&paddr, sizeof (paddr), caddr) == -1) {
2647 				mdb_warn("couldn't read probe pointer at %p",
2648 				    caddr);
2649 				continue;
2650 			}
2651 
2652 			if (paddr == NULL)
2653 				continue;
2654 
2655 			pd.dtpd_id = i + 1;
2656 			if (dtracemdb_probe(NULL, &pd) == 0) {
2657 				mdb_printf("%5d %10s %17s %33s %s\n",
2658 				    pd.dtpd_id, pd.dtpd_provider,
2659 				    pd.dtpd_mod, pd.dtpd_func, pd.dtpd_name);
2660 			}
2661 		}
2662 	} else {
2663 		if (mdb_pwalk("dtrace_ecb", (mdb_walk_cb_t)dtrace_probes_walk,
2664 		    NULL, addr) == -1) {
2665 			mdb_warn("couldn't walk 'dtrace_ecb'");
2666 			return (DCMD_ERR);
2667 		}
2668 	}
2669 
2670 	return (DCMD_OK);
2671 }
2672 
2673 const mdb_dcmd_t kernel_dcmds[] = {
2674 	{ "id2probe", ":", "translate a dtrace_id_t to a dtrace_probe_t",
2675 	    id2probe },
2676 	{ "dtrace", ":[-c cpu]", "print dtrace(1M)-like output",
2677 	    dtrace, dtrace_help },
2678 	{ "dtrace_errhash", ":", "print DTrace error hash", dtrace_errhash },
2679 	{ "dtrace_helptrace", ":", "print DTrace helper trace",
2680 	    dtrace_helptrace },
2681 	{ "dtrace_state", ":", "print active DTrace consumers", dtrace_state,
2682 	    dtrace_state_help },
2683 	{ "dtrace_aggstat", ":",
2684 	    "print DTrace aggregation hash statistics", dtrace_aggstat },
2685 	{ "dtrace_dynstat", ":",
2686 	    "print DTrace dynamic variable hash statistics", dtrace_dynstat },
2687 	{ "dtrace_options", ":",
2688 	    "print a DTrace consumer's current tuneable options",
2689 	    dtrace_options, dtrace_options_help },
2690 	{ "dtrace_probes", "?", "print a DTrace consumer's enabled probes",
2691 	    dtrace_probes, dtrace_probes_help },
2692 	{ NULL }
2693 };
2694 
2695 const mdb_walker_t kernel_walkers[] = {
2696 	{ "dtrace_errhash", "walk hash of DTrace error messasges",
2697 		dtrace_errhash_init, dtrace_errhash_step },
2698 	{ "dtrace_helptrace", "walk DTrace helper trace entries",
2699 		dtrace_helptrace_init, dtrace_helptrace_step },
2700 	{ "dtrace_state", "walk DTrace per-consumer softstate",
2701 		dtrace_state_init, dtrace_state_step },
2702 	{ "dtrace_aggkey", "walk DTrace aggregation keys",
2703 		dtrace_aggkey_init, dtrace_aggkey_step, dtrace_aggkey_fini },
2704 	{ "dtrace_dynvar", "walk DTrace dynamic variables",
2705 		dtrace_dynvar_init, dtrace_dynvar_step, dtrace_dynvar_fini },
2706 	{ "dtrace_ecb", "walk a DTrace consumer's enabling control blocks",
2707 		dtrace_ecb_init, dtrace_ecb_step },
2708 	{ "pid2state", "walk a processes dtrace_state structures",
2709 	    pid2state_init, pid2state_step },
2710 	{ NULL }
2711 };
2712