From: Nicholas Nethercote Date: Fri, 30 Dec 2005 22:39:58 +0000 (+0000) Subject: Add a --trace-mem option to Lackey to print out a memory access trace, if X-Git-Tag: svn/VALGRIND_3_2_0~433 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e3fc627c16fbf574ed9acde2aa1d84810557849b;p=thirdparty%2Fvalgrind.git Add a --trace-mem option to Lackey to print out a memory access trace, if only so people will stop asking how to do it. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@5462 --- diff --git a/lackey/docs/lk-manual.xml b/lackey/docs/lk-manual.xml index 6bec5ea6ad..e21466ebd1 100644 --- a/lackey/docs/lk-manual.xml +++ b/lackey/docs/lk-manual.xml @@ -4,7 +4,7 @@ -Lackey: a very simple profiler +Lackey: a simple profiler and memory tracer To use this tool, you must specify --tool=lackey on the Valgrind @@ -71,6 +71,16 @@ tool. "F32", "F64", and "V128"). + + When command line option + --trace-mem=yes is + specified, it prints out the size and address of almost every load and + store made by the program. See Section 3.3.7 of Nicholas Nethercote's + PhD dissertation "Dynamic Binary Analysis and Instrumentation", 2004, + for details about the few loads and stores that it misses, and other + caveats about the accuracy of the address trace. + + diff --git a/lackey/lk_main.c b/lackey/lk_main.c index e19e64a844..1aa5e85e91 100644 --- a/lackey/lk_main.c +++ b/lackey/lk_main.c @@ -29,6 +29,27 @@ The GNU General Public License is contained in the file COPYING. */ +// This tool shows how to do some basic instrumentation. +// +// In particular, if you are interested in tracing every load and store a +// program does, use the --trace-mem=yes option. Please note that the +// address trace is good, but not perfect; see Section 3.3.7 of Nicholas +// Nethercote's PhD dissertation "Dynamic Binary Analysis and +// Instrumentation", 2004, for details about the few loads and stores that +// it misses, and other caveats about the accuracy of the address trace. +// +// If you want to modify how the memory traces are printed/gathered, look at +// the code that is controlled by the variable 'lk_clo_trace_mem' and the +// functions 'trace_load()' and 'trace_mem'.. With a bit of effort you +// should be able to see which other bits of code can be removed, if that's +// what you want. If you want to do more complex modifications, please read +// VEX/pub/libvex_ir.h to understand the intermediate representation. +// +// For further inspiration, you should look at cachegrind/cg_main.c which +// handles memory accesses in a more sophisticated way -- it groups them +// together for processing into twos and threes so that fewer C calls are +// made and things run faster. + #include "pub_tool_basics.h" #include "pub_tool_tooliface.h" #include "pub_tool_libcassert.h" @@ -47,6 +68,9 @@ static Char* lk_clo_fnname = "_dl_runtime_resolve"; * with command line option --detailed-counts. */ static Bool lk_clo_detailed_counts = False; +/* If true, print the trace of loads and stores. Set with --trace-mem. */ +static Bool lk_clo_trace_mem = False; + /*********************************************************************** * Implement the needs_command_line_options for Valgrind. **********************************************************************/ @@ -55,6 +79,7 @@ static Bool lk_process_cmd_line_option(Char* arg) { VG_STR_CLO(arg, "--fnname", lk_clo_fnname) else VG_BOOL_CLO(arg, "--detailed-counts", lk_clo_detailed_counts) + else VG_BOOL_CLO(arg, "--trace-mem", lk_clo_trace_mem) else return False; @@ -88,7 +113,6 @@ static ULong n_guest_instrs = 0; static ULong n_Jccs = 0; static ULong n_Jccs_untaken = 0; -__attribute__((unused)) static void add_one_func_call(void) { n_func_calls++; @@ -104,13 +128,11 @@ static void add_one_BB_completed(void) n_BBs_completed++; } -__attribute__((unused)) static void add_one_IRStmt(void) { n_IRStmts++; } -__attribute__((unused)) static void add_one_guest_instr(void) { n_guest_instrs++; @@ -223,6 +245,20 @@ static void print_details ( void ) } +/*********************************************************************** + * Data and helpers related to --trace-mem. + **********************************************************************/ + +static VG_REGPARM(2) void trace_load(Addr addr, SizeT size) +{ + VG_(printf)("load : %p, %d\n", addr, size); +} + +static VG_REGPARM(2) void trace_store(Addr addr, SizeT size) +{ + VG_(printf)("store: %p, %d\n", addr, size); +} + /*********************************************************************** * Implement the basic_tool_funcs for Valgrind. **********************************************************************/ @@ -246,6 +282,9 @@ IRBB* lk_instrument( IRBB* bb_in, VexGuestLayout* layout, IRBB* bb; Char fnname[100]; IRType type; + IRExpr** argv; + IRExpr* addr_expr; + IRExpr* size_expr; if (gWordTy != hWordTy) { /* We don't currently support this case. */ @@ -345,6 +384,19 @@ IRBB* lk_instrument( IRBB* bb_in, VexGuestLayout* layout, * constrains them to being flat SSA-style. */ case Ist_Store: + // Add a call to trace_store() if --trace-mem=yes. + if (lk_clo_trace_mem) { + addr_expr = st->Ist.Store.addr; + size_expr = mkIRExpr_HWord( + sizeofIRType( + typeOfIRExpr(bb->tyenv, st->Ist.Store.data))); + argv = mkIRExprVec_2( addr_expr, size_expr ); + di = unsafeIRDirty_0_N( /*regparms*/2, + "trace_store", + VG_(fnptr_to_fnentry)( trace_store ), + argv ); + addStmtToIRBB( bb, IRStmt_Dirty(di) ); + } if (lk_clo_detailed_counts) { type = typeOfIRExpr(bb->tyenv, st->Ist.Store.data); tl_assert(type != Ity_INVALID); @@ -354,6 +406,20 @@ IRBB* lk_instrument( IRBB* bb_in, VexGuestLayout* layout, break; case Ist_Tmp: + // Add a call to trace_load() if --trace-mem=yes. + if (lk_clo_trace_mem) { + IRExpr* data = st->Ist.Tmp.data; + if (data->tag == Iex_Load) { + addr_expr = data->Iex.Load.addr; + size_expr = mkIRExpr_HWord( sizeofIRType(data->Iex.Load.ty) ); + argv = mkIRExprVec_2( addr_expr, size_expr ); + di = unsafeIRDirty_0_N( /*regparms*/2, + "trace_load", + VG_(fnptr_to_fnentry)( trace_load ), + argv ); + addStmtToIRBB( bb, IRStmt_Dirty(di) ); + } + } if (lk_clo_detailed_counts) { IRExpr* expr = st->Ist.Tmp.data; type = typeOfIRExpr(bb->tyenv, expr);