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) 1999, 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
ttrace_ttr_size_check(void)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
ttrace_walk_init(mdb_walk_state_t * wsp)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
ttrace_walk_step(mdb_walk_state_t * wsp)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
ttrace_walk_fini(mdb_walk_state_t * wsp)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
ttrace_syscall(trap_trace_rec_t * rec)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
ttrace_interrupt(trap_trace_rec_t * rec)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
ttrace_apix_interrupt(trap_trace_rec_t * rec)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
ttrace_trap(trap_trace_rec_t * rec)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
ttrace_intr_detail(trap_trace_rec_t * rec)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
ttrace_dumpregs(trap_trace_rec_t * rec)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
ttrace_dumpregs(trap_trace_rec_t * rec)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
ttrace_walk(uintptr_t addr,trap_trace_rec_t * rec,ttrace_dcmd_t * dcmd)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
ttrace(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
mutex_owner_init(mdb_walk_state_t * wsp)584 mutex_owner_init(mdb_walk_state_t *wsp)
585 {
586 return (WALK_NEXT);
587 }
588
589 int
mutex_owner_step(mdb_walk_state_t * wsp)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
gate_desc_dump(gate_desc_t * gate,const char * label,int header)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
gate_desc(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
idt(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
htables_help(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
report_maps_help(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
ptable_help(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 *
_mdb_init(void)784 _mdb_init(void)
785 {
786 return (&modinfo);
787 }
788
789 void
_mdb_fini(void)790 _mdb_fini(void)
791 {
792 free_mmu();
793 }
794