diff options
author | Stephane Marchesin <marchesin@icps.u-strasbg.fr> | 2009-05-04 19:05:59 +0200 |
---|---|---|
committer | Stephane Marchesin <marchesin@icps.u-strasbg.fr> | 2009-05-04 19:05:59 +0200 |
commit | 6e410b3bb6ff51580897431105aae14591cbf7fb (patch) | |
tree | f8aeba9352710f10cd6b1d5138c8fc3ece91c8c3 /mmt |
Diffstat (limited to 'mmt')
-rw-r--r-- | mmt/mmt_main.c | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/mmt/mmt_main.c b/mmt/mmt_main.c new file mode 100644 index 0000000..32bfb7a --- /dev/null +++ b/mmt/mmt_main.c @@ -0,0 +1,385 @@ +/* + * vim:sw=3 ts=3 sts=3 noexpandtab + */ + +/*--------------------------------------------------------------------*/ +/*--- mmaptrace: The mmaptracer tool. mmt_main.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + Copyright (C) 2006 Dave Airlie + + 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. +*/ + +#include "pub_tool_basics.h" +#include "pub_tool_libcprint.h" +#include "pub_tool_libcassert.h" +#include "pub_tool_tooliface.h" +#include "pub_tool_debuginfo.h" +#include "pub_tool_libcbase.h" +#include "pub_tool_options.h" +#include "pub_tool_machine.h" // VG_(fnptr_to_fnentry) + +#define MAX_ITEMS 100 + +static struct mmt_memmap { + Bool initialized; + Addr offset; + Addr addr; + SizeT len; +} mmt_gpu_reg[MAX_ITEMS]; + +static UInt current_item; + +static struct mmt_op { + Addr offset; + SizeT size; + UInt value; + ULong reps; + UInt store; +} last_op; + + +/* Command line options */ +UInt mmt_clo_offset = (UInt) -1; + +static struct mmt_memmap *find_mmap(Addr addr) +{ + struct mmt_memmap *ptr = NULL; + UInt i; + + for (i = 0; i < MAX_ITEMS; i++) { + ptr = &mmt_gpu_reg[i]; + + if (!ptr->initialized) { + /* since we cannot un-init entries in the array, + * we can return once we hit the first uninitialized + * item -- there can't be initialized items following it. + */ + return NULL; + } + + if ((addr > ptr->addr) && (addr < ptr->addr + ptr->len)) + return ptr; + } + + return NULL; +} + +static void +print_op(void) +{ + int i; + + if (last_op.reps > 5) { + VG_(printf)(" ... repeated %lu times total\n", last_op.reps); + } + else { + for (i = 0; i < last_op.reps; i++) { + VG_(printf)("%s: %p, %d, %p\n", last_op.store ? "store" : "load", + last_op.offset, last_op.size, last_op.value); + } + } +} + +static VG_REGPARM(2) void +trace_store(Addr addr, SizeT size, UInt value) +{ + struct mmt_memmap *ptr; + + ptr = find_mmap(addr); + if (!ptr) + return; + + if (last_op.offset != (addr - ptr->addr) || last_op.size != size || + last_op.value != value || !last_op.store) { + print_op(); + + last_op.offset = addr - ptr->addr; + last_op.size = size; + last_op.value = value; + last_op.store = 1; + last_op.reps = 1; + } + else { + last_op.reps++; + + if (last_op.reps % 1000 == 0) + VG_(printf)(" ... repeating: %d times\n", last_op.reps); + if (last_op.reps == ~0UL) + VG_(printf)(" ... overflow!\n"); + } +} + +static VG_REGPARM(2) void +trace_load(Addr addr, SizeT size) +{ + struct mmt_memmap *ptr; + UInt value; + + ptr = find_mmap(addr); + if (!ptr) + return; + + switch (size) { + case 1: + value = *(UChar*) addr; + break; + case 2: + value = *(UShort*) addr; + break; + case 4: + value = *(UInt*) addr; + break; + case 8: + value = *(ULong*) addr; + default: + return; + } + + if (last_op.offset != (addr - ptr->addr) || last_op.size != size || + last_op.value != value || last_op.store) { + print_op(); + + last_op.offset = addr - ptr->addr; + last_op.size = size; + last_op.value = value; + last_op.store = 0; + last_op.reps = 1; + } + else { + last_op.reps++; + + if (last_op.reps % 1000 == 0) + VG_(printf)(" ... repeating: %d times\n", last_op.reps); + if (last_op.reps == ~0UL) + VG_(printf)(" ... overflow!\n"); + } +} + +static void +handle_load(IRSB* bb, IRExpr* addr, Int size) +{ + IRExpr** argv = mkIRExprVec_2(addr, mkIRExpr_HWord(size)); + IRDirty* di = unsafeIRDirty_0_N(2, + "trace_load", + VG_(fnptr_to_fnentry)(trace_load), + argv); + addStmtToIRSB(bb, IRStmt_Dirty(di)); +} + +static void +handle_store(IRSB*bb, IRExpr* addr, Int size, IRExpr* data) +{ + IRExpr** argv = mkIRExprVec_3(addr, mkIRExpr_HWord(size), data); + IRDirty* di = unsafeIRDirty_0_N(2, + "trace_store", + VG_(fnptr_to_fnentry)(trace_store), + argv); + addStmtToIRSB(bb, IRStmt_Dirty(di)); +} + +static IRSB* +mmt_instrument(VgCallbackClosure* closure, + IRSB* bbIn, + VexGuestLayout* layout, + VexGuestExtents* vge, + IRType gWordTy, IRType hWordTy) +{ + IRSB* bbOut; + int i = 0; + + if (gWordTy != hWordTy) { + /* We don't currently support this case. */ + VG_(tool_panic)("host/guest word size mismatch"); + } + if (gWordTy != Ity_I32 && gWordTy != Ity_I64) { + VG_(tool_panic)("word size must be 32 or 64 bits"); + } + + /* Set up BB */ + bbOut = deepCopyIRSBExceptStmts(bbIn); + + /* Copy verbatim any IR preamble preceding the first IMark */ + while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) { + addStmtToIRSB(bbOut, bbIn->stmts[i]); + i++; + } + + for (; i < bbIn->stmts_used; i++) { + IRStmt* st = bbIn->stmts[i]; + IRExpr* data_expr; + IRType arg_ty; + IRTemp t = IRTemp_INVALID; + IRStmt* cast = NULL; + + if (!st) + continue; + + if (st->tag == Ist_Store) { + arg_ty = typeOfIRExpr(bbIn->tyenv, st->Ist.Store.data); + + data_expr = st->Ist.Store.data; + + /* convert data_expr into a 64 bit value */ + switch (arg_ty) { + case Ity_I8: + if (gWordTy == Ity_I32) { + t = newIRTemp(bbOut->tyenv, Ity_I32); + cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_8Uto32, data_expr)); + } + else { + t = newIRTemp(bbOut->tyenv, Ity_I64); + cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_8Uto64, data_expr)); + } + break; + case Ity_I16: + if (gWordTy == Ity_I32) { + t = newIRTemp(bbOut->tyenv, Ity_I32); + cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_16Uto32, data_expr)); + } + else { + t = newIRTemp(bbOut->tyenv, Ity_I64); + cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_16Uto64, data_expr)); + } + break; + case Ity_I32: + if (gWordTy == Ity_I64) { + t = newIRTemp(bbOut->tyenv, Ity_I64); + cast = IRStmt_WrTmp(t, IRExpr_Unop(Iop_32Uto64, data_expr)); + } + break; + case Ity_I64: + if (gWordTy == Ity_I64) { + break; + } + default: + /* since we only support stores up to the guest word size, we + * will never have to evaluate the data_expr that this case + * generates. + */ + if (gWordTy == Ity_I32) { + t = newIRTemp(bbOut->tyenv, Ity_I32); + cast = IRStmt_WrTmp(t, IRExpr_Const (IRConst_U32 (0))); + } + else { + t = newIRTemp(bbOut->tyenv, Ity_I64); + cast = IRStmt_WrTmp(t, IRExpr_Const (IRConst_U64 (0))); + } + break; + } + + if (cast) { + addStmtToIRSB(bbOut, cast); + data_expr = IRExpr_RdTmp(t); + } + + handle_store(bbOut, st->Ist.Store.addr, + sizeofIRType(arg_ty), data_expr); + } else if (st->tag == Ist_WrTmp) { + data_expr = st->Ist.WrTmp.data; + + if (data_expr->tag == Iex_Load) { + handle_load(bbOut, data_expr->Iex.Load.addr, + sizeofIRType (data_expr->Iex.Load.ty)); + } + } + + addStmtToIRSB(bbOut, st); + } + + return bbOut; +} + +static Bool +mmt_process_cmd_line_option(Char* arg) +{ + /* FIXME: make this argument mandatory */ + VG_BHEX_CLO(arg, "--offset", mmt_clo_offset, 0, 0xffffffff) + else + return False; + + VG_(message)(Vg_UserMsg, "set offset to %lx\n", mmt_clo_offset); + + return True; +} + +static void +mmt_print_usage(void) +{ + VG_(printf)(" --offset=<number> (number must be in decimal!)\n"); +} + +static void +mmt_print_debug_usage(void) +{ +} + +static void +mmt_new_mem_mmap(Addr a, SizeT len, Off64T offset, Bool rr, Bool ww, Bool xx) +{ + if (offset != mmt_clo_offset) + return; + + mmt_gpu_reg[current_item].offset = offset; + mmt_gpu_reg[current_item].addr = a; + mmt_gpu_reg[current_item].len = len; + mmt_gpu_reg[current_item].initialized = True; + current_item++; + + VG_(message)(Vg_UserMsg, "got new mmap for %p, len %d, offset %p\n", a, len, offset); +} + +static void +mmt_fini(Int exitcode) +{ +} + +static void mmt_post_clo_init(void) +{ +} + +static void +mmt_pre_clo_init(void) +{ + VG_(details_name) ("mmaptrace"); + VG_(details_version) (NULL); + VG_(details_description) ("an MMAP tracer"); + VG_(details_copyright_author)( + "Copyright (C) 2006, and GNU GPL'd, by Dave Airlie."); + VG_(details_bug_reports_to) (VG_BUGS_TO); + + VG_(basic_tool_funcs) (mmt_post_clo_init, + mmt_instrument, + mmt_fini); + + VG_(needs_command_line_options)(mmt_process_cmd_line_option, + mmt_print_usage, + mmt_print_debug_usage); + + VG_(track_new_mem_mmap) (mmt_new_mem_mmap); + + last_op.offset = 0; + last_op.size = 0; + last_op.value = 0; + last_op.store = 0; + last_op.reps = 0; +} + +VG_DETERMINE_INTERFACE_VERSION(mmt_pre_clo_init) |