Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 5 Feb 2008 07:39:36 GMT
From:      John Birrell <jb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 134827 for review
Message-ID:  <200802050739.m157da2Q007601@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=134827

Change 134827 by jb@jb_freebsd1 on 2008/02/05 07:38:56

	The DTrace tracemem() action has the disadvantage that the size argument
	must be a constant, so it's not terribly useful when trying to trace
	memory which varies in size. I have bumped into this problem so often
	that I decided I needed to actually extend Sun's DTrace design to do
	something more convenient for dumping memory.
	
	Another problem with tracemem() is that it uses dt_print_bytes()
	which tries to be clever and recognise text and 4 and 8 byte integers.
	What I _really_ want to to dump memory in hex. I just can't recognise
	8 byte integers output in decimal when I _really_ want to see each 
	byte.
	
	And to have to specify _exactly_ the memory length when I write the
	D script is really, _really_, *REALLY* annoying.
	
	Part of the problem is that DIF executed with each action is only 
	capable of returning a single 64-bit value. To implement a variable
	length memory trace, I really need to return a memory address _and_
	a size (or length).
	
	To work around the DIF emulation return variable limitation, introduce
	a 'memref' subroutine to combine the address and length into a 'memref'
	variable allocated in scratch space and return a pointer to that as
	the single return value. Then, when back in the action execution code
	for PRINTM, unravel the 'memref' to get the size and adjust the variables
	so that the BYREF code uses the size obtained from the DIF code as well
	as the address.
	
	We still have to specify the size in the printm() action because the
	enabling control block code wants to know what buffer size it requires
	up-front, presumable to avoid having to check for buffer overrun while
	executing the actions.
	
	So... the new action is:
	
	printm(size_t, uint64_t *)
	
	where the size_t *must* be a constant. This allocates the maximum 
	buffer space we reserve. In the event that the traced memory is shorter
	than this value, we just waste the space.
	
	The second argument to printm() is the 'memref' which is a double
	uint64_t value (array) containing the memory address as the first
	entry and the size as the second entry.
	
	To trace a variable length memory buffer:
	
	printf(512, memref(ptr, len));
	
	where 512 is the maximum buffer length we'll accept; ptr is a pointer
	to the memory we are tracing; and len is the length of memory we
	want to trace. Both 'ptr' and 'len' are the result of a DIF expression.
	
	If the memory address is in user space, then it's a little bit more
	obscure:
	
	printm(512, memref(copyin(addr, len), len));
	
	where 'addr' is the address in user space.

Affected files ...

.. //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_cc.c#9 edit
.. //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_consume.c#11 edit
.. //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h#5 edit
.. //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_impl.h#19 edit
.. //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_open.c#23 edit
.. //depot/projects/dtrace/src/sys/contrib/opensolaris/uts/common/dtrace/dtrace.c#32 edit
.. //depot/projects/dtrace/src/sys/contrib/opensolaris/uts/common/sys/dtrace.h#33 edit

Differences ...

==== //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_cc.c#9 (text) ====

@@ -949,6 +949,37 @@
 }
 
 static void
+dt_action_printm(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
+{
+	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
+
+	dt_node_t *size = dnp->dn_args;
+	dt_node_t *addr = dnp->dn_args->dn_list;
+
+	char n[DT_TYPE_NAMELEN];
+
+	if (dt_node_is_posconst(size) == 0) {
+		dnerror(size, D_PRINTM_SIZE, "printm( ) argument #1 must "
+		    "be a non-zero positive integral constant expression\n");
+	}
+
+	if (dt_node_is_pointer(addr) == 0) {
+		dnerror(addr, D_PRINTM_ADDR,
+		    "tracemem( ) argument #2 is incompatible with "
+		    "prototype:\n\tprototype: integer\n"
+		    "\t argument: %s\n",
+		    dt_node_type_name(addr, n, sizeof (n)));
+	}
+
+	dt_cg(yypcb, addr);
+	ap->dtad_difo = dt_as(yypcb);
+	ap->dtad_kind = DTRACEACT_PRINTM;
+
+	ap->dtad_difo->dtdo_rtype.dtdt_flags |= DIF_TF_BYREF;
+	ap->dtad_difo->dtdo_rtype.dtdt_size = size->dn_value + sizeof(uint64_t);
+}
+
+static void
 dt_action_commit(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp)
 {
 	dtrace_actdesc_t *ap = dt_stmt_action(dtp, sdp);
@@ -1014,6 +1045,9 @@
 	case DT_ACT_PRINTF:
 		dt_action_printflike(dtp, dnp->dn_expr, sdp, DTRACEACT_PRINTF);
 		break;
+	case DT_ACT_PRINTM:
+		dt_action_printm(dtp, dnp->dn_expr, sdp);
+		break;
 	case DT_ACT_RAISE:
 		dt_action_raise(dtp, dnp->dn_expr, sdp);
 		break;

==== //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_consume.c#11 (text) ====

@@ -375,7 +375,7 @@
 /*ARGSUSED*/
 int
 dt_print_bytes(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr,
-    size_t nbytes, int width, int quiet)
+    size_t nbytes, int width, int quiet, int raw)
 {
 	/*
 	 * If the byte stream is a series of printable characters, followed by
@@ -388,7 +388,7 @@
 	if (nbytes == 0)
 		return (0);
 
-	if (dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
+	if (raw || dtp->dt_options[DTRACEOPT_RAWBYTES] != DTRACEOPT_UNSET)
 		goto raw;
 
 	for (i = 0; i < nbytes; i++) {
@@ -797,6 +797,16 @@
 #endif
 }
 
+int
+dt_print_memory(dtrace_hdl_t *dtp, FILE *fp, caddr_t addr)
+{
+	int quiet = (dtp->dt_options[DTRACEOPT_QUIET] != DTRACEOPT_UNSET);
+	size_t nbytes = *((uint64_t *) addr);
+
+	return (dt_print_bytes(dtp, fp, addr + sizeof(uint64_t),
+	    nbytes, 50, quiet, 1));
+}
+
 static int
 dt_print_sym(dtrace_hdl_t *dtp, FILE *fp, const char *format, caddr_t addr)
 {
@@ -1113,7 +1123,7 @@
 		    (uint32_t)normal);
 		break;
 	default:
-		err = dt_print_bytes(dtp, fp, addr, size, 50, 0);
+		err = dt_print_bytes(dtp, fp, addr, size, 50, 0, 0);
 		break;
 	}
 
@@ -1488,6 +1498,12 @@
 				goto nextrec;
 			}
 
+			if (act == DTRACEACT_PRINTM) {
+				if (dt_print_memory(dtp, fp, addr) < 0)
+					return (-1);
+				goto nextrec;
+			}
+
 			if (DTRACEACT_ISPRINTFLIKE(act)) {
 				void *fmtdata;
 				int (*func)(dtrace_hdl_t *, FILE *, void *,
@@ -1618,7 +1634,7 @@
 				break;
 			default:
 				n = dt_print_bytes(dtp, fp, addr,
-				    rec->dtrd_size, 33, quiet);
+				    rec->dtrd_size, 33, quiet, 0);
 				break;
 			}
 

==== //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_errtags.h#5 (text) ====

@@ -235,7 +235,9 @@
 	D_FREOPEN_INVALID,		/* frename() filename is invalid */
 	D_LQUANT_MATCHBASE,		/* lquantize() mismatch on base */
 	D_LQUANT_MATCHLIM,		/* lquantize() mismatch on limit */
-	D_LQUANT_MATCHSTEP		/* lquantize() mismatch on step */
+	D_LQUANT_MATCHSTEP,		/* lquantize() mismatch on step */
+	D_PRINTM_ADDR,			/* printm() address bad type */
+	D_PRINTM_SIZE			/* printm() size bad type */
 } dt_errtag_t;
 
 extern const char *dt_errtag(dt_errtag_t);

==== //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_impl.h#19 (text) ====

@@ -430,6 +430,7 @@
 #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 */
 
 /*
  * Sentinel to tell freopen() to restore the saved stdout.  This must not

==== //depot/projects/dtrace/src/contrib/opensolaris/lib/libdtrace/common/dt_open.c#23 (text) ====

@@ -272,6 +272,8 @@
 	&dt_idops_func, "void(@, int32_t, int32_t, ...)" },
 { "max", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MAX, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "void(@)" },
+{ "memref", DT_IDENT_FUNC, 0, DIF_SUBR_MEMREF, DT_ATTR_STABCMN, DT_VERS_1_1,
+	&dt_idops_func, "uint64_t *(void *, size_t)" },
 { "min", DT_IDENT_AGGFUNC, 0, DTRACEAGG_MIN, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "void(@)" },
 { "mod", DT_IDENT_ACTFUNC, 0, DT_ACT_MOD, DT_ATTR_STABCMN,
@@ -312,6 +314,8 @@
 	&dt_idops_func, "void(@, ...)" },
 { "printf", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTF, DT_ATTR_STABCMN, DT_VERS_1_0,
 	&dt_idops_func, "void(@, ...)" },
+{ "printm", DT_IDENT_ACTFUNC, 0, DT_ACT_PRINTM, DT_ATTR_STABCMN, DT_VERS_1_0,
+	&dt_idops_func, "void(size_t, uint64_t *)" },
 { "probefunc", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEFUNC,
 	DT_ATTR_STABCMN, DT_VERS_1_0, &dt_idops_type, "string" },
 { "probemod", DT_IDENT_SCALAR, 0, DIF_VAR_PROBEMOD,

==== //depot/projects/dtrace/src/sys/contrib/opensolaris/uts/common/dtrace/dtrace.c#32 (text) ====

@@ -4493,7 +4493,35 @@
 		break;
 	}
 
+	case DIF_SUBR_MEMREF: {
+		uint64_t size = 2 * sizeof(uint64_t);
+		uint64_t *memref = (uint64_t *) P2ROUNDUP(mstate->dtms_scratch_ptr, 8);
+		size_t scratch_size = ((uintptr_t) memref - mstate->dtms_scratch_ptr) + size;
+
+		/* address and length */
+		memref[0] = tupregs[0].dttk_value;
+		memref[1] = tupregs[1].dttk_value;
+
+		regs[rd] = (uintptr_t) memref;
+		mstate->dtms_scratch_ptr += scratch_size;
+		break;
 	}
+
+	case DIF_SUBR_TYPEREF: {
+		uint64_t size = 3 * sizeof(uint64_t);
+		uint64_t *typeref = (uint64_t *) P2ROUNDUP(mstate->dtms_scratch_ptr, 8);
+		size_t scratch_size = ((uintptr_t) typeref - mstate->dtms_scratch_ptr) + size;
+
+		/* type, length and address */
+		typeref[0] = tupregs[0].dttk_value;
+		typeref[1] = tupregs[1].dttk_value;
+		typeref[2] = tupregs[2].dttk_value;
+
+		regs[rd] = (uintptr_t) typeref;
+		mstate->dtms_scratch_ptr += scratch_size;
+		break;
+	}
+	}
 }
 
 /*
@@ -5997,6 +6025,43 @@
 					    ecb->dte_epid);
 				continue;
 
+			case DTRACEACT_PRINTM: {
+				/* The DIF returns a 'memref'. */
+				uint64_t *memref = (uint64_t *) val;
+
+				/* Get the size from the memref. */
+				size = memref[1];
+
+				/*
+				 * Check if the size exceeds the allocated
+				 * buffer size.
+				 */
+				if (size + sizeof(uint64_t) > dp->dtdo_rtype.dtdt_size) {
+					/* Flag a drop! */
+					*flags |= CPU_DTRACE_DROP;
+					continue;
+				}
+
+				/* Store the size in the buffer first. */
+				DTRACE_STORE(uint64_t, tomax,
+				    valoffs, size);
+
+				/*
+				 * Offset the buffer address to the start
+				 * of the data.
+				 */
+				valoffs += sizeof(uint64_t);
+
+				/*
+				 * Reset to the memory address rather than
+				 * the memref array, then let the BYREF
+				 * code below do the work to store the 
+				 * memory data in the buffer.
+				 */
+				val = memref[0];
+				break;
+			}
+
 			case DTRACEACT_CHILL:
 				if (dtrace_priv_kernel_destructive(state))
 					dtrace_action_chill(&mstate, val);
@@ -8515,7 +8580,9 @@
 			    subr == DIF_SUBR_HTONLL ||
 			    subr == DIF_SUBR_NTOHS ||
 			    subr == DIF_SUBR_NTOHL ||
-			    subr == DIF_SUBR_NTOHLL)
+			    subr == DIF_SUBR_NTOHLL ||
+			    subr == DIF_SUBR_MEMREF ||
+			    subr == DIF_SUBR_TYPEREF)
 				break;
 
 			err += efunc(pc, "invalid subr %u\n", subr);
@@ -9787,6 +9854,10 @@
 			state->dts_speculates = 1;
 			break;
 
+		case DTRACEACT_PRINTM:
+		    	size = dp->dtdo_rtype.dtdt_size;
+			break;
+
 		case DTRACEACT_COMMIT: {
 			dtrace_action_t *act = ecb->dte_action;
 

==== //depot/projects/dtrace/src/sys/contrib/opensolaris/uts/common/sys/dtrace.h#33 (text) ====

@@ -295,8 +295,10 @@
 #define	DIF_SUBR_INET_NTOP		41
 #define	DIF_SUBR_INET_NTOA		42
 #define	DIF_SUBR_INET_NTOA6		43
+#define	DIF_SUBR_MEMREF			44
+#define	DIF_SUBR_TYPEREF		45
 
-#define	DIF_SUBR_MAX			43	/* max subroutine value */
+#define	DIF_SUBR_MAX			45	/* max subroutine value */
 
 typedef uint32_t dif_instr_t;
 
@@ -405,6 +407,7 @@
 #define	DTRACEACT_PRINTF		3	/* printf() action */
 #define	DTRACEACT_PRINTA		4	/* printa() action */
 #define	DTRACEACT_LIBACT		5	/* library-controlled action */
+#define	DTRACEACT_PRINTM		6	/* printm() action */
 
 #define	DTRACEACT_PROC			0x0100
 #define	DTRACEACT_USTACK		(DTRACEACT_PROC + 1)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200802050739.m157da2Q007601>