Index: stable/11/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c =================================================================== --- stable/11/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c (revision 324595) +++ stable/11/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dis.c (revision 324596) @@ -1,526 +1,526 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013 by Delphix. All rights reserved. * Copyright (c) 2013 Joyent, Inc. All rights reserved. */ #include #include #include #include /*ARGSUSED*/ static void dt_dis_log(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%-4s %%r%u, %%r%u, %%r%u", name, DIF_INSTR_R1(in), DIF_INSTR_R2(in), DIF_INSTR_RD(in)); } /*ARGSUSED*/ static void dt_dis_branch(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%-4s %u", name, DIF_INSTR_LABEL(in)); } /*ARGSUSED*/ static void dt_dis_load(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%-4s [%%r%u], %%r%u", name, DIF_INSTR_R1(in), DIF_INSTR_RD(in)); } /*ARGSUSED*/ static void dt_dis_store(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%-4s %%r%u, [%%r%u]", name, DIF_INSTR_R1(in), DIF_INSTR_RD(in)); } /*ARGSUSED*/ static void dt_dis_str(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%s", name); } /*ARGSUSED*/ static void dt_dis_r1rd(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%-4s %%r%u, %%r%u", name, DIF_INSTR_R1(in), DIF_INSTR_RD(in)); } /*ARGSUSED*/ static void dt_dis_cmp(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%-4s %%r%u, %%r%u", name, DIF_INSTR_R1(in), DIF_INSTR_R2(in)); } /*ARGSUSED*/ static void dt_dis_tst(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%-4s %%r%u", name, DIF_INSTR_R1(in)); } static const char * dt_dis_varname(const dtrace_difo_t *dp, uint_t id, uint_t scope) { const dtrace_difv_t *dvp = dp->dtdo_vartab; uint_t i; for (i = 0; i < dp->dtdo_varlen; i++, dvp++) { if (dvp->dtdv_id == id && dvp->dtdv_scope == scope) { if (dvp->dtdv_name < dp->dtdo_strlen) return (dp->dtdo_strtab + dvp->dtdv_name); break; } } return (NULL); } static uint_t dt_dis_scope(const char *name) { switch (name[2]) { case 'l': return (DIFV_SCOPE_LOCAL); case 't': return (DIFV_SCOPE_THREAD); case 'g': return (DIFV_SCOPE_GLOBAL); default: return (-1u); } } static void dt_dis_lda(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { uint_t var = DIF_INSTR_R1(in); const char *vname; (void) fprintf(fp, "%-4s DT_VAR(%u), %%r%u, %%r%u", name, var, DIF_INSTR_R2(in), DIF_INSTR_RD(in)); if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL) (void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname); } static void dt_dis_ldv(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { uint_t var = DIF_INSTR_VAR(in); const char *vname; (void) fprintf(fp, "%-4s DT_VAR(%u), %%r%u", name, var, DIF_INSTR_RD(in)); if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL) (void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname); } static void dt_dis_stv(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { uint_t var = DIF_INSTR_VAR(in); const char *vname; (void) fprintf(fp, "%-4s %%r%u, DT_VAR(%u)", name, DIF_INSTR_RS(in), var); if ((vname = dt_dis_varname(dp, var, dt_dis_scope(name))) != NULL) (void) fprintf(fp, "\t\t! DT_VAR(%u) = \"%s\"", var, vname); } static void dt_dis_setx(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { uint_t intptr = DIF_INSTR_INTEGER(in); (void) fprintf(fp, "%-4s DT_INTEGER[%u], %%r%u", name, intptr, DIF_INSTR_RD(in)); if (intptr < dp->dtdo_intlen) { (void) fprintf(fp, "\t\t! 0x%llx", (u_longlong_t)dp->dtdo_inttab[intptr]); } } static void dt_dis_sets(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { uint_t strptr = DIF_INSTR_STRING(in); (void) fprintf(fp, "%-4s DT_STRING[%u], %%r%u", name, strptr, DIF_INSTR_RD(in)); if (strptr < dp->dtdo_strlen) (void) fprintf(fp, "\t\t! \"%s\"", dp->dtdo_strtab + strptr); } /*ARGSUSED*/ static void dt_dis_ret(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { (void) fprintf(fp, "%-4s %%r%u", name, DIF_INSTR_RD(in)); } /*ARGSUSED*/ static void dt_dis_call(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { uint_t subr = DIF_INSTR_SUBR(in); (void) fprintf(fp, "%-4s DIF_SUBR(%u), %%r%u\t\t! %s", name, subr, DIF_INSTR_RD(in), dtrace_subrstr(NULL, subr)); } /*ARGSUSED*/ static void dt_dis_pushts(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { static const char *const tnames[] = { "D type", "string" }; uint_t type = DIF_INSTR_TYPE(in); const char *pad; if (DIF_INSTR_OP(in) == DIF_OP_PUSHTV) { (void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u", name, type, DIF_INSTR_RS(in)); pad = "\t\t"; } else { (void) fprintf(fp, "%-4s DT_TYPE(%u), %%r%u, %%r%u", name, type, DIF_INSTR_R2(in), DIF_INSTR_RS(in)); pad = "\t"; } if (type < sizeof (tnames) / sizeof (tnames[0])) { (void) fprintf(fp, "%s! DT_TYPE(%u) = %s", pad, type, tnames[type]); } } static void dt_dis_xlate(const dtrace_difo_t *dp, const char *name, dif_instr_t in, FILE *fp) { uint_t xlr = DIF_INSTR_XLREF(in); (void) fprintf(fp, "%-4s DT_XLREF[%u], %%r%u", name, xlr, DIF_INSTR_RD(in)); if (xlr < dp->dtdo_xlmlen) { (void) fprintf(fp, "\t\t! DT_XLREF[%u] = %u.%s", xlr, (uint_t)dp->dtdo_xlmtab[xlr]->dn_membexpr->dn_xlator->dx_id, dp->dtdo_xlmtab[xlr]->dn_membname); } } static char * dt_dis_typestr(const dtrace_diftype_t *t, char *buf, size_t len) { char kind[16], ckind[16]; switch (t->dtdt_kind) { case DIF_TYPE_CTF: (void) strcpy(kind, "D type"); break; case DIF_TYPE_STRING: (void) strcpy(kind, "string"); break; default: (void) snprintf(kind, sizeof (kind), "0x%x", t->dtdt_kind); } switch (t->dtdt_ckind) { case CTF_K_UNKNOWN: (void) strcpy(ckind, "unknown"); break; case CTF_K_INTEGER: (void) strcpy(ckind, "integer"); break; case CTF_K_FLOAT: (void) strcpy(ckind, "float"); break; case CTF_K_POINTER: (void) strcpy(ckind, "pointer"); break; case CTF_K_ARRAY: (void) strcpy(ckind, "array"); break; case CTF_K_FUNCTION: (void) strcpy(ckind, "function"); break; case CTF_K_STRUCT: (void) strcpy(ckind, "struct"); break; case CTF_K_UNION: (void) strcpy(ckind, "union"); break; case CTF_K_ENUM: (void) strcpy(ckind, "enum"); break; case CTF_K_FORWARD: (void) strcpy(ckind, "forward"); break; case CTF_K_TYPEDEF: (void) strcpy(ckind, "typedef"); break; case CTF_K_VOLATILE: (void) strcpy(ckind, "volatile"); break; case CTF_K_CONST: (void) strcpy(ckind, "const"); break; case CTF_K_RESTRICT: (void) strcpy(ckind, "restrict"); break; default: (void) snprintf(ckind, sizeof (ckind), "0x%x", t->dtdt_ckind); } if (t->dtdt_flags & (DIF_TF_BYREF | DIF_TF_BYUREF)) { (void) snprintf(buf, len, "%s (%s) by %sref (size %lu)", kind, ckind, (t->dtdt_flags & DIF_TF_BYUREF) ? "user " : "", (ulong_t)t->dtdt_size); } else { (void) snprintf(buf, len, "%s (%s) (size %lu)", kind, ckind, (ulong_t)t->dtdt_size); } return (buf); } static void dt_dis_rtab(const char *rtag, const dtrace_difo_t *dp, FILE *fp, const dof_relodesc_t *rp, uint32_t len) { (void) fprintf(fp, "\n%-4s %-8s %-8s %s\n", rtag, "OFFSET", "DATA", "NAME"); for (; len != 0; len--, rp++) { (void) fprintf(fp, "%-4u %-8llu %-8llu %s\n", rp->dofr_type, (u_longlong_t)rp->dofr_offset, (u_longlong_t)rp->dofr_data, &dp->dtdo_strtab[rp->dofr_name]); } } void dt_dis(const dtrace_difo_t *dp, FILE *fp) { static const struct opent { const char *op_name; void (*op_func)(const dtrace_difo_t *, const char *, dif_instr_t, FILE *); } optab[] = { { "(illegal opcode)", dt_dis_str }, { "or", dt_dis_log }, /* DIF_OP_OR */ { "xor", dt_dis_log }, /* DIF_OP_XOR */ { "and", dt_dis_log }, /* DIF_OP_AND */ { "sll", dt_dis_log }, /* DIF_OP_SLL */ { "srl", dt_dis_log }, /* DIF_OP_SRL */ { "sub", dt_dis_log }, /* DIF_OP_SUB */ { "add", dt_dis_log }, /* DIF_OP_ADD */ { "mul", dt_dis_log }, /* DIF_OP_MUL */ { "sdiv", dt_dis_log }, /* DIF_OP_SDIV */ { "udiv", dt_dis_log }, /* DIF_OP_UDIV */ { "srem", dt_dis_log }, /* DIF_OP_SREM */ { "urem", dt_dis_log }, /* DIF_OP_UREM */ { "not", dt_dis_r1rd }, /* DIF_OP_NOT */ { "mov", dt_dis_r1rd }, /* DIF_OP_MOV */ { "cmp", dt_dis_cmp }, /* DIF_OP_CMP */ { "tst", dt_dis_tst }, /* DIF_OP_TST */ { "ba", dt_dis_branch }, /* DIF_OP_BA */ { "be", dt_dis_branch }, /* DIF_OP_BE */ { "bne", dt_dis_branch }, /* DIF_OP_BNE */ { "bg", dt_dis_branch }, /* DIF_OP_BG */ { "bgu", dt_dis_branch }, /* DIF_OP_BGU */ { "bge", dt_dis_branch }, /* DIF_OP_BGE */ { "bgeu", dt_dis_branch }, /* DIF_OP_BGEU */ { "bl", dt_dis_branch }, /* DIF_OP_BL */ { "blu", dt_dis_branch }, /* DIF_OP_BLU */ { "ble", dt_dis_branch }, /* DIF_OP_BLE */ { "bleu", dt_dis_branch }, /* DIF_OP_BLEU */ { "ldsb", dt_dis_load }, /* DIF_OP_LDSB */ { "ldsh", dt_dis_load }, /* DIF_OP_LDSH */ { "ldsw", dt_dis_load }, /* DIF_OP_LDSW */ { "ldub", dt_dis_load }, /* DIF_OP_LDUB */ { "lduh", dt_dis_load }, /* DIF_OP_LDUH */ { "lduw", dt_dis_load }, /* DIF_OP_LDUW */ { "ldx", dt_dis_load }, /* DIF_OP_LDX */ { "ret", dt_dis_ret }, /* DIF_OP_RET */ { "nop", dt_dis_str }, /* DIF_OP_NOP */ { "setx", dt_dis_setx }, /* DIF_OP_SETX */ { "sets", dt_dis_sets }, /* DIF_OP_SETS */ { "scmp", dt_dis_cmp }, /* DIF_OP_SCMP */ { "ldga", dt_dis_lda }, /* DIF_OP_LDGA */ { "ldgs", dt_dis_ldv }, /* DIF_OP_LDGS */ { "stgs", dt_dis_stv }, /* DIF_OP_STGS */ { "ldta", dt_dis_lda }, /* DIF_OP_LDTA */ { "ldts", dt_dis_ldv }, /* DIF_OP_LDTS */ { "stts", dt_dis_stv }, /* DIF_OP_STTS */ { "sra", dt_dis_log }, /* DIF_OP_SRA */ { "call", dt_dis_call }, /* DIF_OP_CALL */ { "pushtr", dt_dis_pushts }, /* DIF_OP_PUSHTR */ { "pushtv", dt_dis_pushts }, /* DIF_OP_PUSHTV */ { "popts", dt_dis_str }, /* DIF_OP_POPTS */ { "flushts", dt_dis_str }, /* DIF_OP_FLUSHTS */ { "ldgaa", dt_dis_ldv }, /* DIF_OP_LDGAA */ { "ldtaa", dt_dis_ldv }, /* DIF_OP_LDTAA */ { "stgaa", dt_dis_stv }, /* DIF_OP_STGAA */ { "sttaa", dt_dis_stv }, /* DIF_OP_STTAA */ { "ldls", dt_dis_ldv }, /* DIF_OP_LDLS */ { "stls", dt_dis_stv }, /* DIF_OP_STLS */ { "allocs", dt_dis_r1rd }, /* DIF_OP_ALLOCS */ { "copys", dt_dis_log }, /* DIF_OP_COPYS */ { "stb", dt_dis_store }, /* DIF_OP_STB */ { "sth", dt_dis_store }, /* DIF_OP_STH */ { "stw", dt_dis_store }, /* DIF_OP_STW */ { "stx", dt_dis_store }, /* DIF_OP_STX */ { "uldsb", dt_dis_load }, /* DIF_OP_ULDSB */ { "uldsh", dt_dis_load }, /* DIF_OP_ULDSH */ { "uldsw", dt_dis_load }, /* DIF_OP_ULDSW */ { "uldub", dt_dis_load }, /* DIF_OP_ULDUB */ { "ulduh", dt_dis_load }, /* DIF_OP_ULDUH */ { "ulduw", dt_dis_load }, /* DIF_OP_ULDUW */ { "uldx", dt_dis_load }, /* DIF_OP_ULDX */ { "rldsb", dt_dis_load }, /* DIF_OP_RLDSB */ { "rldsh", dt_dis_load }, /* DIF_OP_RLDSH */ { "rldsw", dt_dis_load }, /* DIF_OP_RLDSW */ { "rldub", dt_dis_load }, /* DIF_OP_RLDUB */ { "rlduh", dt_dis_load }, /* DIF_OP_RLDUH */ { "rlduw", dt_dis_load }, /* DIF_OP_RLDUW */ { "rldx", dt_dis_load }, /* DIF_OP_RLDX */ { "xlate", dt_dis_xlate }, /* DIF_OP_XLATE */ { "xlarg", dt_dis_xlate }, /* DIF_OP_XLARG */ }; const struct opent *op; ulong_t i = 0; char type[DT_TYPE_NAMELEN]; - (void) fprintf(fp, "\nDIFO 0x%p returns %s\n", (void *)dp, + (void) fprintf(fp, "\nDIFO %p returns %s\n", (void *)dp, dt_dis_typestr(&dp->dtdo_rtype, type, sizeof (type))); (void) fprintf(fp, "%-3s %-8s %s\n", "OFF", "OPCODE", "INSTRUCTION"); for (i = 0; i < dp->dtdo_len; i++) { dif_instr_t instr = dp->dtdo_buf[i]; dif_instr_t opcode = DIF_INSTR_OP(instr); if (opcode >= sizeof (optab) / sizeof (optab[0])) opcode = 0; /* force invalid opcode message */ op = &optab[opcode]; (void) fprintf(fp, "%02lu: %08x ", i, instr); op->op_func(dp, op->op_name, instr, fp); (void) fprintf(fp, "\n"); } if (dp->dtdo_varlen != 0) { (void) fprintf(fp, "\n%-16s %-4s %-3s %-3s %-4s %s\n", "NAME", "ID", "KND", "SCP", "FLAG", "TYPE"); } for (i = 0; i < dp->dtdo_varlen; i++) { dtrace_difv_t *v = &dp->dtdo_vartab[i]; char kind[4], scope[4], flags[16] = { 0 }; switch (v->dtdv_kind) { case DIFV_KIND_ARRAY: (void) strcpy(kind, "arr"); break; case DIFV_KIND_SCALAR: (void) strcpy(kind, "scl"); break; default: (void) snprintf(kind, sizeof (kind), "%u", v->dtdv_kind); } switch (v->dtdv_scope) { case DIFV_SCOPE_GLOBAL: (void) strcpy(scope, "glb"); break; case DIFV_SCOPE_THREAD: (void) strcpy(scope, "tls"); break; case DIFV_SCOPE_LOCAL: (void) strcpy(scope, "loc"); break; default: (void) snprintf(scope, sizeof (scope), "%u", v->dtdv_scope); } if (v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)) { (void) snprintf(flags, sizeof (flags), "/0x%x", v->dtdv_flags & ~(DIFV_F_REF | DIFV_F_MOD)); } if (v->dtdv_flags & DIFV_F_REF) (void) strcat(flags, "/r"); if (v->dtdv_flags & DIFV_F_MOD) (void) strcat(flags, "/w"); (void) fprintf(fp, "%-16s %-4u %-3s %-3s %-4s %s\n", &dp->dtdo_strtab[v->dtdv_name], v->dtdv_id, kind, scope, flags + 1, dt_dis_typestr(&v->dtdv_type, type, sizeof (type))); } if (dp->dtdo_xlmlen != 0) { (void) fprintf(fp, "\n%-4s %-3s %-12s %s\n", "XLID", "ARG", "MEMBER", "TYPE"); } for (i = 0; i < dp->dtdo_xlmlen; i++) { dt_node_t *dnp = dp->dtdo_xlmtab[i]; dt_xlator_t *dxp = dnp->dn_membexpr->dn_xlator; (void) fprintf(fp, "%-4u %-3d %-12s %s\n", (uint_t)dxp->dx_id, dxp->dx_arg, dnp->dn_membname, dt_node_type_name(dnp, type, sizeof (type))); } if (dp->dtdo_krelen != 0) dt_dis_rtab("KREL", dp, fp, dp->dtdo_kreltab, dp->dtdo_krelen); if (dp->dtdo_urelen != 0) dt_dis_rtab("UREL", dp, fp, dp->dtdo_ureltab, dp->dtdo_urelen); } Index: stable/11/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c =================================================================== --- stable/11/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c (revision 324595) +++ stable/11/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c (revision 324596) @@ -1,706 +1,706 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2011 by Delphix. All rights reserved. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ /* * DTrace print() action * * This file contains the post-processing logic for the print() action. The * print action behaves identically to trace() in that it generates a * DTRACEACT_DIFEXPR action, but the action argument field refers to a CTF type * string stored in the DOF string table (similar to printf formats). We * take the result of the trace action and post-process it in the fashion of * MDB's ::print dcmd. * * This implementation differs from MDB's in the following ways: * * - We do not expose any options or flags. The behavior of print() is * equivalent to "::print -tn". * * - MDB will display "holes" in structures (unused padding between * members). * * - When printing arrays of structures, MDB will leave a trailing ',' * after the last element. * * - MDB will print time_t types as date and time. * * - MDB will detect when an enum is actually the OR of several flags, * and print it out with the constituent flags separated. * * - For large arrays, MDB will print the first few members and then * print a "..." continuation line. * * - MDB will break and wrap arrays at 80 columns. * * - MDB prints out floats and doubles by hand, as it must run in kmdb * context. We're able to leverage the printf() format strings, * but the result is a slightly different format. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* determines whether the given integer CTF encoding is a character */ #define CTF_IS_CHAR(e) \ (((e).cte_format & (CTF_INT_CHAR | CTF_INT_SIGNED)) == \ (CTF_INT_CHAR | CTF_INT_SIGNED) && (e).cte_bits == NBBY) /* determines whether the given CTF kind is a struct or union */ #define CTF_IS_STRUCTLIKE(k) \ ((k) == CTF_K_STRUCT || (k) == CTF_K_UNION) /* * Print structure passed down recursively through printing algorithm. */ typedef struct dt_printarg { dtrace_hdl_t *pa_dtp; /* libdtrace handle */ caddr_t pa_addr; /* base address of trace data */ ctf_file_t *pa_ctfp; /* CTF container */ int pa_depth; /* member depth */ int pa_nest; /* nested array depth */ FILE *pa_file; /* output file */ } dt_printarg_t; static int dt_print_member(const char *, ctf_id_t, ulong_t, int, void *); /* * Safe version of ctf_type_name() that will fall back to just "" if it * can't resolve the type. */ static void dt_print_type_name(ctf_file_t *ctfp, ctf_id_t id, char *buf, size_t buflen) { if (ctf_type_name(ctfp, id, buf, buflen) == NULL) (void) snprintf(buf, buflen, "<%ld>", id); } /* * Print any necessary trailing braces for structures or unions. We don't get * invoked when a struct or union ends, so we infer the need to print braces * based on the depth the last time we printed something and the new depth. */ static void dt_print_trailing_braces(dt_printarg_t *pap, int depth) { int d; for (d = pap->pa_depth; d > depth; d--) { (void) fprintf(pap->pa_file, "%*s}%s", (d + pap->pa_nest - 1) * 4, "", d == depth + 1 ? "" : "\n"); } } /* * Print the appropriate amount of indentation given the current depth and * array nesting. */ static void dt_print_indent(dt_printarg_t *pap) { (void) fprintf(pap->pa_file, "%*s", (pap->pa_depth + pap->pa_nest) * 4, ""); } /* * Print a bitfield. It's worth noting that the D compiler support for * bitfields is currently broken; printing "D`user_desc_t" (pulled in by the * various D provider files) will produce incorrect results compared to * "genunix`user_desc_t". */ static void print_bitfield(dt_printarg_t *pap, ulong_t off, ctf_encoding_t *ep) { FILE *fp = pap->pa_file; caddr_t addr = pap->pa_addr + off / NBBY; uint64_t mask = (1ULL << ep->cte_bits) - 1; uint64_t value = 0; size_t size = (ep->cte_bits + (NBBY - 1)) / NBBY; uint8_t *buf = (uint8_t *)&value; uint8_t shift; /* * On big-endian machines, we need to adjust the buf pointer to refer * to the lowest 'size' bytes in 'value', and we need to shift based on * the offset from the end of the data, not the offset of the start. */ #if BYTE_ORDER == _BIG_ENDIAN buf += sizeof (value) - size; off += ep->cte_bits; #endif bcopy(addr, buf, size); shift = off % NBBY; /* * Offsets are counted from opposite ends on little- and * big-endian machines. */ #if BYTE_ORDER == _BIG_ENDIAN shift = NBBY - shift; #endif /* * If the bits we want do not begin on a byte boundary, shift the data * right so that the value is in the lowest 'cte_bits' of 'value'. */ if (off % NBBY != 0) value >>= shift; value &= mask; (void) fprintf(fp, "%#llx", (u_longlong_t)value); } /* * Dump the contents of memory as a fixed-size integer in hex. */ static void dt_print_hex(FILE *fp, caddr_t addr, size_t size) { switch (size) { case sizeof (uint8_t): (void) fprintf(fp, "%#x", *(uint8_t *)addr); break; case sizeof (uint16_t): /* LINTED - alignment */ (void) fprintf(fp, "%#x", *(uint16_t *)addr); break; case sizeof (uint32_t): /* LINTED - alignment */ (void) fprintf(fp, "%#x", *(uint32_t *)addr); break; case sizeof (uint64_t): (void) fprintf(fp, "%#llx", /* LINTED - alignment */ (unsigned long long)*(uint64_t *)addr); break; default: (void) fprintf(fp, "", (uint_t)size); } } /* * Print an integer type. Before dumping the contents via dt_print_hex(), we * first check the encoding to see if it's part of a bitfield or a character. */ static void dt_print_int(ctf_id_t base, ulong_t off, dt_printarg_t *pap) { FILE *fp = pap->pa_file; ctf_file_t *ctfp = pap->pa_ctfp; ctf_encoding_t e; size_t size; caddr_t addr = pap->pa_addr + off / NBBY; if (ctf_type_encoding(ctfp, base, &e) == CTF_ERR) { (void) fprintf(fp, ""); return; } /* * This comes from MDB - it's not clear under what circumstances this * would be found. */ if (e.cte_format & CTF_INT_VARARGS) { (void) fprintf(fp, "..."); return; } /* * We print this as a bitfield if the bit encoding indicates it's not * an even power of two byte size, or is larger than 8 bytes. */ size = e.cte_bits / NBBY; if (size > 8 || (e.cte_bits % NBBY) != 0 || (size & (size - 1)) != 0) { print_bitfield(pap, off, &e); return; } /* * If this is a character, print it out as such. */ if (CTF_IS_CHAR(e)) { char c = *(char *)addr; if (isprint(c)) (void) fprintf(fp, "'%c'", c); else if (c == 0) (void) fprintf(fp, "'\\0'"); else (void) fprintf(fp, "'\\%03o'", c); return; } dt_print_hex(fp, addr, size); } /* * Print a floating point (float, double, long double) value. */ /* ARGSUSED */ static void dt_print_float(ctf_id_t base, ulong_t off, dt_printarg_t *pap) { FILE *fp = pap->pa_file; ctf_file_t *ctfp = pap->pa_ctfp; ctf_encoding_t e; caddr_t addr = pap->pa_addr + off / NBBY; if (ctf_type_encoding(ctfp, base, &e) == 0) { if (e.cte_format == CTF_FP_SINGLE && e.cte_bits == sizeof (float) * NBBY) { /* LINTED - alignment */ (void) fprintf(fp, "%+.7e", *((float *)addr)); } else if (e.cte_format == CTF_FP_DOUBLE && e.cte_bits == sizeof (double) * NBBY) { /* LINTED - alignment */ (void) fprintf(fp, "%+.7e", *((double *)addr)); } else if (e.cte_format == CTF_FP_LDOUBLE && e.cte_bits == sizeof (long double) * NBBY) { /* LINTED - alignment */ (void) fprintf(fp, "%+.16LE", *((long double *)addr)); } else { (void) fprintf(fp, ""); } } } /* * A pointer is generally printed as a fixed-size integer. If we have a * function pointer, we try to look up its name. */ static void dt_print_ptr(ctf_id_t base, ulong_t off, dt_printarg_t *pap) { FILE *fp = pap->pa_file; ctf_file_t *ctfp = pap->pa_ctfp; caddr_t addr = pap->pa_addr + off / NBBY; size_t size = ctf_type_size(ctfp, base); ctf_id_t bid = ctf_type_reference(ctfp, base); uint64_t pc; dtrace_syminfo_t dts; GElf_Sym sym; if (bid == CTF_ERR || ctf_type_kind(ctfp, bid) != CTF_K_FUNCTION) { dt_print_hex(fp, addr, size); } else { /* LINTED - alignment */ pc = *((uint64_t *)addr); if (dtrace_lookup_by_addr(pap->pa_dtp, pc, &sym, &dts) != 0) { dt_print_hex(fp, addr, size); } else { (void) fprintf(fp, "%s`%s", dts.dts_object, dts.dts_name); } } } /* * Print out an array. This is somewhat complex, as we must manually visit * each member, and recursively invoke ctf_type_visit() for each member. If * the members are non-structs, then we print them out directly: * * [ 0x14, 0x2e, 0 ] * * If they are structs, then we print out the necessary leading and trailing * braces, to end up with: * * [ * type { * ... * }, * type { * ... * } * ] * * We also use a heuristic to detect whether the array looks like a character * array. If the encoding indicates it's a character, and we have all * printable characters followed by a null byte, then we display it as a * string: * * [ "string" ] */ static void dt_print_array(ctf_id_t base, ulong_t off, dt_printarg_t *pap) { FILE *fp = pap->pa_file; ctf_file_t *ctfp = pap->pa_ctfp; caddr_t addr = pap->pa_addr + off / NBBY; ctf_arinfo_t car; ssize_t eltsize; ctf_encoding_t e; int i; boolean_t isstring; int kind; ctf_id_t rtype; if (ctf_array_info(ctfp, base, &car) == CTF_ERR) { - (void) fprintf(fp, "0x%p", (void *)addr); + (void) fprintf(fp, "%p", (void *)addr); return; } if ((eltsize = ctf_type_size(ctfp, car.ctr_contents)) < 0 || (rtype = ctf_type_resolve(ctfp, car.ctr_contents)) == CTF_ERR || (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR) { (void) fprintf(fp, "", car.ctr_contents); return; } /* see if this looks like a string */ isstring = B_FALSE; if (kind == CTF_K_INTEGER && ctf_type_encoding(ctfp, rtype, &e) != CTF_ERR && CTF_IS_CHAR(e)) { char c; for (i = 0; i < car.ctr_nelems; i++) { c = *((char *)addr + eltsize * i); if (!isprint(c) || c == '\0') break; } if (i != car.ctr_nelems && c == '\0') isstring = B_TRUE; } /* * As a slight aesthetic optimization, if we are a top-level type, then * don't bother printing out the brackets. This lets print("foo") look * like: * * string "foo" * * As D will internally represent this as a char[256] array. */ if (!isstring || pap->pa_depth != 0) (void) fprintf(fp, "[ "); if (isstring) (void) fprintf(fp, "\""); for (i = 0; i < car.ctr_nelems; i++) { if (isstring) { char c = *((char *)addr + eltsize * i); if (c == '\0') break; (void) fprintf(fp, "%c", c); } else { /* * Recursively invoke ctf_type_visit() on each member. * We setup a new printarg struct with 'pa_nest' set to * indicate that we are within a nested array. */ dt_printarg_t pa = *pap; pa.pa_nest += pap->pa_depth + 1; pa.pa_depth = 0; pa.pa_addr = addr + eltsize * i; (void) ctf_type_visit(ctfp, car.ctr_contents, dt_print_member, &pa); dt_print_trailing_braces(&pa, 0); if (i != car.ctr_nelems - 1) (void) fprintf(fp, ", "); else if (CTF_IS_STRUCTLIKE(kind)) (void) fprintf(fp, "\n"); } } if (isstring) (void) fprintf(fp, "\""); if (!isstring || pap->pa_depth != 0) { if (CTF_IS_STRUCTLIKE(kind)) dt_print_indent(pap); else (void) fprintf(fp, " "); (void) fprintf(fp, "]"); } } /* * This isued by both structs and unions to print the leading brace. */ /* ARGSUSED */ static void dt_print_structlike(ctf_id_t id, ulong_t off, dt_printarg_t *pap) { (void) fprintf(pap->pa_file, "{"); } /* * For enums, we try to print the enum name, and fall back to the value if it * can't be determined. We do not do any fancy flag processing like mdb. */ /* ARGSUSED */ static void dt_print_enum(ctf_id_t base, ulong_t off, dt_printarg_t *pap) { FILE *fp = pap->pa_file; ctf_file_t *ctfp = pap->pa_ctfp; const char *ename; ssize_t size; caddr_t addr = pap->pa_addr + off / NBBY; int value = 0; /* * The C standard says that an enum will be at most the sizeof (int). * But if all the values are less than that, the compiler can use a * smaller size. Thanks standards. */ size = ctf_type_size(ctfp, base); switch (size) { case sizeof (uint8_t): value = *(uint8_t *)addr; break; case sizeof (uint16_t): value = *(uint16_t *)addr; break; case sizeof (int32_t): value = *(int32_t *)addr; break; default: (void) fprintf(fp, "", (uint_t)size); return; } if ((ename = ctf_enum_name(ctfp, base, value)) != NULL) (void) fprintf(fp, "%s", ename); else (void) fprintf(fp, "%d", value); } /* * Forward declaration. There's not much to do here without the complete * type information, so just print out this fact and drive on. */ /* ARGSUSED */ static void dt_print_tag(ctf_id_t base, ulong_t off, dt_printarg_t *pap) { (void) fprintf(pap->pa_file, ""); } typedef void dt_printarg_f(ctf_id_t, ulong_t, dt_printarg_t *); static dt_printarg_f *const dt_printfuncs[] = { dt_print_int, /* CTF_K_INTEGER */ dt_print_float, /* CTF_K_FLOAT */ dt_print_ptr, /* CTF_K_POINTER */ dt_print_array, /* CTF_K_ARRAY */ dt_print_ptr, /* CTF_K_FUNCTION */ dt_print_structlike, /* CTF_K_STRUCT */ dt_print_structlike, /* CTF_K_UNION */ dt_print_enum, /* CTF_K_ENUM */ dt_print_tag /* CTF_K_FORWARD */ }; /* * Print one member of a structure. This callback is invoked from * ctf_type_visit() recursively. */ static int dt_print_member(const char *name, ctf_id_t id, ulong_t off, int depth, void *data) { char type[DT_TYPE_NAMELEN]; int kind; dt_printarg_t *pap = data; FILE *fp = pap->pa_file; ctf_file_t *ctfp = pap->pa_ctfp; boolean_t arraymember; boolean_t brief; ctf_encoding_t e; ctf_id_t rtype; dt_print_trailing_braces(pap, depth); /* * dt_print_trailing_braces() doesn't include the trailing newline; add * it here if necessary. */ if (depth < pap->pa_depth) (void) fprintf(fp, "\n"); pap->pa_depth = depth; if ((rtype = ctf_type_resolve(ctfp, id)) == CTF_ERR || (kind = ctf_type_kind(ctfp, rtype)) == CTF_ERR || kind < CTF_K_INTEGER || kind > CTF_K_FORWARD) { dt_print_indent(pap); (void) fprintf(fp, "%s = ", name, id); return (0); } dt_print_type_name(ctfp, id, type, sizeof (type)); arraymember = (pap->pa_nest != 0 && depth == 0); brief = (arraymember && !CTF_IS_STRUCTLIKE(kind)); if (!brief) { /* * If this is a direct array member and a struct (otherwise * brief would be true), then print a trailing newline, as the * array printing code doesn't include it because it might be a * simple type. */ if (arraymember) (void) fprintf(fp, "\n"); dt_print_indent(pap); /* always print the type */ (void) fprintf(fp, "%s", type); if (name[0] != '\0') { /* * For aesthetics, we don't include a space between the * type name and member name if the type is a pointer. * This will give us "void *foo =" instead of "void * * foo =". Unions also have the odd behavior that the * type name is returned as "union ", with a trailing * space, so we also avoid printing a space if the type * name already ends with a space. */ if (type[strlen(type) - 1] != '*' && type[strlen(type) -1] != ' ') { (void) fprintf(fp, " "); } (void) fprintf(fp, "%s", name); /* * If this looks like a bitfield, or is an integer not * aligned on a byte boundary, print the number of * bits after the name. */ if (kind == CTF_K_INTEGER && ctf_type_encoding(ctfp, id, &e) == 0) { ulong_t bits = e.cte_bits; ulong_t size = bits / NBBY; if (bits % NBBY != 0 || off % NBBY != 0 || size > 8 || size != ctf_type_size(ctfp, id)) { (void) fprintf(fp, " :%lu", bits); } } (void) fprintf(fp, " ="); } (void) fprintf(fp, " "); } dt_printfuncs[kind - 1](rtype, off, pap); /* direct simple array members are not separated by newlines */ if (!brief) (void) fprintf(fp, "\n"); return (0); } /* * Main print function invoked by dt_consume_cpu(). */ int dtrace_print(dtrace_hdl_t *dtp, FILE *fp, const char *typename, caddr_t addr, size_t len) { const char *s; char *object; dt_printarg_t pa; ctf_id_t id; dt_module_t *dmp; ctf_file_t *ctfp; int libid; /* * Split the fully-qualified type ID (module`id). This should * always be the format, but if for some reason we don't find the * expected value, return 0 to fall back to the generic trace() * behavior. In the case of userland CTF modules this will actually be * of the format (module`lib`id). This is due to the fact that those * modules have multiple CTF containers which `lib` identifies. */ for (s = typename; *s != '\0' && *s != '`'; s++) ; if (*s != '`') return (0); object = alloca(s - typename + 1); bcopy(typename, object, s - typename); object[s - typename] = '\0'; dmp = dt_module_lookup_by_name(dtp, object); if (dmp == NULL) return (0); if (dmp->dm_pid != 0) { libid = atoi(s + 1); s = strchr(s + 1, '`'); if (s == NULL || libid > dmp->dm_nctflibs) return (0); ctfp = dmp->dm_libctfp[libid]; } else { ctfp = dt_module_getctf(dtp, dmp); } id = atoi(s + 1); /* * Try to get the CTF kind for this id. If something has gone horribly * wrong and we can't resolve the ID, bail out and let trace() do the * work. */ if (ctfp == NULL || ctf_type_kind(ctfp, id) == CTF_ERR) return (0); /* setup the print structure and kick off the main print routine */ pa.pa_dtp = dtp; pa.pa_addr = addr; pa.pa_ctfp = ctfp; pa.pa_nest = 0; pa.pa_depth = 0; pa.pa_file = fp; (void) ctf_type_visit(pa.pa_ctfp, id, dt_print_member, &pa); dt_print_trailing_braces(&pa, 0); return (len); } Index: stable/11 =================================================================== --- stable/11 (revision 324595) +++ stable/11 (revision 324596) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r324373