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