17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
58a6a72fdSaf  * Common Development and Distribution License (the "License").
68a6a72fdSaf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
228a6a72fdSaf  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26*fe73c3d8SBryan Cantrill /*
27*fe73c3d8SBryan Cantrill  * Copyright 2023 Oxide Computer Company
28*fe73c3d8SBryan Cantrill  */
29*fe73c3d8SBryan Cantrill 
307c478bd9Sstevel@tonic-gate #include "cyclic.h"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #define	CYCLIC_TRACE
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
357c478bd9Sstevel@tonic-gate #include <sys/timer.h>
367c478bd9Sstevel@tonic-gate #include <sys/cyclic_impl.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <stdio.h>
397c478bd9Sstevel@tonic-gate 
408a6a72fdSaf int
cyccpu_vread(cyc_cpu_t * cpu,uintptr_t addr)418a6a72fdSaf cyccpu_vread(cyc_cpu_t *cpu, uintptr_t addr)
428a6a72fdSaf {
438a6a72fdSaf 	static int inited = 0;
448a6a72fdSaf 	static int cyc_trace_enabled = 0;
458a6a72fdSaf 	static size_t cyccpu_size;
468a6a72fdSaf 
478a6a72fdSaf 	if (!inited) {
488a6a72fdSaf 		inited = 1;
498a6a72fdSaf 		(void) mdb_readvar(&cyc_trace_enabled, "cyc_trace_enabled");
508a6a72fdSaf 		cyccpu_size = (cyc_trace_enabled) ? sizeof (*cpu) :
518a6a72fdSaf 		    OFFSETOF(cyc_cpu_t, cyp_trace);
528a6a72fdSaf 	}
538a6a72fdSaf 
548a6a72fdSaf 	if (mdb_vread(cpu, cyccpu_size, addr) == -1)
558a6a72fdSaf 		return (-1);
568a6a72fdSaf 
578a6a72fdSaf 	if (!cyc_trace_enabled)
588a6a72fdSaf 		bzero(cpu->cyp_trace, sizeof (cpu->cyp_trace));
598a6a72fdSaf 
608a6a72fdSaf 	return (0);
618a6a72fdSaf }
628a6a72fdSaf 
637c478bd9Sstevel@tonic-gate int
cyccpu_walk_init(mdb_walk_state_t * wsp)647c478bd9Sstevel@tonic-gate cyccpu_walk_init(mdb_walk_state_t *wsp)
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	if (mdb_layered_walk("cpu", wsp) == -1) {
677c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk 'cpu'");
687c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
697c478bd9Sstevel@tonic-gate 	}
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate int
cyccpu_walk_step(mdb_walk_state_t * wsp)757c478bd9Sstevel@tonic-gate cyccpu_walk_step(mdb_walk_state_t *wsp)
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate 	uintptr_t addr = (uintptr_t)((cpu_t *)wsp->walk_layer)->cpu_cyclic;
787c478bd9Sstevel@tonic-gate 	cyc_cpu_t cpu;
797c478bd9Sstevel@tonic-gate 
808a6a72fdSaf 	if (cyccpu_vread(&cpu, addr) == -1) {
817c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
827c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
837c478bd9Sstevel@tonic-gate 	}
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &cpu, wsp->walk_cbdata));
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate int
cycomni_walk_init(mdb_walk_state_t * wsp)897c478bd9Sstevel@tonic-gate cycomni_walk_init(mdb_walk_state_t *wsp)
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate 	cyc_id_t id;
927c478bd9Sstevel@tonic-gate 
93892ad162SToomas Soome 	if (wsp->walk_addr == 0) {
947c478bd9Sstevel@tonic-gate 		mdb_warn("must provide a cyclic id\n");
957c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
967c478bd9Sstevel@tonic-gate 	}
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	if (mdb_vread(&id, sizeof (id), wsp->walk_addr) == -1) {
997c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_id_t at %p", wsp->walk_addr);
1007c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if (id.cyi_cpu != NULL || id.cyi_omni_list == NULL ||
1047c478bd9Sstevel@tonic-gate 	    id.cyi_omni_hdlr.cyo_online == NULL) {
1057c478bd9Sstevel@tonic-gate 		mdb_warn("%p is not an omnipresent cyclic.\n", wsp->walk_addr);
1067c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)id.cyi_omni_list;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate int
cycomni_walk_step(mdb_walk_state_t * wsp)1157c478bd9Sstevel@tonic-gate cycomni_walk_step(mdb_walk_state_t *wsp)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	uintptr_t addr = wsp->walk_addr;
1187c478bd9Sstevel@tonic-gate 	cyc_omni_cpu_t omni;
1197c478bd9Sstevel@tonic-gate 
120892ad162SToomas Soome 	if (addr == 0)
1217c478bd9Sstevel@tonic-gate 		return (WALK_DONE);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	if (mdb_vread(&omni, sizeof (omni), addr) == -1) {
1247c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_omni_cpu at %p", addr);
1257c478bd9Sstevel@tonic-gate 		return (WALK_ERR);
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	wsp->walk_addr = (uintptr_t)omni.cyo_next;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	return (wsp->walk_callback(addr, &omni, wsp->walk_cbdata));
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@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)1347c478bd9Sstevel@tonic-gate cyclic_dump_node(cyc_cpu_t *cpu, cyc_index_t *heap, char **c, size_t w,
1357c478bd9Sstevel@tonic-gate     int ndx, int l, int r, int depth)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	int heap_left, heap_right;
1387c478bd9Sstevel@tonic-gate 	int me;
1397c478bd9Sstevel@tonic-gate 	int i, x = l + (r - l) / 2;
1407c478bd9Sstevel@tonic-gate 	size_t n = w - (x - 1); /* n bytes left for snprintf after c[][x - 1] */
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	heap_left = CYC_HEAP_LEFT(ndx);
1437c478bd9Sstevel@tonic-gate 	heap_right = CYC_HEAP_RIGHT(ndx);
1447c478bd9Sstevel@tonic-gate 	me = heap[ndx];
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	if (ndx >= cpu->cyp_nelems)
1477c478bd9Sstevel@tonic-gate 		return;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	if (me < 10) {
1507c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, " %d", me);
1517c478bd9Sstevel@tonic-gate 	} else if (me >= 100) {
1527c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, "%3d", me);
1537c478bd9Sstevel@tonic-gate 	} else {
1547c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(&c[depth][x - 1], n, "%s%2d%s",
1557c478bd9Sstevel@tonic-gate 		    CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? " " : "", me,
1567c478bd9Sstevel@tonic-gate 		    CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? "" : " ");
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if (r - l > 5) {
1607c478bd9Sstevel@tonic-gate 		c[++depth][x] = '|';
1617c478bd9Sstevel@tonic-gate 		depth++;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 		for (i = l + (r - l) / 4; i < r - (r - l) / 4; i++)
1647c478bd9Sstevel@tonic-gate 			c[depth][i] = '-';
1657c478bd9Sstevel@tonic-gate 		c[depth][l + (r - l) / 4] = '+';
1667c478bd9Sstevel@tonic-gate 		c[depth][r - (r - l) / 4 - 1] = '+';
1677c478bd9Sstevel@tonic-gate 		c[depth][x] = '+';
1687c478bd9Sstevel@tonic-gate 	} else {
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 		if (heap_left >= cpu->cyp_nelems)
1717c478bd9Sstevel@tonic-gate 			return;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(&c[++depth][x - 1], n, "L%d",
1747c478bd9Sstevel@tonic-gate 		    heap[heap_left]);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		if (heap_right >= cpu->cyp_nelems)
1777c478bd9Sstevel@tonic-gate 			return;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		(void) mdb_snprintf(&c[++depth][x - 1], n, "R%d",
1807c478bd9Sstevel@tonic-gate 		    heap[heap_right]);
1817c478bd9Sstevel@tonic-gate 		return;
1827c478bd9Sstevel@tonic-gate 	}
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	if (heap_left < cpu->cyp_nelems)
1857c478bd9Sstevel@tonic-gate 		cyclic_dump_node(cpu, heap, c, w, heap_left, l, x, depth + 1);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	if (heap_right < cpu->cyp_nelems)
1887c478bd9Sstevel@tonic-gate 		cyclic_dump_node(cpu, heap, c, w, heap_right, x, r, depth + 1);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate #define	LINES_PER_LEVEL 3
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate void
cyclic_pretty_dump(cyc_cpu_t * cpu)1947c478bd9Sstevel@tonic-gate cyclic_pretty_dump(cyc_cpu_t *cpu)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	char **c;
1977c478bd9Sstevel@tonic-gate 	int i, j;
1987c478bd9Sstevel@tonic-gate 	int width = 80;
1997c478bd9Sstevel@tonic-gate 	int depth;
2007c478bd9Sstevel@tonic-gate 	cyc_index_t *heap;
2017c478bd9Sstevel@tonic-gate 	size_t hsize = sizeof (cyc_index_t) * cpu->cyp_size;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	heap = mdb_alloc(hsize, UM_SLEEP | UM_GC);
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if (mdb_vread(heap, hsize, (uintptr_t)cpu->cyp_heap) == -1) {
2067c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read heap at %p", (uintptr_t)cpu->cyp_heap);
2077c478bd9Sstevel@tonic-gate 		return;
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	for (depth = 0; (1 << depth) < cpu->cyp_nelems; depth++)
2117c478bd9Sstevel@tonic-gate 		continue;
2127c478bd9Sstevel@tonic-gate 	depth++;
2137c478bd9Sstevel@tonic-gate 	depth = (depth + 1) * LINES_PER_LEVEL;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	c = mdb_zalloc(sizeof (char *) * depth, UM_SLEEP|UM_GC);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
2187c478bd9Sstevel@tonic-gate 		c[i] = mdb_zalloc(width, UM_SLEEP|UM_GC);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	cyclic_dump_node(cpu, heap, c, width, 0, 1, width - 2, 0);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++) {
2237c478bd9Sstevel@tonic-gate 		int dump = 0;
2247c478bd9Sstevel@tonic-gate 		for (j = 0; j < width - 1; j++) {
2257c478bd9Sstevel@tonic-gate 			if (c[i][j] == '\0')
2267c478bd9Sstevel@tonic-gate 				c[i][j] = ' ';
2277c478bd9Sstevel@tonic-gate 			else
2287c478bd9Sstevel@tonic-gate 				dump = 1;
2297c478bd9Sstevel@tonic-gate 		}
2307c478bd9Sstevel@tonic-gate 		c[i][width - 2] = '\n';
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 		if (dump)
2337c478bd9Sstevel@tonic-gate 			mdb_printf(c[i]);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate int
cycinfo(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)2387c478bd9Sstevel@tonic-gate cycinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2397c478bd9Sstevel@tonic-gate {
2407c478bd9Sstevel@tonic-gate 	cyc_cpu_t cpu;
2417c478bd9Sstevel@tonic-gate 	cpu_t c;
2427c478bd9Sstevel@tonic-gate 	cyc_index_t root, i, *heap;
2437c478bd9Sstevel@tonic-gate 	size_t hsize;
2447c478bd9Sstevel@tonic-gate 	cyclic_t *cyc;
2457c478bd9Sstevel@tonic-gate 	uintptr_t caddr;
2467c478bd9Sstevel@tonic-gate 	uint_t verbose = FALSE, Verbose = FALSE;
2477c478bd9Sstevel@tonic-gate 	int header = 0;
2487c478bd9Sstevel@tonic-gate 	cyc_level_t lev;
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
2517c478bd9Sstevel@tonic-gate 		if (mdb_walk_dcmd("cyccpu", "cycinfo", argc, argv) == -1) {
2527c478bd9Sstevel@tonic-gate 			mdb_warn("can't walk 'cyccpu'");
2537c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
2547c478bd9Sstevel@tonic-gate 		}
2557c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (mdb_getopts(argc, argv,
2597c478bd9Sstevel@tonic-gate 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
2607c478bd9Sstevel@tonic-gate 	    'V', MDB_OPT_SETBITS, TRUE, &Verbose, NULL) != argc)
2617c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	if (!DCMD_HDRSPEC(flags) && (verbose || Verbose))
2647c478bd9Sstevel@tonic-gate 		mdb_printf("\n\n");
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags) || verbose || Verbose)
267*fe73c3d8SBryan Cantrill 		mdb_printf("%3s %?s %7s %6s %15s %s\n", "CPU",
268*fe73c3d8SBryan Cantrill 		    "CYC_CPU", "STATE", "NELEMS", "FIRE", "HANDLER");
2697c478bd9Sstevel@tonic-gate 
2708a6a72fdSaf 	if (cyccpu_vread(&cpu, addr) == -1) {
2717c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
2727c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) {
2767c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu);
2777c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	cyc = mdb_alloc(sizeof (cyclic_t) * cpu.cyp_size, UM_SLEEP | UM_GC);
2817c478bd9Sstevel@tonic-gate 	caddr = (uintptr_t)cpu.cyp_cyclics;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if (mdb_vread(cyc, sizeof (cyclic_t) * cpu.cyp_size, caddr) == -1) {
2847c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", caddr);
2857c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	hsize = sizeof (cyc_index_t) * cpu.cyp_size;
2897c478bd9Sstevel@tonic-gate 	heap = mdb_alloc(hsize, UM_SLEEP | UM_GC);
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	if (mdb_vread(heap, hsize, (uintptr_t)cpu.cyp_heap) == -1) {
2927c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read heap at %p", cpu.cyp_heap);
2937c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
2947c478bd9Sstevel@tonic-gate 	}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	root = heap[0];
2977c478bd9Sstevel@tonic-gate 
298*fe73c3d8SBryan Cantrill 	mdb_printf("%3d %0?p %7s %6d ", c.cpu_id, addr,
2997c478bd9Sstevel@tonic-gate 	    cpu.cyp_state == CYS_ONLINE ? "online" :
3007c478bd9Sstevel@tonic-gate 	    cpu.cyp_state == CYS_OFFLINE ? "offline" :
3017c478bd9Sstevel@tonic-gate 	    cpu.cyp_state == CYS_EXPANDING ? "expand" :
3027c478bd9Sstevel@tonic-gate 	    cpu.cyp_state == CYS_REMOVING ? "remove" :
3037c478bd9Sstevel@tonic-gate 	    cpu.cyp_state == CYS_SUSPENDED ? "suspend" : "????",
3047c478bd9Sstevel@tonic-gate 	    cpu.cyp_nelems);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if (cpu.cyp_nelems > 0)
307*fe73c3d8SBryan Cantrill 		mdb_printf("%15llx %a\n",
308*fe73c3d8SBryan Cantrill 		    cyc[root].cy_expire, cyc[root].cy_handler);
3097c478bd9Sstevel@tonic-gate 	else
310*fe73c3d8SBryan Cantrill 		mdb_printf("%15s %s\n", "-", "-");
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (!verbose && !Verbose)
3137c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	mdb_printf("\n");
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	cyclic_pretty_dump(&cpu);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	mdb_inc_indent(2);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	for (i = 0; i < cpu.cyp_size; i++) {
3227c478bd9Sstevel@tonic-gate 		int j;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		for (j = 0; j < cpu.cyp_size; j++) {
3257c478bd9Sstevel@tonic-gate 			if (heap[j] == i)
3267c478bd9Sstevel@tonic-gate 				break;
3277c478bd9Sstevel@tonic-gate 		}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 		if (!Verbose && j >= cpu.cyp_nelems)
3307c478bd9Sstevel@tonic-gate 			continue;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		if (!header) {
3337c478bd9Sstevel@tonic-gate 			header = 1;
334*fe73c3d8SBryan Cantrill 			mdb_printf("\n%?s %3s %3s %3s %5s %14s %s\n",
335*fe73c3d8SBryan Cantrill 			    "ADDR", "NDX", "HPX", "LVL",
336*fe73c3d8SBryan Cantrill 			    "PEND", "FIRE", "HANDLER");
3377c478bd9Sstevel@tonic-gate 		}
3387c478bd9Sstevel@tonic-gate 
339*fe73c3d8SBryan Cantrill 		mdb_printf("%0?p %3d ", caddr + i * sizeof (cyclic_t), i);
3407c478bd9Sstevel@tonic-gate 
341*fe73c3d8SBryan Cantrill 		mdb_printf("%3d ", j);
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 		if (j >= cpu.cyp_nelems) {
344*fe73c3d8SBryan Cantrill 			mdb_printf("%3s %5s %14s %s\n", "-", "-", "-", "-");
3457c478bd9Sstevel@tonic-gate 			continue;
3467c478bd9Sstevel@tonic-gate 		}
3477c478bd9Sstevel@tonic-gate 
348*fe73c3d8SBryan Cantrill 		mdb_printf("%3s %5d ",
349*fe73c3d8SBryan Cantrill 		    cyc[i].cy_level == CY_HIGH_LEVEL ? "hgh" :
350*fe73c3d8SBryan Cantrill 		    cyc[i].cy_level == CY_LOCK_LEVEL ? "lck" :
3517c478bd9Sstevel@tonic-gate 		    cyc[i].cy_level == CY_LOW_LEVEL ? "low" : "????",
352*fe73c3d8SBryan Cantrill 		    cyc[i].cy_pend);
3537c478bd9Sstevel@tonic-gate 
354*fe73c3d8SBryan Cantrill 		if (cyc[i].cy_expire != INT64_MAX)
355*fe73c3d8SBryan Cantrill 			mdb_printf("%14llx ", cyc[i].cy_expire);
3567c478bd9Sstevel@tonic-gate 		else
357*fe73c3d8SBryan Cantrill 			mdb_printf("%14s ", "-");
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 		mdb_printf("%a\n", cyc[i].cy_handler);
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	if (!Verbose)
3647c478bd9Sstevel@tonic-gate 		goto out;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	for (lev = CY_LOW_LEVEL; lev < CY_LOW_LEVEL + CY_SOFT_LEVELS; lev++) {
3677c478bd9Sstevel@tonic-gate 		cyc_softbuf_t *softbuf = &cpu.cyp_softbuf[lev];
3687c478bd9Sstevel@tonic-gate 		char which = softbuf->cys_hard, shared = 1;
3697c478bd9Sstevel@tonic-gate 		cyc_pcbuffer_t *pc;
3707c478bd9Sstevel@tonic-gate 		size_t bufsiz;
3717c478bd9Sstevel@tonic-gate 		cyc_index_t *buf;
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		if (softbuf->cys_hard != softbuf->cys_soft)
3747c478bd9Sstevel@tonic-gate 			shared = 0;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate again:
3777c478bd9Sstevel@tonic-gate 		pc = &softbuf->cys_buf[which];
3787c478bd9Sstevel@tonic-gate 		bufsiz = (pc->cypc_sizemask + 1) * sizeof (cyc_index_t);
3797c478bd9Sstevel@tonic-gate 		buf = mdb_alloc(bufsiz, UM_SLEEP | UM_GC);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 		if (mdb_vread(buf, bufsiz, (uintptr_t)pc->cypc_buf) == -1) {
3827c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't read cypc_buf at %p", pc->cypc_buf);
3837c478bd9Sstevel@tonic-gate 			continue;
3847c478bd9Sstevel@tonic-gate 		}
3857c478bd9Sstevel@tonic-gate 
386*fe73c3d8SBryan Cantrill 		mdb_printf("\n%3s %4s %4s %4s %?s %4s %?s\n", "CPU",
387*fe73c3d8SBryan Cantrill 		    "LEVL", "USER", "NDX", "ADDR", "CYC", "CYC_ADDR", "PEND");
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 		for (i = 0; i <= pc->cypc_sizemask &&
3907c478bd9Sstevel@tonic-gate 		    i <= pc->cypc_prodndx; i++) {
3917c478bd9Sstevel@tonic-gate 			uintptr_t cyc_addr = caddr + buf[i] * sizeof (cyclic_t);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 			mdb_printf("%3d %4s %4s ", c.cpu_id,
3947c478bd9Sstevel@tonic-gate 			    lev == CY_HIGH_LEVEL ? "high" :
3957c478bd9Sstevel@tonic-gate 			    lev == CY_LOCK_LEVEL ? "lock" :
3967c478bd9Sstevel@tonic-gate 			    lev == CY_LOW_LEVEL ? "low" : "????",
3977c478bd9Sstevel@tonic-gate 			    shared ? "shrd" : which == softbuf->cys_hard ?
3987c478bd9Sstevel@tonic-gate 			    "hard" : "soft");
3997c478bd9Sstevel@tonic-gate 
400*fe73c3d8SBryan Cantrill 			mdb_printf("%4d %0?p ", i,
4017c478bd9Sstevel@tonic-gate 			    (uintptr_t)&buf[i] - (uintptr_t)&buf[0] +
4027c478bd9Sstevel@tonic-gate 			    (uintptr_t)pc->cypc_buf, buf[i],
4037c478bd9Sstevel@tonic-gate 			    caddr + buf[i] * sizeof (cyclic_t));
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 			if (i >= pc->cypc_prodndx)
406*fe73c3d8SBryan Cantrill 				mdb_printf("%4s %?s %5s  ", "-", "-", "-");
4077c478bd9Sstevel@tonic-gate 			else {
4087c478bd9Sstevel@tonic-gate 				cyclic_t c;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 				if (mdb_vread(&c, sizeof (c), cyc_addr) == -1) {
4117c478bd9Sstevel@tonic-gate 					mdb_warn("\ncouldn't read cyclic at "
4127c478bd9Sstevel@tonic-gate 					    "%p", cyc_addr);
4137c478bd9Sstevel@tonic-gate 					continue;
4147c478bd9Sstevel@tonic-gate 				}
4157c478bd9Sstevel@tonic-gate 
416*fe73c3d8SBryan Cantrill 				mdb_printf("%4d %0?p %5d  ", buf[i],
417*fe73c3d8SBryan Cantrill 				    cyc_addr, c.cy_pend);
4187c478bd9Sstevel@tonic-gate 			}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 			if (i == (pc->cypc_consndx & pc->cypc_sizemask)) {
421*fe73c3d8SBryan Cantrill 				mdb_printf("<-- c");
4227c478bd9Sstevel@tonic-gate 				if (i == (pc->cypc_prodndx & pc->cypc_sizemask))
423*fe73c3d8SBryan Cantrill 					mdb_printf(",p");
4247c478bd9Sstevel@tonic-gate 				mdb_printf("\n");
4257c478bd9Sstevel@tonic-gate 				continue;
4267c478bd9Sstevel@tonic-gate 			}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 			if (i == (pc->cypc_prodndx & pc->cypc_sizemask)) {
429*fe73c3d8SBryan Cantrill 				mdb_printf("<-- p\n");
4307c478bd9Sstevel@tonic-gate 				continue;
4317c478bd9Sstevel@tonic-gate 			}
4327c478bd9Sstevel@tonic-gate 			mdb_printf("\n");
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 			if (i >= pc->cypc_prodndx)
4357c478bd9Sstevel@tonic-gate 				break;
4367c478bd9Sstevel@tonic-gate 		}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 		if (!shared && which == softbuf->cys_hard) {
4397c478bd9Sstevel@tonic-gate 			which = softbuf->cys_soft;
4407c478bd9Sstevel@tonic-gate 			goto again;
4417c478bd9Sstevel@tonic-gate 		}
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate out:
4457c478bd9Sstevel@tonic-gate 	mdb_dec_indent(2);
4467c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate int
cyctrace_walk_init(mdb_walk_state_t * wsp)4507c478bd9Sstevel@tonic-gate cyctrace_walk_init(mdb_walk_state_t *wsp)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	cyc_cpu_t *cpu;
4537c478bd9Sstevel@tonic-gate 	int i;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	cpu = mdb_zalloc(sizeof (cyc_cpu_t), UM_SLEEP);
4567c478bd9Sstevel@tonic-gate 
457892ad162SToomas Soome 	if (wsp->walk_addr == 0) {
4587c478bd9Sstevel@tonic-gate 		/*
4597c478bd9Sstevel@tonic-gate 		 * If an address isn't provided, we'll use the passive buffer.
4607c478bd9Sstevel@tonic-gate 		 */
4617c478bd9Sstevel@tonic-gate 		GElf_Sym sym;
4627c478bd9Sstevel@tonic-gate 		cyc_tracebuf_t *tr = &cpu->cyp_trace[0];
4637c478bd9Sstevel@tonic-gate 		uintptr_t addr;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 		if (mdb_lookup_by_name("cyc_ptrace", &sym) == -1) {
4667c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't find passive buffer");
4677c478bd9Sstevel@tonic-gate 			return (-1);
4687c478bd9Sstevel@tonic-gate 		}
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 		addr = (uintptr_t)sym.st_value;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 		if (mdb_vread(tr, sizeof (cyc_tracebuf_t), addr) == -1) {
4737c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't read passive buffer");
4747c478bd9Sstevel@tonic-gate 			return (-1);
4757c478bd9Sstevel@tonic-gate 		}
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		wsp->walk_addr = addr - offsetof(cyc_cpu_t, cyp_trace[0]);
4787c478bd9Sstevel@tonic-gate 	} else {
4798a6a72fdSaf 		if (cyccpu_vread(cpu, wsp->walk_addr) == -1) {
4807c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't read cyc_cpu at %p", wsp->walk_addr);
4817c478bd9Sstevel@tonic-gate 			mdb_free(cpu, sizeof (cyc_cpu_t));
4827c478bd9Sstevel@tonic-gate 			return (-1);
4837c478bd9Sstevel@tonic-gate 		}
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	for (i = 0; i < CY_LEVELS; i++) {
4877c478bd9Sstevel@tonic-gate 		if (cpu->cyp_trace[i].cyt_ndx-- == 0)
4887c478bd9Sstevel@tonic-gate 			cpu->cyp_trace[i].cyt_ndx = CY_NTRACEREC - 1;
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate 	wsp->walk_data = cpu;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return (0);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate int
cyctrace_walk_step(mdb_walk_state_t * wsp)4977c478bd9Sstevel@tonic-gate cyctrace_walk_step(mdb_walk_state_t *wsp)
4987c478bd9Sstevel@tonic-gate {
4997c478bd9Sstevel@tonic-gate 	cyc_cpu_t *cpu = wsp->walk_data;
5007c478bd9Sstevel@tonic-gate 	cyc_tracebuf_t *buf = cpu->cyp_trace;
5017c478bd9Sstevel@tonic-gate 	hrtime_t latest = 0;
5027c478bd9Sstevel@tonic-gate 	int i, ndx, new_ndx, lev, rval;
5037c478bd9Sstevel@tonic-gate 	uintptr_t addr;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	for (i = 0; i < CY_LEVELS; i++) {
5067c478bd9Sstevel@tonic-gate 		if ((ndx = buf[i].cyt_ndx) == -1)
5077c478bd9Sstevel@tonic-gate 			continue;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 		/*
5107c478bd9Sstevel@tonic-gate 		 * Account for NPT.
5117c478bd9Sstevel@tonic-gate 		 */
5127c478bd9Sstevel@tonic-gate 		buf[i].cyt_buf[ndx].cyt_tstamp <<= 1;
5137c478bd9Sstevel@tonic-gate 		buf[i].cyt_buf[ndx].cyt_tstamp >>= 1;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 		if (buf[i].cyt_buf[ndx].cyt_tstamp > latest) {
5167c478bd9Sstevel@tonic-gate 			latest = buf[i].cyt_buf[ndx].cyt_tstamp;
5177c478bd9Sstevel@tonic-gate 			lev = i;
5187c478bd9Sstevel@tonic-gate 		}
5197c478bd9Sstevel@tonic-gate 	}
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	/*
5227c478bd9Sstevel@tonic-gate 	 * If we didn't find one, we're done.
5237c478bd9Sstevel@tonic-gate 	 */
5247c478bd9Sstevel@tonic-gate 	if (latest == 0)
5257c478bd9Sstevel@tonic-gate 		return (-1);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	buf = &buf[lev];
5287c478bd9Sstevel@tonic-gate 	ndx = buf->cyt_ndx;
5297c478bd9Sstevel@tonic-gate 	addr = wsp->walk_addr +
5307c478bd9Sstevel@tonic-gate 	    (uintptr_t)&(buf->cyt_buf[ndx]) - (uintptr_t)cpu;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	rval = wsp->walk_callback(addr, &buf->cyt_buf[ndx], wsp->walk_cbdata);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	new_ndx = ndx == 0 ? CY_NTRACEREC - 1 : ndx - 1;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (buf->cyt_buf[new_ndx].cyt_tstamp != 0 &&
5377c478bd9Sstevel@tonic-gate 	    buf->cyt_buf[new_ndx].cyt_tstamp > buf->cyt_buf[ndx].cyt_tstamp)
5387c478bd9Sstevel@tonic-gate 		new_ndx = -1;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	buf->cyt_ndx = new_ndx;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	return (rval);
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate void
cyctrace_walk_fini(mdb_walk_state_t * wsp)5467c478bd9Sstevel@tonic-gate cyctrace_walk_fini(mdb_walk_state_t *wsp)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	cyc_cpu_t *cpu = wsp->walk_data;
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	mdb_free(cpu, sizeof (cyc_cpu_t));
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate #define	WHYLEN	17
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate int
cyctrace_walk(uintptr_t addr,const cyc_tracerec_t * rec,cyc_cpu_t * cpu)5567c478bd9Sstevel@tonic-gate cyctrace_walk(uintptr_t addr, const cyc_tracerec_t *rec, cyc_cpu_t *cpu)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate 	int i;
5597c478bd9Sstevel@tonic-gate 	char c[WHYLEN];
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	for (i = 0; cpu != NULL && i < CY_LEVELS; i++)
5627c478bd9Sstevel@tonic-gate 		if (addr < (uintptr_t)&cpu->cyp_trace[i + 1].cyt_buf[0])
5637c478bd9Sstevel@tonic-gate 			break;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	(void) mdb_readstr(c, WHYLEN, (uintptr_t)rec->cyt_why);
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	mdb_printf("%08p %4s %15llx %-*s %15llx %15llx\n",
5687c478bd9Sstevel@tonic-gate 	    addr & UINT_MAX, cpu == NULL ? "pasv" :
5697c478bd9Sstevel@tonic-gate 	    i == CY_HIGH_LEVEL ? "high" : i == CY_LOCK_LEVEL ? "lock" :
5707c478bd9Sstevel@tonic-gate 	    i == CY_LOW_LEVEL ? "low" : "????", rec->cyt_tstamp, WHYLEN, c,
5717c478bd9Sstevel@tonic-gate 	    rec->cyt_arg0, rec->cyt_arg1);
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	return (0);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5777c478bd9Sstevel@tonic-gate int
cyctrace(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)5787c478bd9Sstevel@tonic-gate cyctrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
581892ad162SToomas Soome 		addr = 0;
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	if (mdb_pwalk("cyctrace", (mdb_walk_cb_t)cyctrace_walk,
5847c478bd9Sstevel@tonic-gate 	    (void *)addr, addr) == -1) {
5857c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't walk cyctrace");
5867c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate int
cyccover_comp(const void * l,const void * r)5937c478bd9Sstevel@tonic-gate cyccover_comp(const void *l, const void *r)
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate 	cyc_coverage_t *lhs = (cyc_coverage_t *)l;
5967c478bd9Sstevel@tonic-gate 	cyc_coverage_t *rhs = (cyc_coverage_t *)r;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 	char ly[WHYLEN], ry[WHYLEN];
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	if (rhs->cyv_why == lhs->cyv_why)
6017c478bd9Sstevel@tonic-gate 		return (0);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	if (rhs->cyv_why == NULL)
6047c478bd9Sstevel@tonic-gate 		return (-1);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	if (lhs->cyv_why == NULL)
6077c478bd9Sstevel@tonic-gate 		return (1);
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	(void) mdb_readstr(ly, WHYLEN, (uintptr_t)lhs->cyv_why);
6107c478bd9Sstevel@tonic-gate 	(void) mdb_readstr(ry, WHYLEN, (uintptr_t)rhs->cyv_why);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	return (strcmp(ly, ry));
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6167c478bd9Sstevel@tonic-gate int
cyccover(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6177c478bd9Sstevel@tonic-gate cyccover(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6187c478bd9Sstevel@tonic-gate {
6197c478bd9Sstevel@tonic-gate 	cyc_coverage_t cv[CY_NCOVERAGE];
6207c478bd9Sstevel@tonic-gate 	char c[WHYLEN];
6217c478bd9Sstevel@tonic-gate 	GElf_Sym sym;
6227c478bd9Sstevel@tonic-gate 	int i;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if ((flags & DCMD_ADDRSPEC) || argc != 0)
6257c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if (mdb_lookup_by_name("cyc_coverage", &sym) == -1) {
6287c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't find coverage information");
6297c478bd9Sstevel@tonic-gate 		return (DCMD_ABORT);
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	addr = (uintptr_t)sym.st_value;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	if (mdb_vread(cv, sizeof (cyc_coverage_t) * CY_NCOVERAGE, addr) == -1) {
6357c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read coverage array at %p", addr);
6367c478bd9Sstevel@tonic-gate 		return (DCMD_ABORT);
6377c478bd9Sstevel@tonic-gate 	}
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	mdb_printf("%-*s %8s %8s %8s %15s %15s\n",
6407c478bd9Sstevel@tonic-gate 	    WHYLEN, "POINT", "HIGH", "LOCK", "LOW/PASV", "ARG0", "ARG1");
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	qsort(cv, CY_NCOVERAGE, sizeof (cyc_coverage_t), cyccover_comp);
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	for (i = 0; i < CY_NCOVERAGE; i++) {
6457c478bd9Sstevel@tonic-gate 		if (cv[i].cyv_why != NULL) {
6467c478bd9Sstevel@tonic-gate 			(void) mdb_readstr(c, WHYLEN, (uintptr_t)cv[i].cyv_why);
6477c478bd9Sstevel@tonic-gate 			mdb_printf("%-*s %8d %8d %8d %15llx %15llx\n",
6487c478bd9Sstevel@tonic-gate 			    WHYLEN, c,
6497c478bd9Sstevel@tonic-gate 			    cv[i].cyv_count[CY_HIGH_LEVEL],
6507c478bd9Sstevel@tonic-gate 			    cv[i].cyv_count[CY_LOCK_LEVEL],
6517c478bd9Sstevel@tonic-gate 			    cv[i].cyv_passive_count != 0 ?
6527c478bd9Sstevel@tonic-gate 			    cv[i].cyv_passive_count :
6537c478bd9Sstevel@tonic-gate 			    cv[i].cyv_count[CY_LOW_LEVEL],
6547c478bd9Sstevel@tonic-gate 			    cv[i].cyv_arg0, cv[i].cyv_arg1);
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6627c478bd9Sstevel@tonic-gate int
cyclic(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)6637c478bd9Sstevel@tonic-gate cyclic(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
6647c478bd9Sstevel@tonic-gate {
6657c478bd9Sstevel@tonic-gate 	cyclic_t cyc;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC) || argc != 0)
6687c478bd9Sstevel@tonic-gate 		return (DCMD_USAGE);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags))
6717c478bd9Sstevel@tonic-gate 		mdb_printf("%?s %4s %5s %5s %15s %7s %s\n", "ADDR", "LEVL",
6727c478bd9Sstevel@tonic-gate 		    "PEND", "FLAGS", "FIRE", "USECINT", "HANDLER");
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	if (mdb_vread(&cyc, sizeof (cyclic_t), addr) == -1) {
6757c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", addr);
6767c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	mdb_printf("%0?p %4s %5d  %04x %15llx %7lld %a\n", addr,
6807c478bd9Sstevel@tonic-gate 	    cyc.cy_level == CY_HIGH_LEVEL ? "high" :
6817c478bd9Sstevel@tonic-gate 	    cyc.cy_level == CY_LOCK_LEVEL ? "lock" :
6827c478bd9Sstevel@tonic-gate 	    cyc.cy_level == CY_LOW_LEVEL ? "low" : "????",
6837c478bd9Sstevel@tonic-gate 	    cyc.cy_pend, cyc.cy_flags, cyc.cy_expire,
6847c478bd9Sstevel@tonic-gate 	    cyc.cy_interval / (uint64_t)(NANOSEC / MICROSEC),
6857c478bd9Sstevel@tonic-gate 	    cyc.cy_handler);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate static int
cycid_cpu(cyc_cpu_t * addr,int ndx)6917c478bd9Sstevel@tonic-gate cycid_cpu(cyc_cpu_t *addr, int ndx)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	cyc_cpu_t cpu;
6947c478bd9Sstevel@tonic-gate 	cpu_t c;
6957c478bd9Sstevel@tonic-gate 	uintptr_t caddr;
6967c478bd9Sstevel@tonic-gate 	cyclic_t cyc;
6977c478bd9Sstevel@tonic-gate 
6988a6a72fdSaf 	if (cyccpu_vread(&cpu, (uintptr_t)addr) == -1) {
6997c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_cpu at %p", addr);
7007c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
7017c478bd9Sstevel@tonic-gate 	}
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) {
7047c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu);
7057c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	caddr = (uintptr_t)cpu.cyp_cyclics + ndx * sizeof (cyclic_t);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (mdb_vread(&cyc, sizeof (cyc), caddr) == -1) {
7117c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyclic at %p", caddr);
7127c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	mdb_printf("%4d %3d %?p %a\n", c.cpu_id, ndx, caddr, cyc.cy_handler);
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	return (DCMD_OK);
7187c478bd9Sstevel@tonic-gate }
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7217c478bd9Sstevel@tonic-gate static int
cycid_walk_omni(uintptr_t addr,const cyc_omni_cpu_t * omni,int * ignored)7227c478bd9Sstevel@tonic-gate cycid_walk_omni(uintptr_t addr, const cyc_omni_cpu_t *omni, int *ignored)
7237c478bd9Sstevel@tonic-gate {
7247c478bd9Sstevel@tonic-gate 	mdb_printf("%?s        ");
7257c478bd9Sstevel@tonic-gate 	cycid_cpu(omni->cyo_cpu, omni->cyo_ndx);
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	return (WALK_NEXT);
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7317c478bd9Sstevel@tonic-gate int
cycid(uintptr_t addr,uint_t flags,int ac,const mdb_arg_t * av)7327c478bd9Sstevel@tonic-gate cycid(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av)
7337c478bd9Sstevel@tonic-gate {
7347c478bd9Sstevel@tonic-gate 	cyc_id_t id;
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	if (!(flags & DCMD_ADDRSPEC)) {
7377c478bd9Sstevel@tonic-gate 		if (mdb_walk_dcmd("cyclic_id_cache", "cycid", ac, av) == -1) {
7387c478bd9Sstevel@tonic-gate 			mdb_warn("can't walk cyclic_id_cache");
7397c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
7407c478bd9Sstevel@tonic-gate 		}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
7437c478bd9Sstevel@tonic-gate 	}
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 	if (DCMD_HDRSPEC(flags)) {
7467c478bd9Sstevel@tonic-gate 		mdb_printf("%?s %4s %3s %?s %s\n", "ADDR", "CPU", "NDX",
7477c478bd9Sstevel@tonic-gate 		    "CYCLIC", "HANDLER");
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (mdb_vread(&id, sizeof (id), addr) == -1) {
7517c478bd9Sstevel@tonic-gate 		mdb_warn("couldn't read cyc_id_t at %p", addr);
7527c478bd9Sstevel@tonic-gate 		return (DCMD_ERR);
7537c478bd9Sstevel@tonic-gate 	}
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 	if (id.cyi_cpu == NULL) {
7567c478bd9Sstevel@tonic-gate 		/*
7577c478bd9Sstevel@tonic-gate 		 * This is an omnipresent cyclic.
7587c478bd9Sstevel@tonic-gate 		 */
7597c478bd9Sstevel@tonic-gate 		mdb_printf("%?p %4s %3s %?s %a\n", addr, "omni", "-", "-",
7607c478bd9Sstevel@tonic-gate 		    id.cyi_omni_hdlr.cyo_online);
7617c478bd9Sstevel@tonic-gate 		mdb_printf("%?s    |\n", "");
7627c478bd9Sstevel@tonic-gate 		mdb_printf("%?s    +-->%4s %3s %?s %s\n", "",
7637c478bd9Sstevel@tonic-gate 		    "CPU", "NDX", "CYCLIC", "HANDLER");
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 		if (mdb_pwalk("cycomni",
7667c478bd9Sstevel@tonic-gate 		    (mdb_walk_cb_t)cycid_walk_omni, NULL, addr) == -1) {
7677c478bd9Sstevel@tonic-gate 			mdb_warn("couldn't walk cycomni for %p", addr);
7687c478bd9Sstevel@tonic-gate 			return (DCMD_ERR);
7697c478bd9Sstevel@tonic-gate 		}
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 		mdb_printf("\n");
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 		return (DCMD_OK);
7747c478bd9Sstevel@tonic-gate 	}
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	mdb_printf("%?p ", addr);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	return (cycid_cpu(id.cyi_cpu, id.cyi_ndx));
7797c478bd9Sstevel@tonic-gate }
780