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