Print this page
11585 ::scalehrtime could be more precise
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
+++ new/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2018 Joyent, Inc.
24 24 */
25 25
26 26 #include <mdb/mdb_modapi.h>
27 27 #include <mdb/mdb_ctf.h>
28 28 #include <sys/cpuvar.h>
29 29 #include <sys/systm.h>
30 30 #include <sys/traptrace.h>
31 31 #include <sys/x_call.h>
32 32 #include <sys/xc_levels.h>
33 33 #include <sys/avintr.h>
34 34 #include <sys/systm.h>
35 35 #include <sys/trap.h>
36 36 #include <sys/mutex.h>
37 37 #include <sys/mutex_impl.h>
38 38 #include "i86mmu.h"
39 39 #include "unix_sup.h"
40 40 #include <sys/apix.h>
41 41 #include <sys/x86_archext.h>
42 42 #include <sys/bitmap.h>
43 43 #include <sys/controlregs.h>
44 44
45 45 #define TT_HDLR_WIDTH 17
46 46
47 47
48 48 /* apix only */
49 49 static apix_impl_t *d_apixs[NCPU];
50 50 static int use_apix = 0;
51 51
52 52 static int
53 53 ttrace_ttr_size_check(void)
54 54 {
55 55 mdb_ctf_id_t ttrtid;
56 56 ssize_t ttr_size;
57 57
58 58 if (mdb_ctf_lookup_by_name("trap_trace_rec_t", &ttrtid) != 0 ||
59 59 mdb_ctf_type_resolve(ttrtid, &ttrtid) != 0) {
60 60 mdb_warn("failed to determine size of trap_trace_rec_t; "
61 61 "non-TRAPTRACE kernel?\n");
62 62 return (0);
63 63 }
64 64
65 65 if ((ttr_size = mdb_ctf_type_size(ttrtid)) !=
66 66 sizeof (trap_trace_rec_t)) {
67 67 /*
68 68 * On Intel machines, this will happen when TTR_STACK_DEPTH
69 69 * is changed. This code could be smarter, and could
70 70 * dynamically adapt to different depths, but not until a
71 71 * need for such adaptation is demonstrated.
72 72 */
73 73 mdb_warn("size of trap_trace_rec_t (%d bytes) doesn't "
74 74 "match expected %d\n", ttr_size, sizeof (trap_trace_rec_t));
75 75 return (0);
76 76 }
77 77
78 78 return (1);
79 79 }
80 80
81 81 int
82 82 ttrace_walk_init(mdb_walk_state_t *wsp)
83 83 {
84 84 trap_trace_ctl_t *ttcp;
85 85 size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU;
86 86 int i;
87 87
88 88 if (!ttrace_ttr_size_check())
89 89 return (WALK_ERR);
90 90
91 91 ttcp = mdb_zalloc(ttc_size, UM_SLEEP);
92 92
93 93 if (wsp->walk_addr != 0) {
94 94 mdb_warn("ttrace only supports global walks\n");
95 95 return (WALK_ERR);
96 96 }
97 97
98 98 if (mdb_readsym(ttcp, ttc_size, "trap_trace_ctl") == -1) {
99 99 mdb_warn("symbol 'trap_trace_ctl' not found; "
100 100 "non-TRAPTRACE kernel?\n");
101 101 mdb_free(ttcp, ttc_size);
102 102 return (WALK_ERR);
103 103 }
104 104
105 105 /*
106 106 * We'll poach the ttc_current pointer (which isn't used for
107 107 * anything) to store a pointer to our current TRAPTRACE record.
108 108 * This allows us to only keep the array of trap_trace_ctl structures
109 109 * as our walker state (ttc_current may be the only kernel data
110 110 * structure member added exclusively to make writing the mdb walker
111 111 * a little easier).
112 112 */
113 113 for (i = 0; i < NCPU; i++) {
114 114 trap_trace_ctl_t *ttc = &ttcp[i];
115 115
116 116 if (ttc->ttc_first == 0)
117 117 continue;
118 118
119 119 /*
120 120 * Assign ttc_current to be the last completed record.
121 121 * Note that the error checking (i.e. in the ttc_next ==
122 122 * ttc_first case) is performed in the step function.
123 123 */
124 124 ttc->ttc_current = ttc->ttc_next - sizeof (trap_trace_rec_t);
125 125 }
126 126
127 127 wsp->walk_data = ttcp;
128 128 return (WALK_NEXT);
129 129 }
130 130
131 131 int
132 132 ttrace_walk_step(mdb_walk_state_t *wsp)
133 133 {
134 134 trap_trace_ctl_t *ttcp = wsp->walk_data, *ttc, *latest_ttc;
135 135 trap_trace_rec_t rec;
136 136 int rval, i, recsize = sizeof (trap_trace_rec_t);
137 137 hrtime_t latest = 0;
138 138
139 139 /*
140 140 * Loop through the CPUs, looking for the latest trap trace record
141 141 * (we want to walk through the trap trace records in reverse
142 142 * chronological order).
143 143 */
144 144 for (i = 0; i < NCPU; i++) {
145 145 ttc = &ttcp[i];
146 146
147 147 if (ttc->ttc_current == 0)
148 148 continue;
149 149
150 150 if (ttc->ttc_current < ttc->ttc_first)
151 151 ttc->ttc_current = ttc->ttc_limit - recsize;
152 152
153 153 if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) {
154 154 mdb_warn("couldn't read rec at %p", ttc->ttc_current);
155 155 return (WALK_ERR);
156 156 }
157 157
158 158 if (rec.ttr_stamp > latest) {
159 159 latest = rec.ttr_stamp;
160 160 latest_ttc = ttc;
161 161 }
162 162 }
163 163
164 164 if (latest == 0)
165 165 return (WALK_DONE);
166 166
167 167 ttc = latest_ttc;
168 168
169 169 if (mdb_vread(&rec, sizeof (rec), ttc->ttc_current) == -1) {
170 170 mdb_warn("couldn't read rec at %p", ttc->ttc_current);
171 171 return (WALK_ERR);
172 172 }
173 173
174 174 rval = wsp->walk_callback(ttc->ttc_current, &rec, wsp->walk_cbdata);
175 175
176 176 if (ttc->ttc_current == ttc->ttc_next)
177 177 ttc->ttc_current = 0;
178 178 else
179 179 ttc->ttc_current -= sizeof (trap_trace_rec_t);
180 180
181 181 return (rval);
182 182 }
183 183
184 184 void
185 185 ttrace_walk_fini(mdb_walk_state_t *wsp)
186 186 {
187 187 mdb_free(wsp->walk_data, sizeof (trap_trace_ctl_t) * NCPU);
188 188 }
189 189
190 190 static int
191 191 ttrace_syscall(trap_trace_rec_t *rec)
192 192 {
193 193 GElf_Sym sym;
194 194 int sysnum = rec->ttr_sysnum;
195 195 uintptr_t addr;
196 196 struct sysent sys;
197 197
198 198 mdb_printf("%-3x", sysnum);
199 199
200 200 if (rec->ttr_sysnum > NSYSCALL) {
201 201 mdb_printf(" %-*d", TT_HDLR_WIDTH, rec->ttr_sysnum);
202 202 return (0);
203 203 }
204 204
205 205 if (mdb_lookup_by_name("sysent", &sym) == -1) {
206 206 mdb_warn("\ncouldn't find 'sysent'");
207 207 return (-1);
208 208 }
209 209
210 210 addr = (uintptr_t)sym.st_value + sysnum * sizeof (struct sysent);
211 211
212 212 if (addr >= (uintptr_t)sym.st_value + sym.st_size) {
213 213 mdb_warn("\nsysnum %d out-of-range\n", sysnum);
214 214 return (-1);
215 215 }
216 216
217 217 if (mdb_vread(&sys, sizeof (sys), addr) == -1) {
218 218 mdb_warn("\nfailed to read sysent at %p", addr);
219 219 return (-1);
220 220 }
221 221
222 222 mdb_printf(" %-*a", TT_HDLR_WIDTH, sys.sy_callc);
223 223
224 224 return (0);
225 225 }
226 226
227 227 static int
228 228 ttrace_interrupt(trap_trace_rec_t *rec)
229 229 {
230 230 GElf_Sym sym;
231 231 uintptr_t addr;
232 232 struct av_head hd;
233 233 struct autovec av;
234 234
235 235 switch (rec->ttr_regs.r_trapno) {
236 236 case T_SOFTINT:
237 237 mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)");
238 238 return (0);
239 239 default:
240 240 break;
241 241 }
242 242
243 243 mdb_printf("%-3x ", rec->ttr_vector);
244 244
245 245 if (mdb_lookup_by_name("autovect", &sym) == -1) {
246 246 mdb_warn("\ncouldn't find 'autovect'");
247 247 return (-1);
248 248 }
249 249
250 250 addr = (uintptr_t)sym.st_value +
251 251 rec->ttr_vector * sizeof (struct av_head);
252 252
253 253 if (addr >= (uintptr_t)sym.st_value + sym.st_size) {
254 254 mdb_warn("\nav_head for vec %x is corrupt\n", rec->ttr_vector);
255 255 return (-1);
256 256 }
257 257
258 258 if (mdb_vread(&hd, sizeof (hd), addr) == -1) {
259 259 mdb_warn("\ncouldn't read av_head for vec %x", rec->ttr_vector);
260 260 return (-1);
261 261 }
262 262
263 263 if (hd.avh_link == NULL) {
264 264 if (rec->ttr_ipl == XC_CPUPOKE_PIL)
265 265 mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)");
266 266 else
267 267 mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)");
268 268 } else {
269 269 if (mdb_vread(&av, sizeof (av), (uintptr_t)hd.avh_link) == -1) {
270 270 mdb_warn("couldn't read autovec at %p",
271 271 (uintptr_t)hd.avh_link);
272 272 }
273 273
274 274 mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector);
275 275 }
276 276
277 277 return (0);
278 278 }
279 279
280 280 static int
281 281 ttrace_apix_interrupt(trap_trace_rec_t *rec)
282 282 {
283 283 struct autovec av;
284 284 apix_impl_t apix;
285 285 apix_vector_t apix_vector;
286 286
287 287 switch (rec->ttr_regs.r_trapno) {
288 288 case T_SOFTINT:
289 289 mdb_printf("%-3s %-*s", "-", TT_HDLR_WIDTH, "(fakesoftint)");
290 290 return (0);
291 291 default:
292 292 break;
293 293 }
294 294
295 295 mdb_printf("%-3x ", rec->ttr_vector);
296 296
297 297 /* Read the per CPU apix entry */
298 298 if (mdb_vread(&apix, sizeof (apix_impl_t),
299 299 (uintptr_t)d_apixs[rec->ttr_cpuid]) == -1) {
300 300 mdb_warn("\ncouldn't read apix[%d]", rec->ttr_cpuid);
301 301 return (-1);
302 302 }
303 303 if (mdb_vread(&apix_vector, sizeof (apix_vector_t),
304 304 (uintptr_t)apix.x_vectbl[rec->ttr_vector]) == -1) {
305 305 mdb_warn("\ncouldn't read apix_vector_t[%d]", rec->ttr_vector);
306 306 return (-1);
307 307 }
308 308 if (apix_vector.v_share == 0) {
309 309 if (rec->ttr_ipl == XC_CPUPOKE_PIL)
310 310 mdb_printf("%-*s", TT_HDLR_WIDTH, "(cpupoke)");
311 311 else
312 312 mdb_printf("%-*s", TT_HDLR_WIDTH, "(spurious)");
313 313 } else {
314 314 if (mdb_vread(&av, sizeof (struct autovec),
315 315 (uintptr_t)(apix_vector.v_autovect)) == -1) {
316 316 mdb_warn("couldn't read autovec at %p",
317 317 (uintptr_t)apix_vector.v_autovect);
318 318 }
319 319
320 320 mdb_printf("%-*a", TT_HDLR_WIDTH, av.av_vector);
321 321 }
322 322
323 323 return (0);
324 324 }
325 325
326 326
327 327 static struct {
328 328 int tt_trapno;
329 329 char *tt_name;
330 330 } ttrace_traps[] = {
331 331 { T_ZERODIV, "divide-error" },
332 332 { T_SGLSTP, "debug-exception" },
333 333 { T_NMIFLT, "nmi-interrupt" },
334 334 { T_BPTFLT, "breakpoint" },
335 335 { T_OVFLW, "into-overflow" },
336 336 { T_BOUNDFLT, "bound-exceeded" },
337 337 { T_ILLINST, "invalid-opcode" },
338 338 { T_NOEXTFLT, "device-not-avail" },
339 339 { T_DBLFLT, "double-fault" },
340 340 { T_EXTOVRFLT, "segment-overrun" },
341 341 { T_TSSFLT, "invalid-tss" },
342 342 { T_SEGFLT, "segment-not-pres" },
343 343 { T_STKFLT, "stack-fault" },
344 344 { T_GPFLT, "general-protectn" },
345 345 { T_PGFLT, "page-fault" },
346 346 { T_EXTERRFLT, "error-fault" },
347 347 { T_ALIGNMENT, "alignment-check" },
348 348 { T_MCE, "machine-check" },
349 349 { T_SIMDFPE, "sse-exception" },
350 350
351 351 { T_DBGENTR, "debug-enter" },
352 352 { T_FASTTRAP, "fasttrap-0xd2" },
353 353 { T_SYSCALLINT, "syscall-0x91" },
354 354 { T_DTRACE_RET, "dtrace-ret" },
355 355 { T_SOFTINT, "softint" },
356 356 { T_INTERRUPT, "interrupt" },
357 357 { T_FAULT, "fault" },
358 358 { T_AST, "ast" },
359 359 { T_SYSCALL, "syscall" },
360 360
361 361 { 0, NULL }
362 362 };
363 363
364 364 static int
365 365 ttrace_trap(trap_trace_rec_t *rec)
366 366 {
367 367 int i;
368 368
369 369 if (rec->ttr_regs.r_trapno == T_AST)
370 370 mdb_printf("%-3s ", "-");
371 371 else
372 372 mdb_printf("%-3x ", rec->ttr_regs.r_trapno);
373 373
374 374 for (i = 0; ttrace_traps[i].tt_name != NULL; i++) {
375 375 if (rec->ttr_regs.r_trapno == ttrace_traps[i].tt_trapno)
376 376 break;
377 377 }
378 378
379 379 if (ttrace_traps[i].tt_name == NULL)
380 380 mdb_printf("%-*s", TT_HDLR_WIDTH, "(unknown)");
381 381 else
382 382 mdb_printf("%-*s", TT_HDLR_WIDTH, ttrace_traps[i].tt_name);
383 383
384 384 return (0);
385 385 }
386 386
387 387 static void
388 388 ttrace_intr_detail(trap_trace_rec_t *rec)
389 389 {
390 390 mdb_printf("\tirq %x ipl %d oldpri %d basepri %d\n", rec->ttr_vector,
391 391 rec->ttr_ipl, rec->ttr_pri, rec->ttr_spl);
392 392 }
393 393
394 394 static struct {
395 395 uchar_t t_marker;
396 396 char *t_name;
397 397 int (*t_hdlr)(trap_trace_rec_t *);
398 398 } ttrace_hdlr[] = {
399 399 { TT_SYSCALL, "sysc", ttrace_syscall },
400 400 { TT_SYSENTER, "syse", ttrace_syscall },
401 401 { TT_SYSC, "asys", ttrace_syscall },
402 402 { TT_SYSC64, "sc64", ttrace_syscall },
403 403 { TT_INTERRUPT, "intr", ttrace_interrupt },
404 404 { TT_TRAP, "trap", ttrace_trap },
405 405 { TT_EVENT, "evnt", ttrace_trap },
406 406 { 0, NULL, NULL }
407 407 };
408 408
409 409 typedef struct ttrace_dcmd {
410 410 processorid_t ttd_cpu;
411 411 uint_t ttd_extended;
412 412 uintptr_t ttd_kthread;
413 413 trap_trace_ctl_t ttd_ttc[NCPU];
414 414 } ttrace_dcmd_t;
415 415
416 416 #if defined(__amd64)
417 417
418 418 #define DUMP(reg) #reg, regs->r_##reg
419 419 #define THREEREGS " %3s: %16lx %3s: %16lx %3s: %16lx\n"
420 420
421 421 static void
422 422 ttrace_dumpregs(trap_trace_rec_t *rec)
423 423 {
424 424 struct regs *regs = &rec->ttr_regs;
425 425
426 426 mdb_printf(THREEREGS, DUMP(rdi), DUMP(rsi), DUMP(rdx));
427 427 mdb_printf(THREEREGS, DUMP(rcx), DUMP(r8), DUMP(r9));
428 428 mdb_printf(THREEREGS, DUMP(rax), DUMP(rbx), DUMP(rbp));
429 429 mdb_printf(THREEREGS, DUMP(r10), DUMP(r11), DUMP(r12));
430 430 mdb_printf(THREEREGS, DUMP(r13), DUMP(r14), DUMP(r15));
431 431 mdb_printf(THREEREGS, DUMP(ds), DUMP(es), DUMP(fs));
432 432 mdb_printf(THREEREGS, DUMP(gs), "trp", regs->r_trapno, DUMP(err));
433 433 mdb_printf(THREEREGS, DUMP(rip), DUMP(cs), DUMP(rfl));
434 434 mdb_printf(THREEREGS, DUMP(rsp), DUMP(ss), "cr2", rec->ttr_cr2);
435 435 mdb_printf(" %3s: %16lx %3s: %16lx\n",
436 436 "fsb", regs->__r_fsbase,
437 437 "gsb", regs->__r_gsbase);
438 438 mdb_printf("\n");
439 439 }
440 440
441 441 #else
442 442
443 443 #define DUMP(reg) #reg, regs->r_##reg
444 444 #define FOURREGS " %3s: %08x %3s: %08x %3s: %08x %3s: %08x\n"
445 445
446 446 static void
447 447 ttrace_dumpregs(trap_trace_rec_t *rec)
448 448 {
449 449 struct regs *regs = &rec->ttr_regs;
450 450
451 451 mdb_printf(FOURREGS, DUMP(gs), DUMP(fs), DUMP(es), DUMP(ds));
452 452 mdb_printf(FOURREGS, DUMP(edi), DUMP(esi), DUMP(ebp), DUMP(esp));
453 453 mdb_printf(FOURREGS, DUMP(ebx), DUMP(edx), DUMP(ecx), DUMP(eax));
454 454 mdb_printf(FOURREGS, "trp", regs->r_trapno, DUMP(err),
455 455 DUMP(pc), DUMP(cs));
456 456 mdb_printf(FOURREGS, DUMP(efl), "usp", regs->r_uesp, DUMP(ss),
457 457 "cr2", rec->ttr_cr2);
458 458 mdb_printf("\n");
459 459 }
460 460
461 461 #endif /* __amd64 */
462 462
463 463 int
464 464 ttrace_walk(uintptr_t addr, trap_trace_rec_t *rec, ttrace_dcmd_t *dcmd)
465 465 {
466 466 struct regs *regs = &rec->ttr_regs;
467 467 processorid_t cpu = -1, i;
468 468
469 469 for (i = 0; i < NCPU; i++) {
470 470 if (addr >= dcmd->ttd_ttc[i].ttc_first &&
471 471 addr < dcmd->ttd_ttc[i].ttc_limit) {
472 472 cpu = i;
473 473 break;
474 474 }
475 475 }
476 476
477 477 if (cpu == -1) {
478 478 mdb_warn("couldn't find %p in any trap trace ctl\n", addr);
479 479 return (WALK_ERR);
480 480 }
481 481
482 482 if (dcmd->ttd_cpu != -1 && cpu != dcmd->ttd_cpu)
483 483 return (WALK_NEXT);
484 484
485 485 if (dcmd->ttd_kthread != 0 &&
486 486 dcmd->ttd_kthread != rec->ttr_curthread)
487 487 return (WALK_NEXT);
488 488
489 489 mdb_printf("%3d %15llx ", cpu, rec->ttr_stamp);
490 490
491 491 for (i = 0; ttrace_hdlr[i].t_hdlr != NULL; i++) {
492 492 if (rec->ttr_marker != ttrace_hdlr[i].t_marker)
493 493 continue;
494 494 mdb_printf("%4s ", ttrace_hdlr[i].t_name);
495 495 if (ttrace_hdlr[i].t_hdlr(rec) == -1)
496 496 return (WALK_ERR);
497 497 }
498 498
499 499 mdb_printf(" %a\n", regs->r_pc);
500 500
501 501 if (dcmd->ttd_extended == FALSE)
502 502 return (WALK_NEXT);
503 503
504 504 if (rec->ttr_marker == TT_INTERRUPT)
505 505 ttrace_intr_detail(rec);
506 506 else
507 507 ttrace_dumpregs(rec);
508 508
509 509 if (rec->ttr_sdepth > 0) {
510 510 for (i = 0; i < rec->ttr_sdepth; i++) {
511 511 if (i >= TTR_STACK_DEPTH) {
512 512 mdb_printf("%17s*** invalid ttr_sdepth (is %d, "
513 513 "should be <= %d)\n", " ", rec->ttr_sdepth,
514 514 TTR_STACK_DEPTH);
515 515 break;
516 516 }
517 517
518 518 mdb_printf("%17s %a()\n", " ", rec->ttr_stack[i]);
519 519 }
520 520 mdb_printf("\n");
521 521 }
522 522
523 523 return (WALK_NEXT);
524 524 }
525 525
526 526 int
527 527 ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
528 528 {
529 529 ttrace_dcmd_t dcmd;
530 530 trap_trace_ctl_t *ttc = dcmd.ttd_ttc;
531 531 trap_trace_rec_t rec;
532 532 size_t ttc_size = sizeof (trap_trace_ctl_t) * NCPU;
533 533
534 534 if (!ttrace_ttr_size_check())
535 535 return (WALK_ERR);
536 536
537 537 bzero(&dcmd, sizeof (dcmd));
538 538 dcmd.ttd_cpu = -1;
539 539 dcmd.ttd_extended = FALSE;
540 540
541 541 if (mdb_readsym(ttc, ttc_size, "trap_trace_ctl") == -1) {
542 542 mdb_warn("symbol 'trap_trace_ctl' not found; "
543 543 "non-TRAPTRACE kernel?\n");
544 544 return (DCMD_ERR);
545 545 }
546 546
547 547 if (mdb_getopts(argc, argv,
548 548 'x', MDB_OPT_SETBITS, TRUE, &dcmd.ttd_extended,
549 549 't', MDB_OPT_UINTPTR, &dcmd.ttd_kthread, NULL) != argc)
550 550 return (DCMD_USAGE);
551 551
552 552 if (DCMD_HDRSPEC(flags)) {
553 553 mdb_printf("%3s %15s %4s %2s %-*s%s\n", "CPU",
554 554 "TIMESTAMP", "TYPE", "Vec", TT_HDLR_WIDTH, "HANDLER",
555 555 " EIP");
556 556 }
557 557
558 558 if (flags & DCMD_ADDRSPEC) {
559 559 if (addr >= NCPU) {
560 560 if (mdb_vread(&rec, sizeof (rec), addr) == -1) {
561 561 mdb_warn("couldn't read trap trace record "
562 562 "at %p", addr);
563 563 return (DCMD_ERR);
564 564 }
565 565
566 566 if (ttrace_walk(addr, &rec, &dcmd) == WALK_ERR)
567 567 return (DCMD_ERR);
568 568
569 569 return (DCMD_OK);
570 570 }
571 571 dcmd.ttd_cpu = addr;
572 572 }
573 573
574 574 if (mdb_readvar(&use_apix, "apix_enable") == -1) {
575 575 mdb_warn("failed to read apix_enable");
576 576 use_apix = 0;
577 577 }
578 578
579 579 if (use_apix) {
580 580 if (mdb_readvar(&d_apixs, "apixs") == -1) {
581 581 mdb_warn("\nfailed to read apixs.");
582 582 return (DCMD_ERR);
583 583 }
584 584 /* change to apix ttrace interrupt handler */
585 585 ttrace_hdlr[4].t_hdlr = ttrace_apix_interrupt;
586 586 }
587 587
588 588 if (mdb_walk("ttrace", (mdb_walk_cb_t)ttrace_walk, &dcmd) == -1) {
589 589 mdb_warn("couldn't walk 'ttrace'");
590 590 return (DCMD_ERR);
591 591 }
592 592
593 593 return (DCMD_OK);
594 594 }
595 595
596 596 /*ARGSUSED*/
597 597 int
598 598 mutex_owner_init(mdb_walk_state_t *wsp)
599 599 {
600 600 return (WALK_NEXT);
601 601 }
602 602
603 603 int
604 604 mutex_owner_step(mdb_walk_state_t *wsp)
605 605 {
606 606 uintptr_t addr = wsp->walk_addr;
607 607 mutex_impl_t mtx;
608 608 uintptr_t owner;
609 609 kthread_t thr;
610 610
611 611 if (mdb_vread(&mtx, sizeof (mtx), addr) == -1)
612 612 return (WALK_ERR);
613 613
614 614 if (!MUTEX_TYPE_ADAPTIVE(&mtx))
615 615 return (WALK_DONE);
616 616
617 617 if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == 0)
618 618 return (WALK_DONE);
619 619
620 620 if (mdb_vread(&thr, sizeof (thr), owner) != -1)
621 621 (void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata);
622 622
623 623 return (WALK_DONE);
624 624 }
625 625
626 626 static void
627 627 gate_desc_dump(gate_desc_t *gate, const char *label, int header)
628 628 {
629 629 const char *lastnm;
630 630 uint_t lastval;
631 631 char type[4];
632 632
633 633 switch (gate->sgd_type) {
634 634 case SDT_SYSIGT:
635 635 strcpy(type, "int");
636 636 break;
637 637 case SDT_SYSTGT:
638 638 strcpy(type, "trp");
639 639 break;
640 640 case SDT_SYSTASKGT:
641 641 strcpy(type, "tsk");
642 642 break;
643 643 default:
644 644 (void) mdb_snprintf(type, sizeof (type), "%3x", gate->sgd_type);
645 645 }
646 646
647 647 #if defined(__amd64)
648 648 lastnm = "IST";
649 649 lastval = gate->sgd_ist;
650 650 #else
651 651 lastnm = "STK";
652 652 lastval = gate->sgd_stkcpy;
653 653 #endif
654 654
655 655 if (header) {
656 656 mdb_printf("%*s%<u>%-30s%</u> %<u>%-4s%</u> %<u>%3s%</u> "
657 657 "%<u>%1s%</u> %<u>%3s%</u> %<u>%3s%</u>\n", strlen(label),
658 658 "", "HANDLER", "SEL", "DPL", "P", "TYP", lastnm);
659 659 }
660 660
661 661 mdb_printf("%s", label);
662 662
663 663 if (gate->sgd_type == SDT_SYSTASKGT)
664 664 mdb_printf("%-30s ", "-");
665 665 else
666 666 mdb_printf("%-30a ", GATESEG_GETOFFSET(gate));
667 667
668 668 mdb_printf("%4x %d %c %3s %2x\n", gate->sgd_selector,
669 669 gate->sgd_dpl, (gate->sgd_p ? '+' : ' '), type, lastval);
670 670 }
671 671
672 672 /*ARGSUSED*/
673 673 static int
674 674 gate_desc(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
675 675 {
676 676 gate_desc_t gate;
677 677
678 678 if (argc != 0 || !(flags & DCMD_ADDRSPEC))
679 679 return (DCMD_USAGE);
680 680
681 681 if (mdb_vread(&gate, sizeof (gate_desc_t), addr) !=
682 682 sizeof (gate_desc_t)) {
683 683 mdb_warn("failed to read gate descriptor at %p\n", addr);
684 684 return (DCMD_ERR);
685 685 }
686 686
687 687 gate_desc_dump(&gate, "", DCMD_HDRSPEC(flags));
688 688
689 689 return (DCMD_OK);
690 690 }
691 691
692 692 /*ARGSUSED*/
693 693 static int
694 694 idt(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
695 695 {
696 696 int i;
697 697
698 698 if (!(flags & DCMD_ADDRSPEC)) {
699 699 GElf_Sym idt0_va;
700 700 gate_desc_t *idt0;
701 701
702 702 if (mdb_lookup_by_name("idt0", &idt0_va) < 0) {
703 703 mdb_warn("failed to find VA of idt0");
704 704 return (DCMD_ERR);
705 705 }
706 706
707 707 addr = idt0_va.st_value;
708 708 if (mdb_vread(&idt0, sizeof (idt0), addr) != sizeof (idt0)) {
709 709 mdb_warn("failed to read idt0 at %p\n", addr);
710 710 return (DCMD_ERR);
711 711 }
712 712
713 713 addr = (uintptr_t)idt0;
714 714 }
715 715
716 716 for (i = 0; i < NIDT; i++, addr += sizeof (gate_desc_t)) {
717 717 gate_desc_t gate;
718 718 char label[6];
719 719
720 720 if (mdb_vread(&gate, sizeof (gate_desc_t), addr) !=
721 721 sizeof (gate_desc_t)) {
722 722 mdb_warn("failed to read gate descriptor at %p\n",
723 723 addr);
724 724 return (DCMD_ERR);
725 725 }
726 726
727 727 (void) mdb_snprintf(label, sizeof (label), "%3d: ", i);
728 728 gate_desc_dump(&gate, label, i == 0);
729 729 }
730 730
731 731 return (DCMD_OK);
732 732 }
733 733
734 734 static void
735 735 htables_help(void)
736 736 {
737 737 mdb_printf(
738 738 "Given a (hat_t *), generates the list of all (htable_t *)s\n"
739 739 "that correspond to that address space\n");
740 740 }
741 741
742 742 static void
743 743 report_maps_help(void)
744 744 {
745 745 mdb_printf(
746 746 "Given a PFN, report HAT structures that map the page, or use\n"
747 747 "the page as a pagetable.\n"
748 748 "\n"
749 749 "-m Interpret the PFN as an MFN (machine frame number)\n");
750 750 }
751 751
752 752 static void
753 753 ptable_help(void)
754 754 {
755 755 mdb_printf(
756 756 "Given a PFN holding a page table, print its contents, and\n"
757 757 "the address of the corresponding htable structure.\n"
758 758 "\n"
759 759 "-m Interpret the PFN as an MFN (machine frame number)\n"
760 760 "-l force page table level (3 is top)\n");
761 761 }
762 762
↓ open down ↓ |
762 lines elided |
↑ open up ↑ |
763 763 static void
764 764 ptmap_help(void)
765 765 {
766 766 mdb_printf(
767 767 "Report all mappings represented by the page table hierarchy\n"
768 768 "rooted at the given cr3 value / physical address.\n"
769 769 "\n"
770 770 "-w run ::whatis on mapping start addresses\n");
771 771 }
772 772
773 +static const char *const scalehrtime_desc =
774 + "Scales a timestamp from ticks to nanoseconds. Unscaled timestamps\n"
775 + "are used as both a quick way of accumulating relative time (as for\n"
776 + "usage) and as a quick way of getting the absolute current time.\n"
777 + "These uses require slightly different scaling algorithms. By\n"
778 + "default, if a specified time is greater than half of the unscaled\n"
779 + "time at the last tick (that is, if the unscaled time represents\n"
780 + "more than half the time since boot), the timestamp is assumed to\n"
781 + "be absolute, and the scaling algorithm used mimics that which the\n"
782 + "kernel uses in gethrtime(). Otherwise, the timestamp is assumed to\n"
783 + "be relative, and the algorithm mimics scalehrtime(). This behavior\n"
784 + "can be overridden by forcing the unscaled time to be interpreted\n"
785 + "as relative (via -r) or absolute (via -a).\n";
786 +
787 +static void
788 +scalehrtime_help(void)
789 +{
790 + mdb_printf("%s", scalehrtime_desc);
791 +}
792 +
773 793 /*
774 794 * NSEC_SHIFT is replicated here (it is not defined in a header file),
775 795 * but for amusement, the reader is directed to the comment that explains
776 796 * the rationale for this particular value on x86. Spoiler: the value is
777 797 * selected to accommodate 60 MHz Pentiums! (And a confession: if the voice
778 798 * in that comment sounds too familiar, it's because your author also wrote
779 799 * that code -- some fifteen years prior to this writing in 2011...)
780 800 */
781 801 #define NSEC_SHIFT 5
782 802
783 803 /*ARGSUSED*/
784 804 static int
785 805 scalehrtime_cmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
786 806 {
787 807 uint32_t nsec_scale;
788 - hrtime_t tsc = addr, hrt;
808 + hrtime_t tsc = addr, hrt, tsc_last, base, mult = 1;
789 809 unsigned int *tscp = (unsigned int *)&tsc;
790 810 uintptr_t scalehrtimef;
791 811 uint64_t scale;
792 812 GElf_Sym sym;
813 + int expected = !(flags & DCMD_ADDRSPEC);
814 + uint_t absolute = FALSE, relative = FALSE;
793 815
794 - if (!(flags & DCMD_ADDRSPEC)) {
795 - if (argc != 1)
796 - return (DCMD_USAGE);
816 + if (mdb_getopts(argc, argv,
817 + 'a', MDB_OPT_SETBITS, TRUE, &absolute,
818 + 'r', MDB_OPT_SETBITS, TRUE, &relative, NULL) != argc - expected)
819 + return (DCMD_USAGE);
797 820
798 - switch (argv[0].a_type) {
821 + if (absolute && relative) {
822 + mdb_warn("can't specify both -a and -r\n");
823 + return (DCMD_USAGE);
824 + }
825 +
826 + if (expected == 1) {
827 + switch (argv[argc - 1].a_type) {
799 828 case MDB_TYPE_STRING:
800 - tsc = mdb_strtoull(argv[0].a_un.a_str);
829 + tsc = mdb_strtoull(argv[argc - 1].a_un.a_str);
801 830 break;
802 831 case MDB_TYPE_IMMEDIATE:
803 - tsc = argv[0].a_un.a_val;
832 + tsc = argv[argc - 1].a_un.a_val;
804 833 break;
805 834 default:
806 835 return (DCMD_USAGE);
807 836 }
808 837 }
809 838
810 839 if (mdb_readsym(&scalehrtimef,
811 840 sizeof (scalehrtimef), "scalehrtimef") == -1) {
812 841 mdb_warn("couldn't read 'scalehrtimef'");
813 842 return (DCMD_ERR);
814 843 }
815 844
816 845 if (mdb_lookup_by_name("tsc_scalehrtime", &sym) == -1) {
817 846 mdb_warn("couldn't find 'tsc_scalehrtime'");
818 847 return (DCMD_ERR);
819 848 }
820 849
821 850 if (sym.st_value != scalehrtimef) {
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
822 851 mdb_warn("::scalehrtime requires that scalehrtimef "
823 852 "be set to tsc_scalehrtime\n");
824 853 return (DCMD_ERR);
825 854 }
826 855
827 856 if (mdb_readsym(&nsec_scale, sizeof (nsec_scale), "nsec_scale") == -1) {
828 857 mdb_warn("couldn't read 'nsec_scale'");
829 858 return (DCMD_ERR);
830 859 }
831 860
861 + if (mdb_readsym(&tsc_last, sizeof (tsc_last), "tsc_last") == -1) {
862 + mdb_warn("couldn't read 'tsc_last'");
863 + return (DCMD_ERR);
864 + }
865 +
866 + if (mdb_readsym(&base, sizeof (base), "tsc_hrtime_base") == -1) {
867 + mdb_warn("couldn't read 'tsc_hrtime_base'");
868 + return (DCMD_ERR);
869 + }
870 +
871 + /*
872 + * If our time is greater than half of tsc_last, we will take our
873 + * delta against tsc_last, convert it, and add that to (or subtract it
874 + * from) tsc_hrtime_base. This mimics what the kernel actually does
875 + * in gethrtime() (modulo the tsc_sync_tick_delta) and gets us a much
876 + * higher precision result than trying to convert a large tsc value.
877 + */
878 + if (absolute || (tsc > (tsc_last >> 1) && !relative)) {
879 + if (tsc > tsc_last) {
880 + tsc = tsc - tsc_last;
881 + } else {
882 + tsc = tsc_last - tsc;
883 + mult = -1;
884 + }
885 + } else {
886 + base = 0;
887 + }
888 +
832 889 scale = (uint64_t)nsec_scale;
833 890
834 891 hrt = ((uint64_t)tscp[1] * scale) << NSEC_SHIFT;
835 892 hrt += ((uint64_t)tscp[0] * scale) >> (32 - NSEC_SHIFT);
836 893
837 - mdb_printf("0x%llx\n", hrt);
894 + mdb_printf("0x%llx\n", base + (hrt * mult));
838 895
839 896 return (DCMD_OK);
840 897 }
841 898
842 899 /*
843 900 * The x86 feature set is implemented as a bitmap array. That bitmap array is
844 901 * stored across a number of uchars based on the BT_SIZEOFMAP(NUM_X86_FEATURES)
845 902 * macro. We have the names for each of these features in unix's text segment
846 903 * so we do not have to duplicate them and instead just look them up.
847 904 */
848 905 /*ARGSUSED*/
849 906 static int
850 907 x86_featureset_cmd(uintptr_t addr, uint_t flags, int argc,
851 908 const mdb_arg_t *argv)
852 909 {
853 910 void *fset;
854 911 GElf_Sym sym;
855 912 uintptr_t nptr;
856 913 char name[128];
857 914 int ii;
858 915
859 916 size_t sz = sizeof (uchar_t) * BT_SIZEOFMAP(NUM_X86_FEATURES);
860 917
861 918 if (argc != 0)
862 919 return (DCMD_USAGE);
863 920
864 921 if (mdb_lookup_by_name("x86_feature_names", &sym) == -1) {
865 922 mdb_warn("couldn't find x86_feature_names");
866 923 return (DCMD_ERR);
867 924 }
868 925
869 926 fset = mdb_zalloc(sz, UM_NOSLEEP);
870 927 if (fset == NULL) {
871 928 mdb_warn("failed to allocate memory for x86_featureset");
872 929 return (DCMD_ERR);
873 930 }
874 931
875 932 if (mdb_readvar(fset, "x86_featureset") != sz) {
876 933 mdb_warn("failed to read x86_featureset");
877 934 mdb_free(fset, sz);
878 935 return (DCMD_ERR);
879 936 }
880 937
881 938 for (ii = 0; ii < NUM_X86_FEATURES; ii++) {
882 939 if (!BT_TEST((ulong_t *)fset, ii))
883 940 continue;
884 941
885 942 if (mdb_vread(&nptr, sizeof (char *), sym.st_value +
886 943 sizeof (void *) * ii) != sizeof (char *)) {
887 944 mdb_warn("failed to read feature array %d", ii);
888 945 mdb_free(fset, sz);
889 946 return (DCMD_ERR);
890 947 }
891 948
892 949 if (mdb_readstr(name, sizeof (name), nptr) == -1) {
893 950 mdb_warn("failed to read feature %d", ii);
894 951 mdb_free(fset, sz);
895 952 return (DCMD_ERR);
896 953 }
897 954 mdb_printf("%s\n", name);
898 955 }
899 956
900 957 mdb_free(fset, sz);
901 958 return (DCMD_OK);
902 959 }
903 960
904 961 #ifdef _KMDB
905 962 /* ARGSUSED */
906 963 static int
907 964 sysregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
908 965 {
909 966 ulong_t cr0, cr2, cr3, cr4;
910 967 desctbr_t gdtr;
911 968
912 969 static const mdb_bitmask_t cr0_flag_bits[] = {
913 970 { "PE", CR0_PE, CR0_PE },
914 971 { "MP", CR0_MP, CR0_MP },
915 972 { "EM", CR0_EM, CR0_EM },
916 973 { "TS", CR0_TS, CR0_TS },
917 974 { "ET", CR0_ET, CR0_ET },
918 975 { "NE", CR0_NE, CR0_NE },
919 976 { "WP", CR0_WP, CR0_WP },
920 977 { "AM", CR0_AM, CR0_AM },
921 978 { "NW", CR0_NW, CR0_NW },
922 979 { "CD", CR0_CD, CR0_CD },
923 980 { "PG", CR0_PG, CR0_PG },
924 981 { NULL, 0, 0 }
925 982 };
926 983
927 984 static const mdb_bitmask_t cr3_flag_bits[] = {
928 985 { "PCD", CR3_PCD, CR3_PCD },
929 986 { "PWT", CR3_PWT, CR3_PWT },
930 987 { NULL, 0, 0, }
931 988 };
932 989
933 990 static const mdb_bitmask_t cr4_flag_bits[] = {
934 991 { "VME", CR4_VME, CR4_VME },
935 992 { "PVI", CR4_PVI, CR4_PVI },
936 993 { "TSD", CR4_TSD, CR4_TSD },
937 994 { "DE", CR4_DE, CR4_DE },
938 995 { "PSE", CR4_PSE, CR4_PSE },
939 996 { "PAE", CR4_PAE, CR4_PAE },
940 997 { "MCE", CR4_MCE, CR4_MCE },
941 998 { "PGE", CR4_PGE, CR4_PGE },
942 999 { "PCE", CR4_PCE, CR4_PCE },
943 1000 { "OSFXSR", CR4_OSFXSR, CR4_OSFXSR },
944 1001 { "OSXMMEXCPT", CR4_OSXMMEXCPT, CR4_OSXMMEXCPT },
945 1002 { "VMXE", CR4_VMXE, CR4_VMXE },
946 1003 { "SMXE", CR4_SMXE, CR4_SMXE },
947 1004 { "PCIDE", CR4_PCIDE, CR4_PCIDE },
948 1005 { "OSXSAVE", CR4_OSXSAVE, CR4_OSXSAVE },
949 1006 { "SMEP", CR4_SMEP, CR4_SMEP },
950 1007 { "SMAP", CR4_SMAP, CR4_SMAP },
951 1008 { NULL, 0, 0 }
952 1009 };
953 1010
954 1011 cr0 = kmdb_unix_getcr0();
955 1012 cr2 = kmdb_unix_getcr2();
956 1013 cr3 = kmdb_unix_getcr3();
957 1014 cr4 = kmdb_unix_getcr4();
958 1015
959 1016 kmdb_unix_getgdtr(&gdtr);
960 1017
961 1018 mdb_printf("%%cr0 = 0x%lx <%b>\n", cr0, cr0, cr0_flag_bits);
962 1019 mdb_printf("%%cr2 = 0x%lx <%a>\n", cr2, cr2);
963 1020
964 1021 if ((cr4 & CR4_PCIDE)) {
965 1022 mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx pcid:%lu>\n", cr3,
966 1023 cr3 >> MMU_PAGESHIFT, cr3 & MMU_PAGEOFFSET);
967 1024 } else {
968 1025 mdb_printf("%%cr3 = 0x%lx <pfn:0x%lx flags:%b>\n", cr3,
969 1026 cr3 >> MMU_PAGESHIFT, cr3, cr3_flag_bits);
970 1027 }
971 1028
972 1029 mdb_printf("%%cr4 = 0x%lx <%b>\n", cr4, cr4, cr4_flag_bits);
973 1030
974 1031 mdb_printf("%%gdtr.base = 0x%lx, %%gdtr.limit = 0x%hx\n",
975 1032 gdtr.dtr_base, gdtr.dtr_limit);
976 1033
977 1034 return (DCMD_OK);
978 1035 }
979 1036 #endif
980 1037
981 1038 static const mdb_dcmd_t dcmds[] = {
982 1039 { "gate_desc", ":", "dump a gate descriptor", gate_desc },
983 1040 { "idt", ":[-v]", "dump an IDT", idt },
984 1041 { "ttrace", "[-x] [-t kthread]", "dump trap trace buffers", ttrace },
985 1042 { "vatopfn", ":[-a as]", "translate address to physical page",
986 1043 va2pfn_dcmd },
987 1044 { "report_maps", ":[-m]",
988 1045 "Given PFN, report mappings / page table usage",
989 1046 report_maps_dcmd, report_maps_help },
990 1047 { "htables", "", "Given hat_t *, lists all its htable_t * values",
991 1048 htables_dcmd, htables_help },
992 1049 { "ptable", ":[-lm]", "Given PFN, dump contents of a page table",
↓ open down ↓ |
145 lines elided |
↑ open up ↑ |
993 1050 ptable_dcmd, ptable_help },
994 1051 { "ptmap", ":", "Given a cr3 value, dump all mappings",
995 1052 ptmap_dcmd, ptmap_help },
996 1053 { "pte", ":[-l N]", "print human readable page table entry",
997 1054 pte_dcmd },
998 1055 { "pfntomfn", ":", "convert physical page to hypervisor machine page",
999 1056 pfntomfn_dcmd },
1000 1057 { "mfntopfn", ":", "convert hypervisor machine page to physical page",
1001 1058 mfntopfn_dcmd },
1002 1059 { "memseg_list", ":", "show memseg list", memseg_list },
1003 - { "scalehrtime", ":",
1004 - "scale an unscaled high-res time", scalehrtime_cmd },
1060 + { "scalehrtime", ":[-a|-r]", "scale an unscaled high-res time",
1061 + scalehrtime_cmd, scalehrtime_help },
1005 1062 { "x86_featureset", NULL, "dump the x86_featureset vector",
1006 1063 x86_featureset_cmd },
1007 1064 #ifdef _KMDB
1008 1065 { "sysregs", NULL, "dump system registers", sysregs_dcmd },
1009 1066 #endif
1010 1067 { NULL }
1011 1068 };
1012 1069
1013 1070 static const mdb_walker_t walkers[] = {
1014 1071 { "ttrace", "walks trap trace buffers in reverse chronological order",
1015 1072 ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini },
1016 1073 { "mutex_owner", "walks the owner of a mutex",
1017 1074 mutex_owner_init, mutex_owner_step },
1018 1075 { "memseg", "walk the memseg structures",
1019 1076 memseg_walk_init, memseg_walk_step, memseg_walk_fini },
1020 1077 { NULL }
1021 1078 };
1022 1079
1023 1080 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1024 1081
1025 1082 const mdb_modinfo_t *
1026 1083 _mdb_init(void)
1027 1084 {
1028 1085 return (&modinfo);
1029 1086 }
1030 1087
1031 1088 void
1032 1089 _mdb_fini(void)
1033 1090 {
1034 1091 free_mmu();
1035 1092 }
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX