Author: pfg
Date: Mon Mar 25 20:38:09 2013
New Revision: 248708
URL: http://svnweb.freebsd.org/changeset/base/248708

Log:
  Dtrace: Add SUN MDB-like type-aware print() action.
  
  Merge change from illumos:
  
  1694 Add type-aware print() action
  
  This is a very nice feature implemented in upstream Dtrace.
  A complete description is available here:
  http://dtrace.org/blogs/eschrock/2011/10/26/your-mdb-fell-into-my-dtrace/
  
  This change bumps the DT_VERS_* number to 1.9.0 in
  accordance to what is done in illumos.
  
  While here also include some minor cleanups to ease further merging
  and appease clang with a fix by Fabian Keil.
  
  Illumos Revisions:    13501:c3a7090dbc16
                        13483:f413e6c5d297
  
  Reference:
  https://www.illumos.org/issues/1560
  https://www.illumos.org/issues/1694
  
  Tested by:    Fabian Keil
  Obtained from:        Illumos
  MFC after:    1 month

Added:
     - copied from r248707, 
vendor/illumos/20120614/cmd/dtrace/test/tst/common/print/
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c
     - copied unchanged from r248707, 
vendor/illumos/dist/lib/libdtrace/common/dt_print.c
Directory Properties:
  head/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/print/   (props 
changed)
Modified:
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_program.c
  head/cddl/contrib/opensolaris/lib/libdtrace/common/dtrace.h
  head/cddl/lib/libdtrace/Makefile
  head/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c  Mon Mar 25 
19:12:36 2013        (r248707)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_cc.c  Mon Mar 25 
20:38:09 2013        (r248708)
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011, Joyent Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
  */
 
 /*
@@ -679,6 +680,51 @@ dt_action_trace(dtrace_hdl_t *dtp, dt_no
        ap->dtad_kind = DTRACEACT_DIFEXPR;
 }
 
+/*
+ * The print() action behaves identically to trace(), except that it stores the
+ * CTF type of the argument (if present) within the DOF for the DIFEXPR action.
+ * To do this, we set the 'dtsd_strdata' to point to the fully-qualified CTF
+ * type ID for the result of the DIF action.  We use the ID instead of the name
+ * to handles complex types like arrays and function pointers that can't be
+ * resolved by ctf_type_lookup().  This is later processed by
+ * dtrace_dof_create() and turned into a reference into the string table so
+ * that we can get the type information when we process the data after the
+ * fact.
+ */
+static void
+dt_action_print(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+       dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+       dt_node_t *dret;
+       size_t len;
+       dt_module_t *dmp;
+
+       if (dt_node_is_void(dnp->dn_args)) {
+               dnerror(dnp->dn_args, D_PRINT_VOID,
+                   "print( ) may not be applied to a void expression\n");
+       }
+
+       if (dt_node_is_dynamic(dnp->dn_args)) {
+               dnerror(dnp->dn_args, D_PRINT_DYN,
+                   "print( ) may not be applied to a dynamic expression\n");
+       }
+
+       dt_cg(yypcb, dnp->dn_args);
+
+       dret = yypcb->pcb_dret;
+       dmp = dt_module_lookup_by_ctf(dtp, dret->dn_ctfp);
+
+       len = snprintf(NULL, 0, "%s`%ld", dmp->dm_name, dret->dn_type) + 1;
+       sdp->dtsd_strdata = dt_alloc(dtp, len);
+       if (sdp->dtsd_strdata == NULL)
+               longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
+       (void) snprintf(sdp->dtsd_strdata, len, "%s`%ld", dmp->dm_name,
+           dret->dn_type);
+
+       ap->dtad_difo = dt_as(yypcb);
+       ap->dtad_kind = DTRACEACT_DIFEXPR;
+}
+
 static void
 dt_action_tracemem(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
 {
@@ -1135,6 +1181,9 @@ dt_compile_fun(dtrace_hdl_t *dtp, dt_nod
        case DT_ACT_TRACE:
                dt_action_trace(dtp, dnp->dn_expr, sdp);
                break;
+       case DT_ACT_PRINT:
+               dt_action_print(dtp, dnp->dn_expr, sdp);
+               break;
        case DT_ACT_TRACEMEM:
                dt_action_tracemem(dtp, dnp->dn_expr, sdp);
                break;

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c     Mon Mar 
25 19:12:36 2013        (r248707)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_consume.c     Mon Mar 
25 20:38:09 2013        (r248708)
@@ -25,6 +25,7 @@
 
 /*
  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
  */
 
 #include <stdlib.h>
@@ -2193,6 +2194,7 @@ again:
 
                        if (act == DTRACEACT_TRACEMEM_DYNSIZE &&
                            rec->dtrd_size == sizeof (uint64_t)) {
+                               /* LINTED - alignment */
                                tracememsize = *((unsigned long long *)addr);
                                continue;
                        }
@@ -2300,6 +2302,35 @@ again:
                                goto nextrec;
                        }
 
+                       /*
+                        * If this is a DIF expression, and the record has a
+                        * format set, this indicates we have a CTF type name
+                        * associated with the data and we should try to print
+                        * it out by type.
+                        */
+                       if (act == DTRACEACT_DIFEXPR) {
+                               const char *strdata = dt_strdata_lookup(dtp,
+                                   rec->dtrd_format);
+                               if (strdata != NULL) {
+                                       n = dtrace_print(dtp, fp, strdata,
+                                           addr, rec->dtrd_size);
+
+                                       /*
+                                        * dtrace_print() will return -1 on
+                                        * error, or return the number of bytes
+                                        * consumed.  It will return 0 if the
+                                        * type couldn't be determined, and we
+                                        * should fall through to the normal
+                                        * trace method.
+                                        */
+                                       if (n < 0)
+                                               return (-1);
+
+                                       if (n > 0)
+                                               goto nextrec;
+                               }
+                       }
+
 nofmt:
                        if (act == DTRACEACT_PRINTA) {
                                dt_print_aggdata_t pd;

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c Mon Mar 25 
19:12:36 2013        (r248707)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_dof.c Mon Mar 25 
20:38:09 2013        (r248708)
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -758,16 +759,23 @@ dtrace_dof_create(dtrace_hdl_t *dtp, dtr
                                dofa[i].dofa_difo = DOF_SECIDX_NONE;
 
                        /*
-                        * If the first action in a statement has format data,
-                        * add the format string to the global string table.
+                        * If the first action in a statement has string data,
+                        * add the string to the global string table.  This can
+                        * be due either to a printf() format string
+                        * (dtsd_fmtdata) or a print() type string
+                        * (dtsd_strdata).
                         */
                        if (sdp != NULL && ap == sdp->dtsd_action) {
                                if (sdp->dtsd_fmtdata != NULL) {
                                        (void) dtrace_printf_format(dtp,
                                            sdp->dtsd_fmtdata, fmt, maxfmt + 1);
                                        strndx = dof_add_string(ddo, fmt);
-                               } else
+                               } else if (sdp->dtsd_strdata != NULL) {
+                                       strndx = dof_add_string(ddo,
+                                           sdp->dtsd_strdata);
+                               } else {
                                        strndx = 0; /* use dtad_arg instead */
+                               }
 
                                if ((next = dt_list_next(next)) != NULL)
                                        sdp = next->ds_desc;

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h     Mon Mar 
25 19:12:36 2013        (r248707)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h     Mon Mar 
25 20:38:09 2013        (r248708)
@@ -24,11 +24,14 @@
  * Use is subject to license terms.
  */
 
+ /*
+  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+  * Copyright (c) 2011 by Delphix. All rights reserved.
+  */
+
 #ifndef        _DT_ERRTAGS_H
 #define        _DT_ERRTAGS_H
 
-#pragma ident  "%Z%%M% %I%     %E% SMI"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -187,6 +190,8 @@ typedef enum {
        D_PRINTA_AGGPROTO,              /* printa() aggregation mismatch */
        D_TRACE_VOID,                   /* trace() argument has void type */
        D_TRACE_DYN,                    /* trace() argument has dynamic type */
+       D_PRINT_VOID,                   /* print() argument has void type */
+       D_PRINT_DYN,                    /* print() argument has dynamic type */
        D_TRACEMEM_ADDR,                /* tracemem() address bad type */
        D_TRACEMEM_SIZE,                /* tracemem() size bad type */
        D_TRACEMEM_ARGS,                /* tracemem() illegal number of args */

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h        Mon Mar 
25 19:12:36 2013        (r248707)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_impl.h        Mon Mar 
25 20:38:09 2013        (r248708)
@@ -26,6 +26,7 @@
 
 /*
  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
  */
 
 #ifndef        _DT_IMPL_H
@@ -253,6 +254,8 @@ struct dtrace_hdl {
        dtrace_aggdesc_t **dt_aggdesc; /* aggregation descriptions */
        int dt_maxformat;       /* max format ID */
        void **dt_formats;      /* pointer to format array */
+       int dt_maxstrdata;      /* max strdata ID */
+       char **dt_strdata;      /* pointer to strdata array */
        dt_aggregate_t dt_aggregate; /* aggregate */
        dtrace_bufdesc_t dt_buf; /* staging buffer */
        struct dt_pfdict *dt_pfdict; /* dictionary of printf conversions */
@@ -438,8 +441,9 @@ struct dtrace_hdl {
 #define        DT_ACT_UMOD             DT_ACT(26)      /* umod() action */
 #define        DT_ACT_UADDR            DT_ACT(27)      /* uaddr() action */
 #define        DT_ACT_SETOPT           DT_ACT(28)      /* setopt() action */
-#define        DT_ACT_PRINTM           DT_ACT(29)      /* printm() action */
-#define        DT_ACT_PRINTT           DT_ACT(30)      /* printt() action */
+#define        DT_ACT_PRINT            DT_ACT(29)      /* print() action */
+#define        DT_ACT_PRINTM           DT_ACT(30)      /* printm() action */
+#define        DT_ACT_PRINTT           DT_ACT(31)      /* printt() action */
 
 /*
  * Sentinel to tell freopen() to restore the saved stdout.  This must not
@@ -641,6 +645,9 @@ extern void dt_aggid_destroy(dtrace_hdl_
 extern void *dt_format_lookup(dtrace_hdl_t *, int);
 extern void dt_format_destroy(dtrace_hdl_t *);
 
+extern const char *dt_strdata_lookup(dtrace_hdl_t *, int);
+extern void dt_strdata_destroy(dtrace_hdl_t *);
+
 extern int dt_print_quantize(dtrace_hdl_t *, FILE *,
     const void *, size_t, uint64_t);
 extern int dt_print_lquantize(dtrace_hdl_t *, FILE *,

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c Mon Mar 25 
19:12:36 2013        (r248707)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_map.c Mon Mar 25 
20:38:09 2013        (r248708)
@@ -23,7 +23,9 @@
  * Use is subject to license terms.
  */
 
-#pragma ident  "%Z%%M% %I%     %E% SMI"
+/*
+ * Copyright (c) 2011 by Delphix. All rights reserved.
+ */
 
 #include <stdlib.h>
 #include <strings.h>
@@ -35,10 +37,81 @@
 #include <dt_printf.h>
 
 static int
+dt_strdata_add(dtrace_hdl_t *dtp, dtrace_recdesc_t *rec, void ***data, int 
*max)
+{
+       int maxformat;
+       dtrace_fmtdesc_t fmt;
+       void *result;
+
+       if (rec->dtrd_format == 0)
+               return (0);
+
+       if (rec->dtrd_format <= *max &&
+           (*data)[rec->dtrd_format - 1] != NULL) {
+               return (0);
+       }
+
+       bzero(&fmt, sizeof (fmt));
+       fmt.dtfd_format = rec->dtrd_format;
+       fmt.dtfd_string = NULL;
+       fmt.dtfd_length = 0;
+
+       if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1)
+               return (dt_set_errno(dtp, errno));
+
+       if ((fmt.dtfd_string = dt_alloc(dtp, fmt.dtfd_length)) == NULL)
+               return (dt_set_errno(dtp, EDT_NOMEM));
+
+       if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
+               free(fmt.dtfd_string);
+               return (dt_set_errno(dtp, errno));
+       }
+
+       while (rec->dtrd_format > (maxformat = *max)) {
+               int new_max = maxformat ? (maxformat << 1) : 1;
+               size_t nsize = new_max * sizeof (void *);
+               size_t osize = maxformat * sizeof (void *);
+               void **new_data = dt_zalloc(dtp, nsize);
+
+               if (new_data == NULL) {
+                       dt_free(dtp, fmt.dtfd_string);
+                       return (dt_set_errno(dtp, EDT_NOMEM));
+               }
+
+               bcopy(*data, new_data, osize);
+               free(*data);
+
+               *data = new_data;
+               *max = new_max;
+       }
+
+       switch (rec->dtrd_action) {
+       case DTRACEACT_DIFEXPR:
+               result = fmt.dtfd_string;
+               break;
+       case DTRACEACT_PRINTA:
+               result = dtrace_printa_create(dtp, fmt.dtfd_string);
+               dt_free(dtp, fmt.dtfd_string);
+               break;
+       default:
+               result = dtrace_printf_create(dtp, fmt.dtfd_string);
+               dt_free(dtp, fmt.dtfd_string);
+               break;
+       }
+
+       if (result == NULL)
+               return (-1);
+
+       (*data)[rec->dtrd_format - 1] = result;
+
+       return (0);
+}
+
+static int
 dt_epid_add(dtrace_hdl_t *dtp, dtrace_epid_t id)
 {
        dtrace_id_t max;
-       int rval, i, maxformat;
+       int rval, i;
        dtrace_eprobedesc_t *enabled, *nenabled;
        dtrace_probedesc_t *probe;
 
@@ -132,71 +205,23 @@ dt_epid_add(dtrace_hdl_t *dtp, dtrace_ep
        }
 
        for (i = 0; i < enabled->dtepd_nrecs; i++) {
-               dtrace_fmtdesc_t fmt;
                dtrace_recdesc_t *rec = &enabled->dtepd_rec[i];
 
-               if (!DTRACEACT_ISPRINTFLIKE(rec->dtrd_action))
-                       continue;
-
-               if (rec->dtrd_format == 0)
-                       continue;
-
-               if (rec->dtrd_format <= dtp->dt_maxformat &&
-                   dtp->dt_formats[rec->dtrd_format - 1] != NULL)
-                       continue;
-
-               bzero(&fmt, sizeof (fmt));
-               fmt.dtfd_format = rec->dtrd_format;
-               fmt.dtfd_string = NULL;
-               fmt.dtfd_length = 0;
-
-               if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
-                       rval = dt_set_errno(dtp, errno);
-                       goto err;
-               }
-
-               if ((fmt.dtfd_string = malloc(fmt.dtfd_length)) == NULL) {
-                       rval = dt_set_errno(dtp, EDT_NOMEM);
-                       goto err;
-               }
-
-               if (dt_ioctl(dtp, DTRACEIOC_FORMAT, &fmt) == -1) {
-                       rval = dt_set_errno(dtp, errno);
-                       free(fmt.dtfd_string);
-                       goto err;
-               }
-
-               while (rec->dtrd_format > (maxformat = dtp->dt_maxformat)) {
-                       int new_max = maxformat ? (maxformat << 1) : 1;
-                       size_t nsize = new_max * sizeof (void *);
-                       size_t osize = maxformat * sizeof (void *);
-                       void **new_formats = malloc(nsize);
-
-                       if (new_formats == NULL) {
-                               rval = dt_set_errno(dtp, EDT_NOMEM);
-                               free(fmt.dtfd_string);
+               if (DTRACEACT_ISPRINTFLIKE(rec->dtrd_action)) {
+                       if (dt_strdata_add(dtp, rec, &dtp->dt_formats,
+                           &dtp->dt_maxformat) != 0) {
+                               rval = -1;
+                               goto err;
+                       }
+               } else if (rec->dtrd_action == DTRACEACT_DIFEXPR) {
+                       if (dt_strdata_add(dtp, rec,
+                           (void ***)&dtp->dt_strdata,
+                           &dtp->dt_maxstrdata) != 0) {
+                               rval = -1;
                                goto err;
                        }
-
-                       bzero(new_formats, nsize);
-                       bcopy(dtp->dt_formats, new_formats, osize);
-                       free(dtp->dt_formats);
-
-                       dtp->dt_formats = new_formats;
-                       dtp->dt_maxformat = new_max;
                }
 
-               dtp->dt_formats[rec->dtrd_format - 1] =
-                   rec->dtrd_action == DTRACEACT_PRINTA ?
-                   dtrace_printa_create(dtp, fmt.dtfd_string) :
-                   dtrace_printf_create(dtp, fmt.dtfd_string);
-
-               free(fmt.dtfd_string);
-
-               if (dtp->dt_formats[rec->dtrd_format - 1] == NULL) {
-                       rval = -1; /* dt_errno is set for us */
-                       goto err;
-               }
        }
 
        dtp->dt_pdesc[id] = probe;
@@ -440,3 +465,28 @@ dt_aggid_destroy(dtrace_hdl_t *dtp)
        dtp->dt_aggdesc = NULL;
        dtp->dt_maxagg = 0;
 }
+
+const char *
+dt_strdata_lookup(dtrace_hdl_t *dtp, int idx)
+{
+       if (idx == 0 || idx > dtp->dt_maxstrdata)
+               return (NULL);
+
+       if (dtp->dt_strdata == NULL)
+               return (NULL);
+
+       return (dtp->dt_strdata[idx - 1]);
+}
+
+void
+dt_strdata_destroy(dtrace_hdl_t *dtp)
+{
+       int i;
+
+       for (i = 0; i < dtp->dt_maxstrdata; i++) {
+               free(dtp->dt_strdata[i]);
+       }
+
+       free(dtp->dt_strdata);
+       dtp->dt_strdata = NULL;
+}

Modified: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c
==============================================================================
--- head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c        Mon Mar 
25 19:12:36 2013        (r248707)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_open.c        Mon Mar 
25 20:38:09 2013        (r248708)
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2011 by Delphix. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -119,8 +120,9 @@
 #define        DT_VERS_1_7_1   DT_VERSION_NUMBER(1, 7, 1)
 #define        DT_VERS_1_8     DT_VERSION_NUMBER(1, 8, 0)
 #define        DT_VERS_1_8_1   DT_VERSION_NUMBER(1, 8, 1)
-#define        DT_VERS_LATEST  DT_VERS_1_8_1
-#define        DT_VERS_STRING  "Sun D 1.8.1"
+#define        DT_VERS_1_9     DT_VERSION_NUMBER(1, 9, 0)
+#define        DT_VERS_LATEST  DT_VERS_1_9
+#define        DT_VERS_STRING  "Sun D 1.9"
 
 const dt_version_t _dtrace_versions[] = {
        DT_VERS_1_0,    /* D API 1.0.0 (PSARC 2001/466) Solaris 10 FCS */
@@ -140,6 +142,7 @@ const dt_version_t _dtrace_versions[] = 
        DT_VERS_1_7_1,  /* D API 1.7.1 */
        DT_VERS_1_8,    /* D API 1.8 */
        DT_VERS_1_8_1,  /* D API 1.8.1 */
+       DT_VERS_1_9,    /* D API 1.9 */
        0
 };
 
@@ -357,6 +360,8 @@ static const dt_ident_t _dtrace_globals[
        &dt_idops_type, "pid_t" },
 { "ppid", DT_IDENT_SCALAR, 0, DIF_VAR_PPID, DT_ATTR_STABCMN, DT_VERS_1_0,
        &dt_idops_type, "pid_t" },
+{ "print", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINT, DT_ATTR_STABCMN, DT_VERS_1_9,
+       &dt_idops_func, "void(@)" },
 { "printa", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTA, DT_ATTR_STABCMN, DT_VERS_1_0,
        &dt_idops_func, "void(@, ...)" },
 { "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0,
@@ -1622,6 +1627,7 @@ dtrace_close(dtrace_hdl_t *dtp)
        dt_epid_destroy(dtp);
        dt_aggid_destroy(dtp);
        dt_format_destroy(dtp);
+       dt_strdata_destroy(dtp);
        dt_buffered_destroy(dtp);
        dt_aggregate_destroy(dtp);
        free(dtp->dt_buf.dtbd_data);

Copied: head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c (from 
r248707, vendor/illumos/dist/lib/libdtrace/common/dt_print.c)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/cddl/contrib/opensolaris/lib/libdtrace/common/dt_print.c       Mon Mar 
25 20:38:09 2013        (r248708, copy of r248707, 
vendor/illumos/dist/lib/libdtrace/common/dt_print.c)
@@ -0,0 +1,648 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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 <sys/sysmacros.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <dt_module.h>
+#include <dt_printf.h>
+#include <dt_string.h>
+#include <dt_impl.h>
+
+/* 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 {
+       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 "<ctfid>" 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.
+        */
+#ifdef _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.
+        */
+#ifdef _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, "<invalid size %u>", (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, "<unknown encoding>");
+               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, "<unknown encoding>");
+               }
+       }
+}
+
+/*
+ * A pointer is printed as a fixed-size integer.  This is used both for
+ * pointers and functions.
+ */
+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);
+
+       dt_print_hex(fp, addr, size);
+}
+
+/*
+ * 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);
+               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, "<invalid type %lu>", 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;
+       int value = 0;
+
+       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, "<forward decl>");
+}
+
+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;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to