angr 9.2.83__py3-none-win_amd64.whl → 9.2.85__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 +1 -1
- angr/analyses/cfg/cfg_base.py +6 -1
- angr/analyses/cfg/cfg_fast.py +32 -10
- angr/analyses/decompiler/clinic.py +204 -4
- angr/analyses/decompiler/condition_processor.py +8 -2
- angr/analyses/decompiler/decompilation_options.py +10 -0
- angr/analyses/decompiler/decompiler.py +19 -17
- angr/analyses/decompiler/goto_manager.py +34 -51
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -5
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +2 -0
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/mod_simplifier.py +2 -0
- angr/analyses/decompiler/optimization_passes/multi_simplifier.py +2 -0
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +131 -3
- angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +3 -3
- angr/analyses/decompiler/optimization_passes/return_duplicator.py +519 -0
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +14 -2
- angr/analyses/decompiler/region_identifier.py +8 -2
- angr/analyses/decompiler/region_simplifiers/goto.py +5 -4
- angr/analyses/decompiler/structured_codegen/c.py +66 -5
- angr/analyses/decompiler/structuring/phoenix.py +3 -1
- angr/analyses/decompiler/structuring/structurer_nodes.py +11 -5
- angr/analyses/decompiler/utils.py +50 -0
- angr/analyses/disassembly.py +10 -3
- angr/analyses/propagator/engine_ail.py +125 -0
- angr/analyses/reaching_definitions/engine_ail.py +36 -2
- angr/analyses/reaching_definitions/rd_initializer.py +15 -1
- angr/analyses/reaching_definitions/rd_state.py +9 -4
- angr/analyses/stack_pointer_tracker.py +10 -17
- angr/analyses/variable_recovery/engine_ail.py +27 -1
- angr/angrdb/serializers/loader.py +10 -3
- angr/calling_conventions.py +2 -0
- angr/engines/pcode/behavior.py +7 -2
- angr/engines/pcode/cc.py +1 -0
- angr/engines/pcode/emulate.py +144 -104
- angr/engines/pcode/lifter.py +135 -79
- angr/knowledge_plugins/functions/function.py +28 -0
- angr/knowledge_plugins/functions/function_manager.py +48 -5
- angr/knowledge_plugins/propagations/states.py +14 -0
- angr/lib/angr_native.dll +0 -0
- angr/procedures/cgc/deallocate.py +5 -2
- angr/procedures/posix/gethostbyname.py +23 -8
- angr/project.py +4 -0
- angr/simos/__init__.py +2 -0
- angr/simos/simos.py +1 -0
- angr/simos/snimmuc_nxp.py +152 -0
- angr/state_plugins/history.py +3 -1
- angr/utils/graph.py +20 -18
- {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/METADATA +9 -8
- {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/RECORD +61 -59
- tests/analyses/cfg/test_cfg_rust_got_resolution.py +2 -1
- tests/analyses/cfg/test_jumptables.py +2 -1
- tests/analyses/decompiler/test_decompiler.py +155 -103
- tests/engines/pcode/test_emulate.py +607 -0
- tests/engines/test_java.py +609 -663
- tests/knowledge_plugins/functions/test_function_manager.py +13 -0
- tests/serialization/test_db.py +30 -0
- angr/analyses/decompiler/optimization_passes/eager_returns.py +0 -285
- {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/LICENSE +0 -0
- {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/WHEEL +0 -0
- {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/entry_points.txt +0 -0
- {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/top_level.txt +0 -0
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
from typing import Optional, TYPE_CHECKING
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
|
-
import claripy
|
|
6
5
|
import ailment
|
|
6
|
+
import claripy
|
|
7
|
+
from unique_log_filter import UniqueLogFilter
|
|
7
8
|
|
|
8
9
|
from ...calling_conventions import SimRegArg
|
|
9
10
|
from ...sim_type import SimTypeFunction
|
|
@@ -17,6 +18,7 @@ if TYPE_CHECKING:
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
l = logging.getLogger(name=__name__)
|
|
21
|
+
l.addFilter(UniqueLogFilter())
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
class SimEngineVRAIL(
|
|
@@ -610,6 +612,30 @@ class SimEngineVRAIL(
|
|
|
610
612
|
r = self.state.top(expr.bits)
|
|
611
613
|
return RichR(r, typevar=r0.typevar)
|
|
612
614
|
|
|
615
|
+
def _ail_handle_LogicalAnd(self, expr):
|
|
616
|
+
arg0, arg1 = expr.operands
|
|
617
|
+
|
|
618
|
+
r0 = self._expr(arg0)
|
|
619
|
+
_ = self._expr(arg1)
|
|
620
|
+
r = self.state.top(expr.bits)
|
|
621
|
+
return RichR(r, typevar=r0.typevar)
|
|
622
|
+
|
|
623
|
+
def _ail_handle_LogicalOr(self, expr):
|
|
624
|
+
arg0, arg1 = expr.operands
|
|
625
|
+
|
|
626
|
+
r0 = self._expr(arg0)
|
|
627
|
+
_ = self._expr(arg1)
|
|
628
|
+
r = self.state.top(expr.bits)
|
|
629
|
+
return RichR(r, typevar=r0.typevar)
|
|
630
|
+
|
|
631
|
+
def _ail_handle_LogicalXor(self, expr):
|
|
632
|
+
arg0, arg1 = expr.operands
|
|
633
|
+
|
|
634
|
+
r0 = self._expr(arg0)
|
|
635
|
+
_ = self._expr(arg1)
|
|
636
|
+
r = self.state.top(expr.bits)
|
|
637
|
+
return RichR(r, typevar=r0.typevar)
|
|
638
|
+
|
|
613
639
|
def _ail_handle_Rol(self, expr):
|
|
614
640
|
arg0, arg1 = expr.operands
|
|
615
641
|
|
|
@@ -3,7 +3,7 @@ from typing import List
|
|
|
3
3
|
|
|
4
4
|
import cle
|
|
5
5
|
|
|
6
|
-
from ...errors import AngrCorruptDBError
|
|
6
|
+
from ...errors import AngrCorruptDBError, AngrDBError
|
|
7
7
|
from ..models import DbObject
|
|
8
8
|
|
|
9
9
|
|
|
@@ -34,13 +34,20 @@ class LoaderSerializer:
|
|
|
34
34
|
# it exists. skip.
|
|
35
35
|
continue
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
try:
|
|
38
|
+
content = obj.cached_content if hasattr(obj, "cached_content") else None
|
|
39
|
+
if content is None:
|
|
40
|
+
# fall back to loading the file again from disk
|
|
41
|
+
with open(obj.binary, "rb") as the_file:
|
|
42
|
+
content = the_file.read()
|
|
43
|
+
except OSError as ex:
|
|
44
|
+
raise AngrDBError(f"Failed to load content for file {obj.binary}.") from ex
|
|
38
45
|
|
|
39
46
|
# save the object
|
|
40
47
|
o = DbObject(
|
|
41
48
|
main_object=loader.main_object is obj,
|
|
42
49
|
path=obj.binary,
|
|
43
|
-
content=
|
|
50
|
+
content=content,
|
|
44
51
|
backend=LoaderSerializer.backend2name.get(obj.__class__),
|
|
45
52
|
backend_args="", # TODO: We will need support from CLE to store loader arguments
|
|
46
53
|
)
|
angr/calling_conventions.py
CHANGED
|
@@ -6,6 +6,7 @@ from collections import defaultdict
|
|
|
6
6
|
import claripy
|
|
7
7
|
import archinfo
|
|
8
8
|
from archinfo import RegisterName
|
|
9
|
+
from unique_log_filter import UniqueLogFilter
|
|
9
10
|
|
|
10
11
|
from .errors import AngrTypeError
|
|
11
12
|
from .sim_type import (
|
|
@@ -32,6 +33,7 @@ from .state_plugins.sim_action_object import SimActionObject
|
|
|
32
33
|
from .engines.soot.engine import SootMixin
|
|
33
34
|
|
|
34
35
|
l = logging.getLogger(name=__name__)
|
|
36
|
+
l.addFilter(UniqueLogFilter())
|
|
35
37
|
|
|
36
38
|
|
|
37
39
|
class PointerWrapper:
|
angr/engines/pcode/behavior.py
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import operator
|
|
2
2
|
from typing import Callable, Iterable, Tuple
|
|
3
3
|
|
|
4
|
-
from pypcode import OpCode
|
|
5
4
|
import claripy
|
|
6
5
|
from claripy.ast.bv import BV
|
|
7
6
|
|
|
8
7
|
from ...errors import AngrError
|
|
9
8
|
|
|
9
|
+
try:
|
|
10
|
+
from pypcode import OpCode
|
|
11
|
+
except ImportError:
|
|
12
|
+
OpCode = None
|
|
13
|
+
|
|
10
14
|
# pylint:disable=abstract-method
|
|
11
15
|
|
|
12
16
|
|
|
@@ -889,7 +893,8 @@ class BehaviorFactory:
|
|
|
889
893
|
|
|
890
894
|
def __init__(self):
|
|
891
895
|
self._behaviors = {}
|
|
892
|
-
|
|
896
|
+
if OpCode:
|
|
897
|
+
self._register_behaviors()
|
|
893
898
|
|
|
894
899
|
def get_behavior_for_opcode(self, opcode: int) -> OpBehavior:
|
|
895
900
|
return self._behaviors[opcode]
|
angr/engines/pcode/cc.py
CHANGED
|
@@ -98,6 +98,7 @@ def register_pcode_arch_default_cc(arch: ArchPcode):
|
|
|
98
98
|
"68000:BE:32:default": SimCCM68k,
|
|
99
99
|
"RISCV:LE:64:RV64G": SimCCRISCV,
|
|
100
100
|
"RISCV:LE:64:RV64GC": SimCCRISCV,
|
|
101
|
+
"sparc:BE:32:default": SimCCSPARC,
|
|
101
102
|
"sparc:BE:64:default": SimCCSPARC,
|
|
102
103
|
"SuperH4:LE:32:default": SimCCSH4,
|
|
103
104
|
"pa-risc:BE:32:default": SimCCPARISC,
|
angr/engines/pcode/emulate.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional
|
|
3
3
|
|
|
4
|
-
from pypcode import OpCode, Varnode, PcodeOp, Translation
|
|
5
4
|
import claripy
|
|
6
5
|
from claripy.ast.bv import BV
|
|
7
6
|
|
|
@@ -12,6 +11,11 @@ from .behavior import OpBehavior
|
|
|
12
11
|
from ...errors import AngrError
|
|
13
12
|
from ...state_plugins.inspect import BP_BEFORE, BP_AFTER
|
|
14
13
|
|
|
14
|
+
try:
|
|
15
|
+
from pypcode import OpCode, Varnode, PcodeOp
|
|
16
|
+
except ImportError:
|
|
17
|
+
pass
|
|
18
|
+
|
|
15
19
|
|
|
16
20
|
l = logging.getLogger(__name__)
|
|
17
21
|
|
|
@@ -21,71 +25,69 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
21
25
|
Mixin for p-code execution.
|
|
22
26
|
"""
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
_current_behavior:
|
|
28
|
+
_current_op: Optional["PcodeOp"]
|
|
29
|
+
_current_op_idx: int
|
|
30
|
+
_current_behavior: Optional[OpBehavior]
|
|
27
31
|
|
|
28
32
|
def __init__(self, *args, **kwargs):
|
|
29
33
|
super().__init__(*args, **kwargs)
|
|
30
|
-
self._current_ins = None
|
|
31
34
|
self._current_op = None
|
|
32
35
|
self._current_behavior = None
|
|
33
|
-
self._special_op_handlers = {
|
|
34
|
-
OpCode.LOAD: self._execute_load,
|
|
35
|
-
OpCode.STORE: self._execute_store,
|
|
36
|
-
OpCode.BRANCH: self._execute_branch,
|
|
37
|
-
OpCode.CBRANCH: self._execute_cbranch,
|
|
38
|
-
OpCode.BRANCHIND: self._execute_branchind,
|
|
39
|
-
OpCode.CALL: self._execute_call,
|
|
40
|
-
OpCode.CALLIND: self._execute_callind,
|
|
41
|
-
OpCode.CALLOTHER: self._execute_callother,
|
|
42
|
-
OpCode.RETURN: self._execute_ret,
|
|
43
|
-
OpCode.MULTIEQUAL: self._execute_multiequal,
|
|
44
|
-
OpCode.INDIRECT: self._execute_indirect,
|
|
45
|
-
OpCode.SEGMENTOP: self._execute_segment_op,
|
|
46
|
-
OpCode.CPOOLREF: self._execute_cpool_ref,
|
|
47
|
-
OpCode.NEW: self._execute_new,
|
|
48
|
-
}
|
|
49
36
|
|
|
50
37
|
def handle_pcode_block(self, irsb: IRSB) -> None:
|
|
51
38
|
"""
|
|
52
|
-
Execute a single IRSB.
|
|
39
|
+
Execute a single P-Code IRSB.
|
|
53
40
|
|
|
54
41
|
:param irsb: Block to be executed.
|
|
55
42
|
"""
|
|
56
43
|
self.irsb = irsb
|
|
44
|
+
|
|
57
45
|
# Hack on a handler here to track whether exit has been handled or not
|
|
58
46
|
# FIXME: Vex models this as a known exit statement, which we should also
|
|
59
47
|
# do here. For now, handle it this way.
|
|
60
48
|
self.state.scratch.exit_handled = False
|
|
49
|
+
self._pcode_tmps = {}
|
|
50
|
+
|
|
51
|
+
fallthru_addr = self.irsb.addr
|
|
52
|
+
self.state.scratch.ins_addr = self.irsb.addr
|
|
53
|
+
last_imark_op_idx = 0
|
|
54
|
+
|
|
55
|
+
# Note: start_op_idx is instruction relative
|
|
56
|
+
start_op_idx = self.state.scratch.statement_offset
|
|
57
|
+
self.state.scratch.statement_offset = 0
|
|
58
|
+
assert start_op_idx == 0, "FIXME: Test statement_offset behavior"
|
|
59
|
+
|
|
60
|
+
for op_idx, op in enumerate(irsb._ops[start_op_idx:]): # FIXME: Shouldn't use protected members of IRSB
|
|
61
|
+
op_idx += start_op_idx
|
|
62
|
+
|
|
63
|
+
if op.opcode == OpCode.IMARK:
|
|
64
|
+
if op_idx > 0:
|
|
65
|
+
# Trigger BP for previous instruction once we reach next IMARK
|
|
66
|
+
self.state._inspect("instruction", BP_AFTER)
|
|
67
|
+
|
|
68
|
+
decode_addr = op.inputs[0].offset
|
|
69
|
+
last_imark_op_idx = op_idx
|
|
70
|
+
|
|
71
|
+
# Note: instruction BP will not be triggered on p-code-relative jumps
|
|
72
|
+
l.debug("Executing machine instruction @ %#x", decode_addr)
|
|
73
|
+
for vn in op.inputs:
|
|
74
|
+
self.state._inspect("instruction", BP_BEFORE, instruction=vn.offset)
|
|
75
|
+
|
|
76
|
+
# FIXME: Hacking this on here but ideally should use "scratch".
|
|
77
|
+
self._pcode_tmps = {} # FIXME: Consider alignment requirements
|
|
78
|
+
self.state.scratch.ins_addr = decode_addr
|
|
79
|
+
fallthru_addr = op.inputs[-1].offset + op.inputs[-1].size
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
self._current_op = op
|
|
83
|
+
self._current_op_idx = op_idx - last_imark_op_idx
|
|
84
|
+
l.debug("Executing P-Code op: %s", self._current_op)
|
|
85
|
+
self._execute_current_op()
|
|
86
|
+
self._current_op = None
|
|
61
87
|
|
|
62
|
-
|
|
63
|
-
for i, ins in enumerate(irsb._instructions):
|
|
64
|
-
l.debug(
|
|
65
|
-
"Executing machine instruction @ %#x (%d of %d)", ins.address.offset, i + 1, len(irsb._instructions)
|
|
66
|
-
)
|
|
67
|
-
|
|
68
|
-
# Execute a single instruction of the emulated machine
|
|
69
|
-
self._current_ins = ins
|
|
70
|
-
self.state.scratch.ins_addr = self._current_ins.address.offset
|
|
71
|
-
|
|
72
|
-
# FIXME: Hacking this on here but ideally should use "scratch".
|
|
73
|
-
self._pcode_tmps = {} # FIXME: Consider alignment requirements
|
|
74
|
-
|
|
75
|
-
self.state._inspect("instruction", BP_BEFORE, instruction=self._current_ins.address.offset)
|
|
76
|
-
offset = self.state.scratch.statement_offset
|
|
77
|
-
self.state.scratch.statement_offset = 0
|
|
78
|
-
for op in self._current_ins.ops[offset:]:
|
|
79
|
-
self._current_op = op
|
|
80
|
-
self._current_behavior = irsb.behaviors.get_behavior_for_opcode(self._current_op.opcode)
|
|
81
|
-
l.debug("Executing p-code op: %s", self._current_op)
|
|
82
|
-
self._execute_current_op()
|
|
88
|
+
if self.state.scratch.statement_offset == 0:
|
|
83
89
|
self.state._inspect("instruction", BP_AFTER)
|
|
84
90
|
|
|
85
|
-
self._current_op = None
|
|
86
|
-
self._current_behavior = None
|
|
87
|
-
fallthru_addr = ins.address.offset + ins.length
|
|
88
|
-
|
|
89
91
|
if not self.state.scratch.exit_handled:
|
|
90
92
|
self.successors.add_successor(
|
|
91
93
|
self.state,
|
|
@@ -100,16 +102,34 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
100
102
|
"""
|
|
101
103
|
Execute the current p-code operation.
|
|
102
104
|
"""
|
|
103
|
-
|
|
105
|
+
self._current_behavior = self.irsb.behaviors.get_behavior_for_opcode(self._current_op.opcode)
|
|
104
106
|
|
|
105
107
|
if self._current_behavior.is_special:
|
|
106
|
-
|
|
108
|
+
handlers = {
|
|
109
|
+
OpCode.LOAD: self._execute_load,
|
|
110
|
+
OpCode.STORE: self._execute_store,
|
|
111
|
+
OpCode.BRANCH: self._execute_branch,
|
|
112
|
+
OpCode.CBRANCH: self._execute_cbranch,
|
|
113
|
+
OpCode.BRANCHIND: self._execute_branchind,
|
|
114
|
+
OpCode.CALL: self._execute_call,
|
|
115
|
+
OpCode.CALLIND: self._execute_callind,
|
|
116
|
+
OpCode.CALLOTHER: self._execute_callother,
|
|
117
|
+
OpCode.RETURN: self._execute_ret,
|
|
118
|
+
OpCode.MULTIEQUAL: self._execute_multiequal,
|
|
119
|
+
OpCode.INDIRECT: self._execute_indirect,
|
|
120
|
+
OpCode.SEGMENTOP: self._execute_segment_op,
|
|
121
|
+
OpCode.CPOOLREF: self._execute_cpool_ref,
|
|
122
|
+
OpCode.NEW: self._execute_new,
|
|
123
|
+
}
|
|
124
|
+
handlers[self._current_behavior.opcode]()
|
|
107
125
|
elif self._current_behavior.is_unary:
|
|
108
126
|
self._execute_unary()
|
|
109
127
|
else:
|
|
110
128
|
self._execute_binary()
|
|
111
129
|
|
|
112
|
-
|
|
130
|
+
self._current_behavior = None
|
|
131
|
+
|
|
132
|
+
def _map_register_name(self, varnode: "Varnode") -> int:
|
|
113
133
|
"""
|
|
114
134
|
Map SLEIGH register offset to ArchInfo register offset based on name.
|
|
115
135
|
|
|
@@ -118,7 +138,7 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
118
138
|
"""
|
|
119
139
|
# FIXME: Will need performance optimization
|
|
120
140
|
# FIXME: Should not get trans object this way. There should be a faster mapping method than going through trans
|
|
121
|
-
reg_name = varnode.
|
|
141
|
+
reg_name = varnode.getRegisterName()
|
|
122
142
|
try:
|
|
123
143
|
reg_offset = self.state.project.arch.get_register_offset(reg_name.lower())
|
|
124
144
|
l.debug("Mapped register '%s' to offset %x", reg_name, reg_offset)
|
|
@@ -143,7 +163,7 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
143
163
|
else:
|
|
144
164
|
return v_in
|
|
145
165
|
|
|
146
|
-
def _set_value(self, varnode: Varnode, value: BV) -> None:
|
|
166
|
+
def _set_value(self, varnode: "Varnode", value: BV) -> None:
|
|
147
167
|
"""
|
|
148
168
|
Store a value for a given varnode.
|
|
149
169
|
|
|
@@ -153,29 +173,28 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
153
173
|
:param varnode: Varnode to store into.
|
|
154
174
|
:param value: Value to store.
|
|
155
175
|
"""
|
|
156
|
-
space_name = varnode.space.name
|
|
157
|
-
|
|
158
176
|
# FIXME: Consider moving into behavior.py
|
|
159
177
|
value = self._adjust_value_size(varnode.size * 8, value)
|
|
160
178
|
assert varnode.size * 8 == value.size()
|
|
161
179
|
|
|
162
|
-
|
|
163
|
-
|
|
180
|
+
space = varnode.space
|
|
181
|
+
l.debug("Storing %s %x %s %d", space.name, varnode.offset, value, varnode.size)
|
|
182
|
+
if space.name == "register":
|
|
164
183
|
self.state.registers.store(
|
|
165
184
|
self._map_register_name(varnode), value, size=varnode.size, endness=self.project.arch.register_endness
|
|
166
185
|
)
|
|
167
186
|
|
|
168
|
-
elif
|
|
187
|
+
elif space.name == "unique":
|
|
169
188
|
self._pcode_tmps[varnode.offset] = value
|
|
170
189
|
|
|
171
|
-
elif
|
|
190
|
+
elif space.name in ("ram", "mem"):
|
|
172
191
|
l.debug("Storing %s to offset %s", value, varnode.offset)
|
|
173
192
|
self.state.memory.store(varnode.offset, value, endness=self.project.arch.memory_endness)
|
|
174
193
|
|
|
175
194
|
else:
|
|
176
|
-
raise AngrError(f"Attempted write to unhandled address space '{
|
|
195
|
+
raise AngrError(f"Attempted write to unhandled address space '{space.name}'")
|
|
177
196
|
|
|
178
|
-
def _get_value(self, varnode: Varnode) -> BV:
|
|
197
|
+
def _get_value(self, varnode: "Varnode") -> BV:
|
|
179
198
|
"""
|
|
180
199
|
Get a value for a given varnode.
|
|
181
200
|
|
|
@@ -218,54 +237,77 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
218
237
|
"""
|
|
219
238
|
Execute the unary behavior of the current op.
|
|
220
239
|
"""
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
out = self._current_behavior.evaluate_unary(self._current_op.output.size, self._current_op.inputs[0].size, in1)
|
|
224
|
-
l.debug("out unary = %s", out)
|
|
240
|
+
in0 = self._get_value(self._current_op.inputs[0])
|
|
241
|
+
out = self._current_behavior.evaluate_unary(self._current_op.output.size, self._current_op.inputs[0].size, in0)
|
|
225
242
|
self._set_value(self._current_op.output, out)
|
|
226
243
|
|
|
227
244
|
def _execute_binary(self) -> None:
|
|
228
245
|
"""
|
|
229
246
|
Execute the binary behavior of the current op.
|
|
230
247
|
"""
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
248
|
+
|
|
249
|
+
# Validate output
|
|
250
|
+
assert self._current_op.output is not None
|
|
251
|
+
if (
|
|
252
|
+
self._current_op.opcode
|
|
253
|
+
in [
|
|
254
|
+
OpCode.INT_LESS,
|
|
255
|
+
OpCode.INT_SLESS,
|
|
256
|
+
OpCode.INT_LESSEQUAL,
|
|
257
|
+
OpCode.INT_SLESSEQUAL,
|
|
258
|
+
OpCode.INT_EQUAL,
|
|
259
|
+
OpCode.INT_NOTEQUAL,
|
|
260
|
+
]
|
|
261
|
+
and self._current_op.output.size != 1
|
|
262
|
+
):
|
|
263
|
+
l.warning(
|
|
264
|
+
"SLEIGH spec states output size for op %s must be 1, but op has %d",
|
|
265
|
+
self._current_op.opcode.__name__,
|
|
266
|
+
self._current_op.output.size,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
# Validate ops that mandate inputs of equal sizes
|
|
270
|
+
# Validate ops that mandate output of greater size
|
|
271
|
+
|
|
272
|
+
# Validate inputs
|
|
273
|
+
|
|
274
|
+
in0 = self._get_value(self._current_op.inputs[0])
|
|
275
|
+
in1 = self._get_value(self._current_op.inputs[1])
|
|
235
276
|
out = self._current_behavior.evaluate_binary(
|
|
236
|
-
self._current_op.output.size, self._current_op.inputs[0].size,
|
|
277
|
+
self._current_op.output.size, self._current_op.inputs[0].size, in0, in1
|
|
237
278
|
)
|
|
238
|
-
l.debug("out binary = %s", out)
|
|
239
279
|
self._set_value(self._current_op.output, out)
|
|
240
280
|
|
|
241
281
|
def _execute_load(self) -> None:
|
|
242
282
|
"""
|
|
243
283
|
Execute a p-code load operation.
|
|
244
284
|
"""
|
|
245
|
-
|
|
246
|
-
|
|
285
|
+
space = self._current_op.inputs[0].getSpaceFromConst()
|
|
286
|
+
offset = self._get_value(self._current_op.inputs[1])
|
|
247
287
|
out = self._current_op.output
|
|
248
|
-
if
|
|
249
|
-
res = self.state.memory.load(
|
|
250
|
-
elif
|
|
251
|
-
res = self.state.registers.load(
|
|
288
|
+
if space.name in ("ram", "mem"):
|
|
289
|
+
res = self.state.memory.load(offset, out.size, endness=self.project.arch.memory_endness)
|
|
290
|
+
elif space.name in "register":
|
|
291
|
+
res = self.state.registers.load(offset, size=out.size, endness=self.project.arch.register_endness)
|
|
252
292
|
else:
|
|
253
293
|
raise AngrError("Load from unhandled address space")
|
|
254
|
-
l.debug("Loaded %s from offset %s", res,
|
|
294
|
+
l.debug("Loaded %s from offset %s", res, offset)
|
|
255
295
|
self._set_value(out, res)
|
|
256
296
|
|
|
297
|
+
# CHECKME: wordsize condition in cpuid load
|
|
298
|
+
|
|
257
299
|
def _execute_store(self) -> None:
|
|
258
300
|
"""
|
|
259
301
|
Execute a p-code store operation.
|
|
260
302
|
"""
|
|
261
|
-
|
|
262
|
-
|
|
303
|
+
space = self._current_op.inputs[0].getSpaceFromConst()
|
|
304
|
+
offset = self._get_value(self._current_op.inputs[1])
|
|
263
305
|
data = self._get_value(self._current_op.inputs[2])
|
|
264
|
-
l.debug("Storing %s at offset %s", data,
|
|
265
|
-
if
|
|
266
|
-
self.state.memory.store(
|
|
267
|
-
elif
|
|
268
|
-
self.state.registers.store(
|
|
306
|
+
l.debug("Storing %s at offset %s", data, offset)
|
|
307
|
+
if space.name in ("ram", "mem"):
|
|
308
|
+
self.state.memory.store(offset, data, endness=self.project.arch.memory_endness)
|
|
309
|
+
elif space.name == "register":
|
|
310
|
+
self.state.registers.store(offset, data, endness=self.project.arch.register_endness)
|
|
269
311
|
else:
|
|
270
312
|
raise AngrError("Store to unhandled address space")
|
|
271
313
|
|
|
@@ -273,12 +315,13 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
273
315
|
"""
|
|
274
316
|
Execute a p-code branch operation.
|
|
275
317
|
"""
|
|
276
|
-
|
|
277
|
-
if
|
|
318
|
+
dest = self._current_op.inputs[0]
|
|
319
|
+
if dest.space.name == "const":
|
|
320
|
+
# P-Code-relative branch
|
|
278
321
|
expr = self.state.scratch.ins_addr
|
|
279
|
-
self.state.scratch.statement_offset =
|
|
322
|
+
self.state.scratch.statement_offset = self._current_op_idx + dest.offset
|
|
280
323
|
else:
|
|
281
|
-
expr =
|
|
324
|
+
expr = dest.offset
|
|
282
325
|
|
|
283
326
|
self.successors.add_successor(
|
|
284
327
|
self.state,
|
|
@@ -297,13 +340,14 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
297
340
|
"""
|
|
298
341
|
exit_state = self.state.copy()
|
|
299
342
|
cond = self._get_value(self._current_op.inputs[1])
|
|
300
|
-
|
|
343
|
+
dest = self._current_op.inputs[0]
|
|
301
344
|
|
|
302
|
-
if
|
|
345
|
+
if dest.space.name == "const":
|
|
346
|
+
# P-Code-relative branch
|
|
303
347
|
expr = exit_state.scratch.ins_addr
|
|
304
|
-
exit_state.scratch.statement_offset =
|
|
348
|
+
exit_state.scratch.statement_offset = self._current_op_idx + dest.offset
|
|
305
349
|
else:
|
|
306
|
-
expr =
|
|
350
|
+
expr = dest.offset
|
|
307
351
|
|
|
308
352
|
self.successors.add_successor(
|
|
309
353
|
exit_state,
|
|
@@ -323,11 +367,9 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
323
367
|
"""
|
|
324
368
|
Execute a p-code return operation.
|
|
325
369
|
"""
|
|
326
|
-
ret_addr = self._get_value(self._current_op.inputs[0])
|
|
327
|
-
|
|
328
370
|
self.successors.add_successor(
|
|
329
371
|
self.state,
|
|
330
|
-
|
|
372
|
+
self._get_value(self._current_op.inputs[0]),
|
|
331
373
|
self.state.scratch.guard,
|
|
332
374
|
"Ijk_Ret",
|
|
333
375
|
exit_stmt_idx=DEFAULT_STATEMENT,
|
|
@@ -340,11 +382,9 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
340
382
|
"""
|
|
341
383
|
Execute a p-code indirect branch operation.
|
|
342
384
|
"""
|
|
343
|
-
expr = self._get_value(self._current_op.inputs[0])
|
|
344
|
-
|
|
345
385
|
self.successors.add_successor(
|
|
346
386
|
self.state,
|
|
347
|
-
|
|
387
|
+
self._get_value(self._current_op.inputs[0]),
|
|
348
388
|
self.state.scratch.guard,
|
|
349
389
|
"Ijk_Boring",
|
|
350
390
|
exit_stmt_idx=DEFAULT_STATEMENT,
|
|
@@ -357,11 +397,13 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
357
397
|
"""
|
|
358
398
|
Execute a p-code call operation.
|
|
359
399
|
"""
|
|
360
|
-
|
|
400
|
+
|
|
401
|
+
# FIXME: Spec claims CALL is semantically equivalent to BRANCH. But are p-code relative calls allowed? We assume
|
|
402
|
+
# not.
|
|
361
403
|
|
|
362
404
|
self.successors.add_successor(
|
|
363
405
|
self.state.copy(), # FIXME: Check extra processing after call
|
|
364
|
-
|
|
406
|
+
self._current_op.inputs[0].offset,
|
|
365
407
|
self.state.scratch.guard,
|
|
366
408
|
"Ijk_Call",
|
|
367
409
|
exit_stmt_idx=DEFAULT_STATEMENT,
|
|
@@ -374,11 +416,9 @@ class PcodeEmulatorMixin(SimEngineBase):
|
|
|
374
416
|
"""
|
|
375
417
|
Execute a p-code indirect call operation.
|
|
376
418
|
"""
|
|
377
|
-
expr = self._get_value(self._current_op.inputs[0])
|
|
378
|
-
|
|
379
419
|
self.successors.add_successor(
|
|
380
420
|
self.state,
|
|
381
|
-
|
|
421
|
+
self._get_value(self._current_op.inputs[0]),
|
|
382
422
|
self.state.scratch.guard,
|
|
383
423
|
"Ijk_Call",
|
|
384
424
|
exit_stmt_idx=DEFAULT_STATEMENT,
|