You can subscribe to this list here.
| 2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
(122) |
Nov
(152) |
Dec
(69) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2003 |
Jan
(6) |
Feb
(25) |
Mar
(73) |
Apr
(82) |
May
(24) |
Jun
(25) |
Jul
(10) |
Aug
(11) |
Sep
(10) |
Oct
(54) |
Nov
(203) |
Dec
(182) |
| 2004 |
Jan
(307) |
Feb
(305) |
Mar
(430) |
Apr
(312) |
May
(187) |
Jun
(342) |
Jul
(487) |
Aug
(637) |
Sep
(336) |
Oct
(373) |
Nov
(441) |
Dec
(210) |
| 2005 |
Jan
(385) |
Feb
(480) |
Mar
(636) |
Apr
(544) |
May
(679) |
Jun
(625) |
Jul
(810) |
Aug
(838) |
Sep
(634) |
Oct
(521) |
Nov
(965) |
Dec
(543) |
| 2006 |
Jan
(494) |
Feb
(431) |
Mar
(546) |
Apr
(411) |
May
(406) |
Jun
(322) |
Jul
(256) |
Aug
(401) |
Sep
(345) |
Oct
(542) |
Nov
(308) |
Dec
(481) |
| 2007 |
Jan
(427) |
Feb
(326) |
Mar
(367) |
Apr
(255) |
May
(244) |
Jun
(204) |
Jul
(223) |
Aug
(231) |
Sep
(354) |
Oct
(374) |
Nov
(497) |
Dec
(362) |
| 2008 |
Jan
(322) |
Feb
(482) |
Mar
(658) |
Apr
(422) |
May
(476) |
Jun
(396) |
Jul
(455) |
Aug
(267) |
Sep
(280) |
Oct
(253) |
Nov
(232) |
Dec
(304) |
| 2009 |
Jan
(486) |
Feb
(470) |
Mar
(458) |
Apr
(423) |
May
(696) |
Jun
(461) |
Jul
(551) |
Aug
(575) |
Sep
(134) |
Oct
(110) |
Nov
(157) |
Dec
(102) |
| 2010 |
Jan
(226) |
Feb
(86) |
Mar
(147) |
Apr
(117) |
May
(107) |
Jun
(203) |
Jul
(193) |
Aug
(238) |
Sep
(300) |
Oct
(246) |
Nov
(23) |
Dec
(75) |
| 2011 |
Jan
(133) |
Feb
(195) |
Mar
(315) |
Apr
(200) |
May
(267) |
Jun
(293) |
Jul
(353) |
Aug
(237) |
Sep
(278) |
Oct
(611) |
Nov
(274) |
Dec
(260) |
| 2012 |
Jan
(303) |
Feb
(391) |
Mar
(417) |
Apr
(441) |
May
(488) |
Jun
(655) |
Jul
(590) |
Aug
(610) |
Sep
(526) |
Oct
(478) |
Nov
(359) |
Dec
(372) |
| 2013 |
Jan
(467) |
Feb
(226) |
Mar
(391) |
Apr
(281) |
May
(299) |
Jun
(252) |
Jul
(311) |
Aug
(352) |
Sep
(481) |
Oct
(571) |
Nov
(222) |
Dec
(231) |
| 2014 |
Jan
(185) |
Feb
(329) |
Mar
(245) |
Apr
(238) |
May
(281) |
Jun
(399) |
Jul
(382) |
Aug
(500) |
Sep
(579) |
Oct
(435) |
Nov
(487) |
Dec
(256) |
| 2015 |
Jan
(338) |
Feb
(357) |
Mar
(330) |
Apr
(294) |
May
(191) |
Jun
(108) |
Jul
(142) |
Aug
(261) |
Sep
(190) |
Oct
(54) |
Nov
(83) |
Dec
(22) |
| 2016 |
Jan
(49) |
Feb
(89) |
Mar
(33) |
Apr
(50) |
May
(27) |
Jun
(34) |
Jul
(53) |
Aug
(53) |
Sep
(98) |
Oct
(206) |
Nov
(93) |
Dec
(53) |
| 2017 |
Jan
(65) |
Feb
(82) |
Mar
(102) |
Apr
(86) |
May
(187) |
Jun
(67) |
Jul
(23) |
Aug
(93) |
Sep
(65) |
Oct
(45) |
Nov
(35) |
Dec
(17) |
| 2018 |
Jan
(26) |
Feb
(35) |
Mar
(38) |
Apr
(32) |
May
(8) |
Jun
(43) |
Jul
(27) |
Aug
(30) |
Sep
(43) |
Oct
(42) |
Nov
(38) |
Dec
(67) |
| 2019 |
Jan
(32) |
Feb
(37) |
Mar
(53) |
Apr
(64) |
May
(49) |
Jun
(18) |
Jul
(14) |
Aug
(53) |
Sep
(25) |
Oct
(30) |
Nov
(49) |
Dec
(31) |
| 2020 |
Jan
(87) |
Feb
(45) |
Mar
(37) |
Apr
(51) |
May
(99) |
Jun
(36) |
Jul
(11) |
Aug
(14) |
Sep
(20) |
Oct
(24) |
Nov
(40) |
Dec
(23) |
| 2021 |
Jan
(14) |
Feb
(53) |
Mar
(85) |
Apr
(15) |
May
(19) |
Jun
(3) |
Jul
(14) |
Aug
(1) |
Sep
(57) |
Oct
(73) |
Nov
(56) |
Dec
(22) |
| 2022 |
Jan
(3) |
Feb
(22) |
Mar
(6) |
Apr
(55) |
May
(46) |
Jun
(39) |
Jul
(15) |
Aug
(9) |
Sep
(11) |
Oct
(34) |
Nov
(20) |
Dec
(36) |
| 2023 |
Jan
(79) |
Feb
(41) |
Mar
(99) |
Apr
(169) |
May
(48) |
Jun
(16) |
Jul
(16) |
Aug
(57) |
Sep
(19) |
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
1
|
2
|
3
(3) |
4
|
5
(7) |
|
6
|
7
|
8
(6) |
9
|
10
|
11
|
12
|
|
13
(1) |
14
|
15
(1) |
16
|
17
(2) |
18
|
19
(1) |
|
20
(2) |
21
(2) |
22
(2) |
23
|
24
|
25
|
26
|
|
27
|
28
(2) |
29
|
30
(1) |
31
|
|
|
|
From: Julian S. <se...@so...> - 2019-10-21 09:28:19
|
https://sourceware.org/git/gitweb.cgi?p=valgrind.git;h=7204d087d266acf4f42dbf1db9a21c6fd0640dd3 commit 7204d087d266acf4f42dbf1db9a21c6fd0640dd3 Author: Julian Seward <js...@ac...> Date: Mon Oct 21 11:19:59 2019 +0200 Initial implementation of C-source-level &&-idiom recovery This branch contains code which avoids Memcheck false positives resulting from gcc and clang creating branches on uninitialised data. For example: bool isClosed; if (src.isRect(..., &isClosed, ...) && isClosed) { clang9 -O2 compiles this as: callq 7e7cdc0 <_ZNK6SkPath6isRectEP6SkRectPbPNS_9DirectionE> cmpb $0x0,-0x60(%rbp) // "if (isClosed) { .." je 7ed9e08 // "je after" test %al,%al // "if (return value of call is nonzero) { .." je 7ed9e08 // "je after" .. after: That is, the && has been evaluated right-to-left. This is a correct transformation if the compiler can prove that the call to |isRect| returns |false| along any path on which it does not write its out-parameter |&isClosed|. In general, for the lazy-semantics (L->R) C-source-level && operator, we have |A && B| == |B && A| if you can prove that |B| is |false| whenever A is undefined. I assume that clang has some kind of interprocedural analysis that tells it that. The compiler is further obliged to show that |B| won't trap, since it is now being evaluated speculatively, but that's no big deal to prove. A similar result holds, per de Morgan, for transformations involving the C language ||. Memcheck correctly handles bitwise &&/|| in the presence of undefined inputs. It has done so since the beginning. However, it assumes that every conditional branch in the program is important -- any branch on uninitialised data is an error. However, this idiom demonstrates otherwise. It defeats Memcheck's existing &&/|| handling because the &&/|| is spread across two basic blocks, rather than being bitwise. This initial commit contains a complete initial implementation to fix that. The basic idea is to detect the && condition spread across two blocks, and transform it into a single block using bitwise &&. Then Memcheck's existing accurate instrumentation of bitwise && will correctly handle it. The transformation is <contents of basic block A> C1 = ... if (!C1) goto after .. falls through to .. <contents of basic block B> C2 = ... if (!C2) goto after .. falls through to .. after: ===> <contents of basic block A> C1 = ... <contents of basic block B, conditional on C1> C2 = ... if (!C1 && !C2) goto after .. falls through to .. after: This assumes that <contents of basic block B> can be conditionalised, at the IR level, so that the guest state is not modified if C1 is |false|. That's not possible for all IRStmt kinds, but it is possible for a large enough subset to make this transformation feasible. There is no corresponding transformation that recovers an || condition, because, per de Morgan, that merely corresponds to swapping the side exits vs fallthoughs, and inverting the sense of the tests, and the pattern-recogniser as implemented checks all possible combinations already. The analysis and block-building is performed on the IR returned by the architecture specific front ends. So they are almost not modified at all: in fact they are simplified because all logic related to chasing through unconditional and conditional branches has been removed from them, redone at the IR level, and centralised. The only file with big changes is the IRSB constructor logic, guest_generic_bb_to_IR.c (a.k.a the "trace builder"). This is a complete rewrite. There is some additional work for the IR optimiser (ir_opt.c), since that needs to do a quick initial simplification pass of the basic blocks, in order to reduce the number of different IR variants that the trace-builder has to pattern match on. An important followup task is to further reduce this cost. There are two new IROps to support this: And1 and Or1, which both operate on Ity_I1. They are regarded as evaluating both arguments, consistent with AndXX and OrXX for all other sizes. It is possible to synthesise at the IR level by widening the value to Ity_I8 or above, doing bitwise And/Or, and re-narrowing it, but this gives inefficient code, so I chose to represent them directly. The transformation appears to work for amd64-linux. In principle -- because it operates entirely at the IR level -- it should work for all targets, providing the initial pre-simplification pass can normalise the block ends into the required form. That will no doubt require some tuning. And1 and Or1 will have to be implemented in all instruction selectors, but that's easy enough. Remaining FIXMEs in the code: * Rename `expr_is_speculatable` et al to `expr_is_conditionalisable`. These functions merely conditionalise code; the speculation has already been done by gcc/clang. * `expr_is_speculatable`: properly check that Iex_Unop/Binop don't contain operatins that might trap (Div, Rem, etc). * `analyse_block_end`: recognise all block ends, and abort on ones that can't be recognised. Needed to ensure we don't miss any cases. * maybe: guest_amd64_toIR.c: generate better code for And1/Or1 * ir_opt.c, do_iropt_BB: remove the initial flattening pass since presimp will already have done it * ir_opt.c, do_minimal_initial_iropt_BB (a.k.a. presimp). Make this as cheap as possible. In particular, calling `cprop_BB_wrk` is total overkill since we only need copy propagation. * ir_opt.c: once the above is done, remove boolean parameter for `cprop_BB_wrk`. * ir_opt.c: concatenate_irsbs: maybe de-dup w.r.t. maybe_unroll_loop_BB. * remove option `guest_chase_cond` from VexControl (?). It was never used. * convert option `guest_chase_thresh` from VexControl (?) into a Bool, since the revised code here only cares about the 0-vs-nonzero distinction now. Diff: --- VEX/priv/guest_amd64_defs.h | 3 - VEX/priv/guest_amd64_toIR.c | 186 +--- VEX/priv/guest_arm64_defs.h | 3 - VEX/priv/guest_arm64_toIR.c | 15 - VEX/priv/guest_arm_defs.h | 3 - VEX/priv/guest_arm_toIR.c | 108 +-- VEX/priv/guest_generic_bb_to_IR.c | 1874 +++++++++++++++++++++++++------------ VEX/priv/guest_generic_bb_to_IR.h | 49 +- VEX/priv/guest_mips_defs.h | 3 - VEX/priv/guest_mips_toIR.c | 85 +- VEX/priv/guest_nanomips_defs.h | 3 - VEX/priv/guest_nanomips_toIR.c | 5 - VEX/priv/guest_ppc_defs.h | 3 - VEX/priv/guest_ppc_toIR.c | 42 +- VEX/priv/guest_s390_defs.h | 3 - VEX/priv/guest_s390_toIR.c | 39 +- VEX/priv/guest_x86_defs.h | 3 - VEX/priv/guest_x86_toIR.c | 153 +-- VEX/priv/host_amd64_isel.c | 23 +- VEX/priv/ir_defs.c | 9 +- VEX/priv/ir_opt.c | 99 +- VEX/priv/ir_opt.h | 6 + VEX/pub/libvex.h | 2 + VEX/pub/libvex_ir.h | 2 + memcheck/mc_translate.c | 46 +- memcheck/tests/vbit-test/binary.c | 6 + memcheck/tests/vbit-test/irops.c | 4 +- memcheck/tests/vbit-test/vbits.c | 2 + memcheck/tests/vbit-test/vbits.h | 4 +- 29 files changed, 1571 insertions(+), 1212 deletions(-) diff --git a/VEX/priv/guest_amd64_defs.h b/VEX/priv/guest_amd64_defs.h index a5de527..54672dc 100644 --- a/VEX/priv/guest_amd64_defs.h +++ b/VEX/priv/guest_amd64_defs.h @@ -49,9 +49,6 @@ guest_generic_bb_to_IR.h. */ extern DisResult disInstr_AMD64 ( IRSB* irbb, - Bool (*resteerOkFn) ( void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_code, Long delta, Addr guest_IP, diff --git a/VEX/priv/guest_amd64_toIR.c b/VEX/priv/guest_amd64_toIR.c index 4bba03c..0bcfefc 100644 --- a/VEX/priv/guest_amd64_toIR.c +++ b/VEX/priv/guest_amd64_toIR.c @@ -2291,7 +2291,6 @@ static void jmp_lit( /*MOD*/DisResult* dres, { vassert(dres->whatNext == Dis_Continue); vassert(dres->len == 0); - vassert(dres->continueAt == 0); vassert(dres->jk_StopHere == Ijk_INVALID); dres->whatNext = Dis_StopHere; dres->jk_StopHere = kind; @@ -2303,7 +2302,6 @@ static void jmp_treg( /*MOD*/DisResult* dres, { vassert(dres->whatNext == Dis_Continue); vassert(dres->len == 0); - vassert(dres->continueAt == 0); vassert(dres->jk_StopHere == Ijk_INVALID); dres->whatNext = Dis_StopHere; dres->jk_StopHere = kind; @@ -2318,7 +2316,6 @@ void jcc_01 ( /*MOD*/DisResult* dres, AMD64Condcode condPos; vassert(dres->whatNext == Dis_Continue); vassert(dres->len == 0); - vassert(dres->continueAt == 0); vassert(dres->jk_StopHere == Ijk_INVALID); dres->whatNext = Dis_StopHere; dres->jk_StopHere = Ijk_Boring; @@ -19834,9 +19831,6 @@ static Long dis_ESC_NONE ( /*MB_OUT*/DisResult* dres, /*MB_OUT*/Bool* expect_CAS, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const VexArchInfo* archinfo, const VexAbiInfo* vbi, Prefix pfx, Int sz, Long deltaIN @@ -20246,53 +20240,10 @@ Long dis_ESC_NONE ( vassert(-128 <= jmpDelta && jmpDelta < 128); d64 = (guest_RIP_bbstart+delta+1) + jmpDelta; delta++; - if (resteerCisOk - && vex_control.guest_chase_cond - && (Addr64)d64 != (Addr64)guest_RIP_bbstart - && jmpDelta < 0 - && resteerOkFn( callback_opaque, (Addr64)d64) ) { - /* Speculation: assume this backward branch is taken. So we - need to emit a side-exit to the insn following this one, - on the negation of the condition, and continue at the - branch target address (d64). If we wind up back at the - first instruction of the trace, just stop; it's better to - let the IR loop unroller handle that case. */ - stmt( IRStmt_Exit( - mk_amd64g_calculate_condition( - (AMD64Condcode)(1 ^ (opc - 0x70))), - Ijk_Boring, - IRConst_U64(guest_RIP_bbstart+delta), - OFFB_RIP ) ); - dres->whatNext = Dis_ResteerC; - dres->continueAt = d64; - comment = "(assumed taken)"; - } - else - if (resteerCisOk - && vex_control.guest_chase_cond - && (Addr64)d64 != (Addr64)guest_RIP_bbstart - && jmpDelta >= 0 - && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) { - /* Speculation: assume this forward branch is not taken. So - we need to emit a side-exit to d64 (the dest) and continue - disassembling at the insn immediately following this - one. */ - stmt( IRStmt_Exit( - mk_amd64g_calculate_condition((AMD64Condcode)(opc - 0x70)), - Ijk_Boring, - IRConst_U64(d64), - OFFB_RIP ) ); - dres->whatNext = Dis_ResteerC; - dres->continueAt = guest_RIP_bbstart+delta; - comment = "(assumed not taken)"; - } - else { - /* Conservative default translation - end the block at this - point. */ - jcc_01( dres, (AMD64Condcode)(opc - 0x70), - guest_RIP_bbstart+delta, d64 ); - vassert(dres->whatNext == Dis_StopHere); - } + /* End the block at this point. */ + jcc_01( dres, (AMD64Condcode)(opc - 0x70), + guest_RIP_bbstart+delta, d64 ); + vassert(dres->whatNext == Dis_StopHere); DIP("j%s-8 0x%llx %s\n", name_AMD64Condcode(opc - 0x70), (ULong)d64, comment); return delta; @@ -21422,14 +21373,8 @@ Long dis_ESC_NONE ( t2 = newTemp(Ity_I64); assign(t2, mkU64((Addr64)d64)); make_redzone_AbiHint(vbi, t1, t2/*nia*/, "call-d32"); - if (resteerOkFn( callback_opaque, (Addr64)d64) ) { - /* follow into the call target. */ - dres->whatNext = Dis_ResteerU; - dres->continueAt = d64; - } else { - jmp_lit(dres, Ijk_Call, d64); - vassert(dres->whatNext == Dis_StopHere); - } + jmp_lit(dres, Ijk_Call, d64); + vassert(dres->whatNext == Dis_StopHere); DIP("call 0x%llx\n", (ULong)d64); return delta; @@ -21440,13 +21385,8 @@ Long dis_ESC_NONE ( if (haveF2(pfx)) DIP("bnd ; "); /* MPX bnd prefix. */ d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta); delta += sz; - if (resteerOkFn(callback_opaque, (Addr64)d64)) { - dres->whatNext = Dis_ResteerU; - dres->continueAt = d64; - } else { - jmp_lit(dres, Ijk_Boring, d64); - vassert(dres->whatNext == Dis_StopHere); - } + jmp_lit(dres, Ijk_Boring, d64); + vassert(dres->whatNext == Dis_StopHere); DIP("jmp 0x%llx\n", (ULong)d64); return delta; @@ -21457,13 +21397,8 @@ Long dis_ESC_NONE ( if (haveF2(pfx)) DIP("bnd ; "); /* MPX bnd prefix. */ d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta); delta++; - if (resteerOkFn(callback_opaque, (Addr64)d64)) { - dres->whatNext = Dis_ResteerU; - dres->continueAt = d64; - } else { - jmp_lit(dres, Ijk_Boring, d64); - vassert(dres->whatNext == Dis_StopHere); - } + jmp_lit(dres, Ijk_Boring, d64); + vassert(dres->whatNext == Dis_StopHere); DIP("jmp-8 0x%llx\n", (ULong)d64); return delta; @@ -21646,9 +21581,6 @@ static Long dis_ESC_0F ( /*MB_OUT*/DisResult* dres, /*MB_OUT*/Bool* expect_CAS, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const VexArchInfo* archinfo, const VexAbiInfo* vbi, Prefix pfx, Int sz, Long deltaIN @@ -21898,56 +21830,10 @@ Long dis_ESC_0F ( jmpDelta = getSDisp32(delta); d64 = (guest_RIP_bbstart+delta+4) + jmpDelta; delta += 4; - if (resteerCisOk - && vex_control.guest_chase_cond - && (Addr64)d64 != (Addr64)guest_RIP_bbstart - && jmpDelta < 0 - && resteerOkFn( callback_opaque, (Addr64)d64) ) { - /* Speculation: assume this backward branch is taken. So - we need to emit a side-exit to the insn following this - one, on the negation of the condition, and continue at - the branch target address (d64). If we wind up back at - the first instruction of the trace, just stop; it's - better to let the IR loop unroller handle that case. */ - stmt( IRStmt_Exit( - mk_amd64g_calculate_condition( - (AMD64Condcode)(1 ^ (opc - 0x80))), - Ijk_Boring, - IRConst_U64(guest_RIP_bbstart+delta), - OFFB_RIP - )); - dres->whatNext = Dis_ResteerC; - dres->continueAt = d64; - comment = "(assumed taken)"; - } - else - if (resteerCisOk - && vex_control.guest_chase_cond - && (Addr64)d64 != (Addr64)guest_RIP_bbstart - && jmpDelta >= 0 - && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) { - /* Speculation: assume this forward branch is not taken. - So we need to emit a side-exit to d64 (the dest) and - continue disassembling at the insn immediately - following this one. */ - stmt( IRStmt_Exit( - mk_amd64g_calculate_condition((AMD64Condcode) - (opc - 0x80)), - Ijk_Boring, - IRConst_U64(d64), - OFFB_RIP - )); - dres->whatNext = Dis_ResteerC; - dres->continueAt = guest_RIP_bbstart+delta; - comment = "(assumed not taken)"; - } - else { - /* Conservative default translation - end the block at - this point. */ - jcc_01( dres, (AMD64Condcode)(opc - 0x80), - guest_RIP_bbstart+delta, d64 ); - vassert(dres->whatNext == Dis_StopHere); - } + /* End the block at this point. */ + jcc_01( dres, (AMD64Condcode)(opc - 0x80), + guest_RIP_bbstart+delta, d64 ); + vassert(dres->whatNext == Dis_StopHere); DIP("j%s-32 0x%llx %s\n", name_AMD64Condcode(opc - 0x80), (ULong)d64, comment); return delta; @@ -22715,9 +22601,6 @@ __attribute__((noinline)) static Long dis_ESC_0F38 ( /*MB_OUT*/DisResult* dres, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const VexArchInfo* archinfo, const VexAbiInfo* vbi, Prefix pfx, Int sz, Long deltaIN @@ -22833,9 +22716,6 @@ __attribute__((noinline)) static Long dis_ESC_0F3A ( /*MB_OUT*/DisResult* dres, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const VexArchInfo* archinfo, const VexAbiInfo* vbi, Prefix pfx, Int sz, Long deltaIN @@ -24175,9 +24055,6 @@ static Long dis_ESC_0F__VEX ( /*MB_OUT*/DisResult* dres, /*OUT*/ Bool* uses_vvvv, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const VexArchInfo* archinfo, const VexAbiInfo* vbi, Prefix pfx, Int sz, Long deltaIN @@ -28146,9 +28023,6 @@ static Long dis_ESC_0F38__VEX ( /*MB_OUT*/DisResult* dres, /*OUT*/ Bool* uses_vvvv, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const VexArchInfo* archinfo, const VexAbiInfo* vbi, Prefix pfx, Int sz, Long deltaIN @@ -30573,9 +30447,6 @@ static Long dis_ESC_0F3A__VEX ( /*MB_OUT*/DisResult* dres, /*OUT*/ Bool* uses_vvvv, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const VexArchInfo* archinfo, const VexAbiInfo* vbi, Prefix pfx, Int sz, Long deltaIN @@ -32194,9 +32065,6 @@ Long dis_ESC_0F3A__VEX ( static DisResult disInstr_AMD64_WRK ( /*OUT*/Bool* expect_CAS, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, Long delta64, const VexArchInfo* archinfo, const VexAbiInfo* vbi, @@ -32229,7 +32097,6 @@ DisResult disInstr_AMD64_WRK ( /* Set result defaults. */ dres.whatNext = Dis_Continue; dres.len = 0; - dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; dres.hint = Dis_HintNone; *expect_CAS = False; @@ -32491,22 +32358,18 @@ DisResult disInstr_AMD64_WRK ( switch (esc) { case ESC_NONE: delta = dis_ESC_NONE( &dres, expect_CAS, - resteerOkFn, resteerCisOk, callback_opaque, archinfo, vbi, pfx, sz, delta ); break; case ESC_0F: delta = dis_ESC_0F ( &dres, expect_CAS, - resteerOkFn, resteerCisOk, callback_opaque, archinfo, vbi, pfx, sz, delta ); break; case ESC_0F38: delta = dis_ESC_0F38( &dres, - resteerOkFn, resteerCisOk, callback_opaque, archinfo, vbi, pfx, sz, delta ); break; case ESC_0F3A: delta = dis_ESC_0F3A( &dres, - resteerOkFn, resteerCisOk, callback_opaque, archinfo, vbi, pfx, sz, delta ); break; default: @@ -32521,20 +32384,14 @@ DisResult disInstr_AMD64_WRK ( switch (esc) { case ESC_0F: delta = dis_ESC_0F__VEX ( &dres, &uses_vvvv, - resteerOkFn, resteerCisOk, - callback_opaque, archinfo, vbi, pfx, sz, delta ); break; case ESC_0F38: delta = dis_ESC_0F38__VEX ( &dres, &uses_vvvv, - resteerOkFn, resteerCisOk, - callback_opaque, archinfo, vbi, pfx, sz, delta ); break; case ESC_0F3A: delta = dis_ESC_0F3A__VEX ( &dres, &uses_vvvv, - resteerOkFn, resteerCisOk, - callback_opaque, archinfo, vbi, pfx, sz, delta ); break; case ESC_NONE: @@ -32618,10 +32475,6 @@ DisResult disInstr_AMD64_WRK ( case Dis_Continue: stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_bbstart + delta) ) ); break; - case Dis_ResteerU: - case Dis_ResteerC: - stmt( IRStmt_Put( OFFB_RIP, mkU64(dres.continueAt) ) ); - break; case Dis_StopHere: break; default: @@ -32645,9 +32498,6 @@ DisResult disInstr_AMD64_WRK ( is located in host memory at &guest_code[delta]. */ DisResult disInstr_AMD64 ( IRSB* irsb_IN, - Bool (*resteerOkFn) ( void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_code_IN, Long delta, Addr guest_IP, @@ -32675,9 +32525,7 @@ DisResult disInstr_AMD64 ( IRSB* irsb_IN, x1 = irsb_IN->stmts_used; expect_CAS = False; - dres = disInstr_AMD64_WRK ( &expect_CAS, resteerOkFn, - resteerCisOk, - callback_opaque, + dres = disInstr_AMD64_WRK ( &expect_CAS, delta, archinfo, abiinfo, sigill_diag_IN ); x2 = irsb_IN->stmts_used; vassert(x2 >= x1); @@ -32708,9 +32556,7 @@ DisResult disInstr_AMD64 ( IRSB* irsb_IN, /* inconsistency detected. re-disassemble the instruction so as to generate a useful error message; then assert. */ vex_traceflags |= VEX_TRACE_FE; - dres = disInstr_AMD64_WRK ( &expect_CAS, resteerOkFn, - resteerCisOk, - callback_opaque, + dres = disInstr_AMD64_WRK ( &expect_CAS, delta, archinfo, abiinfo, sigill_diag_IN ); for (i = x1; i < x2; i++) { vex_printf("\t\t"); diff --git a/VEX/priv/guest_arm64_defs.h b/VEX/priv/guest_arm64_defs.h index 319d601..b2094d6 100644 --- a/VEX/priv/guest_arm64_defs.h +++ b/VEX/priv/guest_arm64_defs.h @@ -39,9 +39,6 @@ guest_generic_bb_to_IR.h. */ extern DisResult disInstr_ARM64 ( IRSB* irbb, - Bool (*resteerOkFn) ( void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_code, Long delta, Addr guest_IP, diff --git a/VEX/priv/guest_arm64_toIR.c b/VEX/priv/guest_arm64_toIR.c index fa5baf1..4e6c597 100644 --- a/VEX/priv/guest_arm64_toIR.c +++ b/VEX/priv/guest_arm64_toIR.c @@ -6742,7 +6742,6 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn, Long simm64 = (Long)sx_to_64(uimm64, 21); vassert(dres->whatNext == Dis_Continue); vassert(dres->len == 4); - vassert(dres->continueAt == 0); vassert(dres->jk_StopHere == Ijk_INVALID); stmt( IRStmt_Exit(unop(Iop_64to1, mk_arm64g_calculate_condition(cond)), Ijk_Boring, @@ -14442,9 +14441,6 @@ Bool dis_ARM64_simd_and_fp(/*MB_OUT*/DisResult* dres, UInt insn) static Bool disInstr_ARM64_WRK ( /*MB_OUT*/DisResult* dres, - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_instr, const VexArchInfo* archinfo, const VexAbiInfo* abiinfo @@ -14468,7 +14464,6 @@ Bool disInstr_ARM64_WRK ( /* Set result defaults. */ dres->whatNext = Dis_Continue; dres->len = 4; - dres->continueAt = 0; dres->jk_StopHere = Ijk_INVALID; dres->hint = Dis_HintNone; @@ -14604,7 +14599,6 @@ Bool disInstr_ARM64_WRK ( if (!ok) { vassert(dres->whatNext == Dis_Continue); vassert(dres->len == 4); - vassert(dres->continueAt == 0); vassert(dres->jk_StopHere == Ijk_INVALID); } @@ -14622,9 +14616,6 @@ Bool disInstr_ARM64_WRK ( is located in host memory at &guest_code[delta]. */ DisResult disInstr_ARM64 ( IRSB* irsb_IN, - Bool (*resteerOkFn) ( void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_code_IN, Long delta_IN, Addr guest_IP, @@ -14651,7 +14642,6 @@ DisResult disInstr_ARM64 ( IRSB* irsb_IN, /* Try to decode */ Bool ok = disInstr_ARM64_WRK( &dres, - resteerOkFn, resteerCisOk, callback_opaque, &guest_code_IN[delta_IN], archinfo, abiinfo ); if (ok) { @@ -14661,10 +14651,6 @@ DisResult disInstr_ARM64 ( IRSB* irsb_IN, case Dis_Continue: putPC( mkU64(dres.len + guest_PC_curr_instr) ); break; - case Dis_ResteerU: - case Dis_ResteerC: - putPC(mkU64(dres.continueAt)); - break; case Dis_StopHere: break; default: @@ -14699,7 +14685,6 @@ DisResult disInstr_ARM64 ( IRSB* irsb_IN, dres.len = 0; dres.whatNext = Dis_StopHere; dres.jk_StopHere = Ijk_NoDecode; - dres.continueAt = 0; } return dres; } diff --git a/VEX/priv/guest_arm_defs.h b/VEX/priv/guest_arm_defs.h index 58bbbd0..85521e7 100644 --- a/VEX/priv/guest_arm_defs.h +++ b/VEX/priv/guest_arm_defs.h @@ -41,9 +41,6 @@ geust_generic_ bb_to_IR.h. */ extern DisResult disInstr_ARM ( IRSB* irbb, - Bool (*resteerOkFn) ( void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_code, Long delta, Addr guest_IP, diff --git a/VEX/priv/guest_arm_toIR.c b/VEX/priv/guest_arm_toIR.c index 50c97e9..6027d47 100644 --- a/VEX/priv/guest_arm_toIR.c +++ b/VEX/priv/guest_arm_toIR.c @@ -16077,9 +16077,6 @@ static Bool decode_NV_instruction_ARMv7_and_below static DisResult disInstr_ARM_WRK ( - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_instr, const VexArchInfo* archinfo, const VexAbiInfo* abiinfo, @@ -16099,7 +16096,6 @@ DisResult disInstr_ARM_WRK ( /* Set result defaults. */ dres.whatNext = Dis_Continue; dres.len = 4; - dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; dres.hint = Dis_HintNone; @@ -17034,75 +17030,19 @@ DisResult disInstr_ARM_WRK ( condT, Ijk_Boring); } if (condT == IRTemp_INVALID) { - /* unconditional transfer to 'dst'. See if we can simply - continue tracing at the destination. */ - if (resteerOkFn( callback_opaque, dst )) { - /* yes */ - dres.whatNext = Dis_ResteerU; - dres.continueAt = dst; - } else { - /* no; terminate the SB at this point. */ - llPutIReg(15, mkU32(dst)); - dres.jk_StopHere = jk; - dres.whatNext = Dis_StopHere; - } + /* Unconditional transfer to 'dst'. Terminate the SB at this point. */ + llPutIReg(15, mkU32(dst)); + dres.jk_StopHere = jk; + dres.whatNext = Dis_StopHere; DIP("b%s 0x%x\n", link ? "l" : "", dst); } else { - /* conditional transfer to 'dst' */ - const HChar* comment = ""; - - /* First see if we can do some speculative chasing into one - arm or the other. Be conservative and only chase if - !link, that is, this is a normal conditional branch to a - known destination. */ - if (!link - && resteerCisOk - && vex_control.guest_chase_cond - && dst < guest_R15_curr_instr_notENC - && resteerOkFn( callback_opaque, dst) ) { - /* Speculation: assume this backward branch is taken. So - we need to emit a side-exit to the insn following this - one, on the negation of the condition, and continue at - the branch target address (dst). */ - stmt( IRStmt_Exit( unop(Iop_Not1, - unop(Iop_32to1, mkexpr(condT))), - Ijk_Boring, - IRConst_U32(guest_R15_curr_instr_notENC+4), - OFFB_R15T )); - dres.whatNext = Dis_ResteerC; - dres.continueAt = (Addr32)dst; - comment = "(assumed taken)"; - } - else - if (!link - && resteerCisOk - && vex_control.guest_chase_cond - && dst >= guest_R15_curr_instr_notENC - && resteerOkFn( callback_opaque, - guest_R15_curr_instr_notENC+4) ) { - /* Speculation: assume this forward branch is not taken. - So we need to emit a side-exit to dst (the dest) and - continue disassembling at the insn immediately - following this one. */ - stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)), - Ijk_Boring, - IRConst_U32(dst), - OFFB_R15T )); - dres.whatNext = Dis_ResteerC; - dres.continueAt = guest_R15_curr_instr_notENC+4; - comment = "(assumed not taken)"; - } - else { - /* Conservative default translation - end the block at - this point. */ - stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)), - jk, IRConst_U32(dst), OFFB_R15T )); - llPutIReg(15, mkU32(guest_R15_curr_instr_notENC + 4)); - dres.jk_StopHere = Ijk_Boring; - dres.whatNext = Dis_StopHere; - } - DIP("b%s%s 0x%x %s\n", link ? "l" : "", nCC(INSN_COND), - dst, comment); + /* Conditional transfer to 'dst'. Terminate the SB at this point. */ + stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)), + jk, IRConst_U32(dst), OFFB_R15T )); + llPutIReg(15, mkU32(guest_R15_curr_instr_notENC + 4)); + dres.jk_StopHere = Ijk_Boring; + dres.whatNext = Dis_StopHere; + DIP("b%s%s 0x%x\n", link ? "l" : "", nCC(INSN_COND), dst); } goto decode_success; } @@ -18896,7 +18836,6 @@ DisResult disInstr_ARM_WRK ( dres.len = 0; dres.whatNext = Dis_StopHere; dres.jk_StopHere = Ijk_NoDecode; - dres.continueAt = 0; return dres; decode_success: @@ -18953,10 +18892,6 @@ DisResult disInstr_ARM_WRK ( case Dis_Continue: llPutIReg(15, mkU32(dres.len + guest_R15_curr_instr_notENC)); break; - case Dis_ResteerU: - case Dis_ResteerC: - llPutIReg(15, mkU32(dres.continueAt)); - break; case Dis_StopHere: break; default: @@ -18989,9 +18924,6 @@ static const UChar it_length_table[256]; /* fwds */ static DisResult disInstr_THUMB_WRK ( - Bool (*resteerOkFn) ( /*opaque*/void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_instr, const VexArchInfo* archinfo, const VexAbiInfo* abiinfo, @@ -19016,7 +18948,6 @@ DisResult disInstr_THUMB_WRK ( /* Set result defaults. */ dres.whatNext = Dis_Continue; dres.len = 2; - dres.continueAt = 0; dres.jk_StopHere = Ijk_INVALID; dres.hint = Dis_HintNone; @@ -20761,7 +20692,6 @@ DisResult disInstr_THUMB_WRK ( /* Change result defaults to suit 32-bit insns. */ vassert(dres.whatNext == Dis_Continue); vassert(dres.len == 2); - vassert(dres.continueAt == 0); dres.len = 4; /* ---------------- BL/BLX simm26 ---------------- */ @@ -23531,7 +23461,6 @@ DisResult disInstr_THUMB_WRK ( dres.len = 0; dres.whatNext = Dis_StopHere; dres.jk_StopHere = Ijk_NoDecode; - dres.continueAt = 0; return dres; decode_success: @@ -23541,10 +23470,6 @@ DisResult disInstr_THUMB_WRK ( case Dis_Continue: llPutIReg(15, mkU32(dres.len + (guest_R15_curr_instr_notENC | 1))); break; - case Dis_ResteerU: - case Dis_ResteerC: - llPutIReg(15, mkU32(dres.continueAt)); - break; case Dis_StopHere: break; default: @@ -23650,9 +23575,6 @@ static const UChar it_length_table[256] is located in host memory at &guest_code[delta]. */ DisResult disInstr_ARM ( IRSB* irsb_IN, - Bool (*resteerOkFn) ( void*, Addr ), - Bool resteerCisOk, - void* callback_opaque, const UChar* guest_code_IN, Long delta_ENCODED, Addr guest_IP_ENCODED, @@ -23679,14 +23601,10 @@ DisResult disInstr_ARM ( IRSB* irsb_IN, } if (isThumb) { - dres = disInstr_THUMB_WRK ( resteerOkFn, - resteerCisOk, callback_opaque, - &guest_code_IN[delta_ENCODED - 1], + dres = disInstr_THUMB_WRK ( &guest_code_IN[delta_ENCODED - 1], archinfo, abiinfo, sigill_diag_IN ); } else { - dres = disInstr_ARM_WRK ( resteerOkFn, - resteerCisOk, callback_opaque, - &guest_code_IN[delta_ENCODED], + dres = disInstr_ARM_WRK ( &guest_code_IN[delta_ENCODED], archinfo, abiinfo, sigill_diag_IN ); } diff --git a/VEX/priv/guest_generic_bb_to_IR.c b/VEX/priv/guest_generic_bb_to_IR.c index 9596787..4cb813f 100644 --- a/VEX/priv/guest_generic_bb_to_IR.c +++ b/VEX/priv/guest_generic_bb_to_IR.c @@ -37,290 +37,738 @@ #include "main_util.h" #include "main_globals.h" #include "guest_generic_bb_to_IR.h" +#include "ir_opt.h" +/*--------------------------------------------------------------*/ +/*--- Forwards for fns called by self-checking translations ---*/ +/*--------------------------------------------------------------*/ + /* Forwards .. */ -VEX_REGPARM(2) -static UInt genericg_compute_checksum_4al ( HWord first_w32, HWord n_w32s ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_1 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_2 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_3 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_4 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_5 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_6 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_7 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_8 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_9 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_10 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_11 ( HWord first_w32 ); -VEX_REGPARM(1) -static UInt genericg_compute_checksum_4al_12 ( HWord first_w32 ); +VEX_REGPARM(2) static UInt genericg_compute_checksum_4al ( HWord first_w32, + HWord n_w32s ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_1 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_2 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_3 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_4 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_5 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_6 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_7 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_8 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_9 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_10 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_11 ( HWord first_w32 ); +VEX_REGPARM(1) static UInt genericg_compute_checksum_4al_12 ( HWord first_w32 ); + +VEX_REGPARM(2) static ULong genericg_compute_checksum_8al ( HWord first_w64, + HWord n_w64s ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_1 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_2 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_3 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_4 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_5 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_6 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_7 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_8 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_9 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_10 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_11 ( HWord first_w64 ); +VEX_REGPARM(1) static ULong genericg_compute_checksum_8al_12 ( HWord first_w64 ); + + +/*--------------------------------------------------------------*/ +/*--- Creation of self-check IR ---*/ +/*--------------------------------------------------------------*/ + +static void create_self_checks_as_needed( + /*MOD*/ IRSB* irsb, + /*OUT*/ UInt* n_sc_extents, + /*MOD*/ VexRegisterUpdates* pxControl, + /*MOD*/ void* callback_opaque, + /*IN*/ UInt (*needs_self_check) + (void*, /*MB_MOD*/VexRegisterUpdates*, + const VexGuestExtents*), + const VexGuestExtents* vge, + const VexAbiInfo* abiinfo_both, + const IRType guest_word_type, + const Int selfcheck_idx, + /*IN*/ Int offB_GUEST_CMSTART, + /*IN*/ Int offB_GUEST_CMLEN, + /*IN*/ Int offB_GUEST_IP, + const Addr guest_IP_sbstart + ) +{ + /* The scheme is to compute a rather crude checksum of the code + we're making a translation of, and add to the IR a call to a + helper routine which recomputes the checksum every time the + translation is run, and requests a retranslation if it doesn't + match. This is obviously very expensive and considerable + efforts are made to speed it up: -VEX_REGPARM(2) -static ULong genericg_compute_checksum_8al ( HWord first_w64, HWord n_w64s ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_1 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_2 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_3 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_4 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_5 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_6 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_7 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_8 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_9 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_10 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_11 ( HWord first_w64 ); -VEX_REGPARM(1) -static ULong genericg_compute_checksum_8al_12 ( HWord first_w64 ); + * the checksum is computed from all the naturally aligned + host-sized words that overlap the translated code. That means + it could depend on up to 7 bytes before and 7 bytes after + which aren't part of the translated area, and so if those + change then we'll unnecessarily have to discard and + retranslate. This seems like a pretty remote possibility and + it seems as if the benefit of not having to deal with the ends + of the range at byte precision far outweigh any possible extra + translations needed. -/* Small helpers */ -static Bool const_False ( void* callback_opaque, Addr a ) { - return False; -} + * there's a generic routine and 12 specialised cases, which + handle the cases of 1 through 12-word lengths respectively. + They seem to cover about 90% of the cases that occur in + practice. -/* Disassemble a complete basic block, starting at guest_IP_start, - returning a new IRSB. The disassembler may chase across basic - block boundaries if it wishes and if chase_into_ok allows it. - The precise guest address ranges from which code has been taken - are written into vge. guest_IP_bbstart is taken to be the IP in - the guest's address space corresponding to the instruction at - &guest_code[0]. + We ask the caller, via needs_self_check, which of the 3 vge + extents needs a check, and only generate check code for those + that do. + */ + { + Addr base2check; + UInt len2check; + HWord expectedhW; + IRTemp tistart_tmp, tilen_tmp; + HWord VEX_REGPARM(2) (*fn_generic)(HWord, HWord); + HWord VEX_REGPARM(1) (*fn_spec)(HWord); + const HChar* nm_generic; + const HChar* nm_spec; + HWord fn_generic_entry = 0; + HWord fn_spec_entry = 0; + UInt host_word_szB = sizeof(HWord); + IRType host_word_type = Ity_INVALID; - dis_instr_fn is the arch-specific fn to disassemble on function; it - is this that does the real work. + UInt extents_needing_check + = needs_self_check(callback_opaque, pxControl, vge); - needs_self_check is a callback used to ask the caller which of the - extents, if any, a self check is required for. The returned value - is a bitmask with a 1 in position i indicating that the i'th extent - needs a check. Since there can be at most 3 extents, the returned - values must be between 0 and 7. + if (host_word_szB == 4) host_word_type = Ity_I32; + if (host_word_szB == 8) host_word_type = Ity_I64; + vassert(host_word_type != Ity_INVALID); - The number of extents which did get a self check (0 to 3) is put in - n_sc_extents. The caller already knows this because it told us - which extents to add checks for, via the needs_self_check callback, - but we ship the number back out here for the caller's convenience. + vassert(vge->n_used >= 1 && vge->n_used <= 3); - preamble_function is a callback which allows the caller to add - its own IR preamble (following the self-check, if any). May be - NULL. If non-NULL, the IRSB under construction is handed to - this function, which presumably adds IR statements to it. The - callback may optionally complete the block and direct bb_to_IR - not to disassemble any instructions into it; this is indicated - by the callback returning True. + /* Caller shouldn't claim that nonexistent extents need a + check. */ + vassert((extents_needing_check >> vge->n_used) == 0); - offB_CMADDR and offB_CMLEN are the offsets of guest_CMADDR and - guest_CMLEN. Since this routine has to work for any guest state, - without knowing what it is, those offsets have to passed in. + /* Guest addresses as IRConsts. Used in self-checks to specify the + restart-after-discard point. */ + IRConst* guest_IP_sbstart_IRConst + = guest_word_type==Ity_I32 + ? IRConst_U32(toUInt(guest_IP_sbstart)) + : IRConst_U64(guest_IP_sbstart); - callback_opaque is a caller-supplied pointer to data which the - callbacks may want to see. Vex has no idea what it is. - (In fact it's a VgInstrumentClosure.) -*/ + const Int n_extent_slots = sizeof(vge->base) / sizeof(vge->base[0]); + vassert(n_extent_slots == 3); -/* Regarding IP updating. dis_instr_fn (that does the guest specific - work of disassembling an individual instruction) must finish the - resulting IR with "PUT(guest_IP) = ". Hence in all cases it must - state the next instruction address. + vassert(selfcheck_idx + (n_extent_slots - 1) * 5 + 4 < irsb->stmts_used); - If the block is to be ended at that point, then this routine - (bb_to_IR) will set up the next/jumpkind/offsIP fields so as to - make a transfer (of the right kind) to "GET(guest_IP)". Hence if - dis_instr_fn generates incorrect IP updates we will see it - immediately (due to jumping to the wrong next guest address). + for (Int i = 0; i < vge->n_used; i++) { + /* Do we need to generate a check for this extent? */ + if ((extents_needing_check & (1 << i)) == 0) + continue; - However it is also necessary to set this up so it can be optimised - nicely. The IRSB exit is defined to update the guest IP, so that - chaining works -- since the chain_me stubs expect the chain-to - address to be in the guest state. Hence what the IRSB next fields - will contain initially is (implicitly) + /* Tell the caller */ + (*n_sc_extents)++; - PUT(guest_IP) [implicitly] = GET(guest_IP) [explicit expr on ::next] + /* the extent we're generating a check for */ + base2check = vge->base[i]; + len2check = vge->len[i]; + + /* stay sane */ + vassert(len2check >= 0 && len2check < 2000/*arbitrary*/); + + /* Skip the check if the translation involved zero bytes */ + if (len2check == 0) + continue; + + HWord first_hW = ((HWord)base2check) + & ~(HWord)(host_word_szB-1); + HWord last_hW = (((HWord)base2check) + len2check - 1) + & ~(HWord)(host_word_szB-1); + vassert(first_hW <= last_hW); + HWord hW_diff = last_hW - first_hW; + vassert(0 == (hW_diff & (host_word_szB-1))); + HWord hWs_to_check = (hW_diff + host_word_szB) / host_word_szB; + vassert(hWs_to_check > 0 + && hWs_to_check < 2004/*arbitrary*/ / host_word_szB); + + /* vex_printf("%lx %lx %ld\n", first_hW, last_hW, hWs_to_check); */ + + if (host_word_szB == 8) { + fn_generic = (VEX_REGPARM(2) HWord(*)(HWord, HWord)) + genericg_compute_checksum_8al; + nm_generic = "genericg_compute_checksum_8al"; + } else { + fn_generic = (VEX_REGPARM(2) HWord(*)(HWord, HWord)) + genericg_compute_checksum_4al; + nm_generic = "genericg_compute_checksum_4al"; + } + + fn_spec = NULL; + nm_spec = NULL; + + if (host_word_szB == 8) { + const HChar* nm = NULL; + ULong VEX_REGPARM(1) (*fn)(HWord) = NULL; + switch (hWs_to_check) { + case 1: fn = genericg_compute_checksum_8al_1; + nm = "genericg_compute_checksum_8al_1"; break; + case 2: fn = genericg_compute_checksum_8al_2; + nm = "genericg_compute_checksum_8al_2"; break; + case 3: fn = genericg_compute_checksum_8al_3; + nm = "genericg_compute_checksum_8al_3"; break; + case 4: fn = genericg_compute_checksum_8al_4; + nm = "genericg_compute_checksum_8al_4"; break; + case 5: fn = genericg_compute_checksum_8al_5; + nm = "genericg_compute_checksum_8al_5"; break; + case 6: fn = genericg_compute_checksum_8al_6; + nm = "genericg_compute_checksum_8al_6"; break; + case 7: fn = genericg_compute_checksum_8al_7; + nm = "genericg_compute_checksum_8al_7"; break; + case 8: fn = genericg_compute_checksum_8al_8; + nm = "genericg_compute_checksum_8al_8"; break; + case 9: fn = genericg_compute_checksum_8al_9; + nm = "genericg_compute_checksum_8al_9"; break; + case 10: fn = genericg_compute_checksum_8al_10; + nm = "genericg_compute_checksum_8al_10"; break; + case 11: fn = genericg_compute_checksum_8al_11; + nm = "genericg_compute_checksum_8al_11"; break; + case 12: fn = genericg_compute_checksum_8al_12; + nm = "genericg_compute_checksum_8al_12"; break; + default: break; + } + fn_spec = (VEX_REGPARM(1) HWord(*)(HWord)) fn; + nm_spec = nm; + } else { + const HChar* nm = NULL; + UInt VEX_REGPARM(1) (*fn)(HWord) = NULL; + switch (hWs_to_check) { + case 1: fn = genericg_compute_checksum_4al_1; + nm = "genericg_compute_checksum_4al_1"; break; + case 2: fn = genericg_compute_checksum_4al_2; + nm = "genericg_compute_checksum_4al_2"; break; + case 3: fn = genericg_compute_checksum_4al_3; + nm = "genericg_compute_checksum_4al_3"; break; + case 4: fn = genericg_compute_checksum_4al_4; + nm = "genericg_compute_checksum_4al_4"; break; + case 5: fn = genericg_compute_checksum_4al_5; + nm = "genericg_compute_checksum_4al_5"; break; + case 6: fn = genericg_compute_checksum_4al_6; + nm = "genericg_compute_checksum_4al_6"; break; + case 7: fn = genericg_compute_checksum_4al_7; + nm = "genericg_compute_checksum_4al_7"; break; + case 8: fn = genericg_compute_checksum_4al_8; + nm = "genericg_compute_checksum_4al_8"; break; + case 9: fn = genericg_compute_checksum_4al_9; + nm = "genericg_compute_checksum_4al_9"; break; + case 10: fn = genericg_compute_checksum_4al_10; + nm = "genericg_compute_checksum_4al_10"; break; + case 11: fn = genericg_compute_checksum_4al_11; + nm = "genericg_compute_checksum_4al_11"; break; + case 12: fn = genericg_compute_checksum_4al_12; + nm = "genericg_compute_checksum_4al_12"; break; + default: break; + } + fn_spec = (VEX_REGPARM(1) HWord(*)(HWord))fn; + nm_spec = nm; + } + + expectedhW = fn_generic( first_hW, hWs_to_check ); + /* If we got a specialised version, check it produces the same + result as the generic version! */ + if (fn_spec) { + vassert(nm_spec); + vassert(expectedhW == fn_spec( first_hW )); + } else { + vassert(!nm_spec); + } + + /* Set CMSTART and CMLEN. These will describe to the despatcher + the area of guest code to invalidate should we exit with a + self-check failure. */ + tistart_tmp = newIRTemp(irsb->tyenv, guest_word_type); + tilen_tmp = newIRTemp(irsb->tyenv, guest_word_type); + + IRConst* base2check_IRConst + = guest_word_type==Ity_I32 ? IRConst_U32(toUInt(base2check)) + : IRConst_U64(base2check); + IRConst* len2check_IRConst + = guest_word_type==Ity_I32 ? IRConst_U32(len2check) + : IRConst_U64(len2check); + + IRStmt** stmt0 = &irsb->stmts[selfcheck_idx + i * 5 + 0]; + IRStmt** stmt1 = &irsb->stmts[selfcheck_idx + i * 5 + 1]; + IRStmt** stmt2 = &irsb->stmts[selfcheck_idx + i * 5 + 2]; + IRStmt** stmt3 = &irsb->stmts[selfcheck_idx + i * 5 + 3]; + IRStmt** stmt4 = &irsb->stmts[selfcheck_idx + i * 5 + 4]; + vassert((*stmt0)->tag == Ist_NoOp); + vassert((*stmt1)->tag == Ist_NoOp); + vassert((*stmt2)->tag == Ist_NoOp); + vassert((*stmt3)->tag == Ist_NoOp); + vassert((*stmt4)->tag == Ist_NoOp); + + *stmt0 = IRStmt_WrTmp(tistart_tmp, IRExpr_Const(base2check_IRConst) ); + *stmt1 = IRStmt_WrTmp(tilen_tmp, IRExpr_Const(len2check_IRConst) ); + *stmt2 = IRStmt_Put( offB_GUEST_CMSTART, IRExpr_RdTmp(tistart_tmp) ); + *stmt3 = IRStmt_Put( offB_GUEST_CMLEN, IRExpr_RdTmp(tilen_tmp) ); + + /* Generate the entry point descriptors */ + if (abiinfo_both->host_ppc_calls_use_fndescrs) { + HWord* descr = (HWord*)fn_generic; + fn_generic_entry = descr[0]; + if (fn_spec) { + descr = (HWord*)fn_spec; + fn_spec_entry = descr[0]; + } else { + fn_spec_entry = (HWord)NULL; + } + } else { + fn_generic_entry = (HWord)fn_generic; + if (fn_spec) { + fn_spec_entry = (HWord)fn_spec; + } else { + fn_spec_entry = (HWord)NULL; + } + } + + IRExpr* callexpr = NULL; + if (fn_spec) { + callexpr = mkIRExprCCall( + host_word_type, 1/*regparms*/, + nm_spec, (void*)fn_spec_entry, + mkIRExprVec_1( + mkIRExpr_HWord( (HWord)first_hW ) + ) + ); + } else { + callexpr = mkIRExprCCall( + host_word_type, 2/*regparms*/, + nm_generic, (void*)fn_generic_entry, + mkIRExprVec_2( + mkIRExpr_HWord( (HWord)first_hW ), + mkIRExpr_HWord( (HWord)hWs_to_check ) + ) + ); + } + + *stmt4 + = IRStmt_Exit( + IRExpr_Binop( + host_word_type==Ity_I64 ? Iop_CmpNE64 : Iop_CmpNE32, + callexpr, + host_word_type==Ity_I64 + ? IRExpr_Const(IRConst_U64(expectedhW)) + : IRExpr_Const(IRConst_U32(expectedhW)) + ), + Ijk_InvalICache, + /* Where we must restart if there's a failure: at the + first extent, regardless of which extent the + failure actually happened in. */ + guest_IP_sbstart_IRConst, + offB_GUEST_IP + ); + } /* for (i = 0; i < vge->n_used; i++) */ + + for (Int i = vge->n_used; + i < sizeof(vge->base) / sizeof(vge->base[0]); i++) { + IRStmt* stmt0 = irsb->stmts[selfcheck_idx + i * 5 + 0]; + IRStmt* stmt1 = irsb->stmts[selfcheck_idx + i * 5 + 1]; + IRStmt* stmt2 = irsb->stmts[selfcheck_idx + i * 5 + 2]; + IRStmt* stmt3 = irsb->stmts[selfcheck_idx + i * 5 + 3]; + IRStmt* stmt4 = irsb->stmts[selfcheck_idx + i * 5 + 4]; + vassert(stmt0->tag == Ist_NoOp); + vassert(stmt1->tag == Ist_NoOp); + vassert(stmt2->tag == Ist_NoOp); + vassert(stmt3->tag == Ist_NoOp); + vassert(stmt4->tag == Ist_NoOp); + } + } +} + + +/*--------------------------------------------------------------*/ +/*--- To do with speculation of IRStmts ---*/ +/*--------------------------------------------------------------*/ + +static Bool expr_is_speculatable ( const IRExpr* e ) +{ + switch (e->tag) { + case Iex_Load: + return False; + case Iex_Unop: // FIXME BOGUS, since it might trap + case Iex_Binop: // FIXME ditto + case Iex_ITE: // this is OK + return True; + case Iex_CCall: + return True; // This is probably correct + case Iex_Get: + return True; + default: + vex_printf("\n"); ppIRExpr(e); + vpanic("expr_is_speculatable: unhandled expr"); + } +} + +static Bool stmt_is_speculatable ( const IRStmt* st ) +{ + switch (st->tag) { + case Ist_IMark: + case Ist_Put: + return True; + case Ist_Store: // definitely not + case Ist_CAS: // definitely not + case Ist_Exit: // We could in fact spec this, if required + return False; + case Ist_WrTmp: + return expr_is_speculatable(st->Ist.WrTmp.data); + default: + vex_printf("\n"); ppIRStmt(st); + vpanic("stmt_is_speculatable: unhandled stmt"); + } +} + +static Bool block_is_speculatable ( const IRSB* bb ) +{ + Int i = bb->stmts_used; + vassert(i >= 2); // Must have at least: IMark, final Exit + i--; + vassert(bb->stmts[i]->tag == Ist_Exit); + i--; + for (; i >= 0; i--) { + if (!stmt_is_speculatable(bb->stmts[i])) + return False; + } + return True; +} + +static void speculate_stmt_to_end_of ( /*MOD*/IRSB* bb, + /*IN*/ IRStmt* st, IRTemp guard ) +{ + // We assume all stmts we're presented with here have previously been OK'd by + // stmt_is_speculatable above. + switch (st->tag) { + case Ist_IMark: + case Ist_WrTmp: // FIXME is this ok? + addStmtToIRSB(bb, st); + break; + case Ist_Put: { + // Put(offs, e) ==> ... [truncated message content] |
|
From: Julian S. <se...@so...> - 2019-10-21 09:28:12
|
The branch 'grail' was created pointing to: 7204d08... Initial implementation of C-source-level &&-idiom recovery |