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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 28 #ifndef DEBUG 29 #define DEBUG 30 #define _SYS_DEBUG_H 31 #include <sys/xc_impl.h> 32 #undef DEBUG 33 #else 34 #define _SYS_DEBUG_H 35 #include <sys/xc_impl.h> 36 #endif 37 38 #include <sys/traptrace.h> 39 #include <sys/machparam.h> 40 #include <sys/intreg.h> 41 #include <sys/ivintr.h> 42 #include <sys/mutex_impl.h> 43 44 #include <mdb/mdb_modapi.h> 45 #include <mdb/mdb_ctf.h> 46 #include <mdb/mdb_whatis.h> 47 #include "sfmmu.h" 48 49 #ifndef SYSTRAP_TT 50 #define SYSTRAP_TT 0x1300 51 #endif 52 53 typedef struct trap_trace_fullrec { 54 struct trap_trace_record ttf_rec; 55 int ttf_cpu; 56 } trap_trace_fullrec_t; 57 58 #ifdef sun4v 59 typedef struct htrap_trace_fullrec { 60 struct htrap_trace_record ttf_rec; 61 int ttf_cpu; 62 } htrap_trace_fullrec_t; 63 #endif 64 65 /* 66 * These strings and accompanying macros allow our string table to look 67 * just like the real table in trap_table.s. 68 */ 69 70 static const char NOT[] = "reserved"; /* common reserved string */ 71 static const char BAD[] = "unused"; /* common unused string */ 72 73 #define NOT4 NOT, NOT, NOT, NOT 74 #define BAD4 BAD, BAD, BAD, BAD 75 76 static const char *const ttdescr[] = { 77 NOT, /* 000 reserved */ 78 "power-on", /* 001 power on reset */ 79 "watchdog", /* 002 watchdog reset */ 80 "xir", /* 003 externally initiated reset */ 81 "sir", /* 004 software initiated reset */ 82 "red", /* 005 red mode exception */ 83 NOT, NOT, /* 006 - 007 reserved */ 84 "immu-xcp", /* 008 instruction access exception */ 85 "immu-miss", /* 009 instruction access MMU miss */ 86 "immu-err", /* 00A instruction access error */ 87 NOT, NOT4, /* 00B - 00F reserved */ 88 "ill-inst", /* 010 illegal instruction */ 89 "priv-inst", /* 011 privileged opcode */ 90 "unimp-ldd", /* 012 unimplemented LDD */ 91 "unimp-std", /* 013 unimplemented STD */ 92 NOT4, NOT4, NOT4, /* 014 - 01F reserved */ 93 "fp-disable", /* 020 fp disabled */ 94 "fp-ieee754", /* 021 fp exception ieee 754 */ 95 "fp-xcp-other", /* 022 fp exception other */ 96 "tag-oflow", /* 023 tag overflow */ 97 "cleanwin", /* 024 clean window */ 98 "cleanwin", /* 025 clean window */ 99 "cleanwin", /* 026 clean window */ 100 "cleanwin", /* 027 clean window */ 101 "div-zero", /* 028 division by zero */ 102 "internal-err", /* 029 internal processor error */ 103 NOT, NOT, NOT4, /* 02A - 02F reserved */ 104 "dmmu-xcp", /* 030 data access exception */ 105 "dmmu-miss", /* 031 data access MMU miss */ 106 "dmmu-err", /* 032 data access error */ 107 "dmmu-prot", /* 033 data access protection */ 108 "unalign", /* 034 mem address not aligned */ 109 "lddf-unalign", /* 035 LDDF mem address not aligned */ 110 "stdf-unalign", /* 036 STDF mem address not aligned */ 111 "priv-act", /* 037 privileged action */ 112 "ldqf-unalign", /* 038 LDQF mem address not aligned */ 113 "stqf-unalign", /* 039 STQF mem address not aligned */ 114 NOT, NOT, NOT4, /* 03A - 03F reserved */ 115 "async-d-err", /* 040 async data error */ 116 "level-1", /* 041 interrupt level 1 */ 117 "level-2", /* 042 interrupt level 2 */ 118 "level-3", /* 043 interrupt level 3 */ 119 "level-4", /* 044 interrupt level 4 */ 120 "level-5", /* 045 interrupt level 5 */ 121 "level-6", /* 046 interrupt level 6 */ 122 "level-7", /* 047 interrupt level 7 */ 123 "level-8", /* 048 interrupt level 8 */ 124 "level-9", /* 049 interrupt level 9 */ 125 "level-10", /* 04A interrupt level 10 */ 126 "level-11", /* 04B interrupt level 11 */ 127 "level-12", /* 04C interrupt level 12 */ 128 "level-13", /* 04D interrupt level 13 */ 129 "level-14", /* 04E interrupt level 14 */ 130 "level-15", /* 04F interrupt level 15 */ 131 NOT4, NOT4, NOT4, NOT4, /* 050 - 05F reserved */ 132 "int-vec", /* 060 interrupt vector */ 133 "pa-watch", /* 061 PA watchpoint */ 134 "va-watch", /* 062 VA watchpoint */ 135 "ecc-err", /* 063 corrected ECC error */ 136 "itlb-miss", /* 064 instruction access MMU miss */ 137 "itlb-miss", /* 065 instruction access MMU miss */ 138 "itlb-miss", /* 066 instruction access MMU miss */ 139 "itlb-miss", /* 067 instruction access MMU miss */ 140 "dtlb-miss", /* 068 data access MMU miss */ 141 "dtlb-miss", /* 069 data access MMU miss */ 142 "dtlb-miss", /* 06A data access MMU miss */ 143 "dtlb-miss", /* 06B data access MMU miss */ 144 "dtlb-prot", /* 06C data access protection */ 145 "dtlb-prot", /* 06D data access protection */ 146 "dtlb-prot", /* 06E data access protection */ 147 "dtlb-prot", /* 06F data access protection */ 148 "fast-ecc-err", /* 070 fast ecache ECC error */ 149 "dp-err", /* 071 data cache parity error */ 150 "ip-err", /* 072 instr cache parity error */ 151 NOT, NOT4, NOT4, /* 073 - 07B reserved */ 152 #ifdef sun4v 153 "cpu-mondo", /* 07C CPU mondo */ 154 "dev-mondo", /* 07D device mondo */ 155 "res.-err", /* 07E resumable error */ 156 "non-res.-err", /* 07F non-resumable error */ 157 #else 158 NOT4, /* 07C - 07F reserved */ 159 #endif 160 "spill-0-norm", /* 080 spill 0 normal */ 161 "spill-0-norm", /* 081 spill 0 normal */ 162 "spill-0-norm", /* 082 spill 0 normal */ 163 "spill-0-norm", /* 083 spill 0 normal */ 164 "spill-1-norm", /* 084 spill 1 normal */ 165 "spill-1-norm", /* 085 spill 1 normal */ 166 "spill-1-norm", /* 086 spill 1 normal */ 167 "spill-1-norm", /* 087 spill 1 normal */ 168 "spill-2-norm", /* 088 spill 2 normal */ 169 "spill-2-norm", /* 089 spill 2 normal */ 170 "spill-2-norm", /* 08A spill 2 normal */ 171 "spill-2-norm", /* 08B spill 2 normal */ 172 "spill-3-norm", /* 08C spill 3 normal */ 173 "spill-3-norm", /* 08D spill 3 normal */ 174 "spill-3-norm", /* 08E spill 3 normal */ 175 "spill-3-norm", /* 08F spill 3 normal */ 176 "spill-4-norm", /* 090 spill 4 normal */ 177 "spill-4-norm", /* 091 spill 4 normal */ 178 "spill-4-norm", /* 092 spill 4 normal */ 179 "spill-4-norm", /* 093 spill 4 normal */ 180 "spill-5-norm", /* 094 spill 5 normal */ 181 "spill-5-norm", /* 095 spill 5 normal */ 182 "spill-5-norm", /* 096 spill 5 normal */ 183 "spill-5-norm", /* 097 spill 5 normal */ 184 "spill-6-norm", /* 098 spill 6 normal */ 185 "spill-6-norm", /* 099 spill 6 normal */ 186 "spill-6-norm", /* 09A spill 6 normal */ 187 "spill-6-norm", /* 09B spill 6 normal */ 188 "spill-7-norm", /* 09C spill 7 normal */ 189 "spill-7-norm", /* 09D spill 7 normal */ 190 "spill-7-norm", /* 09E spill 7 normal */ 191 "spill-7-norm", /* 09F spill 7 normal */ 192 "spill-0-oth", /* 0A0 spill 0 other */ 193 "spill-0-oth", /* 0A1 spill 0 other */ 194 "spill-0-oth", /* 0A2 spill 0 other */ 195 "spill-0-oth", /* 0A3 spill 0 other */ 196 "spill-1-oth", /* 0A4 spill 1 other */ 197 "spill-1-oth", /* 0A5 spill 1 other */ 198 "spill-1-oth", /* 0A6 spill 1 other */ 199 "spill-1-oth", /* 0A7 spill 1 other */ 200 "spill-2-oth", /* 0A8 spill 2 other */ 201 "spill-2-oth", /* 0A9 spill 2 other */ 202 "spill-2-oth", /* 0AA spill 2 other */ 203 "spill-2-oth", /* 0AB spill 2 other */ 204 "spill-3-oth", /* 0AC spill 3 other */ 205 "spill-3-oth", /* 0AD spill 3 other */ 206 "spill-3-oth", /* 0AE spill 3 other */ 207 "spill-3-oth", /* 0AF spill 3 other */ 208 "spill-4-oth", /* 0B0 spill 4 other */ 209 "spill-4-oth", /* 0B1 spill 4 other */ 210 "spill-4-oth", /* 0B2 spill 4 other */ 211 "spill-4-oth", /* 0B3 spill 4 other */ 212 "spill-5-oth", /* 0B4 spill 5 other */ 213 "spill-5-oth", /* 0B5 spill 5 other */ 214 "spill-5-oth", /* 0B6 spill 5 other */ 215 "spill-5-oth", /* 0B7 spill 5 other */ 216 "spill-6-oth", /* 0B8 spill 6 other */ 217 "spill-6-oth", /* 0B9 spill 6 other */ 218 "spill-6-oth", /* 0BA spill 6 other */ 219 "spill-6-oth", /* 0BB spill 6 other */ 220 "spill-7-oth", /* 0BC spill 7 other */ 221 "spill-7-oth", /* 0BD spill 7 other */ 222 "spill-7-oth", /* 0BE spill 7 other */ 223 "spill-7-oth", /* 0BF spill 7 other */ 224 "fill-0-norm", /* 0C0 fill 0 normal */ 225 "fill-0-norm", /* 0C1 fill 0 normal */ 226 "fill-0-norm", /* 0C2 fill 0 normal */ 227 "fill-0-norm", /* 0C3 fill 0 normal */ 228 "fill-1-norm", /* 0C4 fill 1 normal */ 229 "fill-1-norm", /* 0C5 fill 1 normal */ 230 "fill-1-norm", /* 0C6 fill 1 normal */ 231 "fill-1-norm", /* 0C7 fill 1 normal */ 232 "fill-2-norm", /* 0C8 fill 2 normal */ 233 "fill-2-norm", /* 0C9 fill 2 normal */ 234 "fill-2-norm", /* 0CA fill 2 normal */ 235 "fill-2-norm", /* 0CB fill 2 normal */ 236 "fill-3-norm", /* 0CC fill 3 normal */ 237 "fill-3-norm", /* 0CD fill 3 normal */ 238 "fill-3-norm", /* 0CE fill 3 normal */ 239 "fill-3-norm", /* 0CF fill 3 normal */ 240 "fill-4-norm", /* 0D0 fill 4 normal */ 241 "fill-4-norm", /* 0D1 fill 4 normal */ 242 "fill-4-norm", /* 0D2 fill 4 normal */ 243 "fill-4-norm", /* 0D3 fill 4 normal */ 244 "fill-5-norm", /* 0D4 fill 5 normal */ 245 "fill-5-norm", /* 0D5 fill 5 normal */ 246 "fill-5-norm", /* 0D6 fill 5 normal */ 247 "fill-5-norm", /* 0D7 fill 5 normal */ 248 "fill-6-norm", /* 0D8 fill 6 normal */ 249 "fill-6-norm", /* 0D9 fill 6 normal */ 250 "fill-6-norm", /* 0DA fill 6 normal */ 251 "fill-6-norm", /* 0DB fill 6 normal */ 252 "fill-7-norm", /* 0DC fill 7 normal */ 253 "fill-7-norm", /* 0DD fill 7 normal */ 254 "fill-7-norm", /* 0DE fill 7 normal */ 255 "fill-7-norm", /* 0DF fill 7 normal */ 256 "fill-0-oth", /* 0E0 fill 0 other */ 257 "fill-0-oth", /* 0E1 fill 0 other */ 258 "fill-0-oth", /* 0E2 fill 0 other */ 259 "fill-0-oth", /* 0E3 fill 0 other */ 260 "fill-1-oth", /* 0E4 fill 1 other */ 261 "fill-1-oth", /* 0E5 fill 1 other */ 262 "fill-1-oth", /* 0E6 fill 1 other */ 263 "fill-1-oth", /* 0E7 fill 1 other */ 264 "fill-2-oth", /* 0E8 fill 2 other */ 265 "fill-2-oth", /* 0E9 fill 2 other */ 266 "fill-2-oth", /* 0EA fill 2 other */ 267 "fill-2-oth", /* 0EB fill 2 other */ 268 "fill-3-oth", /* 0EC fill 3 other */ 269 "fill-3-oth", /* 0ED fill 3 other */ 270 "fill-3-oth", /* 0EE fill 3 other */ 271 "fill-3-oth", /* 0EF fill 3 other */ 272 "fill-4-oth", /* 0F0 fill 4 other */ 273 "fill-4-oth", /* 0F1 fill 4 other */ 274 "fill-4-oth", /* 0F2 fill 4 other */ 275 "fill-4-oth", /* 0F3 fill 4 other */ 276 "fill-5-oth", /* 0F4 fill 5 other */ 277 "fill-5-oth", /* 0F5 fill 5 other */ 278 "fill-5-oth", /* 0F6 fill 5 other */ 279 "fill-5-oth", /* 0F7 fill 5 other */ 280 "fill-6-oth", /* 0F8 fill 6 other */ 281 "fill-6-oth", /* 0F9 fill 6 other */ 282 "fill-6-oth", /* 0FA fill 6 other */ 283 "fill-6-oth", /* 0FB fill 6 other */ 284 "fill-7-oth", /* 0FC fill 7 other */ 285 "fill-7-oth", /* 0FD fill 7 other */ 286 "fill-7-oth", /* 0FE fill 7 other */ 287 "fill-7-oth", /* 0FF fill 7 other */ 288 "syscall-4x", /* 100 old system call */ 289 "usr-brkpt", /* 101 user breakpoint */ 290 "usr-div-zero", /* 102 user divide by zero */ 291 "flush-wins", /* 103 flush windows */ 292 "clean-wins", /* 104 clean windows */ 293 "range-chk", /* 105 range check ?? */ 294 "fix-align", /* 106 do unaligned references */ 295 BAD, /* 107 unused */ 296 "syscall-32", /* 108 ILP32 system call on LP64 */ 297 "set-t0-addr", /* 109 set trap0 address */ 298 BAD, BAD, BAD4, /* 10A - 10F unused */ 299 BAD4, BAD4, BAD4, BAD4, /* 110 - 11F unused (V9 user traps?) */ 300 "get-cc", /* 120 get condition codes */ 301 "set-cc", /* 121 set condition codes */ 302 "get-psr", /* 122 get psr */ 303 "set-psr", /* 123 set psr (some fields) */ 304 "getts", /* 124 get timestamp */ 305 "gethrvtime", /* 125 get lwp virtual time */ 306 "self-xcall", /* 126 self xcall */ 307 "gethrtime", /* 127 get hrestime */ 308 BAD, /* 128 unused (ST_SETV9STACK) */ 309 "getlgrp", /* 129 get lgrpid */ 310 BAD, BAD, BAD4, /* 12A - 12F unused */ 311 BAD4, BAD4, /* 130 - 137 unused */ 312 "dtrace-pid", /* 138 DTrace pid provider */ 313 BAD, /* 139 unused */ 314 "dtrace-return", /* 13A DTrace pid provider */ 315 BAD, BAD4, /* 13B - 13F unused */ 316 "syscall-64", /* 140 LP64 system call */ 317 BAD, /* 141 unused */ 318 "tt-freeze", /* 142 freeze traptrace */ 319 "tt-unfreeze", /* 143 unfreeze traptrace */ 320 BAD4, BAD4, BAD4, /* 144 - 14F unused */ 321 BAD4, BAD4, BAD4, BAD4, /* 150 - 15F unused */ 322 BAD4, BAD4, BAD4, BAD4, /* 160 - 16F unused */ 323 BAD4, BAD4, BAD4, /* 170 - 17B unused */ 324 "ptl1-panic", /* 17C test ptl1_panic */ 325 "kmdb-enter", /* 17D kmdb enter (L1-A) */ 326 "kmdb-brkpt", /* 17E kmdb breakpoint */ 327 "obp-brkpt", /* 17F obp breakpoint */ 328 #ifdef sun4v 329 "fast_trap", /* 180 hypervisor fast trap */ 330 "cpu_tick_npt", /* 181 cpu_tick_npt() hcall */ 331 "cpu_stick_npt", /* 182 cpu_stick_npt() hcall */ 332 "mmu_map_addr", /* 183 mmu_map_addr() hcall */ 333 "mmu_unmap_addr", /* 184 mmu_unmap_addr() hcall */ 334 "ttrace_addentry", /* 185 ttrace_addentry() hcall */ 335 NOT, NOT, NOT4, NOT4, /* 186 - 18F reserved */ 336 #else 337 NOT4, NOT4, NOT4, NOT4, /* 180 - 18F reserved */ 338 #endif 339 NOT4, NOT4, NOT4, NOT4, /* 190 - 19F reserved */ 340 NOT4, NOT4, NOT4, NOT4, /* 1A0 - 1AF reserved */ 341 NOT4, NOT4, NOT4, NOT4, /* 1B0 - 1BF reserved */ 342 NOT4, NOT4, NOT4, NOT4, /* 1C0 - 1CF reserved */ 343 NOT4, NOT4, NOT4, NOT4, /* 1D0 - 1DF reserved */ 344 NOT4, NOT4, NOT4, NOT4, /* 1E0 - 1EF reserved */ 345 NOT4, NOT4, NOT4, NOT4 /* 1F0 - 1FF reserved */ 346 }; 347 static const size_t ttndescr = sizeof (ttdescr) / sizeof (ttdescr[0]); 348 349 static GElf_Sym iv_sym; 350 351 /* 352 * Persistent data (shouldn't change). 353 */ 354 static int ncpu; /* _ncpu */ 355 static ssize_t mbox_size; /* size of xc_mbox */ 356 static ulong_t mbox_stoff; /* offset of xc_mbox.xc_state */ 357 static mdb_ctf_id_t mbox_states; /* xc_state enumeration */ 358 359 static int 360 fetch_ncpu(void) 361 { 362 if (ncpu == 0) 363 if (mdb_readsym(&ncpu, sizeof (ncpu), "_ncpu") == -1) { 364 mdb_warn("symbol '_ncpu' not found"); 365 return (1); 366 } 367 return (0); 368 } 369 370 static int 371 fetch_mbox(void) 372 { 373 if (mbox_size <= 0) { 374 mdb_ctf_id_t id; 375 376 if (mdb_ctf_lookup_by_name("struct xc_mbox", &id) == -1) { 377 mdb_warn("couldn't find type 'struct xc_mbox'"); 378 return (1); 379 } 380 381 /* 382 * These two could be combined into a single call to 383 * mdb_ctf_member_info if xc_state was actually of type 384 * enum xc_states. 385 */ 386 if (mdb_ctf_lookup_by_name("enum xc_states", 387 &mbox_states) == -1) { 388 mdb_warn("couldn't find type 'enum xc_states'"); 389 return (1); 390 } 391 if (mdb_ctf_offsetof(id, "xc_state", &mbox_stoff) == -1) { 392 mdb_warn("couldn't find 'xc_mbox.xc_state'"); 393 return (1); 394 } 395 mbox_stoff /= NBBY; 396 397 if ((mbox_size = mdb_ctf_type_size(id)) == -1) { 398 mdb_warn("couldn't size 'struct xc_mbox'"); 399 return (1); 400 } 401 } 402 return (0); 403 } 404 405 static int 406 print_range(int start, int end, int separator) 407 { 408 int count; 409 char tmp; 410 char *format; 411 412 if (start == end) { 413 /* Unfortunately, mdb_printf returns void */ 414 format = separator ? ", %d" : "%d"; 415 mdb_printf(format, start); 416 count = mdb_snprintf(&tmp, 1, format, start); 417 } else { 418 format = separator ? ", %d-%d" : "%d-%d"; 419 mdb_printf(format, start, end); 420 count = mdb_snprintf(&tmp, 1, format, start, end); 421 } 422 423 return (count); 424 } 425 426 static void 427 print_cpuset_range(ulong_t *cs, int words, int width) 428 { 429 int i, j; 430 ulong_t m; 431 int in = 0; 432 int start; 433 int end; 434 int count = 0; 435 int sep = 0; 436 437 for (i = 0; i < words; i++) 438 for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1) 439 if (cs[i] & m) { 440 if (in == 0) { 441 start = i * BT_NBIPUL + j; 442 in = 1; 443 } 444 } else { 445 if (in == 1) { 446 end = i * BT_NBIPUL + j - 1; 447 count += print_range(start, end, sep); 448 sep = 1; 449 in = 0; 450 } 451 } 452 if (in == 1) { 453 end = i * BT_NBIPUL - 1; 454 count += print_range(start, end, sep); 455 } 456 457 while (count++ < width) 458 mdb_printf(" "); 459 } 460 461 /*ARGSUSED*/ 462 static int 463 cmd_cpuset(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 464 { 465 uint_t rflag = 0, lflag = 0; 466 int words; 467 ulong_t *setp, set = 0; 468 469 if (mdb_getopts(argc, argv, 470 'l', MDB_OPT_SETBITS, TRUE, &lflag, 471 'r', MDB_OPT_SETBITS, TRUE, &rflag, NULL) != argc) 472 return (DCMD_USAGE); 473 474 if (lflag && rflag) 475 return (DCMD_USAGE); 476 477 if (fetch_ncpu()) 478 return (DCMD_ERR); 479 480 if ((words = BT_BITOUL(ncpu)) == 1) { 481 setp = &set; 482 mdb_vread(setp, sizeof (ulong_t), addr); 483 } else { 484 setp = mdb_alloc(words * sizeof (ulong_t), UM_SLEEP | UM_GC); 485 mdb_vread(setp, words * sizeof (ulong_t), addr); 486 } 487 488 if (lflag) { 489 int i, j; 490 ulong_t m; 491 492 for (i = 0; i < words; i++) 493 for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1) 494 if (setp[i] & m) 495 mdb_printf("%r\n", i * BT_NBIPUL + j); 496 } else if (rflag) { 497 int i; 498 int sep = 0; 499 500 for (i = 0; i < words; i++) { 501 mdb_printf(sep ? " %?0lx" : "%?0lx", setp[i]); 502 sep = 1; 503 } 504 } else { 505 print_cpuset_range(setp, words, 0); 506 } 507 508 return (DCMD_OK); 509 } 510 511 /*ARGSUSED*/ 512 int 513 ttctl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 514 { 515 TRAP_TRACE_CTL *ctls, *ctl; 516 int i, traptrace_buf_inuse = 0; 517 518 if (argc != 0) 519 return (DCMD_USAGE); 520 521 if (fetch_ncpu()) 522 return (DCMD_ERR); 523 524 ctls = mdb_alloc(sizeof (TRAP_TRACE_CTL) * ncpu, UM_SLEEP | UM_GC); 525 if (mdb_readsym(ctls, sizeof (TRAP_TRACE_CTL) * ncpu, 526 "trap_trace_ctl") == -1) { 527 mdb_warn("symbol 'trap_trace_ctl' not found"); 528 return (DCMD_ERR); 529 } 530 531 for (ctl = &ctls[0], i = 0; i < ncpu; i++, ctl++) { 532 if (ctl->d.vaddr_base == 0) 533 continue; 534 535 traptrace_buf_inuse = 1; 536 mdb_printf("trap_trace_ctl[%d] = {\n", i); 537 mdb_printf(" vaddr_base = 0x%lx\n", (long)ctl->d.vaddr_base); 538 mdb_printf(" last_offset = 0x%x\n", ctl->d.last_offset); 539 mdb_printf(" offset = 0x%x\n", ctl->d.offset); 540 mdb_printf(" limit = 0x%x\n", ctl->d.limit); 541 mdb_printf(" paddr_base = 0x%llx\n", ctl->d.paddr_base); 542 mdb_printf(" asi = 0x%02x\n}\n", ctl->d.asi); 543 } 544 if (!traptrace_buf_inuse) { 545 mdb_warn("traptrace not configured"); 546 return (DCMD_ERR); 547 } 548 549 return (DCMD_OK); 550 } 551 552 /*ARGSUSED*/ 553 static int 554 ttprint_short(uintptr_t addr, const trap_trace_fullrec_t *full, int *cpu) 555 { 556 const char *ttstr; 557 const struct trap_trace_record *ttp = &full->ttf_rec; 558 559 if (*cpu == -1) 560 mdb_printf("%3d ", full->ttf_cpu); 561 else 562 if (*cpu != full->ttf_cpu) 563 return (0); 564 565 /* 566 * Decoding the traptype field is a bit messy. First we check for 567 * several well-defined 16-bit values defined in <sys/traptrace.h>. 568 */ 569 switch (ttp->tt_tt) { 570 case TT_SC_ENTR: 571 ttstr = "sys-enter"; 572 break; 573 case TT_SC_RET: 574 ttstr = "sys-exit"; 575 break; 576 case TT_SYS_RTT_PROM: 577 ttstr = "prom_rtt"; 578 break; 579 case TT_SYS_RTT_PRIV: 580 ttstr = "priv_rtt"; 581 break; 582 case TT_SYS_RTT_USER: 583 ttstr = "user_rtt"; 584 break; 585 case TT_INTR_EXIT: 586 ttstr = "int-thr-exit"; 587 break; 588 default: 589 /* 590 * Next we consider several prefixes (which are 591 * typically OR'd with other information such as the 592 * %pil or %tt value at the time of the trace). 593 */ 594 switch (ttp->tt_tt & 0xff00) { 595 case TT_SERVE_INTR: 596 ttstr = "serve-intr"; 597 break; 598 case TT_XCALL: 599 ttstr = "xcall"; 600 break; 601 case TT_XCALL_CONT: 602 ttstr = "xcall-cont"; 603 break; 604 case SYSTRAP_TT: 605 ttstr = "sys_trap"; 606 break; 607 default: 608 /* 609 * Otherwise we try to convert the 610 * tt value to a string using our 611 * giant lookup table. 612 */ 613 ttstr = ttp->tt_tt < ttndescr ? 614 ttdescr[ttp->tt_tt] : "?"; 615 } 616 } 617 618 #ifdef sun4v 619 mdb_printf("%016llx %04hx %-12s %02x %02x %0?p %A\n", ttp->tt_tick, 620 ttp->tt_tt, ttstr, ttp->tt_tl, ttp->tt_gl, 621 ttp->tt_tpc, ttp->tt_tpc); 622 #else 623 mdb_printf("%016llx %04hx %-12s %04hx %0?p %A\n", ttp->tt_tick, 624 ttp->tt_tt, ttstr, ttp->tt_tl, ttp->tt_tpc, ttp->tt_tpc); 625 #endif 626 627 return (WALK_NEXT); 628 } 629 630 /*ARGSUSED*/ 631 static int 632 ttprint_long(uintptr_t addr, const trap_trace_fullrec_t *full, int *cpu) 633 { 634 const struct trap_trace_record *ttp = &full->ttf_rec; 635 636 if (*cpu == -1) 637 mdb_printf("%3d ", full->ttf_cpu); 638 else if (*cpu != full->ttf_cpu) 639 return (WALK_NEXT); 640 641 #ifdef sun4v 642 mdb_printf("%016llx %016llx %04hx %02x %02x %0?p %0?p %0?p " 643 "[%p,%p,%p,%p]\n", 644 ttp->tt_tick, ttp->tt_tstate, ttp->tt_tt, ttp->tt_tl, ttp->tt_gl, 645 ttp->tt_tpc, ttp->tt_sp, ttp->tt_tr, 646 ttp->tt_f1, ttp->tt_f2, ttp->tt_f3, ttp->tt_f4); 647 #else 648 mdb_printf("%016llx %016llx %04hx %04hx %0?p %0?p %0?p [%p,%p,%p,%p]\n", 649 ttp->tt_tick, ttp->tt_tstate, ttp->tt_tt, ttp->tt_tl, 650 ttp->tt_tpc, ttp->tt_sp, ttp->tt_tr, 651 ttp->tt_f1, ttp->tt_f2, ttp->tt_f3, ttp->tt_f4); 652 #endif 653 654 return (WALK_NEXT); 655 } 656 657 typedef struct ttrace_cpu_data { 658 struct trap_trace_record *tc_buf; 659 struct trap_trace_record *tc_rec; 660 struct trap_trace_record *tc_stop; 661 size_t tc_bufsiz; 662 uintptr_t tc_base; 663 } ttrace_cpu_data_t; 664 665 typedef struct ttrace_walk_data { 666 int tw_ncpu; 667 ttrace_cpu_data_t *tw_cpus; 668 } ttrace_walk_data_t; 669 670 int 671 ttrace_walk_init(mdb_walk_state_t *wsp) 672 { 673 TRAP_TRACE_CTL *ctls, *ctl; 674 int i, traptrace_buf_inuse = 0; 675 ttrace_walk_data_t *tw; 676 ttrace_cpu_data_t *tc; 677 struct trap_trace_record *buf; 678 679 if (wsp->walk_addr != NULL) { 680 mdb_warn("ttrace only supports global walks\n"); 681 return (WALK_ERR); 682 } 683 684 if (fetch_ncpu()) 685 return (WALK_ERR); 686 687 ctls = mdb_alloc(sizeof (TRAP_TRACE_CTL) * ncpu, UM_SLEEP); 688 if (mdb_readsym(ctls, sizeof (TRAP_TRACE_CTL) * ncpu, 689 "trap_trace_ctl") == -1) { 690 mdb_warn("symbol 'trap_trace_ctl' not found"); 691 mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu); 692 return (WALK_ERR); 693 } 694 695 tw = mdb_zalloc(sizeof (ttrace_walk_data_t), UM_SLEEP); 696 tw->tw_ncpu = ncpu; 697 tw->tw_cpus = mdb_zalloc(sizeof (ttrace_cpu_data_t) * ncpu, UM_SLEEP); 698 699 for (i = 0; i < ncpu; i++) { 700 ctl = &ctls[i]; 701 702 if (ctl->d.vaddr_base == 0) 703 continue; 704 705 traptrace_buf_inuse = 1; 706 tc = &(tw->tw_cpus[i]); 707 tc->tc_bufsiz = ctl->d.limit - 708 sizeof (struct trap_trace_record); 709 tc->tc_buf = buf = mdb_alloc(tc->tc_bufsiz, UM_SLEEP); 710 tc->tc_base = (uintptr_t)ctl->d.vaddr_base; 711 712 if (mdb_vread(buf, tc->tc_bufsiz, tc->tc_base) == -1) { 713 mdb_warn("failed to read trap trace buffer at %p", 714 ctl->d.vaddr_base); 715 mdb_free(buf, tc->tc_bufsiz); 716 tc->tc_buf = NULL; 717 } else { 718 tc->tc_rec = (struct trap_trace_record *) 719 ((uintptr_t)buf + (uintptr_t)ctl->d.last_offset); 720 tc->tc_stop = (struct trap_trace_record *) 721 ((uintptr_t)buf + (uintptr_t)ctl->d.offset); 722 } 723 } 724 if (!traptrace_buf_inuse) { 725 mdb_warn("traptrace not configured"); 726 mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu); 727 return (DCMD_ERR); 728 } 729 730 mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu); 731 wsp->walk_data = tw; 732 return (WALK_NEXT); 733 } 734 735 int 736 ttrace_walk_step(mdb_walk_state_t *wsp) 737 { 738 ttrace_walk_data_t *tw = wsp->walk_data; 739 ttrace_cpu_data_t *tc; 740 struct trap_trace_record *rec; 741 int oldest, i, status; 742 uint64_t oldest_tick = 0; 743 int done = 1; 744 trap_trace_fullrec_t fullrec; 745 746 for (i = 0; i < tw->tw_ncpu; i++) { 747 tc = &(tw->tw_cpus[i]); 748 749 if (tc->tc_rec == NULL) 750 continue; 751 done = 0; 752 753 if (tc->tc_rec->tt_tick == 0) 754 mdb_warn("Warning: tt_tick == 0\n"); 755 756 if (tc->tc_rec->tt_tick > oldest_tick) { 757 oldest_tick = tc->tc_rec->tt_tick; 758 oldest = i; 759 } 760 } 761 762 if (done) 763 return (-1); 764 765 tc = &(tw->tw_cpus[oldest]); 766 rec = tc->tc_rec; 767 768 fullrec.ttf_rec = *rec; 769 fullrec.ttf_cpu = oldest; 770 771 if (oldest_tick != 0) 772 status = wsp->walk_callback((uintptr_t)rec - 773 (uintptr_t)tc->tc_buf + tc->tc_base, &fullrec, 774 wsp->walk_cbdata); 775 776 tc->tc_rec--; 777 778 if (tc->tc_rec < tc->tc_buf) 779 tc->tc_rec = (struct trap_trace_record *)((uintptr_t) 780 tc->tc_buf + (uintptr_t)tc->tc_bufsiz - 781 sizeof (struct trap_trace_record)); 782 783 if (tc->tc_rec == tc->tc_stop) { 784 tc->tc_rec = NULL; 785 mdb_free(tc->tc_buf, tc->tc_bufsiz); 786 } 787 788 return (status); 789 } 790 791 void 792 ttrace_walk_fini(mdb_walk_state_t *wsp) 793 { 794 ttrace_walk_data_t *tw = wsp->walk_data; 795 796 mdb_free(tw->tw_cpus, sizeof (ttrace_cpu_data_t) * tw->tw_ncpu); 797 mdb_free(tw, sizeof (ttrace_walk_data_t)); 798 } 799 800 int 801 ttrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 802 { 803 uint_t opt_x = FALSE; 804 int cpu = -1; 805 mdb_walk_cb_t ttprint; 806 807 if (mdb_getopts(argc, argv, 808 'x', MDB_OPT_SETBITS, TRUE, &opt_x, NULL) != argc) 809 return (DCMD_USAGE); 810 811 if (flags & DCMD_ADDRSPEC) { 812 if (fetch_ncpu()) 813 return (DCMD_ERR); 814 if (addr >= ncpu) { 815 mdb_warn("expected cpu between 0 and %d\n", ncpu - 1); 816 return (DCMD_ERR); 817 } 818 cpu = (int)addr; 819 } 820 821 if (cpu == -1) 822 mdb_printf("CPU "); 823 824 if (opt_x) { 825 #ifdef sun4v 826 mdb_printf("%-16s %-16s %-4s %-3s %-3s %-?s %-?s %-?s " 827 "F1-4\n", "%tick", "%tstate", "%tt", "%tl", "%gl", 828 "%tpc", "%sp", "TR"); 829 #else 830 mdb_printf("%-16s %-16s %-4s %-4s %-?s %-?s %-?s " 831 "F1-4\n", "%tick", "%tstate", "%tt", "%tl", 832 "%tpc", "%sp", "TR"); 833 #endif 834 835 ttprint = (mdb_walk_cb_t)ttprint_long; 836 } else { 837 #ifdef sun4v 838 mdb_printf("%-16s %-4s %-12s %-3s %-3s %s\n", 839 "%tick", "%tt", "", "%tl", "%gl", "%tpc"); 840 #else 841 mdb_printf("%-16s %-4s %-12s %-4s %s\n", 842 "%tick", "%tt", "", "%tl", "%tpc"); 843 #endif 844 845 ttprint = (mdb_walk_cb_t)ttprint_short; 846 } 847 848 if (mdb_walk("ttrace", ttprint, &cpu) == -1) { 849 mdb_warn("couldn't walk ttrace"); 850 return (DCMD_ERR); 851 } 852 853 return (DCMD_OK); 854 } 855 856 #ifdef sun4v 857 /*ARGSUSED*/ 858 int 859 httctl(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 860 { 861 TRAP_TRACE_CTL *ctls, *ctl; 862 int i, htraptrace_buf_inuse = 0; 863 htrap_trace_hdr_t hdr; 864 865 if (argc != 0) 866 return (DCMD_USAGE); 867 868 if (fetch_ncpu()) 869 return (DCMD_ERR); 870 871 ctls = mdb_alloc(sizeof (TRAP_TRACE_CTL) * ncpu, UM_SLEEP | UM_GC); 872 if (mdb_readsym(ctls, sizeof (TRAP_TRACE_CTL) * ncpu, 873 "trap_trace_ctl") == -1) { 874 mdb_warn("symbol 'trap_trace_ctl' not found"); 875 return (DCMD_ERR); 876 } 877 878 for (ctl = &ctls[0], i = 0; i < ncpu; i++, ctl++) { 879 if (ctl->d.hvaddr_base == 0) 880 continue; 881 882 htraptrace_buf_inuse = 1; 883 mdb_vread(&hdr, sizeof (htrap_trace_hdr_t), 884 (uintptr_t)ctl->d.hvaddr_base); 885 mdb_printf("htrap_trace_ctl[%d] = {\n", i); 886 mdb_printf(" vaddr_base = 0x%lx\n", (long)ctl->d.hvaddr_base); 887 mdb_printf(" last_offset = 0x%lx\n", hdr.last_offset); 888 mdb_printf(" offset = 0x%lx\n", hdr.offset); 889 mdb_printf(" limit = 0x%x\n", ctl->d.hlimit); 890 mdb_printf(" paddr_base = 0x%llx\n}\n", ctl->d.hpaddr_base); 891 } 892 if (!htraptrace_buf_inuse) { 893 mdb_warn("hv traptrace not configured"); 894 return (DCMD_ERR); 895 } 896 897 return (DCMD_OK); 898 } 899 900 /*ARGSUSED*/ 901 static int 902 httprint_short(uintptr_t addr, const htrap_trace_fullrec_t *full, int *cpu) 903 { 904 const char *ttstr; 905 const struct htrap_trace_record *ttp = &full->ttf_rec; 906 907 if (*cpu == -1) 908 mdb_printf("%3d ", full->ttf_cpu); 909 else 910 if (*cpu != full->ttf_cpu) 911 return (0); 912 913 /* 914 * Convert the tt value to a string using our gaint lookuo table 915 */ 916 ttstr = ttp->tt_tt < ttndescr ? ttdescr[ttp->tt_tt] : "?"; 917 918 mdb_printf("%016llx %02x %04hx %04hx %-16s %02x %02x %0?p %A\n", 919 ttp->tt_tick, ttp->tt_ty, ttp->tt_tag, ttp->tt_tt, ttstr, 920 ttp->tt_tl, ttp->tt_gl, ttp->tt_tpc, ttp->tt_tpc); 921 922 return (WALK_NEXT); 923 } 924 925 /*ARGSUSED*/ 926 static int 927 httprint_long(uintptr_t addr, const htrap_trace_fullrec_t *full, int *cpu) 928 { 929 const struct htrap_trace_record *ttp = &full->ttf_rec; 930 931 if (*cpu == -1) 932 mdb_printf("%3d ", full->ttf_cpu); 933 else if (*cpu != full->ttf_cpu) 934 return (WALK_NEXT); 935 936 mdb_printf("%016llx %016llx %02x %02x %04hx %04hx %02x %02x %0?p " 937 "[%p,%p,%p,%p]\n", 938 ttp->tt_tick, ttp->tt_tstate, ttp->tt_hpstate, ttp->tt_ty, 939 ttp->tt_tag, ttp->tt_tt, ttp->tt_tl, ttp->tt_gl, ttp->tt_tpc, 940 ttp->tt_f1, ttp->tt_f2, ttp->tt_f3, ttp->tt_f4); 941 942 return (WALK_NEXT); 943 } 944 945 typedef struct httrace_cpu_data { 946 struct htrap_trace_record *tc_buf; 947 struct htrap_trace_record *tc_rec; 948 struct htrap_trace_record *tc_stop; 949 size_t tc_bufsiz; 950 uintptr_t tc_base; 951 } httrace_cpu_data_t; 952 953 typedef struct httrace_walk_data { 954 int tw_ncpu; 955 httrace_cpu_data_t *tw_cpus; 956 } httrace_walk_data_t; 957 958 int 959 httrace_walk_init(mdb_walk_state_t *wsp) 960 { 961 TRAP_TRACE_CTL *ctls, *ctl; 962 int i, htraptrace_buf_inuse = 0; 963 httrace_walk_data_t *tw; 964 httrace_cpu_data_t *tc; 965 struct htrap_trace_record *buf; 966 htrap_trace_hdr_t *hdr; 967 968 if (wsp->walk_addr != NULL) { 969 mdb_warn("httrace only supports global walks\n"); 970 return (WALK_ERR); 971 } 972 973 if (fetch_ncpu()) 974 return (WALK_ERR); 975 976 ctls = mdb_alloc(sizeof (TRAP_TRACE_CTL) * ncpu, UM_SLEEP); 977 if (mdb_readsym(ctls, sizeof (TRAP_TRACE_CTL) * ncpu, 978 "trap_trace_ctl") == -1) { 979 mdb_warn("symbol 'trap_trace_ctl' not found"); 980 mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu); 981 return (WALK_ERR); 982 } 983 984 tw = mdb_zalloc(sizeof (httrace_walk_data_t), UM_SLEEP); 985 tw->tw_ncpu = ncpu; 986 tw->tw_cpus = mdb_zalloc(sizeof (httrace_cpu_data_t) * ncpu, UM_SLEEP); 987 988 for (i = 0; i < ncpu; i++) { 989 ctl = &ctls[i]; 990 991 if (ctl->d.hvaddr_base == 0) 992 continue; 993 994 htraptrace_buf_inuse = 1; 995 tc = &(tw->tw_cpus[i]); 996 tc->tc_bufsiz = ctl->d.hlimit; 997 tc->tc_buf = buf = mdb_alloc(tc->tc_bufsiz, UM_SLEEP); 998 tc->tc_base = (uintptr_t)ctl->d.hvaddr_base; 999 1000 if (mdb_vread(buf, tc->tc_bufsiz, tc->tc_base) == -1) { 1001 mdb_warn("failed to read hv trap trace buffer at %p", 1002 ctl->d.hvaddr_base); 1003 mdb_free(buf, tc->tc_bufsiz); 1004 tc->tc_buf = NULL; 1005 } else { 1006 hdr = (htrap_trace_hdr_t *)buf; 1007 tc->tc_rec = (struct htrap_trace_record *) 1008 ((uintptr_t)buf + (uintptr_t)hdr->last_offset); 1009 tc->tc_stop = (struct htrap_trace_record *) 1010 ((uintptr_t)buf + (uintptr_t)hdr->offset); 1011 } 1012 } 1013 if (!htraptrace_buf_inuse) { 1014 mdb_warn("hv traptrace not configured"); 1015 mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu); 1016 return (DCMD_ERR); 1017 } 1018 1019 mdb_free(ctls, sizeof (TRAP_TRACE_CTL) * ncpu); 1020 wsp->walk_data = tw; 1021 return (WALK_NEXT); 1022 } 1023 1024 int 1025 httrace_walk_step(mdb_walk_state_t *wsp) 1026 { 1027 httrace_walk_data_t *tw = wsp->walk_data; 1028 httrace_cpu_data_t *tc; 1029 struct htrap_trace_record *rec; 1030 int oldest, i, status; 1031 uint64_t oldest_tick = 0; 1032 int done = 1; 1033 htrap_trace_fullrec_t fullrec; 1034 1035 for (i = 0; i < tw->tw_ncpu; i++) { 1036 tc = &(tw->tw_cpus[i]); 1037 1038 if (tc->tc_rec == NULL) 1039 continue; 1040 done = 0; 1041 1042 if (tc->tc_rec->tt_tick == 0) 1043 mdb_warn("Warning: tt_tick == 0\n"); 1044 1045 if (tc->tc_rec->tt_tick >= oldest_tick) { 1046 oldest_tick = tc->tc_rec->tt_tick; 1047 oldest = i; 1048 } 1049 } 1050 1051 if (done) 1052 return (-1); 1053 1054 tc = &(tw->tw_cpus[oldest]); 1055 rec = tc->tc_rec; 1056 1057 fullrec.ttf_rec = *rec; 1058 fullrec.ttf_cpu = oldest; 1059 1060 if (oldest_tick != 0) 1061 status = wsp->walk_callback((uintptr_t)rec - 1062 (uintptr_t)tc->tc_buf + tc->tc_base, &fullrec, 1063 wsp->walk_cbdata); 1064 1065 tc->tc_rec--; 1066 1067 /* first record of the trap trace buffer is trap trace header */ 1068 if (tc->tc_rec == tc->tc_buf) 1069 tc->tc_rec = (struct htrap_trace_record *)((uintptr_t) 1070 tc->tc_buf + (uintptr_t)tc->tc_bufsiz - 1071 sizeof (struct htrap_trace_record)); 1072 1073 if (tc->tc_rec == tc->tc_stop) { 1074 tc->tc_rec = NULL; 1075 mdb_free(tc->tc_buf, tc->tc_bufsiz); 1076 } 1077 1078 return (status); 1079 } 1080 1081 void 1082 httrace_walk_fini(mdb_walk_state_t *wsp) 1083 { 1084 httrace_walk_data_t *tw = wsp->walk_data; 1085 1086 mdb_free(tw->tw_cpus, sizeof (httrace_cpu_data_t) * tw->tw_ncpu); 1087 mdb_free(tw, sizeof (httrace_walk_data_t)); 1088 } 1089 1090 int 1091 httrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1092 { 1093 uint_t opt_x = FALSE; 1094 int cpu = -1; 1095 mdb_walk_cb_t ttprint; 1096 1097 if (mdb_getopts(argc, argv, 1098 'x', MDB_OPT_SETBITS, TRUE, &opt_x, NULL) != argc) 1099 return (DCMD_USAGE); 1100 1101 if (flags & DCMD_ADDRSPEC) { 1102 if (fetch_ncpu()) 1103 return (DCMD_ERR); 1104 if (addr >= ncpu) { 1105 mdb_warn("expected cpu between 0 and %d\n", ncpu - 1); 1106 return (DCMD_ERR); 1107 } 1108 cpu = (int)addr; 1109 } 1110 1111 if (cpu == -1) 1112 mdb_printf("CPU "); 1113 1114 if (opt_x) { 1115 mdb_printf("%-16s %-16s %-3s %-3s %-4s %-4s %-3s %-3s %-?s " 1116 "F1-4\n", "%tick", "%tstate", "%hp", "%ty", "%tag", 1117 "%tt", "%tl", "%gl", "%tpc"); 1118 ttprint = (mdb_walk_cb_t)httprint_long; 1119 } else { 1120 mdb_printf("%-16s %-3s %-4s %-4s %-16s %-3s %-3s %s\n", 1121 "%tick", "%ty", "%tag", "%tt", "", "%tl", "%gl", 1122 "%tpc"); 1123 ttprint = (mdb_walk_cb_t)httprint_short; 1124 } 1125 1126 if (mdb_walk("httrace", ttprint, &cpu) == -1) { 1127 mdb_warn("couldn't walk httrace"); 1128 return (DCMD_ERR); 1129 } 1130 1131 return (DCMD_OK); 1132 } 1133 #endif 1134 1135 struct { 1136 int xc_type; 1137 const char *xc_str; 1138 } xc_data[] = { 1139 { XT_ONE_SELF, "xt-one-self" }, 1140 { XT_ONE_OTHER, "xt-one-other" }, 1141 { XT_SOME_SELF, "xt-some-self" }, 1142 { XT_SOME_OTHER, "xt-some-other" }, 1143 { XT_ALL_SELF, "xt-all-self" }, 1144 { XT_ALL_OTHER, "xt-all-other" }, 1145 { XC_ONE_SELF, "xc-one-self" }, 1146 { XC_ONE_OTHER, "xc-one-other" }, 1147 { XC_ONE_OTHER_H, "xc-one-other-h" }, 1148 { XC_SOME_SELF, "xc-some-self" }, 1149 { XC_SOME_OTHER, "xc-some-other" }, 1150 { XC_SOME_OTHER_H, "xc-some-other-h" }, 1151 { XC_ALL_SELF, "xc-all-self" }, 1152 { XC_ALL_OTHER, "xc-all-other" }, 1153 { XC_ALL_OTHER_H, "xc-all-other-h" }, 1154 { XC_ATTENTION, "xc-attention" }, 1155 { XC_DISMISSED, "xc-dismissed" }, 1156 { XC_LOOP_ENTER, "xc-loop-enter" }, 1157 { XC_LOOP_DOIT, "xc-loop-doit" }, 1158 { XC_LOOP_EXIT, "xc-loop-exit" }, 1159 { 0, NULL } 1160 }; 1161 1162 /*ARGSUSED*/ 1163 int 1164 xctrace_walk(uintptr_t addr, const trap_trace_fullrec_t *full, int *cpu) 1165 { 1166 const struct trap_trace_record *ttp = &full->ttf_rec; 1167 int i, type = ttp->tt_tt & 0xff; 1168 const char *str = "???"; 1169 1170 if ((ttp->tt_tt & 0xff00) == TT_XCALL) { 1171 for (i = 0; xc_data[i].xc_str != NULL; i++) { 1172 if (xc_data[i].xc_type == type) { 1173 str = xc_data[i].xc_str; 1174 break; 1175 } 1176 } 1177 } else if ((ttp->tt_tt & 0xff00) == TT_XCALL_CONT) { 1178 str = "xcall-cont"; 1179 mdb_printf("%3d %016llx %-16s %08x %08x %08x %08x\n", 1180 full->ttf_cpu, ttp->tt_tick, str, ttp->tt_f1, ttp->tt_f2, 1181 ttp->tt_f3, ttp->tt_f4); 1182 return (WALK_NEXT); 1183 } else if (ttp->tt_tt == 0x60) { 1184 str = "int-vec"; 1185 } else { 1186 return (WALK_NEXT); 1187 } 1188 1189 mdb_printf("%3d %016llx %-16s %08x %a\n", full->ttf_cpu, 1190 ttp->tt_tick, str, ttp->tt_sp, ttp->tt_tr); 1191 1192 return (WALK_NEXT); 1193 } 1194 1195 /*ARGSUSED*/ 1196 int 1197 xctrace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1198 { 1199 if ((flags & DCMD_ADDRSPEC) || argc != 0) 1200 return (DCMD_USAGE); 1201 1202 if (mdb_walk("ttrace", (mdb_walk_cb_t)xctrace_walk, NULL) == -1) { 1203 mdb_warn("couldn't walk ttrace"); 1204 return (DCMD_ERR); 1205 } 1206 1207 return (DCMD_OK); 1208 } 1209 1210 /* 1211 * Grrr... xc_mbox isn't in an _impl header file; we define it here. 1212 */ 1213 typedef struct xc_mbox { 1214 xcfunc_t *xc_func; 1215 uint64_t xc_arg1; 1216 uint64_t xc_arg2; 1217 cpuset_t xc_cpuset; 1218 volatile uint_t xc_state; 1219 } xc_mbox_t; 1220 1221 typedef struct xc_mbox_walk { 1222 int xw_ndx; 1223 uintptr_t xw_addr; 1224 xc_mbox_t *xw_mbox; 1225 } xc_mbox_walk_t; 1226 1227 static int 1228 xc_mbox_walk_init(mdb_walk_state_t *wsp) 1229 { 1230 GElf_Sym sym; 1231 xc_mbox_walk_t *xw; 1232 1233 if (mdb_lookup_by_name("xc_mbox", &sym) == -1) { 1234 mdb_warn("couldn't find 'xc_mbox'"); 1235 return (WALK_ERR); 1236 } 1237 1238 if (fetch_ncpu() || fetch_mbox()) 1239 return (WALK_ERR); 1240 1241 xw = mdb_zalloc(sizeof (xc_mbox_walk_t), UM_SLEEP); 1242 xw->xw_mbox = mdb_zalloc(mbox_size * ncpu, UM_SLEEP); 1243 1244 if (mdb_readsym(xw->xw_mbox, mbox_size * ncpu, "xc_mbox") == -1) { 1245 mdb_warn("couldn't read 'xc_mbox'"); 1246 mdb_free(xw->xw_mbox, mbox_size * ncpu); 1247 mdb_free(xw, sizeof (xc_mbox_walk_t)); 1248 return (WALK_ERR); 1249 } 1250 1251 xw->xw_addr = sym.st_value; 1252 wsp->walk_data = xw; 1253 1254 return (WALK_NEXT); 1255 } 1256 1257 static int 1258 xc_mbox_walk_step(mdb_walk_state_t *wsp) 1259 { 1260 xc_mbox_walk_t *xw = wsp->walk_data; 1261 int status; 1262 1263 if (xw->xw_ndx == ncpu) 1264 return (WALK_DONE); 1265 1266 status = wsp->walk_callback(xw->xw_addr, 1267 &xw->xw_mbox[xw->xw_ndx++], wsp->walk_cbdata); 1268 1269 xw->xw_addr += mbox_size; 1270 return (status); 1271 } 1272 1273 static void 1274 xc_mbox_walk_fini(mdb_walk_state_t *wsp) 1275 { 1276 xc_mbox_walk_t *xw = wsp->walk_data; 1277 1278 mdb_free(xw->xw_mbox, mbox_size * ncpu); 1279 mdb_free(xw, sizeof (xc_mbox_walk_t)); 1280 } 1281 1282 static int 1283 xc_mbox(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1284 { 1285 xc_mbox_t *mbox; 1286 GElf_Sym sym; 1287 const char *state; 1288 1289 if (argc != 0) 1290 return (DCMD_USAGE); 1291 1292 if (!(flags & DCMD_ADDRSPEC)) { 1293 if (mdb_walk_dcmd("xc_mbox", "xc_mbox", argc, argv) == -1) { 1294 mdb_warn("can't walk 'xc_mbox'"); 1295 return (DCMD_ERR); 1296 } 1297 return (DCMD_OK); 1298 } 1299 1300 if (fetch_ncpu() || fetch_mbox()) 1301 return (DCMD_ERR); 1302 1303 if (DCMD_HDRSPEC(flags)) { 1304 mdb_printf("%3s %-8s %-8s %-9s %-16s %-16s %s\n", 1305 "CPU", "ADDR", "STATE", "CPUSET", "ARG1", "ARG2", "HNDLR"); 1306 } 1307 1308 mbox = mdb_alloc(mbox_size, UM_SLEEP | UM_GC); 1309 if (mdb_vread(mbox, mbox_size, addr) == -1) { 1310 mdb_warn("couldn't read xc_mbox at %p", addr); 1311 return (DCMD_ERR); 1312 } 1313 1314 if (mbox->xc_func == NULL) 1315 return (DCMD_OK); 1316 1317 if (mdb_lookup_by_name("xc_mbox", &sym) == -1) { 1318 mdb_warn("couldn't read 'xc_mbox'"); 1319 return (DCMD_ERR); 1320 } 1321 1322 state = mdb_ctf_enum_name(mbox_states, 1323 /* LINTED - alignment */ 1324 *(int *)((char *)mbox + mbox_stoff)); 1325 1326 mdb_printf("%3d %08x %-8s [ ", 1327 (int)((addr - sym.st_value) / mbox_size), addr, 1328 state ? state : "XC_???"); 1329 1330 print_cpuset_range((ulong_t *)&mbox->xc_cpuset, BT_BITOUL(ncpu), 5); 1331 1332 mdb_printf(" ] %-16a %-16a %a\n", 1333 mbox->xc_arg1, mbox->xc_arg2, mbox->xc_func); 1334 1335 return (DCMD_OK); 1336 } 1337 1338 typedef struct vecint_walk_data { 1339 intr_vec_t **vec_table; 1340 uintptr_t vec_base; 1341 size_t vec_idx; 1342 size_t vec_size; 1343 } vecint_walk_data_t; 1344 1345 int 1346 vecint_walk_init(mdb_walk_state_t *wsp) 1347 { 1348 vecint_walk_data_t *vecint; 1349 1350 if (wsp->walk_addr != NULL) { 1351 mdb_warn("vecint walk only supports global walks\n"); 1352 return (WALK_ERR); 1353 } 1354 1355 vecint = mdb_zalloc(sizeof (vecint_walk_data_t), UM_SLEEP); 1356 1357 vecint->vec_size = MAXIVNUM * sizeof (intr_vec_t *); 1358 vecint->vec_base = (uintptr_t)iv_sym.st_value; 1359 vecint->vec_table = mdb_zalloc(vecint->vec_size, UM_SLEEP); 1360 1361 if (mdb_vread(vecint->vec_table, vecint->vec_size, 1362 vecint->vec_base) == -1) { 1363 mdb_warn("couldn't read intr_vec_table"); 1364 mdb_free(vecint->vec_table, vecint->vec_size); 1365 mdb_free(vecint, sizeof (vecint_walk_data_t)); 1366 return (WALK_ERR); 1367 } 1368 1369 wsp->walk_data = vecint; 1370 return (WALK_NEXT); 1371 } 1372 1373 int 1374 vecint_walk_step(mdb_walk_state_t *wsp) 1375 { 1376 vecint_walk_data_t *vecint = (vecint_walk_data_t *)wsp->walk_data; 1377 size_t max = vecint->vec_size / sizeof (intr_vec_t *); 1378 intr_vec_t iv; 1379 int status; 1380 1381 if (wsp->walk_addr == NULL) { 1382 while ((vecint->vec_idx < max) && ((wsp->walk_addr = 1383 (uintptr_t)vecint->vec_table[vecint->vec_idx++]) == NULL)) 1384 continue; 1385 } 1386 1387 if (wsp->walk_addr == NULL) 1388 return (WALK_DONE); 1389 1390 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1391 wsp->walk_cbdata); 1392 1393 if (mdb_vread(&iv, sizeof (intr_vec_t), 1394 (uintptr_t)wsp->walk_addr) == -1) { 1395 mdb_warn("failed to read iv_p %p\n", wsp->walk_addr); 1396 return (WALK_ERR); 1397 } 1398 1399 wsp->walk_addr = (uintptr_t)iv.iv_vec_next; 1400 return (status); 1401 } 1402 1403 void 1404 vecint_walk_fini(mdb_walk_state_t *wsp) 1405 { 1406 vecint_walk_data_t *vecint = wsp->walk_data; 1407 1408 mdb_free(vecint->vec_table, vecint->vec_size); 1409 mdb_free(vecint, sizeof (vecint_walk_data_t)); 1410 } 1411 1412 int 1413 vecint_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1414 { 1415 intr_vec_t iv; 1416 1417 if (!(flags & DCMD_ADDRSPEC)) { 1418 if (mdb_walk_dcmd("vecint", "vecint", argc, argv) == -1) { 1419 mdb_warn("can't walk vecint"); 1420 return (DCMD_ERR); 1421 } 1422 return (DCMD_OK); 1423 } 1424 1425 if (DCMD_HDRSPEC(flags)) { 1426 mdb_printf("%4s %?s %4s %?s %?s %s\n", "INUM", "ADDR", 1427 "PIL", "ARG1", "ARG2", "HANDLER"); 1428 } 1429 1430 if (mdb_vread(&iv, sizeof (iv), addr) == -1) { 1431 mdb_warn("couldn't read intr_vec_table at %p", addr); 1432 return (DCMD_ERR); 1433 } 1434 1435 mdb_printf("%4x %?p %4d %?p %?p %a\n", iv.iv_inum, addr, 1436 iv.iv_pil, iv.iv_arg1, iv.iv_arg2, iv.iv_handler); 1437 1438 return (DCMD_OK); 1439 } 1440 1441 int 1442 softint_walk_init(mdb_walk_state_t *wsp) 1443 { 1444 intr_vec_t *list; 1445 1446 if (wsp->walk_addr != NULL) { 1447 mdb_warn("softint walk only supports global walks\n"); 1448 return (WALK_ERR); 1449 } 1450 1451 /* Read global softint linked list pointer */ 1452 if (mdb_readvar(&list, "softint_list") == -1) { 1453 mdb_warn("failed to read the global softint_list pointer\n"); 1454 return (WALK_ERR); 1455 } 1456 1457 wsp->walk_addr = (uintptr_t)list; 1458 return (WALK_NEXT); 1459 } 1460 1461 /*ARGSUSED*/ 1462 void 1463 softint_walk_fini(mdb_walk_state_t *wsp) 1464 { 1465 /* Nothing to do here */ 1466 } 1467 1468 int 1469 softint_walk_step(mdb_walk_state_t *wsp) 1470 { 1471 intr_vec_t iv; 1472 int status; 1473 1474 if (wsp->walk_addr == NULL) 1475 return (WALK_DONE); 1476 1477 status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data, 1478 wsp->walk_cbdata); 1479 1480 if (mdb_vread(&iv, sizeof (intr_vec_t), 1481 (uintptr_t)wsp->walk_addr) == -1) { 1482 mdb_warn("failed to read iv_p %p\n", wsp->walk_addr); 1483 return (WALK_ERR); 1484 } 1485 1486 wsp->walk_addr = (uintptr_t)iv.iv_vec_next; 1487 return (status); 1488 } 1489 1490 int 1491 softint_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1492 { 1493 intr_vec_t iv; 1494 1495 if (!(flags & DCMD_ADDRSPEC)) { 1496 if (mdb_walk_dcmd("softint", "softint", argc, argv) == -1) { 1497 mdb_warn("can't walk softint"); 1498 return (DCMD_ERR); 1499 } 1500 return (DCMD_OK); 1501 } 1502 1503 if (DCMD_HDRSPEC(flags)) { 1504 mdb_printf("%?s %4s %4s %4s %?s %?s %s\n", "ADDR", "TYPE", 1505 "PEND", "PIL", "ARG1", "ARG2", "HANDLER"); 1506 } 1507 1508 if (mdb_vread(&iv, sizeof (iv), addr) == -1) { 1509 mdb_warn("couldn't read softint at %p", addr); 1510 return (DCMD_ERR); 1511 } 1512 1513 mdb_printf("%?p %4s %4d %4d %?p %?p %a\n", addr, 1514 (iv.iv_flags & IV_SOFTINT_MT) ? "M" : "S", 1515 iv.iv_flags & IV_SOFTINT_PEND, iv.iv_pil, 1516 iv.iv_arg1, iv.iv_arg2, iv.iv_handler); 1517 1518 return (DCMD_OK); 1519 } 1520 1521 static int 1522 whatis_walk_tt(uintptr_t taddr, const trap_trace_fullrec_t *ttf, 1523 mdb_whatis_t *w) 1524 { 1525 uintptr_t cur = 0; 1526 1527 while (mdb_whatis_match(w, taddr, sizeof (struct trap_trace_record), 1528 &cur)) 1529 mdb_whatis_report_object(w, cur, taddr, 1530 "trap trace record for cpu %d\n", ttf->ttf_cpu); 1531 1532 return (WHATIS_WALKRET(w)); 1533 } 1534 1535 /*ARGSUSED*/ 1536 static int 1537 whatis_run_traptrace(mdb_whatis_t *w, void *ignored) 1538 { 1539 GElf_Sym sym; 1540 1541 if (mdb_lookup_by_name("trap_trace_ctl", &sym) == -1) 1542 return (0); 1543 1544 if (mdb_walk("ttrace", (mdb_walk_cb_t)whatis_walk_tt, w) == -1) 1545 mdb_warn("failed to walk 'ttrace'"); 1546 1547 return (0); 1548 } 1549 1550 /*ARGSUSED*/ 1551 int 1552 mutex_owner_init(mdb_walk_state_t *wsp) 1553 { 1554 return (WALK_NEXT); 1555 } 1556 1557 int 1558 mutex_owner_step(mdb_walk_state_t *wsp) 1559 { 1560 uintptr_t addr = wsp->walk_addr; 1561 mutex_impl_t mtx; 1562 uintptr_t owner; 1563 kthread_t thr; 1564 1565 if (mdb_vread(&mtx, sizeof (mtx), addr) == -1) 1566 return (WALK_ERR); 1567 1568 if (!MUTEX_TYPE_ADAPTIVE(&mtx)) 1569 return (WALK_DONE); 1570 1571 if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == NULL) 1572 return (WALK_DONE); 1573 1574 if (mdb_vread(&thr, sizeof (thr), owner) != -1) 1575 (void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata); 1576 1577 return (WALK_DONE); 1578 } 1579 1580 static const mdb_dcmd_t dcmds[] = { 1581 { "cpuset", ":[-l|-r]", "dump a cpuset_t", cmd_cpuset }, 1582 { "ttctl", NULL, "dump trap trace ctl records", ttctl }, 1583 { "ttrace", "[-x]", "dump trap trace buffer for a cpu", ttrace }, 1584 #ifdef sun4v 1585 { "httctl", NULL, "dump hv trap trace ctl records", httctl }, 1586 { "httrace", "[-x]", "dump hv trap trace buffer for a cpu", httrace }, 1587 #endif 1588 { "xc_mbox", "?", "dump xcall mboxes", xc_mbox }, 1589 { "xctrace", NULL, "dump xcall trace buffer", xctrace }, 1590 { "vecint", NULL, "display a registered hardware interrupt", 1591 vecint_dcmd }, 1592 { "softint", NULL, "display a registered software interrupt", 1593 softint_dcmd }, 1594 { "sfmmu_vtop", ":[[-v] -a as]", "print virtual to physical mapping", 1595 sfmmu_vtop }, 1596 { "memseg_list", ":", "show memseg list", memseg_list }, 1597 { "tsbinfo", ":[-l [-a]]", "show tsbinfo", tsbinfo_list, 1598 tsbinfo_help }, 1599 { NULL } 1600 }; 1601 1602 static const mdb_walker_t walkers[] = { 1603 { "mutex_owner", "walks the owner of a mutex", 1604 mutex_owner_init, mutex_owner_step }, 1605 { "ttrace", "walks the trap trace buffer for a CPU", 1606 ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini }, 1607 #ifdef sun4v 1608 { "httrace", "walks the hv trap trace buffer for a CPU", 1609 httrace_walk_init, httrace_walk_step, httrace_walk_fini }, 1610 #endif 1611 { "xc_mbox", "walks the cross call mail boxes", 1612 xc_mbox_walk_init, xc_mbox_walk_step, xc_mbox_walk_fini }, 1613 { "vecint", "walk the list of registered hardware interrupts", 1614 vecint_walk_init, vecint_walk_step, vecint_walk_fini }, 1615 { "softint", "walk the list of registered software interrupts", 1616 softint_walk_init, softint_walk_step, softint_walk_fini }, 1617 { "memseg", "walk the memseg structures", 1618 memseg_walk_init, memseg_walk_step, memseg_walk_fini }, 1619 { NULL } 1620 }; 1621 1622 static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers }; 1623 1624 const mdb_modinfo_t * 1625 _mdb_init(void) 1626 { 1627 if (mdb_lookup_by_name("intr_vec_table", &iv_sym) == -1) { 1628 mdb_warn("couldn't find intr_vec_table"); 1629 return (NULL); 1630 } 1631 1632 mdb_whatis_register("traptrace", whatis_run_traptrace, NULL, 1633 WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID); 1634 1635 return (&modinfo); 1636 } 1637