From: Julian Seward Date: Wed, 3 Nov 2004 09:10:30 +0000 (+0000) Subject: First pass at Memcheck. X-Git-Tag: svn/VALGRIND_3_0_1^2~854 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0d2178b218d17ade2c77eaeb8f1789cef1f9cfcf;p=thirdparty%2Fvalgrind.git First pass at Memcheck. git-svn-id: svn://svn.valgrind.org/vex/trunk@480 --- diff --git a/VEX/head20041019/coregrind/toolfuncs.def b/VEX/head20041019/coregrind/toolfuncs.def index 83bb646641..62f6a2f8cf 100644 --- a/VEX/head20041019/coregrind/toolfuncs.def +++ b/VEX/head20041019/coregrind/toolfuncs.def @@ -24,7 +24,7 @@ void, post_clo_init ## always results in the same output, because basic blocks can be ## retranslated. Unless you're doing something really strange... ## 'orig_addr' is the address of the first instruction in the block. -IRBB*, instrument, IRBB* bb, VexGuestLayout* layout +IRBB*, instrument, IRBB* bb, VexGuestLayout* layout, IRType hWordTy ## Finish up, print out any results, etc. `exitcode' is program's exit ## code. The shadow (if the `shadow_regs' need is set) can be found with diff --git a/VEX/head20041019/coregrind/valgrind.vs b/VEX/head20041019/coregrind/valgrind.vs index 02865d2503..76ebb190c1 100644 --- a/VEX/head20041019/coregrind/valgrind.vs +++ b/VEX/head20041019/coregrind/valgrind.vs @@ -5,11 +5,14 @@ VALGRIND_2.1 { vgProf_*; vgOff_*; vgArch_*; + *IROp*; *IRExpr*; *IRStmt*; *IRBB*; *IRDirty*; *IRType*; + *IRTemp*; + *IRConst*; *IRCallee*; LibVEX_Alloc; diff --git a/VEX/head20041019/memcheck/mc_from_ucode.c b/VEX/head20041019/memcheck/mc_from_ucode.c index a36fcbc21e..f6f6b2ed49 100644 --- a/VEX/head20041019/memcheck/mc_from_ucode.c +++ b/VEX/head20041019/memcheck/mc_from_ucode.c @@ -45,6 +45,8 @@ /* See the corresponding comment at the top of vg_from_ucode.c to find out * how all this works */ +#if 0 + /*----------------------------------------------------*/ /*--- v-size (4, or 2 with OSO) insn emitters ---*/ /*----------------------------------------------------*/ @@ -656,6 +658,8 @@ void SK_(emit_XUInstr) ( UInstr* u, RRegSet regs_live_before ) } } +#endif + /*--------------------------------------------------------------------*/ /*--- end mc_from_ucode.c ---*/ /*--------------------------------------------------------------------*/ diff --git a/VEX/head20041019/memcheck/mc_include.h b/VEX/head20041019/memcheck/mc_include.h index 948cef8ab6..ae6ddc1b4d 100644 --- a/VEX/head20041019/memcheck/mc_include.h +++ b/VEX/head20041019/memcheck/mc_include.h @@ -113,14 +113,9 @@ extern Bool MC_(clo_avoid_strlen_errors); /*--- Functions ---*/ /*------------------------------------------------------------*/ -/* Functions defined in mc_helpers.S */ -extern void MC_(helper_value_check4_fail) ( void ); -extern void MC_(helper_value_check2_fail) ( void ); -extern void MC_(helper_value_check1_fail) ( void ); -extern void MC_(helper_value_check0_fail) ( void ); - - /* Functions defined in mc_main.c */ +extern REGPARM(1) void MC_(helperc_complain_undef) ( HWord ); + extern REGPARM(2) void MC_(helperc_STOREV4) ( Addr, UInt ); extern REGPARM(2) void MC_(helperc_STOREV2) ( Addr, UInt ); extern REGPARM(2) void MC_(helperc_STOREV1) ( Addr, UInt ); diff --git a/VEX/head20041019/memcheck/mc_main.c b/VEX/head20041019/memcheck/mc_main.c index a8369cfadf..67a5ade37c 100644 --- a/VEX/head20041019/memcheck/mc_main.c +++ b/VEX/head20041019/memcheck/mc_main.c @@ -721,10 +721,14 @@ void mc_set_perms (Addr a, UInt len, Bool rr, Bool ww, Bool xx) static void mc_post_regs_write_init ( void ) { +#if 0 UInt i; for (i = FIRST_ARCH_REG; i <= LAST_ARCH_REG; i++) VG_(set_shadow_archreg)( i, VGM_WORD_VALID ); VG_(set_shadow_eflags)( VGM_EFLAGS_VALID ); +#else + VG_(printf)("mc_post_regs_write_init()\n"); +#endif } static void mc_post_reg_write(ThreadId tid, UInt reg) @@ -1102,6 +1106,11 @@ void MC_(helperc_value_check4_fail) ( void ) MC_(record_value_error) ( VG_(get_current_tid)(), 4 ); } +REGPARM(1) void MC_(helperc_complain_undef) ( HWord sz ) +{ + MC_(record_value_error) ( VG_(get_current_tid)(), (Int)sz ); +} + /* --------------------------------------------------------------------- FPU load and store checks, called from generated code. @@ -1692,6 +1701,7 @@ void SK_(pre_clo_init)(void) VG_(init_post_reg_write_clientreq_return) ( & mc_post_reg_write ); VG_(init_post_reg_write_clientcall_return) ( & mc_post_reg_write_clientcall ); +#if 0 /* Three compact slots taken up by stack memory helpers */ VG_(register_compact_helper)((Addr) & MC_(helper_value_check4_fail)); VG_(register_compact_helper)((Addr) & MC_(helper_value_check0_fail)); @@ -1707,6 +1717,7 @@ void SK_(pre_clo_init)(void) VG_(register_noncompact_helper)((Addr) & MC_(fpu_write_check)); VG_(register_noncompact_helper)((Addr) & MC_(fpu_read_check)); VG_(register_noncompact_helper)((Addr) & MC_(helper_value_check1_fail)); +#endif VGP_(register_profile_event) ( VgpSetMem, "set-mem-perms" ); VGP_(register_profile_event) ( VgpCheckMem, "check-mem-perms" ); diff --git a/VEX/head20041019/memcheck/mc_translate.c b/VEX/head20041019/memcheck/mc_translate.c index af01e6d4fb..abd0962a64 100644 --- a/VEX/head20041019/memcheck/mc_translate.c +++ b/VEX/head20041019/memcheck/mc_translate.c @@ -259,7 +259,7 @@ Int SK_(get_Xreg_usage)(UInstr* u, Tag tag, Int* regs, Bool* isWrites) /*------------------------------------------------------------*/ /*--- New instrumentation machinery. ---*/ /*------------------------------------------------------------*/ - +#if 0 static TagOp get_Tag_ImproveOR_TQ ( Int sz ) { @@ -1634,25 +1634,586 @@ static void vg_cleanup ( UCodeBlock* cb ) vg_propagate_definedness ( cb ); vg_delete_redundant_SETVs ( cb ); } +#endif + +#undef dis -/* Caller will print out final instrumented code if necessary; we - print out intermediate instrumented code here if necessary. */ -UCodeBlock* SK_(instrument) ( UCodeBlock* cb, Addr not_used ) +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +/* An atom is either an IRExpr_Const or an IRExpr_Tmp, as defined by + isAtom() in libvex_ir.h. Because this instrumenter expects flat + input, most of this code deals in atoms. Usefully, a value atom + always has a V-value which is also an atom: constants are shadowed + by constants, and temps are shadowed by the corresponding shadow + temporary. */ +typedef IRExpr IRAtom; + +/* Check that both args are atoms and are identically-kinded. */ +static Bool sameKindedAtoms ( IRAtom* a1, IRAtom* a2 ) { - cb = memcheck_instrument ( cb ); - if (MC_(clo_cleanup)) { - if (dis) { - VG_(pp_UCodeBlock) ( cb, "Unimproved instrumented UCode:" ); - VG_(printf)("Instrumentation improvements:\n"); - } - vg_cleanup(cb); - if (dis) VG_(printf)("\n"); + if (a1->tag == Iex_Tmp && a1->tag == Iex_Tmp) + return True; + if (a1->tag == Iex_Const && a1->tag == Iex_Const) + return True; + return False; +} + +/* Carries around state during memcheck instrumentation. */ +typedef + struct { + /* MODIFIED: the bb being constructed. IRStmts are added. */ + IRBB* bb; + + /* MODIFIED: a table [0 .. #temps_in_original_bb-1] which maps + original temps to their current their current shadow temp. + Initially all entries are IRTemp_INVALID. Entries are added + lazily since many original temps are not used due to + optimisation prior to instrumentation. Note that floating + point original tmps are shadowed by integer tmps of the same + size, and Bit-typed original tmps are shadowed by the type + Ity_I8. */ + IRTemp* tmpMap; + Int n_originalTmps; /* for range checking */ + + /* READONLY: the guest layout */ + VexGuestLayout* layout; + /* READONLY: the host word type. Needed for constructing + arguments of type 'HWord' to be passed to helper functions. + Ity_I32 or Ity_I64 only. */ + IRType hWordTy; } - return cb; + MCEnv; + +static Bool isOriginalAtom ( MCEnv* mce, IRAtom* a1 ) +{ + if (a1->tag == Iex_Const) + return True; + if (a1->tag == Iex_Tmp && a1->Iex.Tmp.tmp < mce->n_originalTmps) + return True; + return False; } -#undef dis +static Bool isShadowAtom ( MCEnv* mce, IRAtom* a1 ) +{ + if (a1->tag == Iex_Const) + return True; + if (a1->tag == Iex_Tmp && a1->Iex.Tmp.tmp >= mce->n_originalTmps) + return True; + return False; +} + + + + +/* Shadow state is always accessed using integer types. This returns + an integer type with the same size (as per sizeofIRType) as the + given type. +*/ +static IRType shadowType ( IRType ty ) +{ + switch (ty) { + case Ity_I32: return ty; + default: VG_(skin_panic)("memcheck:shadowType"); + } +} + +/* Find the tmp currently shadowing the given original tmp. If none + so far exists, allocate one. */ +static IRTemp findShadowTmp ( MCEnv* mce, IRTemp orig ) +{ + sk_assert(orig < mce->n_originalTmps); + if (mce->tmpMap[orig] == INVALID_IRTEMP) { + mce->tmpMap[orig] + = newIRTemp(mce->bb->tyenv, + shadowType(mce->bb->tyenv->types[orig])); + } + return mce->tmpMap[orig]; +} + +/* Allocate a new shadow for the given original tmp. This means any + previous shadow is abandoned. This is needed because it is + necessary to give a new value to a shadow once it has been tested + for undefinedness, but unfortunately IR's SSA property disallows + this. Instead we must abandon the old shadow, allocate a new one + and use that instead. */ +static void newShadowTmp ( MCEnv* mce, IRTemp orig ) +{ + sk_assert(orig < mce->n_originalTmps); + mce->tmpMap[orig] + = newIRTemp(mce->bb->tyenv, + shadowType(mce->bb->tyenv->types[orig])); +} + + +static IRExpr* expr2vbits ( MCEnv* mce, IRExpr* e ); + +#define assign(_bb,_tmp,_expr) \ + addStmtToIRBB((_bb), IRStmt_Tmp((_tmp),(_expr))) +#define stmt(_bb,_stmt) \ + addStmtToIRBB((_bb), (_stmt)) + + +#define binop(_op, _arg1, _arg2) IRExpr_Binop((_op),(_arg1),(_arg2)) +#define unop(_op, _arg) IRExpr_Unop((_op),(_arg)) +#define mkU32(_n) IRExpr_Const(IRConst_U32(_n)) +#define mkU64(_n) IRExpr_Const(IRConst_U64(_n)) +#define mkexpr(_tmp) IRExpr_Tmp((_tmp)) + +static IRAtom* assignNew ( MCEnv* mce, IRType ty, IRExpr* e ) { + IRTemp t = newIRTemp(mce->bb->tyenv, ty); + assign(mce->bb, t, e); + return mkexpr(t); +} + +/* Should only be supplied shadow types (I8/I16/I32/UI64). */ +static IRExpr* definedOfType ( IRType ty ) { + switch (ty) { + case Ity_I32: return mkU32(0); + default: VG_(skin_panic)("memcheck:definedOfType"); + } +} + +static IRAtom* mkUifU32 ( MCEnv* mce, IRAtom* a1, IRAtom* a2 ) { + sk_assert(isShadowAtom(mce,a1)); + sk_assert(isShadowAtom(mce,a2)); + return assignNew(mce, Ity_I32, binop(Iop_Or32, a1, a2)); +} + +static IRExpr* mkLeft32 ( MCEnv* mce, IRAtom* a1 ) { + sk_assert(isShadowAtom(mce,a1)); + /* It's safe to duplicate a1 since it's only an atom */ + return assignNew(mce, Ity_I32, + binop(Iop_Or32, a1, unop(Iop_Neg32, a1))); +} + +static void setHelperAnns ( MCEnv* mce, IRDirty* di ) { + di->nFxState = 2; + di->fxState[0].fx = Ifx_Read; + di->fxState[0].offset = mce->layout->offset_SP; + di->fxState[0].size = mce->layout->sizeof_SP; + di->fxState[1].fx = Ifx_Read; + di->fxState[1].offset = mce->layout->offset_IP; + di->fxState[1].size = mce->layout->sizeof_IP; +} + +static IRAtom* genPCastTo( MCEnv* mce, IRAtom* vbits, IRType dst_ty ) { + /* First of all, collapse vbits down to a single bit. */ + sk_assert(isShadowAtom(mce,vbits)); + IRType ty = typeOfIRExpr(mce->bb->tyenv, vbits); + IRAtom* tmp1 = NULL; + switch (ty) { + case Ity_I32: + tmp1 = assignNew(mce, Ity_Bit, binop(Iop_CmpNE32, vbits, mkU32(0))); + break; + default: + VG_(skin_panic)("genPCastTo(1)"); + } + sk_assert(tmp1); + /* Now widen up to the dst type. */ + switch (dst_ty) { + case Ity_Bit: + return tmp1; + case Ity_I32: + return assignNew(mce, Ity_I32, unop(Iop_1Sto32, tmp1)); + default: + ppIRType(dst_ty); + VG_(skin_panic)("genPCastTo(2)"); + } +} + +/* Examine the always-defined sections declared in layout to see if + the (offset,size) section is within one. Note, is is an error to + partially fall into such a region: (offset,size) should either be + completely in such a region or completely not-in such a region. +*/ +static Bool isAlwaysDefd ( MCEnv* mce, Int offset, Int size ) +{ + Int minoffD, maxoffD, i; + Int minoff = offset; + Int maxoff = minoff + size - 1; + sk_assert((minoff & ~0xFFFF) == 0); + sk_assert((maxoff & ~0xFFFF) == 0); + + for (i = 0; i < mce->layout->n_alwaysDefd; i++) { + minoffD = mce->layout->alwaysDefd[i].offset; + maxoffD = minoffD + mce->layout->alwaysDefd[i].size - 1; + sk_assert((minoffD & ~0xFFFF) == 0); + sk_assert((maxoffD & ~0xFFFF) == 0); + + if (maxoff < minoffD || maxoffD < minoff) + continue; /* no overlap */ + if (minoff >= minoffD && maxoff <= maxoffD) + return True; /* completely contained in an always-defd section */ + + VG_(skin_panic)("memcheck:isAlwaysDefd:partial overlap"); + } + return False; /* could not find any containing section */ +} + + +static +void complainIfUndefined ( MCEnv* mce, IRAtom* vatom, IRAtom* atom ) +{ + /* vatom is required to be the V-bits shadow for atom. */ + sk_assert(isOriginalAtom(mce, atom)); + sk_assert(isShadowAtom(mce, vatom)); + sk_assert(sameKindedAtoms(atom, vatom)); + + IRType ty = typeOfIRExpr(mce->bb->tyenv, vatom); + Int sz = sizeofIRType(ty); + + IRExpr* cond = genPCastTo( mce, vatom, Ity_Bit ); + /* cond will be 0 if all defined, and 1 if any not defined. */ + + IRDirty* di + = unsafeIRDirty_0_N( 1/*regparms*/, + "MC_(helperc_complain_undef)", + &MC_(helperc_complain_undef), + mkIRExprVec_1( mkIRExpr_HWord(sz) )); + di->guard = cond; + setHelperAnns( mce, di ); + stmt( mce->bb, IRStmt_Dirty(di)); + + /* Set the shadow tmp to be defined. First, update the + orig->shadow tmp mapping to reflect the fact that this shadow is + getting a new value. */ + sk_assert(isAtom(vatom)); + /* sameKindedAtoms ... */ + if (vatom->tag == Iex_Tmp) { + sk_assert(atom->tag == Iex_Tmp); + newShadowTmp(mce, atom->Iex.Tmp.tmp); + assign(mce->bb, findShadowTmp(mce, atom->Iex.Tmp.tmp), + definedOfType(ty)); + } +} + + +/* Generate into bb suitable actions to shadow this Put. If the state + slice is marked 'always defined', emit a complaint if any of the + supplied V bits are 1, and do not modify shadow state. Otherwise, + write the supplied V bits to the shadow state. */ +static +void do_shadow_PUT ( MCEnv* mce, Int offset, IRAtom* vatom, IRAtom* atom ) +{ + /* vatom is required to be the V-bits shadow for atom. */ + sk_assert(isOriginalAtom(mce, atom)); + sk_assert(isShadowAtom(mce, vatom)); + sk_assert(sameKindedAtoms(atom, vatom)); + IRType ty = typeOfIRExpr(mce->bb->tyenv, vatom); + sk_assert(ty != Ity_Bit); + if (isAlwaysDefd(mce, offset, sizeofIRType(ty))) { + /* emit code to emit a complaint if any of the vbits are 1. */ + complainIfUndefined(mce, vatom, atom); + } else { + /* Do a plain shadow Put. */ + stmt( mce->bb, IRStmt_Put( offset + mce->layout->total_sizeB, vatom ) ); + } +} + + +/* Return an expression which contains the V bits corresponding to the + given GET (passed in in pieces). +*/ +static +IRExpr* shadow_GET ( MCEnv* mce, Int offset, IRType ty ) +{ + IRType tyS = shadowType(ty); + sk_assert(ty != Ity_Bit); + if (isAlwaysDefd(mce, offset, sizeofIRType(ty))) { + /* Always defined, return all zeroes of the relevant type */ + return definedOfType(tyS); + } else { + /* return a cloned version of the Get that refers to the shadow + area. */ + return IRExpr_Get( offset + mce->layout->total_sizeB, tyS ); + } +} + + +/* Return an expression which contains the V bits corresponding to the + given GETI (passed in in pieces). +*/ +static +IRExpr* shadow_GETI ( MCEnv* mce, IRArray* descr, IRAtom* ix, Int bias ) +{ + IRType ty = descr->elemTy; + IRType tyS = shadowType(ty); + Int arrSize = descr->nElems * sizeofIRType(ty); + sk_assert(ty != Ity_Bit); + sk_assert(isOriginalAtom(mce,ix)); + if (isAlwaysDefd(mce, descr->base, arrSize)) { + /* Always defined, return all zeroes of the relevant type */ + return definedOfType(tyS); + } else { + /* return a cloned version of the Get that refers to the shadow + area. */ + IRArray* new_descr + = mkIRArray( descr->base + mce->layout->total_sizeB, + tyS, descr->nElems); + return IRExpr_GetI( new_descr, ix, bias ); + } +} + + +static +IRExpr* expr2vbits_Binop ( MCEnv* mce, + IROp op, + IRExpr* atom1, IRExpr* atom2, + IRExpr* vatom1, IRExpr* vatom2 ) +{ + IRAtom* ta; + sk_assert(isOriginalAtom(mce,atom1)); + sk_assert(isOriginalAtom(mce,atom2)); + sk_assert(isShadowAtom(mce,vatom1)); + sk_assert(isShadowAtom(mce,vatom2)); + sk_assert(sameKindedAtoms(atom1,vatom1)); + sk_assert(sameKindedAtoms(atom2,vatom2)); + switch (op) { + case Iop_Sub32: + case Iop_Add32: + ta = mkUifU32(mce,vatom1,vatom2); + return mkLeft32(mce, ta); + default: + ppIROp(op); + VG_(skin_panic)("memcheck:expr2vbits_Binop"); + } +} + + +static +IRExpr* expr2vbits_LDle ( MCEnv* mce, IRType ty, IRAtom* addr ) +{ + void* helper; + Char* hname; + IRDirty* di; + IRTemp datavbits; + + sk_assert(isOriginalAtom(mce,addr)); + + /* First, emit a definedness test for the address. This also sets + the address (shadow) to 'defined' following the test. */ + complainIfUndefined( mce, expr2vbits( mce, addr ), addr ); + + /* Now cook up a call to the relevant helper function, to read the + data V bits from shadow memory. */ + switch (ty) { + case Ity_I32: helper = &MC_(helperc_LOADV4); + hname = "MC_(helperc_LOADV4)"; + break; + case Ity_I16: helper = &MC_(helperc_LOADV2); + hname = "MC_(helperc_LOADV2)"; + break; + case Ity_I8: helper = &MC_(helperc_LOADV1); + hname = "MC_(helperc_LOADV1)"; + break; + default: VG_(skin_panic)("memcheck:do_shadow_LDle"); + } + + /* We need to have a place to park the V bits we're just about to + read. */ + datavbits = newIRTemp(mce->bb->tyenv, ty); + di = unsafeIRDirty_1_N( datavbits, + 1/*regparms*/, hname, helper, mkIRExprVec_1( addr )); + setHelperAnns( mce, di ); + stmt( mce->bb, IRStmt_Dirty(di) ); + + return mkexpr(datavbits); +} + + +static +IRExpr* expr2vbits ( MCEnv* mce, IRExpr* e ) +{ + IRExpr *v1, *v2; + switch (e->tag) { + + case Iex_Get: + return shadow_GET( mce, e->Iex.Get.offset, e->Iex.Get.ty ); + + case Iex_Tmp: + return IRExpr_Tmp( findShadowTmp(mce, e->Iex.Tmp.tmp) ); + + case Iex_Const: + return definedOfType(shadowType(typeOfIRExpr(mce->bb->tyenv, e))); + + case Iex_Binop: + v1 = expr2vbits( mce, e->Iex.Binop.arg1); + v2 = expr2vbits( mce, e->Iex.Binop.arg2); + return expr2vbits_Binop( + mce, + e->Iex.Binop.op, + e->Iex.Binop.arg1, e->Iex.Binop.arg2, + v1, v2 + ); + + case Iex_LDle: + return expr2vbits_LDle( mce, e->Iex.LDle.ty, e->Iex.LDle.addr ); + + default: + VG_(printf)("\n"); + ppIRExpr(e); + VG_(printf)("\n"); + VG_(skin_panic)("memcheck: expr2vbits"); + } +} + +static +IRExpr* zwidenToHostWord ( MCEnv* mce, IRAtom* vatom ) +{ + /* vatom is vbits-value and as such can only have an integer + type. */ + sk_assert(isShadowAtom(mce,vatom)); + IRType tyH = mce->hWordTy; + IRType ty = typeOfIRExpr(mce->bb->tyenv, vatom); + switch (ty) { + case Ity_I32: + if (tyH == Ity_I32) return vatom; + goto unhandled; + unhandled: + default: VG_(skin_panic)("zwidenToHostWord"); + } +} + +static +void do_shadow_STle ( MCEnv* mce, IRAtom* addr, IRAtom* data ) +{ + IRType ty; + IRDirty* di; + IRExpr* datavbits; + void* helper = NULL; + Char* hname = NULL; + + ty = shadowType(typeOfIRExpr(mce->bb->tyenv, data)); + + sk_assert(isOriginalAtom(mce,addr)); + sk_assert(isOriginalAtom(mce,data)); + + /* First, emit a definedness test for the address. This also sets + the address (shadow) to 'defined' following the test. */ + complainIfUndefined( mce, expr2vbits( mce, addr ), addr); + + /* Now cook up a call to the relevant helper function, to write the + data V bits into shadow memory. */ + datavbits = expr2vbits( mce, data ); + switch (ty) { + case Ity_I32: helper = &MC_(helperc_STOREV4); + hname = "MC_(helperc_STOREV4)"; + break; + case Ity_I16: helper = &MC_(helperc_STOREV2); + hname = "MC_(helperc_STOREV2)"; + break; + case Ity_I8: helper = &MC_(helperc_STOREV1); + hname = "MC_(helperc_STOREV1)"; + break; + default: VG_(skin_panic)("memcheck:do_shadow_STle"); + } + + di = unsafeIRDirty_0_N( + 2/*regparms*/, hname, helper, + mkIRExprVec_2( addr, + zwidenToHostWord( mce, datavbits ))); + setHelperAnns( mce, di ); + stmt( mce->bb, IRStmt_Dirty(di) ); +} + +//////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////// + +IRBB* SK_(instrument) ( IRBB* bb_in, VexGuestLayout* layout, IRType hWordTy ) +{ + Bool verbose = True; + + Int i, j, n_types, first_stmt; + IRStmt* st; + MCEnv mce; + + /* Set up BB */ + IRBB* bb = emptyIRBB(); + bb->tyenv = dopyIRTypeEnv(bb_in->tyenv); + bb->next = dopyIRExpr(bb_in->next); + bb->jumpkind = bb_in->jumpkind; + + /* Allocate shadow IRTemps. + 0 .. n_types-1 are the original IRTemps. + n_types .. 2*n_types-1 are the shadow IRTemps. + */ + n_types = bb->tyenv->types_used; + for (i = 0; i < n_types; i++) + newIRTemp(bb->tyenv, shadowType(bb->tyenv->types[i])); + + /* Set up the running environment. Only .bb is modified as we go + along. */ + mce.bb = bb; + mce.layout = layout; + mce.n_originalTmps = n_types; + mce.hWordTy = hWordTy; + mce.tmpMap = LibVEX_Alloc(n_types * sizeof(IRTemp)); + for (i = 0; i < n_types; i++) + mce.tmpMap[i] = INVALID_IRTEMP; + + for (i = 0; i < bb_in->stmts_used; i++) { + st = bb_in->stmts[i]; + if (!st) continue; + + sk_assert(isFlatIRStmt(st)); + first_stmt = bb->stmts_used; + + if (verbose) { + ppIRStmt(st); + VG_(printf)("\n\n"); + } + + switch (st->tag) { + + case Ist_Tmp: + assign( bb, findShadowTmp(&mce, st->Ist.Tmp.tmp), + expr2vbits( &mce, st->Ist.Tmp.data) ); + break; + + case Ist_Put: + do_shadow_PUT( &mce, + st->Ist.Put.offset, + expr2vbits( &mce, st->Ist.Put.data), + st->Ist.Put.data ); + break; + + case Ist_STle: + do_shadow_STle( &mce, st->Ist.STle.addr, st->Ist.STle.data ); + break; + + default: + VG_(printf)("\n"); + ppIRStmt(st); + VG_(printf)("\n"); + VG_(skin_panic)("memcheck: unhandled IRStmt"); + + } /* switch (st->tag) */ + + if (verbose) { + for (j = first_stmt; j < bb->stmts_used; j++) { + VG_(printf)(" "); + ppIRStmt(bb->stmts[j]); + VG_(printf)("\n"); + } + VG_(printf)("\n"); + } + + addStmtToIRBB(bb, st); + + } + + /* Uh, ok. Now we need to complain if the jump target is + undefined. */ + complainIfUndefined( &mce, expr2vbits( &mce, bb->next ), bb->next ); + + return bb; + +# undef IRSHADOW +} /*--------------------------------------------------------------------*/ /*--- end mc_translate.c ---*/