svn commit: r248708 - in head: cddl/contrib/opensolaris/lib/libdtrace/common cddl/lib/libdtrace sys/cddl/contrib/opensolaris/uts/common/dtrace

Pedro F. Giffuni pfg at FreeBSD.org
Mon Mar 25 20:38:11 UTC 2013


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 ***


More information about the svn-src-all mailing list