1deef35fdSEric Schrock /* 2deef35fdSEric Schrock * CDDL HEADER START 3deef35fdSEric Schrock * 4deef35fdSEric Schrock * The contents of this file are subject to the terms of the 5deef35fdSEric Schrock * Common Development and Distribution License (the "License"). 6deef35fdSEric Schrock * You may not use this file except in compliance with the License. 7deef35fdSEric Schrock * 8deef35fdSEric Schrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9deef35fdSEric Schrock * or http://www.opensolaris.org/os/licensing. 10deef35fdSEric Schrock * See the License for the specific language governing permissions 11deef35fdSEric Schrock * and limitations under the License. 12deef35fdSEric Schrock * 13deef35fdSEric Schrock * When distributing Covered Code, include this CDDL HEADER in each 14deef35fdSEric Schrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15deef35fdSEric Schrock * If applicable, add the following below this CDDL HEADER, with the 16deef35fdSEric Schrock * fields enclosed by brackets "[]" replaced with your own identifying 17deef35fdSEric Schrock * information: Portions Copyright [yyyy] [name of copyright owner] 18deef35fdSEric Schrock * 19deef35fdSEric Schrock * CDDL HEADER END 20deef35fdSEric Schrock */ 21deef35fdSEric Schrock /* 22deef35fdSEric Schrock * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23deef35fdSEric Schrock * Use is subject to license terms. 24deef35fdSEric Schrock */ 25deef35fdSEric Schrock /* 26deef35fdSEric Schrock * Copyright (c) 2011 by Delphix. All rights reserved. 27deef35fdSEric Schrock */ 28b1fa6326SRobert Mustacchi /* 29b1fa6326SRobert Mustacchi * Copyright (c) 2013, Joyent, Inc. All rights reserved. 30b1fa6326SRobert Mustacchi */ 31deef35fdSEric Schrock 32deef35fdSEric Schrock /* 33deef35fdSEric Schrock * DTrace print() action 34deef35fdSEric Schrock * 35deef35fdSEric Schrock * This file contains the post-processing logic for the print() action. The 36deef35fdSEric Schrock * print action behaves identically to trace() in that it generates a 37deef35fdSEric Schrock * DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type 38deef35fdSEric Schrock * string stored in the DOF string table (similar to printf formats). We 39deef35fdSEric Schrock * take the result of the trace action and post-process it in the fashion of 40deef35fdSEric Schrock * MDB's ::print dcmd. 41deef35fdSEric Schrock * 42deef35fdSEric Schrock * This implementation differs from MDB's in the following ways: 43deef35fdSEric Schrock * 44deef35fdSEric Schrock * - We do not expose any options or flags. The behavior of print() is 45deef35fdSEric Schrock * equivalent to "::print -tn". 46deef35fdSEric Schrock * 47deef35fdSEric Schrock * - MDB will display "holes" in structures (unused padding between 48deef35fdSEric Schrock * members). 49deef35fdSEric Schrock * 50deef35fdSEric Schrock * - When printing arrays of structures, MDB will leave a trailing ',' 51deef35fdSEric Schrock * after the last element. 52deef35fdSEric Schrock * 53deef35fdSEric Schrock * - MDB will print time_t types as date and time. 54deef35fdSEric Schrock * 55deef35fdSEric Schrock * - MDB will detect when an enum is actually the OR of several flags, 56deef35fdSEric Schrock * and print it out with the constituent flags separated. 57deef35fdSEric Schrock * 58deef35fdSEric Schrock * - For large arrays, MDB will print the first few members and then 59deef35fdSEric Schrock * print a "..." continuation line. 60deef35fdSEric Schrock * 61deef35fdSEric Schrock * - MDB will break and wrap arrays at 80 columns. 62deef35fdSEric Schrock * 63deef35fdSEric Schrock * - MDB prints out floats and doubles by hand, as it must run in kmdb 64deef35fdSEric Schrock * context. We're able to leverage the printf() format strings, 65deef35fdSEric Schrock * but the result is a slightly different format. 66deef35fdSEric Schrock */ 67deef35fdSEric Schrock 68deef35fdSEric Schrock #include <sys/sysmacros.h> 69deef35fdSEric Schrock #include <strings.h> 70deef35fdSEric Schrock #include <stdlib.h> 71deef35fdSEric Schrock #include <alloca.h> 72deef35fdSEric Schrock #include <assert.h> 73deef35fdSEric Schrock #include <ctype.h> 74deef35fdSEric Schrock #include <errno.h> 75deef35fdSEric Schrock #include <limits.h> 76deef35fdSEric Schrock #include <sys/socket.h> 77deef35fdSEric Schrock #include <netdb.h> 78deef35fdSEric Schrock #include <netinet/in.h> 79deef35fdSEric Schrock #include <arpa/inet.h> 80deef35fdSEric Schrock #include <arpa/nameser.h> 81deef35fdSEric Schrock 82deef35fdSEric Schrock #include <dt_module.h> 83deef35fdSEric Schrock #include <dt_printf.h> 84deef35fdSEric Schrock #include <dt_string.h> 85deef35fdSEric Schrock #include <dt_impl.h> 86deef35fdSEric Schrock 87deef35fdSEric Schrock /* determines whether the given integer CTF encoding is a character */ 88deef35fdSEric Schrock #define CTF_IS_CHAR(e) \ 89deef35fdSEric Schrock (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \ 90deef35fdSEric Schrock (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY) 91deef35fdSEric Schrock /* determines whether the given CTF kind is a struct or union */ 92deef35fdSEric Schrock #define CTF_IS_STRUCTLIKE(k) \ 93deef35fdSEric Schrock ((k) == CTF_K_STRUCT || (k) == CTF_K_UNION) 94deef35fdSEric Schrock 95deef35fdSEric Schrock /* 96deef35fdSEric Schrock * Print structure passed down recursively through printing algorithm. 97deef35fdSEric Schrock */ 98deef35fdSEric Schrock typedef struct dt_printarg { 99b1fa6326SRobert Mustacchi dtrace_hdl_t *pa_dtp; /* libdtrace handle */ 100deef35fdSEric Schrock caddr_t pa_addr; /* base address of trace data */ 101deef35fdSEric Schrock ctf_file_t *pa_ctfp; /* CTF container */ 102deef35fdSEric Schrock int pa_depth; /* member depth */ 103deef35fdSEric Schrock int pa_nest; /* nested array depth */ 104deef35fdSEric Schrock FILE *pa_file; /* output file */ 105deef35fdSEric Schrock } dt_printarg_t; 106deef35fdSEric Schrock 107deef35fdSEric Schrock static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *); 108deef35fdSEric Schrock 109deef35fdSEric Schrock /* 110deef35fdSEric Schrock * Safe version of ctf_type_name() that will fall back to just "<ctfid>" if it 111deef35fdSEric Schrock * can't resolve the type. 112deef35fdSEric Schrock */ 113deef35fdSEric Schrock static void 114deef35fdSEric Schrock dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen) 115deef35fdSEric Schrock { 116deef35fdSEric Schrock if (ctf_type_name(ctfp, id, buf, buflen) == NULL) 117deef35fdSEric Schrock (void) snprintf(buf, buflen, "<%ld>", id); 118deef35fdSEric Schrock } 119deef35fdSEric Schrock 120deef35fdSEric Schrock /* 121deef35fdSEric Schrock * Print any necessary trailing braces for structures or unions. We don't get 122deef35fdSEric Schrock * invoked when a struct or union ends, so we infer the need to print braces 123deef35fdSEric Schrock * based on the depth the last time we printed something and the new depth. 124deef35fdSEric Schrock */ 125deef35fdSEric Schrock static void 126deef35fdSEric Schrock dt_print_trailing_braces(dt_printarg_t *pap, int depth) 127deef35fdSEric Schrock { 128deef35fdSEric Schrock int d; 129deef35fdSEric Schrock 130deef35fdSEric Schrock for (d = pap->pa_depth; d > depth; d--) { 131deef35fdSEric Schrock (void) fprintf(pap->pa_file, "%*s}%s", 132deef35fdSEric Schrock (d + pap->pa_nest - 1) * 4, "", 133deef35fdSEric Schrock d == depth + 1 ? "" : "\n"); 134deef35fdSEric Schrock } 135deef35fdSEric Schrock } 136deef35fdSEric Schrock 137deef35fdSEric Schrock /* 138deef35fdSEric Schrock * Print the appropriate amount of indentation given the current depth and 139deef35fdSEric Schrock * array nesting. 140deef35fdSEric Schrock */ 141deef35fdSEric Schrock static void 142deef35fdSEric Schrock dt_print_indent(dt_printarg_t *pap) 143deef35fdSEric Schrock { 144deef35fdSEric Schrock (void) fprintf(pap->pa_file, "%*s", 145deef35fdSEric Schrock (pap->pa_depth + pap->pa_nest) * 4, ""); 146deef35fdSEric Schrock } 147deef35fdSEric Schrock 148deef35fdSEric Schrock /* 149deef35fdSEric Schrock * Print a bitfield. It's worth noting that the D compiler support for 150deef35fdSEric Schrock * bitfields is currently broken; printing "D`user_desc_t" (pulled in by the 151deef35fdSEric Schrock * various D provider files) will produce incorrect results compared to 152deef35fdSEric Schrock * "genunix`user_desc_t". 153deef35fdSEric Schrock */ 154deef35fdSEric Schrock static void 155deef35fdSEric Schrock print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep) 156deef35fdSEric Schrock { 157deef35fdSEric Schrock FILE *fp = pap->pa_file; 158deef35fdSEric Schrock caddr_t addr = pap->pa_addr + off / NBBY; 159deef35fdSEric Schrock uint64_t mask = (1ULL << ep->cte_bits) - 1; 160deef35fdSEric Schrock uint64_t value = 0; 161deef35fdSEric Schrock size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY; 162deef35fdSEric Schrock uint8_t *buf = (uint8_t *)&value; 163deef35fdSEric Schrock uint8_t shift; 164deef35fdSEric Schrock 165deef35fdSEric Schrock /* 166deef35fdSEric Schrock * On big-endian machines, we need to adjust the buf pointer to refer 167deef35fdSEric Schrock * to the lowest 'size' bytes in 'value', and we need to shift based on 168deef35fdSEric Schrock * the offset from the end of the data, not the offset of the start. 169deef35fdSEric Schrock */ 170deef35fdSEric Schrock #ifdef _BIG_ENDIAN 171deef35fdSEric Schrock buf += sizeof (value) - size; 172deef35fdSEric Schrock off += ep->cte_bits; 173deef35fdSEric Schrock #endif 174deef35fdSEric Schrock bcopy(addr, buf, size); 175deef35fdSEric Schrock shift = off % NBBY; 176deef35fdSEric Schrock 177deef35fdSEric Schrock /* 178deef35fdSEric Schrock * Offsets are counted from opposite ends on little- and 179deef35fdSEric Schrock * big-endian machines. 180deef35fdSEric Schrock */ 181deef35fdSEric Schrock #ifdef _BIG_ENDIAN 182deef35fdSEric Schrock shift = NBBY - shift; 183deef35fdSEric Schrock #endif 184deef35fdSEric Schrock 185deef35fdSEric Schrock /* 186deef35fdSEric Schrock * If the bits we want do not begin on a byte boundary, shift the data 187deef35fdSEric Schrock * right so that the value is in the lowest 'cte_bits' of 'value'. 188deef35fdSEric Schrock */ 189deef35fdSEric Schrock if (off % NBBY != 0) 190deef35fdSEric Schrock value >>= shift; 191deef35fdSEric Schrock value &= mask; 192deef35fdSEric Schrock 193deef35fdSEric Schrock (void) fprintf(fp, "%#llx", (u_longlong_t)value); 194deef35fdSEric Schrock } 195deef35fdSEric Schrock 196deef35fdSEric Schrock /* 197deef35fdSEric Schrock * Dump the contents of memory as a fixed-size integer in hex. 198deef35fdSEric Schrock */ 199deef35fdSEric Schrock static void 200deef35fdSEric Schrock dt_print_hex(FILE *fp, caddr_t addr, size_t size) 201deef35fdSEric Schrock { 202deef35fdSEric Schrock switch (size) { 203deef35fdSEric Schrock case sizeof (uint8_t): 204deef35fdSEric Schrock (void) fprintf(fp, "%#x", *(uint8_t *)addr); 205deef35fdSEric Schrock break; 206deef35fdSEric Schrock case sizeof (uint16_t): 2070979781aSRichard Lowe /* LINTED - alignment */ 208deef35fdSEric Schrock (void) fprintf(fp, "%#x", *(uint16_t *)addr); 209deef35fdSEric Schrock break; 210deef35fdSEric Schrock case sizeof (uint32_t): 2110979781aSRichard Lowe /* LINTED - alignment */ 212deef35fdSEric Schrock (void) fprintf(fp, "%#x", *(uint32_t *)addr); 213deef35fdSEric Schrock break; 214deef35fdSEric Schrock case sizeof (uint64_t): 215deef35fdSEric Schrock (void) fprintf(fp, "%#llx", 2160979781aSRichard Lowe /* LINTED - alignment */ 217deef35fdSEric Schrock (unsigned long long)*(uint64_t *)addr); 218deef35fdSEric Schrock break; 219deef35fdSEric Schrock default: 220deef35fdSEric Schrock (void) fprintf(fp, "<invalid size %u>", (uint_t)size); 221deef35fdSEric Schrock } 222deef35fdSEric Schrock } 223deef35fdSEric Schrock 224deef35fdSEric Schrock /* 225deef35fdSEric Schrock * Print an integer type. Before dumping the contents via dt_print_hex(), we 226deef35fdSEric Schrock * first check the encoding to see if it's part of a bitfield or a character. 227deef35fdSEric Schrock */ 228deef35fdSEric Schrock static void 229deef35fdSEric Schrock dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 230deef35fdSEric Schrock { 231deef35fdSEric Schrock FILE *fp = pap->pa_file; 232deef35fdSEric Schrock ctf_file_t *ctfp = pap->pa_ctfp; 233deef35fdSEric Schrock ctf_encoding_t e; 234deef35fdSEric Schrock size_t size; 235deef35fdSEric Schrock caddr_t addr = pap->pa_addr + off / NBBY; 236deef35fdSEric Schrock 237deef35fdSEric Schrock if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) { 238deef35fdSEric Schrock (void) fprintf(fp, "<unknown encoding>"); 239deef35fdSEric Schrock return; 240deef35fdSEric Schrock } 241deef35fdSEric Schrock 242deef35fdSEric Schrock /* 243deef35fdSEric Schrock * This comes from MDB - it's not clear under what circumstances this 244deef35fdSEric Schrock * would be found. 245deef35fdSEric Schrock */ 246deef35fdSEric Schrock if (e.cte_format & CTF_INT_VARARGS) { 247deef35fdSEric Schrock (void) fprintf(fp, "..."); 248deef35fdSEric Schrock return; 249deef35fdSEric Schrock } 250deef35fdSEric Schrock 251deef35fdSEric Schrock /* 252deef35fdSEric Schrock * We print this as a bitfield if the bit encoding indicates it's not 253deef35fdSEric Schrock * an even power of two byte size, or is larger than 8 bytes. 254deef35fdSEric Schrock */ 255deef35fdSEric Schrock size = e.cte_bits / NBBY; 256deef35fdSEric Schrock if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) { 257deef35fdSEric Schrock print_bitfield(pap, off, &e); 258deef35fdSEric Schrock return; 259deef35fdSEric Schrock } 260deef35fdSEric Schrock 261deef35fdSEric Schrock /* 262deef35fdSEric Schrock * If this is a character, print it out as such. 263deef35fdSEric Schrock */ 264deef35fdSEric Schrock if (CTF_IS_CHAR(e)) { 265deef35fdSEric Schrock char c = *(char *)addr; 266deef35fdSEric Schrock if (isprint(c)) 267deef35fdSEric Schrock (void) fprintf(fp, "'%c'", c); 268deef35fdSEric Schrock else if (c == 0) 269deef35fdSEric Schrock (void) fprintf(fp, "'\\0'"); 270deef35fdSEric Schrock else 271deef35fdSEric Schrock (void) fprintf(fp, "'\\%03o'", c); 272deef35fdSEric Schrock return; 273deef35fdSEric Schrock } 274deef35fdSEric Schrock 275deef35fdSEric Schrock dt_print_hex(fp, addr, size); 276deef35fdSEric Schrock } 277deef35fdSEric Schrock 278deef35fdSEric Schrock /* 279deef35fdSEric Schrock * Print a floating point (float, double, long double) value. 280deef35fdSEric Schrock */ 281deef35fdSEric Schrock /* ARGSUSED */ 282deef35fdSEric Schrock static void 283deef35fdSEric Schrock dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 284deef35fdSEric Schrock { 285deef35fdSEric Schrock FILE *fp = pap->pa_file; 286deef35fdSEric Schrock ctf_file_t *ctfp = pap->pa_ctfp; 287deef35fdSEric Schrock ctf_encoding_t e; 288deef35fdSEric Schrock caddr_t addr = pap->pa_addr + off / NBBY; 289deef35fdSEric Schrock 290deef35fdSEric Schrock if (ctf_type_encoding(ctfp, base, &e) == 0) { 291deef35fdSEric Schrock if (e.cte_format == CTF_FP_SINGLE && 292deef35fdSEric Schrock e.cte_bits == sizeof (float) * NBBY) { 2930979781aSRichard Lowe /* LINTED - alignment */ 294deef35fdSEric Schrock (void) fprintf(fp, "%+.7e", *((float *)addr)); 295deef35fdSEric Schrock } else if (e.cte_format == CTF_FP_DOUBLE && 296deef35fdSEric Schrock e.cte_bits == sizeof (double) * NBBY) { 2970979781aSRichard Lowe /* LINTED - alignment */ 298deef35fdSEric Schrock (void) fprintf(fp, "%+.7e", *((double *)addr)); 299deef35fdSEric Schrock } else if (e.cte_format == CTF_FP_LDOUBLE && 300deef35fdSEric Schrock e.cte_bits == sizeof (long double) * NBBY) { 3010979781aSRichard Lowe /* LINTED - alignment */ 302deef35fdSEric Schrock (void) fprintf(fp, "%+.16LE", *((long double *)addr)); 303deef35fdSEric Schrock } else { 304deef35fdSEric Schrock (void) fprintf(fp, "<unknown encoding>"); 305deef35fdSEric Schrock } 306deef35fdSEric Schrock } 307deef35fdSEric Schrock } 308deef35fdSEric Schrock 309deef35fdSEric Schrock /* 310b1fa6326SRobert Mustacchi * A pointer is generally printed as a fixed-size integer. If we have a 311b1fa6326SRobert Mustacchi * function pointer, we try to look up its name. 312deef35fdSEric Schrock */ 313deef35fdSEric Schrock static void 314deef35fdSEric Schrock dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 315deef35fdSEric Schrock { 316deef35fdSEric Schrock FILE *fp = pap->pa_file; 317deef35fdSEric Schrock ctf_file_t *ctfp = pap->pa_ctfp; 318deef35fdSEric Schrock caddr_t addr = pap->pa_addr + off / NBBY; 319deef35fdSEric Schrock size_t size = ctf_type_size(ctfp, base); 320b1fa6326SRobert Mustacchi ctf_id_t bid = ctf_type_reference(ctfp, base); 321b1fa6326SRobert Mustacchi uint64_t pc; 322b1fa6326SRobert Mustacchi dtrace_syminfo_t dts; 323b1fa6326SRobert Mustacchi GElf_Sym sym; 324deef35fdSEric Schrock 325b1fa6326SRobert Mustacchi if (bid == CTF_ERR || ctf_type_kind(ctfp, bid) != CTF_K_FUNCTION) { 326deef35fdSEric Schrock dt_print_hex(fp, addr, size); 327b1fa6326SRobert Mustacchi } else { 328b1fa6326SRobert Mustacchi /* LINTED - alignment */ 329b1fa6326SRobert Mustacchi pc = *((uint64_t *)addr); 330b1fa6326SRobert Mustacchi if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) { 331b1fa6326SRobert Mustacchi dt_print_hex(fp, addr, size); 332b1fa6326SRobert Mustacchi } else { 333b1fa6326SRobert Mustacchi (void) fprintf(fp, "%s`%s", dts.dts_object, 334b1fa6326SRobert Mustacchi dts.dts_name); 335b1fa6326SRobert Mustacchi } 336b1fa6326SRobert Mustacchi } 337deef35fdSEric Schrock } 338deef35fdSEric Schrock 339deef35fdSEric Schrock /* 340deef35fdSEric Schrock * Print out an array. This is somewhat complex, as we must manually visit 341deef35fdSEric Schrock * each member, and recursively invoke ctf_type_visit() for each member. If 342deef35fdSEric Schrock * the members are non-structs, then we print them out directly: 343deef35fdSEric Schrock * 344deef35fdSEric Schrock * [ 0x14, 0x2e, 0 ] 345deef35fdSEric Schrock * 346deef35fdSEric Schrock * If they are structs, then we print out the necessary leading and trailing 347deef35fdSEric Schrock * braces, to end up with: 348deef35fdSEric Schrock * 349deef35fdSEric Schrock * [ 350deef35fdSEric Schrock * type { 351deef35fdSEric Schrock * ... 352deef35fdSEric Schrock * }, 353deef35fdSEric Schrock * type { 354deef35fdSEric Schrock * ... 355deef35fdSEric Schrock * } 356deef35fdSEric Schrock * ] 357deef35fdSEric Schrock * 358deef35fdSEric Schrock * We also use a heuristic to detect whether the array looks like a character 359deef35fdSEric Schrock * array. If the encoding indicates it's a character, and we have all 360deef35fdSEric Schrock * printable characters followed by a null byte, then we display it as a 361deef35fdSEric Schrock * string: 362deef35fdSEric Schrock * 363deef35fdSEric Schrock * [ "string" ] 364deef35fdSEric Schrock */ 365deef35fdSEric Schrock static void 366deef35fdSEric Schrock dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 367deef35fdSEric Schrock { 368deef35fdSEric Schrock FILE *fp = pap->pa_file; 369deef35fdSEric Schrock ctf_file_t *ctfp = pap->pa_ctfp; 370deef35fdSEric Schrock caddr_t addr = pap->pa_addr + off / NBBY; 371deef35fdSEric Schrock ctf_arinfo_t car; 372deef35fdSEric Schrock ssize_t eltsize; 373deef35fdSEric Schrock ctf_encoding_t e; 374deef35fdSEric Schrock int i; 375deef35fdSEric Schrock boolean_t isstring; 376deef35fdSEric Schrock int kind; 377deef35fdSEric Schrock ctf_id_t rtype; 378deef35fdSEric Schrock 379deef35fdSEric Schrock if (ctf_array_info(ctfp, base, &car) == CTF_ERR) { 380deef35fdSEric Schrock (void) fprintf(fp, "0x%p", (void *)addr); 381deef35fdSEric Schrock return; 382deef35fdSEric Schrock } 383deef35fdSEric Schrock 384deef35fdSEric Schrock if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 || 385deef35fdSEric Schrock (rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR || 386deef35fdSEric Schrock (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) { 387deef35fdSEric Schrock (void) fprintf(fp, "<invalid type %lu>", car.ctr_contents); 388deef35fdSEric Schrock return; 389deef35fdSEric Schrock } 390deef35fdSEric Schrock 391deef35fdSEric Schrock /* see if this looks like a string */ 392deef35fdSEric Schrock isstring = B_FALSE; 393deef35fdSEric Schrock if (kind == CTF_K_INTEGER && 394deef35fdSEric Schrock ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) { 395deef35fdSEric Schrock char c; 396deef35fdSEric Schrock for (i = 0; i < car.ctr_nelems; i++) { 397deef35fdSEric Schrock c = *((char *)addr + eltsize * i); 398deef35fdSEric Schrock if (!isprint(c) || c == '\0') 399deef35fdSEric Schrock break; 400deef35fdSEric Schrock } 401deef35fdSEric Schrock 402deef35fdSEric Schrock if (i != car.ctr_nelems && c == '\0') 403deef35fdSEric Schrock isstring = B_TRUE; 404deef35fdSEric Schrock } 405deef35fdSEric Schrock 406deef35fdSEric Schrock /* 407deef35fdSEric Schrock * As a slight aesthetic optimization, if we are a top-level type, then 408deef35fdSEric Schrock * don't bother printing out the brackets. This lets print("foo") look 409deef35fdSEric Schrock * like: 410deef35fdSEric Schrock * 411deef35fdSEric Schrock * string "foo" 412deef35fdSEric Schrock * 413deef35fdSEric Schrock * As D will internally represent this as a char[256] array. 414deef35fdSEric Schrock */ 415deef35fdSEric Schrock if (!isstring || pap->pa_depth != 0) 416deef35fdSEric Schrock (void) fprintf(fp, "[ "); 417deef35fdSEric Schrock 418deef35fdSEric Schrock if (isstring) 419deef35fdSEric Schrock (void) fprintf(fp, "\""); 420deef35fdSEric Schrock 421deef35fdSEric Schrock for (i = 0; i < car.ctr_nelems; i++) { 422deef35fdSEric Schrock if (isstring) { 423deef35fdSEric Schrock char c = *((char *)addr + eltsize * i); 424deef35fdSEric Schrock if (c == '\0') 425deef35fdSEric Schrock break; 426deef35fdSEric Schrock (void) fprintf(fp, "%c", c); 427deef35fdSEric Schrock } else { 428deef35fdSEric Schrock /* 429deef35fdSEric Schrock * Recursively invoke ctf_type_visit() on each member. 430deef35fdSEric Schrock * We setup a new printarg struct with 'pa_nest' set to 431deef35fdSEric Schrock * indicate that we are within a nested array. 432deef35fdSEric Schrock */ 433deef35fdSEric Schrock dt_printarg_t pa = *pap; 434deef35fdSEric Schrock pa.pa_nest += pap->pa_depth + 1; 435deef35fdSEric Schrock pa.pa_depth = 0; 436deef35fdSEric Schrock pa.pa_addr = addr + eltsize * i; 437deef35fdSEric Schrock (void) ctf_type_visit(ctfp, car.ctr_contents, 438deef35fdSEric Schrock dt_print_member, &pa); 439deef35fdSEric Schrock 440deef35fdSEric Schrock dt_print_trailing_braces(&pa, 0); 441deef35fdSEric Schrock if (i != car.ctr_nelems - 1) 442deef35fdSEric Schrock (void) fprintf(fp, ", "); 443deef35fdSEric Schrock else if (CTF_IS_STRUCTLIKE(kind)) 444deef35fdSEric Schrock (void) fprintf(fp, "\n"); 445deef35fdSEric Schrock } 446deef35fdSEric Schrock } 447deef35fdSEric Schrock 448deef35fdSEric Schrock if (isstring) 449deef35fdSEric Schrock (void) fprintf(fp, "\""); 450deef35fdSEric Schrock 451deef35fdSEric Schrock if (!isstring || pap->pa_depth != 0) { 452deef35fdSEric Schrock if (CTF_IS_STRUCTLIKE(kind)) 453deef35fdSEric Schrock dt_print_indent(pap); 454deef35fdSEric Schrock else 455deef35fdSEric Schrock (void) fprintf(fp, " "); 456deef35fdSEric Schrock (void) fprintf(fp, "]"); 457deef35fdSEric Schrock } 458deef35fdSEric Schrock } 459deef35fdSEric Schrock 460deef35fdSEric Schrock /* 461deef35fdSEric Schrock * This isued by both structs and unions to print the leading brace. 462deef35fdSEric Schrock */ 463deef35fdSEric Schrock /* ARGSUSED */ 464deef35fdSEric Schrock static void 465deef35fdSEric Schrock dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap) 466deef35fdSEric Schrock { 467deef35fdSEric Schrock (void) fprintf(pap->pa_file, "{"); 468deef35fdSEric Schrock } 469deef35fdSEric Schrock 470deef35fdSEric Schrock /* 471deef35fdSEric Schrock * For enums, we try to print the enum name, and fall back to the value if it 472deef35fdSEric Schrock * can't be determined. We do not do any fancy flag processing like mdb. 473deef35fdSEric Schrock */ 474deef35fdSEric Schrock /* ARGSUSED */ 475deef35fdSEric Schrock static void 476deef35fdSEric Schrock dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 477deef35fdSEric Schrock { 478deef35fdSEric Schrock FILE *fp = pap->pa_file; 479deef35fdSEric Schrock ctf_file_t *ctfp = pap->pa_ctfp; 480deef35fdSEric Schrock const char *ename; 481b1fa6326SRobert Mustacchi ssize_t size; 482b1fa6326SRobert Mustacchi caddr_t addr = pap->pa_addr + off / NBBY; 483deef35fdSEric Schrock int value = 0; 484deef35fdSEric Schrock 485b1fa6326SRobert Mustacchi /* 486b1fa6326SRobert Mustacchi * The C standard says that an enum will be at most the sizeof (int). 487b1fa6326SRobert Mustacchi * But if all the values are less than that, the compiler can use a 488b1fa6326SRobert Mustacchi * smaller size. Thanks standards. 489b1fa6326SRobert Mustacchi */ 490b1fa6326SRobert Mustacchi size = ctf_type_size(ctfp, base); 491b1fa6326SRobert Mustacchi switch (size) { 492b1fa6326SRobert Mustacchi case sizeof (uint8_t): 493b1fa6326SRobert Mustacchi value = *(uint8_t *)addr; 494b1fa6326SRobert Mustacchi break; 495b1fa6326SRobert Mustacchi case sizeof (uint16_t): 4962974b68dSRichard Lowe /* LINTED - alignment */ 497b1fa6326SRobert Mustacchi value = *(uint16_t *)addr; 498b1fa6326SRobert Mustacchi break; 499b1fa6326SRobert Mustacchi case sizeof (int32_t): 5002974b68dSRichard Lowe /* LINTED - alignment */ 501b1fa6326SRobert Mustacchi value = *(int32_t *)addr; 502b1fa6326SRobert Mustacchi break; 503b1fa6326SRobert Mustacchi default: 504b1fa6326SRobert Mustacchi (void) fprintf(fp, "<invalid enum size %u>", (uint_t)size); 505b1fa6326SRobert Mustacchi return; 506b1fa6326SRobert Mustacchi } 507b1fa6326SRobert Mustacchi 508deef35fdSEric Schrock if ((ename = ctf_enum_name(ctfp, base, value)) != NULL) 509deef35fdSEric Schrock (void) fprintf(fp, "%s", ename); 510deef35fdSEric Schrock else 511deef35fdSEric Schrock (void) fprintf(fp, "%d", value); 512deef35fdSEric Schrock } 513deef35fdSEric Schrock 514deef35fdSEric Schrock /* 515deef35fdSEric Schrock * Forward declaration. There's not much to do here without the complete 516deef35fdSEric Schrock * type information, so just print out this fact and drive on. 517deef35fdSEric Schrock */ 518deef35fdSEric Schrock /* ARGSUSED */ 519deef35fdSEric Schrock static void 520deef35fdSEric Schrock dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap) 521deef35fdSEric Schrock { 522deef35fdSEric Schrock (void) fprintf(pap->pa_file, "<forward decl>"); 523deef35fdSEric Schrock } 524deef35fdSEric Schrock 525deef35fdSEric Schrock typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *); 526deef35fdSEric Schrock 527deef35fdSEric Schrock static dt_printarg_f *const dt_printfuncs[] = { 528deef35fdSEric Schrock dt_print_int, /* CTF_K_INTEGER */ 529deef35fdSEric Schrock dt_print_float, /* CTF_K_FLOAT */ 530deef35fdSEric Schrock dt_print_ptr, /* CTF_K_POINTER */ 531deef35fdSEric Schrock dt_print_array, /* CTF_K_ARRAY */ 532deef35fdSEric Schrock dt_print_ptr, /* CTF_K_FUNCTION */ 533deef35fdSEric Schrock dt_print_structlike, /* CTF_K_STRUCT */ 534deef35fdSEric Schrock dt_print_structlike, /* CTF_K_UNION */ 535deef35fdSEric Schrock dt_print_enum, /* CTF_K_ENUM */ 536deef35fdSEric Schrock dt_print_tag /* CTF_K_FORWARD */ 537deef35fdSEric Schrock }; 538deef35fdSEric Schrock 539deef35fdSEric Schrock /* 540deef35fdSEric Schrock * Print one member of a structure. This callback is invoked from 541deef35fdSEric Schrock * ctf_type_visit() recursively. 542deef35fdSEric Schrock */ 543deef35fdSEric Schrock static int 544deef35fdSEric Schrock dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth, 545deef35fdSEric Schrock void *data) 546deef35fdSEric Schrock { 547deef35fdSEric Schrock char type[DT_TYPE_NAMELEN]; 548deef35fdSEric Schrock int kind; 549deef35fdSEric Schrock dt_printarg_t *pap = data; 550deef35fdSEric Schrock FILE *fp = pap->pa_file; 551deef35fdSEric Schrock ctf_file_t *ctfp = pap->pa_ctfp; 552deef35fdSEric Schrock boolean_t arraymember; 553deef35fdSEric Schrock boolean_t brief; 554deef35fdSEric Schrock ctf_encoding_t e; 555deef35fdSEric Schrock ctf_id_t rtype; 556deef35fdSEric Schrock 557deef35fdSEric Schrock dt_print_trailing_braces(pap, depth); 558deef35fdSEric Schrock /* 559deef35fdSEric Schrock * dt_print_trailing_braces() doesn't include the trailing newline; add 560deef35fdSEric Schrock * it here if necessary. 561deef35fdSEric Schrock */ 562deef35fdSEric Schrock if (depth < pap->pa_depth) 563deef35fdSEric Schrock (void) fprintf(fp, "\n"); 564deef35fdSEric Schrock pap->pa_depth = depth; 565deef35fdSEric Schrock 566deef35fdSEric Schrock if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR || 567deef35fdSEric Schrock (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR || 568deef35fdSEric Schrock kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) { 569deef35fdSEric Schrock dt_print_indent(pap); 570deef35fdSEric Schrock (void) fprintf(fp, "%s = <invalid type %lu>", name, id); 571deef35fdSEric Schrock return (0); 572deef35fdSEric Schrock } 573deef35fdSEric Schrock 574deef35fdSEric Schrock dt_print_type_name(ctfp, id, type, sizeof (type)); 575deef35fdSEric Schrock 576deef35fdSEric Schrock arraymember = (pap->pa_nest != 0 && depth == 0); 577deef35fdSEric Schrock brief = (arraymember && !CTF_IS_STRUCTLIKE(kind)); 578deef35fdSEric Schrock 579deef35fdSEric Schrock if (!brief) { 580deef35fdSEric Schrock /* 581deef35fdSEric Schrock * If this is a direct array member and a struct (otherwise 582deef35fdSEric Schrock * brief would be true), then print a trailing newline, as the 583deef35fdSEric Schrock * array printing code doesn't include it because it might be a 584deef35fdSEric Schrock * simple type. 585deef35fdSEric Schrock */ 586deef35fdSEric Schrock if (arraymember) 587deef35fdSEric Schrock (void) fprintf(fp, "\n"); 588deef35fdSEric Schrock dt_print_indent(pap); 589deef35fdSEric Schrock 590deef35fdSEric Schrock /* always print the type */ 591deef35fdSEric Schrock (void) fprintf(fp, "%s", type); 592deef35fdSEric Schrock if (name[0] != '\0') { 593deef35fdSEric Schrock /* 594deef35fdSEric Schrock * For aesthetics, we don't include a space between the 595deef35fdSEric Schrock * type name and member name if the type is a pointer. 596deef35fdSEric Schrock * This will give us "void *foo =" instead of "void * 597deef35fdSEric Schrock * foo =". Unions also have the odd behavior that the 598deef35fdSEric Schrock * type name is returned as "union ", with a trailing 599deef35fdSEric Schrock * space, so we also avoid printing a space if the type 600deef35fdSEric Schrock * name already ends with a space. 601deef35fdSEric Schrock */ 602deef35fdSEric Schrock if (type[strlen(type) - 1] != '*' && 603deef35fdSEric Schrock type[strlen(type) -1] != ' ') { 604deef35fdSEric Schrock (void) fprintf(fp, " "); 605deef35fdSEric Schrock } 606deef35fdSEric Schrock (void) fprintf(fp, "%s", name); 607deef35fdSEric Schrock 608deef35fdSEric Schrock /* 609deef35fdSEric Schrock * If this looks like a bitfield, or is an integer not 610deef35fdSEric Schrock * aligned on a byte boundary, print the number of 611deef35fdSEric Schrock * bits after the name. 612deef35fdSEric Schrock */ 613deef35fdSEric Schrock if (kind == CTF_K_INTEGER && 614deef35fdSEric Schrock ctf_type_encoding(ctfp, id, &e) == 0) { 615deef35fdSEric Schrock ulong_t bits = e.cte_bits; 616deef35fdSEric Schrock ulong_t size = bits / NBBY; 617deef35fdSEric Schrock 618deef35fdSEric Schrock if (bits % NBBY != 0 || 619deef35fdSEric Schrock off % NBBY != 0 || 620deef35fdSEric Schrock size > 8 || 621deef35fdSEric Schrock size != ctf_type_size(ctfp, id)) { 622deef35fdSEric Schrock (void) fprintf(fp, " :%lu", bits); 623deef35fdSEric Schrock } 624deef35fdSEric Schrock } 625deef35fdSEric Schrock 626deef35fdSEric Schrock (void) fprintf(fp, " ="); 627deef35fdSEric Schrock } 628deef35fdSEric Schrock (void) fprintf(fp, " "); 629deef35fdSEric Schrock } 630deef35fdSEric Schrock 631deef35fdSEric Schrock dt_printfuncs[kind - 1](rtype, off, pap); 632deef35fdSEric Schrock 633deef35fdSEric Schrock /* direct simple array members are not separated by newlines */ 634deef35fdSEric Schrock if (!brief) 635deef35fdSEric Schrock (void) fprintf(fp, "\n"); 636deef35fdSEric Schrock 637deef35fdSEric Schrock return (0); 638deef35fdSEric Schrock } 639deef35fdSEric Schrock 640deef35fdSEric Schrock /* 641deef35fdSEric Schrock * Main print function invoked by dt_consume_cpu(). 642deef35fdSEric Schrock */ 643deef35fdSEric Schrock int 644deef35fdSEric Schrock dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename, 645deef35fdSEric Schrock caddr_t addr, size_t len) 646deef35fdSEric Schrock { 647deef35fdSEric Schrock const char *s; 648deef35fdSEric Schrock char *object; 649deef35fdSEric Schrock dt_printarg_t pa; 650deef35fdSEric Schrock ctf_id_t id; 651deef35fdSEric Schrock dt_module_t *dmp; 652*a386cc11SRobert Mustacchi ctf_file_t *ctfp; 653*a386cc11SRobert Mustacchi int libid; 654deef35fdSEric Schrock 655deef35fdSEric Schrock /* 656deef35fdSEric Schrock * Split the fully-qualified type ID (module`id). This should 657deef35fdSEric Schrock * always be the format, but if for some reason we don't find the 658deef35fdSEric Schrock * expected value, return 0 to fall back to the generic trace() 659*a386cc11SRobert Mustacchi * behavior. In the case of userland CTF modules this will actually be 660*a386cc11SRobert Mustacchi * of the format (module`lib`id). This is due to the fact that those 661*a386cc11SRobert Mustacchi * modules have multiple CTF containers which `lib` identifies. 662deef35fdSEric Schrock */ 663deef35fdSEric Schrock for (s = typename; *s != '\0' && *s != '`'; s++) 664deef35fdSEric Schrock ; 665deef35fdSEric Schrock 666deef35fdSEric Schrock if (*s != '`') 667deef35fdSEric Schrock return (0); 668deef35fdSEric Schrock 669deef35fdSEric Schrock object = alloca(s - typename + 1); 670deef35fdSEric Schrock bcopy(typename, object, s - typename); 671deef35fdSEric Schrock object[s - typename] = '\0'; 672*a386cc11SRobert Mustacchi dmp = dt_module_lookup_by_name(dtp, object); 673*a386cc11SRobert Mustacchi if (dmp == NULL) 674*a386cc11SRobert Mustacchi return (0); 675*a386cc11SRobert Mustacchi 676*a386cc11SRobert Mustacchi if (dmp->dm_pid != 0) { 677*a386cc11SRobert Mustacchi libid = atoi(s + 1); 678*a386cc11SRobert Mustacchi s = strchr(s + 1, '`'); 679*a386cc11SRobert Mustacchi if (s == NULL || libid > dmp->dm_nctflibs) 680*a386cc11SRobert Mustacchi return (0); 681*a386cc11SRobert Mustacchi ctfp = dmp->dm_libctfp[libid]; 682*a386cc11SRobert Mustacchi } else { 683*a386cc11SRobert Mustacchi ctfp = dt_module_getctf(dtp, dmp); 684*a386cc11SRobert Mustacchi } 685*a386cc11SRobert Mustacchi 686deef35fdSEric Schrock id = atoi(s + 1); 687deef35fdSEric Schrock 688deef35fdSEric Schrock /* 689deef35fdSEric Schrock * Try to get the CTF kind for this id. If something has gone horribly 690deef35fdSEric Schrock * wrong and we can't resolve the ID, bail out and let trace() do the 691deef35fdSEric Schrock * work. 692deef35fdSEric Schrock */ 693*a386cc11SRobert Mustacchi if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR) 694deef35fdSEric Schrock return (0); 695deef35fdSEric Schrock 696deef35fdSEric Schrock /* setup the print structure and kick off the main print routine */ 697b1fa6326SRobert Mustacchi pa.pa_dtp = dtp; 698deef35fdSEric Schrock pa.pa_addr = addr; 699*a386cc11SRobert Mustacchi pa.pa_ctfp = ctfp; 700deef35fdSEric Schrock pa.pa_nest = 0; 701deef35fdSEric Schrock pa.pa_depth = 0; 702deef35fdSEric Schrock pa.pa_file = fp; 703deef35fdSEric Schrock (void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa); 704deef35fdSEric Schrock 705deef35fdSEric Schrock dt_print_trailing_braces(&pa, 0); 706deef35fdSEric Schrock 707deef35fdSEric Schrock return (len); 708deef35fdSEric Schrock } 709