xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/cyclic.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "cyclic.h"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #define	CYCLIC_TRACE
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
34*0Sstevel@tonic-gate #include <sys/timer.h>
35*0Sstevel@tonic-gate #include <sys/cyclic_impl.h>
36*0Sstevel@tonic-gate #include <sys/sysmacros.h>
37*0Sstevel@tonic-gate #include <stdio.h>
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate int
40*0Sstevel@tonic-gate cyccpu_walk_init(mdb_walk_state_t *wsp)
41*0Sstevel@tonic-gate {
42*0Sstevel@tonic-gate 	if (mdb_layered_walk("cpu", wsp) == -1) {
43*0Sstevel@tonic-gate 		mdb_warn("couldn't walk 'cpu'");
44*0Sstevel@tonic-gate 		return (WALK_ERR);
45*0Sstevel@tonic-gate 	}
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate 	return (WALK_NEXT);
48*0Sstevel@tonic-gate }
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate int
51*0Sstevel@tonic-gate cyccpu_walk_step(mdb_walk_state_t *wsp)
52*0Sstevel@tonic-gate {
53*0Sstevel@tonic-gate 	uintptr_t addr = (uintptr_t)((cpu_t *)wsp->walk_layer)->cpu_cyclic;
54*0Sstevel@tonic-gate 	cyc_cpu_t cpu;
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate 	if (mdb_vread(&cpu, sizeof (cpu), addr) == -1) {
57*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
58*0Sstevel@tonic-gate 		return (WALK_ERR);
59*0Sstevel@tonic-gate 	}
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &cpu, wsp->walk_cbdata));
62*0Sstevel@tonic-gate }
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate int
65*0Sstevel@tonic-gate cycomni_walk_init(mdb_walk_state_t *wsp)
66*0Sstevel@tonic-gate {
67*0Sstevel@tonic-gate 	cyc_id_t id;
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
70*0Sstevel@tonic-gate 		mdb_warn("must provide a cyclic id\n");
71*0Sstevel@tonic-gate 		return (WALK_ERR);
72*0Sstevel@tonic-gate 	}
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate 	if (mdb_vread(&id, sizeof (id), wsp->walk_addr) == -1) {
75*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_id_t at %p", wsp->walk_addr);
76*0Sstevel@tonic-gate 		return (WALK_ERR);
77*0Sstevel@tonic-gate 	}
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate 	if (id.cyi_cpu != NULL || id.cyi_omni_list == NULL ||
80*0Sstevel@tonic-gate 	    id.cyi_omni_hdlr.cyo_online == NULL) {
81*0Sstevel@tonic-gate 		mdb_warn("%p is not an omnipresent cyclic.\n", wsp->walk_addr);
82*0Sstevel@tonic-gate 		return (WALK_ERR);
83*0Sstevel@tonic-gate 	}
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)id.cyi_omni_list;
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	return (WALK_NEXT);
88*0Sstevel@tonic-gate }
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate int
91*0Sstevel@tonic-gate cycomni_walk_step(mdb_walk_state_t *wsp)
92*0Sstevel@tonic-gate {
93*0Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
94*0Sstevel@tonic-gate 	cyc_omni_cpu_t omni;
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate 	if (addr == NULL)
97*0Sstevel@tonic-gate 		return (WALK_DONE);
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate 	if (mdb_vread(&omni, sizeof (omni), addr) == -1) {
100*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_omni_cpu at %p", addr);
101*0Sstevel@tonic-gate 		return (WALK_ERR);
102*0Sstevel@tonic-gate 	}
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)omni.cyo_next;
105*0Sstevel@tonic-gate 
106*0Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &omni, wsp->walk_cbdata));
107*0Sstevel@tonic-gate }
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate void
110*0Sstevel@tonic-gate cyclic_dump_node(cyc_cpu_t *cpu, cyc_index_t *heap, char **c, size_t w,
111*0Sstevel@tonic-gate     int ndx, int l, int r, int depth)
112*0Sstevel@tonic-gate {
113*0Sstevel@tonic-gate 	int heap_left, heap_right;
114*0Sstevel@tonic-gate 	int me;
115*0Sstevel@tonic-gate 	int i, x = l + (r - l) / 2;
116*0Sstevel@tonic-gate 	size_t n = w - (x - 1); /* n bytes left for snprintf after c[][x - 1] */
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 	heap_left = CYC_HEAP_LEFT(ndx);
119*0Sstevel@tonic-gate 	heap_right = CYC_HEAP_RIGHT(ndx);
120*0Sstevel@tonic-gate 	me = heap[ndx];
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	if (ndx >= cpu->cyp_nelems)
123*0Sstevel@tonic-gate 		return;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 	if (me < 10) {
126*0Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, " %d", me);
127*0Sstevel@tonic-gate 	} else if (me >= 100) {
128*0Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, "%3d", me);
129*0Sstevel@tonic-gate 	} else {
130*0Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, "%s%2d%s",
131*0Sstevel@tonic-gate 		    CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? " " : "", me,
132*0Sstevel@tonic-gate 		    CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? "" : " ");
133*0Sstevel@tonic-gate 	}
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	if (r - l > 5) {
136*0Sstevel@tonic-gate 		c[++depth][x] = '|';
137*0Sstevel@tonic-gate 		depth++;
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 		for (i = l + (r - l) / 4; i < r - (r - l) / 4; i++)
140*0Sstevel@tonic-gate 			c[depth][i] = '-';
141*0Sstevel@tonic-gate 		c[depth][l + (r - l) / 4] = '+';
142*0Sstevel@tonic-gate 		c[depth][r - (r - l) / 4 - 1] = '+';
143*0Sstevel@tonic-gate 		c[depth][x] = '+';
144*0Sstevel@tonic-gate 	} else {
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate 		if (heap_left >= cpu->cyp_nelems)
147*0Sstevel@tonic-gate 			return;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 		(void) mdb_snprintf(&c[++depth][x - 1], n, "L%d",
150*0Sstevel@tonic-gate 		    heap[heap_left]);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 		if (heap_right >= cpu->cyp_nelems)
153*0Sstevel@tonic-gate 			return;
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate 		(void) mdb_snprintf(&c[++depth][x - 1], n, "R%d",
156*0Sstevel@tonic-gate 		    heap[heap_right]);
157*0Sstevel@tonic-gate 		return;
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate 	if (heap_left < cpu->cyp_nelems)
161*0Sstevel@tonic-gate 		cyclic_dump_node(cpu, heap, c, w, heap_left, l, x, depth + 1);
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	if (heap_right < cpu->cyp_nelems)
164*0Sstevel@tonic-gate 		cyclic_dump_node(cpu, heap, c, w, heap_right, x, r, depth + 1);
165*0Sstevel@tonic-gate }
166*0Sstevel@tonic-gate 
167*0Sstevel@tonic-gate #define	LINES_PER_LEVEL 3
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate void
170*0Sstevel@tonic-gate cyclic_pretty_dump(cyc_cpu_t *cpu)
171*0Sstevel@tonic-gate {
172*0Sstevel@tonic-gate 	char **c;
173*0Sstevel@tonic-gate 	int i, j;
174*0Sstevel@tonic-gate 	int width = 80;
175*0Sstevel@tonic-gate 	int depth;
176*0Sstevel@tonic-gate 	cyc_index_t *heap;
177*0Sstevel@tonic-gate 	size_t hsize = sizeof (cyc_index_t) * cpu->cyp_size;
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 	heap = mdb_alloc(hsize, UM_SLEEP | UM_GC);
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	if (mdb_vread(heap, hsize, (uintptr_t)cpu->cyp_heap) == -1) {
182*0Sstevel@tonic-gate 		mdb_warn("couldn't read heap at %p", (uintptr_t)cpu->cyp_heap);
183*0Sstevel@tonic-gate 		return;
184*0Sstevel@tonic-gate 	}
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	for (depth = 0; (1 << depth) < cpu->cyp_nelems; depth++)
187*0Sstevel@tonic-gate 		continue;
188*0Sstevel@tonic-gate 	depth++;
189*0Sstevel@tonic-gate 	depth = (depth + 1) * LINES_PER_LEVEL;
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	c = mdb_zalloc(sizeof (char *) * depth, UM_SLEEP|UM_GC);
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
194*0Sstevel@tonic-gate 		c[i] = mdb_zalloc(width, UM_SLEEP|UM_GC);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	cyclic_dump_node(cpu, heap, c, width, 0, 1, width - 2, 0);
197*0Sstevel@tonic-gate 
198*0Sstevel@tonic-gate 	for (i = 0; i < depth; i++) {
199*0Sstevel@tonic-gate 		int dump = 0;
200*0Sstevel@tonic-gate 		for (j = 0; j < width - 1; j++) {
201*0Sstevel@tonic-gate 			if (c[i][j] == '\0')
202*0Sstevel@tonic-gate 				c[i][j] = ' ';
203*0Sstevel@tonic-gate 			else
204*0Sstevel@tonic-gate 				dump = 1;
205*0Sstevel@tonic-gate 		}
206*0Sstevel@tonic-gate 		c[i][width - 2] = '\n';
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 		if (dump)
209*0Sstevel@tonic-gate 			mdb_printf(c[i]);
210*0Sstevel@tonic-gate 	}
211*0Sstevel@tonic-gate }
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate /*
214*0Sstevel@tonic-gate  * Yes, this is very weak.  Full 16-column-wide 64-bit addresses screw up
215*0Sstevel@tonic-gate  * ::cycinfo's very carefully planned 80-column layout.  We set the column
216*0Sstevel@tonic-gate  * width for addresses to be 11 (instead of 16), knowing that the kernel
217*0Sstevel@tonic-gate  * heap (from which these data structures are allocated) starts at
218*0Sstevel@tonic-gate  * 0x0000030000000000, and isn't likely to extend to 0x0000100000000000.
219*0Sstevel@tonic-gate  */
220*0Sstevel@tonic-gate #ifdef _LP64
221*0Sstevel@tonic-gate #define	CYC_ADDR_WIDTH	11
222*0Sstevel@tonic-gate #else
223*0Sstevel@tonic-gate #define	CYC_ADDR_WIDTH	8
224*0Sstevel@tonic-gate #endif
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate int
227*0Sstevel@tonic-gate cycinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
228*0Sstevel@tonic-gate {
229*0Sstevel@tonic-gate 	cyc_cpu_t cpu;
230*0Sstevel@tonic-gate 	cpu_t c;
231*0Sstevel@tonic-gate 	cyc_index_t root, i, *heap;
232*0Sstevel@tonic-gate 	size_t hsize;
233*0Sstevel@tonic-gate 	cyclic_t *cyc;
234*0Sstevel@tonic-gate 	uintptr_t caddr;
235*0Sstevel@tonic-gate 	uint_t verbose = FALSE, Verbose = FALSE;
236*0Sstevel@tonic-gate 	int header = 0;
237*0Sstevel@tonic-gate 	cyc_level_t lev;
238*0Sstevel@tonic-gate 
239*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
240*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("cyccpu", "cycinfo", argc, argv) == -1) {
241*0Sstevel@tonic-gate 			mdb_warn("can't walk 'cyccpu'");
242*0Sstevel@tonic-gate 			return (DCMD_ERR);
243*0Sstevel@tonic-gate 		}
244*0Sstevel@tonic-gate 		return (DCMD_OK);
245*0Sstevel@tonic-gate 	}
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
248*0Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
249*0Sstevel@tonic-gate 	    'V', MDB_OPT_SETBITS, TRUE, &Verbose, NULL) != argc)
250*0Sstevel@tonic-gate 		return (DCMD_USAGE);
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	if (!DCMD_HDRSPEC(flags) && (verbose || Verbose))
253*0Sstevel@tonic-gate 		mdb_printf("\n\n");
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) || verbose || Verbose)
256*0Sstevel@tonic-gate 		mdb_printf("%3s %*s %7s %6s %*s %15s %s\n", "CPU",
257*0Sstevel@tonic-gate 		    CYC_ADDR_WIDTH, "CYC_CPU", "STATE", "NELEMS",
258*0Sstevel@tonic-gate 		    CYC_ADDR_WIDTH, "ROOT", "FIRE", "HANDLER");
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	if (mdb_vread(&cpu, sizeof (cpu), addr) == -1) {
261*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
262*0Sstevel@tonic-gate 		return (DCMD_ERR);
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) {
266*0Sstevel@tonic-gate 		mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu);
267*0Sstevel@tonic-gate 		return (DCMD_ERR);
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	cyc = mdb_alloc(sizeof (cyclic_t) * cpu.cyp_size, UM_SLEEP | UM_GC);
271*0Sstevel@tonic-gate 	caddr = (uintptr_t)cpu.cyp_cyclics;
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	if (mdb_vread(cyc, sizeof (cyclic_t) * cpu.cyp_size, caddr) == -1) {
274*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", caddr);
275*0Sstevel@tonic-gate 		return (DCMD_ERR);
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	hsize = sizeof (cyc_index_t) * cpu.cyp_size;
279*0Sstevel@tonic-gate 	heap = mdb_alloc(hsize, UM_SLEEP | UM_GC);
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 	if (mdb_vread(heap, hsize, (uintptr_t)cpu.cyp_heap) == -1) {
282*0Sstevel@tonic-gate 		mdb_warn("couldn't read heap at %p", cpu.cyp_heap);
283*0Sstevel@tonic-gate 		return (DCMD_ERR);
284*0Sstevel@tonic-gate 	}
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	root = heap[0];
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	mdb_printf("%3d %0*p %7s %6d ", c.cpu_id, CYC_ADDR_WIDTH, addr,
289*0Sstevel@tonic-gate 	    cpu.cyp_state == CYS_ONLINE ? "online" :
290*0Sstevel@tonic-gate 	    cpu.cyp_state == CYS_OFFLINE ? "offline" :
291*0Sstevel@tonic-gate 	    cpu.cyp_state == CYS_EXPANDING ? "expand" :
292*0Sstevel@tonic-gate 	    cpu.cyp_state == CYS_REMOVING ? "remove" :
293*0Sstevel@tonic-gate 	    cpu.cyp_state == CYS_SUSPENDED ? "suspend" : "????",
294*0Sstevel@tonic-gate 	    cpu.cyp_nelems);
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	if (cpu.cyp_nelems > 0)
297*0Sstevel@tonic-gate 		mdb_printf("%0*p %15llx %a\n", CYC_ADDR_WIDTH,
298*0Sstevel@tonic-gate 		    caddr, cyc[root].cy_expire, cyc[root].cy_handler);
299*0Sstevel@tonic-gate 	else
300*0Sstevel@tonic-gate 		mdb_printf("%*s %15s %s\n", CYC_ADDR_WIDTH, "-", "-", "-");
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	if (!verbose && !Verbose)
303*0Sstevel@tonic-gate 		return (DCMD_OK);
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate 	mdb_printf("\n");
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	cyclic_pretty_dump(&cpu);
308*0Sstevel@tonic-gate 
309*0Sstevel@tonic-gate 	mdb_inc_indent(2);
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	for (i = 0; i < cpu.cyp_size; i++) {
312*0Sstevel@tonic-gate 		int j;
313*0Sstevel@tonic-gate 
314*0Sstevel@tonic-gate 		for (j = 0; j < cpu.cyp_size; j++) {
315*0Sstevel@tonic-gate 			if (heap[j] == i)
316*0Sstevel@tonic-gate 				break;
317*0Sstevel@tonic-gate 		}
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 		if (!Verbose && j >= cpu.cyp_nelems)
320*0Sstevel@tonic-gate 			continue;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 		if (!header) {
323*0Sstevel@tonic-gate 			header = 1;
324*0Sstevel@tonic-gate 			mdb_printf("\n%*s %3s %4s %4s %5s %15s %7s %s\n",
325*0Sstevel@tonic-gate 			    CYC_ADDR_WIDTH, "ADDR", "NDX", "HEAP", "LEVL",
326*0Sstevel@tonic-gate 			    "PEND", "FIRE", "USECINT", "HANDLER");
327*0Sstevel@tonic-gate 		}
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 		mdb_printf("%0*p %3d ", CYC_ADDR_WIDTH,
330*0Sstevel@tonic-gate 		    caddr + i * sizeof (cyclic_t), i);
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 		mdb_printf("%4d ", j);
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 		if (j >= cpu.cyp_nelems) {
335*0Sstevel@tonic-gate 			mdb_printf("%4s %5s %15s %7s %s\n", "-", "-",
336*0Sstevel@tonic-gate 			    "-", "-", "-");
337*0Sstevel@tonic-gate 			continue;
338*0Sstevel@tonic-gate 		}
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 		mdb_printf("%4s %5d %15llx ",
341*0Sstevel@tonic-gate 		    cyc[i].cy_level == CY_HIGH_LEVEL ? "high" :
342*0Sstevel@tonic-gate 		    cyc[i].cy_level == CY_LOCK_LEVEL ? "lock" :
343*0Sstevel@tonic-gate 		    cyc[i].cy_level == CY_LOW_LEVEL ? "low" : "????",
344*0Sstevel@tonic-gate 		    cyc[i].cy_pend, cyc[i].cy_expire);
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 		if (cyc[i].cy_interval + cyc[i].cy_expire != INT64_MAX)
347*0Sstevel@tonic-gate 			mdb_printf("%7lld ", cyc[i].cy_interval /
348*0Sstevel@tonic-gate 			    (uint64_t)(NANOSEC / MICROSEC));
349*0Sstevel@tonic-gate 		else
350*0Sstevel@tonic-gate 			mdb_printf("%7s ", "-");
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 		mdb_printf("%a\n", cyc[i].cy_handler);
353*0Sstevel@tonic-gate 	}
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	if (!Verbose)
357*0Sstevel@tonic-gate 		goto out;
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 	for (lev = CY_LOW_LEVEL; lev < CY_LOW_LEVEL + CY_SOFT_LEVELS; lev++) {
360*0Sstevel@tonic-gate 		cyc_softbuf_t *softbuf = &cpu.cyp_softbuf[lev];
361*0Sstevel@tonic-gate 		char which = softbuf->cys_hard, shared = 1;
362*0Sstevel@tonic-gate 		cyc_pcbuffer_t *pc;
363*0Sstevel@tonic-gate 		size_t bufsiz;
364*0Sstevel@tonic-gate 		cyc_index_t *buf;
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 		if (softbuf->cys_hard != softbuf->cys_soft)
367*0Sstevel@tonic-gate 			shared = 0;
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate again:
370*0Sstevel@tonic-gate 		pc = &softbuf->cys_buf[which];
371*0Sstevel@tonic-gate 		bufsiz = (pc->cypc_sizemask + 1) * sizeof (cyc_index_t);
372*0Sstevel@tonic-gate 		buf = mdb_alloc(bufsiz, UM_SLEEP | UM_GC);
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 		if (mdb_vread(buf, bufsiz, (uintptr_t)pc->cypc_buf) == -1) {
375*0Sstevel@tonic-gate 			mdb_warn("couldn't read cypc_buf at %p", pc->cypc_buf);
376*0Sstevel@tonic-gate 			continue;
377*0Sstevel@tonic-gate 		}
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 		mdb_printf("\n%3s %4s %4s %4s %*s %4s %*s\n", "CPU",
380*0Sstevel@tonic-gate 		    "LEVL", "USER", "NDX", CYC_ADDR_WIDTH, "ADDR", "CYC",
381*0Sstevel@tonic-gate 		    CYC_ADDR_WIDTH, "CYC_ADDR", "PEND");
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 		for (i = 0; i <= pc->cypc_sizemask &&
384*0Sstevel@tonic-gate 		    i <= pc->cypc_prodndx; i++) {
385*0Sstevel@tonic-gate 			uintptr_t cyc_addr = caddr + buf[i] * sizeof (cyclic_t);
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 			mdb_printf("%3d %4s %4s ", c.cpu_id,
388*0Sstevel@tonic-gate 			    lev == CY_HIGH_LEVEL ? "high" :
389*0Sstevel@tonic-gate 			    lev == CY_LOCK_LEVEL ? "lock" :
390*0Sstevel@tonic-gate 			    lev == CY_LOW_LEVEL ? "low" : "????",
391*0Sstevel@tonic-gate 			    shared ? "shrd" : which == softbuf->cys_hard ?
392*0Sstevel@tonic-gate 			    "hard" : "soft");
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 			mdb_printf("%4d %0*p ", i, CYC_ADDR_WIDTH,
395*0Sstevel@tonic-gate 			    (uintptr_t)&buf[i] - (uintptr_t)&buf[0] +
396*0Sstevel@tonic-gate 			    (uintptr_t)pc->cypc_buf, buf[i],
397*0Sstevel@tonic-gate 			    caddr + buf[i] * sizeof (cyclic_t));
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 			if (i >= pc->cypc_prodndx)
400*0Sstevel@tonic-gate 				mdb_printf("%4s %*s %5s  ",
401*0Sstevel@tonic-gate 				    "-", CYC_ADDR_WIDTH, "-", "-");
402*0Sstevel@tonic-gate 			else {
403*0Sstevel@tonic-gate 				cyclic_t c;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 				if (mdb_vread(&c, sizeof (c), cyc_addr) == -1) {
406*0Sstevel@tonic-gate 					mdb_warn("\ncouldn't read cyclic at "
407*0Sstevel@tonic-gate 					    "%p", cyc_addr);
408*0Sstevel@tonic-gate 					continue;
409*0Sstevel@tonic-gate 				}
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 				mdb_printf("%4d %0*p %5d  ", buf[i],
412*0Sstevel@tonic-gate 				    CYC_ADDR_WIDTH, cyc_addr, c.cy_pend);
413*0Sstevel@tonic-gate 			}
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 			if (i == (pc->cypc_consndx & pc->cypc_sizemask)) {
416*0Sstevel@tonic-gate 				mdb_printf("<-- consndx");
417*0Sstevel@tonic-gate 				if (i == (pc->cypc_prodndx & pc->cypc_sizemask))
418*0Sstevel@tonic-gate 					mdb_printf(",prodndx");
419*0Sstevel@tonic-gate 				mdb_printf("\n");
420*0Sstevel@tonic-gate 				continue;
421*0Sstevel@tonic-gate 			}
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 			if (i == (pc->cypc_prodndx & pc->cypc_sizemask)) {
424*0Sstevel@tonic-gate 				mdb_printf("<-- prodndx\n");
425*0Sstevel@tonic-gate 				continue;
426*0Sstevel@tonic-gate 			}
427*0Sstevel@tonic-gate 			mdb_printf("\n");
428*0Sstevel@tonic-gate 
429*0Sstevel@tonic-gate 			if (i >= pc->cypc_prodndx)
430*0Sstevel@tonic-gate 				break;
431*0Sstevel@tonic-gate 		}
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 		if (!shared && which == softbuf->cys_hard) {
434*0Sstevel@tonic-gate 			which = softbuf->cys_soft;
435*0Sstevel@tonic-gate 			goto again;
436*0Sstevel@tonic-gate 		}
437*0Sstevel@tonic-gate 	}
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate out:
440*0Sstevel@tonic-gate 	mdb_dec_indent(2);
441*0Sstevel@tonic-gate 	return (DCMD_OK);
442*0Sstevel@tonic-gate }
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate int
445*0Sstevel@tonic-gate cyctrace_walk_init(mdb_walk_state_t *wsp)
446*0Sstevel@tonic-gate {
447*0Sstevel@tonic-gate 	cyc_cpu_t *cpu;
448*0Sstevel@tonic-gate 	int i;
449*0Sstevel@tonic-gate 
450*0Sstevel@tonic-gate 	cpu = mdb_zalloc(sizeof (cyc_cpu_t), UM_SLEEP);
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
453*0Sstevel@tonic-gate 		/*
454*0Sstevel@tonic-gate 		 * If an address isn't provided, we'll use the passive buffer.
455*0Sstevel@tonic-gate 		 */
456*0Sstevel@tonic-gate 		GElf_Sym sym;
457*0Sstevel@tonic-gate 		cyc_tracebuf_t *tr = &cpu->cyp_trace[0];
458*0Sstevel@tonic-gate 		uintptr_t addr;
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 		if (mdb_lookup_by_name("cyc_ptrace", &sym) == -1) {
461*0Sstevel@tonic-gate 			mdb_warn("couldn't find passive buffer");
462*0Sstevel@tonic-gate 			return (-1);
463*0Sstevel@tonic-gate 		}
464*0Sstevel@tonic-gate 
465*0Sstevel@tonic-gate 		addr = (uintptr_t)sym.st_value;
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 		if (mdb_vread(tr, sizeof (cyc_tracebuf_t), addr) == -1) {
468*0Sstevel@tonic-gate 			mdb_warn("couldn't read passive buffer");
469*0Sstevel@tonic-gate 			return (-1);
470*0Sstevel@tonic-gate 		}
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 		wsp->walk_addr = addr - offsetof(cyc_cpu_t, cyp_trace[0]);
473*0Sstevel@tonic-gate 	} else {
474*0Sstevel@tonic-gate 		if (mdb_vread(cpu, sizeof (cyc_cpu_t), wsp->walk_addr) == -1) {
475*0Sstevel@tonic-gate 			mdb_warn("couldn't read cyc_cpu at %p", wsp->walk_addr);
476*0Sstevel@tonic-gate 			mdb_free(cpu, sizeof (cyc_cpu_t));
477*0Sstevel@tonic-gate 			return (-1);
478*0Sstevel@tonic-gate 		}
479*0Sstevel@tonic-gate 	}
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	for (i = 0; i < CY_LEVELS; i++) {
482*0Sstevel@tonic-gate 		if (cpu->cyp_trace[i].cyt_ndx-- == 0)
483*0Sstevel@tonic-gate 			cpu->cyp_trace[i].cyt_ndx = CY_NTRACEREC - 1;
484*0Sstevel@tonic-gate 	}
485*0Sstevel@tonic-gate 
486*0Sstevel@tonic-gate 	wsp->walk_data = cpu;
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 	return (0);
489*0Sstevel@tonic-gate }
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate int
492*0Sstevel@tonic-gate cyctrace_walk_step(mdb_walk_state_t *wsp)
493*0Sstevel@tonic-gate {
494*0Sstevel@tonic-gate 	cyc_cpu_t *cpu = wsp->walk_data;
495*0Sstevel@tonic-gate 	cyc_tracebuf_t *buf = cpu->cyp_trace;
496*0Sstevel@tonic-gate 	hrtime_t latest = 0;
497*0Sstevel@tonic-gate 	int i, ndx, new_ndx, lev, rval;
498*0Sstevel@tonic-gate 	uintptr_t addr;
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	for (i = 0; i < CY_LEVELS; i++) {
501*0Sstevel@tonic-gate 		if ((ndx = buf[i].cyt_ndx) == -1)
502*0Sstevel@tonic-gate 			continue;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 		/*
505*0Sstevel@tonic-gate 		 * Account for NPT.
506*0Sstevel@tonic-gate 		 */
507*0Sstevel@tonic-gate 		buf[i].cyt_buf[ndx].cyt_tstamp <<= 1;
508*0Sstevel@tonic-gate 		buf[i].cyt_buf[ndx].cyt_tstamp >>= 1;
509*0Sstevel@tonic-gate 
510*0Sstevel@tonic-gate 		if (buf[i].cyt_buf[ndx].cyt_tstamp > latest) {
511*0Sstevel@tonic-gate 			latest = buf[i].cyt_buf[ndx].cyt_tstamp;
512*0Sstevel@tonic-gate 			lev = i;
513*0Sstevel@tonic-gate 		}
514*0Sstevel@tonic-gate 	}
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 	/*
517*0Sstevel@tonic-gate 	 * If we didn't find one, we're done.
518*0Sstevel@tonic-gate 	 */
519*0Sstevel@tonic-gate 	if (latest == 0)
520*0Sstevel@tonic-gate 		return (-1);
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	buf = &buf[lev];
523*0Sstevel@tonic-gate 	ndx = buf->cyt_ndx;
524*0Sstevel@tonic-gate 	addr = wsp->walk_addr +
525*0Sstevel@tonic-gate 	    (uintptr_t)&(buf->cyt_buf[ndx]) - (uintptr_t)cpu;
526*0Sstevel@tonic-gate 
527*0Sstevel@tonic-gate 	rval = wsp->walk_callback(addr, &buf->cyt_buf[ndx], wsp->walk_cbdata);
528*0Sstevel@tonic-gate 
529*0Sstevel@tonic-gate 	new_ndx = ndx == 0 ? CY_NTRACEREC - 1 : ndx - 1;
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	if (buf->cyt_buf[new_ndx].cyt_tstamp != 0 &&
532*0Sstevel@tonic-gate 	    buf->cyt_buf[new_ndx].cyt_tstamp > buf->cyt_buf[ndx].cyt_tstamp)
533*0Sstevel@tonic-gate 		new_ndx = -1;
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 	buf->cyt_ndx = new_ndx;
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 	return (rval);
538*0Sstevel@tonic-gate }
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate void
541*0Sstevel@tonic-gate cyctrace_walk_fini(mdb_walk_state_t *wsp)
542*0Sstevel@tonic-gate {
543*0Sstevel@tonic-gate 	cyc_cpu_t *cpu = wsp->walk_data;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	mdb_free(cpu, sizeof (cyc_cpu_t));
546*0Sstevel@tonic-gate }
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate #define	WHYLEN	17
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate int
551*0Sstevel@tonic-gate cyctrace_walk(uintptr_t addr, const cyc_tracerec_t *rec, cyc_cpu_t *cpu)
552*0Sstevel@tonic-gate {
553*0Sstevel@tonic-gate 	int i;
554*0Sstevel@tonic-gate 	char c[WHYLEN];
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	for (i = 0; cpu != NULL && i < CY_LEVELS; i++)
557*0Sstevel@tonic-gate 		if (addr < (uintptr_t)&cpu->cyp_trace[i + 1].cyt_buf[0])
558*0Sstevel@tonic-gate 			break;
559*0Sstevel@tonic-gate 
560*0Sstevel@tonic-gate 	(void) mdb_readstr(c, WHYLEN, (uintptr_t)rec->cyt_why);
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	mdb_printf("%08p %4s %15llx %-*s %15llx %15llx\n",
563*0Sstevel@tonic-gate 	    addr & UINT_MAX, cpu == NULL ? "pasv" :
564*0Sstevel@tonic-gate 	    i == CY_HIGH_LEVEL ? "high" : i == CY_LOCK_LEVEL ? "lock" :
565*0Sstevel@tonic-gate 	    i == CY_LOW_LEVEL ? "low" : "????", rec->cyt_tstamp, WHYLEN, c,
566*0Sstevel@tonic-gate 	    rec->cyt_arg0, rec->cyt_arg1);
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate 	return (0);
569*0Sstevel@tonic-gate }
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate /*ARGSUSED*/
572*0Sstevel@tonic-gate int
573*0Sstevel@tonic-gate cyctrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
574*0Sstevel@tonic-gate {
575*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
576*0Sstevel@tonic-gate 		addr = NULL;
577*0Sstevel@tonic-gate 
578*0Sstevel@tonic-gate 	if (mdb_pwalk("cyctrace", (mdb_walk_cb_t)cyctrace_walk,
579*0Sstevel@tonic-gate 	    (void *)addr, addr) == -1) {
580*0Sstevel@tonic-gate 		mdb_warn("couldn't walk cyctrace");
581*0Sstevel@tonic-gate 		return (DCMD_ERR);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 
584*0Sstevel@tonic-gate 	return (DCMD_OK);
585*0Sstevel@tonic-gate }
586*0Sstevel@tonic-gate 
587*0Sstevel@tonic-gate int
588*0Sstevel@tonic-gate cyccover_comp(const void *l, const void *r)
589*0Sstevel@tonic-gate {
590*0Sstevel@tonic-gate 	cyc_coverage_t *lhs = (cyc_coverage_t *)l;
591*0Sstevel@tonic-gate 	cyc_coverage_t *rhs = (cyc_coverage_t *)r;
592*0Sstevel@tonic-gate 
593*0Sstevel@tonic-gate 	char ly[WHYLEN], ry[WHYLEN];
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	if (rhs->cyv_why == lhs->cyv_why)
596*0Sstevel@tonic-gate 		return (0);
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate 	if (rhs->cyv_why == NULL)
599*0Sstevel@tonic-gate 		return (-1);
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate 	if (lhs->cyv_why == NULL)
602*0Sstevel@tonic-gate 		return (1);
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 	(void) mdb_readstr(ly, WHYLEN, (uintptr_t)lhs->cyv_why);
605*0Sstevel@tonic-gate 	(void) mdb_readstr(ry, WHYLEN, (uintptr_t)rhs->cyv_why);
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate 	return (strcmp(ly, ry));
608*0Sstevel@tonic-gate }
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate /*ARGSUSED*/
611*0Sstevel@tonic-gate int
612*0Sstevel@tonic-gate cyccover(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
613*0Sstevel@tonic-gate {
614*0Sstevel@tonic-gate 	cyc_coverage_t cv[CY_NCOVERAGE];
615*0Sstevel@tonic-gate 	char c[WHYLEN];
616*0Sstevel@tonic-gate 	GElf_Sym sym;
617*0Sstevel@tonic-gate 	int i;
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
620*0Sstevel@tonic-gate 		return (DCMD_USAGE);
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	if (mdb_lookup_by_name("cyc_coverage", &sym) == -1) {
623*0Sstevel@tonic-gate 		mdb_warn("couldn't find coverage information");
624*0Sstevel@tonic-gate 		return (DCMD_ABORT);
625*0Sstevel@tonic-gate 	}
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	addr = (uintptr_t)sym.st_value;
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	if (mdb_vread(cv, sizeof (cyc_coverage_t) * CY_NCOVERAGE, addr) == -1) {
630*0Sstevel@tonic-gate 		mdb_warn("couldn't read coverage array at %p", addr);
631*0Sstevel@tonic-gate 		return (DCMD_ABORT);
632*0Sstevel@tonic-gate 	}
633*0Sstevel@tonic-gate 
634*0Sstevel@tonic-gate 	mdb_printf("%-*s %8s %8s %8s %15s %15s\n",
635*0Sstevel@tonic-gate 	    WHYLEN, "POINT", "HIGH", "LOCK", "LOW/PASV", "ARG0", "ARG1");
636*0Sstevel@tonic-gate 
637*0Sstevel@tonic-gate 	qsort(cv, CY_NCOVERAGE, sizeof (cyc_coverage_t), cyccover_comp);
638*0Sstevel@tonic-gate 
639*0Sstevel@tonic-gate 	for (i = 0; i < CY_NCOVERAGE; i++) {
640*0Sstevel@tonic-gate 		if (cv[i].cyv_why != NULL) {
641*0Sstevel@tonic-gate 			(void) mdb_readstr(c, WHYLEN, (uintptr_t)cv[i].cyv_why);
642*0Sstevel@tonic-gate 			mdb_printf("%-*s %8d %8d %8d %15llx %15llx\n",
643*0Sstevel@tonic-gate 			    WHYLEN, c,
644*0Sstevel@tonic-gate 			    cv[i].cyv_count[CY_HIGH_LEVEL],
645*0Sstevel@tonic-gate 			    cv[i].cyv_count[CY_LOCK_LEVEL],
646*0Sstevel@tonic-gate 			    cv[i].cyv_passive_count != 0 ?
647*0Sstevel@tonic-gate 			    cv[i].cyv_passive_count :
648*0Sstevel@tonic-gate 			    cv[i].cyv_count[CY_LOW_LEVEL],
649*0Sstevel@tonic-gate 			    cv[i].cyv_arg0, cv[i].cyv_arg1);
650*0Sstevel@tonic-gate 		}
651*0Sstevel@tonic-gate 	}
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate 	return (DCMD_OK);
654*0Sstevel@tonic-gate }
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate /*ARGSUSED*/
657*0Sstevel@tonic-gate int
658*0Sstevel@tonic-gate cyclic(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
659*0Sstevel@tonic-gate {
660*0Sstevel@tonic-gate 	cyclic_t cyc;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
663*0Sstevel@tonic-gate 		return (DCMD_USAGE);
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
666*0Sstevel@tonic-gate 		mdb_printf("%?s %4s %5s %5s %15s %7s %s\n", "ADDR", "LEVL",
667*0Sstevel@tonic-gate 		    "PEND", "FLAGS", "FIRE", "USECINT", "HANDLER");
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	if (mdb_vread(&cyc, sizeof (cyclic_t), addr) == -1) {
670*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", addr);
671*0Sstevel@tonic-gate 		return (DCMD_ERR);
672*0Sstevel@tonic-gate 	}
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 	mdb_printf("%0?p %4s %5d  %04x %15llx %7lld %a\n", addr,
675*0Sstevel@tonic-gate 	    cyc.cy_level == CY_HIGH_LEVEL ? "high" :
676*0Sstevel@tonic-gate 	    cyc.cy_level == CY_LOCK_LEVEL ? "lock" :
677*0Sstevel@tonic-gate 	    cyc.cy_level == CY_LOW_LEVEL ? "low" : "????",
678*0Sstevel@tonic-gate 	    cyc.cy_pend, cyc.cy_flags, cyc.cy_expire,
679*0Sstevel@tonic-gate 	    cyc.cy_interval / (uint64_t)(NANOSEC / MICROSEC),
680*0Sstevel@tonic-gate 	    cyc.cy_handler);
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 	return (DCMD_OK);
683*0Sstevel@tonic-gate }
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate static int
686*0Sstevel@tonic-gate cycid_cpu(cyc_cpu_t *addr, int ndx)
687*0Sstevel@tonic-gate {
688*0Sstevel@tonic-gate 	cyc_cpu_t cpu;
689*0Sstevel@tonic-gate 	cpu_t c;
690*0Sstevel@tonic-gate 	uintptr_t caddr;
691*0Sstevel@tonic-gate 	cyclic_t cyc;
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 	if (mdb_vread(&cpu, sizeof (cpu), (uintptr_t)addr) == -1) {
694*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
695*0Sstevel@tonic-gate 		return (DCMD_ERR);
696*0Sstevel@tonic-gate 	}
697*0Sstevel@tonic-gate 
698*0Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) {
699*0Sstevel@tonic-gate 		mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu);
700*0Sstevel@tonic-gate 		return (DCMD_ERR);
701*0Sstevel@tonic-gate 	}
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 	caddr = (uintptr_t)cpu.cyp_cyclics + ndx * sizeof (cyclic_t);
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	if (mdb_vread(&cyc, sizeof (cyc), caddr) == -1) {
706*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", caddr);
707*0Sstevel@tonic-gate 		return (DCMD_ERR);
708*0Sstevel@tonic-gate 	}
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 	mdb_printf("%4d %3d %?p %a\n", c.cpu_id, ndx, caddr, cyc.cy_handler);
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 	return (DCMD_OK);
713*0Sstevel@tonic-gate }
714*0Sstevel@tonic-gate 
715*0Sstevel@tonic-gate /*ARGSUSED*/
716*0Sstevel@tonic-gate static int
717*0Sstevel@tonic-gate cycid_walk_omni(uintptr_t addr, const cyc_omni_cpu_t *omni, int *ignored)
718*0Sstevel@tonic-gate {
719*0Sstevel@tonic-gate 	mdb_printf("%?s        ");
720*0Sstevel@tonic-gate 	cycid_cpu(omni->cyo_cpu, omni->cyo_ndx);
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	return (WALK_NEXT);
723*0Sstevel@tonic-gate }
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate /*ARGSUSED*/
726*0Sstevel@tonic-gate int
727*0Sstevel@tonic-gate cycid(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
728*0Sstevel@tonic-gate {
729*0Sstevel@tonic-gate 	cyc_id_t id;
730*0Sstevel@tonic-gate 
731*0Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
732*0Sstevel@tonic-gate 		if (mdb_walk_dcmd("cyclic_id_cache", "cycid", ac, av) == -1) {
733*0Sstevel@tonic-gate 			mdb_warn("can't walk cyclic_id_cache");
734*0Sstevel@tonic-gate 			return (DCMD_ERR);
735*0Sstevel@tonic-gate 		}
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 		return (DCMD_OK);
738*0Sstevel@tonic-gate 	}
739*0Sstevel@tonic-gate 
740*0Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
741*0Sstevel@tonic-gate 		mdb_printf("%?s %4s %3s %?s %s\n", "ADDR", "CPU", "NDX",
742*0Sstevel@tonic-gate 		    "CYCLIC", "HANDLER");
743*0Sstevel@tonic-gate 	}
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	if (mdb_vread(&id, sizeof (id), addr) == -1) {
746*0Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_id_t at %p", addr);
747*0Sstevel@tonic-gate 		return (DCMD_ERR);
748*0Sstevel@tonic-gate 	}
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	if (id.cyi_cpu == NULL) {
751*0Sstevel@tonic-gate 		/*
752*0Sstevel@tonic-gate 		 * This is an omnipresent cyclic.
753*0Sstevel@tonic-gate 		 */
754*0Sstevel@tonic-gate 		mdb_printf("%?p %4s %3s %?s %a\n", addr, "omni", "-", "-",
755*0Sstevel@tonic-gate 		    id.cyi_omni_hdlr.cyo_online);
756*0Sstevel@tonic-gate 		mdb_printf("%?s    |\n", "");
757*0Sstevel@tonic-gate 		mdb_printf("%?s    +-->%4s %3s %?s %s\n", "",
758*0Sstevel@tonic-gate 		    "CPU", "NDX", "CYCLIC", "HANDLER");
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 		if (mdb_pwalk("cycomni",
761*0Sstevel@tonic-gate 		    (mdb_walk_cb_t)cycid_walk_omni, NULL, addr) == -1) {
762*0Sstevel@tonic-gate 			mdb_warn("couldn't walk cycomni for %p", addr);
763*0Sstevel@tonic-gate 			return (DCMD_ERR);
764*0Sstevel@tonic-gate 		}
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 		mdb_printf("\n");
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate 		return (DCMD_OK);
769*0Sstevel@tonic-gate 	}
770*0Sstevel@tonic-gate 
771*0Sstevel@tonic-gate 	mdb_printf("%?p ", addr);
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	return (cycid_cpu(id.cyi_cpu, id.cyi_ndx));
774*0Sstevel@tonic-gate }
775