--- valgrind-3.1.0/configure.in 2005-11-26 08:35:39.000000000 -0500 +++ valgrind-3.1.0-itrace/configure.in 2006-02-24 07:31:20.000000000 -0500 @@ -509,7 +509,13 @@ none/tests/ppc32/Makefile none/tests/x86/Makefile none/docs/Makefile -) + itrace/Makefile + itrace/docs/Makefile + itrace/tests/Makefile ) +# itrace/tests/x86/Makefile +# itrace/tests/ppc32/Makefile +# itrace/tests/amd64/Makefile +#) cat< + diff -ruaN valgrind-3.1.0/itrace/docs/it-manual.xml valgrind-3.1.0-itrace/itrace/docs/it-manual.xml --- valgrind-3.1.0/itrace/docs/it-manual.xml 1969-12-31 19:00:00.000000000 -0500 +++ valgrind-3.1.0-itrace/itrace/docs/it-manual.xml 2006-02-24 06:16:10.000000000 -0500 @@ -0,0 +1,133 @@ + + + + + +Valgrind-itrace: The Instrcution Trace tool +A tool that trace instructions and memory accesses. + + +Instruction Trace + +To use this tool, specify --tool=itrace on the Valgrind command line. + + +Itrace is a simple tool to output a trace of the instructions executed by the processor. Instruction traces can be used by subsequent, architecture-specific tools to look for problematic code sequences, to find misaligned memory access, for calculating cycle counts (often complex as processors develop deeper and more sophisticated pipelines), to determine structural coverage on an object-code basis, or for analyzing suboptimal sequences and mis-optimizations in executing instruction streams. + +Valgrind-itrace is a tool for tracing instructions and memory accesses +and recording all the executed guest instructions and memory addresses. In particular, +it records: + + + Instruction address and content; + + + Load and Store operation; + + + Run-time data and address for memory access. + + + + + + +Instruction Tracer +Trace every actually executed instruction. + + + +Memory Tracer +Trace every meory access, record like R/W Address Data. + + + + + +Instruction Trace Howto + + +Valgrind-itrace invoking and options +Until now, there is two options for valgrind-itrace +--trace-function=fnuction-name. This option could filter the output and only output the instructions and memory access in function fnuction-name +--trace-calltree=fnuction-name. This option could filter the output and only output the all the instructions and memory access called by function fnuction-name +. + + + +Instruction Trace Output Format + + + H valgrind-itrace + Indicates the start of the trace, possibly with additional data in no specific format. + + + + J aaaa xxxx [; symbol] + Instruction-with-address record. aaaa is the address of the instruction, xxxx is a byte dump of the instruction itself. All values are in hex. A symbol name associated with the address may be provided, if instruction on this address is the first instruction of the function or symbol. Note that "J" does not imply that a branch occurred, it merely indicates that the record includes the address of the instruction executed. + + + + I xxxx + Instruction record for an instruction that immediately follows the previous instruction. The address can be determined from the length of the preceding instruction. + + + + G + Indicates a gap in the trace. This will happen, for instance, when valgrind simulates an int 80 (on x86) or sc (on ppc) instruction, or when a branch occurs to code not being traced. + + + + R aaaaaaaa rrrr + W aaaaaaaa wwwwwwww + Indicates that the previous instruction caused a read of the bytes rrrr at the address, or a write of bytes wwwwwwwww. The length of the read or write is indicated by the number of bytes shown. R and W records occur in order. + + + + + + +Instruction Trace Output Example + +Here is an example of output when valgrind-itrace trace itrace/tests/hello_world: +[qiyao@localhost valgrind-3.1.0]$ valgrind --tool=itrace --trace-filter=print itrace/tests/hello_world + + + + + + + + diff -ruaN valgrind-3.1.0/itrace/docs/Makefile.am valgrind-3.1.0-itrace/itrace/docs/Makefile.am --- valgrind-3.1.0/itrace/docs/Makefile.am 1969-12-31 19:00:00.000000000 -0500 +++ valgrind-3.1.0-itrace/itrace/docs/Makefile.am 2006-02-15 01:39:53.000000000 -0500 @@ -0,0 +1 @@ +EXTRA_DIST = it-manual.xml diff -ruaN valgrind-3.1.0/itrace/it_main.c valgrind-3.1.0-itrace/itrace/it_main.c --- valgrind-3.1.0/itrace/it_main.c 1969-12-31 19:00:00.000000000 -0500 +++ valgrind-3.1.0-itrace/itrace/it_main.c 2006-02-24 07:19:03.000000000 -0500 @@ -0,0 +1,446 @@ + +/*----------------------------------------------------------------------------*/ +/*--- Valgrind-itrace: The Instruction Trace tool. it_main.c ---*/ +/*----------------------------------------------------------------------------*/ + +/* + This file is part of itrace-valgrind, the Valgrind tool, which + trace instruction. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. + + This file is written by Yao Qi +*/ + +#include "pub_tool_basics.h" +#include "pub_tool_libcassert.h" +#include "pub_tool_tooliface.h" + +#include "pub_tool_libcprint.h" +#include "pub_tool_options.h" +#include "pub_tool_debuginfo.h" +#include "pub_tool_libcbase.h" + +#define FN_LEN 20 +static Char* fn_name = NULL; +static Char* trace_calltree = NULL; +static Char fn_name_buf[FN_LEN]={0}; + +/* In function. */ +static Int in_func = 0; + + +typedef struct Instruction +{ + Addr instruction; + Int length; +} Inst; +/* To distinguish I and J record. */ +static Inst last = {NULL, 0}; + +static Int print_flag = 0; + +/* count the number of printed instructions in one BB. Reset at the entry +of every BB. */ +static Int print_inst_bb = 0; + +void compute_print_flag (Addr instruction) +{ + if (trace_calltree) + print_flag = in_func ? 1:0; + else if (fn_name) + { + VG_(get_fnname)(instruction, fn_name_buf, FN_LEN); + if (in_func && !(VG_(strcmp)(fn_name_buf, fn_name))) + print_flag = 1; + else + print_flag = 0; + } + else + /* neither is specified, trace all instructions. */ + print_flag = 1; +} + +static VG_REGPARM(2) + void print_instruction (Addr instruction, Int len) +{ + Int j; + UChar* i; + /* assume 32-bit addr. */ + UChar buf[8]; + Char func_name [FN_LEN]; + + /* step 1. check. */ + //tl_assert(len < 16); + tl_assert (instruction != NULL); + + /* step 2. print instruction or not*/ + if (fn_name || trace_calltree) + { + VG_(memset)(fn_name_buf,0,sizeof(fn_name_buf)); + VG_(get_fnname_if_entry)(instruction, fn_name_buf, FN_LEN); + + if ((fn_name && !VG_(strcmp)(fn_name_buf, fn_name)) + ||(trace_calltree && !VG_(strcmp)(fn_name_buf, trace_calltree))) in_func++; + } + /* compute print flag. */ + compute_print_flag(instruction); + if (print_flag == 0) return; + + /* step 3. */ + print_inst_bb++; + + /* Print address of instruction if it is not sequent. */ + if (instruction != last.instruction + last.length) + { + VG_(printf)("J "); + VG_(sprintf)(buf,"%lx",instruction); + /* Left-justify the result, and fill in with '0' */ + for(j=0;j < 8 - VG_(strlen)(buf);j++) VG_(printf)("0"); + for (j=0; j<8&&buf[j]; j++) VG_(printf)("%c",buf[j]); + VG_(printf)(" "); + } + else + { + VG_(printf)("I "); + /* for debug purpose. */ + /* + VG_(sprintf)(buf,"%lx",instruction); + + for(j=0;j < 8 - VG_(strlen)(buf);j++) VG_(printf)("0"); + for (j=0; j<8&&buf[j]; j++) VG_(printf)("%c",buf[j]); + VG_(printf)(" "); + */ + } + /* Print instruction in hex. */ + i = (UChar*) instruction; + for (j=0 ; j< len; j++) + if (i[j] > 0xf) VG_(printf)("%2x", i[j]); + else VG_(printf)("0%x",i[j]); + + /* Print name of function if this instruction is the first one in + this function. */ + if (VG_(get_fnname_if_entry)(instruction, func_name,FN_LEN)) + VG_(printf)(" ; %s",func_name); + /* for debug purpose. */ + /* + else + { + VG_(get_fnname)(instruction, func_name, FN_LEN); + VG_(printf)(" : %s",func_name); + } + */ + VG_(printf)("\n"); + + /* Update last instruction. */ + last.instruction = instruction; + last.length = len; +} + +static void print_data (Addr addr, HWord size, IREndness end) +{ + UChar print_buf[16]; + Int j; + + /* Assume 32-bit Address. */ + tl_assert (sizeof(addr) == 4); + tl_assert (size > 0); + tl_assert (size%8 == 0); + + VG_(sprintf)(print_buf,"%lx",addr); + /* Left-justify the result, and fill in with '0' */ + for (j=0; j< sizeof(addr)*2 - VG_(strlen)(print_buf);j++) VG_(printf)("0"); + for (j=0; j< sizeof(addr)*2 && print_buf[j]; j++) VG_(printf)("%c",print_buf[j]); + + VG_(printf)(" "); + + VG_(memcpy)(print_buf,(UChar*)addr, size/8); + /* Endianess of memory. */ + if (end == Iend_BE) + { + for (j=0; j< size/8; j++) + if (print_buf[j] > 0xf) VG_(printf)("%2x",print_buf[j]); + else VG_(printf)("0%x",print_buf[j]); + } + else + { + for (j=size/8 - 1; j>=0 ;j--) + if (print_buf[j] > 0xf) VG_(printf)("%2x",print_buf[j]); + else VG_(printf)("0%x",print_buf[j]); + } + + VG_(printf)("\n"); +} + +static VG_REGPARM(3) + void print_write_data (Addr addr, HWord size, IREndness end) +{ + if (print_flag == 0) return; + VG_(printf)("W "); + print_data (addr, size, end); +} + +static VG_REGPARM(3) + void print_read_data (Addr addr, HWord size, IREndness end) +{ + if (print_flag == 0) return; + + VG_(printf)("R "); + print_data (addr, size, end); +} +void print_jumpkind (Int kind) +{ + /*Print Jump Kind. You could print what you like later. */ + switch (kind) + { + case Ijk_Boring: + case Ijk_TInval: + + case Ijk_Ret: + case Ijk_Call: + case Ijk_Sys_syscall: + case Ijk_Sys_int128: + case Ijk_Sys_int32: + case Ijk_Sys_sysenter: + case Ijk_EmWarn: + VG_(printf)("G\n"); + break; + + case Ijk_ClientReq: + case Ijk_Yield: + case Ijk_NoDecode: + case Ijk_MapFail: + ppIRJumpKind(kind); + tl_assert(0); + break; + default: + VG_(printf)("No such jumpkind!\n"); + tl_assert(0); + } +} + +/* Do something when exit BB. */ +static VG_REGPARM(2) + void deal_exit_bb (Addr bb_last_inst_addr, Int jumpkind) +{ + if (in_func && jumpkind == Ijk_Ret) + { + VG_(memset)(fn_name_buf,0,sizeof(fn_name_buf)); + VG_(get_fnname)(bb_last_inst_addr, fn_name_buf, FN_LEN); + + if ((fn_name && !VG_(strcmp)(fn_name_buf, fn_name)) + ||(trace_calltree && !VG_(strcmp)(fn_name_buf, trace_calltree))) + in_func--; + } + + if (print_inst_bb) + print_jumpkind(jumpkind); +} + +static void it_post_clo_init(void) +{ + VG_(printf)("H valgrind-itrace\n"); + /* Check options. */ + /* both options specified, not support now. */ + if ( trace_calltree && fn_name) + { + VG_(printf)("\n"); + VG_(printf)("Current version of itrace do not support both options specified simultaneouslly!"); + VG_(printf)("\n"); + tl_assert(0); + } +} + +static IRBB* it_instrument(IRBB* bb_in, VexGuestLayout* layout, + Addr64 orig_addr_noredir, VexGuestExtents* vge, + IRType gWordTy, IRType hWordTy) +{ + IRDirty* di; + Int i; + IRBB* bb; + + IRExpr** argv; + HWord size; + + Addr bb_last_inst = NULL; + + if (gWordTy != hWordTy) { + /* We don't currently support this case. */ + VG_(tool_panic)("host/guest word size mismatch"); + } + + /* Remove the empty stmts. */ + for (i = 0; !bb_in->stmts[i] && i < bb_in->stmts_used; i++) + ; + /* Set up BB */ + bb = emptyIRBB(); + bb->tyenv = dopyIRTypeEnv(bb_in->tyenv); + bb->next = dopyIRExpr(bb_in->next); + bb->jumpkind = bb_in->jumpkind; + + /* Reset the counter at the beginning of BB. */ + print_inst_bb = 0; + + for (/* use current */; i < bb_in->stmts_used; i++) + { + IRStmt* st = bb_in->stmts[i]; + if (!st) continue; + + /* Print the content of guest instruction. */ + switch (st->tag) { + /* Instruction trace has nothing to do with them, just break.*/ + case Ist_Exit: case Ist_NoOp: case Ist_AbiHint: + case Ist_Put: case Ist_PutI: case Ist_MFence: case Ist_Dirty: + addStmtToIRBB ( bb, st); + break; + + case Ist_IMark: + bb_last_inst = st->Ist.IMark.addr; + + di = unsafeIRDirty_0_N( 2,"print_instruction",&print_instruction, + mkIRExprVec_2(mkIRExpr_HWord((HWord)st->Ist.IMark.addr),mkIRExpr_HWord(st->Ist.IMark.len)) + ); + addStmtToIRBB( bb, IRStmt_Dirty(di)); + + addStmtToIRBB ( bb, st); + break; + + /* Record STORE operation. */ + case Ist_Store: + tl_assert(isIRAtom(st->Ist.Store.data)); + tl_assert(isIRAtom(st->Ist.Store.addr)); + + /* Add STORE before instrument, so DATA is accessible thru ADDR + after WRITE operation. */ + addStmtToIRBB( bb, st ); + + switch (typeOfIRExpr(bb->tyenv,st->Ist.Store.data)) + { + case Ity_I64: case Ity_F64: + size = 64; break; + case Ity_I16: + size = 16; break; + case Ity_I32: case Ity_F32: + size =32; break; + case Ity_I1: case Ity_I8: + size = 8; break; + case Ity_V128: + size = 128; break; + default: + ppIRType (typeOfIRExpr(bb->tyenv,st->Ist.Store.data)); + tl_assert(0); + } + + argv = mkIRExprVec_3(st->Ist.Store.addr, mkIRExpr_HWord(size), mkIRExpr_HWord(st->Ist.Store.end)); + di = unsafeIRDirty_0_N( 3,"print_write_data", &print_write_data, argv); + + addStmtToIRBB( bb, IRStmt_Dirty(di)); + break; + + case Ist_Tmp: + /* Record LOAD operation. */ + if (st->Ist.Tmp.data->tag == Iex_Load) + { + tl_assert(isIRAtom(st->Ist.Tmp.data->Iex.Load.addr)); + switch (st->Ist.Tmp.data->Iex.Load.ty) + { + case Ity_I1: case Ity_I8: + size = 8; break; + case Ity_I16: + size = 16; break; + case Ity_I32: case Ity_F32: + size = 32; break; + case Ity_I64: case Ity_F64: + size = 64; break; + case Ity_V128: + size = 128; break; + default: + ppIRType(st->Ist.Tmp.data->Iex.Load.ty); + tl_assert(0); + } + + argv = mkIRExprVec_3(st->Ist.Tmp.data->Iex.Load.addr, + mkIRExpr_HWord(size), + mkIRExpr_HWord(st->Ist.Tmp.data->Iex.Load.end)); + + di = unsafeIRDirty_0_N( 3, "print_read_data", &print_read_data, argv); + + addStmtToIRBB( bb, IRStmt_Dirty(di)); + } + addStmtToIRBB( bb, st); + break; + + default: + tl_assert(0); + break; + } + } + + di = unsafeIRDirty_0_N( 2,"deal_exit_bb",&deal_exit_bb, + mkIRExprVec_2(mkIRExpr_HWord((HWord)bb_last_inst),mkIRExpr_HWord((HWord)bb->jumpkind)) + ); + addStmtToIRBB( bb, IRStmt_Dirty(di)); + + return bb; +} + +static void it_fini(Int exitcode) +{ +} + +static Bool it_process_cmd_line_option (Char* arg) +{ + VG_STR_CLO (arg, "--trace-function", fn_name) + else VG_STR_CLO (arg, "--trace-calltree", trace_calltree) + else return False; + + return True; +} + +static void it_print_usage (void) +{ + VG_(printf) ("--trace-function=, trace instructions in this function\n"); + VG_(printf) ("--trace-calltree=, trace instructions in all functions called by \n"); +} + +static void it_print_debug_usage (void) +{} + +static void it_pre_clo_init(void) +{ + VG_(details_name) ("valgrind-itrace"); + VG_(details_version) (NULL); + VG_(details_description) ("Instruction and memory tracer"); + VG_(details_copyright_author)( + "Copyright (C) 2005, and GNU GPL'd."); + VG_(details_bug_reports_to) (VG_BUGS_TO); + + VG_(basic_tool_funcs) (it_post_clo_init, + it_instrument, + it_fini); + VG_(needs_command_line_options) (it_process_cmd_line_option, + it_print_usage, + it_print_debug_usage); + /* No needs, no core events to track */ +} + +VG_DETERMINE_INTERFACE_VERSION(it_pre_clo_init) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff -ruaN valgrind-3.1.0/itrace/Makefile.am valgrind-3.1.0-itrace/itrace/Makefile.am --- valgrind-3.1.0/itrace/Makefile.am 1969-12-31 19:00:00.000000000 -0500 +++ valgrind-3.1.0-itrace/itrace/Makefile.am 2006-02-24 07:19:05.000000000 -0500 @@ -0,0 +1,41 @@ +include $(top_srcdir)/Makefile.tool.am + +CLEANFILES = *.o + +noinst_PROGRAMS = +if VG_X86_LINUX +noinst_PROGRAMS += itrace-x86-linux +CLEANFILES += itrace-x86-linux +endif +if VG_AMD64_LINUX +noinst_PROGRAMS += itrace-amd64-linux +CLEANFILES += itrace-amd64-linux +endif +if VG_PPC32_LINUX +noinst_PROGRAMS += itrace-ppc32-linux +CLEANFILES += itrace-ppc32-linux +endif + +ITRACE_SOURCES_COMMON = it_main.c + + +itrace_x86_linux_SOURCES = $(ITRACE_SOURCES_COMMON) +itrace_x86_linux_CPPFLAGS = $(AM_CPPFLAGS_X86_LINUX) +itrace_x86_linux_CFLAGS = $(AM_CFLAGS_X86_LINUX) +itrace_x86_linux_DEPENDENCIES = $(COREGRIND_LIBS_X86_LINUX) +itrace_x86_linux_LDADD = $(TOOL_LDADD_X86_LINUX) +itrace_x86_linux_LDFLAGS = $(TOOL_LDFLAGS_X86_LINUX) + +itrace_amd64_linux_SOURCES = $(ITRACE_SOURCES_COMMON) +itrace_amd64_linux_CPPFLAGS = $(AM_CPPFLAGS_AMD64_LINUX) +itrace_amd64_linux_CFLAGS = $(AM_CFLAGS_AMD64_LINUX) +itrace_amd64_linux_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_LINUX) +itrace_amd64_linux_LDADD = $(TOOL_LDADD_AMD64_LINUX) +itrace_amd64_linux_LDFLAGS = $(TOOL_LDFLAGS_AMD64_LINUX) + +itrace_ppc32_linux_SOURCES = $(ITRACE_SOURCES_COMMON) +itrace_ppc32_linux_CPPFLAGS = $(AM_CPPFLAGS_PPC32_LINUX) +itrace_ppc32_linux_CFLAGS = $(AM_CFLAGS_PPC32_LINUX) +itrace_ppc32_linux_DEPENDENCIES = $(COREGRIND_LIBS_PPC32_LINUX) +itrace_ppc32_linux_LDADD = $(TOOL_LDADD_PPC32_LINUX) +itrace_ppc32_linux_LDFLAGS = $(TOOL_LDFLAGS_PPC32_LINUX) diff -ruaN valgrind-3.1.0/itrace/tests/Makefile.am valgrind-3.1.0-itrace/itrace/tests/Makefile.am --- valgrind-3.1.0/itrace/tests/Makefile.am 1969-12-31 19:00:00.000000000 -0500 +++ valgrind-3.1.0-itrace/itrace/tests/Makefile.am 2006-02-24 07:25:21.000000000 -0500 @@ -0,0 +1,2 @@ + +