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
53typedef struct trap_trace_fullrec {
54	struct trap_trace_record ttf_rec;
55	int ttf_cpu;
56} trap_trace_fullrec_t;
57
58#ifdef sun4v
59typedef 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
70static const char NOT[] = "reserved";	/* common reserved string */
71static const char BAD[] = "unused";	/* common unused string */
72
73#define	NOT4	NOT, NOT, NOT, NOT
74#define	BAD4	BAD, BAD, BAD, BAD
75
76static 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};
347static const size_t ttndescr = sizeof (ttdescr) / sizeof (ttdescr[0]);
348
349static GElf_Sym iv_sym;
350
351/*
352 * Persistent data (shouldn't change).
353 */
354static int ncpu;		/* _ncpu */
355static ssize_t mbox_size;	/* size of xc_mbox */
356static ulong_t mbox_stoff;	/* offset of xc_mbox.xc_state */
357static mdb_ctf_id_t mbox_states; /* xc_state enumeration */
358
359static int
360fetch_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
370static int
371fetch_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
405static int
406print_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
426static void
427print_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*/
462static int
463cmd_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*/
512int
513ttctl(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*/
553static int
554ttprint_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*/
631static int
632ttprint_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
657typedef 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
665typedef struct ttrace_walk_data {
666	int tw_ncpu;
667	ttrace_cpu_data_t *tw_cpus;
668} ttrace_walk_data_t;
669
670int
671ttrace_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 != (uintptr_t)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
735int
736ttrace_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
791void
792ttrace_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
800int
801ttrace(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*/
858int
859httctl(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*/
901static int
902httprint_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*/
926static int
927httprint_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
945typedef 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
953typedef struct httrace_walk_data {
954	int tw_ncpu;
955	httrace_cpu_data_t *tw_cpus;
956} httrace_walk_data_t;
957
958int
959httrace_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 != (uintptr_t)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
1024int
1025httrace_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
1081void
1082httrace_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
1090int
1091httrace(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
1135struct {
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*/
1163int
1164xctrace_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*/
1196int
1197xctrace(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 */
1213typedef 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
1221typedef 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
1227static int
1228xc_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
1257static int
1258xc_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
1273static void
1274xc_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
1282static int
1283xc_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
1338typedef 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
1345int
1346vecint_walk_init(mdb_walk_state_t *wsp)
1347{
1348	vecint_walk_data_t	*vecint;
1349
1350	if (wsp->walk_addr != (uintptr_t)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
1373int
1374vecint_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 == (uintptr_t)NULL) {
1382		while ((vecint->vec_idx < max) && ((wsp->walk_addr =
1383		    (uintptr_t)vecint->vec_table[vecint->vec_idx++]) ==
1384		    (uintptr_t)NULL))
1385			continue;
1386	}
1387
1388	if (wsp->walk_addr == (uintptr_t)NULL)
1389		return (WALK_DONE);
1390
1391	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1392	    wsp->walk_cbdata);
1393
1394	if (mdb_vread(&iv, sizeof (intr_vec_t),
1395	    (uintptr_t)wsp->walk_addr) == -1) {
1396		mdb_warn("failed to read iv_p %p\n", wsp->walk_addr);
1397		return (WALK_ERR);
1398	}
1399
1400	wsp->walk_addr = (uintptr_t)iv.iv_vec_next;
1401	return (status);
1402}
1403
1404void
1405vecint_walk_fini(mdb_walk_state_t *wsp)
1406{
1407	vecint_walk_data_t	*vecint = wsp->walk_data;
1408
1409	mdb_free(vecint->vec_table, vecint->vec_size);
1410	mdb_free(vecint, sizeof (vecint_walk_data_t));
1411}
1412
1413int
1414vecint_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1415{
1416	intr_vec_t	iv;
1417
1418	if (!(flags & DCMD_ADDRSPEC)) {
1419		if (mdb_walk_dcmd("vecint", "vecint", argc, argv) == -1) {
1420			mdb_warn("can't walk vecint");
1421			return (DCMD_ERR);
1422		}
1423		return (DCMD_OK);
1424	}
1425
1426	if (DCMD_HDRSPEC(flags)) {
1427		mdb_printf("%4s %?s %4s %?s %?s %s\n", "INUM", "ADDR",
1428		    "PIL", "ARG1", "ARG2", "HANDLER");
1429	}
1430
1431	if (mdb_vread(&iv, sizeof (iv), addr) == -1) {
1432		mdb_warn("couldn't read intr_vec_table at %p", addr);
1433		return (DCMD_ERR);
1434	}
1435
1436	mdb_printf("%4x %?p %4d %?p %?p %a\n", iv.iv_inum, addr,
1437	    iv.iv_pil, iv.iv_arg1, iv.iv_arg2, iv.iv_handler);
1438
1439	return (DCMD_OK);
1440}
1441
1442int
1443softint_walk_init(mdb_walk_state_t *wsp)
1444{
1445	intr_vec_t	*list;
1446
1447	if (wsp->walk_addr != (uintptr_t)NULL) {
1448		mdb_warn("softint walk only supports global walks\n");
1449		return (WALK_ERR);
1450	}
1451
1452	/* Read global softint linked list pointer */
1453	if (mdb_readvar(&list, "softint_list") == -1) {
1454		mdb_warn("failed to read the global softint_list pointer\n");
1455		return (WALK_ERR);
1456	}
1457
1458	wsp->walk_addr = (uintptr_t)list;
1459	return (WALK_NEXT);
1460}
1461
1462/*ARGSUSED*/
1463void
1464softint_walk_fini(mdb_walk_state_t *wsp)
1465{
1466	/* Nothing to do here */
1467}
1468
1469int
1470softint_walk_step(mdb_walk_state_t *wsp)
1471{
1472	intr_vec_t		iv;
1473	int			status;
1474
1475	if (wsp->walk_addr == (uintptr_t)NULL)
1476		return (WALK_DONE);
1477
1478	status = wsp->walk_callback(wsp->walk_addr, wsp->walk_data,
1479	    wsp->walk_cbdata);
1480
1481	if (mdb_vread(&iv, sizeof (intr_vec_t),
1482	    (uintptr_t)wsp->walk_addr) == -1) {
1483		mdb_warn("failed to read iv_p %p\n", wsp->walk_addr);
1484		return (WALK_ERR);
1485	}
1486
1487	wsp->walk_addr = (uintptr_t)iv.iv_vec_next;
1488	return (status);
1489}
1490
1491int
1492softint_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1493{
1494	intr_vec_t	iv;
1495
1496	if (!(flags & DCMD_ADDRSPEC)) {
1497		if (mdb_walk_dcmd("softint", "softint", argc, argv) == -1) {
1498			mdb_warn("can't walk softint");
1499			return (DCMD_ERR);
1500		}
1501		return (DCMD_OK);
1502	}
1503
1504	if (DCMD_HDRSPEC(flags)) {
1505		mdb_printf("%?s %4s %4s %4s %?s %?s %s\n", "ADDR", "TYPE",
1506		    "PEND", "PIL", "ARG1", "ARG2", "HANDLER");
1507	}
1508
1509	if (mdb_vread(&iv, sizeof (iv), addr) == -1) {
1510		mdb_warn("couldn't read softint at %p", addr);
1511		return (DCMD_ERR);
1512	}
1513
1514	mdb_printf("%?p %4s %4d %4d %?p %?p %a\n", addr,
1515	    (iv.iv_flags & IV_SOFTINT_MT) ? "M" : "S",
1516	    iv.iv_flags & IV_SOFTINT_PEND, iv.iv_pil,
1517	    iv.iv_arg1, iv.iv_arg2, iv.iv_handler);
1518
1519	return (DCMD_OK);
1520}
1521
1522static int
1523whatis_walk_tt(uintptr_t taddr, const trap_trace_fullrec_t *ttf,
1524    mdb_whatis_t *w)
1525{
1526	uintptr_t cur = 0;
1527
1528	while (mdb_whatis_match(w, taddr, sizeof (struct trap_trace_record),
1529	    &cur))
1530		mdb_whatis_report_object(w, cur, taddr,
1531		    "trap trace record for cpu %d\n", ttf->ttf_cpu);
1532
1533	return (WHATIS_WALKRET(w));
1534}
1535
1536/*ARGSUSED*/
1537static int
1538whatis_run_traptrace(mdb_whatis_t *w, void *ignored)
1539{
1540	GElf_Sym sym;
1541
1542	if (mdb_lookup_by_name("trap_trace_ctl", &sym) == -1)
1543		return (0);
1544
1545	if (mdb_walk("ttrace", (mdb_walk_cb_t)whatis_walk_tt, w) == -1)
1546		mdb_warn("failed to walk 'ttrace'");
1547
1548	return (0);
1549}
1550
1551/*ARGSUSED*/
1552int
1553mutex_owner_init(mdb_walk_state_t *wsp)
1554{
1555	return (WALK_NEXT);
1556}
1557
1558int
1559mutex_owner_step(mdb_walk_state_t *wsp)
1560{
1561	uintptr_t addr = wsp->walk_addr;
1562	mutex_impl_t mtx;
1563	uintptr_t owner;
1564	kthread_t thr;
1565
1566	if (mdb_vread(&mtx, sizeof (mtx), addr) == -1)
1567		return (WALK_ERR);
1568
1569	if (!MUTEX_TYPE_ADAPTIVE(&mtx))
1570		return (WALK_DONE);
1571
1572	if ((owner = (uintptr_t)MUTEX_OWNER(&mtx)) == (uintptr_t)NULL)
1573		return (WALK_DONE);
1574
1575	if (mdb_vread(&thr, sizeof (thr), owner) != -1)
1576		(void) wsp->walk_callback(owner, &thr, wsp->walk_cbdata);
1577
1578	return (WALK_DONE);
1579}
1580
1581static const mdb_dcmd_t dcmds[] = {
1582	{ "cpuset", ":[-l|-r]", "dump a cpuset_t", cmd_cpuset },
1583	{ "ttctl", NULL, "dump trap trace ctl records", ttctl },
1584	{ "ttrace", "[-x]", "dump trap trace buffer for a cpu", ttrace },
1585#ifdef sun4v
1586	{ "httctl", NULL, "dump hv trap trace ctl records", httctl },
1587	{ "httrace", "[-x]", "dump hv trap trace buffer for a cpu", httrace },
1588#endif
1589	{ "xc_mbox", "?", "dump xcall mboxes", xc_mbox },
1590	{ "xctrace", NULL, "dump xcall trace buffer", xctrace },
1591	{ "vecint", NULL, "display a registered hardware interrupt",
1592	    vecint_dcmd },
1593	{ "softint", NULL, "display a registered software interrupt",
1594	    softint_dcmd },
1595	{ "sfmmu_vtop", ":[[-v] -a as]", "print virtual to physical mapping",
1596	    sfmmu_vtop },
1597	{ "memseg_list", ":", "show memseg list", memseg_list },
1598	{ "tsbinfo", ":[-l [-a]]", "show tsbinfo", tsbinfo_list,
1599	    tsbinfo_help },
1600	{ NULL }
1601};
1602
1603static const mdb_walker_t walkers[] = {
1604	{ "mutex_owner", "walks the owner of a mutex",
1605		mutex_owner_init, mutex_owner_step },
1606	{ "ttrace", "walks the trap trace buffer for a CPU",
1607		ttrace_walk_init, ttrace_walk_step, ttrace_walk_fini },
1608#ifdef sun4v
1609	{ "httrace", "walks the hv trap trace buffer for a CPU",
1610		httrace_walk_init, httrace_walk_step, httrace_walk_fini },
1611#endif
1612	{ "xc_mbox", "walks the cross call mail boxes",
1613		xc_mbox_walk_init, xc_mbox_walk_step, xc_mbox_walk_fini },
1614	{ "vecint", "walk the list of registered hardware interrupts",
1615		vecint_walk_init, vecint_walk_step, vecint_walk_fini },
1616	{ "softint", "walk the list of registered software interrupts",
1617		softint_walk_init, softint_walk_step, softint_walk_fini },
1618	{ "memseg", "walk the memseg structures",
1619		memseg_walk_init, memseg_walk_step, memseg_walk_fini },
1620	{ NULL }
1621};
1622
1623static const mdb_modinfo_t modinfo = { MDB_API_VERSION, dcmds, walkers };
1624
1625const mdb_modinfo_t *
1626_mdb_init(void)
1627{
1628	if (mdb_lookup_by_name("intr_vec_table", &iv_sym) == -1) {
1629		mdb_warn("couldn't find intr_vec_table");
1630		return (NULL);
1631	}
1632
1633	mdb_whatis_register("traptrace", whatis_run_traptrace, NULL,
1634	    WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
1635
1636	return (&modinfo);
1637}
1638