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