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