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>