1238582Smm/*
2238582Smm * CDDL HEADER START
3238582Smm *
4238582Smm * The contents of this file are subject to the terms of the
5238582Smm * Common Development and Distribution License (the "License").
6238582Smm * You may not use this file except in compliance with the License.
7238582Smm *
8238582Smm * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9238582Smm * or http://www.opensolaris.org/os/licensing.
10238582Smm * See the License for the specific language governing permissions
11238582Smm * and limitations under the License.
12238582Smm *
13238582Smm * When distributing Covered Code, include this CDDL HEADER in each
14238582Smm * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15238582Smm * If applicable, add the following below this CDDL HEADER, with the
16238582Smm * fields enclosed by brackets "[]" replaced with your own identifying
17238582Smm * information: Portions Copyright [yyyy] [name of copyright owner]
18238582Smm *
19238582Smm * CDDL HEADER END
20238582Smm */
21238582Smm/*
22238582Smm * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23238582Smm * Use is subject to license terms.
24238582Smm */
25238582Smm/*
26238582Smm * Copyright (c) 2011 by Delphix. All rights reserved.
27238582Smm */
28250485Spfg/*
29250485Spfg * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
30250485Spfg */
31238582Smm
32238582Smm/*
33238582Smm * DTrace print() action
34238582Smm *
35238582Smm * This file contains the post-processing logic for the print() action.  The
36238582Smm * print action behaves identically to trace() in that it generates a
37238582Smm * DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type
38238582Smm * string stored in the DOF string table (similar to printf formats).  We
39238582Smm * take the result of the trace action and post-process it in the fashion of
40238582Smm * MDB's ::print dcmd.
41238582Smm *
42238582Smm * This implementation differs from MDB's in the following ways:
43238582Smm *
44238582Smm * 	- We do not expose any options or flags.  The behavior of print() is
45238582Smm *	  equivalent to "::print -tn".
46238582Smm *
47238582Smm * 	- MDB will display "holes" in structures (unused padding between
48238582Smm *	  members).
49238582Smm *
50238582Smm * 	- When printing arrays of structures, MDB will leave a trailing ','
51238582Smm *	  after the last element.
52238582Smm *
53238582Smm *	- MDB will print time_t types as date and time.
54238582Smm *
55238582Smm *	- MDB will detect when an enum is actually the OR of several flags,
56238582Smm *	  and print it out with the constituent flags separated.
57238582Smm *
58238582Smm *	- For large arrays, MDB will print the first few members and then
59238582Smm *	  print a "..." continuation line.
60238582Smm *
61238582Smm *	- MDB will break and wrap arrays at 80 columns.
62238582Smm *
63238582Smm *	- MDB prints out floats and doubles by hand, as it must run in kmdb
64238582Smm *	  context.  We're able to leverage the printf() format strings,
65238582Smm *	  but the result is a slightly different format.
66238582Smm */
67238582Smm
68238582Smm#include <sys/sysmacros.h>
69238582Smm#include <strings.h>
70238582Smm#include <stdlib.h>
71238582Smm#include <alloca.h>
72238582Smm#include <assert.h>
73238582Smm#include <ctype.h>
74238582Smm#include <errno.h>
75238582Smm#include <limits.h>
76238582Smm#include <sys/socket.h>
77238582Smm#include <netdb.h>
78238582Smm#include <netinet/in.h>
79238582Smm#include <arpa/inet.h>
80238582Smm#include <arpa/nameser.h>
81238582Smm
82238582Smm#include <dt_module.h>
83238582Smm#include <dt_printf.h>
84238582Smm#include <dt_string.h>
85238582Smm#include <dt_impl.h>
86238582Smm
87238582Smm/* determines whether the given integer CTF encoding is a character */
88238582Smm#define	CTF_IS_CHAR(e) \
89238582Smm	(((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
90238582Smm	(CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
91238582Smm/* determines whether the given CTF kind is a struct or union */
92238582Smm#define	CTF_IS_STRUCTLIKE(k) \
93238582Smm	((k) == CTF_K_STRUCT || (k) == CTF_K_UNION)
94238582Smm
95238582Smm/*
96238582Smm * Print structure passed down recursively through printing algorithm.
97238582Smm */
98238582Smmtypedef struct dt_printarg {
99250485Spfg	dtrace_hdl_t	*pa_dtp;	/* libdtrace handle */
100238582Smm	caddr_t		pa_addr;	/* base address of trace data */
101238582Smm	ctf_file_t	*pa_ctfp;	/* CTF container */
102238582Smm	int		pa_depth;	/* member depth */
103238582Smm	int		pa_nest;	/* nested array depth */
104238582Smm	FILE		*pa_file;	/* output file */
105238582Smm} dt_printarg_t;
106238582Smm
107238582Smmstatic int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);
108238582Smm
109238582Smm/*
110238582Smm * Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it
111238582Smm * can't resolve the type.
112238582Smm */
113238582Smmstatic void
114238582Smmdt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen)
115238582Smm{
116238582Smm	if (ctf_type_name(ctfp, id, buf, buflen) == NULL)
117238582Smm		(void) snprintf(buf, buflen, "<%ld>", id);
118238582Smm}
119238582Smm
120238582Smm/*
121238582Smm * Print any necessary trailing braces for structures or unions.  We don't get
122238582Smm * invoked when a struct or union ends, so we infer the need to print braces
123238582Smm * based on the depth the last time we printed something and the new depth.
124238582Smm */
125238582Smmstatic void
126238582Smmdt_print_trailing_braces(dt_printarg_t *pap, int depth)
127238582Smm{
128238582Smm	int d;
129238582Smm
130238582Smm	for (d = pap->pa_depth; d > depth; d--) {
131238582Smm		(void) fprintf(pap->pa_file, "%*s}%s",
132238582Smm		    (d + pap->pa_nest - 1) * 4, "",
133238582Smm		    d == depth + 1 ? "" : "\n");
134238582Smm	}
135238582Smm}
136238582Smm
137238582Smm/*
138238582Smm * Print the appropriate amount of indentation given the current depth and
139238582Smm * array nesting.
140238582Smm */
141238582Smmstatic void
142238582Smmdt_print_indent(dt_printarg_t *pap)
143238582Smm{
144238582Smm	(void) fprintf(pap->pa_file, "%*s",
145238582Smm	    (pap->pa_depth + pap->pa_nest) * 4, "");
146238582Smm}
147238582Smm
148238582Smm/*
149238582Smm * Print a bitfield.  It's worth noting that the D compiler support for
150238582Smm * bitfields is currently broken; printing "D`user_desc_t" (pulled in by the
151238582Smm * various D provider files) will produce incorrect results compared to
152238582Smm * "genunix`user_desc_t".
153238582Smm */
154238582Smmstatic void
155238582Smmprint_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
156238582Smm{
157238582Smm	FILE *fp = pap->pa_file;
158238582Smm	caddr_t addr = pap->pa_addr + off / NBBY;
159238582Smm	uint64_t mask = (1ULL << ep->cte_bits) - 1;
160238582Smm	uint64_t value = 0;
161238582Smm	size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
162238582Smm	uint8_t *buf = (uint8_t *)&value;
163238582Smm	uint8_t shift;
164238582Smm
165238582Smm	/*
166238582Smm	 * On big-endian machines, we need to adjust the buf pointer to refer
167238582Smm	 * to the lowest 'size' bytes in 'value', and we need to shift based on
168238582Smm	 * the offset from the end of the data, not the offset of the start.
169238582Smm	 */
170238582Smm#ifdef _BIG_ENDIAN
171238582Smm	buf += sizeof (value) - size;
172238582Smm	off += ep->cte_bits;
173238582Smm#endif
174238582Smm	bcopy(addr, buf, size);
175238582Smm	shift = off % NBBY;
176238582Smm
177238582Smm	/*
178238582Smm	 * Offsets are counted from opposite ends on little- and
179238582Smm	 * big-endian machines.
180238582Smm	 */
181238582Smm#ifdef _BIG_ENDIAN
182238582Smm	shift = NBBY - shift;
183238582Smm#endif
184238582Smm
185238582Smm	/*
186238582Smm	 * If the bits we want do not begin on a byte boundary, shift the data
187238582Smm	 * right so that the value is in the lowest 'cte_bits' of 'value'.
188238582Smm	 */
189238582Smm	if (off % NBBY != 0)
190238582Smm		value >>= shift;
191238582Smm	value &= mask;
192238582Smm
193238582Smm	(void) fprintf(fp, "%#llx", (u_longlong_t)value);
194238582Smm}
195238582Smm
196238582Smm/*
197238582Smm * Dump the contents of memory as a fixed-size integer in hex.
198238582Smm */
199238582Smmstatic void
200238582Smmdt_print_hex(FILE *fp, caddr_t addr, size_t size)
201238582Smm{
202238582Smm	switch (size) {
203238582Smm	case sizeof (uint8_t):
204238582Smm		(void) fprintf(fp, "%#x", *(uint8_t *)addr);
205238582Smm		break;
206238582Smm	case sizeof (uint16_t):
207238582Smm		/* LINTED - alignment */
208238582Smm		(void) fprintf(fp, "%#x", *(uint16_t *)addr);
209238582Smm		break;
210238582Smm	case sizeof (uint32_t):
211238582Smm		/* LINTED - alignment */
212238582Smm		(void) fprintf(fp, "%#x", *(uint32_t *)addr);
213238582Smm		break;
214238582Smm	case sizeof (uint64_t):
215238582Smm		(void) fprintf(fp, "%#llx",
216238582Smm		    /* LINTED - alignment */
217238582Smm		    (unsigned long long)*(uint64_t *)addr);
218238582Smm		break;
219238582Smm	default:
220238582Smm		(void) fprintf(fp, "<invalid size %u>", (uint_t)size);
221238582Smm	}
222238582Smm}
223238582Smm
224238582Smm/*
225238582Smm * Print an integer type.  Before dumping the contents via dt_print_hex(), we
226238582Smm * first check the encoding to see if it's part of a bitfield or a character.
227238582Smm */
228238582Smmstatic void
229238582Smmdt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
230238582Smm{
231238582Smm	FILE *fp = pap->pa_file;
232238582Smm	ctf_file_t *ctfp = pap->pa_ctfp;
233238582Smm	ctf_encoding_t e;
234238582Smm	size_t size;
235238582Smm	caddr_t addr = pap->pa_addr + off / NBBY;
236238582Smm
237238582Smm	if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {
238238582Smm		(void) fprintf(fp, "<unknown encoding>");
239238582Smm		return;
240238582Smm	}
241238582Smm
242238582Smm	/*
243238582Smm	 * This comes from MDB - it's not clear under what circumstances this
244238582Smm	 * would be found.
245238582Smm	 */
246238582Smm	if (e.cte_format & CTF_INT_VARARGS) {
247238582Smm		(void) fprintf(fp, "...");
248238582Smm		return;
249238582Smm	}
250238582Smm
251238582Smm	/*
252238582Smm	 * We print this as a bitfield if the bit encoding indicates it's not
253238582Smm	 * an even power of two byte size, or is larger than 8 bytes.
254238582Smm	 */
255238582Smm	size = e.cte_bits / NBBY;
256238582Smm	if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {
257238582Smm		print_bitfield(pap, off, &e);
258238582Smm		return;
259238582Smm	}
260238582Smm
261238582Smm	/*
262238582Smm	 * If this is a character, print it out as such.
263238582Smm	 */
264238582Smm	if (CTF_IS_CHAR(e)) {
265238582Smm		char c = *(char *)addr;
266238582Smm		if (isprint(c))
267238582Smm			(void) fprintf(fp, "'%c'", c);
268238582Smm		else if (c == 0)
269238582Smm			(void) fprintf(fp, "'\\0'");
270238582Smm		else
271238582Smm			(void) fprintf(fp, "'\\%03o'", c);
272238582Smm		return;
273238582Smm	}
274238582Smm
275238582Smm	dt_print_hex(fp, addr, size);
276238582Smm}
277238582Smm
278238582Smm/*
279238582Smm * Print a floating point (float, double, long double) value.
280238582Smm */
281238582Smm/* ARGSUSED */
282238582Smmstatic void
283238582Smmdt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
284238582Smm{
285238582Smm	FILE *fp = pap->pa_file;
286238582Smm	ctf_file_t *ctfp = pap->pa_ctfp;
287238582Smm	ctf_encoding_t e;
288238582Smm	caddr_t addr = pap->pa_addr + off / NBBY;
289238582Smm
290238582Smm	if (ctf_type_encoding(ctfp, base, &e) == 0) {
291238582Smm		if (e.cte_format == CTF_FP_SINGLE &&
292238582Smm		    e.cte_bits == sizeof (float) * NBBY) {
293238582Smm			/* LINTED - alignment */
294238582Smm			(void) fprintf(fp, "%+.7e", *((float *)addr));
295238582Smm		} else if (e.cte_format == CTF_FP_DOUBLE &&
296238582Smm		    e.cte_bits == sizeof (double) * NBBY) {
297238582Smm			/* LINTED - alignment */
298238582Smm			(void) fprintf(fp, "%+.7e", *((double *)addr));
299238582Smm		} else if (e.cte_format == CTF_FP_LDOUBLE &&
300238582Smm		    e.cte_bits == sizeof (long double) * NBBY) {
301238582Smm			/* LINTED - alignment */
302238582Smm			(void) fprintf(fp, "%+.16LE", *((long double *)addr));
303238582Smm		} else {
304238582Smm			(void) fprintf(fp, "<unknown encoding>");
305238582Smm		}
306238582Smm	}
307238582Smm}
308238582Smm
309238582Smm/*
310250485Spfg * A pointer is generally printed as a fixed-size integer.  If we have a
311250485Spfg * function pointer, we try to look up its name.
312238582Smm */
313238582Smmstatic void
314238582Smmdt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
315238582Smm{
316238582Smm	FILE *fp = pap->pa_file;
317238582Smm	ctf_file_t *ctfp = pap->pa_ctfp;
318238582Smm	caddr_t addr = pap->pa_addr + off / NBBY;
319238582Smm	size_t size = ctf_type_size(ctfp, base);
320250485Spfg	ctf_id_t bid = ctf_type_reference(ctfp, base);
321250485Spfg	uint64_t pc;
322250485Spfg	dtrace_syminfo_t dts;
323250485Spfg	GElf_Sym sym;
324238582Smm
325250485Spfg	if (bid == CTF_ERR || ctf_type_kind(ctfp, bid) != CTF_K_FUNCTION) {
326250485Spfg		dt_print_hex(fp, addr, size);
327250485Spfg	} else {
328250485Spfg		/* LINTED - alignment */
329250485Spfg		pc = *((uint64_t *)addr);
330250485Spfg		if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) {
331250485Spfg			dt_print_hex(fp, addr, size);
332250485Spfg		} else {
333250485Spfg			(void) fprintf(fp, "%s`%s", dts.dts_object,
334250485Spfg			    dts.dts_name);
335250485Spfg		}
336250485Spfg	}
337238582Smm}
338238582Smm
339238582Smm/*
340238582Smm * Print out an array.  This is somewhat complex, as we must manually visit
341238582Smm * each member, and recursively invoke ctf_type_visit() for each member.  If
342238582Smm * the members are non-structs, then we print them out directly:
343238582Smm *
344238582Smm * 	[ 0x14, 0x2e, 0 ]
345238582Smm *
346238582Smm * If they are structs, then we print out the necessary leading and trailing
347238582Smm * braces, to end up with:
348238582Smm *
349238582Smm *	[
350238582Smm *	    type {
351238582Smm *	    ...
352238582Smm *	    },
353238582Smm *	    type {
354238582Smm *	    ...
355238582Smm *	    }
356238582Smm *	]
357238582Smm *
358238582Smm * We also use a heuristic to detect whether the array looks like a character
359238582Smm * array.  If the encoding indicates it's a character, and we have all
360238582Smm * printable characters followed by a null byte, then we display it as a
361238582Smm * string:
362238582Smm *
363238582Smm *	[ "string" ]
364238582Smm */
365238582Smmstatic void
366238582Smmdt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
367238582Smm{
368238582Smm	FILE *fp = pap->pa_file;
369238582Smm	ctf_file_t *ctfp = pap->pa_ctfp;
370238582Smm	caddr_t addr = pap->pa_addr + off / NBBY;
371238582Smm	ctf_arinfo_t car;
372238582Smm	ssize_t eltsize;
373238582Smm	ctf_encoding_t e;
374238582Smm	int i;
375238582Smm	boolean_t isstring;
376238582Smm	int kind;
377238582Smm	ctf_id_t rtype;
378238582Smm
379238582Smm	if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {
380238582Smm		(void) fprintf(fp, "0x%p", (void *)addr);
381238582Smm		return;
382238582Smm	}
383238582Smm
384238582Smm	if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||
385238582Smm	    (rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||
386238582Smm	    (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {
387238582Smm		(void) fprintf(fp, "<invalid type %lu>", car.ctr_contents);
388238582Smm		return;
389238582Smm	}
390238582Smm
391238582Smm	/* see if this looks like a string */
392238582Smm	isstring = B_FALSE;
393238582Smm	if (kind == CTF_K_INTEGER &&
394238582Smm	    ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) {
395238582Smm		char c;
396238582Smm		for (i = 0; i < car.ctr_nelems; i++) {
397238582Smm			c = *((char *)addr + eltsize * i);
398238582Smm			if (!isprint(c) || c == '\0')
399238582Smm				break;
400238582Smm		}
401238582Smm
402238582Smm		if (i != car.ctr_nelems && c == '\0')
403238582Smm			isstring = B_TRUE;
404238582Smm	}
405238582Smm
406238582Smm	/*
407238582Smm	 * As a slight aesthetic optimization, if we are a top-level type, then
408238582Smm	 * don't bother printing out the brackets.  This lets print("foo") look
409238582Smm	 * like:
410238582Smm	 *
411238582Smm	 * 	string "foo"
412238582Smm	 *
413238582Smm	 * As D will internally represent this as a char[256] array.
414238582Smm	 */
415238582Smm	if (!isstring || pap->pa_depth != 0)
416238582Smm		(void) fprintf(fp, "[ ");
417238582Smm
418238582Smm	if (isstring)
419238582Smm		(void) fprintf(fp, "\"");
420238582Smm
421238582Smm	for (i = 0; i < car.ctr_nelems; i++) {
422238582Smm		if (isstring) {
423238582Smm			char c = *((char *)addr + eltsize * i);
424238582Smm			if (c == '\0')
425238582Smm				break;
426238582Smm			(void) fprintf(fp, "%c", c);
427238582Smm		} else {
428238582Smm			/*
429238582Smm			 * Recursively invoke ctf_type_visit() on each member.
430238582Smm			 * We setup a new printarg struct with 'pa_nest' set to
431238582Smm			 * indicate that we are within a nested array.
432238582Smm			 */
433238582Smm			dt_printarg_t pa = *pap;
434238582Smm			pa.pa_nest += pap->pa_depth + 1;
435238582Smm			pa.pa_depth = 0;
436238582Smm			pa.pa_addr = addr + eltsize * i;
437238582Smm			(void) ctf_type_visit(ctfp, car.ctr_contents,
438238582Smm			    dt_print_member, &pa);
439238582Smm
440238582Smm			dt_print_trailing_braces(&pa, 0);
441238582Smm			if (i != car.ctr_nelems - 1)
442238582Smm				(void) fprintf(fp, ", ");
443238582Smm			else if (CTF_IS_STRUCTLIKE(kind))
444238582Smm				(void) fprintf(fp, "\n");
445238582Smm		}
446238582Smm	}
447238582Smm
448238582Smm	if (isstring)
449238582Smm		(void) fprintf(fp, "\"");
450238582Smm
451238582Smm	if (!isstring || pap->pa_depth != 0) {
452238582Smm		if (CTF_IS_STRUCTLIKE(kind))
453238582Smm			dt_print_indent(pap);
454238582Smm		else
455238582Smm			(void) fprintf(fp, " ");
456238582Smm		(void) fprintf(fp, "]");
457238582Smm	}
458238582Smm}
459238582Smm
460238582Smm/*
461238582Smm * This isued by both structs and unions to print the leading brace.
462238582Smm */
463238582Smm/* ARGSUSED */
464238582Smmstatic void
465238582Smmdt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)
466238582Smm{
467238582Smm	(void) fprintf(pap->pa_file, "{");
468238582Smm}
469238582Smm
470238582Smm/*
471238582Smm * For enums, we try to print the enum name, and fall back to the value if it
472238582Smm * can't be determined.  We do not do any fancy flag processing like mdb.
473238582Smm */
474238582Smm/* ARGSUSED */
475238582Smmstatic void
476238582Smmdt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
477238582Smm{
478238582Smm	FILE *fp = pap->pa_file;
479238582Smm	ctf_file_t *ctfp = pap->pa_ctfp;
480238582Smm	const char *ename;
481250485Spfg	ssize_t size;
482250485Spfg	caddr_t addr = pap->pa_addr + off / NBBY;
483238582Smm	int value = 0;
484238582Smm
485250485Spfg	/*
486250485Spfg	 * The C standard says that an enum will be at most the sizeof (int).
487250485Spfg	 * But if all the values are less than that, the compiler can use a
488250485Spfg	 * smaller size. Thanks standards.
489250485Spfg	 */
490250485Spfg	size = ctf_type_size(ctfp, base);
491250485Spfg	switch (size) {
492250485Spfg	case sizeof (uint8_t):
493250485Spfg		value = *(uint8_t *)addr;
494250485Spfg		break;
495250485Spfg	case sizeof (uint16_t):
496250485Spfg		value = *(uint16_t *)addr;
497250485Spfg		break;
498250485Spfg	case sizeof (int32_t):
499250485Spfg		value = *(int32_t *)addr;
500250485Spfg		break;
501250485Spfg	default:
502250485Spfg		(void) fprintf(fp, "<invalid enum size %u>", (uint_t)size);
503250485Spfg		return;
504250485Spfg	}
505250485Spfg
506238582Smm	if ((ename = ctf_enum_name(ctfp, base, value)) != NULL)
507238582Smm		(void) fprintf(fp, "%s", ename);
508238582Smm	else
509238582Smm		(void) fprintf(fp, "%d", value);
510238582Smm}
511238582Smm
512238582Smm/*
513238582Smm * Forward declaration.  There's not much to do here without the complete
514238582Smm * type information, so just print out this fact and drive on.
515238582Smm */
516238582Smm/* ARGSUSED */
517238582Smmstatic void
518238582Smmdt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
519238582Smm{
520238582Smm	(void) fprintf(pap->pa_file, "<forward decl>");
521238582Smm}
522238582Smm
523238582Smmtypedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);
524238582Smm
525238582Smmstatic dt_printarg_f *const dt_printfuncs[] = {
526238582Smm	dt_print_int,		/* CTF_K_INTEGER */
527238582Smm	dt_print_float,		/* CTF_K_FLOAT */
528238582Smm	dt_print_ptr,		/* CTF_K_POINTER */
529238582Smm	dt_print_array,		/* CTF_K_ARRAY */
530238582Smm	dt_print_ptr,		/* CTF_K_FUNCTION */
531238582Smm	dt_print_structlike,	/* CTF_K_STRUCT */
532238582Smm	dt_print_structlike,	/* CTF_K_UNION */
533238582Smm	dt_print_enum,		/* CTF_K_ENUM */
534238582Smm	dt_print_tag		/* CTF_K_FORWARD */
535238582Smm};
536238582Smm
537238582Smm/*
538238582Smm * Print one member of a structure.  This callback is invoked from
539238582Smm * ctf_type_visit() recursively.
540238582Smm */
541238582Smmstatic int
542238582Smmdt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth,
543238582Smm    void *data)
544238582Smm{
545238582Smm	char type[DT_TYPE_NAMELEN];
546238582Smm	int kind;
547238582Smm	dt_printarg_t *pap = data;
548238582Smm	FILE *fp = pap->pa_file;
549238582Smm	ctf_file_t *ctfp = pap->pa_ctfp;
550238582Smm	boolean_t arraymember;
551238582Smm	boolean_t brief;
552238582Smm	ctf_encoding_t e;
553238582Smm	ctf_id_t rtype;
554238582Smm
555238582Smm	dt_print_trailing_braces(pap, depth);
556238582Smm	/*
557238582Smm	 * dt_print_trailing_braces() doesn't include the trailing newline; add
558238582Smm	 * it here if necessary.
559238582Smm	 */
560238582Smm	if (depth < pap->pa_depth)
561238582Smm		(void) fprintf(fp, "\n");
562238582Smm	pap->pa_depth = depth;
563238582Smm
564238582Smm	if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
565238582Smm	    (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
566238582Smm	    kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
567238582Smm		dt_print_indent(pap);
568238582Smm		(void) fprintf(fp, "%s = <invalid type %lu>", name, id);
569238582Smm		return (0);
570238582Smm	}
571238582Smm
572238582Smm	dt_print_type_name(ctfp, id, type, sizeof (type));
573238582Smm
574238582Smm	arraymember = (pap->pa_nest != 0 && depth == 0);
575238582Smm	brief = (arraymember && !CTF_IS_STRUCTLIKE(kind));
576238582Smm
577238582Smm	if (!brief) {
578238582Smm		/*
579238582Smm		 * If this is a direct array member and a struct (otherwise
580238582Smm		 * brief would be true), then print a trailing newline, as the
581238582Smm		 * array printing code doesn't include it because it might be a
582238582Smm		 * simple type.
583238582Smm		 */
584238582Smm		if (arraymember)
585238582Smm			(void) fprintf(fp, "\n");
586238582Smm		dt_print_indent(pap);
587238582Smm
588238582Smm		/* always print the type */
589238582Smm		(void) fprintf(fp, "%s", type);
590238582Smm		if (name[0] != '\0') {
591238582Smm			/*
592238582Smm			 * For aesthetics, we don't include a space between the
593238582Smm			 * type name and member name if the type is a pointer.
594238582Smm			 * This will give us "void *foo =" instead of "void *
595238582Smm			 * foo =".  Unions also have the odd behavior that the
596238582Smm			 * type name is returned as "union ", with a trailing
597238582Smm			 * space, so we also avoid printing a space if the type
598238582Smm			 * name already ends with a space.
599238582Smm			 */
600238582Smm			if (type[strlen(type) - 1] != '*' &&
601238582Smm			    type[strlen(type) -1] != ' ') {
602238582Smm				(void) fprintf(fp, " ");
603238582Smm			}
604238582Smm			(void) fprintf(fp, "%s", name);
605238582Smm
606238582Smm			/*
607238582Smm			 * If this looks like a bitfield, or is an integer not
608238582Smm			 * aligned on a byte boundary, print the number of
609238582Smm			 * bits after the name.
610238582Smm			 */
611238582Smm			if (kind == CTF_K_INTEGER &&
612238582Smm			    ctf_type_encoding(ctfp, id, &e) == 0) {
613238582Smm				ulong_t bits = e.cte_bits;
614238582Smm				ulong_t size = bits / NBBY;
615238582Smm
616238582Smm				if (bits % NBBY != 0 ||
617238582Smm				    off % NBBY != 0 ||
618238582Smm				    size > 8 ||
619238582Smm				    size != ctf_type_size(ctfp, id)) {
620238582Smm					(void) fprintf(fp, " :%lu", bits);
621238582Smm				}
622238582Smm			}
623238582Smm
624238582Smm			(void) fprintf(fp, " =");
625238582Smm		}
626238582Smm		(void) fprintf(fp, " ");
627238582Smm	}
628238582Smm
629238582Smm	dt_printfuncs[kind - 1](rtype, off, pap);
630238582Smm
631238582Smm	/* direct simple array members are not separated by newlines */
632238582Smm	if (!brief)
633238582Smm		(void) fprintf(fp, "\n");
634238582Smm
635238582Smm	return (0);
636238582Smm}
637238582Smm
638238582Smm/*
639238582Smm * Main print function invoked by dt_consume_cpu().
640238582Smm */
641238582Smmint
642238582Smmdtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
643238582Smm    caddr_t addr, size_t len)
644238582Smm{
645238582Smm	const char *s;
646238582Smm	char *object;
647238582Smm	dt_printarg_t pa;
648238582Smm	ctf_id_t id;
649238582Smm	dt_module_t *dmp;
650238582Smm
651238582Smm	/*
652238582Smm	 * Split the fully-qualified type ID (module`id).  This should
653238582Smm	 * always be the format, but if for some reason we don't find the
654238582Smm	 * expected value, return 0 to fall back to the generic trace()
655238582Smm	 * behavior.
656238582Smm	 */
657238582Smm	for (s = typename; *s != '\0' && *s != '`'; s++)
658238582Smm		;
659238582Smm
660238582Smm	if (*s != '`')
661238582Smm		return (0);
662238582Smm
663238582Smm	object = alloca(s - typename + 1);
664238582Smm	bcopy(typename, object, s - typename);
665238582Smm	object[s - typename] = '\0';
666238582Smm	id = atoi(s + 1);
667238582Smm
668238582Smm	/*
669238582Smm	 * Try to get the CTF kind for this id.  If something has gone horribly
670238582Smm	 * wrong and we can't resolve the ID, bail out and let trace() do the
671238582Smm	 * work.
672238582Smm	 */
673238582Smm	dmp = dt_module_lookup_by_name(dtp, object);
674238582Smm	if (dmp == NULL || ctf_type_kind(dt_module_getctf(dtp, dmp),
675238582Smm	    id) == CTF_ERR) {
676238582Smm		return (0);
677238582Smm	}
678238582Smm
679238582Smm	/* setup the print structure and kick off the main print routine */
680250485Spfg	pa.pa_dtp = dtp;
681238582Smm	pa.pa_addr = addr;
682238582Smm	pa.pa_ctfp = dt_module_getctf(dtp, dmp);
683238582Smm	pa.pa_nest = 0;
684238582Smm	pa.pa_depth = 0;
685238582Smm	pa.pa_file = fp;
686238582Smm	(void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
687238582Smm
688238582Smm	dt_print_trailing_braces(&pa, 0);
689238582Smm
690238582Smm	return (len);
691238582Smm}
692