yaxpeax_core/analyses/value_range/
mod.rs

1use yaxpeax_arch::Arch;
2use arch::DecodeFrom;
3use memory::MemoryRange;
4use analyses::control_flow::ControlFlowGraph;
5use analyses::static_single_assignment::{DefSource, SSA, SSAValues};
6
7pub trait ConditionalBoundInference<A: Arch + SSAValues, U> {
8    /// Finds the instruction responsible for the condition that `conditional_instr` branches on.
9    /// For some architectures, this may be a ways earlier in the program. For others, this may
10    /// simply be "the conditional instruction".
11    fn conditional_source_for(conditional_instr: &A::Instruction, conditional_addr: A::Address, dfg: &SSA<A>) -> Option<(A::Address, DefSource<A::Address>)>;
12
13    /// This yadda yadda's the good stuff. Given a conditional instruction, and instruction that
14    /// decides its conditionality (these may be the same!) apply bounds to the program for
15    /// control-depndent edges.
16    fn infer_conditional_bounds(
17        curr_block: A::Address,
18        test_instr: &A::Instruction,
19        test_addr: A::Address,
20        conditional_instr: &A::Instruction,
21        conditional_addr: A::Address,
22        cfg: &ControlFlowGraph<A::Address>,
23        dfg: &SSA<A>,
24        aux_data: &mut U) -> bool;
25
26    /// Is the instruction in question one that an implementor might want to look at?
27    fn inferrable_conditional(conditional_instr: &A::Instruction) -> bool;
28
29    fn add_conditional_bounds<M: MemoryRange<A>>(block_start: A::Address, conditional: A::Address, conditional_instr: &A::Instruction, cfg: &ControlFlowGraph<A::Address>, dfg: &SSA<A>, data: &M, aux_data: &mut U) -> bool
30        where A: DecodeFrom<M>,
31    {
32        match Self::conditional_source_for(conditional_instr, conditional, dfg) {
33            Some((src_addr, DefSource::Instruction)) => {
34                if let Some(range) = data.range_from(src_addr) {
35                    if let Ok(test_instr) = A::decode_from(&range) {
36                        // and now that we have the instruction...
37                        Self::infer_conditional_bounds(block_start, &test_instr, src_addr, conditional_instr, conditional, cfg, dfg, aux_data)
38                    } else {
39                        // flags are defined at an instruction that does not decode or is not in
40                        // the program's space?
41                        unreachable!();
42                    }
43                } else {
44                    // flags are defined at an address that's invalid?
45                    unreachable!();
46                }
47            }
48            Some((_, DefSource::External)) |
49            Some((_, DefSource::Phi)) |
50            Some((_, DefSource::Modifier(_))) |
51            Some((_, DefSource::Between(_))) => {
52                // Flags are defined by some non-instruction source. We can't do anything useful there,
53                // because we would be bounding flags specifically - if a branch is taken or not we may
54                // trivially know the state of flags upon reaching the branch.
55                //
56                // A conditional source being from not the conditional instruction will have some form
57                // like:
58                // * a specific modifier asserting the condition to some state (or, unknown)
59                //   - here we will either agree or disagree. disagreement is interesting
60                //     because that implies the condition will never be true - that should
61                //     be eliminated as a possibility by conditional propagation before this
62                //     is performed
63                // * a phi node between condition variables
64                //   - this is interesting, but as-yet unsupported. a bound introduced by a branch
65                //     would be reflected on all phi'd nodes, and would be not-incorrectly written
66                //     as a bound on the result of the phi operation.
67                // * a between-block modifier
68                //   - this is very similar to the modifier case above. either we agree with this
69                //     and introduce no interesting information, or we disagree and are looking at
70                //     a dead branch.
71                false
72            }
73            None => {
74                // Nothing we can do for flags that come from places we don't know
75                // (really, this probably means the flags are defined by an input to the function)
76                false
77            }
78        }
79    }
80}
81
82/// A struct that existes purely to have a non-effecting implementation of conditional bound
83/// inference.
84#[allow(dead_code)]
85struct NoConditionalInference { }
86
87impl <A: Arch + SSAValues, U> ConditionalBoundInference<A, U> for NoConditionalInference {
88    fn conditional_source_for(_conditional_instr: &A::Instruction, _conditional_addr: A::Address, _dfg: &SSA<A>) -> Option<(A::Address, DefSource<A::Address>)> {
89        None
90    }
91
92    fn infer_conditional_bounds(_curr_block: A::Address, _test_instr: &A::Instruction, _test_addr: A::Address, _conditional_instr: &A::Instruction, _conditional_addr: A::Address, _cfg: &ControlFlowGraph<A::Address>, _dfg: &SSA<A>, _aux_data: &mut U) -> bool {
93        false
94    }
95
96    fn inferrable_conditional(_conditional_instr: &A::Instruction) -> bool {
97        false
98    }
99}