xref: /titanic_44/usr/src/cmd/trapstat/sun4/trapstat.c (revision ae115bc77f6fcde83175c75b4206dc2e50747966)
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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <strings.h>
37 #include <limits.h>
38 #include <sys/mman.h>
39 #include <sys/pset.h>
40 #include <sys/varargs.h>
41 #include <sys/trapstat.h>
42 #include <sys/wait.h>
43 #include <stddef.h>
44 #include <termio.h>
45 
46 #define	TSTAT_DEVICE	"/dev/trapstat"
47 #define	TSTAT_COMMAND	"trapstat"
48 #define	TSTAT_DELTA(data, old, member) g_absolute ? (data)->member : \
49 	(uint64_t)(0.5 + (g_interval / (double)((data)->tdata_snapts - \
50 	(old)->tdata_snapts)) * (double)((data)->member - (old)->member))
51 
52 #define	TSTAT_PRINT_MISSDATA(diff, time) \
53 	(void) printf(" %9lld %4.1f", (diff), (time));
54 
55 #define	TSTAT_PAGESIZE_MODIFIERS	" kmgtp"
56 #define	TSTAT_PAGESIZE_STRLEN		10
57 #define	TSTAT_MAX_RATE			5000
58 #define	TSTAT_COLUMN_OFFS	26
59 #define	TSTAT_COLUMNS_PER_CPU	9
60 
61 static tstat_data_t *g_data[2];
62 static tstat_data_t *g_ndata, *g_odata;
63 static processorid_t g_max_cpus;
64 static int8_t *g_selected;
65 static timer_t g_tid;
66 static int g_interval = NANOSEC;
67 static int g_peffect = 1;
68 static int g_absolute = 0;
69 static sigset_t g_oset;
70 
71 static psetid_t g_pset = PS_NONE;
72 static processorid_t *g_pset_cpus;
73 static uint_t g_pset_ncpus;
74 
75 static int g_cpus_per_line = (80 - TSTAT_COLUMN_OFFS) / TSTAT_COLUMNS_PER_CPU;
76 static int g_winch;
77 
78 static int g_pgsizes;
79 static size_t *g_pgsize;
80 static char **g_pgnames;
81 static size_t g_datasize;
82 
83 static int g_gen;
84 static int g_fd;
85 static uint8_t g_active[TSTAT_NENT];
86 
87 static hrtime_t g_start;
88 
89 static int g_exec_errno;
90 static int g_child_exited;
91 static int g_child_status;
92 
93 static void (*g_process)(void *, uint64_t, double);
94 static void *g_arg;
95 
96 typedef struct tstat_sum {
97 	uint64_t	tsum_diff;
98 	double		tsum_time;
99 } tstat_sum_t;
100 
101 #define	TSTAT_ENT_USED			0
102 #define	TSTAT_ENT_RESERVED		1
103 #define	TSTAT_ENT_UNUSED		2
104 #define	TSTAT_ENT_CONTINUED		3
105 
106 typedef struct tstat_ent {
107 	char *tent_name;
108 	char *tent_descr;
109 	int tent_type;
110 } tstat_ent_t;
111 
112 static tstat_ent_t g_traps[] = {
113 #ifndef	sun4v
114 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
115 	{ "power-on", 		"power on reset" },
116 	{ "watchdog", 		"watchdog reset" },
117 	{ "xir", 		"externally initiated reset" },
118 	{ "sir", 		"software initiated reset" },
119 	{ "red", 		"RED state exception" },
120 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
121 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
122 	{ "immu-xcp", 		"instruction access exception" },
123 	{ "immu-miss", 		"instruction access MMU miss" },
124 	{ "immu-err", 		"instruction access error" },
125 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
126 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
127 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
128 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
129 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
130 	{ "ill-inst", 		"illegal instruction" },
131 	{ "priv-inst", 		"privileged opcode" },
132 	{ "unimp-ldd", 		"unimplemented LDD" },
133 	{ "unimp-std", 		"unimplemented STD" },
134 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
135 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
136 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
137 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
138 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
139 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
140 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
141 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
142 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
143 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
144 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
145 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
146 	{ "fp-disabled", 	"fp disabled" },
147 	{ "fp-ieee754", 	"fp exception ieee754" },
148 	{ "fp-xcp-other", 	"fp exception other" },
149 	{ "tag-oflow", 		"tag overflow" },
150 	{ "cleanwin", 		"clean window" },
151 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
152 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
153 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
154 	{ "div-zero", 		"division by zero" },
155 	{ "internal-err", 	"internal processor error" },
156 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
157 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
158 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
159 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
160 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
161 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
162 	{ "dmmu-xcp", 		"data access exception" },
163 	{ "dmmu-miss", 		"data access MMU miss" },
164 	{ "dmmu-err", 		"data access error" },
165 	{ "dmmu-prot", 		"data access protection" },
166 	{ "unalign", 		"mem address not aligned" },
167 	{ "lddf-unalign", 	"LDDF mem address not aligned" },
168 	{ "stdf-unalign", 	"STDF mem address not aligned" },
169 	{ "priv-act", 		"privileged action" },
170 	{ "ldqf-unalign",	"LDQF mem address not aligned" },
171 	{ "stqf-unalign", 	"STQF mem address not aligned" },
172 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
173 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
174 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
175 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
176 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
177 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
178 	{ "async-d-err", 	"async data error" },
179 	{ "level-1", 		"interrupt level 1" },
180 	{ "level-2", 		"interrupt level 2" },
181 	{ "level-3", 		"interrupt level 3" },
182 	{ "level-4", 		"interrupt level 4" },
183 	{ "level-5", 		"interrupt level 5" },
184 	{ "level-6", 		"interrupt level 6" },
185 	{ "level-7", 		"interrupt level 7" },
186 	{ "level-8", 		"interrupt level 8" },
187 	{ "level-9", 		"interrupt level 9" },
188 	{ "level-10", 		"interrupt level 10" },
189 	{ "level-11", 		"interrupt level 11" },
190 	{ "level-12", 		"interrupt level 12" },
191 	{ "level-13", 		"interrupt level 13" },
192 	{ "level-14", 		"interrupt level 14" },
193 	{ "level-15", 		"interrupt level 15" },
194 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
195 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
196 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
197 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
198 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
199 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
200 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
201 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
202 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
203 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
204 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
205 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
206 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
207 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
208 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
209 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
210 	{ "int-vec", 		"interrupt vector" },
211 	{ "pa-watch", 		"PA watchpoint" },
212 	{ "va-watch", 		"VA watchpoint" },
213 	{ "ecc-err", 		"corrected ECC error" },
214 	{ "itlb-miss", 		"instruction access MMU miss" },
215 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
216 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
217 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
218 	{ "dtlb-miss", 		"data access MMU miss" },
219 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
220 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
221 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
222 	{ "dtlb-prot", 		"data access protection" },
223 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
224 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
225 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
226 	{ "fast-ecc",		"fast ECC error" },
227 	{ "dcache-parity",	"D-cache parity error" },
228 	{ "icache-parity",	"I-cache parity error" },
229 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
230 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
231 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
232 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
233 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
234 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
235 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
236 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
237 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
238 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
239 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
240 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
241 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
242 #else /* sun4v */
243 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
244 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
245 	{ "watchdog", 		"watchdog reset" },
246 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
247 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
248 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
249 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
250 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
251 	{ "immu-xcp", 		"instruction access exception" },
252 	{ "immu-miss", 		"instruction access MMU miss" },
253 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
254 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
255 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
256 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
257 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
258 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
259 	{ "ill-inst", 		"illegal instruction" },
260 	{ "priv-inst", 		"privileged opcode" },
261 	{ "unimp-ldd", 		"unimplemented LDD" },
262 	{ "unimp-std", 		"unimplemented STD" },
263 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
264 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
265 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
266 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
267 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
268 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
269 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
270 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
271 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
272 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
273 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
274 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
275 	{ "fp-disabled", 	"fp disabled" },
276 	{ "fp-ieee754", 	"fp exception ieee754" },
277 	{ "fp-xcp-other", 	"fp exception other" },
278 	{ "tag-oflow", 		"tag overflow" },
279 	{ "cleanwin", 		"clean window" },
280 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
281 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
282 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
283 	{ "div-zero", 		"division by zero" },
284 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
285 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
286 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
287 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
288 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
289 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
290 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
291 	{ "dmmu-xcp", 		"data access exception" },
292 	{ "dmmu-miss", 		"data access MMU miss" },
293 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
294 	{ "dmmu-prot", 		"data access protection" },
295 	{ "unalign", 		"mem address not aligned" },
296 	{ "lddf-unalign", 	"LDDF mem address not aligned" },
297 	{ "stdf-unalign", 	"STDF mem address not aligned" },
298 	{ "priv-act", 		"privileged action" },
299 	{ "ldqf-unalign",	"LDQF mem address not aligned" },
300 	{ "stqf-unalign", 	"STQF mem address not aligned" },
301 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
302 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
303 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
304 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
305 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
306 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
307 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
308 	{ "level-1", 		"interrupt level 1" },
309 	{ "level-2", 		"interrupt level 2" },
310 	{ "level-3", 		"interrupt level 3" },
311 	{ "level-4", 		"interrupt level 4" },
312 	{ "level-5", 		"interrupt level 5" },
313 	{ "level-6", 		"interrupt level 6" },
314 	{ "level-7", 		"interrupt level 7" },
315 	{ "level-8", 		"interrupt level 8" },
316 	{ "level-9", 		"interrupt level 9" },
317 	{ "level-10", 		"interrupt level 10" },
318 	{ "level-11", 		"interrupt level 11" },
319 	{ "level-12", 		"interrupt level 12" },
320 	{ "level-13", 		"interrupt level 13" },
321 	{ "level-14", 		"interrupt level 14" },
322 	{ "level-15", 		"interrupt level 15" },
323 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
324 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
325 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
326 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
327 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
328 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
329 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
330 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
331 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
332 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
333 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
334 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
335 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
336 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
337 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
338 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
339 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
340 	{ "pa-watch", 		"PA watchpoint" },
341 	{ "va-watch", 		"VA watchpoint" },
342 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
343 	{ "itlb-miss", 		"instruction access MMU miss" },
344 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
345 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
346 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
347 	{ "dtlb-miss", 		"data access MMU miss" },
348 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
349 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
350 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
351 	{ "dtlb-prot", 		"data access protection" },
352 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
353 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
354 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
355 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
356 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
357 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
358 	{ "ctl-xfer",		"control transfer" },
359 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
360 	{ "instr-brkpt",	"instruction breakpoint" },
361 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
362 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
363 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
364 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
365 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
366 	{ "hw-changed", 	"hardware changed" },
367 	{ "cpu_mondo", 		"cpu mondo trap" },
368 	{ "dev_mondo", 		"device mondo trap" },
369 	{ "res-err", 		"resumable error" },
370 	{ "nonres-err",		"non-resumable error" },
371 #endif /* sun4v */
372 	{ "spill-0-normal", 	"spill 0 normal" },
373 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
374 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
375 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
376 	{ "spill-user-32", 	"spill user window, 32-bit" },
377 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
378 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
379 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
380 	{ "spill-user-64", 	"spill user window, 64-bit" },
381 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
382 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
383 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
384 	{ "spill-user-32-cln", 	"spill, clean user window, 32-bit" },
385 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
386 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
387 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
388 	{ "spill-user-64-cln", 	"spill, clean user window, 64-bit" },
389 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
390 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
391 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
392 	{ "spill-kern-32", 	"spill kernel window, 32-bit" },
393 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
394 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
395 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
396 	{ "spill-kern-64", 	"spill kernel window, 64-bit" },
397 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
398 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
399 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
400 	{ "spill-mixed", 	"spill window, mixed 32-bit/64-bit" },
401 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
402 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
403 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
404 	{ "spill-0-other", 	"spill 0 other" },
405 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
406 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
407 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
408 	{ "spill-asuser-32", 	"spill user window as kernel, 32-bit" },
409 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
410 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
411 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
412 	{ "spill-asuser-64", 	"spill user window as kernel, 64-bit" },
413 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
414 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
415 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
416 	{ "spill-asuser-32-cln", "spill, clean user window as kernel, 32-bit" },
417 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
418 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
419 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
420 	{ "spill-asuser-64-cln", "spill, clean user window as kernel, 64-bit" },
421 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
422 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
423 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
424 	{ "spill-5-other", 	"spill 5 other" },
425 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
426 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
427 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
428 	{ "spill-6-other", 	"spill 6 other" },
429 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
430 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
431 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
432 	{ "spill-7-other", 	"spill 7 other" },
433 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
434 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
435 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
436 	{ "fill-0-normal", 	"fill 0 normal" },
437 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
438 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
439 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
440 	{ "fill-user-32", 	"fill user window, 32-bit" },
441 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
442 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
443 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
444 	{ "fill-user-64", 	"fill user window, 64-bit" },
445 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
446 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
447 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
448 	{ "fill-user-32-cln", 	"fill user window, 32-bit" },
449 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
450 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
451 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
452 	{ "fill-user-64-cln", 	"fill user window, 64-bit" },
453 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
454 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
455 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
456 	{ "fill-kern-32", 	"fill kernel window, 32-bit" },
457 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
458 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
459 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
460 	{ "fill-kern-64", 	"fill kernel window, 64-bit" },
461 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
462 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
463 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
464 	{ "fill-mixed", 	"fill window, mixed 32-bit/64-bit" },
465 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
466 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
467 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
468 	{ "fill-0-other", 	"fill 0 other" },
469 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
470 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
471 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
472 	{ "fill-asuser-32", 	"fill user window as kernel, 32-bit" },
473 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
474 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
475 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
476 	{ "fill-asuser-64", 	"fill user window as kernel, 64-bit" },
477 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
478 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
479 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
480 	{ "fill-asuser-32-cln", "fill user window as kernel, 32-bit" },
481 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
482 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
483 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
484 	{ "fill-asuser-64-cln",	"fill user window as kernel, 64-bit" },
485 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
486 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
487 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
488 	{ "fill-5-other", 	"fill 5 other" },
489 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
490 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
491 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
492 	{ "fill-6-other", 	"fill 6 other" },
493 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
494 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
495 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
496 	{ "fill-7-other", 	"fill 7 other" },
497 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
498 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
499 	{ NULL, NULL,		TSTAT_ENT_CONTINUED },
500 	{ "syscall-4x", 	"old system call" },
501 	{ "usr-brkpt", 		"user breakpoint" },
502 	{ "usr-div-zero", 	"user divide by zero" },
503 	{ "flush-wins", 	"flush windows" },
504 	{ "clean-wins", 	"clean windows" },
505 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
506 	{ "fix-align", 		"fix unaligned references" },
507 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
508 	{ "syscall-32", 	"ILP32 system call" },
509 	{ "set-t0-addr", 	"set trap0 address" },
510 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
511 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
512 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
513 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
514 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
515 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
516 	{ "trap-inst-16", 	"trap instruction 16", },
517 	{ "trap-inst-17", 	"trap instruction 17", },
518 	{ "trap-inst-18", 	"trap instruction 18", },
519 	{ "trap-inst-19", 	"trap instruction 19", },
520 	{ "trap-inst-20", 	"trap instruction 20", },
521 	{ "trap-inst-21", 	"trap instruction 21", },
522 	{ "trap-inst-22", 	"trap instruction 22", },
523 	{ "trap-inst-23", 	"trap instruction 23", },
524 	{ "trap-inst-24", 	"trap instruction 24", },
525 	{ "trap-inst-25", 	"trap instruction 25", },
526 	{ "trap-inst-26", 	"trap instruction 26", },
527 	{ "trap-inst-27", 	"trap instruction 27", },
528 	{ "trap-inst-28", 	"trap instruction 28", },
529 	{ "trap-inst-29", 	"trap instruction 29", },
530 	{ "trap-inst-30", 	"trap instruction 30", },
531 	{ "trap-inst-31", 	"trap instruction 31", },
532 	{ "get-cc", 		"get condition codes" },
533 	{ "set-cc", 		"set condition codes" },
534 	{ "get-psr", 		"get psr" },
535 	{ "set-psr", 		"set psr (some fields)" },
536 	{ "getts", 		"get timestamp" },
537 	{ "gethrvtime", 	"get lwp virtual time" },
538 	{ "self-xcall", 	"self xcall" },
539 	{ "gethrtime", 		"get hrestime" },
540 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
541 	{ "getlgrp",		"get lgrpid" },
542 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
543 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
544 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
545 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
546 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
547 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
548 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
549 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
550 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
551 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
552 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
553 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
554 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
555 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
556 	{ "dtrace-pid",		"DTrace pid provider" },
557 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
558 	{ "dtrace-return",	"DTrace pid provider return" },
559 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
560 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
561 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
562 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
563 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
564 	{ "syscall-64", 	"LP64 system call" },
565 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
566 	{ "tt-freeze", 		"freeze traptrace" },
567 	{ "tt-unfreeze", 	"unfreeze traptrace" },
568 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
569 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
570 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
571 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
572 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
573 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
574 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
575 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
576 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
577 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
578 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
579 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
580 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
581 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
582 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
583 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
584 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
585 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
586 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
587 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
588 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
589 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
590 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
591 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
592 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
593 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
594 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
595 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
596 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
597 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
598 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
599 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
600 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
601 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
602 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
603 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
604 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
605 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
606 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
607 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
608 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
609 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
610 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
611 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
612 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
613 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
614 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
615 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
616 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
617 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
618 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
619 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
620 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
621 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
622 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
623 	{ NULL, NULL,		TSTAT_ENT_UNUSED },
624 	{ "ptl1-panic", 	"test ptl1-panic" },
625 	{ "kmdb-enter", 	"kmdb enter (L1-A)" },
626 	{ "kmdb-brkpt", 	"kmdb breakpoint" },
627 	{ "obp-brkpt", 		"obp breakpoint" },
628 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
629 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
630 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
631 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
632 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
633 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
634 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
635 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
636 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
637 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
638 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
639 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
640 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
641 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
642 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
643 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
644 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
645 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
646 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
647 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
648 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
649 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
650 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
651 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
652 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
653 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
654 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
655 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
656 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
657 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
658 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
659 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
660 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
661 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
662 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
663 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
664 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
665 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
666 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
667 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
668 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
669 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
670 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
671 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
672 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
673 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
674 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
675 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
676 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
677 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
678 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
679 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
680 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
681 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
682 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
683 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
684 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
685 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
686 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
687 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
688 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
689 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
690 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
691 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
692 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
693 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
694 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
695 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
696 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
697 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
698 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
699 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
700 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
701 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
702 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
703 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
704 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
705 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
706 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
707 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
708 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
709 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
710 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
711 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
712 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
713 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
714 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
715 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
716 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
717 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
718 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
719 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
720 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
721 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
722 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
723 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
724 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
725 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
726 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
727 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
728 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
729 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
730 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
731 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
732 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
733 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
734 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
735 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
736 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
737 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
738 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
739 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
740 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
741 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
742 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
743 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
744 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
745 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
746 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
747 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
748 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
749 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
750 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
751 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
752 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
753 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
754 	{ NULL, NULL,		TSTAT_ENT_RESERVED },
755 	{ NULL, NULL,		TSTAT_ENT_RESERVED }
756 };
757 
758 static void
759 usage(void)
760 {
761 	(void) fprintf(stderr,
762 	    "\nusage:  trapstat [ -t | -T | -e entrylist ]\n"
763 	    "   [ -C psrset | -c cpulist ]\n"
764 	    "   [ -P ] [ -a ] [ -r rate ] [[ interval [ count ] ] | "
765 	    "command [ args ] ]\n\n"
766 	    "Trap selection options:\n\n"
767 	    " -t             TLB statistics\n"
768 	    " -T             TLB statistics, with pagesize information\n"
769 	    " -e entrylist   Enable statistics only for entries specified "
770 	    "by entrylist\n\n"
771 	    "CPU selection options:\n\n"
772 	    " -c cpulist     Enable statistics only for specified CPU list\n"
773 	    " -C psrset      Enable statistics only for specified processor "
774 	    "set\n\n"
775 	    "Other options:\n\n"
776 	    " -a             Display trap values as accumulating values "
777 	    "instead of rates\n"
778 	    " -l             List trap table entries and exit\n"
779 	    " -P             Display output in parsable format\n"
780 	    " -r hz          Set sampling rate to be hz samples "
781 	    "per second\n\n");
782 
783 	exit(EXIT_FAILURE);
784 }
785 
786 static void
787 fatal(char *fmt, ...)
788 {
789 	va_list ap;
790 	int error = errno;
791 
792 	va_start(ap, fmt);
793 
794 	(void) fprintf(stderr, TSTAT_COMMAND ": ");
795 	(void) vfprintf(stderr, fmt, ap);
796 
797 	if (fmt[strlen(fmt) - 1] != '\n')
798 		(void) fprintf(stderr, ": %s\n", strerror(error));
799 
800 	exit(EXIT_FAILURE);
801 }
802 
803 static void
804 set_width(void)
805 {
806 	struct winsize win;
807 
808 	if (!isatty(fileno(stdout)))
809 		return;
810 
811 	if (ioctl(fileno(stdout), TIOCGWINSZ, &win) == -1)
812 		return;
813 
814 	if (win.ws_col == 0) {
815 		/*
816 		 * If TIOCGWINSZ returned 0 for the columns, just return --
817 		 * thereby using the default value of g_cpus_per_line.  (This
818 		 * happens, e.g., when running over a tip line.)
819 		 */
820 		return;
821 	}
822 
823 	g_cpus_per_line = (win.ws_col - TSTAT_COLUMN_OFFS) /
824 	    TSTAT_COLUMNS_PER_CPU;
825 
826 	if (g_cpus_per_line < 1)
827 		g_cpus_per_line = 1;
828 }
829 
830 static void
831 intr(int signo)
832 {
833 	int error = errno;
834 
835 	switch (signo) {
836 	case SIGWINCH:
837 		g_winch = 1;
838 		set_width();
839 		break;
840 
841 	case SIGCHLD:
842 		g_child_exited = 1;
843 
844 		while (wait(&g_child_status) == -1 && errno == EINTR)
845 			continue;
846 		break;
847 
848 	default:
849 		break;
850 	}
851 
852 	errno = error;
853 }
854 
855 static void
856 setup(void)
857 {
858 	struct sigaction act;
859 	struct sigevent ev;
860 	sigset_t set;
861 	int i;
862 
863 	for (i = 0; i < TSTAT_NENT; i++) {
864 		if (g_traps[i].tent_type == TSTAT_ENT_RESERVED)
865 			g_traps[i].tent_name = "reserved";
866 
867 		if (g_traps[i].tent_type == TSTAT_ENT_UNUSED)
868 			g_traps[i].tent_name = "unused";
869 	}
870 
871 	g_max_cpus = (processorid_t)sysconf(_SC_CPUID_MAX) + 1;
872 
873 	if ((g_selected = malloc(sizeof (int8_t) * g_max_cpus)) == NULL)
874 		fatal("could not allocate g_selected");
875 
876 	bzero(g_selected, sizeof (int8_t) * g_max_cpus);
877 
878 	g_pset_cpus = malloc(sizeof (processorid_t) * g_max_cpus);
879 	if (g_pset_cpus == NULL)
880 		fatal("could not allocate g_pset_cpus");
881 
882 	bzero(g_pset_cpus, sizeof (processorid_t) * g_max_cpus);
883 
884 	if ((g_pgsizes = getpagesizes(NULL, 0)) == -1)
885 		fatal("getpagesizes()");
886 
887 	if ((g_pgsize = malloc(sizeof (size_t) * g_pgsizes)) == NULL)
888 		fatal("could not allocate g_pgsize array");
889 
890 	if (getpagesizes(g_pgsize, g_pgsizes) == -1)
891 		fatal("getpagesizes(%d)", g_pgsizes);
892 
893 	if ((g_pgnames = malloc(sizeof (char *) * g_pgsizes)) == NULL)
894 		fatal("could not allocate g_pgnames");
895 
896 	for (i = 0; i < g_pgsizes; i++) {
897 		size_t j, mul;
898 		size_t sz = g_pgsize[i];
899 
900 		if ((g_pgnames[i] = malloc(TSTAT_PAGESIZE_STRLEN)) == NULL)
901 			fatal("could not allocate g_pgnames[%d]", i);
902 
903 		for (j = 0, mul = 10; (1 << mul) <= sz; j++, mul += 10)
904 			continue;
905 
906 		(void) snprintf(g_pgnames[i], TSTAT_PAGESIZE_STRLEN,
907 		    "%d%c", sz >> (mul - 10), " kmgtpe"[j]);
908 	}
909 
910 	g_datasize =
911 	    sizeof (tstat_data_t) + (g_pgsizes - 1) * sizeof (tstat_pgszdata_t);
912 
913 	if ((g_data[0] = malloc(g_datasize * g_max_cpus)) == NULL)
914 		fatal("could not allocate data buffer 0");
915 
916 	if ((g_data[1] = malloc(g_datasize * g_max_cpus)) == NULL)
917 		fatal("could not allocate data buffer 1");
918 
919 	(void) sigemptyset(&act.sa_mask);
920 	act.sa_flags = 0;
921 	act.sa_handler = intr;
922 	(void) sigaction(SIGUSR1, &act, NULL);
923 	(void) sigaction(SIGCHLD, &act, NULL);
924 
925 	(void) sigaddset(&act.sa_mask, SIGCHLD);
926 	(void) sigaddset(&act.sa_mask, SIGUSR1);
927 	(void) sigaction(SIGWINCH, &act, NULL);
928 	set_width();
929 
930 	(void) sigemptyset(&set);
931 	(void) sigaddset(&set, SIGCHLD);
932 	(void) sigaddset(&set, SIGUSR1);
933 	(void) sigaddset(&set, SIGWINCH);
934 	(void) sigprocmask(SIG_BLOCK, &set, &g_oset);
935 
936 	ev.sigev_notify = SIGEV_SIGNAL;
937 	ev.sigev_signo = SIGUSR1;
938 
939 	if (timer_create(CLOCK_HIGHRES, &ev, &g_tid) == -1)
940 		fatal("cannot create CLOCK_HIGHRES timer");
941 }
942 
943 static void
944 set_interval(hrtime_t nsec)
945 {
946 	struct itimerspec ts;
947 
948 	/*
949 	 * If the interval is less than one second, we'll report the
950 	 * numbers in terms of rate-per-interval.  If the interval is
951 	 * greater than one second, we'll report numbers in terms of
952 	 * rate-per-second.
953 	 */
954 	g_interval = nsec < NANOSEC ? nsec : NANOSEC;
955 
956 	ts.it_value.tv_sec = nsec / NANOSEC;
957 	ts.it_value.tv_nsec = nsec % NANOSEC;
958 	ts.it_interval.tv_sec = nsec / NANOSEC;
959 	ts.it_interval.tv_nsec = nsec % NANOSEC;
960 
961 	if (timer_settime(g_tid, TIMER_RELTIME, &ts, NULL) == -1)
962 		fatal("cannot set time on CLOCK_HIGHRES timer");
963 }
964 
965 static void
966 print_entries(FILE *stream, int parsable)
967 {
968 	int entno;
969 
970 	if (!parsable) {
971 		(void) fprintf(stream, "  %3s %3s | %-20s | %s\n", "hex",
972 		    "dec", "entry name", "description");
973 
974 		(void) fprintf(stream, "----------+----------------------"
975 		    "+-----------------------\n");
976 	}
977 
978 	for (entno = 0; entno < TSTAT_NENT; entno++) {
979 		if (g_traps[entno].tent_type != TSTAT_ENT_USED)
980 			continue;
981 
982 		(void) fprintf(stream, "0x%03x %3d %s%-20s %s%s\n",
983 		    entno, entno,
984 		    parsable ? "" : "| ", g_traps[entno].tent_name,
985 		    parsable ? "" : "| ", g_traps[entno].tent_descr);
986 	}
987 }
988 
989 static void
990 select_entry(char *entry)
991 {
992 	ulong_t entno;
993 	char *end;
994 
995 	/*
996 	 * The entry may be specified as a number (e.g., "0x68", "104") or
997 	 * as a name ("dtlb-miss").
998 	 */
999 	entno = strtoul(entry, &end, 0);
1000 
1001 	if (*end == '\0') {
1002 		if (entno >= TSTAT_NENT)
1003 			goto bad_entry;
1004 	} else {
1005 		for (entno = 0; entno < TSTAT_NENT; entno++) {
1006 			if (g_traps[entno].tent_type != TSTAT_ENT_USED)
1007 				continue;
1008 
1009 			if (strcmp(entry, g_traps[entno].tent_name) == 0)
1010 				break;
1011 		}
1012 
1013 		if (entno == TSTAT_NENT)
1014 			goto bad_entry;
1015 	}
1016 
1017 	if (ioctl(g_fd, TSTATIOC_ENTRY, entno) == -1)
1018 		fatal("TSTATIOC_ENTRY failed for entry 0x%x", entno);
1019 
1020 	g_active[entno] = 1;
1021 	return;
1022 
1023 bad_entry:
1024 	(void) fprintf(stderr, TSTAT_COMMAND ": invalid entry '%s'", entry);
1025 	(void) fprintf(stderr, "; valid entries:\n\n");
1026 	print_entries(stderr, 0);
1027 	exit(EXIT_FAILURE);
1028 }
1029 
1030 static void
1031 select_cpu(processorid_t cpu)
1032 {
1033 	if (g_pset != PS_NONE)
1034 		fatal("cannot specify both a processor set and a processor\n");
1035 
1036 	if (cpu < 0 || cpu >= g_max_cpus)
1037 		fatal("cpu %d out of range\n", cpu);
1038 
1039 	if (p_online(cpu, P_STATUS) == -1) {
1040 		if (errno != EINVAL)
1041 			fatal("could not get status for cpu %d", cpu);
1042 		fatal("cpu %d not present\n", cpu);
1043 	}
1044 
1045 	g_selected[cpu] = 1;
1046 }
1047 
1048 static void
1049 select_cpus(processorid_t low, processorid_t high)
1050 {
1051 	if (g_pset != PS_NONE)
1052 		fatal("cannot specify both a processor set and processors\n");
1053 
1054 	if (low < 0 || low >= g_max_cpus)
1055 		fatal("invalid cpu '%d'\n", low);
1056 
1057 	if (high < 0 || high >= g_max_cpus)
1058 		fatal("invalid cpu '%d'\n", high);
1059 
1060 	if (low >= high)
1061 		fatal("invalid range '%d' to '%d'\n", low, high);
1062 
1063 	do {
1064 		if (p_online(low, P_STATUS) != -1)
1065 			g_selected[low] = 1;
1066 	} while (++low <= high);
1067 }
1068 
1069 static void
1070 select_pset(psetid_t pset)
1071 {
1072 	processorid_t i;
1073 
1074 	if (pset < 0)
1075 		fatal("processor set %d is out of range\n", pset);
1076 
1077 	/*
1078 	 * Only one processor set can be specified.
1079 	 */
1080 	if (g_pset != PS_NONE)
1081 		fatal("at most one processor set may be specified\n");
1082 
1083 	/*
1084 	 * One cannot select processors _and_ a processor set.
1085 	 */
1086 	for (i = 0; i < g_max_cpus; i++)
1087 		if (g_selected[i])
1088 			break;
1089 
1090 	if (i != g_max_cpus)
1091 		fatal("cannot specify both a processor and a processor set\n");
1092 
1093 	g_pset = pset;
1094 	g_pset_ncpus = g_max_cpus;
1095 
1096 	if (pset_info(g_pset, NULL, &g_pset_ncpus, g_pset_cpus) == -1)
1097 		fatal("invalid processor set: %d\n", g_pset);
1098 
1099 	if (g_pset_ncpus == 0)
1100 		fatal("processor set %d empty\n", g_pset);
1101 
1102 	if (ioctl(g_fd, TSTATIOC_NOCPU) == -1)
1103 		fatal("TSTATIOC_NOCPU failed");
1104 
1105 	for (i = 0; i < g_pset_ncpus; i++)
1106 		g_selected[g_pset_cpus[i]] = 1;
1107 }
1108 
1109 static void
1110 check_pset(void)
1111 {
1112 	uint_t ncpus = g_max_cpus;
1113 	processorid_t i;
1114 
1115 	if (g_pset == PS_NONE)
1116 		return;
1117 
1118 	if (pset_info(g_pset, NULL, &ncpus, g_pset_cpus) == -1) {
1119 		if (errno == EINVAL)
1120 			fatal("processor set %d destroyed\n", g_pset);
1121 
1122 		fatal("couldn't get info for processor set %d", g_pset);
1123 	}
1124 
1125 	if (ncpus == 0)
1126 		fatal("processor set %d empty\n", g_pset);
1127 
1128 	if (ncpus == g_pset_ncpus) {
1129 		for (i = 0; i < g_pset_ncpus; i++) {
1130 			if (!g_selected[g_pset_cpus[i]])
1131 				break;
1132 		}
1133 
1134 		/*
1135 		 * If the number of CPUs hasn't changed, and every CPU
1136 		 * in the processor set is also selected, we know that the
1137 		 * processor set itself hasn't changed.
1138 		 */
1139 		if (i == g_pset_ncpus)
1140 			return;
1141 	}
1142 
1143 	/*
1144 	 * If we're here, we have a new processor set.  First, we need
1145 	 * to zero out the selection array.
1146 	 */
1147 	bzero(g_selected, sizeof (int8_t) * g_max_cpus);
1148 
1149 	g_pset_ncpus = ncpus;
1150 
1151 	if (ioctl(g_fd, TSTATIOC_STOP) == -1)
1152 		fatal("TSTATIOC_STOP failed");
1153 
1154 	if (ioctl(g_fd, TSTATIOC_NOCPU) == -1)
1155 		fatal("TSATIOC_NOCPU failed");
1156 
1157 	for (i = 0; i < g_pset_ncpus; i++) {
1158 		g_selected[g_pset_cpus[i]] = 1;
1159 		if (ioctl(g_fd, TSTATIOC_CPU, g_pset_cpus[i]) == -1)
1160 			fatal("TSTATIOC_CPU failed for cpu %d", i);
1161 	}
1162 
1163 	/*
1164 	 * Now that we have selected the CPUs, we're going to reenable
1165 	 * trapstat, and reread the data for the current generation.
1166 	 */
1167 	if (ioctl(g_fd, TSTATIOC_GO) == -1)
1168 		fatal("TSTATIOC_GO failed");
1169 
1170 	if (ioctl(g_fd, TSTATIOC_READ, g_data[g_gen]) == -1)
1171 		fatal("TSTATIOC_READ failed");
1172 }
1173 
1174 static void
1175 missdata(tstat_missdata_t *miss, tstat_missdata_t *omiss)
1176 {
1177 	hrtime_t ts = g_ndata->tdata_snapts - g_odata->tdata_snapts;
1178 	hrtime_t tick = g_ndata->tdata_snaptick - g_odata->tdata_snaptick;
1179 	uint64_t raw = miss->tmiss_count - omiss->tmiss_count;
1180 	uint64_t diff = g_absolute ? miss->tmiss_count :
1181 	    (uint64_t)(0.5 + g_interval /
1182 	    (double)ts * (double)(miss->tmiss_count - omiss->tmiss_count));
1183 	hrtime_t peffect = raw * g_ndata->tdata_peffect * g_peffect, time;
1184 	double p;
1185 
1186 	/*
1187 	 * Now we need to account for the trapstat probe effect.  Take
1188 	 * the amount of time spent in the handler, and add the
1189 	 * amount of time known to be due to the trapstat probe effect.
1190 	 */
1191 	time = miss->tmiss_time - omiss->tmiss_time + peffect;
1192 
1193 	if (time >= tick) {
1194 		/*
1195 		 * This really shouldn't happen unless our calculation of
1196 		 * the probe effect was vastly incorrect.  In any case,
1197 		 * print 99.9 for the time instead of printing negative
1198 		 * values...
1199 		 */
1200 		time = tick / 1000 * 999;
1201 	}
1202 
1203 	p = (double)time / (double)tick * (double)100.0;
1204 
1205 	(*g_process)(g_arg, diff, p);
1206 }
1207 
1208 static void
1209 tlbdata(tstat_tlbdata_t *tlb, tstat_tlbdata_t *otlb)
1210 {
1211 	missdata(&tlb->ttlb_tlb, &otlb->ttlb_tlb);
1212 	missdata(&tlb->ttlb_tsb, &otlb->ttlb_tsb);
1213 }
1214 
1215 static void
1216 print_missdata(double *ttl, uint64_t diff, double p)
1217 {
1218 	TSTAT_PRINT_MISSDATA(diff, p);
1219 
1220 	if (ttl != NULL)
1221 		*ttl += p;
1222 }
1223 
1224 static void
1225 print_modepgsz(char *prefix, tstat_modedata_t *data, tstat_modedata_t *odata)
1226 {
1227 	int ps;
1228 	size_t incr = sizeof (tstat_pgszdata_t);
1229 
1230 	for (ps = 0; ps < g_pgsizes; ps++) {
1231 		double ttl = 0.0;
1232 
1233 		g_process = (void(*)(void *, uint64_t, double))print_missdata;
1234 		g_arg = &ttl;
1235 
1236 		(void) printf("%s %4s|", prefix, g_pgnames[ps]);
1237 		tlbdata(&data->tmode_itlb, &odata->tmode_itlb);
1238 		(void) printf(" |");
1239 		tlbdata(&data->tmode_dtlb, &odata->tmode_dtlb);
1240 
1241 		(void) printf(" |%4.1f\n", ttl);
1242 
1243 		data = (tstat_modedata_t *)((uintptr_t)data + incr);
1244 		odata = (tstat_modedata_t *)((uintptr_t)odata + incr);
1245 	}
1246 }
1247 
1248 static void
1249 parsable_modepgsz(char *prefix, tstat_modedata_t *data, tstat_modedata_t *odata)
1250 {
1251 	int ps;
1252 	size_t incr = sizeof (tstat_pgszdata_t);
1253 
1254 	g_process = (void(*)(void *, uint64_t, double))print_missdata;
1255 	g_arg = NULL;
1256 
1257 	for (ps = 0; ps < g_pgsizes; ps++) {
1258 		(void) printf("%s %7d", prefix, g_pgsize[ps]);
1259 		tlbdata(&data->tmode_itlb, &odata->tmode_itlb);
1260 		tlbdata(&data->tmode_dtlb, &odata->tmode_dtlb);
1261 		(void) printf("\n");
1262 
1263 		data = (tstat_modedata_t *)((uintptr_t)data + incr);
1264 		odata = (tstat_modedata_t *)((uintptr_t)odata + incr);
1265 	}
1266 }
1267 
1268 static void
1269 sum_missdata(void *sump, uint64_t diff, double p)
1270 {
1271 	tstat_sum_t *sum = *((tstat_sum_t **)sump);
1272 
1273 	sum->tsum_diff += diff;
1274 	sum->tsum_time += p;
1275 
1276 	(*(tstat_sum_t **)sump)++;
1277 }
1278 
1279 static void
1280 sum_modedata(tstat_modedata_t *data, tstat_modedata_t *odata, tstat_sum_t *sum)
1281 {
1282 	int ps, incr = sizeof (tstat_pgszdata_t);
1283 	tstat_sum_t *sump;
1284 
1285 	for (ps = 0; ps < g_pgsizes; ps++) {
1286 		sump = sum;
1287 
1288 		g_process = sum_missdata;
1289 		g_arg = &sump;
1290 
1291 		tlbdata(&data->tmode_itlb, &odata->tmode_itlb);
1292 		tlbdata(&data->tmode_dtlb, &odata->tmode_dtlb);
1293 
1294 		data = (tstat_modedata_t *)((uintptr_t)data + incr);
1295 		odata = (tstat_modedata_t *)((uintptr_t)odata + incr);
1296 	}
1297 }
1298 
1299 static void
1300 print_sum(tstat_sum_t *sum, int divisor)
1301 {
1302 	int i;
1303 	double ttl = 0.0;
1304 
1305 	for (i = 0; i < 4; i++) {
1306 		if (i == 2)
1307 			(void) printf(" |");
1308 
1309 		sum[i].tsum_time /= divisor;
1310 
1311 		TSTAT_PRINT_MISSDATA(sum[i].tsum_diff, sum[i].tsum_time);
1312 		ttl += sum[i].tsum_time;
1313 	}
1314 
1315 	(void) printf(" |%4.1f\n", ttl);
1316 }
1317 
1318 static void
1319 print_tlbpgsz(tstat_data_t *data, tstat_data_t *odata)
1320 {
1321 	int i, cpu, ncpus = 0;
1322 	char pre[12];
1323 	tstat_sum_t sum[4];
1324 
1325 	(void) printf("cpu m size| %9s %4s %9s %4s | %9s %4s %9s %4s |%4s\n"
1326 	    "----------+-------------------------------+-----------------------"
1327 	    "--------+----\n", "itlb-miss", "%tim", "itsb-miss", "%tim",
1328 	    "dtlb-miss", "%tim", "dtsb-miss", "%tim", "%tim");
1329 
1330 	bzero(sum, sizeof (sum));
1331 
1332 	for (i = 0; i < g_max_cpus; i++) {
1333 		tstat_pgszdata_t *pgsz = data->tdata_pgsz;
1334 		tstat_pgszdata_t *opgsz = odata->tdata_pgsz;
1335 
1336 		if ((cpu = data->tdata_cpuid) == -1)
1337 			break;
1338 
1339 		if (i != 0)
1340 			(void) printf("----------+-----------------------------"
1341 			    "--+-------------------------------+----\n");
1342 
1343 		g_ndata = data;
1344 		g_odata = odata;
1345 
1346 		(void) sprintf(pre, "%3d u", cpu);
1347 		print_modepgsz(pre, &pgsz->tpgsz_user, &opgsz->tpgsz_user);
1348 		sum_modedata(&pgsz->tpgsz_user, &opgsz->tpgsz_user, sum);
1349 
1350 		(void) printf("- - - - - + - - - - - - - - - - - - - -"
1351 		    " - + - - - - - - - - - - - - - - - + - -\n");
1352 
1353 		(void) sprintf(pre, "%3d k", cpu);
1354 		print_modepgsz(pre, &pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel);
1355 		sum_modedata(&pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel, sum);
1356 
1357 		data = (tstat_data_t *)((uintptr_t)data + g_datasize);
1358 		odata = (tstat_data_t *)((uintptr_t)odata + g_datasize);
1359 		ncpus++;
1360 	}
1361 
1362 	(void) printf("==========+===============================+========="
1363 	    "======================+====\n");
1364 	(void) printf("      ttl |");
1365 	print_sum(sum, ncpus);
1366 	(void) printf("\n");
1367 }
1368 
1369 static void
1370 parsable_tlbpgsz(tstat_data_t *data, tstat_data_t *odata)
1371 {
1372 	int i, cpu;
1373 	char pre[30];
1374 
1375 	for (i = 0; i < g_max_cpus; i++) {
1376 		tstat_pgszdata_t *pgsz = data->tdata_pgsz;
1377 		tstat_pgszdata_t *opgsz = odata->tdata_pgsz;
1378 
1379 		if ((cpu = data->tdata_cpuid) == -1)
1380 			break;
1381 
1382 		g_ndata = data;
1383 		g_odata = odata;
1384 
1385 		(void) sprintf(pre, "%lld %3d u",
1386 		    data->tdata_snapts - g_start, cpu);
1387 		parsable_modepgsz(pre, &pgsz->tpgsz_user, &opgsz->tpgsz_user);
1388 
1389 		pre[strlen(pre) - 1] = 'k';
1390 		parsable_modepgsz(pre, &pgsz->tpgsz_kernel,
1391 		    &opgsz->tpgsz_kernel);
1392 
1393 		data = (tstat_data_t *)((uintptr_t)data + g_datasize);
1394 		odata = (tstat_data_t *)((uintptr_t)odata + g_datasize);
1395 	}
1396 }
1397 
1398 static void
1399 print_modedata(tstat_modedata_t *data, tstat_modedata_t *odata, int parsable)
1400 {
1401 	int ps, i;
1402 	size_t incr = sizeof (tstat_pgszdata_t);
1403 	tstat_sum_t sum[4], *sump = sum;
1404 	double ttl = 0.0;
1405 
1406 	bzero(sum, sizeof (sum));
1407 	g_process = sum_missdata;
1408 	g_arg = &sump;
1409 
1410 	for (ps = 0; ps < g_pgsizes; ps++) {
1411 		tlbdata(&data->tmode_itlb, &odata->tmode_itlb);
1412 		tlbdata(&data->tmode_dtlb, &odata->tmode_dtlb);
1413 
1414 		data = (tstat_modedata_t *)((uintptr_t)data + incr);
1415 		odata = (tstat_modedata_t *)((uintptr_t)odata + incr);
1416 		sump = sum;
1417 	}
1418 
1419 	for (i = 0; i < 4; i++) {
1420 		if (i == 2 && !parsable)
1421 			(void) printf(" |");
1422 
1423 		TSTAT_PRINT_MISSDATA(sum[i].tsum_diff, sum[i].tsum_time);
1424 		ttl += sum[i].tsum_time;
1425 	}
1426 
1427 	if (parsable) {
1428 		(void) printf("\n");
1429 		return;
1430 	}
1431 
1432 	(void) printf(" |%4.1f\n", ttl);
1433 }
1434 
1435 static void
1436 print_tlb(tstat_data_t *data, tstat_data_t *odata)
1437 {
1438 	int i, cpu, ncpus = 0;
1439 	tstat_sum_t sum[4];
1440 
1441 	(void) printf("cpu m| %9s %4s %9s %4s | %9s %4s %9s %4s |%4s\n"
1442 	    "-----+-------------------------------+-----------------------"
1443 	    "--------+----\n", "itlb-miss", "%tim", "itsb-miss", "%tim",
1444 	    "dtlb-miss", "%tim", "dtsb-miss", "%tim", "%tim");
1445 
1446 	bzero(sum, sizeof (sum));
1447 
1448 	for (i = 0; i < g_max_cpus; i++) {
1449 		tstat_pgszdata_t *pgsz = data->tdata_pgsz;
1450 		tstat_pgszdata_t *opgsz = odata->tdata_pgsz;
1451 
1452 		if ((cpu = data->tdata_cpuid) == -1)
1453 			break;
1454 
1455 		if (i != 0)
1456 			(void) printf("-----+-------------------------------+-"
1457 			    "------------------------------+----\n");
1458 
1459 		g_ndata = data;
1460 		g_odata = odata;
1461 
1462 		(void) printf("%3d u|", cpu);
1463 		print_modedata(&pgsz->tpgsz_user, &opgsz->tpgsz_user, 0);
1464 		sum_modedata(&pgsz->tpgsz_user, &opgsz->tpgsz_user, sum);
1465 
1466 		(void) printf("%3d k|", cpu);
1467 		print_modedata(&pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel, 0);
1468 		sum_modedata(&pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel, sum);
1469 
1470 		data = (tstat_data_t *)((uintptr_t)data + g_datasize);
1471 		odata = (tstat_data_t *)((uintptr_t)odata + g_datasize);
1472 		ncpus++;
1473 	}
1474 
1475 	(void) printf("=====+===============================+========="
1476 	    "======================+====\n");
1477 
1478 	(void) printf(" ttl |");
1479 	print_sum(sum, ncpus);
1480 	(void) printf("\n");
1481 }
1482 
1483 static void
1484 parsable_tlb(tstat_data_t *data, tstat_data_t *odata)
1485 {
1486 	int i, cpu;
1487 
1488 	for (i = 0; i < g_max_cpus; i++) {
1489 		tstat_pgszdata_t *pgsz = data->tdata_pgsz;
1490 		tstat_pgszdata_t *opgsz = odata->tdata_pgsz;
1491 
1492 		if ((cpu = data->tdata_cpuid) == -1)
1493 			break;
1494 
1495 		g_ndata = data;
1496 		g_odata = odata;
1497 
1498 		(void) printf("%lld %3d u ", data->tdata_snapts - g_start, cpu);
1499 		print_modedata(&pgsz->tpgsz_user, &opgsz->tpgsz_user, 1);
1500 		(void) printf("%lld %3d k ", data->tdata_snapts - g_start, cpu);
1501 		print_modedata(&pgsz->tpgsz_kernel, &opgsz->tpgsz_kernel, 1);
1502 
1503 		data = (tstat_data_t *)((uintptr_t)data + g_datasize);
1504 		odata = (tstat_data_t *)((uintptr_t)odata + g_datasize);
1505 	}
1506 }
1507 
1508 static void
1509 print_stats(tstat_data_t *data, tstat_data_t *odata)
1510 {
1511 	int i, j, k, done;
1512 	processorid_t id;
1513 	tstat_data_t *base = data;
1514 
1515 	/*
1516 	 * First, blast through all of the data updating our array
1517 	 * of active traps.  We keep an array of active traps to prevent
1518 	 * printing lines for traps that are never seen -- while still printing
1519 	 * lines for traps that have been seen only once on some CPU.
1520 	 */
1521 	for (i = 0; i < g_max_cpus; i++) {
1522 		if (data[i].tdata_cpuid == -1)
1523 			break;
1524 
1525 		for (j = 0; j < TSTAT_NENT; j++) {
1526 			if (!data[i].tdata_traps[j] || g_active[j])
1527 				continue;
1528 
1529 			g_active[j] = 1;
1530 		}
1531 	}
1532 
1533 	data = base;
1534 
1535 	for (done = 0; !done; data += g_cpus_per_line) {
1536 		for (i = 0; i < g_cpus_per_line; i++) {
1537 			if (&data[i] - base >= g_max_cpus)
1538 				break;
1539 
1540 			if ((id = data[i].tdata_cpuid) == -1)
1541 				break;
1542 
1543 			if (i == 0)
1544 				(void) printf("vct name                |");
1545 
1546 			(void) printf("   %scpu%d", id >= 100 ? "" :
1547 			    id >= 10 ? " " : "  ", id);
1548 		}
1549 
1550 		if (i == 0)
1551 			break;
1552 
1553 		if (i != g_cpus_per_line)
1554 			done = 1;
1555 
1556 		(void) printf("\n------------------------+");
1557 
1558 		for (j = 0; j < i; j++)
1559 			(void) printf("---------");
1560 		(void) printf("\n");
1561 
1562 		for (j = 0; j < TSTAT_NENT; j++) {
1563 			if (!g_active[j])
1564 				continue;
1565 
1566 			(void) printf("%3x %-20s|", j, g_traps[j].tent_name);
1567 			for (k = 0; k < i; k++) {
1568 				(void) printf(" %8lld", TSTAT_DELTA(&data[k],
1569 				    &odata[data - base + k], tdata_traps[j]));
1570 			}
1571 			(void) printf("\n");
1572 		}
1573 		(void) printf("\n");
1574 	}
1575 }
1576 
1577 static void
1578 parsable_stats(tstat_data_t *data, tstat_data_t *odata)
1579 {
1580 	tstat_data_t *base;
1581 	int i;
1582 
1583 	for (base = data; data - base < g_max_cpus; data++, odata++) {
1584 		if (data->tdata_cpuid == -1)
1585 			break;
1586 
1587 		for (i = 0; i < TSTAT_NENT; i++) {
1588 			if (!data->tdata_traps[i] && !g_active[i])
1589 				continue;
1590 
1591 			(void) printf("%lld %d %x %s ",
1592 			    data->tdata_snapts - g_start, data->tdata_cpuid, i,
1593 			    g_traps[i].tent_name);
1594 
1595 			(void) printf("%lld\n", TSTAT_DELTA(data, odata,
1596 			    tdata_traps[i]));
1597 		}
1598 	}
1599 }
1600 
1601 static void
1602 check_data(tstat_data_t *data, tstat_data_t *odata)
1603 {
1604 	tstat_data_t *ndata;
1605 	int i;
1606 
1607 	if (data->tdata_cpuid == -1) {
1608 		/*
1609 		 * The last CPU we were watching must have been DR'd out
1610 		 * of the system.  Print a vaguely useful message and exit.
1611 		 */
1612 		fatal("all initially selected CPUs have been unconfigured\n");
1613 	}
1614 
1615 	/*
1616 	 * If a CPU is DR'd out of the system, we'll stop receiving data
1617 	 * for it.  CPUs are never added, however (that is, if a CPU is
1618 	 * DR'd into the system, we won't automatically start receiving
1619 	 * data for it).  We check for this by making sure that all of
1620 	 * the CPUs present in the old data are present in the new data.
1621 	 * If we find one missing in the new data, we correct the old data
1622 	 * by removing the old CPU.  This assures that delta are printed
1623 	 * correctly.
1624 	 */
1625 	for (i = 0; i < g_max_cpus; i++) {
1626 		if (odata->tdata_cpuid == -1)
1627 			return;
1628 
1629 		if (data->tdata_cpuid != odata->tdata_cpuid)
1630 			break;
1631 
1632 		data = (tstat_data_t *)((uintptr_t)data + g_datasize);
1633 		odata = (tstat_data_t *)((uintptr_t)odata + g_datasize);
1634 	}
1635 
1636 	if (i == g_max_cpus)
1637 		return;
1638 
1639 	/*
1640 	 * If we're here, we know that the odata is a CPU which has been
1641 	 * DR'd out.  We'll now smoosh it out of the old data.
1642 	 */
1643 	for (odata->tdata_cpuid = -1; i < g_max_cpus - 1; i++) {
1644 		ndata = (tstat_data_t *)((uintptr_t)odata + g_datasize);
1645 		bcopy(ndata, odata, g_datasize);
1646 		ndata->tdata_cpuid = -1;
1647 	}
1648 
1649 	/*
1650 	 * There may be other CPUs DR'd out; tail-call recurse.
1651 	 */
1652 	check_data(data, odata);
1653 }
1654 
1655 int
1656 main(int argc, char **argv)
1657 {
1658 	processorid_t id;
1659 	char c, *end;
1660 	ulong_t indefinite;
1661 	long count = 0, rate = 0;
1662 	int list = 0, parsable = 0;
1663 	void (*print)(tstat_data_t *, tstat_data_t *);
1664 	sigset_t set;
1665 
1666 	struct {
1667 		char opt;
1668 		void (*print)(tstat_data_t *, tstat_data_t *);
1669 		void (*parsable)(tstat_data_t *, tstat_data_t *);
1670 		int repeat;
1671 	} tab[] = {
1672 		{ '\0',	print_stats,	parsable_stats,		0 },
1673 		{ 'e',	print_stats,	parsable_stats,		1 },
1674 		{ 't',	print_tlb,	parsable_tlb,		0 },
1675 		{ 'T',	print_tlbpgsz,	parsable_tlbpgsz,	0 },
1676 		{ -1,	NULL,		NULL,			0 }
1677 	}, *tabent = NULL, *iter;
1678 
1679 	uintptr_t offs = (uintptr_t)&tab->print - (uintptr_t)tab;
1680 
1681 	/*
1682 	 * If argv[0] is non-NULL, set argv[0] to keep any getopt(3C) output
1683 	 * consistent with other error output.
1684 	 */
1685 	if (argv[0] != NULL)
1686 		argv[0] = TSTAT_COMMAND;
1687 
1688 	if ((g_fd = open(TSTAT_DEVICE, O_RDWR)) == -1)
1689 		fatal("couldn't open " TSTAT_DEVICE);
1690 
1691 	setup();
1692 
1693 	while ((c = getopt(argc, argv, "alnNtTc:C:r:e:P")) != EOF) {
1694 		/*
1695 		 * First, check to see if this option changes our printing
1696 		 * function.
1697 		 */
1698 		for (iter = tab; iter->opt >= 0; iter++) {
1699 			if (c != iter->opt)
1700 				continue;
1701 
1702 			if (tabent != NULL) {
1703 				if (tabent == iter) {
1704 					if (tabent->repeat) {
1705 						/*
1706 						 * This option is allowed to
1707 						 * have repeats; break out.
1708 						 */
1709 						break;
1710 					}
1711 
1712 					fatal("expected -%c at most once\n", c);
1713 				}
1714 
1715 				fatal("only one of -%c, -%c expected\n",
1716 				    tabent->opt, c);
1717 			}
1718 
1719 			tabent = iter;
1720 			break;
1721 		}
1722 
1723 		switch (c) {
1724 		case 'a':
1725 			g_absolute = 1;
1726 			break;
1727 
1728 		case 'e': {
1729 			char *s = strtok(optarg, ",");
1730 
1731 			while (s != NULL) {
1732 				select_entry(s);
1733 				s = strtok(NULL, ",");
1734 			}
1735 
1736 			break;
1737 		}
1738 
1739 		case 'l':
1740 			list = 1;
1741 			break;
1742 
1743 		case 'n':
1744 			/*
1745 			 * This undocumented option prevents trapstat from
1746 			 * actually switching the %tba to point to the
1747 			 * interposing trap table.  It's very useful when
1748 			 * debugging trapstat bugs:  one can specify "-n"
1749 			 * and then examine the would-be interposing trap
1750 			 * table without running the risk of RED stating.
1751 			 */
1752 			if (ioctl(g_fd, TSTATIOC_NOGO) == -1)
1753 				fatal("TSTATIOC_NOGO");
1754 			break;
1755 
1756 		case 'N':
1757 			/*
1758 			 * This undocumented option forces trapstat to ignore
1759 			 * its determined probe effect.  This may be useful
1760 			 * if it is believed that the probe effect has been
1761 			 * grossly overestimated.
1762 			 */
1763 			g_peffect = 0;
1764 			break;
1765 
1766 		case 't':
1767 		case 'T':
1768 			/*
1769 			 * When running with TLB statistics, we want to
1770 			 * minimize probe effect by running with all other
1771 			 * entries explicitly disabled.
1772 			 */
1773 			if (ioctl(g_fd, TSTATIOC_NOENTRY) == -1)
1774 				fatal("TSTATIOC_NOENTRY");
1775 
1776 			if (ioctl(g_fd, TSTATIOC_TLBDATA) == -1)
1777 				fatal("TSTATIOC_TLBDATA");
1778 			break;
1779 
1780 		case 'c': {
1781 			/*
1782 			 * We allow CPUs to be specified as an optionally
1783 			 * comma separated list of either CPU IDs or ranges
1784 			 * of CPU IDs.
1785 			 */
1786 			char *s = strtok(optarg, ",");
1787 
1788 			while (s != NULL) {
1789 				id = strtoul(s, &end, 0);
1790 
1791 				if (id == ULONG_MAX && errno == ERANGE) {
1792 					*end = '\0';
1793 					fatal("invalid cpu '%s'\n", s);
1794 				}
1795 
1796 				if (*(s = end) != '\0') {
1797 					processorid_t p;
1798 
1799 					if (*s != '-')
1800 						fatal("invalid cpu '%s'\n", s);
1801 					p = strtoul(++s, &end, 0);
1802 
1803 					if (*end != '\0' ||
1804 					    (p == ULONG_MAX && errno == ERANGE))
1805 						fatal("invalid cpu '%s'\n", s);
1806 
1807 					select_cpus(id, p);
1808 				} else {
1809 					select_cpu(id);
1810 				}
1811 
1812 				s = strtok(NULL, ",");
1813 			}
1814 
1815 			break;
1816 		}
1817 
1818 		case 'C': {
1819 			psetid_t pset = strtoul(optarg, &end, 0);
1820 
1821 			if (*end != '\0' ||
1822 			    (pset == ULONG_MAX && errno == ERANGE))
1823 				fatal("invalid processor set '%s'\n", optarg);
1824 
1825 			select_pset(pset);
1826 			break;
1827 		}
1828 
1829 		case 'r': {
1830 			rate = strtol(optarg, &end, 0);
1831 
1832 			if (*end != '\0' ||
1833 			    (rate == LONG_MAX && errno == ERANGE))
1834 				fatal("invalid rate '%s'\n", optarg);
1835 
1836 			if (rate <= 0)
1837 				fatal("rate must be greater than zero\n");
1838 
1839 			if (rate > TSTAT_MAX_RATE)
1840 				fatal("rate may not exceed %d\n",
1841 				    TSTAT_MAX_RATE);
1842 
1843 			set_interval(NANOSEC / rate);
1844 			break;
1845 		}
1846 
1847 		case 'P':
1848 			offs = (uintptr_t)&tab->parsable - (uintptr_t)tab;
1849 			parsable = 1;
1850 			break;
1851 
1852 		default:
1853 			usage();
1854 		}
1855 	}
1856 
1857 	if (list) {
1858 		print_entries(stdout, parsable);
1859 		exit(EXIT_SUCCESS);
1860 	}
1861 
1862 	if (optind != argc) {
1863 
1864 		int interval = strtol(argv[optind], &end, 0);
1865 
1866 		if (*end != '\0') {
1867 			/*
1868 			 * That wasn't a valid number.  It must be that we're
1869 			 * to execute this command.
1870 			 */
1871 			switch (vfork()) {
1872 			case 0:
1873 				(void) close(g_fd);
1874 				(void) sigprocmask(SIG_SETMASK, &g_oset, NULL);
1875 				(void) execvp(argv[optind], &argv[optind]);
1876 
1877 				/*
1878 				 * No luck.  Set errno.
1879 				 */
1880 				g_exec_errno = errno;
1881 				_exit(EXIT_FAILURE);
1882 				/*NOTREACHED*/
1883 			case -1:
1884 				fatal("cannot fork");
1885 				/*NOTREACHED*/
1886 			default:
1887 				break;
1888 			}
1889 		} else {
1890 			if (interval <= 0)
1891 				fatal("interval must be greater than zero.\n");
1892 
1893 			if (interval == LONG_MAX && errno == ERANGE)
1894 				fatal("invalid interval '%s'\n", argv[optind]);
1895 
1896 			set_interval(NANOSEC * (hrtime_t)interval);
1897 
1898 			if (++optind != argc) {
1899 				char *s = argv[optind];
1900 
1901 				count = strtol(s, &end, 0);
1902 
1903 				if (*end != '\0' || count <= 0 ||
1904 				    (count == LONG_MAX && errno == ERANGE))
1905 					fatal("invalid count '%s'\n", s);
1906 			}
1907 		}
1908 	} else {
1909 		if (!rate)
1910 			set_interval(NANOSEC);
1911 	}
1912 
1913 	if (tabent == NULL)
1914 		tabent = tab;
1915 
1916 	print = *(void(**)(tstat_data_t *, tstat_data_t *))
1917 	    ((uintptr_t)tabent + offs);
1918 
1919 	for (id = 0; id < g_max_cpus; id++) {
1920 		if (!g_selected[id])
1921 			continue;
1922 
1923 		if (ioctl(g_fd, TSTATIOC_CPU, id) == -1)
1924 			fatal("TSTATIOC_CPU failed for cpu %d", id);
1925 	}
1926 
1927 	g_start = gethrtime();
1928 
1929 	if (ioctl(g_fd, TSTATIOC_GO) == -1)
1930 		fatal("TSTATIOC_GO failed");
1931 
1932 	if (ioctl(g_fd, TSTATIOC_READ, g_data[g_gen ^ 1]) == -1)
1933 		fatal("initial TSTATIOC_READ failed");
1934 
1935 	(void) sigemptyset(&set);
1936 
1937 	for (indefinite = (count == 0); indefinite || count; count--) {
1938 
1939 		(void) sigsuspend(&set);
1940 
1941 		if (g_winch) {
1942 			g_winch = 0;
1943 			continue;
1944 		}
1945 
1946 		if (g_child_exited && g_exec_errno != 0) {
1947 			errno = g_exec_errno;
1948 			fatal("could not execute %s", argv[optind]);
1949 		}
1950 
1951 		if (ioctl(g_fd, TSTATIOC_READ, g_data[g_gen]) == -1)
1952 			fatal("TSTATIOC_READ failed");
1953 
1954 		/*
1955 		 * Before we blithely print the data, we need to
1956 		 * make sure that we haven't lost a CPU.
1957 		 */
1958 		check_data(g_data[g_gen], g_data[g_gen ^ 1]);
1959 		(*print)(g_data[g_gen], g_data[g_gen ^ 1]);
1960 		(void) fflush(stdout);
1961 
1962 		if (g_child_exited) {
1963 			if (WIFEXITED(g_child_status)) {
1964 				if (WEXITSTATUS(g_child_status) == 0)
1965 					break;
1966 
1967 				(void) fprintf(stderr, TSTAT_COMMAND ": "
1968 				    "warning: %s exited with code %d\n",
1969 				    argv[optind], WEXITSTATUS(g_child_status));
1970 			} else {
1971 				(void) fprintf(stderr, TSTAT_COMMAND ": "
1972 				    "warning: %s died on signal %d\n",
1973 				    argv[optind], WTERMSIG(g_child_status));
1974 			}
1975 			break;
1976 		}
1977 
1978 		check_pset();
1979 
1980 		g_gen ^= 1;
1981 	}
1982 
1983 	return (0);
1984 }
1985