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