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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <mdb/mdb_modapi.h> 29 #include <mdb/mdb_ctf.h> 30 #include <sys/cpuvar.h> 31 #include <sys/systm.h> 32 #include <sys/traptrace.h> 33 #include <sys/x_call.h> 34 #include <sys/avintr.h> 35 #include <sys/systm.h> 36 #include <sys/trap.h> 37 #include <sys/mutex.h> 38 #include <sys/mutex_impl.h> 39 #include "i86mmu.h" 40 41 #define TT_HDLR_WIDTH 17 42 43 static int 44 ttrace_ttr_size_check(void) 45 { 46 mdb_ctf_id_t ttrtid; 47 ssize_t ttr_size; 48 49 if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 || 50 mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) { 51 mdb_warn("failed to determine size of trap_trace_rec_t; " 52 "non-TRAPTRACE kernel?\n"); 53 return (0); 54 } 55 56 if ((ttr_size = mdb_ctf_type_size(ttrtid)) != 57 sizeof (trap_trace_rec_t)) { 58 /* 59 * On Intel machines, this will happen when TTR_STACK_DEPTH 60 * is changed. This code could be smarter, and could 61 * dynamically adapt to different depths, but not until a 62 * need for such adaptation is demonstrated. 63 */ 64 mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't " 65 "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t)); 66 return (0); 67 } 68 69 return (1); 70 } 71 72 int 73 ttrace_walk_init(mdb_walk_state_t *wsp) 74 { 75 trap_trace_ctl_t *ttcp; 76 size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 77 int i; 78 79 if (!ttrace_ttr_size_check()) 80 return (WALK_ERR); 81 82 ttcp = mdb_zalloc(ttc_size, UM_SLEEP); 83 84 if (wsp->walk_addr != NULL) { 85 mdb_warn("ttrace only supports global walks\n"); 86 return (WALK_ERR); 87 } 88 89 if (mdb_readsym(ttcp, ttc_size, "trap_trace_ctl") == -1) { 90 mdb_warn("symbol 'trap_trace_ctl' not found; " 91 "non-TRAPTRACE kernel?\n"); 92 mdb_free(ttcp, ttc_size); 93 return (WALK_ERR); 94 } 95 96 /* 97 * We'll poach the ttc_current pointer (which isn't used for 98 * anything) to store a pointer to our current TRAPTRACE record. 99 * This allows us to only keep the array of trap_trace_ctl structures 100 * as our walker state (ttc_current may be the only kernel data 101 * structure member added exclusively to make writing the mdb walker 102 * a little easier). 103 */ 104 for (i = 0; i < NCPU; i++) { 105 trap_trace_ctl_t *ttc = &ttcp[i]; 106 107 if (ttc->ttc_first == NULL) 108 continue; 109 110 /* 111 * Assign ttc_current to be the last completed record. 112 * Note that the error checking (i.e. in the ttc_next == 113 * ttc_first case) is performed in the step function. 114 */ 115 ttc->ttc_current = ttc->ttc_next - sizeof (trap_trace_rec_t); 116 } 117 118 wsp->walk_data = ttcp; 119 return (WALK_NEXT); 120 } 121 122 int 123 ttrace_walk_step(mdb_walk_state_t *wsp) 124 { 125 trap_trace_ctl_t *ttcp = wsp->walk_data, *ttc, *latest_ttc; 126 trap_trace_rec_t rec; 127 int rval, i, recsize = sizeof (trap_trace_rec_t); 128 hrtime_t latest = 0; 129 130 /* 131 * Loop through the CPUs, looking for the latest trap trace record 132 * (we want to walk through the trap trace records in reverse 133 * chronological order). 134 */ 135 for (i = 0; i < NCPU; i++) { 136 ttc = &ttcp[i]; 137 138 if (ttc->ttc_current == NULL) 139 continue; 140 141 if (ttc->ttc_current < ttc->ttc_first) 142 ttc->ttc_current = ttc->ttc_limit - recsize; 143 144 if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 145 mdb_warn("couldn't read rec at %p", ttc->ttc_current); 146 return (WALK_ERR); 147 } 148 149 if (rec.ttr_stamp > latest) { 150 latest = rec.ttr_stamp; 151 latest_ttc = ttc; 152 } 153 } 154 155 if (latest == 0) 156 return (WALK_DONE); 157 158 ttc = latest_ttc; 159 160 if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) { 161 mdb_warn("couldn't read rec at %p", ttc->ttc_current); 162 return (WALK_ERR); 163 } 164 165 rval = wsp->walk_callback(ttc->ttc_current, &rec, wsp->walk_cbdata); 166 167 if (ttc->ttc_current == ttc->ttc_next) 168 ttc->ttc_current = NULL; 169 else 170 ttc->ttc_current -= sizeof (trap_trace_rec_t); 171 172 return (rval); 173 } 174 175 void 176 ttrace_walk_fini(mdb_walk_state_t *wsp) 177 { 178 mdb_free(wsp->walk_data, sizeof (trap_trace_ctl_t) * NCPU); 179 } 180 181 static int 182 ttrace_syscall(trap_trace_rec_t *rec) 183 { 184 GElf_Sym sym; 185 int sysnum = rec->ttr_sysnum; 186 uintptr_t addr; 187 struct sysent sys; 188 189 mdb_printf("%-3x", sysnum); 190 191 if (rec->ttr_sysnum > NSYSCALL) { 192 mdb_printf(" %-*d", TT_HDLR_WIDTH, rec->ttr_sysnum); 193 return (0); 194 } 195 196 if (mdb_lookup_by_name("sysent", &sym) == -1) { 197 mdb_warn("\ncouldn't find 'sysent'"); 198 return (-1); 199 } 200 201 addr = (uintptr_t)sym.st_value + sysnum * sizeof (struct sysent); 202 203 if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 204 mdb_warn("\nsysnum %d out-of-range\n", sysnum); 205 return (-1); 206 } 207 208 if (mdb_vread(&sys, sizeof (sys), addr) == -1) { 209 mdb_warn("\nfailed to read sysent at %p", addr); 210 return (-1); 211 } 212 213 mdb_printf(" %-*a", TT_HDLR_WIDTH, sys.sy_callc); 214 215 return (0); 216 } 217 218 static int 219 ttrace_interrupt(trap_trace_rec_t *rec) 220 { 221 GElf_Sym sym; 222 uintptr_t addr; 223 struct av_head hd; 224 struct autovec av; 225 226 switch (rec->ttr_regs.r_trapno) { 227 case T_SOFTINT: 228 mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)"); 229 return (0); 230 default: 231 break; 232 } 233 234 mdb_printf("%-3x ", rec->ttr_vector); 235 236 if (mdb_lookup_by_name("autovect", &sym) == -1) { 237 mdb_warn("\ncouldn't find 'autovect'"); 238 return (-1); 239 } 240 241 addr = (uintptr_t)sym.st_value + 242 rec->ttr_vector * sizeof (struct av_head); 243 244 if (addr >= (uintptr_t)sym.st_value + sym.st_size) { 245 mdb_warn("\nav_head for vec %x is corrupt\n", rec->ttr_vector); 246 return (-1); 247 } 248 249 if (mdb_vread(&hd, sizeof (hd), addr) == -1) { 250 mdb_warn("\ncouldn't read av_head for vec %x", rec->ttr_vector); 251 return (-1); 252 } 253 254 if (hd.avh_link == NULL) { 255 if (rec->ttr_ipl == XC_CPUPOKE_PIL) 256 mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)"); 257 else 258 mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)"); 259 } else { 260 if (mdb_vread(&av, sizeof (av), (uintptr_t)hd.avh_link) == -1) { 261 mdb_warn("couldn't read autovec at %p", 262 (uintptr_t)hd.avh_link); 263 } 264 265 mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector); 266 } 267 268 return (0); 269 } 270 271 static struct { 272 int tt_trapno; 273 char *tt_name; 274 } ttrace_traps[] = { 275 { T_ZERODIV, "divide-error" }, 276 { T_SGLSTP, "debug-exception" }, 277 { T_NMIFLT, "nmi-interrupt" }, 278 { T_BPTFLT, "breakpoint" }, 279 { T_OVFLW, "into-overflow" }, 280 { T_BOUNDFLT, "bound-exceeded" }, 281 { T_ILLINST, "invalid-opcode" }, 282 { T_NOEXTFLT, "device-not-avail" }, 283 { T_DBLFLT, "double-fault" }, 284 { T_EXTOVRFLT, "segment-overrun" }, 285 { T_TSSFLT, "invalid-tss" }, 286 { T_SEGFLT, "segment-not-pres" }, 287 { T_STKFLT, "stack-fault" }, 288 { T_GPFLT, "general-protectn" }, 289 { T_PGFLT, "page-fault" }, 290 { T_EXTERRFLT, "error-fault" }, 291 { T_ALIGNMENT, "alignment-check" }, 292 { T_MCE, "machine-check" }, 293 { T_SIMDFPE, "sse-exception" }, 294 295 { T_DBGENTR, "debug-enter" }, 296 { T_FASTTRAP, "fasttrap-0xd2" }, 297 { T_SYSCALLINT, "syscall-0x91" }, 298 { T_DTRACE_RET, "dtrace-ret" }, 299 { T_SOFTINT, "softint" }, 300 { T_INTERRUPT, "interrupt" }, 301 { T_FAULT, "fault" }, 302 { T_AST, "ast" }, 303 { T_SYSCALL, "syscall" }, 304 305 { 0, NULL } 306 }; 307 308 static int 309 ttrace_trap(trap_trace_rec_t *rec) 310 { 311 int i; 312 313 if (rec->ttr_regs.r_trapno == T_AST) 314 mdb_printf("%-3s ", "-"); 315 else 316 mdb_printf("%-3x ", rec->ttr_regs.r_trapno); 317 318 for (i = 0; ttrace_traps[i].tt_name != NULL; i++) { 319 if (rec->ttr_regs.r_trapno == ttrace_traps[i].tt_trapno) 320 break; 321 } 322 323 if (ttrace_traps[i].tt_name == NULL) 324 mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)"); 325 else 326 mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_traps[i].tt_name); 327 328 return (0); 329 } 330 331 static struct { 332 int tt_type; 333 char *tt_name; 334 } ttrace_xcalls[] = { 335 { TT_XC_SVC_BEGIN, "<svc-begin>" }, 336 { TT_XC_SVC_END, "<svc-end>" }, 337 { TT_XC_START, "<start>" }, 338 { TT_XC_WAIT, "<wait>" }, 339 { TT_XC_ACK, "<ack>" }, 340 { TT_XC_CAPTURE, "<capture>" }, 341 { TT_XC_RELEASE, "<release>" }, 342 { TT_XC_POKE_CPU, "<poke-cpu>" }, 343 { TT_XC_CBE_FIRE, "<cbe-fire>" }, 344 { TT_XC_CBE_XCALL, "<cbe-xcall>" }, 345 { 0, NULL } 346 }; 347 348 static int 349 ttrace_xcall(trap_trace_rec_t *rec) 350 { 351 struct _xc_entry *xce = &(rec->ttr_info.xc_entry); 352 int i; 353 354 for (i = 0; ttrace_xcalls[i].tt_name != NULL; i++) 355 if (ttrace_xcalls[i].tt_type == xce->xce_marker) 356 break; 357 358 switch (xce->xce_marker) { 359 case TT_XC_SVC_BEGIN: 360 case TT_XC_SVC_END: 361 mdb_printf("%3s ", "-"); 362 break; 363 default: 364 mdb_printf("%3x ", (int)xce->xce_arg); 365 break; 366 } 367 368 if (ttrace_xcalls[i].tt_name == NULL) 369 mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)"); 370 else 371 mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_xcalls[i].tt_name); 372 return (0); 373 } 374 375 static char * 376 xc_pri_to_str(int pri) 377 { 378 switch (pri) { 379 case X_CALL_LOPRI: 380 return (" low"); 381 case X_CALL_MEDPRI: 382 return (" med"); 383 case X_CALL_HIPRI: 384 return ("high"); 385 default: 386 return ("bad?"); 387 } 388 } 389 390 static char * 391 xc_state_to_str(uint8_t state) 392 { 393 switch (state) { 394 case XC_DONE: 395 return ("done"); 396 case XC_HOLD: 397 return ("hold"); 398 case XC_SYNC_OP: 399 return ("sync"); 400 case XC_CALL_OP: 401 return ("call"); 402 case XC_WAIT: 403 return ("wait"); 404 default: 405 return ("bad?"); 406 } 407 } 408 409 static void 410 ttrace_intr_detail(trap_trace_rec_t *rec) 411 { 412 mdb_printf("\tirq %x ipl %d oldpri %d basepri %d\n", rec->ttr_vector, 413 rec->ttr_ipl, rec->ttr_pri, rec->ttr_spl); 414 } 415 416 static void 417 ttrace_xcall_detail(trap_trace_rec_t *rec) 418 { 419 struct _xc_entry *xce = &(rec->ttr_info.xc_entry); 420 421 if ((uint_t)xce->xce_pri < X_CALL_LEVELS) 422 mdb_printf("\t%s pri [%s] ", xc_pri_to_str(xce->xce_pri), 423 xc_state_to_str(xce->xce_state)); 424 else 425 mdb_printf("\t"); 426 427 switch (xce->xce_marker) { 428 case TT_XC_SVC_BEGIN: 429 if (xce->xce_pri != X_CALL_MEDPRI && xce->xce_func != NULL) 430 mdb_printf("call %a() ..", xce->xce_func); 431 break; 432 case TT_XC_SVC_END: 433 if (xce->xce_arg == DDI_INTR_UNCLAIMED) 434 mdb_printf("[spurious]"); 435 else if (xce->xce_pri != X_CALL_MEDPRI && 436 xce->xce_func != NULL) 437 mdb_printf(".. called %a() returned %d", 438 xce->xce_func, xce->xce_retval); 439 break; 440 case TT_XC_START: 441 case TT_XC_CAPTURE: 442 mdb_printf("--> cpu%d", (int)xce->xce_arg); 443 break; 444 case TT_XC_RELEASE: 445 case TT_XC_WAIT: 446 case TT_XC_ACK: 447 mdb_printf("<-- cpu%d", (int)xce->xce_arg); 448 break; 449 case TT_XC_POKE_CPU: 450 case TT_XC_CBE_FIRE: 451 case TT_XC_CBE_XCALL: 452 mdb_printf("--> cpu%d", (int)xce->xce_arg); 453 break; 454 default: 455 mdb_printf("tag %d? arg 0x%lx", 456 xce->xce_marker, xce->xce_arg); 457 break; 458 } 459 mdb_printf("\n\n"); 460 } 461 462 static struct { 463 uchar_t t_marker; 464 char *t_name; 465 int (*t_hdlr)(trap_trace_rec_t *); 466 } ttrace_hdlr[] = { 467 { TT_SYSCALL, "sysc", ttrace_syscall }, 468 { TT_SYSENTER, "syse", ttrace_syscall }, 469 { TT_SYSC, "asys", ttrace_syscall }, 470 { TT_SYSC64, "sc64", ttrace_syscall }, 471 { TT_INTERRUPT, "intr", ttrace_interrupt }, 472 { TT_TRAP, "trap", ttrace_trap }, 473 { TT_EVENT, "evnt", ttrace_trap }, 474 { TT_XCALL, "xcal", ttrace_xcall }, 475 { 0, NULL, NULL } 476 }; 477 478 typedef struct ttrace_dcmd { 479 processorid_t ttd_cpu; 480 uint_t ttd_extended; 481 trap_trace_ctl_t ttd_ttc[NCPU]; 482 } ttrace_dcmd_t; 483 484 #if defined(__amd64) 485 486 #define DUMP(reg) #reg, regs->r_##reg 487 #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n" 488 489 static void 490 ttrace_dumpregs(trap_trace_rec_t *rec) 491 { 492 struct regs *regs = &rec->ttr_regs; 493 494 mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx)); 495 mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9)); 496 mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp)); 497 mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12)); 498 mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15)); 499 mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs)); 500 mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err)); 501 mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl)); 502 mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2); 503 mdb_printf("\n"); 504 } 505 506 #else 507 508 #define DUMP(reg) #reg, regs->r_##reg 509 #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n" 510 511 static void 512 ttrace_dumpregs(trap_trace_rec_t *rec) 513 { 514 struct regs *regs = &rec->ttr_regs; 515 516 mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds)); 517 mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp)); 518 mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax)); 519 mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err), 520 DUMP(pc), DUMP(cs)); 521 mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss), 522 "cr2", rec->ttr_cr2); 523 mdb_printf("\n"); 524 } 525 526 #endif /* __amd64 */ 527 528 int 529 ttrace_walk(uintptr_t addr, trap_trace_rec_t *rec, ttrace_dcmd_t *dcmd) 530 { 531 struct regs *regs = &rec->ttr_regs; 532 processorid_t cpu = -1, i; 533 534 for (i = 0; i < NCPU; i++) { 535 if (addr >= dcmd->ttd_ttc[i].ttc_first && 536 addr < dcmd->ttd_ttc[i].ttc_limit) { 537 cpu = i; 538 break; 539 } 540 } 541 542 if (cpu == -1) { 543 mdb_warn("couldn't find %p in any trap trace ctl\n", addr); 544 return (WALK_ERR); 545 } 546 547 if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu) 548 return (WALK_NEXT); 549 550 mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp); 551 552 for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) { 553 if (rec->ttr_marker != ttrace_hdlr[i].t_marker) 554 continue; 555 mdb_printf("%4s ", ttrace_hdlr[i].t_name); 556 if (ttrace_hdlr[i].t_hdlr(rec) == -1) 557 return (WALK_ERR); 558 } 559 560 mdb_printf(" %a\n", regs->r_pc); 561 562 if (dcmd->ttd_extended == FALSE) 563 return (WALK_NEXT); 564 565 if (rec->ttr_marker == TT_XCALL) 566 ttrace_xcall_detail(rec); 567 else if (rec->ttr_marker == TT_INTERRUPT) 568 ttrace_intr_detail(rec); 569 else 570 ttrace_dumpregs(rec); 571 572 if (rec->ttr_sdepth > 0) { 573 for (i = 0; i < rec->ttr_sdepth; i++) { 574 if (i >= TTR_STACK_DEPTH) { 575 mdb_printf("%17s*** invalid ttr_sdepth (is %d, " 576 "should be <= %d)\n", " ", rec->ttr_sdepth, 577 TTR_STACK_DEPTH); 578 break; 579 } 580 581 mdb_printf("%17s %a()\n", " ", rec->ttr_stack[i]); 582 } 583 mdb_printf("\n"); 584 } 585 586 return (WALK_NEXT); 587 } 588 589 int 590 ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 591 { 592 ttrace_dcmd_t dcmd; 593 trap_trace_ctl_t *ttc = dcmd.ttd_ttc; 594 trap_trace_rec_t rec; 595 size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU; 596 597 if (!ttrace_ttr_size_check()) 598 return (WALK_ERR); 599 600 bzero(&dcmd, sizeof (dcmd)); 601 dcmd.ttd_cpu = -1; 602 dcmd.ttd_extended = FALSE; 603 604 if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) { 605 mdb_warn("symbol 'trap_trace_ctl' not found; " 606 "non-TRAPTRACE kernel?\n"); 607 return (DCMD_ERR); 608 } 609 610 if (mdb_getopts(argc, argv, 611 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended, NULL) != argc) 612 return (DCMD_USAGE); 613 614 if (DCMD_HDRSPEC(flags)) { 615 mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU", 616 "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER", 617 " EIP"); 618 } 619 620 if (flags & DCMD_ADDRSPEC) { 621 if (addr >= NCPU) { 622 if (mdb_vread(&rec, sizeof (rec), addr) == -1) { 623 mdb_warn("couldn't read trap trace record " 624 "at %p", addr); 625 return (DCMD_ERR); 626 } 627 628 if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR) 629 return (DCMD_ERR); 630 631 return (DCMD_OK); 632 } 633 dcmd.ttd_cpu = addr; 634 } 635 636 if (mdb_walk("ttrace", (mdb_walk_cb_t)ttrace_walk, &dcmd) == -1) { 637 mdb_warn("couldn't walk 'ttrace'"); 638 return (DCMD_ERR); 639 } 640 641 return (DCMD_OK); 642 } 643 644 /*ARGSUSED*/ 645 int 646 mutex_owner_init(mdb_walk_state_t *wsp) 647 { 648 return (WALK_NEXT); 649 } 650 651 int 652 mutex_owner_step(mdb_walk_state_t *wsp) 653 { 654 uintptr_t addr = wsp->walk_addr; 655 mutex_impl_t mtx; 656 uintptr_t owner; 657 kthread_t thr; 658 659 if (mdb_vread(&mtx, sizeof (mtx), addr) == -1) 660 return (WALK_ERR); 661 662 if (!MUTEX_TYPE_ADAPTIVE(&mtx)) 663 return (WALK_DONE); 664 665 if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == NULL) 666 return (WALK_DONE); 667 668 if (mdb_vread(&thr, sizeof (thr), owner) != -1) 669 (void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata); 670 671 return (WALK_DONE); 672 } 673 674 static void 675 gate_desc_dump(gate_desc_t *gate, const char *label, int header) 676 { 677 const char *lastnm; 678 uint_t lastval; 679 char type[4]; 680 681 switch (gate->sgd_type) { 682 case SDT_SYSIGT: 683 strcpy(type, "int"); 684 break; 685 case SDT_SYSTGT: 686 strcpy(type, "trp"); 687 break; 688 case SDT_SYSTASKGT: 689 strcpy(type, "tsk"); 690 break; 691 default: 692 (void) mdb_snprintf(type, sizeof (type), "%3x", gate->sgd_type); 693 } 694 695 #if defined(__amd64) 696 lastnm = "IST"; 697 lastval = gate->sgd_ist; 698 #else 699 lastnm = "STK"; 700 lastval = gate->sgd_stkcpy; 701 #endif 702 703 if (header) { 704 mdb_printf("%*s%<u>%-30s%</u> %<u>%-4s%</u> %<u>%3s%</u> " 705 "%<u>%1s%</u> %<u>%3s%</u> %<u>%3s%</u>\n", strlen(label), 706 "", "HANDLER", "SEL", "DPL", "P", "TYP", lastnm); 707 } 708 709 mdb_printf("%s", label); 710 711 if (gate->sgd_type == SDT_SYSTASKGT) 712 mdb_printf("%-30s ", "-"); 713 else 714 mdb_printf("%-30a ", GATESEG_GETOFFSET(gate)); 715 716 mdb_printf("%4x %d %c %3s %2x\n", gate->sgd_selector, 717 gate->sgd_dpl, (gate->sgd_p ? '+' : ' '), type, lastval); 718 } 719 720 /*ARGSUSED*/ 721 static int 722 gate_desc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 723 { 724 gate_desc_t gate; 725 726 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 727 return (DCMD_USAGE); 728 729 if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 730 sizeof (gate_desc_t)) { 731 mdb_warn("failed to read gate descriptor at %p\n", addr); 732 return (DCMD_ERR); 733 } 734 735 gate_desc_dump(&gate, "", DCMD_HDRSPEC(flags)); 736 737 return (DCMD_OK); 738 } 739 740 /*ARGSUSED*/ 741 static int 742 idt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 743 { 744 int i; 745 746 if (!(flags & DCMD_ADDRSPEC)) { 747 GElf_Sym idt; 748 749 if (mdb_lookup_by_name("idt0", &idt) < 0) { 750 mdb_warn("failed to find idt0"); 751 return (DCMD_ERR); 752 } 753 754 addr = idt.st_value; 755 } 756 757 for (i = 0; i < NIDT; i++, addr += sizeof (gate_desc_t)) { 758 gate_desc_t gate; 759 char label[6]; 760 761 if (mdb_vread(&gate, sizeof (gate_desc_t), addr) != 762 sizeof (gate_desc_t)) { 763 mdb_warn("failed to read gate descriptor at %p\n", 764 addr); 765 return (DCMD_ERR); 766 } 767 768 (void) mdb_snprintf(label, sizeof (label), "%3d: ", i); 769 gate_desc_dump(&gate, label, i == 0); 770 } 771 772 return (DCMD_OK); 773 } 774 775 static void 776 htables_help(void) 777 { 778 mdb_printf( 779 "Given a (hat_t *), generates the list of all (htable_t *)s\n" 780 "that correspond to that address space\n"); 781 } 782 783 static void 784 report_maps_help(void) 785 { 786 mdb_printf( 787 "Given a PFN, report HAT structures that map the page, or use\n" 788 "the page as a pagetable.\n" 789 "\n" 790 "-m Interpret the PFN as an MFN (machine frame number)\n"); 791 } 792 793 static void 794 ptable_help(void) 795 { 796 mdb_printf( 797 "Given a PFN holding a page table, print its contents, and\n" 798 "the address of the corresponding htable structure.\n" 799 "\n" 800 "-m Interpret the PFN as an MFN (machine frame number)\n"); 801 } 802 803 static const mdb_dcmd_t dcmds[] = { 804 { "gate_desc", ":", "dump a gate descriptor", gate_desc }, 805 { "idt", ":[-v]", "dump an IDT", idt }, 806 { "ttrace", "[-x]", "dump trap trace buffers", ttrace }, 807 { "vatopfn", ":[-a as]", "translate address to physical page", 808 va2pfn_dcmd }, 809 { "report_maps", ":[-m]", 810 "Given PFN, report mappings / page table usage", 811 report_maps_dcmd, report_maps_help }, 812 { "htables", "", "Given hat_t *, lists all its htable_t * values", 813 htables_dcmd, htables_help }, 814 { "ptable", ":[-m]", "Given PFN, dump contents of a page table", 815 ptable_dcmd, ptable_help }, 816 { "pte", ":[-p XXXXX] [-l N]", "print human readable page table entry", 817 pte_dcmd }, 818 { "page_num2pp", ":", "page frame number to page structure", 819 page_num2pp }, 820 { "pfntomfn", ":", "convert physical page to hypervisor machine page", 821 pfntomfn_dcmd }, 822 { "mfntopfn", ":", "convert hypervisor machine page to physical page", 823 mfntopfn_dcmd }, 824 { "memseg_list", ":", "show memseg list", memseg_list }, 825 { NULL } 826 }; 827 828 static const mdb_walker_t walkers[] = { 829 { "ttrace", "walks trap trace buffers in reverse chronological order", 830 ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini }, 831 { "mutex_owner", "walks the owner of a mutex", 832 mutex_owner_init, mutex_owner_step }, 833 { "memseg", "walk the memseg structures", 834 memseg_walk_init, memseg_walk_step, memseg_walk_fini }, 835 { NULL } 836 }; 837 838 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 839 840 const mdb_modinfo_t * 841 _mdb_init(void) 842 { 843 return (&modinfo); 844 } 845 846 void 847 _mdb_fini(void) 848 { 849 free_mmu(); 850 } 851