From: Julian Seward Date: Sun, 7 Nov 2004 18:46:22 +0000 (+0000) Subject: Memcheck: add helper functions to support 64-bit loads/stores. This X-Git-Tag: svn/VALGRIND_3_0_1^2~813 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=680525ffbb7b467f2223bedd1b7585c1fb195a0e;p=thirdparty%2Fvalgrind.git Memcheck: add helper functions to support 64-bit loads/stores. This stuff all needs serious rethinking to make it work on 64-bit platforms and on big-endian platforms. git-svn-id: svn://svn.valgrind.org/vex/trunk@521 --- diff --git a/VEX/head20041019/memcheck/mac_shared.h b/VEX/head20041019/memcheck/mac_shared.h index 4a5014c98b..b41f12fb59 100644 --- a/VEX/head20041019/memcheck/mac_shared.h +++ b/VEX/head20041019/memcheck/mac_shared.h @@ -233,6 +233,9 @@ extern UInt MAC_(event_ctr)[N_PROF_EVENTS]; #define VGM_WORD_VALID 0 #define VGM_WORD_INVALID 0xFFFFFFFF +#define VGM_WORD64_VALID 0x0ULL +#define VGM_WORD64_INVALID 0xFFFFFFFFFFFFFFFFULL + #define VGM_EFLAGS_VALID 0xFFFFFFFE #define VGM_EFLAGS_INVALID 0xFFFFFFFF /* not used */ diff --git a/VEX/head20041019/memcheck/mc_include.h b/VEX/head20041019/memcheck/mc_include.h index ae6ddc1b4d..d294530d0a 100644 --- a/VEX/head20041019/memcheck/mc_include.h +++ b/VEX/head20041019/memcheck/mc_include.h @@ -116,6 +116,7 @@ extern Bool MC_(clo_avoid_strlen_errors); /* Functions defined in mc_main.c */ extern REGPARM(1) void MC_(helperc_complain_undef) ( HWord ); +extern REGPARM(1) void MC_(helperc_STOREV8) ( Addr, ULong ); 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 ); @@ -123,6 +124,7 @@ extern REGPARM(2) void MC_(helperc_STOREV1) ( Addr, UInt ); extern REGPARM(1) UInt MC_(helperc_LOADV1) ( Addr ); extern REGPARM(1) UInt MC_(helperc_LOADV2) ( Addr ); extern REGPARM(1) UInt MC_(helperc_LOADV4) ( Addr ); +extern REGPARM(1) ULong MC_(helperc_LOADV8) ( Addr ); extern REGPARM(2) void MC_(fpu_write_check) ( Addr addr, Int size ); extern REGPARM(2) void MC_(fpu_read_check) ( Addr addr, Int size ); diff --git a/VEX/head20041019/memcheck/mc_main.c b/VEX/head20041019/memcheck/mc_main.c index e0bce694ed..7bc2708a80 100644 --- a/VEX/head20041019/memcheck/mc_main.c +++ b/VEX/head20041019/memcheck/mc_main.c @@ -93,12 +93,16 @@ /*--- Function declarations. ---*/ /*------------------------------------------------------------*/ -static UInt mc_rd_V4_SLOWLY ( Addr a ); -static UInt mc_rd_V2_SLOWLY ( Addr a ); -static UInt mc_rd_V1_SLOWLY ( Addr a ); +static ULong mc_rd_V8_SLOWLY ( Addr a ); +static UInt mc_rd_V4_SLOWLY ( Addr a ); +static UInt mc_rd_V2_SLOWLY ( Addr a ); +static UInt mc_rd_V1_SLOWLY ( Addr a ); + +static void mc_wr_V8_SLOWLY ( Addr a, ULong vbytes ); static void mc_wr_V4_SLOWLY ( Addr a, UInt vbytes ); static void mc_wr_V2_SLOWLY ( Addr a, UInt vbytes ); static void mc_wr_V1_SLOWLY ( Addr a, UInt vbytes ); + static void mc_fpu_read_check_SLOWLY ( Addr addr, Int size ); static void mc_fpu_write_check_SLOWLY ( Addr addr, Int size ); @@ -759,13 +763,90 @@ static __inline__ UInt shiftRight16 ( UInt x ) } -/* Read/write 1/2/4 sized V bytes, and emit an address error if +/* Read/write 1/2/4/8 sized V bytes, and emit an address error if needed. */ -/* VG_(helperc_{LD,ST}V{1,2,4}) handle the common case fast. +/* MC_(helperc_{LD,ST}V{1,2,4,8}) handle the common case fast. Under all other circumstances, it defers to the relevant _SLOWLY function, which can handle all situations. */ + +/* ------------------------ Size = 8 ------------------------ */ + +REGPARM(1) +ULong MC_(helperc_LOADV8) ( Addr a ) +{ +# ifdef VG_DEBUG_MEMORY + return mc_rd_V8_SLOWLY(a); +# else + if (IS_ALIGNED8_ADDR(a)) { + UInt sec_no = shiftRight16(a) & 0xFFFF; + SecMap* sm = primary_map[sec_no]; + UInt a_off = (a & 0xFFFF) >> 3; + UChar abits = sm->abits[a_off]; + if (abits == VGM_BYTE_VALID) { + /* a is 8-aligned, mapped, and addressible. */ + UInt v_off = a & 0xFFFF; + /* LITTLE-ENDIAN */ + UInt vLo = ((UInt*)(sm->vbyte))[ (v_off >> 2) ]; + UInt vHi = ((UInt*)(sm->vbyte))[ (v_off >> 2) + 1 ]; + return ( ((ULong)vHi) << 32 ) | ((ULong)vLo); + } else { + return mc_rd_V8_SLOWLY(a); + } + } + else + if (IS_ALIGNED4_ADDR(a)) { + /* LITTLE-ENDIAN */ + UInt vLo = MC_(helperc_LOADV4)(a+0); + UInt vHi = MC_(helperc_LOADV4)(a+4); + return ( ((ULong)vHi) << 32 ) | ((ULong)vLo); + } + else + return mc_rd_V8_SLOWLY(a); +# endif +} + +REGPARM(1) +void MC_(helperc_STOREV8) ( Addr a, ULong vbytes ) +{ +# ifdef VG_DEBUG_MEMORY + mc_wr_V8_SLOWLY(a, vbytes); +# else + if (IS_ALIGNED8_ADDR(a)) { + UInt sec_no = shiftRight16(a) & 0xFFFF; + SecMap* sm = primary_map[sec_no]; + UInt a_off = (a & 0xFFFF) >> 3; + UChar abits = sm->abits[a_off]; + if (abits == VGM_BYTE_VALID) { + /* a is 8-aligned, mapped, and addressible. */ + UInt v_off = a & 0xFFFF; + UInt vHi = (UInt)(vbytes >> 32); + UInt vLo = (UInt)vbytes; + /* LITTLE-ENDIAN */ + ((UInt*)(sm->vbyte))[ (v_off >> 2) ] = vLo; + ((UInt*)(sm->vbyte))[ (v_off >> 2) + 1 ] = vHi; + } else { + mc_wr_V8_SLOWLY(a, vbytes); + } + return; + } + else + if (IS_ALIGNED4_ADDR(a)) { + UInt vHi = (UInt)(vbytes >> 32); + UInt vLo = (UInt)vbytes; + /* LITTLE-ENDIAN */ + MC_(helperc_STOREV4)(a+0, vLo); + MC_(helperc_STOREV4)(a+4, vHi); + return; + } + else + mc_wr_V8_SLOWLY(a, vbytes); +# endif +} + +/* ------------------------ Size = 4 ------------------------ */ + REGPARM(1) UInt MC_(helperc_LOADV4) ( Addr a ) { @@ -816,6 +897,8 @@ void MC_(helperc_STOREV4) ( Addr a, UInt vbytes ) # endif } +/* ------------------------ Size = 2 ------------------------ */ + REGPARM(1) UInt MC_(helperc_LOADV2) ( Addr a ) { @@ -860,6 +943,8 @@ void MC_(helperc_STOREV2) ( Addr a, UInt vbytes ) # endif } +/* ------------------------ Size = 1 ------------------------ */ + REGPARM(1) UInt MC_(helperc_LOADV1) ( Addr a ) { @@ -907,9 +992,129 @@ void MC_(helperc_STOREV1) ( Addr a, UInt vbytes ) /*------------------------------------------------------------*/ /*--- Fallback functions to handle cases that the above ---*/ -/*--- VG_(helperc_{LD,ST}V{1,2,4}) can't manage. ---*/ +/*--- MC_(helperc_{LD,ST}V{1,2,4,8}) can't manage. ---*/ /*------------------------------------------------------------*/ +/* ------------------------ Size = 8 ------------------------ */ + +static ULong mc_rd_V8_SLOWLY ( Addr a ) +{ + Bool a0ok, a1ok, a2ok, a3ok, a4ok, a5ok, a6ok, a7ok; + UInt vb0, vb1, vb2, vb3, vb4, vb5, vb6, vb7; + + PROF_EVENT(70); + + /* First establish independently the addressibility of the 4 bytes + involved. */ + a0ok = get_abit(a+0) == VGM_BIT_VALID; + a1ok = get_abit(a+1) == VGM_BIT_VALID; + a2ok = get_abit(a+2) == VGM_BIT_VALID; + a3ok = get_abit(a+3) == VGM_BIT_VALID; + a4ok = get_abit(a+4) == VGM_BIT_VALID; + a5ok = get_abit(a+5) == VGM_BIT_VALID; + a6ok = get_abit(a+6) == VGM_BIT_VALID; + a7ok = get_abit(a+7) == VGM_BIT_VALID; + + /* Also get the validity bytes for the address. */ + vb0 = (UInt)get_vbyte(a+0); + vb1 = (UInt)get_vbyte(a+1); + vb2 = (UInt)get_vbyte(a+2); + vb3 = (UInt)get_vbyte(a+3); + vb4 = (UInt)get_vbyte(a+4); + vb5 = (UInt)get_vbyte(a+5); + vb6 = (UInt)get_vbyte(a+6); + vb7 = (UInt)get_vbyte(a+7); + + /* Now distinguish 3 cases */ + + /* Case 1: the address is completely valid, so: + - no addressing error + - return V bytes as read from memory + */ + if (a0ok && a1ok && a2ok && a3ok && a4ok && a5ok && a6ok && a7ok) { + ULong vw = VGM_WORD64_INVALID; + vw <<= 8; vw |= vb7; + vw <<= 8; vw |= vb6; + vw <<= 8; vw |= vb5; + vw <<= 8; vw |= vb4; + vw <<= 8; vw |= vb3; + vw <<= 8; vw |= vb2; + vw <<= 8; vw |= vb1; + vw <<= 8; vw |= vb0; + return vw; + } + + /* Case 2: the address is completely invalid. + - emit addressing error + - return V word indicating validity. + This sounds strange, but if we make loads from invalid addresses + give invalid data, we also risk producing a number of confusing + undefined-value errors later, which confuses the fact that the + error arose in the first place from an invalid address. + */ + /* VG_(printf)("%p (%d %d %d %d)\n", a, a0ok, a1ok, a2ok, a3ok); */ + if (!MAC_(clo_partial_loads_ok) + || ((a & 7) != 0) + || (!a0ok && !a1ok && !a2ok && !a3ok && !a4ok && !a5ok && !a6ok && !a7ok)) { + MAC_(record_address_error)( VG_(get_current_tid)(), a, 8, False ); + return VGM_WORD64_VALID; + } + + /* Case 3: the address is partially valid. + - no addressing error + - returned V word is invalid where the address is invalid, + and contains V bytes from memory otherwise. + Case 3 is only allowed if MC_(clo_partial_loads_ok) is True + (which is the default), and the address is 4-aligned. + If not, Case 2 will have applied. + */ + sk_assert(MAC_(clo_partial_loads_ok)); + { + ULong vw = VGM_WORD64_INVALID; + vw <<= 8; vw |= (a7ok ? vb7 : VGM_BYTE_INVALID); + vw <<= 8; vw |= (a6ok ? vb6 : VGM_BYTE_INVALID); + vw <<= 8; vw |= (a5ok ? vb5 : VGM_BYTE_INVALID); + vw <<= 8; vw |= (a4ok ? vb4 : VGM_BYTE_INVALID); + vw <<= 8; vw |= (a3ok ? vb3 : VGM_BYTE_INVALID); + vw <<= 8; vw |= (a2ok ? vb2 : VGM_BYTE_INVALID); + vw <<= 8; vw |= (a1ok ? vb1 : VGM_BYTE_INVALID); + vw <<= 8; vw |= (a0ok ? vb0 : VGM_BYTE_INVALID); + return vw; + } +} + +static void mc_wr_V8_SLOWLY ( Addr a, ULong vbytes ) +{ + /* Check the address for validity. */ + Bool aerr = False; + PROF_EVENT(71); + + if (get_abit(a+0) != VGM_BIT_VALID) aerr = True; + if (get_abit(a+1) != VGM_BIT_VALID) aerr = True; + if (get_abit(a+2) != VGM_BIT_VALID) aerr = True; + if (get_abit(a+3) != VGM_BIT_VALID) aerr = True; + if (get_abit(a+4) != VGM_BIT_VALID) aerr = True; + if (get_abit(a+5) != VGM_BIT_VALID) aerr = True; + if (get_abit(a+6) != VGM_BIT_VALID) aerr = True; + if (get_abit(a+7) != VGM_BIT_VALID) aerr = True; + + /* Store the V bytes, remembering to do it little-endian-ly. */ + set_vbyte( a+0, vbytes & 0x000000FF ); vbytes >>= 8; + set_vbyte( a+1, vbytes & 0x000000FF ); vbytes >>= 8; + set_vbyte( a+2, vbytes & 0x000000FF ); vbytes >>= 8; + set_vbyte( a+3, vbytes & 0x000000FF ); vbytes >>= 8; + set_vbyte( a+4, vbytes & 0x000000FF ); vbytes >>= 8; + set_vbyte( a+5, vbytes & 0x000000FF ); vbytes >>= 8; + set_vbyte( a+6, vbytes & 0x000000FF ); vbytes >>= 8; + set_vbyte( a+7, vbytes & 0x000000FF ); + + /* If an address error has happened, report it. */ + if (aerr) + MAC_(record_address_error)( VG_(get_current_tid)(), a, 8, True ); +} + +/* ------------------------ Size = 4 ------------------------ */ + static UInt mc_rd_V4_SLOWLY ( Addr a ) { Bool a0ok, a1ok, a2ok, a3ok; @@ -1003,6 +1208,8 @@ static void mc_wr_V4_SLOWLY ( Addr a, UInt vbytes ) MAC_(record_address_error)( VG_(get_current_tid)(), a, 4, True ); } +/* ------------------------ Size = 2 ------------------------ */ + static UInt mc_rd_V2_SLOWLY ( Addr a ) { /* Check the address for validity. */ @@ -1044,6 +1251,8 @@ static void mc_wr_V2_SLOWLY ( Addr a, UInt vbytes ) MAC_(record_address_error)( VG_(get_current_tid)(), a, 2, True ); } +/* ------------------------ Size = 1 ------------------------ */ + static UInt mc_rd_V1_SLOWLY ( Addr a ) { /* Check the address for validity. */ @@ -1337,9 +1546,9 @@ void mc_fpu_write_check_SLOWLY ( Addr addr, Int size ) a_here = addr+i; a_ok = get_abit(a_here) == VGM_BIT_VALID; if (a_ok) { - set_vbyte(a_here, VGM_BYTE_VALID); + set_vbyte(a_here, VGM_BYTE_VALID); } else { - set_vbyte(a_here, VGM_BYTE_INVALID); + set_vbyte(a_here, VGM_BYTE_INVALID); aerr = True; } } @@ -1701,24 +1910,6 @@ 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)); - VG_(register_compact_helper)((Addr) & MC_(helper_value_check2_fail)); - VG_(register_compact_helper)((Addr) & MC_(helperc_STOREV4)); - VG_(register_compact_helper)((Addr) & MC_(helperc_LOADV4)); - - /* These two made non-compact because 2-byte transactions are rare. */ - VG_(register_noncompact_helper)((Addr) & MC_(helperc_STOREV2)); - VG_(register_noncompact_helper)((Addr) & MC_(helperc_STOREV1)); - VG_(register_noncompact_helper)((Addr) & MC_(helperc_LOADV2)); - VG_(register_noncompact_helper)((Addr) & MC_(helperc_LOADV1)); - 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" ); VGP_(register_profile_event) ( VgpESPAdj, "adjust-ESP" ); diff --git a/VEX/head20041019/memcheck/mc_translate.c b/VEX/head20041019/memcheck/mc_translate.c index 4f03b9ed5c..49ac87ae3e 100644 --- a/VEX/head20041019/memcheck/mc_translate.c +++ b/VEX/head20041019/memcheck/mc_translate.c @@ -792,9 +792,15 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, /* First arg is I32 (rounding mode), second is F64 (data). */ return mkLazy2(mce, Ity_I16, vatom1, vatom2); + case Iop_AddF64: + case Iop_DivF64: + case Iop_SubF64: case Iop_MulF64: return mkLazy2(mce, Ity_I64, vatom1, vatom2); + case Iop_CmpF64: + return mkLazy2(mce, Ity_I32, vatom1, vatom2); + /* non-FP after here */ case Iop_DivModU64to32: @@ -906,9 +912,14 @@ IRExpr* expr2vbits_Unop ( MCEnv* mce, IROp op, IRAtom* atom ) switch (op) { case Iop_F32toF64: - case Iop_I32toF64: + case Iop_I32toF64: + case Iop_I64toF64: + case Iop_NegF64: return mkPCastTo(mce, Ity_I64, vatom); + case Iop_F64toF32: + return mkPCastTo(mce, Ity_I32, vatom); + case Iop_64to32: case Iop_64HIto32: case Iop_1Uto32: @@ -958,6 +969,9 @@ IRAtom* expr2vbits_LDle ( MCEnv* mce, IRType ty, IRAtom* addr ) data V bits from shadow memory. */ ty = shadowType(ty); switch (ty) { + case Ity_I64: helper = &MC_(helperc_LOADV8); + hname = "MC_(helperc_LOADV8)"; + break; case Ity_I32: helper = &MC_(helperc_LOADV4); hname = "MC_(helperc_LOADV4)"; break; @@ -1111,6 +1125,9 @@ void do_shadow_STle ( MCEnv* mce, IRAtom* addr, IRAtom* data ) data V bits into shadow memory. */ datavbits = expr2vbits( mce, data ); switch (ty) { + case Ity_I64: helper = &MC_(helperc_STOREV8); + hname = "MC_(helperc_STOREV8)"; + break; case Ity_I32: helper = &MC_(helperc_STOREV4); hname = "MC_(helperc_STOREV4)"; break; @@ -1123,10 +1140,19 @@ void do_shadow_STle ( MCEnv* mce, IRAtom* addr, IRAtom* data ) default: VG_(skin_panic)("memcheck:do_shadow_STle"); } - di = unsafeIRDirty_0_N( - 2/*regparms*/, hname, helper, - mkIRExprVec_2( addr, - zwidenToHostWord( mce, datavbits ))); + if (ty == Ity_I64) { + /* We can't do this with regparm 2 on x86, since the back end + isn't clever enough to handle 64-bit regparm args. Therefore + be different. */ + di = unsafeIRDirty_0_N( + 1/*regparms*/, hname, helper, + mkIRExprVec_2( addr, datavbits )); + } else { + di = unsafeIRDirty_0_N( + 2/*regparms*/, hname, helper, + mkIRExprVec_2( addr, + zwidenToHostWord( mce, datavbits ))); + } setHelperAnns( mce, di ); stmt( mce->bb, IRStmt_Dirty(di) ); }