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