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}