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 5*8a6a72fdSaf * Common Development and Distribution License (the "License"). 6*8a6a72fdSaf * 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 /* 22*8a6a72fdSaf * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include "cyclic.h" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #define CYCLIC_TRACE 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 337c478bd9Sstevel@tonic-gate #include <sys/timer.h> 347c478bd9Sstevel@tonic-gate #include <sys/cyclic_impl.h> 357c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 367c478bd9Sstevel@tonic-gate #include <stdio.h> 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate int 39*8a6a72fdSaf cyccpu_vread(cyc_cpu_t *cpu, uintptr_t addr) 40*8a6a72fdSaf { 41*8a6a72fdSaf static int inited = 0; 42*8a6a72fdSaf static int cyc_trace_enabled = 0; 43*8a6a72fdSaf static size_t cyccpu_size; 44*8a6a72fdSaf 45*8a6a72fdSaf if (!inited) { 46*8a6a72fdSaf inited = 1; 47*8a6a72fdSaf (void) mdb_readvar(&cyc_trace_enabled, "cyc_trace_enabled"); 48*8a6a72fdSaf cyccpu_size = (cyc_trace_enabled) ? sizeof (*cpu) : 49*8a6a72fdSaf OFFSETOF(cyc_cpu_t, cyp_trace); 50*8a6a72fdSaf } 51*8a6a72fdSaf 52*8a6a72fdSaf if (mdb_vread(cpu, cyccpu_size, addr) == -1) 53*8a6a72fdSaf return (-1); 54*8a6a72fdSaf 55*8a6a72fdSaf if (!cyc_trace_enabled) 56*8a6a72fdSaf bzero(cpu->cyp_trace, sizeof (cpu->cyp_trace)); 57*8a6a72fdSaf 58*8a6a72fdSaf return (0); 59*8a6a72fdSaf } 60*8a6a72fdSaf 61*8a6a72fdSaf int 627c478bd9Sstevel@tonic-gate cyccpu_walk_init(mdb_walk_state_t *wsp) 637c478bd9Sstevel@tonic-gate { 647c478bd9Sstevel@tonic-gate if (mdb_layered_walk("cpu", wsp) == -1) { 657c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk 'cpu'"); 667c478bd9Sstevel@tonic-gate return (WALK_ERR); 677c478bd9Sstevel@tonic-gate } 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate return (WALK_NEXT); 707c478bd9Sstevel@tonic-gate } 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate int 737c478bd9Sstevel@tonic-gate cyccpu_walk_step(mdb_walk_state_t *wsp) 747c478bd9Sstevel@tonic-gate { 757c478bd9Sstevel@tonic-gate uintptr_t addr = (uintptr_t)((cpu_t *)wsp->walk_layer)->cpu_cyclic; 767c478bd9Sstevel@tonic-gate cyc_cpu_t cpu; 777c478bd9Sstevel@tonic-gate 78*8a6a72fdSaf if (cyccpu_vread(&cpu, addr) == -1) { 797c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyc_cpu at %p", addr); 807c478bd9Sstevel@tonic-gate return (WALK_ERR); 817c478bd9Sstevel@tonic-gate } 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate return (wsp->walk_callback(addr, &cpu, wsp->walk_cbdata)); 847c478bd9Sstevel@tonic-gate } 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate int 877c478bd9Sstevel@tonic-gate cycomni_walk_init(mdb_walk_state_t *wsp) 887c478bd9Sstevel@tonic-gate { 897c478bd9Sstevel@tonic-gate cyc_id_t id; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) { 927c478bd9Sstevel@tonic-gate mdb_warn("must provide a cyclic id\n"); 937c478bd9Sstevel@tonic-gate return (WALK_ERR); 947c478bd9Sstevel@tonic-gate } 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate if (mdb_vread(&id, sizeof (id), wsp->walk_addr) == -1) { 977c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyc_id_t at %p", wsp->walk_addr); 987c478bd9Sstevel@tonic-gate return (WALK_ERR); 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate if (id.cyi_cpu != NULL || id.cyi_omni_list == NULL || 1027c478bd9Sstevel@tonic-gate id.cyi_omni_hdlr.cyo_online == NULL) { 1037c478bd9Sstevel@tonic-gate mdb_warn("%p is not an omnipresent cyclic.\n", wsp->walk_addr); 1047c478bd9Sstevel@tonic-gate return (WALK_ERR); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)id.cyi_omni_list; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate return (WALK_NEXT); 1107c478bd9Sstevel@tonic-gate } 1117c478bd9Sstevel@tonic-gate 1127c478bd9Sstevel@tonic-gate int 1137c478bd9Sstevel@tonic-gate cycomni_walk_step(mdb_walk_state_t *wsp) 1147c478bd9Sstevel@tonic-gate { 1157c478bd9Sstevel@tonic-gate uintptr_t addr = wsp->walk_addr; 1167c478bd9Sstevel@tonic-gate cyc_omni_cpu_t omni; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate if (addr == NULL) 1197c478bd9Sstevel@tonic-gate return (WALK_DONE); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate if (mdb_vread(&omni, sizeof (omni), addr) == -1) { 1227c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyc_omni_cpu at %p", addr); 1237c478bd9Sstevel@tonic-gate return (WALK_ERR); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate wsp->walk_addr = (uintptr_t)omni.cyo_next; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate return (wsp->walk_callback(addr, &omni, wsp->walk_cbdata)); 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate void 1327c478bd9Sstevel@tonic-gate cyclic_dump_node(cyc_cpu_t *cpu, cyc_index_t *heap, char **c, size_t w, 1337c478bd9Sstevel@tonic-gate int ndx, int l, int r, int depth) 1347c478bd9Sstevel@tonic-gate { 1357c478bd9Sstevel@tonic-gate int heap_left, heap_right; 1367c478bd9Sstevel@tonic-gate int me; 1377c478bd9Sstevel@tonic-gate int i, x = l + (r - l) / 2; 1387c478bd9Sstevel@tonic-gate size_t n = w - (x - 1); /* n bytes left for snprintf after c[][x - 1] */ 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate heap_left = CYC_HEAP_LEFT(ndx); 1417c478bd9Sstevel@tonic-gate heap_right = CYC_HEAP_RIGHT(ndx); 1427c478bd9Sstevel@tonic-gate me = heap[ndx]; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate if (ndx >= cpu->cyp_nelems) 1457c478bd9Sstevel@tonic-gate return; 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate if (me < 10) { 1487c478bd9Sstevel@tonic-gate (void) mdb_snprintf(&c[depth][x - 1], n, " %d", me); 1497c478bd9Sstevel@tonic-gate } else if (me >= 100) { 1507c478bd9Sstevel@tonic-gate (void) mdb_snprintf(&c[depth][x - 1], n, "%3d", me); 1517c478bd9Sstevel@tonic-gate } else { 1527c478bd9Sstevel@tonic-gate (void) mdb_snprintf(&c[depth][x - 1], n, "%s%2d%s", 1537c478bd9Sstevel@tonic-gate CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? " " : "", me, 1547c478bd9Sstevel@tonic-gate CYC_HEAP_LEFT(CYC_HEAP_PARENT(ndx)) == ndx ? "" : " "); 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate if (r - l > 5) { 1587c478bd9Sstevel@tonic-gate c[++depth][x] = '|'; 1597c478bd9Sstevel@tonic-gate depth++; 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate for (i = l + (r - l) / 4; i < r - (r - l) / 4; i++) 1627c478bd9Sstevel@tonic-gate c[depth][i] = '-'; 1637c478bd9Sstevel@tonic-gate c[depth][l + (r - l) / 4] = '+'; 1647c478bd9Sstevel@tonic-gate c[depth][r - (r - l) / 4 - 1] = '+'; 1657c478bd9Sstevel@tonic-gate c[depth][x] = '+'; 1667c478bd9Sstevel@tonic-gate } else { 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate if (heap_left >= cpu->cyp_nelems) 1697c478bd9Sstevel@tonic-gate return; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate (void) mdb_snprintf(&c[++depth][x - 1], n, "L%d", 1727c478bd9Sstevel@tonic-gate heap[heap_left]); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (heap_right >= cpu->cyp_nelems) 1757c478bd9Sstevel@tonic-gate return; 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate (void) mdb_snprintf(&c[++depth][x - 1], n, "R%d", 1787c478bd9Sstevel@tonic-gate heap[heap_right]); 1797c478bd9Sstevel@tonic-gate return; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate if (heap_left < cpu->cyp_nelems) 1837c478bd9Sstevel@tonic-gate cyclic_dump_node(cpu, heap, c, w, heap_left, l, x, depth + 1); 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate if (heap_right < cpu->cyp_nelems) 1867c478bd9Sstevel@tonic-gate cyclic_dump_node(cpu, heap, c, w, heap_right, x, r, depth + 1); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate #define LINES_PER_LEVEL 3 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate void 1927c478bd9Sstevel@tonic-gate cyclic_pretty_dump(cyc_cpu_t *cpu) 1937c478bd9Sstevel@tonic-gate { 1947c478bd9Sstevel@tonic-gate char **c; 1957c478bd9Sstevel@tonic-gate int i, j; 1967c478bd9Sstevel@tonic-gate int width = 80; 1977c478bd9Sstevel@tonic-gate int depth; 1987c478bd9Sstevel@tonic-gate cyc_index_t *heap; 1997c478bd9Sstevel@tonic-gate size_t hsize = sizeof (cyc_index_t) * cpu->cyp_size; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate heap = mdb_alloc(hsize, UM_SLEEP | UM_GC); 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate if (mdb_vread(heap, hsize, (uintptr_t)cpu->cyp_heap) == -1) { 2047c478bd9Sstevel@tonic-gate mdb_warn("couldn't read heap at %p", (uintptr_t)cpu->cyp_heap); 2057c478bd9Sstevel@tonic-gate return; 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate for (depth = 0; (1 << depth) < cpu->cyp_nelems; depth++) 2097c478bd9Sstevel@tonic-gate continue; 2107c478bd9Sstevel@tonic-gate depth++; 2117c478bd9Sstevel@tonic-gate depth = (depth + 1) * LINES_PER_LEVEL; 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate c = mdb_zalloc(sizeof (char *) * depth, UM_SLEEP|UM_GC); 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) 2167c478bd9Sstevel@tonic-gate c[i] = mdb_zalloc(width, UM_SLEEP|UM_GC); 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate cyclic_dump_node(cpu, heap, c, width, 0, 1, width - 2, 0); 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate for (i = 0; i < depth; i++) { 2217c478bd9Sstevel@tonic-gate int dump = 0; 2227c478bd9Sstevel@tonic-gate for (j = 0; j < width - 1; j++) { 2237c478bd9Sstevel@tonic-gate if (c[i][j] == '\0') 2247c478bd9Sstevel@tonic-gate c[i][j] = ' '; 2257c478bd9Sstevel@tonic-gate else 2267c478bd9Sstevel@tonic-gate dump = 1; 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate c[i][width - 2] = '\n'; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate if (dump) 2317c478bd9Sstevel@tonic-gate mdb_printf(c[i]); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate } 2347c478bd9Sstevel@tonic-gate 2357c478bd9Sstevel@tonic-gate /* 2367c478bd9Sstevel@tonic-gate * Yes, this is very weak. Full 16-column-wide 64-bit addresses screw up 2377c478bd9Sstevel@tonic-gate * ::cycinfo's very carefully planned 80-column layout. We set the column 2387c478bd9Sstevel@tonic-gate * width for addresses to be 11 (instead of 16), knowing that the kernel 2397c478bd9Sstevel@tonic-gate * heap (from which these data structures are allocated) starts at 2407c478bd9Sstevel@tonic-gate * 0x0000030000000000, and isn't likely to extend to 0x0000100000000000. 2417c478bd9Sstevel@tonic-gate */ 2427c478bd9Sstevel@tonic-gate #ifdef _LP64 2437c478bd9Sstevel@tonic-gate #define CYC_ADDR_WIDTH 11 2447c478bd9Sstevel@tonic-gate #else 2457c478bd9Sstevel@tonic-gate #define CYC_ADDR_WIDTH 8 2467c478bd9Sstevel@tonic-gate #endif 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate int 2497c478bd9Sstevel@tonic-gate cycinfo(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2507c478bd9Sstevel@tonic-gate { 2517c478bd9Sstevel@tonic-gate cyc_cpu_t cpu; 2527c478bd9Sstevel@tonic-gate cpu_t c; 2537c478bd9Sstevel@tonic-gate cyc_index_t root, i, *heap; 2547c478bd9Sstevel@tonic-gate size_t hsize; 2557c478bd9Sstevel@tonic-gate cyclic_t *cyc; 2567c478bd9Sstevel@tonic-gate uintptr_t caddr; 2577c478bd9Sstevel@tonic-gate uint_t verbose = FALSE, Verbose = FALSE; 2587c478bd9Sstevel@tonic-gate int header = 0; 2597c478bd9Sstevel@tonic-gate cyc_level_t lev; 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 2627c478bd9Sstevel@tonic-gate if (mdb_walk_dcmd("cyccpu", "cycinfo", argc, argv) == -1) { 2637c478bd9Sstevel@tonic-gate mdb_warn("can't walk 'cyccpu'"); 2647c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2657c478bd9Sstevel@tonic-gate } 2667c478bd9Sstevel@tonic-gate return (DCMD_OK); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (mdb_getopts(argc, argv, 2707c478bd9Sstevel@tonic-gate 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2717c478bd9Sstevel@tonic-gate 'V', MDB_OPT_SETBITS, TRUE, &Verbose, NULL) != argc) 2727c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate if (!DCMD_HDRSPEC(flags) && (verbose || Verbose)) 2757c478bd9Sstevel@tonic-gate mdb_printf("\n\n"); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags) || verbose || Verbose) 2787c478bd9Sstevel@tonic-gate mdb_printf("%3s %*s %7s %6s %*s %15s %s\n", "CPU", 2797c478bd9Sstevel@tonic-gate CYC_ADDR_WIDTH, "CYC_CPU", "STATE", "NELEMS", 2807c478bd9Sstevel@tonic-gate CYC_ADDR_WIDTH, "ROOT", "FIRE", "HANDLER"); 2817c478bd9Sstevel@tonic-gate 282*8a6a72fdSaf if (cyccpu_vread(&cpu, addr) == -1) { 2837c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyc_cpu at %p", addr); 2847c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) { 2887c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu); 2897c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate 2927c478bd9Sstevel@tonic-gate cyc = mdb_alloc(sizeof (cyclic_t) * cpu.cyp_size, UM_SLEEP | UM_GC); 2937c478bd9Sstevel@tonic-gate caddr = (uintptr_t)cpu.cyp_cyclics; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if (mdb_vread(cyc, sizeof (cyclic_t) * cpu.cyp_size, caddr) == -1) { 2967c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyclic at %p", caddr); 2977c478bd9Sstevel@tonic-gate return (DCMD_ERR); 2987c478bd9Sstevel@tonic-gate } 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate hsize = sizeof (cyc_index_t) * cpu.cyp_size; 3017c478bd9Sstevel@tonic-gate heap = mdb_alloc(hsize, UM_SLEEP | UM_GC); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate if (mdb_vread(heap, hsize, (uintptr_t)cpu.cyp_heap) == -1) { 3047c478bd9Sstevel@tonic-gate mdb_warn("couldn't read heap at %p", cpu.cyp_heap); 3057c478bd9Sstevel@tonic-gate return (DCMD_ERR); 3067c478bd9Sstevel@tonic-gate } 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate root = heap[0]; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate mdb_printf("%3d %0*p %7s %6d ", c.cpu_id, CYC_ADDR_WIDTH, addr, 3117c478bd9Sstevel@tonic-gate cpu.cyp_state == CYS_ONLINE ? "online" : 3127c478bd9Sstevel@tonic-gate cpu.cyp_state == CYS_OFFLINE ? "offline" : 3137c478bd9Sstevel@tonic-gate cpu.cyp_state == CYS_EXPANDING ? "expand" : 3147c478bd9Sstevel@tonic-gate cpu.cyp_state == CYS_REMOVING ? "remove" : 3157c478bd9Sstevel@tonic-gate cpu.cyp_state == CYS_SUSPENDED ? "suspend" : "????", 3167c478bd9Sstevel@tonic-gate cpu.cyp_nelems); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if (cpu.cyp_nelems > 0) 3197c478bd9Sstevel@tonic-gate mdb_printf("%0*p %15llx %a\n", CYC_ADDR_WIDTH, 3207c478bd9Sstevel@tonic-gate caddr, cyc[root].cy_expire, cyc[root].cy_handler); 3217c478bd9Sstevel@tonic-gate else 3227c478bd9Sstevel@tonic-gate mdb_printf("%*s %15s %s\n", CYC_ADDR_WIDTH, "-", "-", "-"); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if (!verbose && !Verbose) 3257c478bd9Sstevel@tonic-gate return (DCMD_OK); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate mdb_printf("\n"); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate cyclic_pretty_dump(&cpu); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate mdb_inc_indent(2); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate for (i = 0; i < cpu.cyp_size; i++) { 3347c478bd9Sstevel@tonic-gate int j; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate for (j = 0; j < cpu.cyp_size; j++) { 3377c478bd9Sstevel@tonic-gate if (heap[j] == i) 3387c478bd9Sstevel@tonic-gate break; 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate if (!Verbose && j >= cpu.cyp_nelems) 3427c478bd9Sstevel@tonic-gate continue; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if (!header) { 3457c478bd9Sstevel@tonic-gate header = 1; 3467c478bd9Sstevel@tonic-gate mdb_printf("\n%*s %3s %4s %4s %5s %15s %7s %s\n", 3477c478bd9Sstevel@tonic-gate CYC_ADDR_WIDTH, "ADDR", "NDX", "HEAP", "LEVL", 3487c478bd9Sstevel@tonic-gate "PEND", "FIRE", "USECINT", "HANDLER"); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate mdb_printf("%0*p %3d ", CYC_ADDR_WIDTH, 3527c478bd9Sstevel@tonic-gate caddr + i * sizeof (cyclic_t), i); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate mdb_printf("%4d ", j); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate if (j >= cpu.cyp_nelems) { 3577c478bd9Sstevel@tonic-gate mdb_printf("%4s %5s %15s %7s %s\n", "-", "-", 3587c478bd9Sstevel@tonic-gate "-", "-", "-"); 3597c478bd9Sstevel@tonic-gate continue; 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate mdb_printf("%4s %5d %15llx ", 3637c478bd9Sstevel@tonic-gate cyc[i].cy_level == CY_HIGH_LEVEL ? "high" : 3647c478bd9Sstevel@tonic-gate cyc[i].cy_level == CY_LOCK_LEVEL ? "lock" : 3657c478bd9Sstevel@tonic-gate cyc[i].cy_level == CY_LOW_LEVEL ? "low" : "????", 3667c478bd9Sstevel@tonic-gate cyc[i].cy_pend, cyc[i].cy_expire); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate if (cyc[i].cy_interval + cyc[i].cy_expire != INT64_MAX) 3697c478bd9Sstevel@tonic-gate mdb_printf("%7lld ", cyc[i].cy_interval / 3707c478bd9Sstevel@tonic-gate (uint64_t)(NANOSEC / MICROSEC)); 3717c478bd9Sstevel@tonic-gate else 3727c478bd9Sstevel@tonic-gate mdb_printf("%7s ", "-"); 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate mdb_printf("%a\n", cyc[i].cy_handler); 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate if (!Verbose) 3797c478bd9Sstevel@tonic-gate goto out; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate for (lev = CY_LOW_LEVEL; lev < CY_LOW_LEVEL + CY_SOFT_LEVELS; lev++) { 3827c478bd9Sstevel@tonic-gate cyc_softbuf_t *softbuf = &cpu.cyp_softbuf[lev]; 3837c478bd9Sstevel@tonic-gate char which = softbuf->cys_hard, shared = 1; 3847c478bd9Sstevel@tonic-gate cyc_pcbuffer_t *pc; 3857c478bd9Sstevel@tonic-gate size_t bufsiz; 3867c478bd9Sstevel@tonic-gate cyc_index_t *buf; 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate if (softbuf->cys_hard != softbuf->cys_soft) 3897c478bd9Sstevel@tonic-gate shared = 0; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate again: 3927c478bd9Sstevel@tonic-gate pc = &softbuf->cys_buf[which]; 3937c478bd9Sstevel@tonic-gate bufsiz = (pc->cypc_sizemask + 1) * sizeof (cyc_index_t); 3947c478bd9Sstevel@tonic-gate buf = mdb_alloc(bufsiz, UM_SLEEP | UM_GC); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate if (mdb_vread(buf, bufsiz, (uintptr_t)pc->cypc_buf) == -1) { 3977c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cypc_buf at %p", pc->cypc_buf); 3987c478bd9Sstevel@tonic-gate continue; 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate mdb_printf("\n%3s %4s %4s %4s %*s %4s %*s\n", "CPU", 4027c478bd9Sstevel@tonic-gate "LEVL", "USER", "NDX", CYC_ADDR_WIDTH, "ADDR", "CYC", 4037c478bd9Sstevel@tonic-gate CYC_ADDR_WIDTH, "CYC_ADDR", "PEND"); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate for (i = 0; i <= pc->cypc_sizemask && 4067c478bd9Sstevel@tonic-gate i <= pc->cypc_prodndx; i++) { 4077c478bd9Sstevel@tonic-gate uintptr_t cyc_addr = caddr + buf[i] * sizeof (cyclic_t); 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate mdb_printf("%3d %4s %4s ", c.cpu_id, 4107c478bd9Sstevel@tonic-gate lev == CY_HIGH_LEVEL ? "high" : 4117c478bd9Sstevel@tonic-gate lev == CY_LOCK_LEVEL ? "lock" : 4127c478bd9Sstevel@tonic-gate lev == CY_LOW_LEVEL ? "low" : "????", 4137c478bd9Sstevel@tonic-gate shared ? "shrd" : which == softbuf->cys_hard ? 4147c478bd9Sstevel@tonic-gate "hard" : "soft"); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate mdb_printf("%4d %0*p ", i, CYC_ADDR_WIDTH, 4177c478bd9Sstevel@tonic-gate (uintptr_t)&buf[i] - (uintptr_t)&buf[0] + 4187c478bd9Sstevel@tonic-gate (uintptr_t)pc->cypc_buf, buf[i], 4197c478bd9Sstevel@tonic-gate caddr + buf[i] * sizeof (cyclic_t)); 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate if (i >= pc->cypc_prodndx) 4227c478bd9Sstevel@tonic-gate mdb_printf("%4s %*s %5s ", 4237c478bd9Sstevel@tonic-gate "-", CYC_ADDR_WIDTH, "-", "-"); 4247c478bd9Sstevel@tonic-gate else { 4257c478bd9Sstevel@tonic-gate cyclic_t c; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate if (mdb_vread(&c, sizeof (c), cyc_addr) == -1) { 4287c478bd9Sstevel@tonic-gate mdb_warn("\ncouldn't read cyclic at " 4297c478bd9Sstevel@tonic-gate "%p", cyc_addr); 4307c478bd9Sstevel@tonic-gate continue; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate mdb_printf("%4d %0*p %5d ", buf[i], 4347c478bd9Sstevel@tonic-gate CYC_ADDR_WIDTH, cyc_addr, c.cy_pend); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate if (i == (pc->cypc_consndx & pc->cypc_sizemask)) { 4387c478bd9Sstevel@tonic-gate mdb_printf("<-- consndx"); 4397c478bd9Sstevel@tonic-gate if (i == (pc->cypc_prodndx & pc->cypc_sizemask)) 4407c478bd9Sstevel@tonic-gate mdb_printf(",prodndx"); 4417c478bd9Sstevel@tonic-gate mdb_printf("\n"); 4427c478bd9Sstevel@tonic-gate continue; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate if (i == (pc->cypc_prodndx & pc->cypc_sizemask)) { 4467c478bd9Sstevel@tonic-gate mdb_printf("<-- prodndx\n"); 4477c478bd9Sstevel@tonic-gate continue; 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate mdb_printf("\n"); 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate if (i >= pc->cypc_prodndx) 4527c478bd9Sstevel@tonic-gate break; 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if (!shared && which == softbuf->cys_hard) { 4567c478bd9Sstevel@tonic-gate which = softbuf->cys_soft; 4577c478bd9Sstevel@tonic-gate goto again; 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate out: 4627c478bd9Sstevel@tonic-gate mdb_dec_indent(2); 4637c478bd9Sstevel@tonic-gate return (DCMD_OK); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate int 4677c478bd9Sstevel@tonic-gate cyctrace_walk_init(mdb_walk_state_t *wsp) 4687c478bd9Sstevel@tonic-gate { 4697c478bd9Sstevel@tonic-gate cyc_cpu_t *cpu; 4707c478bd9Sstevel@tonic-gate int i; 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate cpu = mdb_zalloc(sizeof (cyc_cpu_t), UM_SLEEP); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate if (wsp->walk_addr == NULL) { 4757c478bd9Sstevel@tonic-gate /* 4767c478bd9Sstevel@tonic-gate * If an address isn't provided, we'll use the passive buffer. 4777c478bd9Sstevel@tonic-gate */ 4787c478bd9Sstevel@tonic-gate GElf_Sym sym; 4797c478bd9Sstevel@tonic-gate cyc_tracebuf_t *tr = &cpu->cyp_trace[0]; 4807c478bd9Sstevel@tonic-gate uintptr_t addr; 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate if (mdb_lookup_by_name("cyc_ptrace", &sym) == -1) { 4837c478bd9Sstevel@tonic-gate mdb_warn("couldn't find passive buffer"); 4847c478bd9Sstevel@tonic-gate return (-1); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate addr = (uintptr_t)sym.st_value; 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate if (mdb_vread(tr, sizeof (cyc_tracebuf_t), addr) == -1) { 4907c478bd9Sstevel@tonic-gate mdb_warn("couldn't read passive buffer"); 4917c478bd9Sstevel@tonic-gate return (-1); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate wsp->walk_addr = addr - offsetof(cyc_cpu_t, cyp_trace[0]); 4957c478bd9Sstevel@tonic-gate } else { 496*8a6a72fdSaf if (cyccpu_vread(cpu, wsp->walk_addr) == -1) { 4977c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyc_cpu at %p", wsp->walk_addr); 4987c478bd9Sstevel@tonic-gate mdb_free(cpu, sizeof (cyc_cpu_t)); 4997c478bd9Sstevel@tonic-gate return (-1); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate } 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate for (i = 0; i < CY_LEVELS; i++) { 5047c478bd9Sstevel@tonic-gate if (cpu->cyp_trace[i].cyt_ndx-- == 0) 5057c478bd9Sstevel@tonic-gate cpu->cyp_trace[i].cyt_ndx = CY_NTRACEREC - 1; 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate wsp->walk_data = cpu; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate return (0); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate int 5147c478bd9Sstevel@tonic-gate cyctrace_walk_step(mdb_walk_state_t *wsp) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate cyc_cpu_t *cpu = wsp->walk_data; 5177c478bd9Sstevel@tonic-gate cyc_tracebuf_t *buf = cpu->cyp_trace; 5187c478bd9Sstevel@tonic-gate hrtime_t latest = 0; 5197c478bd9Sstevel@tonic-gate int i, ndx, new_ndx, lev, rval; 5207c478bd9Sstevel@tonic-gate uintptr_t addr; 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate for (i = 0; i < CY_LEVELS; i++) { 5237c478bd9Sstevel@tonic-gate if ((ndx = buf[i].cyt_ndx) == -1) 5247c478bd9Sstevel@tonic-gate continue; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate /* 5277c478bd9Sstevel@tonic-gate * Account for NPT. 5287c478bd9Sstevel@tonic-gate */ 5297c478bd9Sstevel@tonic-gate buf[i].cyt_buf[ndx].cyt_tstamp <<= 1; 5307c478bd9Sstevel@tonic-gate buf[i].cyt_buf[ndx].cyt_tstamp >>= 1; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate if (buf[i].cyt_buf[ndx].cyt_tstamp > latest) { 5337c478bd9Sstevel@tonic-gate latest = buf[i].cyt_buf[ndx].cyt_tstamp; 5347c478bd9Sstevel@tonic-gate lev = i; 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate /* 5397c478bd9Sstevel@tonic-gate * If we didn't find one, we're done. 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate if (latest == 0) 5427c478bd9Sstevel@tonic-gate return (-1); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate buf = &buf[lev]; 5457c478bd9Sstevel@tonic-gate ndx = buf->cyt_ndx; 5467c478bd9Sstevel@tonic-gate addr = wsp->walk_addr + 5477c478bd9Sstevel@tonic-gate (uintptr_t)&(buf->cyt_buf[ndx]) - (uintptr_t)cpu; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate rval = wsp->walk_callback(addr, &buf->cyt_buf[ndx], wsp->walk_cbdata); 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate new_ndx = ndx == 0 ? CY_NTRACEREC - 1 : ndx - 1; 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate if (buf->cyt_buf[new_ndx].cyt_tstamp != 0 && 5547c478bd9Sstevel@tonic-gate buf->cyt_buf[new_ndx].cyt_tstamp > buf->cyt_buf[ndx].cyt_tstamp) 5557c478bd9Sstevel@tonic-gate new_ndx = -1; 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate buf->cyt_ndx = new_ndx; 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate return (rval); 5607c478bd9Sstevel@tonic-gate } 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate void 5637c478bd9Sstevel@tonic-gate cyctrace_walk_fini(mdb_walk_state_t *wsp) 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate cyc_cpu_t *cpu = wsp->walk_data; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate mdb_free(cpu, sizeof (cyc_cpu_t)); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate #define WHYLEN 17 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate int 5737c478bd9Sstevel@tonic-gate cyctrace_walk(uintptr_t addr, const cyc_tracerec_t *rec, cyc_cpu_t *cpu) 5747c478bd9Sstevel@tonic-gate { 5757c478bd9Sstevel@tonic-gate int i; 5767c478bd9Sstevel@tonic-gate char c[WHYLEN]; 5777c478bd9Sstevel@tonic-gate 5787c478bd9Sstevel@tonic-gate for (i = 0; cpu != NULL && i < CY_LEVELS; i++) 5797c478bd9Sstevel@tonic-gate if (addr < (uintptr_t)&cpu->cyp_trace[i + 1].cyt_buf[0]) 5807c478bd9Sstevel@tonic-gate break; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate (void) mdb_readstr(c, WHYLEN, (uintptr_t)rec->cyt_why); 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate mdb_printf("%08p %4s %15llx %-*s %15llx %15llx\n", 5857c478bd9Sstevel@tonic-gate addr & UINT_MAX, cpu == NULL ? "pasv" : 5867c478bd9Sstevel@tonic-gate i == CY_HIGH_LEVEL ? "high" : i == CY_LOCK_LEVEL ? "lock" : 5877c478bd9Sstevel@tonic-gate i == CY_LOW_LEVEL ? "low" : "????", rec->cyt_tstamp, WHYLEN, c, 5887c478bd9Sstevel@tonic-gate rec->cyt_arg0, rec->cyt_arg1); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate return (0); 5917c478bd9Sstevel@tonic-gate } 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5947c478bd9Sstevel@tonic-gate int 5957c478bd9Sstevel@tonic-gate cyctrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 5967c478bd9Sstevel@tonic-gate { 5977c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc != 0) 5987c478bd9Sstevel@tonic-gate addr = NULL; 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate if (mdb_pwalk("cyctrace", (mdb_walk_cb_t)cyctrace_walk, 6017c478bd9Sstevel@tonic-gate (void *)addr, addr) == -1) { 6027c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk cyctrace"); 6037c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate return (DCMD_OK); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate int 6107c478bd9Sstevel@tonic-gate cyccover_comp(const void *l, const void *r) 6117c478bd9Sstevel@tonic-gate { 6127c478bd9Sstevel@tonic-gate cyc_coverage_t *lhs = (cyc_coverage_t *)l; 6137c478bd9Sstevel@tonic-gate cyc_coverage_t *rhs = (cyc_coverage_t *)r; 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate char ly[WHYLEN], ry[WHYLEN]; 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate if (rhs->cyv_why == lhs->cyv_why) 6187c478bd9Sstevel@tonic-gate return (0); 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate if (rhs->cyv_why == NULL) 6217c478bd9Sstevel@tonic-gate return (-1); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate if (lhs->cyv_why == NULL) 6247c478bd9Sstevel@tonic-gate return (1); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate (void) mdb_readstr(ly, WHYLEN, (uintptr_t)lhs->cyv_why); 6277c478bd9Sstevel@tonic-gate (void) mdb_readstr(ry, WHYLEN, (uintptr_t)rhs->cyv_why); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate return (strcmp(ly, ry)); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6337c478bd9Sstevel@tonic-gate int 6347c478bd9Sstevel@tonic-gate cyccover(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6357c478bd9Sstevel@tonic-gate { 6367c478bd9Sstevel@tonic-gate cyc_coverage_t cv[CY_NCOVERAGE]; 6377c478bd9Sstevel@tonic-gate char c[WHYLEN]; 6387c478bd9Sstevel@tonic-gate GElf_Sym sym; 6397c478bd9Sstevel@tonic-gate int i; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate if ((flags & DCMD_ADDRSPEC) || argc != 0) 6427c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate if (mdb_lookup_by_name("cyc_coverage", &sym) == -1) { 6457c478bd9Sstevel@tonic-gate mdb_warn("couldn't find coverage information"); 6467c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 6477c478bd9Sstevel@tonic-gate } 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate addr = (uintptr_t)sym.st_value; 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate if (mdb_vread(cv, sizeof (cyc_coverage_t) * CY_NCOVERAGE, addr) == -1) { 6527c478bd9Sstevel@tonic-gate mdb_warn("couldn't read coverage array at %p", addr); 6537c478bd9Sstevel@tonic-gate return (DCMD_ABORT); 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate mdb_printf("%-*s %8s %8s %8s %15s %15s\n", 6577c478bd9Sstevel@tonic-gate WHYLEN, "POINT", "HIGH", "LOCK", "LOW/PASV", "ARG0", "ARG1"); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate qsort(cv, CY_NCOVERAGE, sizeof (cyc_coverage_t), cyccover_comp); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate for (i = 0; i < CY_NCOVERAGE; i++) { 6627c478bd9Sstevel@tonic-gate if (cv[i].cyv_why != NULL) { 6637c478bd9Sstevel@tonic-gate (void) mdb_readstr(c, WHYLEN, (uintptr_t)cv[i].cyv_why); 6647c478bd9Sstevel@tonic-gate mdb_printf("%-*s %8d %8d %8d %15llx %15llx\n", 6657c478bd9Sstevel@tonic-gate WHYLEN, c, 6667c478bd9Sstevel@tonic-gate cv[i].cyv_count[CY_HIGH_LEVEL], 6677c478bd9Sstevel@tonic-gate cv[i].cyv_count[CY_LOCK_LEVEL], 6687c478bd9Sstevel@tonic-gate cv[i].cyv_passive_count != 0 ? 6697c478bd9Sstevel@tonic-gate cv[i].cyv_passive_count : 6707c478bd9Sstevel@tonic-gate cv[i].cyv_count[CY_LOW_LEVEL], 6717c478bd9Sstevel@tonic-gate cv[i].cyv_arg0, cv[i].cyv_arg1); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate return (DCMD_OK); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6797c478bd9Sstevel@tonic-gate int 6807c478bd9Sstevel@tonic-gate cyclic(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 6817c478bd9Sstevel@tonic-gate { 6827c478bd9Sstevel@tonic-gate cyclic_t cyc; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC) || argc != 0) 6857c478bd9Sstevel@tonic-gate return (DCMD_USAGE); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) 6887c478bd9Sstevel@tonic-gate mdb_printf("%?s %4s %5s %5s %15s %7s %s\n", "ADDR", "LEVL", 6897c478bd9Sstevel@tonic-gate "PEND", "FLAGS", "FIRE", "USECINT", "HANDLER"); 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate if (mdb_vread(&cyc, sizeof (cyclic_t), addr) == -1) { 6927c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyclic at %p", addr); 6937c478bd9Sstevel@tonic-gate return (DCMD_ERR); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate mdb_printf("%0?p %4s %5d %04x %15llx %7lld %a\n", addr, 6977c478bd9Sstevel@tonic-gate cyc.cy_level == CY_HIGH_LEVEL ? "high" : 6987c478bd9Sstevel@tonic-gate cyc.cy_level == CY_LOCK_LEVEL ? "lock" : 6997c478bd9Sstevel@tonic-gate cyc.cy_level == CY_LOW_LEVEL ? "low" : "????", 7007c478bd9Sstevel@tonic-gate cyc.cy_pend, cyc.cy_flags, cyc.cy_expire, 7017c478bd9Sstevel@tonic-gate cyc.cy_interval / (uint64_t)(NANOSEC / MICROSEC), 7027c478bd9Sstevel@tonic-gate cyc.cy_handler); 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate return (DCMD_OK); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate static int 7087c478bd9Sstevel@tonic-gate cycid_cpu(cyc_cpu_t *addr, int ndx) 7097c478bd9Sstevel@tonic-gate { 7107c478bd9Sstevel@tonic-gate cyc_cpu_t cpu; 7117c478bd9Sstevel@tonic-gate cpu_t c; 7127c478bd9Sstevel@tonic-gate uintptr_t caddr; 7137c478bd9Sstevel@tonic-gate cyclic_t cyc; 7147c478bd9Sstevel@tonic-gate 715*8a6a72fdSaf if (cyccpu_vread(&cpu, (uintptr_t)addr) == -1) { 7167c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyc_cpu at %p", addr); 7177c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7187c478bd9Sstevel@tonic-gate } 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate if (mdb_vread(&c, sizeof (c), (uintptr_t)cpu.cyp_cpu) == -1) { 7217c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cpu at %p", cpu.cyp_cpu); 7227c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate caddr = (uintptr_t)cpu.cyp_cyclics + ndx * sizeof (cyclic_t); 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate if (mdb_vread(&cyc, sizeof (cyc), caddr) == -1) { 7287c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyclic at %p", caddr); 7297c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate mdb_printf("%4d %3d %?p %a\n", c.cpu_id, ndx, caddr, cyc.cy_handler); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate return (DCMD_OK); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7387c478bd9Sstevel@tonic-gate static int 7397c478bd9Sstevel@tonic-gate cycid_walk_omni(uintptr_t addr, const cyc_omni_cpu_t *omni, int *ignored) 7407c478bd9Sstevel@tonic-gate { 7417c478bd9Sstevel@tonic-gate mdb_printf("%?s "); 7427c478bd9Sstevel@tonic-gate cycid_cpu(omni->cyo_cpu, omni->cyo_ndx); 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate return (WALK_NEXT); 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 7487c478bd9Sstevel@tonic-gate int 7497c478bd9Sstevel@tonic-gate cycid(uintptr_t addr, uint_t flags, int ac, const mdb_arg_t *av) 7507c478bd9Sstevel@tonic-gate { 7517c478bd9Sstevel@tonic-gate cyc_id_t id; 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate if (!(flags & DCMD_ADDRSPEC)) { 7547c478bd9Sstevel@tonic-gate if (mdb_walk_dcmd("cyclic_id_cache", "cycid", ac, av) == -1) { 7557c478bd9Sstevel@tonic-gate mdb_warn("can't walk cyclic_id_cache"); 7567c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate return (DCMD_OK); 7607c478bd9Sstevel@tonic-gate } 7617c478bd9Sstevel@tonic-gate 7627c478bd9Sstevel@tonic-gate if (DCMD_HDRSPEC(flags)) { 7637c478bd9Sstevel@tonic-gate mdb_printf("%?s %4s %3s %?s %s\n", "ADDR", "CPU", "NDX", 7647c478bd9Sstevel@tonic-gate "CYCLIC", "HANDLER"); 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate if (mdb_vread(&id, sizeof (id), addr) == -1) { 7687c478bd9Sstevel@tonic-gate mdb_warn("couldn't read cyc_id_t at %p", addr); 7697c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate if (id.cyi_cpu == NULL) { 7737c478bd9Sstevel@tonic-gate /* 7747c478bd9Sstevel@tonic-gate * This is an omnipresent cyclic. 7757c478bd9Sstevel@tonic-gate */ 7767c478bd9Sstevel@tonic-gate mdb_printf("%?p %4s %3s %?s %a\n", addr, "omni", "-", "-", 7777c478bd9Sstevel@tonic-gate id.cyi_omni_hdlr.cyo_online); 7787c478bd9Sstevel@tonic-gate mdb_printf("%?s |\n", ""); 7797c478bd9Sstevel@tonic-gate mdb_printf("%?s +-->%4s %3s %?s %s\n", "", 7807c478bd9Sstevel@tonic-gate "CPU", "NDX", "CYCLIC", "HANDLER"); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate if (mdb_pwalk("cycomni", 7837c478bd9Sstevel@tonic-gate (mdb_walk_cb_t)cycid_walk_omni, NULL, addr) == -1) { 7847c478bd9Sstevel@tonic-gate mdb_warn("couldn't walk cycomni for %p", addr); 7857c478bd9Sstevel@tonic-gate return (DCMD_ERR); 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate mdb_printf("\n"); 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate return (DCMD_OK); 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate mdb_printf("%?p ", addr); 7947c478bd9Sstevel@tonic-gate 7957c478bd9Sstevel@tonic-gate return (cycid_cpu(id.cyi_cpu, id.cyi_ndx)); 7967c478bd9Sstevel@tonic-gate } 797