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