154727873SPedro F. Giffuni /*
254727873SPedro F. Giffuni  * CDDL HEADER START
354727873SPedro F. Giffuni  *
454727873SPedro F. Giffuni  * The contents of this file are subject to the terms of the
554727873SPedro F. Giffuni  * Common Development and Distribution License (the "License").
654727873SPedro F. Giffuni  * You may not use this file except in compliance with the License.
754727873SPedro F. Giffuni  *
854727873SPedro F. Giffuni  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
954727873SPedro F. Giffuni  * or http://www.opensolaris.org/os/licensing.
1054727873SPedro F. Giffuni  * See the License for the specific language governing permissions
1154727873SPedro F. Giffuni  * and limitations under the License.
1254727873SPedro F. Giffuni  *
1354727873SPedro F. Giffuni  * When distributing Covered Code, include this CDDL HEADER in each
1454727873SPedro F. Giffuni  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1554727873SPedro F. Giffuni  * If applicable, add the following below this CDDL HEADER, with the
1654727873SPedro F. Giffuni  * fields enclosed by brackets "[]" replaced with your own identifying
1754727873SPedro F. Giffuni  * information: Portions Copyright [yyyy] [name of copyright owner]
1854727873SPedro F. Giffuni  *
1954727873SPedro F. Giffuni  * CDDL HEADER END
2054727873SPedro F. Giffuni  */
2154727873SPedro F. Giffuni /*
2254727873SPedro F. Giffuni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2354727873SPedro F. Giffuni  * Use is subject to license terms.
2454727873SPedro F. Giffuni  */
2554727873SPedro F. Giffuni /*
2654727873SPedro F. Giffuni  * Copyright (c) 2011 by Delphix. All rights reserved.
2754727873SPedro F. Giffuni  */
28acc92950SPedro F. Giffuni /*
29acc92950SPedro F. Giffuni  * Copyright (c) 2013, Joyent, Inc.  All rights reserved.
3093f27766SDomagoj Stolfa  * Copyright (c) 2023, Domagoj Stolfa. All rights reserved.
31acc92950SPedro F. Giffuni  */
3254727873SPedro F. Giffuni 
3354727873SPedro F. Giffuni /*
3454727873SPedro F. Giffuni  * DTrace print() action
3554727873SPedro F. Giffuni  *
3654727873SPedro F. Giffuni  * This file contains the post-processing logic for the print() action.  The
3754727873SPedro F. Giffuni  * print action behaves identically to trace() in that it generates a
3854727873SPedro F. Giffuni  * DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type
3954727873SPedro F. Giffuni  * string stored in the DOF string table (similar to printf formats).  We
4054727873SPedro F. Giffuni  * take the result of the trace action and post-process it in the fashion of
4154727873SPedro F. Giffuni  * MDB's ::print dcmd.
4254727873SPedro F. Giffuni  *
4354727873SPedro F. Giffuni  * This implementation differs from MDB's in the following ways:
4454727873SPedro F. Giffuni  *
4554727873SPedro F. Giffuni  * 	- We do not expose any options or flags.  The behavior of print() is
4654727873SPedro F. Giffuni  *	  equivalent to "::print -tn".
4754727873SPedro F. Giffuni  *
4854727873SPedro F. Giffuni  * 	- MDB will display "holes" in structures (unused padding between
4954727873SPedro F. Giffuni  *	  members).
5054727873SPedro F. Giffuni  *
5154727873SPedro F. Giffuni  * 	- When printing arrays of structures, MDB will leave a trailing ','
5254727873SPedro F. Giffuni  *	  after the last element.
5354727873SPedro F. Giffuni  *
5454727873SPedro F. Giffuni  *	- MDB will print time_t types as date and time.
5554727873SPedro F. Giffuni  *
5654727873SPedro F. Giffuni  *	- MDB will detect when an enum is actually the OR of several flags,
5754727873SPedro F. Giffuni  *	  and print it out with the constituent flags separated.
5854727873SPedro F. Giffuni  *
5954727873SPedro F. Giffuni  *	- For large arrays, MDB will print the first few members and then
6054727873SPedro F. Giffuni  *	  print a "..." continuation line.
6154727873SPedro F. Giffuni  *
6254727873SPedro F. Giffuni  *	- MDB will break and wrap arrays at 80 columns.
6354727873SPedro F. Giffuni  *
6454727873SPedro F. Giffuni  *	- MDB prints out floats and doubles by hand, as it must run in kmdb
6554727873SPedro F. Giffuni  *	  context.  We're able to leverage the printf() format strings,
6654727873SPedro F. Giffuni  *	  but the result is a slightly different format.
6754727873SPedro F. Giffuni  */
6854727873SPedro F. Giffuni 
6954727873SPedro F. Giffuni #include <sys/sysmacros.h>
7054727873SPedro F. Giffuni #include <strings.h>
7154727873SPedro F. Giffuni #include <stdlib.h>
7254727873SPedro F. Giffuni #include <alloca.h>
7354727873SPedro F. Giffuni #include <assert.h>
7454727873SPedro F. Giffuni #include <ctype.h>
7554727873SPedro F. Giffuni #include <errno.h>
7654727873SPedro F. Giffuni #include <limits.h>
7754727873SPedro F. Giffuni #include <sys/socket.h>
7854727873SPedro F. Giffuni #include <netdb.h>
7954727873SPedro F. Giffuni #include <netinet/in.h>
8054727873SPedro F. Giffuni #include <arpa/inet.h>
8154727873SPedro F. Giffuni 
8254727873SPedro F. Giffuni #include <dt_module.h>
8354727873SPedro F. Giffuni #include <dt_printf.h>
8454727873SPedro F. Giffuni #include <dt_string.h>
8554727873SPedro F. Giffuni #include <dt_impl.h>
8693f27766SDomagoj Stolfa #include <dt_oformat.h>
8754727873SPedro F. Giffuni 
8854727873SPedro F. Giffuni /* determines whether the given integer CTF encoding is a character */
8954727873SPedro F. Giffuni #define	CTF_IS_CHAR(e) \
9054727873SPedro F. Giffuni 	(((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \
9154727873SPedro F. Giffuni 	(CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)
9254727873SPedro F. Giffuni /* determines whether the given CTF kind is a struct or union */
9354727873SPedro F. Giffuni #define	CTF_IS_STRUCTLIKE(k) \
9454727873SPedro F. Giffuni 	((k) == CTF_K_STRUCT || (k) == CTF_K_UNION)
9554727873SPedro F. Giffuni 
9654727873SPedro F. Giffuni /*
9754727873SPedro F. Giffuni  * Print structure passed down recursively through printing algorithm.
9854727873SPedro F. Giffuni  */
9954727873SPedro F. Giffuni typedef struct dt_printarg {
100acc92950SPedro F. Giffuni 	dtrace_hdl_t	*pa_dtp;	/* libdtrace handle */
10154727873SPedro F. Giffuni 	caddr_t		pa_addr;	/* base address of trace data */
10254727873SPedro F. Giffuni 	ctf_file_t	*pa_ctfp;	/* CTF container */
10354727873SPedro F. Giffuni 	int		pa_depth;	/* member depth */
10454727873SPedro F. Giffuni 	int		pa_nest;	/* nested array depth */
10554727873SPedro F. Giffuni 	FILE		*pa_file;	/* output file */
10693f27766SDomagoj Stolfa 	const char	*pa_object;	/* object name */
10754727873SPedro F. Giffuni } dt_printarg_t;
10854727873SPedro F. Giffuni 
10993f27766SDomagoj Stolfa static int dt_format_member(const char *, ctf_id_t, ulong_t, int, void *);
11054727873SPedro F. Giffuni static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);
11154727873SPedro F. Giffuni 
11254727873SPedro F. Giffuni /*
11354727873SPedro F. Giffuni  * Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it
11454727873SPedro F. Giffuni  * can't resolve the type.
11554727873SPedro F. Giffuni  */
11654727873SPedro F. Giffuni static void
dt_print_type_name(ctf_file_t * ctfp,ctf_id_t id,char * buf,size_t buflen)11754727873SPedro F. Giffuni dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen)
11854727873SPedro F. Giffuni {
11954727873SPedro F. Giffuni 	if (ctf_type_name(ctfp, id, buf, buflen) == NULL)
12054727873SPedro F. Giffuni 		(void) snprintf(buf, buflen, "<%ld>", id);
12154727873SPedro F. Giffuni }
12254727873SPedro F. Giffuni 
12354727873SPedro F. Giffuni /*
12454727873SPedro F. Giffuni  * Print any necessary trailing braces for structures or unions.  We don't get
12554727873SPedro F. Giffuni  * invoked when a struct or union ends, so we infer the need to print braces
12654727873SPedro F. Giffuni  * based on the depth the last time we printed something and the new depth.
12754727873SPedro F. Giffuni  */
12854727873SPedro F. Giffuni static void
dt_print_trailing_braces(dt_printarg_t * pap,int depth)12954727873SPedro F. Giffuni dt_print_trailing_braces(dt_printarg_t *pap, int depth)
13054727873SPedro F. Giffuni {
13154727873SPedro F. Giffuni 	int d;
13254727873SPedro F. Giffuni 
13354727873SPedro F. Giffuni 	for (d = pap->pa_depth; d > depth; d--) {
13454727873SPedro F. Giffuni 		(void) fprintf(pap->pa_file, "%*s}%s",
13554727873SPedro F. Giffuni 		    (d + pap->pa_nest - 1) * 4, "",
13654727873SPedro F. Giffuni 		    d == depth + 1 ? "" : "\n");
13754727873SPedro F. Giffuni 	}
13854727873SPedro F. Giffuni }
13954727873SPedro F. Giffuni 
14054727873SPedro F. Giffuni /*
14154727873SPedro F. Giffuni  * Print the appropriate amount of indentation given the current depth and
14254727873SPedro F. Giffuni  * array nesting.
14354727873SPedro F. Giffuni  */
14454727873SPedro F. Giffuni static void
dt_print_indent(dt_printarg_t * pap)14554727873SPedro F. Giffuni dt_print_indent(dt_printarg_t *pap)
14654727873SPedro F. Giffuni {
14754727873SPedro F. Giffuni 	(void) fprintf(pap->pa_file, "%*s",
14854727873SPedro F. Giffuni 	    (pap->pa_depth + pap->pa_nest) * 4, "");
14954727873SPedro F. Giffuni }
15054727873SPedro F. Giffuni 
15154727873SPedro F. Giffuni /*
15254727873SPedro F. Giffuni  * Print a bitfield.  It's worth noting that the D compiler support for
15354727873SPedro F. Giffuni  * bitfields is currently broken; printing "D`user_desc_t" (pulled in by the
15454727873SPedro F. Giffuni  * various D provider files) will produce incorrect results compared to
15554727873SPedro F. Giffuni  * "genunix`user_desc_t".
15654727873SPedro F. Giffuni  */
15754727873SPedro F. Giffuni static void
print_bitfield(dt_printarg_t * pap,ulong_t off,ctf_encoding_t * ep)15854727873SPedro F. Giffuni print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)
15954727873SPedro F. Giffuni {
16054727873SPedro F. Giffuni 	FILE *fp = pap->pa_file;
16154727873SPedro F. Giffuni 	caddr_t addr = pap->pa_addr + off / NBBY;
16254727873SPedro F. Giffuni 	uint64_t mask = (1ULL << ep->cte_bits) - 1;
16354727873SPedro F. Giffuni 	uint64_t value = 0;
16454727873SPedro F. Giffuni 	size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;
16554727873SPedro F. Giffuni 	uint8_t *buf = (uint8_t *)&value;
16654727873SPedro F. Giffuni 	uint8_t shift;
16754727873SPedro F. Giffuni 
16854727873SPedro F. Giffuni 	/*
16954727873SPedro F. Giffuni 	 * On big-endian machines, we need to adjust the buf pointer to refer
17054727873SPedro F. Giffuni 	 * to the lowest 'size' bytes in 'value', and we need to shift based on
17154727873SPedro F. Giffuni 	 * the offset from the end of the data, not the offset of the start.
17254727873SPedro F. Giffuni 	 */
1736574b8edSMark Johnston #if BYTE_ORDER == _BIG_ENDIAN
17454727873SPedro F. Giffuni 	buf += sizeof (value) - size;
17554727873SPedro F. Giffuni 	off += ep->cte_bits;
17654727873SPedro F. Giffuni #endif
17754727873SPedro F. Giffuni 	bcopy(addr, buf, size);
17854727873SPedro F. Giffuni 	shift = off % NBBY;
17954727873SPedro F. Giffuni 
18054727873SPedro F. Giffuni 	/*
18154727873SPedro F. Giffuni 	 * Offsets are counted from opposite ends on little- and
18254727873SPedro F. Giffuni 	 * big-endian machines.
18354727873SPedro F. Giffuni 	 */
1846574b8edSMark Johnston #if BYTE_ORDER == _BIG_ENDIAN
18554727873SPedro F. Giffuni 	shift = NBBY - shift;
18654727873SPedro F. Giffuni #endif
18754727873SPedro F. Giffuni 
18854727873SPedro F. Giffuni 	/*
18954727873SPedro F. Giffuni 	 * If the bits we want do not begin on a byte boundary, shift the data
19054727873SPedro F. Giffuni 	 * right so that the value is in the lowest 'cte_bits' of 'value'.
19154727873SPedro F. Giffuni 	 */
19254727873SPedro F. Giffuni 	if (off % NBBY != 0)
19354727873SPedro F. Giffuni 		value >>= shift;
19454727873SPedro F. Giffuni 	value &= mask;
19554727873SPedro F. Giffuni 
19693f27766SDomagoj Stolfa 	xo_emit("{:value/%#llx}", (u_longlong_t)value);
19793f27766SDomagoj Stolfa 
19893f27766SDomagoj Stolfa 	/* Flush in order to ensure output is aligned properly */
19993f27766SDomagoj Stolfa 	xo_flush();
20054727873SPedro F. Giffuni }
20154727873SPedro F. Giffuni 
20254727873SPedro F. Giffuni /*
20354727873SPedro F. Giffuni  * Dump the contents of memory as a fixed-size integer in hex.
20454727873SPedro F. Giffuni  */
20554727873SPedro F. Giffuni static void
dt_print_hex(FILE * fp,caddr_t addr,size_t size)20654727873SPedro F. Giffuni dt_print_hex(FILE *fp, caddr_t addr, size_t size)
20754727873SPedro F. Giffuni {
20854727873SPedro F. Giffuni 	switch (size) {
20954727873SPedro F. Giffuni 	case sizeof (uint8_t):
21093f27766SDomagoj Stolfa 		xo_emit("{:value/%#x}", *(uint8_t *)addr);
21154727873SPedro F. Giffuni 		break;
21254727873SPedro F. Giffuni 	case sizeof (uint16_t):
21393f27766SDomagoj Stolfa 		xo_emit("{:value/%#x}", *(uint16_t *)addr);
21454727873SPedro F. Giffuni 		break;
21554727873SPedro F. Giffuni 	case sizeof (uint32_t):
21693f27766SDomagoj Stolfa 		xo_emit("{:value/%#x}", *(uint32_t *)addr);
21754727873SPedro F. Giffuni 		break;
21854727873SPedro F. Giffuni 	case sizeof (uint64_t):
21993f27766SDomagoj Stolfa 		xo_emit("{:value/%#llx}",
22054727873SPedro F. Giffuni 		    (unsigned long long)*(uint64_t *)addr);
22154727873SPedro F. Giffuni 		break;
22254727873SPedro F. Giffuni 	default:
22393f27766SDomagoj Stolfa 		xo_emit("<{:warning} {:size/%u}>", "invalid size",
22493f27766SDomagoj Stolfa 		    (uint_t)size);
22554727873SPedro F. Giffuni 	}
22693f27766SDomagoj Stolfa 
22793f27766SDomagoj Stolfa 	/* Flush in order to ensure output is aligned properly */
22893f27766SDomagoj Stolfa 	xo_flush();
22954727873SPedro F. Giffuni }
23054727873SPedro F. Giffuni 
23154727873SPedro F. Giffuni /*
23254727873SPedro F. Giffuni  * Print an integer type.  Before dumping the contents via dt_print_hex(), we
23354727873SPedro F. Giffuni  * first check the encoding to see if it's part of a bitfield or a character.
23454727873SPedro F. Giffuni  */
23554727873SPedro F. Giffuni static void
dt_print_int(ctf_id_t base,ulong_t off,dt_printarg_t * pap)23654727873SPedro F. Giffuni dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
23754727873SPedro F. Giffuni {
23854727873SPedro F. Giffuni 	FILE *fp = pap->pa_file;
23954727873SPedro F. Giffuni 	ctf_file_t *ctfp = pap->pa_ctfp;
24093f27766SDomagoj Stolfa 	dtrace_hdl_t *dtp = pap->pa_dtp;
24154727873SPedro F. Giffuni 	ctf_encoding_t e;
24254727873SPedro F. Giffuni 	size_t size;
24354727873SPedro F. Giffuni 	caddr_t addr = pap->pa_addr + off / NBBY;
24454727873SPedro F. Giffuni 
24554727873SPedro F. Giffuni 	if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {
24693f27766SDomagoj Stolfa 		xo_emit("<{:warning}>", "unknown encoding");
24793f27766SDomagoj Stolfa 
24893f27766SDomagoj Stolfa 		/* Flush in order to ensure output is aligned properly */
24993f27766SDomagoj Stolfa 		xo_flush();
25054727873SPedro F. Giffuni 		return;
25154727873SPedro F. Giffuni 	}
25254727873SPedro F. Giffuni 
25354727873SPedro F. Giffuni 	/*
25454727873SPedro F. Giffuni 	 * This comes from MDB - it's not clear under what circumstances this
25554727873SPedro F. Giffuni 	 * would be found.
25654727873SPedro F. Giffuni 	 */
25754727873SPedro F. Giffuni 	if (e.cte_format & CTF_INT_VARARGS) {
25893f27766SDomagoj Stolfa 		if (!dtp->dt_oformat)
25954727873SPedro F. Giffuni 			(void)fprintf(fp, "...");
26054727873SPedro F. Giffuni 		return;
26154727873SPedro F. Giffuni 	}
26254727873SPedro F. Giffuni 
26354727873SPedro F. Giffuni 	/*
26454727873SPedro F. Giffuni 	 * We print this as a bitfield if the bit encoding indicates it's not
26554727873SPedro F. Giffuni 	 * an even power of two byte size, or is larger than 8 bytes.
26654727873SPedro F. Giffuni 	 */
26754727873SPedro F. Giffuni 	size = e.cte_bits / NBBY;
26854727873SPedro F. Giffuni 	if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {
26954727873SPedro F. Giffuni 		print_bitfield(pap, off, &e);
27054727873SPedro F. Giffuni 		return;
27154727873SPedro F. Giffuni 	}
27254727873SPedro F. Giffuni 
27354727873SPedro F. Giffuni 	/*
27454727873SPedro F. Giffuni 	 * If this is a character, print it out as such.
27554727873SPedro F. Giffuni 	 */
27654727873SPedro F. Giffuni 	if (CTF_IS_CHAR(e)) {
27754727873SPedro F. Giffuni 		char c = *(char *)addr;
27854727873SPedro F. Giffuni 		if (isprint(c))
27993f27766SDomagoj Stolfa 			xo_emit("'{:value/%c}'", c);
28054727873SPedro F. Giffuni 		else if (c == 0)
28193f27766SDomagoj Stolfa 			xo_emit("'\\{:value/0}'");
28254727873SPedro F. Giffuni 		else
28393f27766SDomagoj Stolfa 			xo_emit("'\\{:value/%03o}'", c);
28493f27766SDomagoj Stolfa 
28593f27766SDomagoj Stolfa 		/* Flush in order to ensure output is aligned properly */
28693f27766SDomagoj Stolfa 		xo_flush();
28754727873SPedro F. Giffuni 		return;
28854727873SPedro F. Giffuni 	}
28954727873SPedro F. Giffuni 
29054727873SPedro F. Giffuni 	dt_print_hex(fp, addr, size);
29154727873SPedro F. Giffuni }
29254727873SPedro F. Giffuni 
29354727873SPedro F. Giffuni /*
29454727873SPedro F. Giffuni  * Print a floating point (float, double, long double) value.
29554727873SPedro F. Giffuni  */
29654727873SPedro F. Giffuni /* ARGSUSED */
29754727873SPedro F. Giffuni static void
dt_print_float(ctf_id_t base,ulong_t off,dt_printarg_t * pap)29854727873SPedro F. Giffuni dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
29954727873SPedro F. Giffuni {
30054727873SPedro F. Giffuni 	FILE *fp = pap->pa_file;
30154727873SPedro F. Giffuni 	ctf_file_t *ctfp = pap->pa_ctfp;
30254727873SPedro F. Giffuni 	ctf_encoding_t e;
30354727873SPedro F. Giffuni 	caddr_t addr = pap->pa_addr + off / NBBY;
30493f27766SDomagoj Stolfa 	dtrace_hdl_t *dtp = pap->pa_dtp;
30554727873SPedro F. Giffuni 
30654727873SPedro F. Giffuni 	if (ctf_type_encoding(ctfp, base, &e) == 0) {
30754727873SPedro F. Giffuni 		if (e.cte_format == CTF_FP_SINGLE &&
30854727873SPedro F. Giffuni 		    e.cte_bits == sizeof (float) * NBBY) {
30993f27766SDomagoj Stolfa 			xo_emit("{:value/%+.7e}", *((float *)addr));
31054727873SPedro F. Giffuni 		} else if (e.cte_format == CTF_FP_DOUBLE &&
31154727873SPedro F. Giffuni 		    e.cte_bits == sizeof (double) * NBBY) {
31293f27766SDomagoj Stolfa 			xo_emit("{:value/%+.7e}", *((double *)addr));
31354727873SPedro F. Giffuni 		} else if (e.cte_format == CTF_FP_LDOUBLE &&
31454727873SPedro F. Giffuni 		    e.cte_bits == sizeof (long double) * NBBY) {
31593f27766SDomagoj Stolfa 			xo_emit("{:value/%+.16LE}", *((long double *)addr));
31654727873SPedro F. Giffuni 		} else {
31793f27766SDomagoj Stolfa 			xo_emit("<{:warning}>", "unknown encoding");
31854727873SPedro F. Giffuni 		}
31954727873SPedro F. Giffuni 	}
32054727873SPedro F. Giffuni }
32154727873SPedro F. Giffuni 
32254727873SPedro F. Giffuni /*
323acc92950SPedro F. Giffuni  * A pointer is generally printed as a fixed-size integer.  If we have a
324acc92950SPedro F. Giffuni  * function pointer, we try to look up its name.
32554727873SPedro F. Giffuni  */
32654727873SPedro F. Giffuni static void
dt_print_ptr(ctf_id_t base,ulong_t off,dt_printarg_t * pap)32754727873SPedro F. Giffuni dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
32854727873SPedro F. Giffuni {
32954727873SPedro F. Giffuni 	FILE *fp = pap->pa_file;
33054727873SPedro F. Giffuni 	ctf_file_t *ctfp = pap->pa_ctfp;
33154727873SPedro F. Giffuni 	caddr_t addr = pap->pa_addr + off / NBBY;
33254727873SPedro F. Giffuni 	size_t size = ctf_type_size(ctfp, base);
333acc92950SPedro F. Giffuni 	ctf_id_t bid = ctf_type_reference(ctfp, base);
334acc92950SPedro F. Giffuni 	uint64_t pc;
335acc92950SPedro F. Giffuni 	dtrace_syminfo_t dts;
336acc92950SPedro F. Giffuni 	GElf_Sym sym;
33754727873SPedro F. Giffuni 
338acc92950SPedro F. Giffuni 	if (bid == CTF_ERR || ctf_type_kind(ctfp, bid) != CTF_K_FUNCTION) {
33954727873SPedro F. Giffuni 		dt_print_hex(fp, addr, size);
340acc92950SPedro F. Giffuni 	} else {
341acc92950SPedro F. Giffuni 		/* LINTED - alignment */
342acc92950SPedro F. Giffuni 		pc = *((uint64_t *)addr);
343acc92950SPedro F. Giffuni 		if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) {
344acc92950SPedro F. Giffuni 			dt_print_hex(fp, addr, size);
345acc92950SPedro F. Giffuni 		} else {
34693f27766SDomagoj Stolfa 			xo_emit("{:value/%s`%s}", dts.dts_object, dts.dts_name);
347acc92950SPedro F. Giffuni 		}
348acc92950SPedro F. Giffuni 	}
34954727873SPedro F. Giffuni }
35054727873SPedro F. Giffuni 
35154727873SPedro F. Giffuni /*
35254727873SPedro F. Giffuni  * Print out an array.  This is somewhat complex, as we must manually visit
35354727873SPedro F. Giffuni  * each member, and recursively invoke ctf_type_visit() for each member.  If
35454727873SPedro F. Giffuni  * the members are non-structs, then we print them out directly:
35554727873SPedro F. Giffuni  *
35654727873SPedro F. Giffuni  * 	[ 0x14, 0x2e, 0 ]
35754727873SPedro F. Giffuni  *
35854727873SPedro F. Giffuni  * If they are structs, then we print out the necessary leading and trailing
35954727873SPedro F. Giffuni  * braces, to end up with:
36054727873SPedro F. Giffuni  *
36154727873SPedro F. Giffuni  *	[
36254727873SPedro F. Giffuni  *	    type {
36354727873SPedro F. Giffuni  *	    ...
36454727873SPedro F. Giffuni  *	    },
36554727873SPedro F. Giffuni  *	    type {
36654727873SPedro F. Giffuni  *	    ...
36754727873SPedro F. Giffuni  *	    }
36854727873SPedro F. Giffuni  *	]
36954727873SPedro F. Giffuni  *
37054727873SPedro F. Giffuni  * We also use a heuristic to detect whether the array looks like a character
37154727873SPedro F. Giffuni  * array.  If the encoding indicates it's a character, and we have all
37254727873SPedro F. Giffuni  * printable characters followed by a null byte, then we display it as a
37354727873SPedro F. Giffuni  * string:
37454727873SPedro F. Giffuni  *
37554727873SPedro F. Giffuni  *	[ "string" ]
37654727873SPedro F. Giffuni  */
37754727873SPedro F. Giffuni static void
dt_print_array(ctf_id_t base,ulong_t off,dt_printarg_t * pap)37854727873SPedro F. Giffuni dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
37954727873SPedro F. Giffuni {
38054727873SPedro F. Giffuni 	FILE *fp = pap->pa_file;
38154727873SPedro F. Giffuni 	ctf_file_t *ctfp = pap->pa_ctfp;
38254727873SPedro F. Giffuni 	caddr_t addr = pap->pa_addr + off / NBBY;
38393f27766SDomagoj Stolfa 	char *str;
38454727873SPedro F. Giffuni 	ctf_arinfo_t car;
38554727873SPedro F. Giffuni 	ssize_t eltsize;
38654727873SPedro F. Giffuni 	ctf_encoding_t e;
38754727873SPedro F. Giffuni 	int i;
38854727873SPedro F. Giffuni 	boolean_t isstring;
38954727873SPedro F. Giffuni 	int kind;
39054727873SPedro F. Giffuni 	ctf_id_t rtype;
39193f27766SDomagoj Stolfa 	dtrace_hdl_t *dtp = pap->pa_dtp;
39254727873SPedro F. Giffuni 
39354727873SPedro F. Giffuni 	if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {
39493f27766SDomagoj Stolfa 		xo_emit("{:value/%p}", (void *)addr);
39554727873SPedro F. Giffuni 		return;
39654727873SPedro F. Giffuni 	}
39754727873SPedro F. Giffuni 
39854727873SPedro F. Giffuni 	if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||
39954727873SPedro F. Giffuni 	    (rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||
40054727873SPedro F. Giffuni 	    (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {
40193f27766SDomagoj Stolfa 		xo_emit("<{:warning} {:type-identifier/%lu}>", "invalid type",
40293f27766SDomagoj Stolfa 		    car.ctr_contents);
40354727873SPedro F. Giffuni 		return;
40454727873SPedro F. Giffuni 	}
40554727873SPedro F. Giffuni 
40654727873SPedro F. Giffuni 	/* see if this looks like a string */
40754727873SPedro F. Giffuni 	isstring = B_FALSE;
40854727873SPedro F. Giffuni 	if (kind == CTF_K_INTEGER &&
40954727873SPedro F. Giffuni 	    ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) {
41054727873SPedro F. Giffuni 		char c;
41154727873SPedro F. Giffuni 		for (i = 0; i < car.ctr_nelems; i++) {
41254727873SPedro F. Giffuni 			c = *((char *)addr + eltsize * i);
41354727873SPedro F. Giffuni 			if (!isprint(c) || c == '\0')
41454727873SPedro F. Giffuni 				break;
41554727873SPedro F. Giffuni 		}
41654727873SPedro F. Giffuni 
41754727873SPedro F. Giffuni 		if (i != car.ctr_nelems && c == '\0')
41854727873SPedro F. Giffuni 			isstring = B_TRUE;
41954727873SPedro F. Giffuni 	}
42054727873SPedro F. Giffuni 
42154727873SPedro F. Giffuni 	/*
42254727873SPedro F. Giffuni 	 * As a slight aesthetic optimization, if we are a top-level type, then
42354727873SPedro F. Giffuni 	 * don't bother printing out the brackets.  This lets print("foo") look
42454727873SPedro F. Giffuni 	 * like:
42554727873SPedro F. Giffuni 	 *
42654727873SPedro F. Giffuni 	 * 	string "foo"
42754727873SPedro F. Giffuni 	 *
42854727873SPedro F. Giffuni 	 * As D will internally represent this as a char[256] array.
42954727873SPedro F. Giffuni 	 */
43093f27766SDomagoj Stolfa 	if (dtp->dt_oformat) {
43193f27766SDomagoj Stolfa 		if (!isstring)
43293f27766SDomagoj Stolfa 			xo_open_list("value");
43393f27766SDomagoj Stolfa 		else {
43493f27766SDomagoj Stolfa 			str = malloc(car.ctr_nelems);
43593f27766SDomagoj Stolfa 			if (str == NULL)
43693f27766SDomagoj Stolfa 				return;
43793f27766SDomagoj Stolfa 			*str = 0;
43893f27766SDomagoj Stolfa 		}
43993f27766SDomagoj Stolfa 	} else {
44054727873SPedro F. Giffuni 		if (!isstring || pap->pa_depth != 0)
44154727873SPedro F. Giffuni 			(void)fprintf(fp, "[ ");
44254727873SPedro F. Giffuni 
44354727873SPedro F. Giffuni 		if (isstring)
44454727873SPedro F. Giffuni 			(void)fprintf(fp, "\"");
44593f27766SDomagoj Stolfa 	}
44654727873SPedro F. Giffuni 
44754727873SPedro F. Giffuni 	for (i = 0; i < car.ctr_nelems; i++) {
44854727873SPedro F. Giffuni 		if (isstring) {
44954727873SPedro F. Giffuni 			char c = *((char *)addr + eltsize * i);
45093f27766SDomagoj Stolfa 			if (c == '\0') {
45193f27766SDomagoj Stolfa 				if (dtp->dt_oformat)
45293f27766SDomagoj Stolfa 					str[i] = 0;
45354727873SPedro F. Giffuni 				break;
45493f27766SDomagoj Stolfa 			}
45593f27766SDomagoj Stolfa 
45693f27766SDomagoj Stolfa 			if (dtp->dt_oformat)
45793f27766SDomagoj Stolfa 				str[i] = c;
45893f27766SDomagoj Stolfa 			else
45954727873SPedro F. Giffuni 				(void)fprintf(fp, "%c", c);
46093f27766SDomagoj Stolfa 		} else if (dtp->dt_oformat) {
46193f27766SDomagoj Stolfa 			dt_printarg_t pa = *pap;
46293f27766SDomagoj Stolfa 			pa.pa_nest += pap->pa_depth + 1;
46393f27766SDomagoj Stolfa 			pa.pa_depth = 0;
46493f27766SDomagoj Stolfa 			pa.pa_addr = addr + eltsize * i;
46593f27766SDomagoj Stolfa 
46693f27766SDomagoj Stolfa 			(void) ctf_type_visit(ctfp, car.ctr_contents,
46793f27766SDomagoj Stolfa 			    dt_format_member, &pa);
46854727873SPedro F. Giffuni 		} else {
46954727873SPedro F. Giffuni 			/*
47054727873SPedro F. Giffuni 			 * Recursively invoke ctf_type_visit() on each member.
47154727873SPedro F. Giffuni 			 * We setup a new printarg struct with 'pa_nest' set to
47254727873SPedro F. Giffuni 			 * indicate that we are within a nested array.
47354727873SPedro F. Giffuni 			 */
47454727873SPedro F. Giffuni 			dt_printarg_t pa = *pap;
47554727873SPedro F. Giffuni 			pa.pa_nest += pap->pa_depth + 1;
47654727873SPedro F. Giffuni 			pa.pa_depth = 0;
47754727873SPedro F. Giffuni 			pa.pa_addr = addr + eltsize * i;
47854727873SPedro F. Giffuni 			(void) ctf_type_visit(ctfp, car.ctr_contents,
47954727873SPedro F. Giffuni 			    dt_print_member, &pa);
48054727873SPedro F. Giffuni 
48154727873SPedro F. Giffuni 			dt_print_trailing_braces(&pa, 0);
48254727873SPedro F. Giffuni 			if (i != car.ctr_nelems - 1)
48354727873SPedro F. Giffuni 				(void) fprintf(fp, ", ");
48454727873SPedro F. Giffuni 			else if (CTF_IS_STRUCTLIKE(kind))
48554727873SPedro F. Giffuni 				(void) fprintf(fp, "\n");
48654727873SPedro F. Giffuni 		}
48754727873SPedro F. Giffuni 	}
48854727873SPedro F. Giffuni 
48993f27766SDomagoj Stolfa 	if (dtp->dt_oformat) {
49093f27766SDomagoj Stolfa 		if (!isstring)
49193f27766SDomagoj Stolfa 			xo_close_list("value");
49293f27766SDomagoj Stolfa 		else {
49393f27766SDomagoj Stolfa 			xo_emit("{:value/%s}", str);
49493f27766SDomagoj Stolfa 			free(str);
49593f27766SDomagoj Stolfa 		}
49693f27766SDomagoj Stolfa 	} else {
49754727873SPedro F. Giffuni 		if (isstring)
49854727873SPedro F. Giffuni 			(void)fprintf(fp, "\"");
49954727873SPedro F. Giffuni 
50054727873SPedro F. Giffuni 		if (!isstring || pap->pa_depth != 0) {
50154727873SPedro F. Giffuni 			if (CTF_IS_STRUCTLIKE(kind))
50254727873SPedro F. Giffuni 				dt_print_indent(pap);
50354727873SPedro F. Giffuni 			else
50454727873SPedro F. Giffuni 				(void)fprintf(fp, " ");
50554727873SPedro F. Giffuni 			(void)fprintf(fp, "]");
50654727873SPedro F. Giffuni 		}
50754727873SPedro F. Giffuni 	}
50893f27766SDomagoj Stolfa }
50954727873SPedro F. Giffuni 
51054727873SPedro F. Giffuni /*
51154727873SPedro F. Giffuni  * This isued by both structs and unions to print the leading brace.
51254727873SPedro F. Giffuni  */
51354727873SPedro F. Giffuni /* ARGSUSED */
51454727873SPedro F. Giffuni static void
dt_print_structlike(ctf_id_t id,ulong_t off,dt_printarg_t * pap)51554727873SPedro F. Giffuni dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)
51654727873SPedro F. Giffuni {
51793f27766SDomagoj Stolfa 	if (pap->pa_dtp->dt_oformat == DTRACE_OFORMAT_TEXT)
51854727873SPedro F. Giffuni 		(void)fprintf(pap->pa_file, "{");
51954727873SPedro F. Giffuni }
52054727873SPedro F. Giffuni 
52154727873SPedro F. Giffuni /*
52254727873SPedro F. Giffuni  * For enums, we try to print the enum name, and fall back to the value if it
52354727873SPedro F. Giffuni  * can't be determined.  We do not do any fancy flag processing like mdb.
52454727873SPedro F. Giffuni  */
52554727873SPedro F. Giffuni /* ARGSUSED */
52654727873SPedro F. Giffuni static void
dt_print_enum(ctf_id_t base,ulong_t off,dt_printarg_t * pap)52754727873SPedro F. Giffuni dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
52854727873SPedro F. Giffuni {
52954727873SPedro F. Giffuni 	FILE *fp = pap->pa_file;
53054727873SPedro F. Giffuni 	ctf_file_t *ctfp = pap->pa_ctfp;
53154727873SPedro F. Giffuni 	const char *ename;
532acc92950SPedro F. Giffuni 	ssize_t size;
533acc92950SPedro F. Giffuni 	caddr_t addr = pap->pa_addr + off / NBBY;
53454727873SPedro F. Giffuni 	int value = 0;
53593f27766SDomagoj Stolfa 	dtrace_hdl_t *dtp = pap->pa_dtp;
53654727873SPedro F. Giffuni 
537acc92950SPedro F. Giffuni 	/*
538acc92950SPedro F. Giffuni 	 * The C standard says that an enum will be at most the sizeof (int).
539acc92950SPedro F. Giffuni 	 * But if all the values are less than that, the compiler can use a
540acc92950SPedro F. Giffuni 	 * smaller size. Thanks standards.
541acc92950SPedro F. Giffuni 	 */
542acc92950SPedro F. Giffuni 	size = ctf_type_size(ctfp, base);
543acc92950SPedro F. Giffuni 	switch (size) {
544acc92950SPedro F. Giffuni 	case sizeof (uint8_t):
545acc92950SPedro F. Giffuni 		value = *(uint8_t *)addr;
546acc92950SPedro F. Giffuni 		break;
547acc92950SPedro F. Giffuni 	case sizeof (uint16_t):
548acc92950SPedro F. Giffuni 		value = *(uint16_t *)addr;
549acc92950SPedro F. Giffuni 		break;
550acc92950SPedro F. Giffuni 	case sizeof (int32_t):
551acc92950SPedro F. Giffuni 		value = *(int32_t *)addr;
552acc92950SPedro F. Giffuni 		break;
553acc92950SPedro F. Giffuni 	default:
55493f27766SDomagoj Stolfa 		xo_emit("<{:warning} {:size/%u}>", "invalid enum size",
55593f27766SDomagoj Stolfa 		    (uint_t)size);
556acc92950SPedro F. Giffuni 		return;
557acc92950SPedro F. Giffuni 	}
558acc92950SPedro F. Giffuni 
55993f27766SDomagoj Stolfa 	if ((ename = ctf_enum_name(ctfp, base, value)) != NULL) {
56093f27766SDomagoj Stolfa 		xo_emit("{:value/%s}", ename);
56193f27766SDomagoj Stolfa 	} else {
56293f27766SDomagoj Stolfa 		xo_emit("{:value/%d}", value);
56393f27766SDomagoj Stolfa 	}
56493f27766SDomagoj Stolfa 
56593f27766SDomagoj Stolfa 	/* Flush in order to ensure output is aligned properly */
56693f27766SDomagoj Stolfa 	xo_flush();
56754727873SPedro F. Giffuni }
56854727873SPedro F. Giffuni 
56954727873SPedro F. Giffuni /*
57054727873SPedro F. Giffuni  * Forward declaration.  There's not much to do here without the complete
57154727873SPedro F. Giffuni  * type information, so just print out this fact and drive on.
57254727873SPedro F. Giffuni  */
57354727873SPedro F. Giffuni /* ARGSUSED */
57454727873SPedro F. Giffuni static void
dt_print_tag(ctf_id_t base,ulong_t off,dt_printarg_t * pap)57554727873SPedro F. Giffuni dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)
57654727873SPedro F. Giffuni {
57793f27766SDomagoj Stolfa 	if (pap->pa_dtp->dt_oformat == DTRACE_OFORMAT_TEXT)
57854727873SPedro F. Giffuni 		(void)fprintf(pap->pa_file, "<forward decl>");
57954727873SPedro F. Giffuni }
58054727873SPedro F. Giffuni 
58154727873SPedro F. Giffuni typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);
58254727873SPedro F. Giffuni 
58354727873SPedro F. Giffuni static dt_printarg_f *const dt_printfuncs[] = {
58454727873SPedro F. Giffuni 	dt_print_int,		/* CTF_K_INTEGER */
58554727873SPedro F. Giffuni 	dt_print_float,		/* CTF_K_FLOAT */
58654727873SPedro F. Giffuni 	dt_print_ptr,		/* CTF_K_POINTER */
58754727873SPedro F. Giffuni 	dt_print_array,		/* CTF_K_ARRAY */
58854727873SPedro F. Giffuni 	dt_print_ptr,		/* CTF_K_FUNCTION */
58954727873SPedro F. Giffuni 	dt_print_structlike,	/* CTF_K_STRUCT */
59054727873SPedro F. Giffuni 	dt_print_structlike,	/* CTF_K_UNION */
59154727873SPedro F. Giffuni 	dt_print_enum,		/* CTF_K_ENUM */
59254727873SPedro F. Giffuni 	dt_print_tag		/* CTF_K_FORWARD */
59354727873SPedro F. Giffuni };
59454727873SPedro F. Giffuni 
59593f27766SDomagoj Stolfa static int
dt_format_member(const char * name,ctf_id_t id,ulong_t off,int depth,void * data)59693f27766SDomagoj Stolfa dt_format_member(const char *name, ctf_id_t id, ulong_t off, int depth,
59793f27766SDomagoj Stolfa     void *data)
59893f27766SDomagoj Stolfa {
59993f27766SDomagoj Stolfa 	char type[DT_TYPE_NAMELEN];
60093f27766SDomagoj Stolfa 	int kind;
60193f27766SDomagoj Stolfa 	dt_printarg_t *pap = data;
60293f27766SDomagoj Stolfa 	FILE *fp = pap->pa_file;
60393f27766SDomagoj Stolfa 	ctf_file_t *ctfp = pap->pa_ctfp;
60493f27766SDomagoj Stolfa 	boolean_t arraymember;
60593f27766SDomagoj Stolfa 	boolean_t brief;
60693f27766SDomagoj Stolfa 	ctf_encoding_t e;
60793f27766SDomagoj Stolfa 	ctf_id_t rtype;
60893f27766SDomagoj Stolfa 
60993f27766SDomagoj Stolfa 	if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
61093f27766SDomagoj Stolfa 	    (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
61193f27766SDomagoj Stolfa 	    kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
61293f27766SDomagoj Stolfa 		xo_emit("{:name/%s} <{:warning} {:type-identifier/%lu}>"
61393f27766SDomagoj Stolfa 			" {:value/0x%llx}",
61493f27766SDomagoj Stolfa 		    name, "invalid type", id, pap->pa_addr);
61593f27766SDomagoj Stolfa 		return (0);
61693f27766SDomagoj Stolfa 	}
61793f27766SDomagoj Stolfa 
61893f27766SDomagoj Stolfa 	dt_print_type_name(ctfp, id, type, sizeof (type));
61993f27766SDomagoj Stolfa 	xo_open_instance("type");
62093f27766SDomagoj Stolfa 	if (pap->pa_object) {
62193f27766SDomagoj Stolfa 		xo_emit("{:object-name/%s}", pap->pa_object);
62293f27766SDomagoj Stolfa 		/* Clear the object to avoid duplication */
62393f27766SDomagoj Stolfa 		pap->pa_object = NULL;
62493f27766SDomagoj Stolfa 	}
62593f27766SDomagoj Stolfa 
62693f27766SDomagoj Stolfa 	if (*name != 0)
62793f27766SDomagoj Stolfa 		xo_emit("{:member-name/%s}", name);
62893f27766SDomagoj Stolfa 	xo_emit("{:name/%s} {:ctfid/%ld}", type, id);
62993f27766SDomagoj Stolfa 	dt_printfuncs[kind - 1](rtype, off, pap);
63093f27766SDomagoj Stolfa 
63193f27766SDomagoj Stolfa 	xo_close_instance("type");
63293f27766SDomagoj Stolfa 	return (0);
63393f27766SDomagoj Stolfa }
63493f27766SDomagoj Stolfa 
63554727873SPedro F. Giffuni /*
63654727873SPedro F. Giffuni  * Print one member of a structure.  This callback is invoked from
63754727873SPedro F. Giffuni  * ctf_type_visit() recursively.
63854727873SPedro F. Giffuni  */
63954727873SPedro F. Giffuni static int
dt_print_member(const char * name,ctf_id_t id,ulong_t off,int depth,void * data)64054727873SPedro F. Giffuni dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth,
64154727873SPedro F. Giffuni     void *data)
64254727873SPedro F. Giffuni {
64354727873SPedro F. Giffuni 	char type[DT_TYPE_NAMELEN];
64454727873SPedro F. Giffuni 	int kind;
64554727873SPedro F. Giffuni 	dt_printarg_t *pap = data;
64654727873SPedro F. Giffuni 	FILE *fp = pap->pa_file;
64754727873SPedro F. Giffuni 	ctf_file_t *ctfp = pap->pa_ctfp;
64854727873SPedro F. Giffuni 	boolean_t arraymember;
64954727873SPedro F. Giffuni 	boolean_t brief;
65054727873SPedro F. Giffuni 	ctf_encoding_t e;
65154727873SPedro F. Giffuni 	ctf_id_t rtype;
65254727873SPedro F. Giffuni 
65354727873SPedro F. Giffuni 	dt_print_trailing_braces(pap, depth);
65454727873SPedro F. Giffuni 	/*
65554727873SPedro F. Giffuni 	 * dt_print_trailing_braces() doesn't include the trailing newline; add
65654727873SPedro F. Giffuni 	 * it here if necessary.
65754727873SPedro F. Giffuni 	 */
65854727873SPedro F. Giffuni 	if (depth < pap->pa_depth)
65954727873SPedro F. Giffuni 		(void) fprintf(fp, "\n");
66054727873SPedro F. Giffuni 	pap->pa_depth = depth;
66154727873SPedro F. Giffuni 
66254727873SPedro F. Giffuni 	if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||
66354727873SPedro F. Giffuni 	    (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||
66454727873SPedro F. Giffuni 	    kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {
66554727873SPedro F. Giffuni 		dt_print_indent(pap);
66654727873SPedro F. Giffuni 		(void) fprintf(fp, "%s = <invalid type %lu>", name, id);
66754727873SPedro F. Giffuni 		return (0);
66854727873SPedro F. Giffuni 	}
66954727873SPedro F. Giffuni 
67054727873SPedro F. Giffuni 	dt_print_type_name(ctfp, id, type, sizeof (type));
67154727873SPedro F. Giffuni 
67254727873SPedro F. Giffuni 	arraymember = (pap->pa_nest != 0 && depth == 0);
67354727873SPedro F. Giffuni 	brief = (arraymember && !CTF_IS_STRUCTLIKE(kind));
67454727873SPedro F. Giffuni 
67554727873SPedro F. Giffuni 	if (!brief) {
67654727873SPedro F. Giffuni 		/*
67754727873SPedro F. Giffuni 		 * If this is a direct array member and a struct (otherwise
67854727873SPedro F. Giffuni 		 * brief would be true), then print a trailing newline, as the
67954727873SPedro F. Giffuni 		 * array printing code doesn't include it because it might be a
68054727873SPedro F. Giffuni 		 * simple type.
68154727873SPedro F. Giffuni 		 */
68254727873SPedro F. Giffuni 		if (arraymember)
68354727873SPedro F. Giffuni 			(void) fprintf(fp, "\n");
68454727873SPedro F. Giffuni 		dt_print_indent(pap);
68554727873SPedro F. Giffuni 
68654727873SPedro F. Giffuni 		/* always print the type */
68754727873SPedro F. Giffuni 		(void) fprintf(fp, "%s", type);
68854727873SPedro F. Giffuni 		if (name[0] != '\0') {
68954727873SPedro F. Giffuni 			/*
69054727873SPedro F. Giffuni 			 * For aesthetics, we don't include a space between the
69154727873SPedro F. Giffuni 			 * type name and member name if the type is a pointer.
69254727873SPedro F. Giffuni 			 * This will give us "void *foo =" instead of "void *
69354727873SPedro F. Giffuni 			 * foo =".  Unions also have the odd behavior that the
69454727873SPedro F. Giffuni 			 * type name is returned as "union ", with a trailing
69554727873SPedro F. Giffuni 			 * space, so we also avoid printing a space if the type
69654727873SPedro F. Giffuni 			 * name already ends with a space.
69754727873SPedro F. Giffuni 			 */
69854727873SPedro F. Giffuni 			if (type[strlen(type) - 1] != '*' &&
69954727873SPedro F. Giffuni 			    type[strlen(type) -1] != ' ') {
70054727873SPedro F. Giffuni 				(void) fprintf(fp, " ");
70154727873SPedro F. Giffuni 			}
70254727873SPedro F. Giffuni 			(void) fprintf(fp, "%s", name);
70354727873SPedro F. Giffuni 
70454727873SPedro F. Giffuni 			/*
70554727873SPedro F. Giffuni 			 * If this looks like a bitfield, or is an integer not
70654727873SPedro F. Giffuni 			 * aligned on a byte boundary, print the number of
70754727873SPedro F. Giffuni 			 * bits after the name.
70854727873SPedro F. Giffuni 			 */
70954727873SPedro F. Giffuni 			if (kind == CTF_K_INTEGER &&
71054727873SPedro F. Giffuni 			    ctf_type_encoding(ctfp, id, &e) == 0) {
71154727873SPedro F. Giffuni 				ulong_t bits = e.cte_bits;
71254727873SPedro F. Giffuni 				ulong_t size = bits / NBBY;
71354727873SPedro F. Giffuni 
71454727873SPedro F. Giffuni 				if (bits % NBBY != 0 ||
71554727873SPedro F. Giffuni 				    off % NBBY != 0 ||
71654727873SPedro F. Giffuni 				    size > 8 ||
71754727873SPedro F. Giffuni 				    size != ctf_type_size(ctfp, id)) {
71854727873SPedro F. Giffuni 					(void) fprintf(fp, " :%lu", bits);
71954727873SPedro F. Giffuni 				}
72054727873SPedro F. Giffuni 			}
72154727873SPedro F. Giffuni 
72254727873SPedro F. Giffuni 			(void) fprintf(fp, " =");
72354727873SPedro F. Giffuni 		}
72454727873SPedro F. Giffuni 		(void) fprintf(fp, " ");
72554727873SPedro F. Giffuni 	}
72654727873SPedro F. Giffuni 
72754727873SPedro F. Giffuni 	dt_printfuncs[kind - 1](rtype, off, pap);
72854727873SPedro F. Giffuni 
72954727873SPedro F. Giffuni 	/* direct simple array members are not separated by newlines */
73054727873SPedro F. Giffuni 	if (!brief)
73154727873SPedro F. Giffuni 		(void) fprintf(fp, "\n");
73254727873SPedro F. Giffuni 
73354727873SPedro F. Giffuni 	return (0);
73454727873SPedro F. Giffuni }
73554727873SPedro F. Giffuni 
73693f27766SDomagoj Stolfa static ctf_id_t
dt_print_prepare(dtrace_hdl_t * dtp,const char * typename,caddr_t addr,size_t len,dt_printarg_t * pa)73793f27766SDomagoj Stolfa dt_print_prepare(dtrace_hdl_t *dtp, const char *typename, caddr_t addr,
73893f27766SDomagoj Stolfa     size_t len, dt_printarg_t *pa)
73954727873SPedro F. Giffuni {
74054727873SPedro F. Giffuni 	const char *s;
74154727873SPedro F. Giffuni 	char *object;
74254727873SPedro F. Giffuni 	ctf_id_t id;
74354727873SPedro F. Giffuni 	dt_module_t *dmp;
7448e648814SRui Paulo 	ctf_file_t *ctfp;
7458e648814SRui Paulo 	int libid;
74654727873SPedro F. Giffuni 
74754727873SPedro F. Giffuni 	/*
74854727873SPedro F. Giffuni 	 * Split the fully-qualified type ID (module`id).  This should
74954727873SPedro F. Giffuni 	 * always be the format, but if for some reason we don't find the
75054727873SPedro F. Giffuni 	 * expected value, return 0 to fall back to the generic trace()
7518e648814SRui Paulo 	 * behavior. In the case of userland CTF modules this will actually be
7528e648814SRui Paulo 	 * of the format (module`lib`id). This is due to the fact that those
7538e648814SRui Paulo 	 * modules have multiple CTF containers which `lib` identifies.
75454727873SPedro F. Giffuni 	 */
75554727873SPedro F. Giffuni 	for (s = typename; *s != '\0' && *s != '`'; s++)
75654727873SPedro F. Giffuni 		;
75754727873SPedro F. Giffuni 
75854727873SPedro F. Giffuni 	if (*s != '`')
75993f27766SDomagoj Stolfa 		return (CTF_ERR);
76054727873SPedro F. Giffuni 
76154727873SPedro F. Giffuni 	object = alloca(s - typename + 1);
76254727873SPedro F. Giffuni 	bcopy(typename, object, s - typename);
76354727873SPedro F. Giffuni 	object[s - typename] = '\0';
7648e648814SRui Paulo 	dmp = dt_module_lookup_by_name(dtp, object);
7658e648814SRui Paulo 	if (dmp == NULL)
76693f27766SDomagoj Stolfa 		return (CTF_ERR);
7678e648814SRui Paulo 
7688e648814SRui Paulo 	if (dmp->dm_pid != 0) {
7698e648814SRui Paulo 		libid = atoi(s + 1);
7708e648814SRui Paulo 		s = strchr(s + 1, '`');
7718e648814SRui Paulo 		if (s == NULL || libid > dmp->dm_nctflibs)
77293f27766SDomagoj Stolfa 			return (CTF_ERR);
7738e648814SRui Paulo 		ctfp = dmp->dm_libctfp[libid];
7748e648814SRui Paulo 	} else {
7758e648814SRui Paulo 		ctfp = dt_module_getctf(dtp, dmp);
7768e648814SRui Paulo 	}
7778e648814SRui Paulo 
77854727873SPedro F. Giffuni 	id = atoi(s + 1);
77954727873SPedro F. Giffuni 
78054727873SPedro F. Giffuni 	/*
78154727873SPedro F. Giffuni 	 * Try to get the CTF kind for this id.  If something has gone horribly
78254727873SPedro F. Giffuni 	 * wrong and we can't resolve the ID, bail out and let trace() do the
78354727873SPedro F. Giffuni 	 * work.
78454727873SPedro F. Giffuni 	 */
7858e648814SRui Paulo 	if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR)
78693f27766SDomagoj Stolfa 		return (CTF_ERR);
78793f27766SDomagoj Stolfa 
78893f27766SDomagoj Stolfa 	pa->pa_dtp = dtp;
78993f27766SDomagoj Stolfa 	pa->pa_addr = addr;
79093f27766SDomagoj Stolfa 	pa->pa_ctfp = ctfp;
79193f27766SDomagoj Stolfa 	pa->pa_nest = 0;
79293f27766SDomagoj Stolfa 	pa->pa_depth = 0;
79393f27766SDomagoj Stolfa 	pa->pa_object = strdup(object);
79493f27766SDomagoj Stolfa 	return (id);
79593f27766SDomagoj Stolfa }
79693f27766SDomagoj Stolfa 
79793f27766SDomagoj Stolfa /*
79893f27766SDomagoj Stolfa  * Main print function invoked by dt_consume_cpu().
79993f27766SDomagoj Stolfa  */
80093f27766SDomagoj Stolfa int
dtrace_print(dtrace_hdl_t * dtp,FILE * fp,const char * typename,caddr_t addr,size_t len)80193f27766SDomagoj Stolfa dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
80293f27766SDomagoj Stolfa     caddr_t addr, size_t len)
80393f27766SDomagoj Stolfa {
80493f27766SDomagoj Stolfa 	dt_printarg_t pa;
80593f27766SDomagoj Stolfa 	ctf_id_t id;
80693f27766SDomagoj Stolfa 
80793f27766SDomagoj Stolfa 	id = dt_print_prepare(dtp, typename, addr, len, &pa);
80893f27766SDomagoj Stolfa 	if (id == CTF_ERR)
80954727873SPedro F. Giffuni 		return (0);
81054727873SPedro F. Giffuni 
81154727873SPedro F. Giffuni 	pa.pa_file = fp;
81254727873SPedro F. Giffuni 	(void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);
81354727873SPedro F. Giffuni 
81454727873SPedro F. Giffuni 	dt_print_trailing_braces(&pa, 0);
81593f27766SDomagoj Stolfa 	dt_free(dtp, (void *)pa.pa_object);
81654727873SPedro F. Giffuni 
81754727873SPedro F. Giffuni 	return (len);
81854727873SPedro F. Giffuni }
81993f27766SDomagoj Stolfa 
82093f27766SDomagoj Stolfa /*
82193f27766SDomagoj Stolfa  * Main format function invoked by dt_consume_cpu().
82293f27766SDomagoj Stolfa  */
82393f27766SDomagoj Stolfa int
dtrace_format_print(dtrace_hdl_t * dtp,FILE * fp,const char * typename,caddr_t addr,size_t len)82493f27766SDomagoj Stolfa dtrace_format_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,
82593f27766SDomagoj Stolfa     caddr_t addr, size_t len)
82693f27766SDomagoj Stolfa {
82793f27766SDomagoj Stolfa 	dt_printarg_t pa;
82893f27766SDomagoj Stolfa 	ctf_id_t id;
82993f27766SDomagoj Stolfa 	char toplevel[1024];
83093f27766SDomagoj Stolfa 
83193f27766SDomagoj Stolfa 	id = dt_print_prepare(dtp, typename, addr, len, &pa);
83293f27766SDomagoj Stolfa 	if (id == CTF_ERR)
83393f27766SDomagoj Stolfa 		return (0);
83493f27766SDomagoj Stolfa 
83593f27766SDomagoj Stolfa 	if (ctf_type_name(pa.pa_ctfp, id, toplevel, sizeof(toplevel)) < 0)
83693f27766SDomagoj Stolfa 		return (0);
83793f27766SDomagoj Stolfa 
83893f27766SDomagoj Stolfa 	xo_open_list("type");
83993f27766SDomagoj Stolfa 	(void) ctf_type_visit(pa.pa_ctfp, id, dt_format_member, &pa);
84093f27766SDomagoj Stolfa 	xo_close_list("type");
84193f27766SDomagoj Stolfa 	dt_free(dtp, (void *)pa.pa_object);
84293f27766SDomagoj Stolfa 
84393f27766SDomagoj Stolfa 	return (len);
84493f27766SDomagoj Stolfa }
84593f27766SDomagoj Stolfa 
846