Path: blob/main/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
39562 views
/*1* CDDL HEADER START2*3* The contents of this file are subject to the terms of the4* Common Development and Distribution License (the "License").5* You may not use this file except in compliance with the License.6*7* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE8* or http://www.opensolaris.org/os/licensing.9* See the License for the specific language governing permissions10* and limitations under the License.11*12* When distributing Covered Code, include this CDDL HEADER in each13* file and include the License file at usr/src/OPENSOLARIS.LICENSE.14* If applicable, add the following below this CDDL HEADER, with the15* fields enclosed by brackets "[]" replaced with your own identifying16* information: Portions Copyright [yyyy] [name of copyright owner]17*18* CDDL HEADER END19*/20/*21* Copyright 2009 Sun Microsystems, Inc. All rights reserved.22* Use is subject to license terms.23*/24/*25* Copyright (c) 2011 by Delphix. All rights reserved.26*/27/*28* Copyright (c) 2013, Joyent, Inc. All rights reserved.29* Copyright (c) 2023, Domagoj Stolfa. All rights reserved.30*/3132/*33* DTrace print() action34*35* This file contains the post-processing logic for the print() action. The36* print action behaves identically to trace() in that it generates a37* DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type38* string stored in the DOF string table (similar to printf formats). We39* take the result of the trace action and post-process it in the fashion of40* MDB's ::print dcmd.41*42* This implementation differs from MDB's in the following ways:43*44* - We do not expose any options or flags. The behavior of print() is45* equivalent to "::print -tn".46*47* - MDB will display "holes" in structures (unused padding between48* members).49*50* - When printing arrays of structures, MDB will leave a trailing ','51* after the last element.52*53* - MDB will print time_t types as date and time.54*55* - MDB will detect when an enum is actually the OR of several flags,56* and print it out with the constituent flags separated.57*58* - For large arrays, MDB will print the first few members and then59* print a "..." continuation line.60*61* - MDB will break and wrap arrays at 80 columns.62*63* - MDB prints out floats and doubles by hand, as it must run in kmdb64* context. We're able to leverage the printf() format strings,65* but the result is a slightly different format.66*/6768#include <sys/sysmacros.h>69#include <strings.h>70#include <stdlib.h>71#include <alloca.h>72#include <assert.h>73#include <ctype.h>74#include <errno.h>75#include <limits.h>76#include <sys/socket.h>77#include <netdb.h>78#include <netinet/in.h>79#include <arpa/inet.h>8081#include <dt_module.h>82#include <dt_printf.h>83#include <dt_string.h>84#include <dt_impl.h>85#include <dt_oformat.h>8687/* determines whether the given integer CTF encoding is a character */88#define CTF_IS_CHAR(e) \89(((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \90(CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY)91/* determines whether the given CTF kind is a struct or union */92#define CTF_IS_STRUCTLIKE(k) \93((k) == CTF_K_STRUCT || (k) == CTF_K_UNION)9495/*96* Print structure passed down recursively through printing algorithm.97*/98typedef struct dt_printarg {99dtrace_hdl_t *pa_dtp; /* libdtrace handle */100caddr_t pa_addr; /* base address of trace data */101ctf_file_t *pa_ctfp; /* CTF container */102int pa_depth; /* member depth */103int pa_nest; /* nested array depth */104FILE *pa_file; /* output file */105const char *pa_object; /* object name */106} dt_printarg_t;107108static int dt_format_member(const char *, ctf_id_t, ulong_t, int, void *);109static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *);110111/*112* Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it113* can't resolve the type.114*/115static void116dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen)117{118if (ctf_type_name(ctfp, id, buf, buflen) == NULL)119(void) snprintf(buf, buflen, "<%ld>", id);120}121122/*123* Print any necessary trailing braces for structures or unions. We don't get124* invoked when a struct or union ends, so we infer the need to print braces125* based on the depth the last time we printed something and the new depth.126*/127static void128dt_print_trailing_braces(dt_printarg_t *pap, int depth)129{130int d;131132for (d = pap->pa_depth; d > depth; d--) {133(void) fprintf(pap->pa_file, "%*s}%s",134(d + pap->pa_nest - 1) * 4, "",135d == depth + 1 ? "" : "\n");136}137}138139/*140* Print the appropriate amount of indentation given the current depth and141* array nesting.142*/143static void144dt_print_indent(dt_printarg_t *pap)145{146(void) fprintf(pap->pa_file, "%*s",147(pap->pa_depth + pap->pa_nest) * 4, "");148}149150/*151* Print a bitfield. It's worth noting that the D compiler support for152* bitfields is currently broken; printing "D`user_desc_t" (pulled in by the153* various D provider files) will produce incorrect results compared to154* "genunix`user_desc_t".155*/156static void157print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep)158{159FILE *fp = pap->pa_file;160caddr_t addr = pap->pa_addr + off / NBBY;161uint64_t mask = (1ULL << ep->cte_bits) - 1;162uint64_t value = 0;163size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY;164uint8_t *buf = (uint8_t *)&value;165uint8_t shift;166167/*168* On big-endian machines, we need to adjust the buf pointer to refer169* to the lowest 'size' bytes in 'value', and we need to shift based on170* the offset from the end of the data, not the offset of the start.171*/172#if BYTE_ORDER == _BIG_ENDIAN173buf += sizeof (value) - size;174off += ep->cte_bits;175#endif176bcopy(addr, buf, size);177shift = off % NBBY;178179/*180* Offsets are counted from opposite ends on little- and181* big-endian machines.182*/183#if BYTE_ORDER == _BIG_ENDIAN184shift = NBBY - shift;185#endif186187/*188* If the bits we want do not begin on a byte boundary, shift the data189* right so that the value is in the lowest 'cte_bits' of 'value'.190*/191if (off % NBBY != 0)192value >>= shift;193value &= mask;194195xo_emit("{:value/%#llx}", (u_longlong_t)value);196197/* Flush in order to ensure output is aligned properly */198xo_flush();199}200201/*202* Dump the contents of memory as a fixed-size integer in hex.203*/204static void205dt_print_hex(FILE *fp, caddr_t addr, size_t size)206{207switch (size) {208case sizeof (uint8_t):209xo_emit("{:value/%#x}", *(uint8_t *)addr);210break;211case sizeof (uint16_t):212xo_emit("{:value/%#x}", *(uint16_t *)addr);213break;214case sizeof (uint32_t):215xo_emit("{:value/%#x}", *(uint32_t *)addr);216break;217case sizeof (uint64_t):218xo_emit("{:value/%#llx}",219(unsigned long long)*(uint64_t *)addr);220break;221default:222xo_emit("<{:warning} {:size/%u}>", "invalid size",223(uint_t)size);224}225226/* Flush in order to ensure output is aligned properly */227xo_flush();228}229230/*231* Print an integer type. Before dumping the contents via dt_print_hex(), we232* first check the encoding to see if it's part of a bitfield or a character.233*/234static void235dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap)236{237FILE *fp = pap->pa_file;238ctf_file_t *ctfp = pap->pa_ctfp;239dtrace_hdl_t *dtp = pap->pa_dtp;240ctf_encoding_t e;241size_t size;242caddr_t addr = pap->pa_addr + off / NBBY;243244if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) {245xo_emit("<{:warning}>", "unknown encoding");246247/* Flush in order to ensure output is aligned properly */248xo_flush();249return;250}251252/*253* This comes from MDB - it's not clear under what circumstances this254* would be found.255*/256if (e.cte_format & CTF_INT_VARARGS) {257if (!dtp->dt_oformat)258(void)fprintf(fp, "...");259return;260}261262/*263* We print this as a bitfield if the bit encoding indicates it's not264* an even power of two byte size, or is larger than 8 bytes.265*/266size = e.cte_bits / NBBY;267if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) {268print_bitfield(pap, off, &e);269return;270}271272/*273* If this is a character, print it out as such.274*/275if (CTF_IS_CHAR(e)) {276char c = *(char *)addr;277if (isprint(c))278xo_emit("'{:value/%c}'", c);279else if (c == 0)280xo_emit("'\\{:value/0}'");281else282xo_emit("'\\{:value/%03o}'", c);283284/* Flush in order to ensure output is aligned properly */285xo_flush();286return;287}288289dt_print_hex(fp, addr, size);290}291292/*293* Print a floating point (float, double, long double) value.294*/295/* ARGSUSED */296static void297dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap)298{299FILE *fp = pap->pa_file;300ctf_file_t *ctfp = pap->pa_ctfp;301ctf_encoding_t e;302caddr_t addr = pap->pa_addr + off / NBBY;303dtrace_hdl_t *dtp = pap->pa_dtp;304305if (ctf_type_encoding(ctfp, base, &e) == 0) {306if (e.cte_format == CTF_FP_SINGLE &&307e.cte_bits == sizeof (float) * NBBY) {308xo_emit("{:value/%+.7e}", *((float *)addr));309} else if (e.cte_format == CTF_FP_DOUBLE &&310e.cte_bits == sizeof (double) * NBBY) {311xo_emit("{:value/%+.7e}", *((double *)addr));312} else if (e.cte_format == CTF_FP_LDOUBLE &&313e.cte_bits == sizeof (long double) * NBBY) {314xo_emit("{:value/%+.16LE}", *((long double *)addr));315} else {316xo_emit("<{:warning}>", "unknown encoding");317}318}319}320321/*322* A pointer is generally printed as a fixed-size integer. If we have a323* function pointer, we try to look up its name.324*/325static void326dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap)327{328FILE *fp = pap->pa_file;329ctf_file_t *ctfp = pap->pa_ctfp;330caddr_t addr = pap->pa_addr + off / NBBY;331size_t size = ctf_type_size(ctfp, base);332ctf_id_t bid = ctf_type_reference(ctfp, base);333uint64_t pc;334dtrace_syminfo_t dts;335GElf_Sym sym;336337if (bid == CTF_ERR || ctf_type_kind(ctfp, bid) != CTF_K_FUNCTION) {338dt_print_hex(fp, addr, size);339} else {340/* LINTED - alignment */341pc = *((uint64_t *)addr);342if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) {343dt_print_hex(fp, addr, size);344} else {345xo_emit("{:value/%s`%s}", dts.dts_object, dts.dts_name);346}347}348}349350/*351* Print out an array. This is somewhat complex, as we must manually visit352* each member, and recursively invoke ctf_type_visit() for each member. If353* the members are non-structs, then we print them out directly:354*355* [ 0x14, 0x2e, 0 ]356*357* If they are structs, then we print out the necessary leading and trailing358* braces, to end up with:359*360* [361* type {362* ...363* },364* type {365* ...366* }367* ]368*369* We also use a heuristic to detect whether the array looks like a character370* array. If the encoding indicates it's a character, and we have all371* printable characters followed by a null byte, then we display it as a372* string:373*374* [ "string" ]375*/376static void377dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap)378{379FILE *fp = pap->pa_file;380ctf_file_t *ctfp = pap->pa_ctfp;381caddr_t addr = pap->pa_addr + off / NBBY;382char *str;383ctf_arinfo_t car;384ssize_t eltsize;385ctf_encoding_t e;386int i;387boolean_t isstring;388int kind;389ctf_id_t rtype;390dtrace_hdl_t *dtp = pap->pa_dtp;391392if (ctf_array_info(ctfp, base, &car) == CTF_ERR) {393xo_emit("{:value/%p}", (void *)addr);394return;395}396397if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 ||398(rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR ||399(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) {400xo_emit("<{:warning} {:type-identifier/%lu}>", "invalid type",401car.ctr_contents);402return;403}404405/* see if this looks like a string */406isstring = B_FALSE;407if (kind == CTF_K_INTEGER &&408ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) {409char c;410for (i = 0; i < car.ctr_nelems; i++) {411c = *((char *)addr + eltsize * i);412if (!isprint(c) || c == '\0')413break;414}415416if (i != car.ctr_nelems && c == '\0')417isstring = B_TRUE;418}419420/*421* As a slight aesthetic optimization, if we are a top-level type, then422* don't bother printing out the brackets. This lets print("foo") look423* like:424*425* string "foo"426*427* As D will internally represent this as a char[256] array.428*/429if (dtp->dt_oformat) {430if (!isstring)431xo_open_list("value");432else {433str = malloc(car.ctr_nelems);434if (str == NULL)435return;436*str = 0;437}438} else {439if (!isstring || pap->pa_depth != 0)440(void)fprintf(fp, "[ ");441442if (isstring)443(void)fprintf(fp, "\"");444}445446for (i = 0; i < car.ctr_nelems; i++) {447if (isstring) {448char c = *((char *)addr + eltsize * i);449if (c == '\0') {450if (dtp->dt_oformat)451str[i] = 0;452break;453}454455if (dtp->dt_oformat)456str[i] = c;457else458(void)fprintf(fp, "%c", c);459} else if (dtp->dt_oformat) {460dt_printarg_t pa = *pap;461pa.pa_nest += pap->pa_depth + 1;462pa.pa_depth = 0;463pa.pa_addr = addr + eltsize * i;464465(void) ctf_type_visit(ctfp, car.ctr_contents,466dt_format_member, &pa);467} else {468/*469* Recursively invoke ctf_type_visit() on each member.470* We setup a new printarg struct with 'pa_nest' set to471* indicate that we are within a nested array.472*/473dt_printarg_t pa = *pap;474pa.pa_nest += pap->pa_depth + 1;475pa.pa_depth = 0;476pa.pa_addr = addr + eltsize * i;477(void) ctf_type_visit(ctfp, car.ctr_contents,478dt_print_member, &pa);479480dt_print_trailing_braces(&pa, 0);481if (i != car.ctr_nelems - 1)482(void) fprintf(fp, ", ");483else if (CTF_IS_STRUCTLIKE(kind))484(void) fprintf(fp, "\n");485}486}487488if (dtp->dt_oformat) {489if (!isstring)490xo_close_list("value");491else {492xo_emit("{:value/%s}", str);493free(str);494}495} else {496if (isstring)497(void)fprintf(fp, "\"");498499if (!isstring || pap->pa_depth != 0) {500if (CTF_IS_STRUCTLIKE(kind))501dt_print_indent(pap);502else503(void)fprintf(fp, " ");504(void)fprintf(fp, "]");505}506}507}508509/*510* This isued by both structs and unions to print the leading brace.511*/512/* ARGSUSED */513static void514dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap)515{516if (pap->pa_dtp->dt_oformat == DTRACE_OFORMAT_TEXT)517(void)fprintf(pap->pa_file, "{");518}519520/*521* For enums, we try to print the enum name, and fall back to the value if it522* can't be determined. We do not do any fancy flag processing like mdb.523*/524/* ARGSUSED */525static void526dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap)527{528FILE *fp = pap->pa_file;529ctf_file_t *ctfp = pap->pa_ctfp;530const char *ename;531ssize_t size;532caddr_t addr = pap->pa_addr + off / NBBY;533int value = 0;534dtrace_hdl_t *dtp = pap->pa_dtp;535536/*537* The C standard says that an enum will be at most the sizeof (int).538* But if all the values are less than that, the compiler can use a539* smaller size. Thanks standards.540*/541size = ctf_type_size(ctfp, base);542switch (size) {543case sizeof (uint8_t):544value = *(uint8_t *)addr;545break;546case sizeof (uint16_t):547value = *(uint16_t *)addr;548break;549case sizeof (int32_t):550value = *(int32_t *)addr;551break;552default:553xo_emit("<{:warning} {:size/%u}>", "invalid enum size",554(uint_t)size);555return;556}557558if ((ename = ctf_enum_name(ctfp, base, value)) != NULL) {559xo_emit("{:value/%s}", ename);560} else {561xo_emit("{:value/%d}", value);562}563564/* Flush in order to ensure output is aligned properly */565xo_flush();566}567568/*569* Forward declaration. There's not much to do here without the complete570* type information, so just print out this fact and drive on.571*/572/* ARGSUSED */573static void574dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap)575{576if (pap->pa_dtp->dt_oformat == DTRACE_OFORMAT_TEXT)577(void)fprintf(pap->pa_file, "<forward decl>");578}579580typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *);581582static dt_printarg_f *const dt_printfuncs[] = {583dt_print_int, /* CTF_K_INTEGER */584dt_print_float, /* CTF_K_FLOAT */585dt_print_ptr, /* CTF_K_POINTER */586dt_print_array, /* CTF_K_ARRAY */587dt_print_ptr, /* CTF_K_FUNCTION */588dt_print_structlike, /* CTF_K_STRUCT */589dt_print_structlike, /* CTF_K_UNION */590dt_print_enum, /* CTF_K_ENUM */591dt_print_tag /* CTF_K_FORWARD */592};593594static int595dt_format_member(const char *name, ctf_id_t id, ulong_t off, int depth,596void *data)597{598char type[DT_TYPE_NAMELEN];599int kind;600dt_printarg_t *pap = data;601FILE *fp = pap->pa_file;602ctf_file_t *ctfp = pap->pa_ctfp;603boolean_t arraymember;604boolean_t brief;605ctf_encoding_t e;606ctf_id_t rtype;607608if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||609(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||610kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {611xo_emit("{:name/%s} <{:warning} {:type-identifier/%lu}>"612" {:value/0x%llx}",613name, "invalid type", id, pap->pa_addr);614return (0);615}616617dt_print_type_name(ctfp, id, type, sizeof (type));618xo_open_instance("type");619if (pap->pa_object) {620xo_emit("{:object-name/%s}", pap->pa_object);621/* Clear the object to avoid duplication */622pap->pa_object = NULL;623}624625if (*name != 0)626xo_emit("{:member-name/%s}", name);627xo_emit("{:name/%s} {:ctfid/%ld}", type, id);628dt_printfuncs[kind - 1](rtype, off, pap);629630xo_close_instance("type");631return (0);632}633634/*635* Print one member of a structure. This callback is invoked from636* ctf_type_visit() recursively.637*/638static int639dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth,640void *data)641{642char type[DT_TYPE_NAMELEN];643int kind;644dt_printarg_t *pap = data;645FILE *fp = pap->pa_file;646ctf_file_t *ctfp = pap->pa_ctfp;647boolean_t arraymember;648boolean_t brief;649ctf_encoding_t e;650ctf_id_t rtype;651652dt_print_trailing_braces(pap, depth);653/*654* dt_print_trailing_braces() doesn't include the trailing newline; add655* it here if necessary.656*/657if (depth < pap->pa_depth)658(void) fprintf(fp, "\n");659pap->pa_depth = depth;660661if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR ||662(kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR ||663kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) {664dt_print_indent(pap);665(void) fprintf(fp, "%s = <invalid type %lu>", name, id);666return (0);667}668669dt_print_type_name(ctfp, id, type, sizeof (type));670671arraymember = (pap->pa_nest != 0 && depth == 0);672brief = (arraymember && !CTF_IS_STRUCTLIKE(kind));673674if (!brief) {675/*676* If this is a direct array member and a struct (otherwise677* brief would be true), then print a trailing newline, as the678* array printing code doesn't include it because it might be a679* simple type.680*/681if (arraymember)682(void) fprintf(fp, "\n");683dt_print_indent(pap);684685/* always print the type */686(void) fprintf(fp, "%s", type);687if (name[0] != '\0') {688/*689* For aesthetics, we don't include a space between the690* type name and member name if the type is a pointer.691* This will give us "void *foo =" instead of "void *692* foo =". Unions also have the odd behavior that the693* type name is returned as "union ", with a trailing694* space, so we also avoid printing a space if the type695* name already ends with a space.696*/697if (type[strlen(type) - 1] != '*' &&698type[strlen(type) -1] != ' ') {699(void) fprintf(fp, " ");700}701(void) fprintf(fp, "%s", name);702703/*704* If this looks like a bitfield, or is an integer not705* aligned on a byte boundary, print the number of706* bits after the name.707*/708if (kind == CTF_K_INTEGER &&709ctf_type_encoding(ctfp, id, &e) == 0) {710ulong_t bits = e.cte_bits;711ulong_t size = bits / NBBY;712713if (bits % NBBY != 0 ||714off % NBBY != 0 ||715size > 8 ||716size != ctf_type_size(ctfp, id)) {717(void) fprintf(fp, " :%lu", bits);718}719}720721(void) fprintf(fp, " =");722}723(void) fprintf(fp, " ");724}725726dt_printfuncs[kind - 1](rtype, off, pap);727728/* direct simple array members are not separated by newlines */729if (!brief)730(void) fprintf(fp, "\n");731732return (0);733}734735static ctf_id_t736dt_print_prepare(dtrace_hdl_t *dtp, const char *typename, caddr_t addr,737size_t len, dt_printarg_t *pa)738{739const char *s;740char *object;741ctf_id_t id;742dt_module_t *dmp;743ctf_file_t *ctfp;744int libid;745746/*747* Split the fully-qualified type ID (module`id). This should748* always be the format, but if for some reason we don't find the749* expected value, return 0 to fall back to the generic trace()750* behavior. In the case of userland CTF modules this will actually be751* of the format (module`lib`id). This is due to the fact that those752* modules have multiple CTF containers which `lib` identifies.753*/754for (s = typename; *s != '\0' && *s != '`'; s++)755;756757if (*s != '`')758return (CTF_ERR);759760object = alloca(s - typename + 1);761bcopy(typename, object, s - typename);762object[s - typename] = '\0';763dmp = dt_module_lookup_by_name(dtp, object);764if (dmp == NULL)765return (CTF_ERR);766767if (dmp->dm_pid != 0) {768libid = atoi(s + 1);769s = strchr(s + 1, '`');770if (s == NULL || libid > dmp->dm_nctflibs)771return (CTF_ERR);772ctfp = dmp->dm_libctfp[libid];773} else {774ctfp = dt_module_getctf(dtp, dmp);775}776777id = atoi(s + 1);778779/*780* Try to get the CTF kind for this id. If something has gone horribly781* wrong and we can't resolve the ID, bail out and let trace() do the782* work.783*/784if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR)785return (CTF_ERR);786787pa->pa_dtp = dtp;788pa->pa_addr = addr;789pa->pa_ctfp = ctfp;790pa->pa_nest = 0;791pa->pa_depth = 0;792pa->pa_object = strdup(object);793return (id);794}795796/*797* Main print function invoked by dt_consume_cpu().798*/799int800dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,801caddr_t addr, size_t len)802{803dt_printarg_t pa;804ctf_id_t id;805806id = dt_print_prepare(dtp, typename, addr, len, &pa);807if (id == CTF_ERR)808return (0);809810pa.pa_file = fp;811(void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa);812813dt_print_trailing_braces(&pa, 0);814dt_free(dtp, (void *)pa.pa_object);815816return (len);817}818819/*820* Main format function invoked by dt_consume_cpu().821*/822int823dtrace_format_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename,824caddr_t addr, size_t len)825{826dt_printarg_t pa;827ctf_id_t id;828char toplevel[1024];829830id = dt_print_prepare(dtp, typename, addr, len, &pa);831if (id == CTF_ERR)832return (0);833834if (ctf_type_name(pa.pa_ctfp, id, toplevel, sizeof(toplevel)) < 0)835return (0);836837xo_open_list("type");838(void) ctf_type_visit(pa.pa_ctfp, id, dt_format_member, &pa);839xo_close_list("type");840dt_free(dtp, (void *)pa.pa_object);841842return (len);843}844845846847