angr 9.2.131__py3-none-win_amd64.whl → 9.2.133__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +128 -128
- angr/analyses/__init__.py +38 -38
- angr/analyses/analysis.py +6 -2
- angr/analyses/backward_slice.py +3 -4
- angr/analyses/binary_optimizer.py +5 -12
- angr/analyses/bindiff.py +3 -6
- angr/analyses/calling_convention.py +3 -4
- angr/analyses/cfg/__init__.py +3 -3
- angr/analyses/cfg/cfg_base.py +1 -1
- angr/analyses/cfg/cfg_emulated.py +5 -5
- angr/analyses/cfg/cfg_fast.py +19 -17
- angr/analyses/cfg/indirect_jump_resolvers/__init__.py +5 -5
- angr/analyses/cfg/indirect_jump_resolvers/amd64_elf_got.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +148 -101
- angr/analyses/cfg/indirect_jump_resolvers/x86_elf_pic_plt.py +1 -1
- angr/analyses/data_dep/__init__.py +4 -4
- angr/analyses/datagraph_meta.py +1 -1
- angr/analyses/ddg.py +16 -17
- angr/analyses/decompiler/__init__.py +12 -12
- angr/analyses/decompiler/ail_simplifier.py +24 -12
- angr/analyses/decompiler/block_similarity.py +2 -4
- angr/analyses/decompiler/block_simplifier.py +10 -21
- angr/analyses/decompiler/callsite_maker.py +1 -1
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +1 -1
- angr/analyses/decompiler/clinic.py +122 -41
- angr/analyses/decompiler/condition_processor.py +57 -39
- angr/analyses/decompiler/counters/__init__.py +3 -3
- angr/analyses/decompiler/decompilation_cache.py +7 -7
- angr/analyses/decompiler/dephication/__init__.py +1 -1
- angr/analyses/decompiler/dephication/graph_rewriting.py +1 -1
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +11 -3
- angr/analyses/decompiler/dephication/rewriting_engine.py +169 -45
- angr/analyses/decompiler/dephication/seqnode_dephication.py +5 -4
- angr/analyses/decompiler/expression_narrower.py +1 -1
- angr/analyses/decompiler/graph_region.py +8 -8
- angr/analyses/decompiler/optimization_passes/__init__.py +20 -20
- angr/analyses/decompiler/optimization_passes/const_derefs.py +1 -0
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +1 -2
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +41 -16
- angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_reverter.py +8 -7
- angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py +1 -3
- angr/analyses/decompiler/optimization_passes/engine_base.py +262 -84
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +175 -39
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +2 -5
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +5 -5
- angr/analyses/decompiler/optimization_passes/mod_simplifier.py +12 -3
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +42 -19
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +9 -5
- angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/base.py +6 -6
- angr/analyses/decompiler/peephole_optimizations/remove_noop_conversions.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_bit_extractions.py +1 -1
- angr/analyses/decompiler/presets/__init__.py +1 -1
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +3 -3
- angr/analyses/decompiler/region_simplifiers/switch_cluster_simplifier.py +8 -12
- angr/analyses/decompiler/ssailification/rewriting.py +1 -2
- angr/analyses/decompiler/ssailification/rewriting_engine.py +139 -56
- angr/analyses/decompiler/ssailification/ssailification.py +2 -1
- angr/analyses/decompiler/ssailification/traversal.py +4 -6
- angr/analyses/decompiler/ssailification/traversal_engine.py +125 -42
- angr/analyses/decompiler/structured_codegen/__init__.py +5 -5
- angr/analyses/decompiler/structured_codegen/base.py +3 -3
- angr/analyses/decompiler/structured_codegen/c.py +39 -40
- angr/analyses/decompiler/structuring/__init__.py +3 -3
- angr/analyses/decompiler/structuring/phoenix.py +45 -29
- angr/analyses/decompiler/structuring/structurer_base.py +2 -2
- angr/analyses/decompiler/structuring/structurer_nodes.py +23 -14
- angr/analyses/deobfuscator/__init__.py +3 -3
- angr/analyses/deobfuscator/irsb_reg_collector.py +29 -60
- angr/analyses/deobfuscator/string_obf_finder.py +2 -2
- angr/analyses/deobfuscator/string_obf_opt_passes.py +1 -1
- angr/analyses/disassembly.py +4 -4
- angr/analyses/forward_analysis/__init__.py +1 -1
- angr/analyses/forward_analysis/visitors/graph.py +6 -6
- angr/analyses/init_finder.py +47 -22
- angr/analyses/loop_analysis.py +1 -1
- angr/analyses/loopfinder.py +1 -1
- angr/analyses/propagator/engine_base.py +21 -14
- angr/analyses/propagator/engine_vex.py +149 -179
- angr/analyses/propagator/outdated_definition_walker.py +12 -6
- angr/analyses/propagator/propagator.py +10 -28
- angr/analyses/propagator/top_checker_mixin.py +211 -5
- angr/analyses/propagator/vex_vars.py +4 -4
- angr/analyses/reaching_definitions/__init__.py +9 -9
- angr/analyses/reaching_definitions/call_trace.py +2 -2
- angr/analyses/reaching_definitions/dep_graph.py +1 -1
- angr/analyses/reaching_definitions/engine_ail.py +304 -329
- angr/analyses/reaching_definitions/engine_vex.py +243 -229
- angr/analyses/reaching_definitions/function_handler.py +3 -3
- angr/analyses/reaching_definitions/function_handler_library/__init__.py +1 -1
- angr/analyses/reaching_definitions/rd_state.py +47 -42
- angr/analyses/reassembler.py +26 -31
- angr/analyses/s_liveness.py +8 -0
- angr/analyses/s_propagator.py +18 -3
- angr/analyses/s_reaching_definitions/s_rda_view.py +2 -5
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +9 -5
- angr/analyses/stack_pointer_tracker.py +4 -4
- angr/analyses/typehoon/simple_solver.py +14 -14
- angr/analyses/typehoon/translator.py +10 -2
- angr/analyses/typehoon/typeconsts.py +11 -3
- angr/analyses/typehoon/typevars.py +26 -26
- angr/analyses/unpacker/__init__.py +1 -1
- angr/analyses/variable_recovery/engine_ail.py +299 -259
- angr/analyses/variable_recovery/engine_base.py +138 -121
- angr/analyses/variable_recovery/engine_vex.py +175 -185
- angr/analyses/variable_recovery/irsb_scanner.py +49 -38
- angr/analyses/variable_recovery/variable_recovery.py +28 -5
- angr/analyses/variable_recovery/variable_recovery_base.py +33 -34
- angr/analyses/variable_recovery/variable_recovery_fast.py +4 -8
- angr/analyses/veritesting.py +2 -2
- angr/analyses/vfg.py +5 -5
- angr/analyses/xrefs.py +46 -19
- angr/angrdb/serializers/__init__.py +1 -1
- angr/annocfg.py +20 -15
- angr/blade.py +2 -2
- angr/block.py +20 -25
- angr/calling_conventions.py +12 -14
- angr/code_location.py +6 -10
- angr/codenode.py +3 -3
- angr/engines/__init__.py +12 -14
- angr/engines/engine.py +24 -61
- angr/engines/light/__init__.py +13 -5
- angr/engines/light/data.py +1 -1
- angr/engines/light/engine.py +1003 -1185
- angr/engines/pcode/__init__.py +1 -1
- angr/engines/pcode/behavior.py +1 -1
- angr/engines/pcode/cc.py +2 -0
- angr/engines/pcode/lifter.py +13 -15
- angr/engines/soot/expressions/__init__.py +12 -12
- angr/engines/soot/statements/__init__.py +6 -6
- angr/engines/soot/values/__init__.py +6 -6
- angr/engines/soot/values/arrayref.py +2 -2
- angr/engines/soot/values/constants.py +1 -1
- angr/engines/soot/values/instancefieldref.py +1 -1
- angr/engines/soot/values/paramref.py +1 -1
- angr/engines/soot/values/staticfieldref.py +1 -1
- angr/engines/successors.py +15 -14
- angr/engines/vex/__init__.py +5 -5
- angr/engines/vex/claripy/ccall.py +2 -2
- angr/engines/vex/claripy/datalayer.py +1 -1
- angr/engines/vex/claripy/irop.py +19 -19
- angr/engines/vex/heavy/__init__.py +2 -2
- angr/engines/vex/heavy/actions.py +1 -3
- angr/engines/vex/heavy/heavy.py +4 -6
- angr/engines/vex/lifter.py +2 -4
- angr/engines/vex/light/light.py +0 -2
- angr/engines/vex/light/slicing.py +5 -5
- angr/exploration_techniques/__init__.py +19 -142
- angr/exploration_techniques/base.py +126 -0
- angr/exploration_techniques/bucketizer.py +1 -1
- angr/exploration_techniques/dfs.py +3 -1
- angr/exploration_techniques/director.py +2 -3
- angr/exploration_techniques/driller_core.py +1 -1
- angr/exploration_techniques/explorer.py +4 -2
- angr/exploration_techniques/lengthlimiter.py +2 -1
- angr/exploration_techniques/local_loop_seer.py +2 -1
- angr/exploration_techniques/loop_seer.py +5 -5
- angr/exploration_techniques/manual_mergepoint.py +2 -1
- angr/exploration_techniques/memory_watcher.py +3 -1
- angr/exploration_techniques/oppologist.py +4 -5
- angr/exploration_techniques/slicecutor.py +4 -2
- angr/exploration_techniques/spiller.py +1 -1
- angr/exploration_techniques/stochastic.py +2 -1
- angr/exploration_techniques/stub_stasher.py +2 -1
- angr/exploration_techniques/suggestions.py +3 -1
- angr/exploration_techniques/symbion.py +3 -1
- angr/exploration_techniques/tech_builder.py +2 -1
- angr/exploration_techniques/threading.py +2 -11
- angr/exploration_techniques/timeout.py +4 -2
- angr/exploration_techniques/tracer.py +4 -3
- angr/exploration_techniques/unique.py +3 -2
- angr/exploration_techniques/veritesting.py +1 -1
- angr/factory.py +36 -6
- angr/keyed_region.py +4 -4
- angr/knowledge_base.py +1 -1
- angr/knowledge_plugins/__init__.py +11 -11
- angr/knowledge_plugins/cfg/__init__.py +5 -5
- angr/knowledge_plugins/cfg/cfg_manager.py +2 -2
- angr/knowledge_plugins/cfg/cfg_model.py +8 -8
- angr/knowledge_plugins/cfg/cfg_node.py +19 -19
- angr/knowledge_plugins/cfg/indirect_jump.py +6 -6
- angr/knowledge_plugins/cfg/memory_data.py +5 -7
- angr/knowledge_plugins/functions/function.py +48 -52
- angr/knowledge_plugins/functions/function_parser.py +4 -4
- angr/knowledge_plugins/key_definitions/__init__.py +3 -3
- angr/knowledge_plugins/key_definitions/atoms.py +8 -8
- angr/knowledge_plugins/key_definitions/definition.py +1 -1
- angr/knowledge_plugins/key_definitions/live_definitions.py +30 -27
- angr/knowledge_plugins/labels.py +1 -1
- angr/knowledge_plugins/propagations/__init__.py +1 -1
- angr/knowledge_plugins/propagations/prop_value.py +2 -2
- angr/knowledge_plugins/propagations/propagation_model.py +7 -8
- angr/knowledge_plugins/propagations/states.py +44 -39
- angr/knowledge_plugins/variables/variable_access.py +2 -2
- angr/knowledge_plugins/variables/variable_manager.py +24 -10
- angr/knowledge_plugins/xrefs/xref.py +5 -8
- angr/lib/angr_native.dll +0 -0
- angr/misc/__init__.py +4 -4
- angr/misc/hookset.py +4 -5
- angr/misc/loggers.py +2 -2
- angr/misc/telemetry.py +1 -1
- angr/procedures/__init__.py +1 -1
- angr/procedures/cgc/fdwait.py +2 -2
- angr/procedures/definitions/__init__.py +2 -2
- angr/procedures/definitions/linux_kernel.py +0 -1
- angr/procedures/definitions/parse_syscalls_from_local_system.py +1 -1
- angr/procedures/definitions/parse_win32json.py +0 -1
- angr/procedures/ntdll/exceptions.py +1 -1
- angr/procedures/stubs/format_parser.py +3 -3
- angr/procedures/win32/dynamic_loading.py +1 -1
- angr/protos/__init__.py +3 -3
- angr/sim_manager.py +3 -5
- angr/sim_state.py +40 -42
- angr/sim_state_options.py +3 -3
- angr/sim_type.py +15 -14
- angr/sim_variable.py +42 -45
- angr/simos/__init__.py +4 -4
- angr/simos/cgc.py +1 -1
- angr/simos/simos.py +1 -1
- angr/simos/userland.py +1 -1
- angr/slicer.py +4 -7
- angr/state_plugins/__init__.py +34 -34
- angr/state_plugins/callstack.py +5 -12
- angr/state_plugins/heap/__init__.py +2 -2
- angr/state_plugins/heap/heap_brk.py +2 -4
- angr/state_plugins/heap/heap_ptmalloc.py +1 -1
- angr/state_plugins/jni_references.py +3 -2
- angr/state_plugins/scratch.py +1 -1
- angr/state_plugins/sim_action.py +1 -4
- angr/state_plugins/sim_event.py +1 -1
- angr/state_plugins/solver.py +7 -9
- angr/state_plugins/uc_manager.py +1 -1
- angr/state_plugins/view.py +2 -2
- angr/storage/__init__.py +1 -1
- angr/storage/file.py +10 -10
- angr/storage/memory_mixins/__init__.py +46 -46
- angr/storage/memory_mixins/default_filler_mixin.py +1 -3
- angr/storage/memory_mixins/javavm_memory_mixin.py +2 -2
- angr/storage/memory_mixins/name_resolution_mixin.py +2 -2
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -3
- angr/storage/memory_mixins/paged_memory/pages/__init__.py +6 -6
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/multi_values.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +1 -1
- angr/storage/memory_mixins/paged_memory/pages/ultra_page.py +2 -4
- angr/storage/memory_mixins/regioned_memory/__init__.py +3 -3
- angr/storage/memory_mixins/regioned_memory/region_data.py +5 -5
- angr/storage/memory_mixins/regioned_memory/region_meta_mixin.py +7 -9
- angr/storage/memory_mixins/regioned_memory/regioned_memory_mixin.py +4 -4
- angr/storage/memory_object.py +4 -4
- angr/utils/__init__.py +3 -3
- angr/utils/bits.py +12 -0
- angr/utils/dynamic_dictlist.py +1 -1
- angr/utils/graph.py +1 -1
- angr/utils/orderedset.py +4 -1
- angr/utils/segment_list.py +2 -2
- angr/utils/ssa/__init__.py +33 -8
- {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/METADATA +6 -6
- {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/RECORD +263 -264
- angr/analyses/propagator/engine_ail.py +0 -1562
- angr/storage/memory_mixins/__init__.pyi +0 -48
- {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/LICENSE +0 -0
- {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/WHEEL +0 -0
- {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/entry_points.txt +0 -0
- {angr-9.2.131.dist-info → angr-9.2.133.dist-info}/top_level.txt +0 -0
|
@@ -1,1562 +0,0 @@
|
|
|
1
|
-
# pylint:disable=arguments-differ,arguments-renamed,isinstance-second-argument-not-valid-type
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
import logging
|
|
5
|
-
|
|
6
|
-
import claripy
|
|
7
|
-
from ailment import Stmt, Expr
|
|
8
|
-
from unique_log_filter import UniqueLogFilter
|
|
9
|
-
|
|
10
|
-
from angr.knowledge_plugins.propagations.prop_value import PropValue, Detail
|
|
11
|
-
from angr.knowledge_plugins.key_definitions.atoms import Register
|
|
12
|
-
|
|
13
|
-
from angr.code_location import ExternalCodeLocation
|
|
14
|
-
from angr.utils.constants import is_alignment_mask
|
|
15
|
-
from angr.engines.light import SimEngineLightAILMixin
|
|
16
|
-
from angr.sim_variable import SimStackVariable, SimMemoryVariable
|
|
17
|
-
from angr.analyses.reaching_definitions.reaching_definitions import OP_BEFORE, OP_AFTER
|
|
18
|
-
from .engine_base import SimEnginePropagatorBase
|
|
19
|
-
|
|
20
|
-
if TYPE_CHECKING:
|
|
21
|
-
from .propagator import PropagatorAILState
|
|
22
|
-
from angr.code_location import CodeLocation
|
|
23
|
-
|
|
24
|
-
l = logging.getLogger(name=__name__)
|
|
25
|
-
l.addFilter(UniqueLogFilter())
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class SimEnginePropagatorAIL(
|
|
29
|
-
SimEngineLightAILMixin,
|
|
30
|
-
SimEnginePropagatorBase,
|
|
31
|
-
):
|
|
32
|
-
"""
|
|
33
|
-
The AIl engine for Propagator.
|
|
34
|
-
"""
|
|
35
|
-
|
|
36
|
-
state: PropagatorAILState
|
|
37
|
-
|
|
38
|
-
def _is_top(self, expr: claripy.ast.Base | Expr.StackBaseOffset) -> bool:
|
|
39
|
-
if isinstance(expr, Expr.StackBaseOffset):
|
|
40
|
-
return False
|
|
41
|
-
return super()._is_top(expr)
|
|
42
|
-
|
|
43
|
-
def extract_offset_to_sp(self, expr: claripy.ast.Base | Expr.StackBaseOffset) -> int | None:
|
|
44
|
-
if isinstance(expr, Expr.StackBaseOffset):
|
|
45
|
-
return expr.offset
|
|
46
|
-
if isinstance(expr, Expr.Expression):
|
|
47
|
-
# not supported
|
|
48
|
-
return None
|
|
49
|
-
return super().extract_offset_to_sp(expr)
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
# AIL statement handlers
|
|
53
|
-
#
|
|
54
|
-
|
|
55
|
-
def _handle_Stmt(self, stmt):
|
|
56
|
-
# walk stmt.src to find all cases where a register appears above a threshold (so we don't incorrectly
|
|
57
|
-
# replace the first one)
|
|
58
|
-
from angr.analyses.decompiler.counters.expression_counters import (
|
|
59
|
-
RegisterExpressionCounter,
|
|
60
|
-
OperatorCounter,
|
|
61
|
-
) # pylint:disable=wrong-import-position
|
|
62
|
-
|
|
63
|
-
# special case: if shift-right appears in stmt.src, we allow replacement of all registers even if they appear
|
|
64
|
-
# multiple times in this statement. this is to allow the optimization of modulos and divisions later.
|
|
65
|
-
octr = OperatorCounter(["Shr", "Sar"], stmt)
|
|
66
|
-
if octr.count >= 1:
|
|
67
|
-
pass
|
|
68
|
-
else:
|
|
69
|
-
if isinstance(stmt, Stmt.Assignment):
|
|
70
|
-
ctr = RegisterExpressionCounter(stmt.src)
|
|
71
|
-
else:
|
|
72
|
-
ctr = RegisterExpressionCounter(stmt)
|
|
73
|
-
self._multi_occurrence_registers = {key for key, count in ctr.counts.items() if count > 1}
|
|
74
|
-
|
|
75
|
-
super()._handle_Stmt(stmt)
|
|
76
|
-
|
|
77
|
-
self._multi_occurrence_registers = None
|
|
78
|
-
|
|
79
|
-
def _ail_handle_Assignment(self, stmt):
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
:param Stmt.Assignment stmt:
|
|
83
|
-
:return:
|
|
84
|
-
"""
|
|
85
|
-
|
|
86
|
-
src = self._expr(stmt.src)
|
|
87
|
-
dst = stmt.dst
|
|
88
|
-
|
|
89
|
-
if type(dst) is Expr.Tmp:
|
|
90
|
-
self.state.store_temp(dst.tmp_idx, src)
|
|
91
|
-
self.state.temp_expressions[dst.tmp_idx] = stmt.src
|
|
92
|
-
|
|
93
|
-
elif type(dst) is Expr.Register:
|
|
94
|
-
codeloc = self._codeloc()
|
|
95
|
-
|
|
96
|
-
if src.needs_details:
|
|
97
|
-
# provide details
|
|
98
|
-
src = src.with_details(dst.size, dst, self._codeloc())
|
|
99
|
-
|
|
100
|
-
# do not store tmps into register
|
|
101
|
-
if any(self.has_tmpexpr(expr) for expr in src.all_exprs()):
|
|
102
|
-
src = PropValue(src.value, offset_and_details={0: Detail(src.value.size() // 8, dst, None)})
|
|
103
|
-
self.state.store_register(dst, src)
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
isinstance(stmt.src, (Expr.Register, Stmt.Call))
|
|
107
|
-
or isinstance(stmt.src, (Expr.Convert))
|
|
108
|
-
and isinstance(stmt.src.operand, Stmt.Call)
|
|
109
|
-
):
|
|
110
|
-
# set equivalence
|
|
111
|
-
self.state.add_equivalence(codeloc, dst, stmt.src)
|
|
112
|
-
|
|
113
|
-
if src.one_expr is not None:
|
|
114
|
-
self.state.register_expressions[(dst.reg_offset, dst.size)] = dst, src.one_expr, codeloc
|
|
115
|
-
else:
|
|
116
|
-
self.state.register_expressions[(dst.reg_offset, dst.size)] = dst, stmt.src, codeloc
|
|
117
|
-
|
|
118
|
-
if dst.reg_offset == self.arch.sp_offset:
|
|
119
|
-
self.state._sp_adjusted = True
|
|
120
|
-
else:
|
|
121
|
-
l.warning("Unsupported type of Assignment dst %s.", type(dst).__name__)
|
|
122
|
-
|
|
123
|
-
def _ail_handle_Store(self, stmt: Stmt.Store):
|
|
124
|
-
self.state: PropagatorAILState
|
|
125
|
-
|
|
126
|
-
addr = self._expr(stmt.addr)
|
|
127
|
-
data = self._expr(stmt.data)
|
|
128
|
-
|
|
129
|
-
# is it accessing the stack?
|
|
130
|
-
sp_offset = self.extract_offset_to_sp(addr.one_expr) if addr.one_expr is not None else None
|
|
131
|
-
if sp_offset is not None:
|
|
132
|
-
if isinstance(data.one_expr, Expr.StackBaseOffset):
|
|
133
|
-
# convert it to a BV
|
|
134
|
-
expr = data.one_expr
|
|
135
|
-
data_v = self.sp_offset(stmt.addr.bits, data.one_expr.offset)
|
|
136
|
-
size = data_v.size() // self.arch.byte_width
|
|
137
|
-
to_store = PropValue.from_value_and_details(data_v, size, expr, self._codeloc())
|
|
138
|
-
elif isinstance(data.value, claripy.ast.BV):
|
|
139
|
-
expr = data.one_expr if data.one_expr is not None else stmt.data
|
|
140
|
-
data_v = data.value
|
|
141
|
-
size = data_v.size() // self.arch.byte_width
|
|
142
|
-
to_store = PropValue.from_value_and_details(data_v, size, expr, self._codeloc())
|
|
143
|
-
else:
|
|
144
|
-
expr = data.one_expr
|
|
145
|
-
size = stmt.size
|
|
146
|
-
to_store = data.with_details(
|
|
147
|
-
stmt.size, data.one_expr if data.one_expr is not None else stmt.data, self._codeloc()
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
# ensure there isn't a Tmp variable in the data
|
|
151
|
-
if expr is None or not self.has_tmpexpr(expr):
|
|
152
|
-
# Storing data to a stack variable
|
|
153
|
-
self.state.store_stack_variable(sp_offset, to_store, endness=stmt.endness)
|
|
154
|
-
|
|
155
|
-
# set equivalence
|
|
156
|
-
var = SimStackVariable(sp_offset, size)
|
|
157
|
-
self.state.add_equivalence(self._codeloc(), var, stmt.data)
|
|
158
|
-
|
|
159
|
-
else:
|
|
160
|
-
addr_concrete = addr.one_expr
|
|
161
|
-
if addr_concrete is None:
|
|
162
|
-
# it can be a potential stack store with a variable offset
|
|
163
|
-
self.state.last_stack_store = (self.block.addr, self.stmt_idx, stmt)
|
|
164
|
-
else:
|
|
165
|
-
self.state.global_stores.append((self.block.addr, self.stmt_idx, addr_concrete, stmt))
|
|
166
|
-
if isinstance(addr_concrete, Expr.Const) and isinstance(stmt.size, int):
|
|
167
|
-
# set equivalence
|
|
168
|
-
var = SimMemoryVariable(addr_concrete.value, stmt.size)
|
|
169
|
-
self.state.add_equivalence(self._codeloc(), var, stmt.data)
|
|
170
|
-
|
|
171
|
-
def _ail_handle_Jump(self, stmt):
|
|
172
|
-
target = self._expr(stmt.target)
|
|
173
|
-
if target is None or target.one_expr == stmt.target:
|
|
174
|
-
return
|
|
175
|
-
|
|
176
|
-
target_oneexpr = target.one_expr
|
|
177
|
-
if target_oneexpr is not None and isinstance(target_oneexpr, Expr.Const):
|
|
178
|
-
new_jump_stmt = Stmt.Jump(stmt.idx, target.one_expr, **stmt.tags)
|
|
179
|
-
self.state.add_replacement(
|
|
180
|
-
self._codeloc(),
|
|
181
|
-
stmt,
|
|
182
|
-
new_jump_stmt,
|
|
183
|
-
)
|
|
184
|
-
|
|
185
|
-
def _ail_handle_Call(self, expr_stmt: Stmt.Call):
|
|
186
|
-
if isinstance(expr_stmt.target, Expr.Expression):
|
|
187
|
-
_ = self._expr(expr_stmt.target)
|
|
188
|
-
|
|
189
|
-
if expr_stmt.args:
|
|
190
|
-
for arg in expr_stmt.args:
|
|
191
|
-
_ = self._expr(arg)
|
|
192
|
-
|
|
193
|
-
if expr_stmt.ret_expr is not None:
|
|
194
|
-
if isinstance(expr_stmt.ret_expr, Expr.Register):
|
|
195
|
-
# it has a return expression. awesome - treat it as an assignment
|
|
196
|
-
|
|
197
|
-
# assume the return value always uses a full-width register
|
|
198
|
-
# FIXME: Expose it as a configuration option
|
|
199
|
-
return_value_use_full_width_reg = True
|
|
200
|
-
if return_value_use_full_width_reg:
|
|
201
|
-
v = PropValue.from_value_and_details(
|
|
202
|
-
self.state.top(self.arch.bits), self.arch.bytes, expr_stmt.ret_expr, self._codeloc()
|
|
203
|
-
)
|
|
204
|
-
self.state.store_register(
|
|
205
|
-
Expr.Register(
|
|
206
|
-
None,
|
|
207
|
-
expr_stmt.ret_expr.variable,
|
|
208
|
-
expr_stmt.ret_expr.reg_offset,
|
|
209
|
-
self.arch.bits,
|
|
210
|
-
reg_name=self.arch.translate_register_name(
|
|
211
|
-
expr_stmt.ret_expr.reg_offset, size=self.arch.bits
|
|
212
|
-
),
|
|
213
|
-
),
|
|
214
|
-
v,
|
|
215
|
-
)
|
|
216
|
-
else:
|
|
217
|
-
v = PropValue.from_value_and_details(
|
|
218
|
-
self.state.top(expr_stmt.ret_expr.size * self.arch.byte_width),
|
|
219
|
-
expr_stmt.ret_expr.size,
|
|
220
|
-
expr_stmt.ret_expr,
|
|
221
|
-
self._codeloc(),
|
|
222
|
-
)
|
|
223
|
-
self.state.store_register(expr_stmt.ret_expr, v)
|
|
224
|
-
# set equivalence
|
|
225
|
-
self.state.add_equivalence(self._codeloc(), expr_stmt.ret_expr, expr_stmt)
|
|
226
|
-
else:
|
|
227
|
-
l.warning("Unsupported ret_expr type %s.", expr_stmt.ret_expr.__class__)
|
|
228
|
-
|
|
229
|
-
if self.state._sp_adjusted and self.arch.call_pushes_ret:
|
|
230
|
-
# stack pointers still exist in the block. so we must emulate the return of the call
|
|
231
|
-
sp_reg = Expr.Register(None, None, self.arch.sp_offset, self.arch.bits)
|
|
232
|
-
sp_value = self.state.load_register(sp_reg)
|
|
233
|
-
if sp_value is not None and 0 in sp_value.offset_and_details and len(sp_value.offset_and_details) == 1:
|
|
234
|
-
sp_expr = sp_value.offset_and_details[0].expr
|
|
235
|
-
if sp_expr is not None:
|
|
236
|
-
if isinstance(sp_expr, Expr.StackBaseOffset):
|
|
237
|
-
sp_expr_new = sp_expr.copy()
|
|
238
|
-
sp_expr_new.offset += self.arch.bytes
|
|
239
|
-
else:
|
|
240
|
-
sp_expr_new = Expr.BinaryOp(
|
|
241
|
-
None, "Add", [sp_expr, Expr.Const(None, None, self.arch.bytes, sp_expr.bits)], False
|
|
242
|
-
)
|
|
243
|
-
sp_value_new = PropValue(
|
|
244
|
-
sp_value.value + self.arch.bytes,
|
|
245
|
-
offset_and_details={
|
|
246
|
-
0: Detail(
|
|
247
|
-
sp_value.offset_and_details[0].size,
|
|
248
|
-
sp_expr_new,
|
|
249
|
-
self._codeloc(),
|
|
250
|
-
)
|
|
251
|
-
},
|
|
252
|
-
)
|
|
253
|
-
self.state.store_register(sp_reg, sp_value_new)
|
|
254
|
-
|
|
255
|
-
def _ail_handle_ConditionalJump(self, stmt):
|
|
256
|
-
condition = self._expr(stmt.condition)
|
|
257
|
-
true_target = self._expr(stmt.true_target) if stmt.true_target is not None else None
|
|
258
|
-
_ = self._expr(stmt.false_target) if stmt.false_target is not None else None
|
|
259
|
-
|
|
260
|
-
# parse the condition to set initial values for true/false branches
|
|
261
|
-
if condition is not None and isinstance(true_target.one_expr, Expr.Const):
|
|
262
|
-
cond_expr = condition.one_expr
|
|
263
|
-
if (
|
|
264
|
-
isinstance(cond_expr, Expr.BinaryOp)
|
|
265
|
-
and cond_expr.op == "CmpEQ"
|
|
266
|
-
and isinstance(cond_expr.operands[1], Expr.Const)
|
|
267
|
-
):
|
|
268
|
-
# is there a register that's equivalent to the variable?
|
|
269
|
-
for _, (reg_atom, reg_expr, _) in self.state.register_expressions.items():
|
|
270
|
-
if cond_expr.operands[0] == reg_expr:
|
|
271
|
-
# found it!
|
|
272
|
-
key = self.block.addr, true_target.one_expr.value
|
|
273
|
-
self.state.block_initial_reg_values[key].append(
|
|
274
|
-
(
|
|
275
|
-
reg_atom,
|
|
276
|
-
cond_expr.operands[1],
|
|
277
|
-
)
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
def _ail_handle_Return(self, stmt: Stmt.Return):
|
|
281
|
-
if stmt.ret_exprs:
|
|
282
|
-
for ret_expr in stmt.ret_exprs:
|
|
283
|
-
self._expr(ret_expr)
|
|
284
|
-
|
|
285
|
-
#
|
|
286
|
-
# AIL expression handlers
|
|
287
|
-
#
|
|
288
|
-
|
|
289
|
-
# this method exists so that I can annotate the return type
|
|
290
|
-
def _expr(self, expr) -> PropValue | None: # pylint:disable=useless-super-delegation
|
|
291
|
-
return super()._expr(expr)
|
|
292
|
-
|
|
293
|
-
def _ail_handle_Tmp(self, expr: Expr.Tmp) -> PropValue:
|
|
294
|
-
tmp = self.state.load_tmp(expr.tmp_idx)
|
|
295
|
-
|
|
296
|
-
if tmp is not None:
|
|
297
|
-
# very first step - if we can get rid of this tmp and replace it with another, we should
|
|
298
|
-
if expr.tmp_idx in self.state.temp_expressions:
|
|
299
|
-
tmp_expr = self.state.temp_expressions[expr.tmp_idx]
|
|
300
|
-
for _, (reg_atom, reg_expr, def_at) in self.state.register_expressions.items():
|
|
301
|
-
if reg_expr.likes(tmp_expr):
|
|
302
|
-
# make sure the register still holds the same value
|
|
303
|
-
current_reg_value = self.state.load_register(reg_atom)
|
|
304
|
-
if current_reg_value is not None and 0 in current_reg_value.offset_and_details:
|
|
305
|
-
detail = current_reg_value.offset_and_details[0]
|
|
306
|
-
if detail.def_at == def_at:
|
|
307
|
-
outdated = False
|
|
308
|
-
outdated_, has_avoid_ = self.is_using_outdated_def(
|
|
309
|
-
detail.expr, detail.def_at, self._codeloc(), avoid=expr
|
|
310
|
-
)
|
|
311
|
-
if outdated_ or has_avoid_:
|
|
312
|
-
outdated = True
|
|
313
|
-
if not outdated:
|
|
314
|
-
l.debug("Add a replacement: %s with %s", expr, reg_atom)
|
|
315
|
-
self.state.add_replacement(self._codeloc(), expr, reg_atom)
|
|
316
|
-
top = self.state.top(expr.size * self.arch.byte_width)
|
|
317
|
-
return PropValue.from_value_and_details(top, expr.size, expr, self._codeloc())
|
|
318
|
-
|
|
319
|
-
# check if this new_expr uses any expression that has been overwritten
|
|
320
|
-
all_subexprs = list(tmp.all_exprs())
|
|
321
|
-
outdated = False
|
|
322
|
-
offset_and_details = tmp.offset_and_details or {}
|
|
323
|
-
for detail in offset_and_details.values():
|
|
324
|
-
if detail.expr is None:
|
|
325
|
-
continue
|
|
326
|
-
outdated_, has_avoid_ = self.is_using_outdated_def(
|
|
327
|
-
detail.expr, detail.def_at, self._codeloc(), avoid=expr
|
|
328
|
-
)
|
|
329
|
-
if outdated_ or has_avoid_:
|
|
330
|
-
outdated = True
|
|
331
|
-
break
|
|
332
|
-
|
|
333
|
-
if not offset_and_details:
|
|
334
|
-
l.warning("Tmp expression has no details or offsets")
|
|
335
|
-
return tmp
|
|
336
|
-
|
|
337
|
-
if None in all_subexprs or outdated:
|
|
338
|
-
top = self.state.top(expr.size * self.arch.byte_width)
|
|
339
|
-
self.state.add_replacement(self._codeloc(), expr, top)
|
|
340
|
-
return PropValue.from_value_and_details(top, expr.size, expr, self._codeloc())
|
|
341
|
-
|
|
342
|
-
if len(all_subexprs) == 1 and 0 in tmp.offset_and_details and tmp.offset_and_details[0].size == expr.size:
|
|
343
|
-
subexpr = all_subexprs[0]
|
|
344
|
-
l.debug("Add a replacement: %s with %s", expr, subexpr)
|
|
345
|
-
self.state.add_replacement(self._codeloc(), expr, subexpr)
|
|
346
|
-
elif tmp.offset_and_details and 0 in tmp.offset_and_details:
|
|
347
|
-
non_zero_subexprs = list(tmp.non_zero_exprs())
|
|
348
|
-
if len(non_zero_subexprs) == 1 and non_zero_subexprs[0] is tmp.offset_and_details[0].expr:
|
|
349
|
-
# we will use the zero-extended version as the replacement
|
|
350
|
-
subexpr = non_zero_subexprs[0]
|
|
351
|
-
subexpr = PropValue.extend_ail_expression(expr.bits - subexpr.bits, subexpr)
|
|
352
|
-
l.debug("Add a replacement: %s with %s", expr, subexpr)
|
|
353
|
-
self.state.add_replacement(self._codeloc(), expr, subexpr)
|
|
354
|
-
return tmp
|
|
355
|
-
|
|
356
|
-
if not self._propagate_tmps:
|
|
357
|
-
# we should not propagate any tmps. as a result, we return None for reading attempts to a tmp.
|
|
358
|
-
return PropValue(self.state.top(expr.size * self.arch.byte_width))
|
|
359
|
-
|
|
360
|
-
return PropValue(self.state.top(expr.size * self.arch.byte_width))
|
|
361
|
-
|
|
362
|
-
def _ail_handle_Register(self, expr: Expr.Register) -> PropValue | None:
|
|
363
|
-
self.state: PropagatorAILState
|
|
364
|
-
|
|
365
|
-
# Special handling for SP and BP
|
|
366
|
-
if self._stack_pointer_tracker is not None:
|
|
367
|
-
if expr.reg_offset == self.arch.sp_offset:
|
|
368
|
-
sb_offset = self._stack_pointer_tracker.offset_before(self.ins_addr, self.arch.sp_offset)
|
|
369
|
-
if sb_offset is not None:
|
|
370
|
-
new_expr = Expr.StackBaseOffset(None, self.arch.bits, sb_offset)
|
|
371
|
-
self.state.add_replacement(self._codeloc(), expr, new_expr, bp_as_gpr=self.bp_as_gpr)
|
|
372
|
-
return PropValue.from_value_and_details(
|
|
373
|
-
self.sp_offset(expr.bits, sb_offset), expr.size, new_expr, self._codeloc()
|
|
374
|
-
)
|
|
375
|
-
elif expr.reg_offset == self.arch.bp_offset and not self.bp_as_gpr:
|
|
376
|
-
sb_offset = self._stack_pointer_tracker.offset_before(self.ins_addr, self.arch.bp_offset)
|
|
377
|
-
if sb_offset is not None:
|
|
378
|
-
new_expr = Expr.StackBaseOffset(None, self.arch.bits, sb_offset)
|
|
379
|
-
self.state.add_replacement(self._codeloc(), expr, new_expr, bp_as_gpr=self.bp_as_gpr)
|
|
380
|
-
return PropValue.from_value_and_details(
|
|
381
|
-
self.sp_offset(expr.bits, sb_offset), expr.size, new_expr, self._codeloc()
|
|
382
|
-
)
|
|
383
|
-
|
|
384
|
-
# determine if we should skip replacing the current register
|
|
385
|
-
if self._multi_occurrence_registers and (expr.reg_offset, expr.size) in self._multi_occurrence_registers:
|
|
386
|
-
# don't replace this register
|
|
387
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
388
|
-
|
|
389
|
-
def _test_concatenation(pv: PropValue):
|
|
390
|
-
if pv.offset_and_details is not None and len(pv.offset_and_details) == 2 and 0 in pv.offset_and_details:
|
|
391
|
-
lo_value = pv.offset_and_details[0]
|
|
392
|
-
hi_offset = next(iter(k for k in pv.offset_and_details if k != 0))
|
|
393
|
-
hi_value = pv.offset_and_details[hi_offset]
|
|
394
|
-
if lo_value.def_at == hi_value.def_at or isinstance(hi_value.expr, Expr.Const):
|
|
395
|
-
# it's the same value or the high-end extension is a pure constant. we can apply concatenation here
|
|
396
|
-
if isinstance(hi_value.expr, Expr.Const) and hi_value.expr.value == 0:
|
|
397
|
-
# it's probably an up-cast
|
|
398
|
-
mappings = {
|
|
399
|
-
# (lo_value.size, hi_value.size): (from_bits, to_bits)
|
|
400
|
-
(1, 1): (8, 16), # char to short
|
|
401
|
-
(1, 3): (8, 32), # char to int
|
|
402
|
-
(1, 7): (8, 64), # char to int64
|
|
403
|
-
(2, 2): (16, 32), # short to int
|
|
404
|
-
(2, 6): (16, 64), # short to int64
|
|
405
|
-
(4, 4): (32, 64), # int to int64
|
|
406
|
-
}
|
|
407
|
-
key = (lo_value.size, hi_value.size)
|
|
408
|
-
if key in mappings:
|
|
409
|
-
from_bits, to_bits = mappings[key]
|
|
410
|
-
result_expr = Expr.Convert(None, from_bits, to_bits, False, lo_value.expr, **expr.tags)
|
|
411
|
-
return True, result_expr
|
|
412
|
-
result_expr = Expr.BinaryOp(None, "Concat", [hi_value.expr, lo_value.expr], False)
|
|
413
|
-
return True, result_expr
|
|
414
|
-
return False, None
|
|
415
|
-
|
|
416
|
-
new_expr = self.state.load_register(expr)
|
|
417
|
-
|
|
418
|
-
# where was this register defined?
|
|
419
|
-
reg_defat = None
|
|
420
|
-
if self._reaching_definitions is not None:
|
|
421
|
-
codeloc = self._codeloc()
|
|
422
|
-
reg_defat_defs = self._reaching_definitions.get_defs(
|
|
423
|
-
Register(expr.reg_offset, expr.size), codeloc, OP_BEFORE
|
|
424
|
-
)
|
|
425
|
-
reg_defat_codelocs = {reg_def.codeloc for reg_def in reg_defat_defs}
|
|
426
|
-
if len(reg_defat_codelocs) == 1:
|
|
427
|
-
reg_defat = next(iter(reg_defat_codelocs))
|
|
428
|
-
if reg_defat.stmt_idx is None:
|
|
429
|
-
# the observation point is in a callee function
|
|
430
|
-
reg_defat = None
|
|
431
|
-
if isinstance(reg_defat, ExternalCodeLocation):
|
|
432
|
-
reg_defat = None
|
|
433
|
-
|
|
434
|
-
stmt_to_remove = None
|
|
435
|
-
if new_expr is not None:
|
|
436
|
-
has_avoid_ = False
|
|
437
|
-
|
|
438
|
-
# check if this new_expr uses any expression that has been overwritten
|
|
439
|
-
replaced = False
|
|
440
|
-
outdated = False
|
|
441
|
-
all_subexprs = list(new_expr.all_exprs())
|
|
442
|
-
for _, detail in new_expr.offset_and_details.items():
|
|
443
|
-
if detail.expr is None:
|
|
444
|
-
break
|
|
445
|
-
outdated_, has_avoid_ = self.is_using_outdated_def(
|
|
446
|
-
detail.expr,
|
|
447
|
-
reg_defat if reg_defat is not None else detail.def_at,
|
|
448
|
-
self._codeloc(),
|
|
449
|
-
avoid=expr,
|
|
450
|
-
)
|
|
451
|
-
if outdated_ or has_avoid_:
|
|
452
|
-
outdated = True
|
|
453
|
-
break
|
|
454
|
-
|
|
455
|
-
if (
|
|
456
|
-
all_subexprs
|
|
457
|
-
and None not in all_subexprs
|
|
458
|
-
and len(all_subexprs) == 1
|
|
459
|
-
and has_avoid_
|
|
460
|
-
and self._reaching_definitions is not None
|
|
461
|
-
) and (
|
|
462
|
-
# special case:
|
|
463
|
-
#
|
|
464
|
-
# 1 | ecx_1 = ecx_0 + ebx
|
|
465
|
-
# 2 | eax = ecx_1 + 2
|
|
466
|
-
#
|
|
467
|
-
# since ecx_0 is dead after statement 1, we can always propagate ecx_1 as long as we guarantee the
|
|
468
|
-
# removal of statement 1 in a later pass, immediately after we perform replacements.
|
|
469
|
-
self._multi_occurrence_registers is None
|
|
470
|
-
or (expr.reg_offset, expr.size) not in self._multi_occurrence_registers
|
|
471
|
-
):
|
|
472
|
-
reg_defs = self._reaching_definitions.get_defs(
|
|
473
|
-
Register(expr.reg_offset, expr.size), self._codeloc(), OP_BEFORE
|
|
474
|
-
)
|
|
475
|
-
if len(reg_defs) == 1:
|
|
476
|
-
reg_def = next(iter(reg_defs))
|
|
477
|
-
# is it only used once?
|
|
478
|
-
reg_uses = self._reaching_definitions.all_uses.get_uses(reg_def)
|
|
479
|
-
if (
|
|
480
|
-
len(reg_uses) == 1
|
|
481
|
-
# is the definition location an assignment statement?
|
|
482
|
-
and reg_def.codeloc.block_addr == self.block.addr
|
|
483
|
-
and reg_def.codeloc.stmt_idx == self.stmt_idx - 1
|
|
484
|
-
):
|
|
485
|
-
stmt = self.block.statements[reg_def.codeloc.stmt_idx]
|
|
486
|
-
if (
|
|
487
|
-
isinstance(stmt, Stmt.Assignment)
|
|
488
|
-
and isinstance(stmt.dst, Expr.Register)
|
|
489
|
-
and stmt.dst.size == expr.size
|
|
490
|
-
and all_subexprs[0].likes(stmt.src)
|
|
491
|
-
and not self.state.has_replacements_at(reg_def.codeloc)
|
|
492
|
-
):
|
|
493
|
-
# ok we are getting rid of the original statement
|
|
494
|
-
outdated = False
|
|
495
|
-
stmt_to_remove = reg_def.codeloc
|
|
496
|
-
|
|
497
|
-
if all_subexprs and None not in all_subexprs and not outdated:
|
|
498
|
-
if len(all_subexprs) == 1:
|
|
499
|
-
# trivial case
|
|
500
|
-
subexpr = all_subexprs[0]
|
|
501
|
-
if subexpr.size == expr.size:
|
|
502
|
-
force_replace = self.should_force_replace(self.block.statements[self.stmt_idx], subexpr)
|
|
503
|
-
l.debug("Try to add a replacement: %s with %s", expr, subexpr)
|
|
504
|
-
replaced = self.state.add_replacement(
|
|
505
|
-
self._codeloc(),
|
|
506
|
-
expr,
|
|
507
|
-
subexpr,
|
|
508
|
-
force_replace=force_replace,
|
|
509
|
-
stmt_to_remove=stmt_to_remove,
|
|
510
|
-
bp_as_gpr=self.bp_as_gpr,
|
|
511
|
-
)
|
|
512
|
-
else:
|
|
513
|
-
is_concatenation, result_expr = _test_concatenation(new_expr)
|
|
514
|
-
if is_concatenation:
|
|
515
|
-
l.debug("Try to add a replacement: %s with %s", expr, result_expr)
|
|
516
|
-
force_replace = self.should_force_replace(self.block.statements[self.stmt_idx], result_expr)
|
|
517
|
-
replaced = self.state.add_replacement(
|
|
518
|
-
self._codeloc(),
|
|
519
|
-
expr,
|
|
520
|
-
result_expr,
|
|
521
|
-
force_replace=force_replace,
|
|
522
|
-
stmt_to_remove=stmt_to_remove,
|
|
523
|
-
bp_as_gpr=self.bp_as_gpr,
|
|
524
|
-
)
|
|
525
|
-
elif (
|
|
526
|
-
all_subexprs
|
|
527
|
-
and None not in all_subexprs
|
|
528
|
-
and len(all_subexprs) == 1
|
|
529
|
-
and self._reaching_definitions is not None
|
|
530
|
-
):
|
|
531
|
-
# if the expression has been replaced before, we should remove previous replacements
|
|
532
|
-
reg_defs = self._reaching_definitions.get_defs(
|
|
533
|
-
Register(expr.reg_offset, expr.size), self._codeloc(), OP_BEFORE
|
|
534
|
-
)
|
|
535
|
-
reg_def = next(iter(reg_defs)) if len(reg_defs) == 1 else None
|
|
536
|
-
updated_codelocs = self.state.revert_past_replacements(
|
|
537
|
-
all_subexprs[0], to_replace=expr, to_replace_def=reg_def
|
|
538
|
-
)
|
|
539
|
-
# scan through the code locations and recursively remove assignment replacements
|
|
540
|
-
while updated_codelocs:
|
|
541
|
-
new_updated_codelocs = set()
|
|
542
|
-
for u_codeloc in updated_codelocs:
|
|
543
|
-
if (
|
|
544
|
-
u_codeloc.block_addr == self.block.addr
|
|
545
|
-
and isinstance(self.block.statements[u_codeloc.stmt_idx], Stmt.Assignment)
|
|
546
|
-
and isinstance(self.block.statements[u_codeloc.stmt_idx].dst, Expr.Register)
|
|
547
|
-
):
|
|
548
|
-
dst_reg = self.block.statements[u_codeloc.stmt_idx].dst
|
|
549
|
-
# where is this assignment used?
|
|
550
|
-
reg_defs = self._reaching_definitions.get_defs(
|
|
551
|
-
Register(dst_reg.reg_offset, dst_reg.size), u_codeloc, OP_AFTER
|
|
552
|
-
)
|
|
553
|
-
if len(reg_defs) == 1:
|
|
554
|
-
reg_def = next(iter(reg_defs))
|
|
555
|
-
uses = self._reaching_definitions.all_uses.get_uses(reg_def)
|
|
556
|
-
for used_codeloc in uses:
|
|
557
|
-
if used_codeloc in self.state._replacements:
|
|
558
|
-
for to_replace, replace_by in list(
|
|
559
|
-
self.state._replacements[used_codeloc].items()
|
|
560
|
-
):
|
|
561
|
-
if isinstance(replace_by, dict):
|
|
562
|
-
replace_by = replace_by["expr"]
|
|
563
|
-
if not self.state.is_top(replace_by) and to_replace.likes(dst_reg):
|
|
564
|
-
del self.state._replacements[used_codeloc][to_replace]
|
|
565
|
-
new_updated_codelocs.add(used_codeloc)
|
|
566
|
-
updated_codelocs = new_updated_codelocs
|
|
567
|
-
|
|
568
|
-
if not replaced:
|
|
569
|
-
l.debug("Add a replacement: %s with TOP", expr)
|
|
570
|
-
self.state.add_replacement(self._codeloc(), expr, self.state.top(expr.bits), bp_as_gpr=self.bp_as_gpr)
|
|
571
|
-
else:
|
|
572
|
-
return new_expr
|
|
573
|
-
|
|
574
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
575
|
-
|
|
576
|
-
def _ail_handle_Load(self, expr: Expr.Load) -> PropValue | None:
|
|
577
|
-
self.state: PropagatorAILState
|
|
578
|
-
|
|
579
|
-
addr = self._expr(expr.addr)
|
|
580
|
-
|
|
581
|
-
addr_expr = addr.one_expr
|
|
582
|
-
var_defat = None
|
|
583
|
-
|
|
584
|
-
if addr_expr is not None:
|
|
585
|
-
if isinstance(addr_expr, Expr.StackBaseOffset) and not isinstance(expr.addr, Expr.StackBaseOffset):
|
|
586
|
-
l.debug("Add a replacement: %s with %s", expr.addr, addr_expr)
|
|
587
|
-
self.state.add_replacement(self._codeloc(), expr.addr, addr_expr)
|
|
588
|
-
|
|
589
|
-
sp_offset = self.extract_offset_to_sp(addr_expr)
|
|
590
|
-
if sp_offset is not None:
|
|
591
|
-
# Stack variable.
|
|
592
|
-
var = self.state.load_stack_variable(sp_offset, expr.size, endness=expr.endness)
|
|
593
|
-
if var is not None:
|
|
594
|
-
var_defat = var.one_defat
|
|
595
|
-
# We do not add replacements here since in AIL function and block simplifiers we explicitly forbid
|
|
596
|
-
# replacing stack variables, unless this is the parameter of a call (indicated by expr.func_arg is
|
|
597
|
-
# True).
|
|
598
|
-
if getattr(expr, "func_arg", False) is True or (
|
|
599
|
-
self.state._gp is not None
|
|
600
|
-
and not self.state.is_top(var.value)
|
|
601
|
-
and var.value.concrete
|
|
602
|
-
and var.value.concrete_value == self.state._gp
|
|
603
|
-
):
|
|
604
|
-
if var.one_expr is not None:
|
|
605
|
-
outdated, has_avoid = self.is_using_outdated_def(
|
|
606
|
-
var.one_expr, var.one_defat, self._codeloc(), avoid=expr.addr
|
|
607
|
-
)
|
|
608
|
-
if not (outdated or has_avoid):
|
|
609
|
-
l.debug("Add a replacement: %s with %s", expr, var.one_expr)
|
|
610
|
-
self.state.add_replacement(self._codeloc(), expr, var.one_expr)
|
|
611
|
-
else:
|
|
612
|
-
# there isn't a single expression to replace with. remove the old replacement for this
|
|
613
|
-
# expression if available.
|
|
614
|
-
self.state.add_replacement(self._codeloc(), expr, self.state.top(expr.bits))
|
|
615
|
-
if not self.state.is_top(var.value):
|
|
616
|
-
return var
|
|
617
|
-
|
|
618
|
-
if addr_expr is not None and addr_expr is not expr.addr:
|
|
619
|
-
new_expr = Expr.Load(expr.idx, addr_expr, expr.size, expr.endness, **expr.tags)
|
|
620
|
-
else:
|
|
621
|
-
new_expr = expr
|
|
622
|
-
return PropValue.from_value_and_details(
|
|
623
|
-
self.state.top(expr.size * self.arch.byte_width),
|
|
624
|
-
expr.size,
|
|
625
|
-
new_expr,
|
|
626
|
-
self._codeloc() if var_defat is None else var_defat,
|
|
627
|
-
)
|
|
628
|
-
|
|
629
|
-
def _ail_handle_Convert(self, expr: Expr.Convert) -> PropValue:
|
|
630
|
-
o_value = self._expr(expr.operand)
|
|
631
|
-
|
|
632
|
-
if not (expr.from_type == Expr.Convert.TYPE_INT and expr.to_type == Expr.Convert.TYPE_INT):
|
|
633
|
-
# we do not support floating-point conversions
|
|
634
|
-
new_value = self.state.top(expr.to_bits)
|
|
635
|
-
return PropValue.from_value_and_details(new_value, expr.size, expr, self._codeloc())
|
|
636
|
-
|
|
637
|
-
if o_value is None or self.state.is_top(o_value.value):
|
|
638
|
-
new_value = self.state.top(expr.to_bits)
|
|
639
|
-
else:
|
|
640
|
-
if expr.from_bits < expr.to_bits:
|
|
641
|
-
if expr.is_signed:
|
|
642
|
-
new_value = claripy.SignExt(expr.to_bits - expr.from_bits, o_value.value)
|
|
643
|
-
else:
|
|
644
|
-
new_value = claripy.ZeroExt(expr.to_bits - expr.from_bits, o_value.value)
|
|
645
|
-
elif expr.from_bits > expr.to_bits:
|
|
646
|
-
new_value = claripy.Extract(expr.to_bits - 1, 0, o_value.value)
|
|
647
|
-
else:
|
|
648
|
-
new_value = o_value.value
|
|
649
|
-
|
|
650
|
-
o_expr = o_value.one_expr
|
|
651
|
-
o_defat = o_value.one_defat
|
|
652
|
-
if o_expr is not None:
|
|
653
|
-
# easy cases
|
|
654
|
-
if type(o_expr) is Expr.Convert:
|
|
655
|
-
if expr.from_bits == o_expr.to_bits and expr.to_bits == o_expr.from_bits:
|
|
656
|
-
# eliminate the redundant Convert
|
|
657
|
-
new_expr = o_expr.operand
|
|
658
|
-
else:
|
|
659
|
-
new_expr = Expr.Convert(
|
|
660
|
-
expr.idx, o_expr.from_bits, expr.to_bits, expr.is_signed, o_expr.operand, **o_expr.tags
|
|
661
|
-
)
|
|
662
|
-
elif type(o_expr) is Expr.Const:
|
|
663
|
-
# do the conversion right away
|
|
664
|
-
value = o_expr.value
|
|
665
|
-
mask = (2**expr.to_bits) - 1
|
|
666
|
-
value &= mask
|
|
667
|
-
new_expr = Expr.Const(expr.idx, o_expr.variable, value, expr.to_bits, **expr.tags)
|
|
668
|
-
else:
|
|
669
|
-
new_expr = Expr.Convert(expr.idx, expr.from_bits, expr.to_bits, expr.is_signed, o_expr, **expr.tags)
|
|
670
|
-
|
|
671
|
-
if (
|
|
672
|
-
isinstance(new_expr, Expr.Convert)
|
|
673
|
-
and not new_expr.is_signed
|
|
674
|
-
and new_expr.to_bits > new_expr.from_bits
|
|
675
|
-
and new_expr.from_bits % self.arch.byte_width == 0
|
|
676
|
-
):
|
|
677
|
-
# special handling for zero-extension: it simplifies the code if we explicitly model zeros
|
|
678
|
-
new_size = new_expr.from_bits // self.arch.byte_width
|
|
679
|
-
offset_and_details = {
|
|
680
|
-
0: Detail(new_size, new_expr.operand, o_defat),
|
|
681
|
-
new_size: Detail(
|
|
682
|
-
new_expr.size - new_size,
|
|
683
|
-
Expr.Const(expr.idx, None, 0, new_expr.to_bits - new_expr.from_bits, **new_expr.tags),
|
|
684
|
-
self._codeloc(),
|
|
685
|
-
),
|
|
686
|
-
}
|
|
687
|
-
else:
|
|
688
|
-
offset_and_details = {0: Detail(expr.size, new_expr, self._codeloc())}
|
|
689
|
-
|
|
690
|
-
return PropValue(new_value, offset_and_details=offset_and_details)
|
|
691
|
-
|
|
692
|
-
if o_value.offset_and_details:
|
|
693
|
-
# hard cases... we will keep certain labels and eliminate other labels
|
|
694
|
-
start_offset = 0
|
|
695
|
-
end_offset = expr.to_bits // self.arch.byte_width # end_offset is exclusive
|
|
696
|
-
offset_and_details = {}
|
|
697
|
-
max_offset = max(o_value.offset_and_details.keys())
|
|
698
|
-
for offset_, detail_ in o_value.offset_and_details.items():
|
|
699
|
-
if offset_ < start_offset < offset_ + detail_.size:
|
|
700
|
-
# we start here
|
|
701
|
-
off = 0
|
|
702
|
-
siz = min(end_offset, offset_ + detail_.size) - start_offset
|
|
703
|
-
expr_ = PropValue.extract_ail_expression(
|
|
704
|
-
(start_offset - offset_) * self.arch.byte_width, siz * self.arch.byte_width, detail_.expr
|
|
705
|
-
)
|
|
706
|
-
offset_and_details[off] = Detail(siz, expr_, detail_.def_at)
|
|
707
|
-
elif offset_ >= start_offset and offset_ + detail_.size <= end_offset:
|
|
708
|
-
# we include the whole thing
|
|
709
|
-
off = offset_ - start_offset
|
|
710
|
-
siz = detail_.size
|
|
711
|
-
if off == max_offset and off + siz < end_offset:
|
|
712
|
-
# extend the expr
|
|
713
|
-
expr_ = PropValue.extend_ail_expression(
|
|
714
|
-
(end_offset - (off + siz)) * self.arch.byte_width, detail_.expr
|
|
715
|
-
)
|
|
716
|
-
siz = end_offset - off
|
|
717
|
-
else:
|
|
718
|
-
expr_ = detail_.expr
|
|
719
|
-
offset_and_details[off] = Detail(siz, expr_, detail_.def_at)
|
|
720
|
-
elif offset_ < end_offset <= offset_ + detail_.size:
|
|
721
|
-
# we include all the way until end_offset
|
|
722
|
-
if offset_ < start_offset:
|
|
723
|
-
off = 0
|
|
724
|
-
siz = end_offset - start_offset
|
|
725
|
-
else:
|
|
726
|
-
off = offset_ - start_offset
|
|
727
|
-
siz = end_offset - offset_
|
|
728
|
-
expr_ = PropValue.extract_ail_expression(0, siz * self.arch.byte_width, detail_.expr)
|
|
729
|
-
offset_and_details[off] = Detail(siz, expr_, detail_.def_at)
|
|
730
|
-
|
|
731
|
-
return PropValue(new_value, offset_and_details=offset_and_details)
|
|
732
|
-
# it's empty... no expression is available for whatever reason
|
|
733
|
-
return PropValue.from_value_and_details(new_value, expr.size, expr, self._codeloc())
|
|
734
|
-
|
|
735
|
-
def _ail_handle_Const(self, expr: Expr.Const) -> PropValue:
|
|
736
|
-
if isinstance(expr.value, float):
|
|
737
|
-
v = claripy.FPV(expr.value, claripy.FSORT_DOUBLE if expr.bits == 64 else claripy.FSORT_FLOAT)
|
|
738
|
-
else:
|
|
739
|
-
v = claripy.BVV(expr.value, expr.bits)
|
|
740
|
-
return PropValue.from_value_and_details(v, expr.size, expr, self._codeloc())
|
|
741
|
-
|
|
742
|
-
def _ail_handle_DirtyExpression(self, expr: Expr.DirtyExpression) -> PropValue | None: # pylint:disable=no-self-use
|
|
743
|
-
for operand in expr.operands:
|
|
744
|
-
_ = self._expr(operand)
|
|
745
|
-
|
|
746
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
747
|
-
|
|
748
|
-
def _ail_handle_VEXCCallExpression(
|
|
749
|
-
self, expr: Expr.VEXCCallExpression
|
|
750
|
-
) -> PropValue | None: # pylint:disable=no-self-use
|
|
751
|
-
for operand in expr.operands:
|
|
752
|
-
_ = self._expr(operand)
|
|
753
|
-
|
|
754
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
755
|
-
|
|
756
|
-
def _ail_handle_ITE(self, expr: Expr.ITE) -> PropValue | None:
|
|
757
|
-
# pylint:disable=unused-variable
|
|
758
|
-
self._expr(expr.cond) # cond
|
|
759
|
-
self._expr(expr.iftrue) # iftrue
|
|
760
|
-
self._expr(expr.iffalse) # iffalse
|
|
761
|
-
|
|
762
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
763
|
-
|
|
764
|
-
def _ail_handle_Reinterpret(self, expr: Expr.Reinterpret) -> PropValue | None:
|
|
765
|
-
arg = self._expr(expr.operand)
|
|
766
|
-
|
|
767
|
-
if self.state.is_top(arg.value):
|
|
768
|
-
one_expr = arg.one_expr
|
|
769
|
-
if one_expr is not None:
|
|
770
|
-
expr = Expr.Reinterpret(
|
|
771
|
-
expr.idx, expr.from_bits, expr.from_type, expr.to_bits, expr.to_type, one_expr, **expr.tags
|
|
772
|
-
)
|
|
773
|
-
|
|
774
|
-
return PropValue.from_value_and_details(arg.value, expr.size, expr, self._codeloc())
|
|
775
|
-
|
|
776
|
-
def _ail_handle_CallExpr(self, expr_stmt: Stmt.Call) -> PropValue | None:
|
|
777
|
-
if isinstance(expr_stmt.target, Expr.Expression):
|
|
778
|
-
_ = self._expr(expr_stmt.target)
|
|
779
|
-
|
|
780
|
-
if expr_stmt.args:
|
|
781
|
-
for arg in expr_stmt.args:
|
|
782
|
-
_ = self._expr(arg)
|
|
783
|
-
|
|
784
|
-
# ignore ret_expr
|
|
785
|
-
return PropValue.from_value_and_details(
|
|
786
|
-
self.state.top(expr_stmt.bits), expr_stmt.size, expr_stmt, self._codeloc()
|
|
787
|
-
)
|
|
788
|
-
|
|
789
|
-
def _ail_handle_Not(self, expr):
|
|
790
|
-
o_value = self._expr(expr.operand)
|
|
791
|
-
|
|
792
|
-
value = self.state.top(expr.bits)
|
|
793
|
-
if o_value is None:
|
|
794
|
-
new_expr = expr
|
|
795
|
-
else:
|
|
796
|
-
o_expr = o_value.one_expr
|
|
797
|
-
new_expr = Expr.UnaryOp(expr.idx, "Not", o_expr if o_expr is not None else expr.operands[0], **expr.tags)
|
|
798
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
799
|
-
|
|
800
|
-
def _ail_handle_Neg(self, expr):
|
|
801
|
-
o_value = self._expr(expr.operand)
|
|
802
|
-
|
|
803
|
-
value = self.state.top(expr.bits)
|
|
804
|
-
if o_value is None:
|
|
805
|
-
new_expr = expr
|
|
806
|
-
else:
|
|
807
|
-
o_expr = o_value.one_expr
|
|
808
|
-
new_expr = Expr.UnaryOp(expr.idx, "Neg", o_expr if o_expr is not None else expr.operands[0], **expr.tags)
|
|
809
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
810
|
-
|
|
811
|
-
def _ail_handle_BitwiseNeg(self, expr):
|
|
812
|
-
o_value = self._expr(expr.operand)
|
|
813
|
-
|
|
814
|
-
value = self.state.top(expr.bits)
|
|
815
|
-
if o_value is None:
|
|
816
|
-
new_expr = expr
|
|
817
|
-
else:
|
|
818
|
-
o_expr = o_value.one_expr
|
|
819
|
-
new_expr = Expr.UnaryOp(
|
|
820
|
-
expr.idx, "BitwiseNeg", o_expr if o_expr is not None else expr.operands[0], **expr.tags
|
|
821
|
-
)
|
|
822
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
823
|
-
|
|
824
|
-
def _ail_handle_Cmp(self, expr: Expr.BinaryOp) -> PropValue:
|
|
825
|
-
operand_0_value = self._expr(expr.operands[0])
|
|
826
|
-
operand_1_value = self._expr(expr.operands[1])
|
|
827
|
-
|
|
828
|
-
if operand_0_value is not None and operand_1_value is not None:
|
|
829
|
-
operand_0_oneexpr = operand_0_value.one_expr
|
|
830
|
-
operand_1_oneexpr = operand_1_value.one_expr
|
|
831
|
-
if operand_0_oneexpr is expr.operands[0] and operand_1_oneexpr is expr.operands[1]:
|
|
832
|
-
# nothing changed
|
|
833
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
834
|
-
operand_0 = operand_0_oneexpr if operand_0_oneexpr is not None else expr.operands[0]
|
|
835
|
-
operand_1 = operand_1_oneexpr if operand_1_oneexpr is not None else expr.operands[1]
|
|
836
|
-
|
|
837
|
-
new_expr = Expr.BinaryOp(expr.idx, expr.op, [operand_0, operand_1], expr.signed, **expr.tags)
|
|
838
|
-
else:
|
|
839
|
-
new_expr = expr
|
|
840
|
-
|
|
841
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, new_expr, self._codeloc())
|
|
842
|
-
|
|
843
|
-
_ail_handle_CmpF = _ail_handle_Cmp
|
|
844
|
-
_ail_handle_CmpLE = _ail_handle_Cmp
|
|
845
|
-
_ail_handle_CmpLEs = _ail_handle_Cmp
|
|
846
|
-
_ail_handle_CmpLT = _ail_handle_Cmp
|
|
847
|
-
_ail_handle_CmpLTs = _ail_handle_Cmp
|
|
848
|
-
_ail_handle_CmpGE = _ail_handle_Cmp
|
|
849
|
-
_ail_handle_CmpGEs = _ail_handle_Cmp
|
|
850
|
-
_ail_handle_CmpGT = _ail_handle_Cmp
|
|
851
|
-
_ail_handle_CmpGTs = _ail_handle_Cmp
|
|
852
|
-
_ail_handle_CmpEQ = _ail_handle_Cmp
|
|
853
|
-
_ail_handle_CmpNE = _ail_handle_Cmp
|
|
854
|
-
_ail_handle_CmpORD = _ail_handle_Cmp
|
|
855
|
-
|
|
856
|
-
def _ail_handle_Add(self, expr: Expr.BinaryOp) -> PropValue:
|
|
857
|
-
o0_value = self._expr(expr.operands[0])
|
|
858
|
-
o1_value = self._expr(expr.operands[1])
|
|
859
|
-
|
|
860
|
-
if o0_value is None or o1_value is None:
|
|
861
|
-
new_expr = expr
|
|
862
|
-
value = self.state.top(expr.bits)
|
|
863
|
-
else:
|
|
864
|
-
if o0_value.value.concrete and o1_value.value.concrete:
|
|
865
|
-
value = (o0_value.value + o1_value.value) & ((1 << self.arch.bits) - 1)
|
|
866
|
-
else:
|
|
867
|
-
value = self.state.top(expr.bits)
|
|
868
|
-
|
|
869
|
-
o0_expr = o0_value.one_expr
|
|
870
|
-
o1_expr = o1_value.one_expr
|
|
871
|
-
if isinstance(o0_expr, Expr.BasePointerOffset) and isinstance(o1_expr, Expr.Const):
|
|
872
|
-
new_expr = o0_value.one_expr.copy()
|
|
873
|
-
new_expr.offset += o1_expr.value
|
|
874
|
-
else:
|
|
875
|
-
new_expr = Expr.BinaryOp(
|
|
876
|
-
expr.idx,
|
|
877
|
-
"Add",
|
|
878
|
-
[
|
|
879
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
880
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
881
|
-
],
|
|
882
|
-
expr.signed,
|
|
883
|
-
floating_point=expr.floating_point,
|
|
884
|
-
rounding_mode=expr.rounding_mode,
|
|
885
|
-
**expr.tags,
|
|
886
|
-
)
|
|
887
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
888
|
-
|
|
889
|
-
def _ail_handle_Sub(self, expr: Expr.BinaryOp) -> PropValue:
|
|
890
|
-
o0_value = self._expr(expr.operands[0])
|
|
891
|
-
o1_value = self._expr(expr.operands[1])
|
|
892
|
-
|
|
893
|
-
if o0_value is None or o1_value is None:
|
|
894
|
-
new_expr = expr
|
|
895
|
-
value = self.state.top(expr.bits)
|
|
896
|
-
else:
|
|
897
|
-
if o0_value.value.concrete and o1_value.value.concrete:
|
|
898
|
-
value = (o0_value.value - o1_value.value) & ((1 << self.arch.bits) - 1)
|
|
899
|
-
else:
|
|
900
|
-
value = self.state.top(expr.bits)
|
|
901
|
-
|
|
902
|
-
o0_expr = o0_value.one_expr
|
|
903
|
-
o1_expr = o1_value.one_expr
|
|
904
|
-
if isinstance(o0_expr, Expr.BasePointerOffset) and isinstance(o1_expr, Expr.Const):
|
|
905
|
-
new_expr = o0_value.one_expr.copy()
|
|
906
|
-
new_expr.offset -= o1_expr.value
|
|
907
|
-
else:
|
|
908
|
-
new_expr = Expr.BinaryOp(
|
|
909
|
-
expr.idx,
|
|
910
|
-
"Sub",
|
|
911
|
-
[
|
|
912
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
913
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
914
|
-
],
|
|
915
|
-
expr.signed,
|
|
916
|
-
floating_point=expr.floating_point,
|
|
917
|
-
rounding_mode=expr.rounding_mode,
|
|
918
|
-
**expr.tags,
|
|
919
|
-
)
|
|
920
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
921
|
-
|
|
922
|
-
def _ail_handle_StackBaseOffset(self, expr: Expr.StackBaseOffset) -> PropValue: # pylint:disable=no-self-use
|
|
923
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, expr, self._codeloc())
|
|
924
|
-
|
|
925
|
-
def _ail_handle_And(self, expr: Expr.BinaryOp):
|
|
926
|
-
o0_value = self._expr(expr.operands[0])
|
|
927
|
-
o1_value = self._expr(expr.operands[1])
|
|
928
|
-
|
|
929
|
-
value = self.state.top(expr.bits)
|
|
930
|
-
if o0_value is None or o1_value is None:
|
|
931
|
-
new_expr = expr
|
|
932
|
-
else:
|
|
933
|
-
o0_expr = o0_value.one_expr
|
|
934
|
-
o1_expr = o1_value.one_expr
|
|
935
|
-
|
|
936
|
-
# Special logic for stack pointer alignment
|
|
937
|
-
sp_offset = self.extract_offset_to_sp(o0_value.value)
|
|
938
|
-
if (
|
|
939
|
-
sp_offset is not None
|
|
940
|
-
and type(o1_expr) is Expr.Const
|
|
941
|
-
and is_alignment_mask(o1_expr.value)
|
|
942
|
-
or (
|
|
943
|
-
isinstance(o0_expr, Expr.StackBaseOffset)
|
|
944
|
-
and type(o1_expr) is Expr.Const
|
|
945
|
-
and is_alignment_mask(o1_expr.value)
|
|
946
|
-
)
|
|
947
|
-
):
|
|
948
|
-
value = o0_value.value
|
|
949
|
-
new_expr = o0_expr
|
|
950
|
-
else:
|
|
951
|
-
value = self.state.top(expr.bits)
|
|
952
|
-
new_expr = Expr.BinaryOp(
|
|
953
|
-
expr.idx,
|
|
954
|
-
"And",
|
|
955
|
-
[
|
|
956
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
957
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
958
|
-
],
|
|
959
|
-
expr.signed,
|
|
960
|
-
floating_point=expr.floating_point,
|
|
961
|
-
rounding_mode=expr.rounding_mode,
|
|
962
|
-
**expr.tags,
|
|
963
|
-
)
|
|
964
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
965
|
-
|
|
966
|
-
def _ail_handle_Or(self, expr: Expr.BinaryOp):
|
|
967
|
-
o0_value = self._expr(expr.operands[0])
|
|
968
|
-
o1_value = self._expr(expr.operands[1])
|
|
969
|
-
|
|
970
|
-
value = self.state.top(expr.bits)
|
|
971
|
-
if o0_value is None or o1_value is None:
|
|
972
|
-
new_expr = expr
|
|
973
|
-
else:
|
|
974
|
-
o0_expr = o0_value.one_expr
|
|
975
|
-
o1_expr = o1_value.one_expr
|
|
976
|
-
new_expr = Expr.BinaryOp(
|
|
977
|
-
expr.idx,
|
|
978
|
-
"Or",
|
|
979
|
-
[
|
|
980
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
981
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
982
|
-
],
|
|
983
|
-
expr.signed,
|
|
984
|
-
floating_point=expr.floating_point,
|
|
985
|
-
rounding_mode=expr.rounding_mode,
|
|
986
|
-
**expr.tags,
|
|
987
|
-
)
|
|
988
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
989
|
-
|
|
990
|
-
def _ail_handle_Xor(self, expr: Expr.BinaryOp):
|
|
991
|
-
o0_value = self._expr(expr.operands[0])
|
|
992
|
-
o1_value = self._expr(expr.operands[1])
|
|
993
|
-
|
|
994
|
-
value = self.state.top(expr.bits)
|
|
995
|
-
if o0_value is None or o1_value is None:
|
|
996
|
-
new_expr = expr
|
|
997
|
-
else:
|
|
998
|
-
o0_expr = o0_value.one_expr
|
|
999
|
-
o1_expr = o1_value.one_expr
|
|
1000
|
-
new_expr = Expr.BinaryOp(
|
|
1001
|
-
expr.idx,
|
|
1002
|
-
"Xor",
|
|
1003
|
-
[
|
|
1004
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1005
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1006
|
-
],
|
|
1007
|
-
expr.signed,
|
|
1008
|
-
floating_point=expr.floating_point,
|
|
1009
|
-
rounding_mode=expr.rounding_mode,
|
|
1010
|
-
**expr.tags,
|
|
1011
|
-
)
|
|
1012
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1013
|
-
|
|
1014
|
-
def _ail_handle_Shl(self, expr: Expr.BinaryOp):
|
|
1015
|
-
o0_value = self._expr(expr.operands[0])
|
|
1016
|
-
o1_value = self._expr(expr.operands[1])
|
|
1017
|
-
|
|
1018
|
-
value = self.state.top(expr.bits)
|
|
1019
|
-
if o0_value is None or o1_value is None:
|
|
1020
|
-
new_expr = expr
|
|
1021
|
-
else:
|
|
1022
|
-
o0_expr = o0_value.one_expr
|
|
1023
|
-
o1_expr = o1_value.one_expr
|
|
1024
|
-
new_expr = Expr.BinaryOp(
|
|
1025
|
-
expr.idx,
|
|
1026
|
-
"Shl",
|
|
1027
|
-
[
|
|
1028
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1029
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1030
|
-
],
|
|
1031
|
-
expr.signed,
|
|
1032
|
-
floating_point=expr.floating_point,
|
|
1033
|
-
rounding_mode=expr.rounding_mode,
|
|
1034
|
-
**expr.tags,
|
|
1035
|
-
)
|
|
1036
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1037
|
-
|
|
1038
|
-
def _ail_handle_Shr(self, expr: Expr.BinaryOp):
|
|
1039
|
-
o0_value = self._expr(expr.operands[0])
|
|
1040
|
-
o1_value = self._expr(expr.operands[1])
|
|
1041
|
-
|
|
1042
|
-
value = self.state.top(expr.bits)
|
|
1043
|
-
if o0_value is None or o1_value is None:
|
|
1044
|
-
new_expr = expr
|
|
1045
|
-
else:
|
|
1046
|
-
o0_expr = o0_value.one_expr
|
|
1047
|
-
o1_expr = o1_value.one_expr
|
|
1048
|
-
new_expr = Expr.BinaryOp(
|
|
1049
|
-
expr.idx,
|
|
1050
|
-
"Shr",
|
|
1051
|
-
[
|
|
1052
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1053
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1054
|
-
],
|
|
1055
|
-
expr.signed,
|
|
1056
|
-
floating_point=expr.floating_point,
|
|
1057
|
-
rounding_mode=expr.rounding_mode,
|
|
1058
|
-
**expr.tags,
|
|
1059
|
-
)
|
|
1060
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1061
|
-
|
|
1062
|
-
def _ail_handle_Sar(self, expr: Expr.BinaryOp):
|
|
1063
|
-
o0_value = self._expr(expr.operands[0])
|
|
1064
|
-
o1_value = self._expr(expr.operands[1])
|
|
1065
|
-
|
|
1066
|
-
value = self.state.top(expr.bits)
|
|
1067
|
-
if o0_value is None or o1_value is None:
|
|
1068
|
-
new_expr = expr
|
|
1069
|
-
else:
|
|
1070
|
-
o0_expr = o0_value.one_expr
|
|
1071
|
-
o1_expr = o1_value.one_expr
|
|
1072
|
-
new_expr = Expr.BinaryOp(
|
|
1073
|
-
expr.idx,
|
|
1074
|
-
"Sar",
|
|
1075
|
-
[
|
|
1076
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1077
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1078
|
-
],
|
|
1079
|
-
expr.signed,
|
|
1080
|
-
floating_point=expr.floating_point,
|
|
1081
|
-
rounding_mode=expr.rounding_mode,
|
|
1082
|
-
**expr.tags,
|
|
1083
|
-
)
|
|
1084
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1085
|
-
|
|
1086
|
-
def _ail_handle_Rol(self, expr: Expr.BinaryOp):
|
|
1087
|
-
o0_value = self._expr(expr.operands[0])
|
|
1088
|
-
o1_value = self._expr(expr.operands[1])
|
|
1089
|
-
|
|
1090
|
-
value = self.state.top(expr.bits)
|
|
1091
|
-
if o0_value is None or o1_value is None:
|
|
1092
|
-
new_expr = expr
|
|
1093
|
-
else:
|
|
1094
|
-
o0_expr = o0_value.one_expr
|
|
1095
|
-
o1_expr = o1_value.one_expr
|
|
1096
|
-
new_expr = Expr.BinaryOp(
|
|
1097
|
-
expr.idx,
|
|
1098
|
-
"Rol",
|
|
1099
|
-
[
|
|
1100
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1101
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1102
|
-
],
|
|
1103
|
-
expr.signed,
|
|
1104
|
-
floating_point=expr.floating_point,
|
|
1105
|
-
rounding_mode=expr.rounding_mode,
|
|
1106
|
-
**expr.tags,
|
|
1107
|
-
)
|
|
1108
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1109
|
-
|
|
1110
|
-
def _ail_handle_Ror(self, expr: Expr.BinaryOp):
|
|
1111
|
-
o0_value = self._expr(expr.operands[0])
|
|
1112
|
-
o1_value = self._expr(expr.operands[1])
|
|
1113
|
-
|
|
1114
|
-
value = self.state.top(expr.bits)
|
|
1115
|
-
if o0_value is None or o1_value is None:
|
|
1116
|
-
new_expr = expr
|
|
1117
|
-
else:
|
|
1118
|
-
o0_expr = o0_value.one_expr
|
|
1119
|
-
o1_expr = o1_value.one_expr
|
|
1120
|
-
new_expr = Expr.BinaryOp(
|
|
1121
|
-
expr.idx,
|
|
1122
|
-
"Ror",
|
|
1123
|
-
[
|
|
1124
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1125
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1126
|
-
],
|
|
1127
|
-
expr.signed,
|
|
1128
|
-
floating_point=expr.floating_point,
|
|
1129
|
-
rounding_mode=expr.rounding_mode,
|
|
1130
|
-
**expr.tags,
|
|
1131
|
-
)
|
|
1132
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1133
|
-
|
|
1134
|
-
def _ail_handle_Mul(self, expr):
|
|
1135
|
-
o0_value = self._expr(expr.operands[0])
|
|
1136
|
-
o1_value = self._expr(expr.operands[1])
|
|
1137
|
-
|
|
1138
|
-
value = self.state.top(expr.bits)
|
|
1139
|
-
if o0_value is None or o1_value is None:
|
|
1140
|
-
new_expr = expr
|
|
1141
|
-
else:
|
|
1142
|
-
o0_expr = o0_value.one_expr
|
|
1143
|
-
o1_expr = o1_value.one_expr
|
|
1144
|
-
new_expr = Expr.BinaryOp(
|
|
1145
|
-
expr.idx,
|
|
1146
|
-
"Mul",
|
|
1147
|
-
[
|
|
1148
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1149
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1150
|
-
],
|
|
1151
|
-
expr.signed,
|
|
1152
|
-
floating_point=expr.floating_point,
|
|
1153
|
-
rounding_mode=expr.rounding_mode,
|
|
1154
|
-
**expr.tags,
|
|
1155
|
-
)
|
|
1156
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1157
|
-
|
|
1158
|
-
_ail_handle_AddV = _ail_handle_Add
|
|
1159
|
-
_ail_handle_MulV = _ail_handle_Mul
|
|
1160
|
-
|
|
1161
|
-
def _ail_handle_Mull(self, expr):
|
|
1162
|
-
o0_value = self._expr(expr.operands[0])
|
|
1163
|
-
o1_value = self._expr(expr.operands[1])
|
|
1164
|
-
|
|
1165
|
-
value = self.state.top(expr.bits)
|
|
1166
|
-
if o0_value is None or o1_value is None:
|
|
1167
|
-
new_expr = expr
|
|
1168
|
-
else:
|
|
1169
|
-
o0_expr = o0_value.one_expr
|
|
1170
|
-
o1_expr = o1_value.one_expr
|
|
1171
|
-
new_expr = Expr.BinaryOp(
|
|
1172
|
-
expr.idx,
|
|
1173
|
-
"Mull",
|
|
1174
|
-
[
|
|
1175
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1176
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1177
|
-
],
|
|
1178
|
-
expr.signed,
|
|
1179
|
-
bits=expr.bits,
|
|
1180
|
-
floating_point=expr.floating_point,
|
|
1181
|
-
rounding_mode=expr.rounding_mode,
|
|
1182
|
-
**expr.tags,
|
|
1183
|
-
)
|
|
1184
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1185
|
-
|
|
1186
|
-
def _ail_handle_Div(self, expr):
|
|
1187
|
-
o0_value = self._expr(expr.operands[0])
|
|
1188
|
-
o1_value = self._expr(expr.operands[1])
|
|
1189
|
-
|
|
1190
|
-
value = self.state.top(expr.bits)
|
|
1191
|
-
if o0_value is None or o1_value is None:
|
|
1192
|
-
new_expr = expr
|
|
1193
|
-
else:
|
|
1194
|
-
o0_expr = o0_value.one_expr
|
|
1195
|
-
o1_expr = o1_value.one_expr
|
|
1196
|
-
new_expr = Expr.BinaryOp(
|
|
1197
|
-
expr.idx,
|
|
1198
|
-
"Div",
|
|
1199
|
-
[
|
|
1200
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1201
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1202
|
-
],
|
|
1203
|
-
expr.signed,
|
|
1204
|
-
floating_point=expr.floating_point,
|
|
1205
|
-
rounding_mode=expr.rounding_mode,
|
|
1206
|
-
**expr.tags,
|
|
1207
|
-
)
|
|
1208
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1209
|
-
|
|
1210
|
-
def _ail_handle_DivMod(self, expr):
|
|
1211
|
-
o0_value = self._expr(expr.operands[0])
|
|
1212
|
-
o1_value = self._expr(expr.operands[1])
|
|
1213
|
-
|
|
1214
|
-
value = self.state.top(expr.bits)
|
|
1215
|
-
if o0_value is None or o1_value is None:
|
|
1216
|
-
new_expr = expr
|
|
1217
|
-
else:
|
|
1218
|
-
o0_expr = o0_value.one_expr
|
|
1219
|
-
o1_expr = o1_value.one_expr
|
|
1220
|
-
new_expr = Expr.BinaryOp(
|
|
1221
|
-
expr.idx,
|
|
1222
|
-
"DivMod",
|
|
1223
|
-
[
|
|
1224
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1225
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1226
|
-
],
|
|
1227
|
-
expr.signed,
|
|
1228
|
-
bits=expr.bits,
|
|
1229
|
-
floating_point=expr.floating_point,
|
|
1230
|
-
rounding_mode=expr.rounding_mode,
|
|
1231
|
-
from_bits=expr.from_bits,
|
|
1232
|
-
to_bits=expr.to_bits,
|
|
1233
|
-
**expr.tags,
|
|
1234
|
-
)
|
|
1235
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1236
|
-
|
|
1237
|
-
def _ail_handle_Mod(self, expr):
|
|
1238
|
-
o0_value = self._expr(expr.operands[0])
|
|
1239
|
-
o1_value = self._expr(expr.operands[1])
|
|
1240
|
-
|
|
1241
|
-
value = self.state.top(expr.bits)
|
|
1242
|
-
if o0_value is None or o1_value is None:
|
|
1243
|
-
new_expr = expr
|
|
1244
|
-
else:
|
|
1245
|
-
o0_expr = o0_value.one_expr
|
|
1246
|
-
o1_expr = o1_value.one_expr
|
|
1247
|
-
new_expr = Expr.BinaryOp(
|
|
1248
|
-
expr.idx,
|
|
1249
|
-
"Mod",
|
|
1250
|
-
[
|
|
1251
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1252
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1253
|
-
],
|
|
1254
|
-
expr.signed,
|
|
1255
|
-
floating_point=expr.floating_point,
|
|
1256
|
-
rounding_mode=expr.rounding_mode,
|
|
1257
|
-
**expr.tags,
|
|
1258
|
-
)
|
|
1259
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1260
|
-
|
|
1261
|
-
def _ail_handle_LogicalAnd(self, expr: Expr.BinaryOp):
|
|
1262
|
-
o0_value = self._expr(expr.operands[0])
|
|
1263
|
-
o1_value = self._expr(expr.operands[1])
|
|
1264
|
-
|
|
1265
|
-
value = self.state.top(expr.bits)
|
|
1266
|
-
if o0_value is None or o1_value is None:
|
|
1267
|
-
new_expr = expr
|
|
1268
|
-
else:
|
|
1269
|
-
o0_expr = o0_value.one_expr
|
|
1270
|
-
o1_expr = o1_value.one_expr
|
|
1271
|
-
|
|
1272
|
-
value = self.state.top(expr.bits)
|
|
1273
|
-
new_expr = Expr.BinaryOp(
|
|
1274
|
-
expr.idx,
|
|
1275
|
-
"LogicalAnd",
|
|
1276
|
-
[
|
|
1277
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1278
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1279
|
-
],
|
|
1280
|
-
expr.signed,
|
|
1281
|
-
**expr.tags,
|
|
1282
|
-
)
|
|
1283
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1284
|
-
|
|
1285
|
-
def _ail_handle_LogicalOr(self, expr: Expr.BinaryOp):
|
|
1286
|
-
o0_value = self._expr(expr.operands[0])
|
|
1287
|
-
o1_value = self._expr(expr.operands[1])
|
|
1288
|
-
|
|
1289
|
-
value = self.state.top(expr.bits)
|
|
1290
|
-
if o0_value is None or o1_value is None:
|
|
1291
|
-
new_expr = expr
|
|
1292
|
-
else:
|
|
1293
|
-
o0_expr = o0_value.one_expr
|
|
1294
|
-
o1_expr = o1_value.one_expr
|
|
1295
|
-
|
|
1296
|
-
value = self.state.top(expr.bits)
|
|
1297
|
-
new_expr = Expr.BinaryOp(
|
|
1298
|
-
expr.idx,
|
|
1299
|
-
"LogicalOr",
|
|
1300
|
-
[
|
|
1301
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1302
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1303
|
-
],
|
|
1304
|
-
expr.signed,
|
|
1305
|
-
**expr.tags,
|
|
1306
|
-
)
|
|
1307
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1308
|
-
|
|
1309
|
-
def _ail_handle_LogicalXor(self, expr: Expr.BinaryOp):
|
|
1310
|
-
o0_value = self._expr(expr.operands[0])
|
|
1311
|
-
o1_value = self._expr(expr.operands[1])
|
|
1312
|
-
|
|
1313
|
-
value = self.state.top(expr.bits)
|
|
1314
|
-
if o0_value is None or o1_value is None:
|
|
1315
|
-
new_expr = expr
|
|
1316
|
-
else:
|
|
1317
|
-
o0_expr = o0_value.one_expr
|
|
1318
|
-
o1_expr = o1_value.one_expr
|
|
1319
|
-
|
|
1320
|
-
value = self.state.top(expr.bits)
|
|
1321
|
-
new_expr = Expr.BinaryOp(
|
|
1322
|
-
expr.idx,
|
|
1323
|
-
"LogicalXor",
|
|
1324
|
-
[
|
|
1325
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1326
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1327
|
-
],
|
|
1328
|
-
expr.signed,
|
|
1329
|
-
**expr.tags,
|
|
1330
|
-
)
|
|
1331
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1332
|
-
|
|
1333
|
-
def _ail_handle_Carry(self, expr: Expr.BinaryOp):
|
|
1334
|
-
o0_value = self._expr(expr.operands[0])
|
|
1335
|
-
o1_value = self._expr(expr.operands[1])
|
|
1336
|
-
|
|
1337
|
-
value = self.state.top(expr.bits)
|
|
1338
|
-
if o0_value is None or o1_value is None:
|
|
1339
|
-
new_expr = expr
|
|
1340
|
-
else:
|
|
1341
|
-
o0_expr = o0_value.one_expr
|
|
1342
|
-
o1_expr = o1_value.one_expr
|
|
1343
|
-
new_expr = Expr.BinaryOp(
|
|
1344
|
-
expr.idx,
|
|
1345
|
-
"Carry",
|
|
1346
|
-
[
|
|
1347
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1348
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1349
|
-
],
|
|
1350
|
-
expr.signed,
|
|
1351
|
-
bits=expr.bits,
|
|
1352
|
-
floating_point=expr.floating_point,
|
|
1353
|
-
rounding_mode=expr.rounding_mode,
|
|
1354
|
-
**expr.tags,
|
|
1355
|
-
)
|
|
1356
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1357
|
-
|
|
1358
|
-
def _ail_handle_SCarry(self, expr: Expr.BinaryOp):
|
|
1359
|
-
o0_value = self._expr(expr.operands[0])
|
|
1360
|
-
o1_value = self._expr(expr.operands[1])
|
|
1361
|
-
|
|
1362
|
-
value = self.state.top(expr.bits)
|
|
1363
|
-
if o0_value is None or o1_value is None:
|
|
1364
|
-
new_expr = expr
|
|
1365
|
-
else:
|
|
1366
|
-
o0_expr = o0_value.one_expr
|
|
1367
|
-
o1_expr = o1_value.one_expr
|
|
1368
|
-
new_expr = Expr.BinaryOp(
|
|
1369
|
-
expr.idx,
|
|
1370
|
-
"SCarry",
|
|
1371
|
-
[
|
|
1372
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1373
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1374
|
-
],
|
|
1375
|
-
expr.signed,
|
|
1376
|
-
bits=expr.bits,
|
|
1377
|
-
floating_point=expr.floating_point,
|
|
1378
|
-
rounding_mode=expr.rounding_mode,
|
|
1379
|
-
**expr.tags,
|
|
1380
|
-
)
|
|
1381
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1382
|
-
|
|
1383
|
-
def _ail_handle_SBorrow(self, expr: Expr.BinaryOp):
|
|
1384
|
-
o0_value = self._expr(expr.operands[0])
|
|
1385
|
-
o1_value = self._expr(expr.operands[1])
|
|
1386
|
-
|
|
1387
|
-
value = self.state.top(expr.bits)
|
|
1388
|
-
if o0_value is None or o1_value is None:
|
|
1389
|
-
new_expr = expr
|
|
1390
|
-
else:
|
|
1391
|
-
o0_expr = o0_value.one_expr
|
|
1392
|
-
o1_expr = o1_value.one_expr
|
|
1393
|
-
new_expr = Expr.BinaryOp(
|
|
1394
|
-
expr.idx,
|
|
1395
|
-
"SBorrow",
|
|
1396
|
-
[
|
|
1397
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1398
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1399
|
-
],
|
|
1400
|
-
expr.signed,
|
|
1401
|
-
bits=expr.bits,
|
|
1402
|
-
floating_point=expr.floating_point,
|
|
1403
|
-
rounding_mode=expr.rounding_mode,
|
|
1404
|
-
**expr.tags,
|
|
1405
|
-
)
|
|
1406
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1407
|
-
|
|
1408
|
-
def _ail_handle_TernaryOp(self, expr: Expr.TernaryOp):
|
|
1409
|
-
o0_value = self._expr(expr.operands[0])
|
|
1410
|
-
o1_value = self._expr(expr.operands[1])
|
|
1411
|
-
o2_value = self._expr(expr.operands[2])
|
|
1412
|
-
|
|
1413
|
-
if o0_value is None or o1_value is None or o2_value is None:
|
|
1414
|
-
new_expr = expr
|
|
1415
|
-
else:
|
|
1416
|
-
o0_expr = o0_value.one_expr
|
|
1417
|
-
o1_expr = o1_value.one_expr
|
|
1418
|
-
o2_expr = o2_value.one_expr
|
|
1419
|
-
new_expr = Expr.TernaryOp(
|
|
1420
|
-
expr.idx,
|
|
1421
|
-
expr.op,
|
|
1422
|
-
[
|
|
1423
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1424
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1425
|
-
o2_expr if o2_expr is not None else expr.operands[2],
|
|
1426
|
-
],
|
|
1427
|
-
bits=expr.bits,
|
|
1428
|
-
**expr.tags,
|
|
1429
|
-
)
|
|
1430
|
-
|
|
1431
|
-
return PropValue.from_value_and_details(self.state.top(expr.bits), expr.size, new_expr, self._codeloc())
|
|
1432
|
-
|
|
1433
|
-
def _ail_handle_Concat(self, expr):
|
|
1434
|
-
o0_value = self._expr(expr.operands[0])
|
|
1435
|
-
o1_value = self._expr(expr.operands[1])
|
|
1436
|
-
|
|
1437
|
-
value = self.state.top(expr.bits)
|
|
1438
|
-
if o0_value is None or o1_value is None:
|
|
1439
|
-
new_expr = expr
|
|
1440
|
-
else:
|
|
1441
|
-
o0_expr = o0_value.one_expr
|
|
1442
|
-
o1_expr = o1_value.one_expr
|
|
1443
|
-
new_expr = Expr.BinaryOp(
|
|
1444
|
-
expr.idx,
|
|
1445
|
-
"Concat",
|
|
1446
|
-
[
|
|
1447
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1448
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1449
|
-
],
|
|
1450
|
-
expr.signed,
|
|
1451
|
-
**expr.tags,
|
|
1452
|
-
)
|
|
1453
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1454
|
-
|
|
1455
|
-
def _ail_handle_ExpCmpNE(self, expr):
|
|
1456
|
-
o0_value = self._expr(expr.operands[0])
|
|
1457
|
-
o1_value = self._expr(expr.operands[1])
|
|
1458
|
-
|
|
1459
|
-
value = self.state.top(expr.bits)
|
|
1460
|
-
if o0_value is None or o1_value is None:
|
|
1461
|
-
new_expr = expr
|
|
1462
|
-
else:
|
|
1463
|
-
o0_expr = o0_value.one_expr
|
|
1464
|
-
o1_expr = o1_value.one_expr
|
|
1465
|
-
new_expr = Expr.BinaryOp(
|
|
1466
|
-
expr.idx,
|
|
1467
|
-
"ExpCmpNE",
|
|
1468
|
-
[
|
|
1469
|
-
o0_expr if o0_expr is not None else expr.operands[0],
|
|
1470
|
-
o1_expr if o1_expr is not None else expr.operands[1],
|
|
1471
|
-
],
|
|
1472
|
-
expr.signed,
|
|
1473
|
-
**expr.tags,
|
|
1474
|
-
)
|
|
1475
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1476
|
-
|
|
1477
|
-
def _ail_handle_Clz(self, expr):
|
|
1478
|
-
o0_value = self._expr(expr.operand)
|
|
1479
|
-
|
|
1480
|
-
value = self.state.top(expr.bits)
|
|
1481
|
-
if o0_value is None:
|
|
1482
|
-
new_expr = expr
|
|
1483
|
-
else:
|
|
1484
|
-
o0_expr = o0_value.one_expr
|
|
1485
|
-
new_expr = Expr.UnaryOp(
|
|
1486
|
-
expr.idx,
|
|
1487
|
-
"Clz",
|
|
1488
|
-
o0_expr if o0_expr is not None else expr.operand,
|
|
1489
|
-
**expr.tags,
|
|
1490
|
-
)
|
|
1491
|
-
return PropValue.from_value_and_details(value, expr.size, new_expr, self._codeloc())
|
|
1492
|
-
|
|
1493
|
-
#
|
|
1494
|
-
# Util methods
|
|
1495
|
-
#
|
|
1496
|
-
|
|
1497
|
-
def is_using_outdated_def(
|
|
1498
|
-
self,
|
|
1499
|
-
expr: Expr.Expression,
|
|
1500
|
-
expr_defat: CodeLocation | None,
|
|
1501
|
-
current_loc: CodeLocation,
|
|
1502
|
-
avoid: Expr.Expression | None = None,
|
|
1503
|
-
) -> tuple[bool, bool]:
|
|
1504
|
-
if self._reaching_definitions is None:
|
|
1505
|
-
l.warning(
|
|
1506
|
-
"Reaching definition information is not provided to propagator. Assume the definition is out-dated."
|
|
1507
|
-
)
|
|
1508
|
-
return True, False
|
|
1509
|
-
|
|
1510
|
-
if expr_defat is None:
|
|
1511
|
-
# the definition originates outside the current node or function
|
|
1512
|
-
l.warning("Unknown where the expression is defined. Assume the definition is out-dated.")
|
|
1513
|
-
return True, False
|
|
1514
|
-
|
|
1515
|
-
from .outdated_definition_walker import OutdatedDefinitionWalker # pylint:disable=import-outside-toplevel
|
|
1516
|
-
|
|
1517
|
-
walker = OutdatedDefinitionWalker(
|
|
1518
|
-
expr,
|
|
1519
|
-
expr_defat,
|
|
1520
|
-
current_loc,
|
|
1521
|
-
self.state,
|
|
1522
|
-
self.arch,
|
|
1523
|
-
avoid=avoid,
|
|
1524
|
-
extract_offset_to_sp=self.extract_offset_to_sp,
|
|
1525
|
-
rda=self._reaching_definitions,
|
|
1526
|
-
)
|
|
1527
|
-
walker.walk_expression(expr)
|
|
1528
|
-
return walker.out_dated, walker.has_avoid
|
|
1529
|
-
|
|
1530
|
-
def should_force_replace(self, stmt: Stmt.Statement, new_expr: Expr.Expression) -> bool:
|
|
1531
|
-
"""
|
|
1532
|
-
Determine if the expression should be replaced.
|
|
1533
|
-
|
|
1534
|
-
We always replace the expression if:
|
|
1535
|
-
|
|
1536
|
-
- the current statement is an indirect jump. this is to ensure the dynamically calculated jump targets are
|
|
1537
|
-
always using the originally defined expressions, which usually leads to better decompilation output.
|
|
1538
|
-
- the current statement is a return to make void functions (even when we incorrectly determine that they return
|
|
1539
|
-
something) look better in general.
|
|
1540
|
-
- the current statement has a shift-right operation and the source expression has a shift-right operation. this
|
|
1541
|
-
is to support the peephole optimizations for division and modulo.
|
|
1542
|
-
|
|
1543
|
-
:param stmt:
|
|
1544
|
-
:param new_expr:
|
|
1545
|
-
:return:
|
|
1546
|
-
"""
|
|
1547
|
-
if isinstance(stmt, (Stmt.Jump, Stmt.Return)):
|
|
1548
|
-
return True
|
|
1549
|
-
|
|
1550
|
-
from angr.analyses.decompiler.counters.expression_counters import (
|
|
1551
|
-
OperatorCounter,
|
|
1552
|
-
) # pylint:disable=wrong-import-position
|
|
1553
|
-
|
|
1554
|
-
octr0 = OperatorCounter(["Shr", "Sar"], stmt)
|
|
1555
|
-
octr1 = OperatorCounter(["Shr", "Sar"], new_expr)
|
|
1556
|
-
return bool(octr0.count >= 1 and octr1.count >= 1 or octr0.count >= 2)
|
|
1557
|
-
|
|
1558
|
-
@staticmethod
|
|
1559
|
-
def has_tmpexpr(expr: Expr.Expression) -> bool:
|
|
1560
|
-
from .tmpvar_finder import TmpvarFinder # pylint:disable=import-outside-toplevel
|
|
1561
|
-
|
|
1562
|
-
return TmpvarFinder(expr).has_tmp
|