PERFORCE change 134827 for review
John Birrell
jb at FreeBSD.org
Mon Feb 4 23:39:37 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=134827
Change 134827 by jb at 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)
More information about the p4-projects
mailing list