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
fetch_ncpu(void)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
fetch_mbox(void)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
print_range(int start,int end,int separator)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
print_cpuset_range(ulong_t * cs,int words,int width)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
cmd_cpuset(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
ttctl(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
ttprint_short(uintptr_t addr,const trap_trace_fullrec_t * full,int * cpu)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
ttprint_long(uintptr_t addr,const trap_trace_fullrec_t * full,int * cpu)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
ttrace_walk_init(mdb_walk_state_t * wsp)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
ttrace_walk_step(mdb_walk_state_t * wsp)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
ttrace_walk_fini(mdb_walk_state_t * wsp)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
ttrace(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
httctl(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
httprint_short(uintptr_t addr,const htrap_trace_fullrec_t * full,int * cpu)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
httprint_long(uintptr_t addr,const htrap_trace_fullrec_t * full,int * cpu)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
httrace_walk_init(mdb_walk_state_t * wsp)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
httrace_walk_step(mdb_walk_state_t * wsp)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
httrace_walk_fini(mdb_walk_state_t * wsp)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
httrace(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
xctrace_walk(uintptr_t addr,const trap_trace_fullrec_t * full,int * cpu)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
xctrace(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
xc_mbox_walk_init(mdb_walk_state_t * wsp)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
xc_mbox_walk_step(mdb_walk_state_t * wsp)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
xc_mbox_walk_fini(mdb_walk_state_t * wsp)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
xc_mbox(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
vecint_walk_init(mdb_walk_state_t * wsp)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
vecint_walk_step(mdb_walk_state_t * wsp)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
vecint_walk_fini(mdb_walk_state_t * wsp)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
vecint_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
softint_walk_init(mdb_walk_state_t * wsp)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
softint_walk_fini(mdb_walk_state_t * wsp)1463 softint_walk_fini(mdb_walk_state_t *wsp)
1464 {
1465 /* Nothing to do here */
1466 }
1467
1468 int
softint_walk_step(mdb_walk_state_t * wsp)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
softint_dcmd(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)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
whatis_walk_tt(uintptr_t taddr,const trap_trace_fullrec_t * ttf,mdb_whatis_t * w)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
whatis_run_traptrace(mdb_whatis_t * w,void * ignored)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
mutex_owner_init(mdb_walk_state_t * wsp)1552 mutex_owner_init(mdb_walk_state_t *wsp)
1553 {
1554 return (WALK_NEXT);
1555 }
1556
1557 int
mutex_owner_step(mdb_walk_state_t * wsp)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 *
_mdb_init(void)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