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