xref: /onnv-gate/usr/src/cmd/mdb/common/modules/genunix/cyclic.c (revision 3277:153d1be61d60)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*3277Saf  * Common Development and Distribution License (the "License").
6*3277Saf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*3277Saf  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include "cyclic.h"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #define	CYCLIC_TRACE
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
330Sstevel@tonic-gate #include <sys/timer.h>
340Sstevel@tonic-gate #include <sys/cyclic_impl.h>
350Sstevel@tonic-gate #include <sys/sysmacros.h>
360Sstevel@tonic-gate #include <stdio.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate int
cyccpu_vread(cyc_cpu_t * cpu,uintptr_t addr)39*3277Saf cyccpu_vread(cyc_cpu_t *cpu, uintptr_t addr)
40*3277Saf {
41*3277Saf 	static int inited = 0;
42*3277Saf 	static int cyc_trace_enabled = 0;
43*3277Saf 	static size_t cyccpu_size;
44*3277Saf 
45*3277Saf 	if (!inited) {
46*3277Saf 		inited = 1;
47*3277Saf 		(void) mdb_readvar(&cyc_trace_enabled, "cyc_trace_enabled");
48*3277Saf 		cyccpu_size = (cyc_trace_enabled) ? sizeof (*cpu) :
49*3277Saf 		    OFFSETOF(cyc_cpu_t, cyp_trace);
50*3277Saf 	}
51*3277Saf 
52*3277Saf 	if (mdb_vread(cpu, cyccpu_size, addr) == -1)
53*3277Saf 		return (-1);
54*3277Saf 
55*3277Saf 	if (!cyc_trace_enabled)
56*3277Saf 		bzero(cpu->cyp_trace, sizeof (cpu->cyp_trace));
57*3277Saf 
58*3277Saf 	return (0);
59*3277Saf }
60*3277Saf 
61*3277Saf int
cyccpu_walk_init(mdb_walk_state_t * wsp)620Sstevel@tonic-gate cyccpu_walk_init(mdb_walk_state_t *wsp)
630Sstevel@tonic-gate {
640Sstevel@tonic-gate 	if (mdb_layered_walk("cpu", wsp) == -1) {
650Sstevel@tonic-gate 		mdb_warn("couldn't walk 'cpu'");
660Sstevel@tonic-gate 		return (WALK_ERR);
670Sstevel@tonic-gate 	}
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	return (WALK_NEXT);
700Sstevel@tonic-gate }
710Sstevel@tonic-gate 
720Sstevel@tonic-gate int
cyccpu_walk_step(mdb_walk_state_t * wsp)730Sstevel@tonic-gate cyccpu_walk_step(mdb_walk_state_t *wsp)
740Sstevel@tonic-gate {
750Sstevel@tonic-gate 	uintptr_t addr = (uintptr_t)((cpu_t *)wsp->walk_layer)->cpu_cyclic;
760Sstevel@tonic-gate 	cyc_cpu_t cpu;
770Sstevel@tonic-gate 
78*3277Saf 	if (cyccpu_vread(&cpu, addr) == -1) {
790Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
800Sstevel@tonic-gate 		return (WALK_ERR);
810Sstevel@tonic-gate 	}
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &cpu, wsp->walk_cbdata));
840Sstevel@tonic-gate }
850Sstevel@tonic-gate 
860Sstevel@tonic-gate int
cycomni_walk_init(mdb_walk_state_t * wsp)870Sstevel@tonic-gate cycomni_walk_init(mdb_walk_state_t *wsp)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	cyc_id_t id;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
920Sstevel@tonic-gate 		mdb_warn("must provide a cyclic id\n");
930Sstevel@tonic-gate 		return (WALK_ERR);
940Sstevel@tonic-gate 	}
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	if (mdb_vread(&id, sizeof (id), wsp->walk_addr) == -1) {
970Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_id_t at %p", wsp->walk_addr);
980Sstevel@tonic-gate 		return (WALK_ERR);
990Sstevel@tonic-gate 	}
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	if (id.cyi_cpu != NULL || id.cyi_omni_list == NULL ||
1020Sstevel@tonic-gate 	    id.cyi_omni_hdlr.cyo_online == NULL) {
1030Sstevel@tonic-gate 		mdb_warn("%p is not an omnipresent cyclic.\n", wsp->walk_addr);
1040Sstevel@tonic-gate 		return (WALK_ERR);
1050Sstevel@tonic-gate 	}
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)id.cyi_omni_list;
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 	return (WALK_NEXT);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate int
cycomni_walk_step(mdb_walk_state_t * wsp)1130Sstevel@tonic-gate cycomni_walk_step(mdb_walk_state_t *wsp)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
1160Sstevel@tonic-gate 	cyc_omni_cpu_t omni;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	if (addr == NULL)
1190Sstevel@tonic-gate 		return (WALK_DONE);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	if (mdb_vread(&omni, sizeof (omni), addr) == -1) {
1220Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_omni_cpu at %p", addr);
1230Sstevel@tonic-gate 		return (WALK_ERR);
1240Sstevel@tonic-gate 	}
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)omni.cyo_next;
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &omni, wsp->walk_cbdata));
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate void
cyclic_dump_node(cyc_cpu_t * cpu,cyc_index_t * heap,char ** c,size_t w,int ndx,int l,int r,int depth)1320Sstevel@tonic-gate cyclic_dump_node(cyc_cpu_t *cpu, cyc_index_t *heap, char **c, size_t w,
1330Sstevel@tonic-gate     int ndx, int l, int r, int depth)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate 	int heap_left, heap_right;
1360Sstevel@tonic-gate 	int me;
1370Sstevel@tonic-gate 	int i, x = l + (r - l) / 2;
1380Sstevel@tonic-gate 	size_t n = w - (x - 1); /* n bytes left for snprintf after c[][x - 1] */
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	heap_left = CYC_HEAP_LEFT(ndx);
1410Sstevel@tonic-gate 	heap_right = CYC_HEAP_RIGHT(ndx);
1420Sstevel@tonic-gate 	me = heap[ndx];
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if (ndx >= cpu->cyp_nelems)
1450Sstevel@tonic-gate 		return;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if (me < 10) {
1480Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, " %d", me);
1490Sstevel@tonic-gate 	} else if (me >= 100) {
1500Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, "%3d", me);
1510Sstevel@tonic-gate 	} else {
1520Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, "%s%2d%s",
1530Sstevel@tonic-gate 		    CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? " " : "", me,
1540Sstevel@tonic-gate 		    CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? "" : " ");
1550Sstevel@tonic-gate 	}
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	if (r - l > 5) {
1580Sstevel@tonic-gate 		c[++depth][x] = '|';
1590Sstevel@tonic-gate 		depth++;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 		for (i = l + (r - l) / 4; i < r - (r - l) / 4; i++)
1620Sstevel@tonic-gate 			c[depth][i] = '-';
1630Sstevel@tonic-gate 		c[depth][l + (r - l) / 4] = '+';
1640Sstevel@tonic-gate 		c[depth][r - (r - l) / 4 - 1] = '+';
1650Sstevel@tonic-gate 		c[depth][x] = '+';
1660Sstevel@tonic-gate 	} else {
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		if (heap_left >= cpu->cyp_nelems)
1690Sstevel@tonic-gate 			return;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 		(void) mdb_snprintf(&c[++depth][x - 1], n, "L%d",
1720Sstevel@tonic-gate 		    heap[heap_left]);
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 		if (heap_right >= cpu->cyp_nelems)
1750Sstevel@tonic-gate 			return;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 		(void) mdb_snprintf(&c[++depth][x - 1], n, "R%d",
1780Sstevel@tonic-gate 		    heap[heap_right]);
1790Sstevel@tonic-gate 		return;
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	if (heap_left < cpu->cyp_nelems)
1830Sstevel@tonic-gate 		cyclic_dump_node(cpu, heap, c, w, heap_left, l, x, depth + 1);
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate 	if (heap_right < cpu->cyp_nelems)
1860Sstevel@tonic-gate 		cyclic_dump_node(cpu, heap, c, w, heap_right, x, r, depth + 1);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate #define	LINES_PER_LEVEL 3
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate void
cyclic_pretty_dump(cyc_cpu_t * cpu)1920Sstevel@tonic-gate cyclic_pretty_dump(cyc_cpu_t *cpu)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	char **c;
1950Sstevel@tonic-gate 	int i, j;
1960Sstevel@tonic-gate 	int width = 80;
1970Sstevel@tonic-gate 	int depth;
1980Sstevel@tonic-gate 	cyc_index_t *heap;
1990Sstevel@tonic-gate 	size_t hsize = sizeof (cyc_index_t) * cpu->cyp_size;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	heap = mdb_alloc(hsize, UM_SLEEP | UM_GC);
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate 	if (mdb_vread(heap, hsize, (uintptr_t)cpu->cyp_heap) == -1) {
2040Sstevel@tonic-gate 		mdb_warn("couldn't read heap at %p", (uintptr_t)cpu->cyp_heap);
2050Sstevel@tonic-gate 		return;
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	for (depth = 0; (1 << depth) < cpu->cyp_nelems; depth++)
2090Sstevel@tonic-gate 		continue;
2100Sstevel@tonic-gate 	depth++;
2110Sstevel@tonic-gate 	depth = (depth + 1) * LINES_PER_LEVEL;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	c = mdb_zalloc(sizeof (char *) * depth, UM_SLEEP|UM_GC);
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
2160Sstevel@tonic-gate 		c[i] = mdb_zalloc(width, UM_SLEEP|UM_GC);
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	cyclic_dump_node(cpu, heap, c, width, 0, 1, width - 2, 0);
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	for (i = 0; i < depth; i++) {
2210Sstevel@tonic-gate 		int dump = 0;
2220Sstevel@tonic-gate 		for (j = 0; j < width - 1; j++) {
2230Sstevel@tonic-gate 			if (c[i][j] == '\0')
2240Sstevel@tonic-gate 				c[i][j] = ' ';
2250Sstevel@tonic-gate 			else
2260Sstevel@tonic-gate 				dump = 1;
2270Sstevel@tonic-gate 		}
2280Sstevel@tonic-gate 		c[i][width - 2] = '\n';
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 		if (dump)
2310Sstevel@tonic-gate 			mdb_printf(c[i]);
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate  * Yes, this is very weak.  Full 16-column-wide 64-bit addresses screw up
2370Sstevel@tonic-gate  * ::cycinfo's very carefully planned 80-column layout.  We set the column
2380Sstevel@tonic-gate  * width for addresses to be 11 (instead of 16), knowing that the kernel
2390Sstevel@tonic-gate  * heap (from which these data structures are allocated) starts at
2400Sstevel@tonic-gate  * 0x0000030000000000, and isn't likely to extend to 0x0000100000000000.
2410Sstevel@tonic-gate  */
2420Sstevel@tonic-gate #ifdef _LP64
2430Sstevel@tonic-gate #define	CYC_ADDR_WIDTH	11
2440Sstevel@tonic-gate #else
2450Sstevel@tonic-gate #define	CYC_ADDR_WIDTH	8
2460Sstevel@tonic-gate #endif
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate int
cycinfo(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2490Sstevel@tonic-gate cycinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2500Sstevel@tonic-gate {
2510Sstevel@tonic-gate 	cyc_cpu_t cpu;
2520Sstevel@tonic-gate 	cpu_t c;
2530Sstevel@tonic-gate 	cyc_index_t root, i, *heap;
2540Sstevel@tonic-gate 	size_t hsize;
2550Sstevel@tonic-gate 	cyclic_t *cyc;
2560Sstevel@tonic-gate 	uintptr_t caddr;
2570Sstevel@tonic-gate 	uint_t verbose = FALSE, Verbose = FALSE;
2580Sstevel@tonic-gate 	int header = 0;
2590Sstevel@tonic-gate 	cyc_level_t lev;
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
2620Sstevel@tonic-gate 		if (mdb_walk_dcmd("cyccpu", "cycinfo", argc, argv) == -1) {
2630Sstevel@tonic-gate 			mdb_warn("can't walk 'cyccpu'");
2640Sstevel@tonic-gate 			return (DCMD_ERR);
2650Sstevel@tonic-gate 		}
2660Sstevel@tonic-gate 		return (DCMD_OK);
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
2700Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
2710Sstevel@tonic-gate 	    'V', MDB_OPT_SETBITS, TRUE, &Verbose, NULL) != argc)
2720Sstevel@tonic-gate 		return (DCMD_USAGE);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	if (!DCMD_HDRSPEC(flags) && (verbose || Verbose))
2750Sstevel@tonic-gate 		mdb_printf("\n\n");
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) || verbose || Verbose)
2780Sstevel@tonic-gate 		mdb_printf("%3s %*s %7s %6s %*s %15s %s\n", "CPU",
2790Sstevel@tonic-gate 		    CYC_ADDR_WIDTH, "CYC_CPU", "STATE", "NELEMS",
2800Sstevel@tonic-gate 		    CYC_ADDR_WIDTH, "ROOT", "FIRE", "HANDLER");
2810Sstevel@tonic-gate 
282*3277Saf 	if (cyccpu_vread(&cpu, addr) == -1) {
2830Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
2840Sstevel@tonic-gate 		return (DCMD_ERR);
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) {
2880Sstevel@tonic-gate 		mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu);
2890Sstevel@tonic-gate 		return (DCMD_ERR);
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	cyc = mdb_alloc(sizeof (cyclic_t) * cpu.cyp_size, UM_SLEEP | UM_GC);
2930Sstevel@tonic-gate 	caddr = (uintptr_t)cpu.cyp_cyclics;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	if (mdb_vread(cyc, sizeof (cyclic_t) * cpu.cyp_size, caddr) == -1) {
2960Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", caddr);
2970Sstevel@tonic-gate 		return (DCMD_ERR);
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	hsize = sizeof (cyc_index_t) * cpu.cyp_size;
3010Sstevel@tonic-gate 	heap = mdb_alloc(hsize, UM_SLEEP | UM_GC);
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate 	if (mdb_vread(heap, hsize, (uintptr_t)cpu.cyp_heap) == -1) {
3040Sstevel@tonic-gate 		mdb_warn("couldn't read heap at %p", cpu.cyp_heap);
3050Sstevel@tonic-gate 		return (DCMD_ERR);
3060Sstevel@tonic-gate 	}
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	root = heap[0];
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	mdb_printf("%3d %0*p %7s %6d ", c.cpu_id, CYC_ADDR_WIDTH, addr,
3110Sstevel@tonic-gate 	    cpu.cyp_state == CYS_ONLINE ? "online" :
3120Sstevel@tonic-gate 	    cpu.cyp_state == CYS_OFFLINE ? "offline" :
3130Sstevel@tonic-gate 	    cpu.cyp_state == CYS_EXPANDING ? "expand" :
3140Sstevel@tonic-gate 	    cpu.cyp_state == CYS_REMOVING ? "remove" :
3150Sstevel@tonic-gate 	    cpu.cyp_state == CYS_SUSPENDED ? "suspend" : "????",
3160Sstevel@tonic-gate 	    cpu.cyp_nelems);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	if (cpu.cyp_nelems > 0)
3190Sstevel@tonic-gate 		mdb_printf("%0*p %15llx %a\n", CYC_ADDR_WIDTH,
3200Sstevel@tonic-gate 		    caddr, cyc[root].cy_expire, cyc[root].cy_handler);
3210Sstevel@tonic-gate 	else
3220Sstevel@tonic-gate 		mdb_printf("%*s %15s %s\n", CYC_ADDR_WIDTH, "-", "-", "-");
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	if (!verbose && !Verbose)
3250Sstevel@tonic-gate 		return (DCMD_OK);
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	mdb_printf("\n");
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	cyclic_pretty_dump(&cpu);
3300Sstevel@tonic-gate 
3310Sstevel@tonic-gate 	mdb_inc_indent(2);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	for (i = 0; i < cpu.cyp_size; i++) {
3340Sstevel@tonic-gate 		int j;
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 		for (j = 0; j < cpu.cyp_size; j++) {
3370Sstevel@tonic-gate 			if (heap[j] == i)
3380Sstevel@tonic-gate 				break;
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		if (!Verbose && j >= cpu.cyp_nelems)
3420Sstevel@tonic-gate 			continue;
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 		if (!header) {
3450Sstevel@tonic-gate 			header = 1;
3460Sstevel@tonic-gate 			mdb_printf("\n%*s %3s %4s %4s %5s %15s %7s %s\n",
3470Sstevel@tonic-gate 			    CYC_ADDR_WIDTH, "ADDR", "NDX", "HEAP", "LEVL",
3480Sstevel@tonic-gate 			    "PEND", "FIRE", "USECINT", "HANDLER");
3490Sstevel@tonic-gate 		}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 		mdb_printf("%0*p %3d ", CYC_ADDR_WIDTH,
3520Sstevel@tonic-gate 		    caddr + i * sizeof (cyclic_t), i);
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 		mdb_printf("%4d ", j);
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 		if (j >= cpu.cyp_nelems) {
3570Sstevel@tonic-gate 			mdb_printf("%4s %5s %15s %7s %s\n", "-", "-",
3580Sstevel@tonic-gate 			    "-", "-", "-");
3590Sstevel@tonic-gate 			continue;
3600Sstevel@tonic-gate 		}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		mdb_printf("%4s %5d %15llx ",
3630Sstevel@tonic-gate 		    cyc[i].cy_level == CY_HIGH_LEVEL ? "high" :
3640Sstevel@tonic-gate 		    cyc[i].cy_level == CY_LOCK_LEVEL ? "lock" :
3650Sstevel@tonic-gate 		    cyc[i].cy_level == CY_LOW_LEVEL ? "low" : "????",
3660Sstevel@tonic-gate 		    cyc[i].cy_pend, cyc[i].cy_expire);
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 		if (cyc[i].cy_interval + cyc[i].cy_expire != INT64_MAX)
3690Sstevel@tonic-gate 			mdb_printf("%7lld ", cyc[i].cy_interval /
3700Sstevel@tonic-gate 			    (uint64_t)(NANOSEC / MICROSEC));
3710Sstevel@tonic-gate 		else
3720Sstevel@tonic-gate 			mdb_printf("%7s ", "-");
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 		mdb_printf("%a\n", cyc[i].cy_handler);
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	if (!Verbose)
3790Sstevel@tonic-gate 		goto out;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	for (lev = CY_LOW_LEVEL; lev < CY_LOW_LEVEL + CY_SOFT_LEVELS; lev++) {
3820Sstevel@tonic-gate 		cyc_softbuf_t *softbuf = &cpu.cyp_softbuf[lev];
3830Sstevel@tonic-gate 		char which = softbuf->cys_hard, shared = 1;
3840Sstevel@tonic-gate 		cyc_pcbuffer_t *pc;
3850Sstevel@tonic-gate 		size_t bufsiz;
3860Sstevel@tonic-gate 		cyc_index_t *buf;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 		if (softbuf->cys_hard != softbuf->cys_soft)
3890Sstevel@tonic-gate 			shared = 0;
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate again:
3920Sstevel@tonic-gate 		pc = &softbuf->cys_buf[which];
3930Sstevel@tonic-gate 		bufsiz = (pc->cypc_sizemask + 1) * sizeof (cyc_index_t);
3940Sstevel@tonic-gate 		buf = mdb_alloc(bufsiz, UM_SLEEP | UM_GC);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 		if (mdb_vread(buf, bufsiz, (uintptr_t)pc->cypc_buf) == -1) {
3970Sstevel@tonic-gate 			mdb_warn("couldn't read cypc_buf at %p", pc->cypc_buf);
3980Sstevel@tonic-gate 			continue;
3990Sstevel@tonic-gate 		}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 		mdb_printf("\n%3s %4s %4s %4s %*s %4s %*s\n", "CPU",
4020Sstevel@tonic-gate 		    "LEVL", "USER", "NDX", CYC_ADDR_WIDTH, "ADDR", "CYC",
4030Sstevel@tonic-gate 		    CYC_ADDR_WIDTH, "CYC_ADDR", "PEND");
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 		for (i = 0; i <= pc->cypc_sizemask &&
4060Sstevel@tonic-gate 		    i <= pc->cypc_prodndx; i++) {
4070Sstevel@tonic-gate 			uintptr_t cyc_addr = caddr + buf[i] * sizeof (cyclic_t);
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 			mdb_printf("%3d %4s %4s ", c.cpu_id,
4100Sstevel@tonic-gate 			    lev == CY_HIGH_LEVEL ? "high" :
4110Sstevel@tonic-gate 			    lev == CY_LOCK_LEVEL ? "lock" :
4120Sstevel@tonic-gate 			    lev == CY_LOW_LEVEL ? "low" : "????",
4130Sstevel@tonic-gate 			    shared ? "shrd" : which == softbuf->cys_hard ?
4140Sstevel@tonic-gate 			    "hard" : "soft");
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 			mdb_printf("%4d %0*p ", i, CYC_ADDR_WIDTH,
4170Sstevel@tonic-gate 			    (uintptr_t)&buf[i] - (uintptr_t)&buf[0] +
4180Sstevel@tonic-gate 			    (uintptr_t)pc->cypc_buf, buf[i],
4190Sstevel@tonic-gate 			    caddr + buf[i] * sizeof (cyclic_t));
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 			if (i >= pc->cypc_prodndx)
4220Sstevel@tonic-gate 				mdb_printf("%4s %*s %5s  ",
4230Sstevel@tonic-gate 				    "-", CYC_ADDR_WIDTH, "-", "-");
4240Sstevel@tonic-gate 			else {
4250Sstevel@tonic-gate 				cyclic_t c;
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 				if (mdb_vread(&c, sizeof (c), cyc_addr) == -1) {
4280Sstevel@tonic-gate 					mdb_warn("\ncouldn't read cyclic at "
4290Sstevel@tonic-gate 					    "%p", cyc_addr);
4300Sstevel@tonic-gate 					continue;
4310Sstevel@tonic-gate 				}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 				mdb_printf("%4d %0*p %5d  ", buf[i],
4340Sstevel@tonic-gate 				    CYC_ADDR_WIDTH, cyc_addr, c.cy_pend);
4350Sstevel@tonic-gate 			}
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 			if (i == (pc->cypc_consndx & pc->cypc_sizemask)) {
4380Sstevel@tonic-gate 				mdb_printf("<-- consndx");
4390Sstevel@tonic-gate 				if (i == (pc->cypc_prodndx & pc->cypc_sizemask))
4400Sstevel@tonic-gate 					mdb_printf(",prodndx");
4410Sstevel@tonic-gate 				mdb_printf("\n");
4420Sstevel@tonic-gate 				continue;
4430Sstevel@tonic-gate 			}
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 			if (i == (pc->cypc_prodndx & pc->cypc_sizemask)) {
4460Sstevel@tonic-gate 				mdb_printf("<-- prodndx\n");
4470Sstevel@tonic-gate 				continue;
4480Sstevel@tonic-gate 			}
4490Sstevel@tonic-gate 			mdb_printf("\n");
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 			if (i >= pc->cypc_prodndx)
4520Sstevel@tonic-gate 				break;
4530Sstevel@tonic-gate 		}
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 		if (!shared && which == softbuf->cys_hard) {
4560Sstevel@tonic-gate 			which = softbuf->cys_soft;
4570Sstevel@tonic-gate 			goto again;
4580Sstevel@tonic-gate 		}
4590Sstevel@tonic-gate 	}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate out:
4620Sstevel@tonic-gate 	mdb_dec_indent(2);
4630Sstevel@tonic-gate 	return (DCMD_OK);
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate int
cyctrace_walk_init(mdb_walk_state_t * wsp)4670Sstevel@tonic-gate cyctrace_walk_init(mdb_walk_state_t *wsp)
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate 	cyc_cpu_t *cpu;
4700Sstevel@tonic-gate 	int i;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	cpu = mdb_zalloc(sizeof (cyc_cpu_t), UM_SLEEP);
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	if (wsp->walk_addr == NULL) {
4750Sstevel@tonic-gate 		/*
4760Sstevel@tonic-gate 		 * If an address isn't provided, we'll use the passive buffer.
4770Sstevel@tonic-gate 		 */
4780Sstevel@tonic-gate 		GElf_Sym sym;
4790Sstevel@tonic-gate 		cyc_tracebuf_t *tr = &cpu->cyp_trace[0];
4800Sstevel@tonic-gate 		uintptr_t addr;
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate 		if (mdb_lookup_by_name("cyc_ptrace", &sym) == -1) {
4830Sstevel@tonic-gate 			mdb_warn("couldn't find passive buffer");
4840Sstevel@tonic-gate 			return (-1);
4850Sstevel@tonic-gate 		}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 		addr = (uintptr_t)sym.st_value;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 		if (mdb_vread(tr, sizeof (cyc_tracebuf_t), addr) == -1) {
4900Sstevel@tonic-gate 			mdb_warn("couldn't read passive buffer");
4910Sstevel@tonic-gate 			return (-1);
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		wsp->walk_addr = addr - offsetof(cyc_cpu_t, cyp_trace[0]);
4950Sstevel@tonic-gate 	} else {
496*3277Saf 		if (cyccpu_vread(cpu, wsp->walk_addr) == -1) {
4970Sstevel@tonic-gate 			mdb_warn("couldn't read cyc_cpu at %p", wsp->walk_addr);
4980Sstevel@tonic-gate 			mdb_free(cpu, sizeof (cyc_cpu_t));
4990Sstevel@tonic-gate 			return (-1);
5000Sstevel@tonic-gate 		}
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	for (i = 0; i < CY_LEVELS; i++) {
5040Sstevel@tonic-gate 		if (cpu->cyp_trace[i].cyt_ndx-- == 0)
5050Sstevel@tonic-gate 			cpu->cyp_trace[i].cyt_ndx = CY_NTRACEREC - 1;
5060Sstevel@tonic-gate 	}
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate 	wsp->walk_data = cpu;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 	return (0);
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate int
cyctrace_walk_step(mdb_walk_state_t * wsp)5140Sstevel@tonic-gate cyctrace_walk_step(mdb_walk_state_t *wsp)
5150Sstevel@tonic-gate {
5160Sstevel@tonic-gate 	cyc_cpu_t *cpu = wsp->walk_data;
5170Sstevel@tonic-gate 	cyc_tracebuf_t *buf = cpu->cyp_trace;
5180Sstevel@tonic-gate 	hrtime_t latest = 0;
5190Sstevel@tonic-gate 	int i, ndx, new_ndx, lev, rval;
5200Sstevel@tonic-gate 	uintptr_t addr;
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	for (i = 0; i < CY_LEVELS; i++) {
5230Sstevel@tonic-gate 		if ((ndx = buf[i].cyt_ndx) == -1)
5240Sstevel@tonic-gate 			continue;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 		/*
5270Sstevel@tonic-gate 		 * Account for NPT.
5280Sstevel@tonic-gate 		 */
5290Sstevel@tonic-gate 		buf[i].cyt_buf[ndx].cyt_tstamp <<= 1;
5300Sstevel@tonic-gate 		buf[i].cyt_buf[ndx].cyt_tstamp >>= 1;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 		if (buf[i].cyt_buf[ndx].cyt_tstamp > latest) {
5330Sstevel@tonic-gate 			latest = buf[i].cyt_buf[ndx].cyt_tstamp;
5340Sstevel@tonic-gate 			lev = i;
5350Sstevel@tonic-gate 		}
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	/*
5390Sstevel@tonic-gate 	 * If we didn't find one, we're done.
5400Sstevel@tonic-gate 	 */
5410Sstevel@tonic-gate 	if (latest == 0)
5420Sstevel@tonic-gate 		return (-1);
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate 	buf = &buf[lev];
5450Sstevel@tonic-gate 	ndx = buf->cyt_ndx;
5460Sstevel@tonic-gate 	addr = wsp->walk_addr +
5470Sstevel@tonic-gate 	    (uintptr_t)&(buf->cyt_buf[ndx]) - (uintptr_t)cpu;
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	rval = wsp->walk_callback(addr, &buf->cyt_buf[ndx], wsp->walk_cbdata);
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	new_ndx = ndx == 0 ? CY_NTRACEREC - 1 : ndx - 1;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	if (buf->cyt_buf[new_ndx].cyt_tstamp != 0 &&
5540Sstevel@tonic-gate 	    buf->cyt_buf[new_ndx].cyt_tstamp > buf->cyt_buf[ndx].cyt_tstamp)
5550Sstevel@tonic-gate 		new_ndx = -1;
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	buf->cyt_ndx = new_ndx;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	return (rval);
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate void
cyctrace_walk_fini(mdb_walk_state_t * wsp)5630Sstevel@tonic-gate cyctrace_walk_fini(mdb_walk_state_t *wsp)
5640Sstevel@tonic-gate {
5650Sstevel@tonic-gate 	cyc_cpu_t *cpu = wsp->walk_data;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	mdb_free(cpu, sizeof (cyc_cpu_t));
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate #define	WHYLEN	17
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate int
cyctrace_walk(uintptr_t addr,const cyc_tracerec_t * rec,cyc_cpu_t * cpu)5730Sstevel@tonic-gate cyctrace_walk(uintptr_t addr, const cyc_tracerec_t *rec, cyc_cpu_t *cpu)
5740Sstevel@tonic-gate {
5750Sstevel@tonic-gate 	int i;
5760Sstevel@tonic-gate 	char c[WHYLEN];
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	for (i = 0; cpu != NULL && i < CY_LEVELS; i++)
5790Sstevel@tonic-gate 		if (addr < (uintptr_t)&cpu->cyp_trace[i + 1].cyt_buf[0])
5800Sstevel@tonic-gate 			break;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	(void) mdb_readstr(c, WHYLEN, (uintptr_t)rec->cyt_why);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	mdb_printf("%08p %4s %15llx %-*s %15llx %15llx\n",
5850Sstevel@tonic-gate 	    addr & UINT_MAX, cpu == NULL ? "pasv" :
5860Sstevel@tonic-gate 	    i == CY_HIGH_LEVEL ? "high" : i == CY_LOCK_LEVEL ? "lock" :
5870Sstevel@tonic-gate 	    i == CY_LOW_LEVEL ? "low" : "????", rec->cyt_tstamp, WHYLEN, c,
5880Sstevel@tonic-gate 	    rec->cyt_arg0, rec->cyt_arg1);
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	return (0);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate /*ARGSUSED*/
5940Sstevel@tonic-gate int
cyctrace(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5950Sstevel@tonic-gate cyctrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5960Sstevel@tonic-gate {
5970Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
5980Sstevel@tonic-gate 		addr = NULL;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (mdb_pwalk("cyctrace", (mdb_walk_cb_t)cyctrace_walk,
6010Sstevel@tonic-gate 	    (void *)addr, addr) == -1) {
6020Sstevel@tonic-gate 		mdb_warn("couldn't walk cyctrace");
6030Sstevel@tonic-gate 		return (DCMD_ERR);
6040Sstevel@tonic-gate 	}
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 	return (DCMD_OK);
6070Sstevel@tonic-gate }
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate int
cyccover_comp(const void * l,const void * r)6100Sstevel@tonic-gate cyccover_comp(const void *l, const void *r)
6110Sstevel@tonic-gate {
6120Sstevel@tonic-gate 	cyc_coverage_t *lhs = (cyc_coverage_t *)l;
6130Sstevel@tonic-gate 	cyc_coverage_t *rhs = (cyc_coverage_t *)r;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	char ly[WHYLEN], ry[WHYLEN];
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	if (rhs->cyv_why == lhs->cyv_why)
6180Sstevel@tonic-gate 		return (0);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (rhs->cyv_why == NULL)
6210Sstevel@tonic-gate 		return (-1);
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	if (lhs->cyv_why == NULL)
6240Sstevel@tonic-gate 		return (1);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	(void) mdb_readstr(ly, WHYLEN, (uintptr_t)lhs->cyv_why);
6270Sstevel@tonic-gate 	(void) mdb_readstr(ry, WHYLEN, (uintptr_t)rhs->cyv_why);
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	return (strcmp(ly, ry));
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate /*ARGSUSED*/
6330Sstevel@tonic-gate int
cyccover(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6340Sstevel@tonic-gate cyccover(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6350Sstevel@tonic-gate {
6360Sstevel@tonic-gate 	cyc_coverage_t cv[CY_NCOVERAGE];
6370Sstevel@tonic-gate 	char c[WHYLEN];
6380Sstevel@tonic-gate 	GElf_Sym sym;
6390Sstevel@tonic-gate 	int i;
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
6420Sstevel@tonic-gate 		return (DCMD_USAGE);
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	if (mdb_lookup_by_name("cyc_coverage", &sym) == -1) {
6450Sstevel@tonic-gate 		mdb_warn("couldn't find coverage information");
6460Sstevel@tonic-gate 		return (DCMD_ABORT);
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	addr = (uintptr_t)sym.st_value;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	if (mdb_vread(cv, sizeof (cyc_coverage_t) * CY_NCOVERAGE, addr) == -1) {
6520Sstevel@tonic-gate 		mdb_warn("couldn't read coverage array at %p", addr);
6530Sstevel@tonic-gate 		return (DCMD_ABORT);
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	mdb_printf("%-*s %8s %8s %8s %15s %15s\n",
6570Sstevel@tonic-gate 	    WHYLEN, "POINT", "HIGH", "LOCK", "LOW/PASV", "ARG0", "ARG1");
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	qsort(cv, CY_NCOVERAGE, sizeof (cyc_coverage_t), cyccover_comp);
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	for (i = 0; i < CY_NCOVERAGE; i++) {
6620Sstevel@tonic-gate 		if (cv[i].cyv_why != NULL) {
6630Sstevel@tonic-gate 			(void) mdb_readstr(c, WHYLEN, (uintptr_t)cv[i].cyv_why);
6640Sstevel@tonic-gate 			mdb_printf("%-*s %8d %8d %8d %15llx %15llx\n",
6650Sstevel@tonic-gate 			    WHYLEN, c,
6660Sstevel@tonic-gate 			    cv[i].cyv_count[CY_HIGH_LEVEL],
6670Sstevel@tonic-gate 			    cv[i].cyv_count[CY_LOCK_LEVEL],
6680Sstevel@tonic-gate 			    cv[i].cyv_passive_count != 0 ?
6690Sstevel@tonic-gate 			    cv[i].cyv_passive_count :
6700Sstevel@tonic-gate 			    cv[i].cyv_count[CY_LOW_LEVEL],
6710Sstevel@tonic-gate 			    cv[i].cyv_arg0, cv[i].cyv_arg1);
6720Sstevel@tonic-gate 		}
6730Sstevel@tonic-gate 	}
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	return (DCMD_OK);
6760Sstevel@tonic-gate }
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate /*ARGSUSED*/
6790Sstevel@tonic-gate int
cyclic(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6800Sstevel@tonic-gate cyclic(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6810Sstevel@tonic-gate {
6820Sstevel@tonic-gate 	cyclic_t cyc;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
6850Sstevel@tonic-gate 		return (DCMD_USAGE);
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
6880Sstevel@tonic-gate 		mdb_printf("%?s %4s %5s %5s %15s %7s %s\n", "ADDR", "LEVL",
6890Sstevel@tonic-gate 		    "PEND", "FLAGS", "FIRE", "USECINT", "HANDLER");
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	if (mdb_vread(&cyc, sizeof (cyclic_t), addr) == -1) {
6920Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", addr);
6930Sstevel@tonic-gate 		return (DCMD_ERR);
6940Sstevel@tonic-gate 	}
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	mdb_printf("%0?p %4s %5d  %04x %15llx %7lld %a\n", addr,
6970Sstevel@tonic-gate 	    cyc.cy_level == CY_HIGH_LEVEL ? "high" :
6980Sstevel@tonic-gate 	    cyc.cy_level == CY_LOCK_LEVEL ? "lock" :
6990Sstevel@tonic-gate 	    cyc.cy_level == CY_LOW_LEVEL ? "low" : "????",
7000Sstevel@tonic-gate 	    cyc.cy_pend, cyc.cy_flags, cyc.cy_expire,
7010Sstevel@tonic-gate 	    cyc.cy_interval / (uint64_t)(NANOSEC / MICROSEC),
7020Sstevel@tonic-gate 	    cyc.cy_handler);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	return (DCMD_OK);
7050Sstevel@tonic-gate }
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate static int
cycid_cpu(cyc_cpu_t * addr,int ndx)7080Sstevel@tonic-gate cycid_cpu(cyc_cpu_t *addr, int ndx)
7090Sstevel@tonic-gate {
7100Sstevel@tonic-gate 	cyc_cpu_t cpu;
7110Sstevel@tonic-gate 	cpu_t c;
7120Sstevel@tonic-gate 	uintptr_t caddr;
7130Sstevel@tonic-gate 	cyclic_t cyc;
7140Sstevel@tonic-gate 
715*3277Saf 	if (cyccpu_vread(&cpu, (uintptr_t)addr) == -1) {
7160Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
7170Sstevel@tonic-gate 		return (DCMD_ERR);
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) {
7210Sstevel@tonic-gate 		mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu);
7220Sstevel@tonic-gate 		return (DCMD_ERR);
7230Sstevel@tonic-gate 	}
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	caddr = (uintptr_t)cpu.cyp_cyclics + ndx * sizeof (cyclic_t);
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	if (mdb_vread(&cyc, sizeof (cyc), caddr) == -1) {
7280Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", caddr);
7290Sstevel@tonic-gate 		return (DCMD_ERR);
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	mdb_printf("%4d %3d %?p %a\n", c.cpu_id, ndx, caddr, cyc.cy_handler);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	return (DCMD_OK);
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate /*ARGSUSED*/
7380Sstevel@tonic-gate static int
cycid_walk_omni(uintptr_t addr,const cyc_omni_cpu_t * omni,int * ignored)7390Sstevel@tonic-gate cycid_walk_omni(uintptr_t addr, const cyc_omni_cpu_t *omni, int *ignored)
7400Sstevel@tonic-gate {
7410Sstevel@tonic-gate 	mdb_printf("%?s        ");
7420Sstevel@tonic-gate 	cycid_cpu(omni->cyo_cpu, omni->cyo_ndx);
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	return (WALK_NEXT);
7450Sstevel@tonic-gate }
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate /*ARGSUSED*/
7480Sstevel@tonic-gate int
cycid(uintptr_t addr,uint_t flags,int ac,const mdb_arg_t * av)7490Sstevel@tonic-gate cycid(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
7500Sstevel@tonic-gate {
7510Sstevel@tonic-gate 	cyc_id_t id;
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
7540Sstevel@tonic-gate 		if (mdb_walk_dcmd("cyclic_id_cache", "cycid", ac, av) == -1) {
7550Sstevel@tonic-gate 			mdb_warn("can't walk cyclic_id_cache");
7560Sstevel@tonic-gate 			return (DCMD_ERR);
7570Sstevel@tonic-gate 		}
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 		return (DCMD_OK);
7600Sstevel@tonic-gate 	}
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
7630Sstevel@tonic-gate 		mdb_printf("%?s %4s %3s %?s %s\n", "ADDR", "CPU", "NDX",
7640Sstevel@tonic-gate 		    "CYCLIC", "HANDLER");
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	if (mdb_vread(&id, sizeof (id), addr) == -1) {
7680Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_id_t at %p", addr);
7690Sstevel@tonic-gate 		return (DCMD_ERR);
7700Sstevel@tonic-gate 	}
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	if (id.cyi_cpu == NULL) {
7730Sstevel@tonic-gate 		/*
7740Sstevel@tonic-gate 		 * This is an omnipresent cyclic.
7750Sstevel@tonic-gate 		 */
7760Sstevel@tonic-gate 		mdb_printf("%?p %4s %3s %?s %a\n", addr, "omni", "-", "-",
7770Sstevel@tonic-gate 		    id.cyi_omni_hdlr.cyo_online);
7780Sstevel@tonic-gate 		mdb_printf("%?s    |\n", "");
7790Sstevel@tonic-gate 		mdb_printf("%?s    +-->%4s %3s %?s %s\n", "",
7800Sstevel@tonic-gate 		    "CPU", "NDX", "CYCLIC", "HANDLER");
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 		if (mdb_pwalk("cycomni",
7830Sstevel@tonic-gate 		    (mdb_walk_cb_t)cycid_walk_omni, NULL, addr) == -1) {
7840Sstevel@tonic-gate 			mdb_warn("couldn't walk cycomni for %p", addr);
7850Sstevel@tonic-gate 			return (DCMD_ERR);
7860Sstevel@tonic-gate 		}
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 		mdb_printf("\n");
7890Sstevel@tonic-gate 
7900Sstevel@tonic-gate 		return (DCMD_OK);
7910Sstevel@tonic-gate 	}
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	mdb_printf("%?p ", addr);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	return (cycid_cpu(id.cyi_cpu, id.cyi_ndx));
7960Sstevel@tonic-gate }
797