angr 9.2.138__py3-none-macosx_11_0_arm64.whl → 9.2.139__py3-none-macosx_11_0_arm64.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/calling_convention/fact_collector.py +59 -12
- angr/analyses/calling_convention/utils.py +2 -2
- angr/analyses/cfg/cfg_fast.py +12 -4
- angr/analyses/decompiler/ail_simplifier.py +14 -3
- angr/analyses/decompiler/block_simplifier.py +0 -2
- angr/analyses/decompiler/callsite_maker.py +80 -14
- angr/analyses/decompiler/clinic.py +31 -37
- angr/analyses/decompiler/condition_processor.py +2 -2
- angr/analyses/decompiler/decompiler.py +2 -0
- angr/analyses/decompiler/dephication/rewriting_engine.py +16 -7
- angr/analyses/decompiler/optimization_passes/__init__.py +3 -0
- angr/analyses/decompiler/optimization_passes/condition_constprop.py +149 -0
- angr/analyses/decompiler/optimization_passes/deadblock_remover.py +12 -3
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +5 -2
- angr/analyses/decompiler/optimization_passes/return_duplicator_base.py +15 -7
- angr/analyses/decompiler/optimization_passes/return_duplicator_high.py +7 -10
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +12 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +61 -25
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_shifts.py +50 -1
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/region_simplifiers/region_simplifier.py +4 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +20 -2
- angr/analyses/decompiler/ssailification/traversal_engine.py +4 -3
- angr/analyses/decompiler/structured_codegen/c.py +10 -3
- angr/analyses/decompiler/structuring/dream.py +7 -2
- angr/analyses/decompiler/structuring/phoenix.py +101 -49
- angr/analyses/decompiler/structuring/structurer_base.py +85 -36
- angr/analyses/decompiler/structuring/structurer_nodes.py +3 -1
- angr/analyses/deobfuscator/api_obf_finder.py +6 -1
- angr/analyses/deobfuscator/api_obf_type2_finder.py +158 -0
- angr/analyses/s_propagator.py +127 -50
- angr/analyses/s_reaching_definitions/s_rda_view.py +2 -2
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +3 -1
- angr/analyses/variable_recovery/engine_ail.py +1 -1
- angr/analyses/variable_recovery/engine_base.py +55 -62
- angr/analyses/variable_recovery/engine_vex.py +1 -1
- angr/analyses/variable_recovery/irsb_scanner.py +2 -2
- angr/calling_conventions.py +66 -9
- angr/engines/engine.py +2 -18
- angr/engines/light/engine.py +3 -8
- angr/engines/pcode/emulate.py +2 -2
- angr/engines/pcode/lifter.py +2 -2
- angr/engines/successors.py +1 -8
- angr/engines/vex/lifter.py +2 -2
- angr/engines/vex/light/light.py +2 -2
- angr/knowledge_plugins/cfg/cfg_model.py +3 -2
- angr/knowledge_plugins/labels.py +2 -2
- angr/knowledge_plugins/obfuscations.py +1 -0
- angr/knowledge_plugins/xrefs/xref_manager.py +4 -0
- angr/lib/angr_native.dylib +0 -0
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/METADATA +6 -6
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/RECORD +59 -57
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/LICENSE +0 -0
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/WHEEL +0 -0
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/entry_points.txt +0 -0
- {angr-9.2.138.dist-info → angr-9.2.139.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# pylint:disable=too-many-boolean-expressions
|
|
1
2
|
from __future__ import annotations
|
|
2
3
|
from typing import Any
|
|
3
4
|
|
|
@@ -332,6 +333,9 @@ class FactCollector(Analysis):
|
|
|
332
333
|
cc_cls = default_cc(
|
|
333
334
|
self.project.arch.name, platform=self.project.simos.name if self.project.simos is not None else None
|
|
334
335
|
)
|
|
336
|
+
if cc_cls is None:
|
|
337
|
+
# don't know what the calling convention may be... give up
|
|
338
|
+
return
|
|
335
339
|
cc = cc_cls(self.project.arch)
|
|
336
340
|
if isinstance(cc.RETURN_VAL, SimRegArg):
|
|
337
341
|
retreg_offset = cc.RETURN_VAL.check_offset(self.project.arch)
|
|
@@ -401,6 +405,16 @@ class FactCollector(Analysis):
|
|
|
401
405
|
func_graph = self.function.transition_graph
|
|
402
406
|
callee_restored_regs = set()
|
|
403
407
|
|
|
408
|
+
sp_masks = {
|
|
409
|
+
0xFFFFFFFE,
|
|
410
|
+
0xFFFFFFFC,
|
|
411
|
+
0xFFFFFFF8,
|
|
412
|
+
0xFFFFFFF0,
|
|
413
|
+
0xFFFFFFFF_FFFFFFFE,
|
|
414
|
+
0xFFFFFFFF_FFFFFFFC,
|
|
415
|
+
0xFFFFFFFF_FFFFFFF8,
|
|
416
|
+
0xFFFFFFFF_FFFFFFF0,
|
|
417
|
+
}
|
|
404
418
|
for endpoint in self.function.endpoints:
|
|
405
419
|
traversed = set()
|
|
406
420
|
queue: list[tuple[int, BlockNode | HookNode]] = [(0, endpoint)]
|
|
@@ -434,17 +448,29 @@ class FactCollector(Analysis):
|
|
|
434
448
|
tmps[stmt.tmp] = "stack_value"
|
|
435
449
|
elif isinstance(stmt.data, pyvex.IRExpr.Const):
|
|
436
450
|
tmps[stmt.tmp] = "const"
|
|
437
|
-
elif isinstance(stmt.data, pyvex.IRExpr.Binop)
|
|
438
|
-
stmt.data.op.startswith("Iop_Add") or stmt.data.op.startswith("Iop_Sub")
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
451
|
+
elif isinstance(stmt.data, pyvex.IRExpr.Binop):
|
|
452
|
+
if stmt.data.op.startswith("Iop_Add") or stmt.data.op.startswith("Iop_Sub"):
|
|
453
|
+
if (
|
|
454
|
+
isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
|
|
455
|
+
and tmps.get(stmt.data.args[0].tmp) == "sp"
|
|
456
|
+
) or (
|
|
457
|
+
isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp)
|
|
458
|
+
and tmps.get(stmt.data.args[1].tmp) == "sp"
|
|
459
|
+
):
|
|
460
|
+
tmps[stmt.tmp] = "sp"
|
|
461
|
+
elif stmt.data.op.startswith("Iop_And"): # noqa: SIM102
|
|
462
|
+
if (
|
|
463
|
+
isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp)
|
|
464
|
+
and tmps.get(stmt.data.args[0].tmp) == "sp"
|
|
465
|
+
and isinstance(stmt.data.args[1], pyvex.IRExpr.Const)
|
|
466
|
+
and stmt.data.args[1].con.value in sp_masks
|
|
467
|
+
) or (
|
|
468
|
+
isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp)
|
|
469
|
+
and tmps.get(stmt.data.args[1].tmp) == "sp"
|
|
470
|
+
and isinstance(stmt.data.args[0], pyvex.IRExpr.Const)
|
|
471
|
+
and stmt.data.args[0].con.value in sp_masks
|
|
472
|
+
):
|
|
473
|
+
tmps[stmt.tmp] = "sp"
|
|
448
474
|
if isinstance(stmt, pyvex.IRStmt.Put):
|
|
449
475
|
size = stmt.data.result_size(block.vex.tyenv) // self.project.arch.byte_width
|
|
450
476
|
# is the data loaded from the stack?
|
|
@@ -460,7 +486,28 @@ class FactCollector(Analysis):
|
|
|
460
486
|
if pred not in traversed and depth + 1 <= self._max_depth and edge_type == "transition":
|
|
461
487
|
queue.append((depth + 1, pred))
|
|
462
488
|
|
|
463
|
-
return callee_restored_regs
|
|
489
|
+
# remove offsets of registers that may store return values from callee_restored_regs
|
|
490
|
+
ret_reg_offsets = set()
|
|
491
|
+
cc_cls = default_cc(
|
|
492
|
+
self.project.arch.name, platform=self.project.simos.name if self.project.simos is not None else None
|
|
493
|
+
)
|
|
494
|
+
if cc_cls is not None:
|
|
495
|
+
cc = cc_cls(self.project.arch)
|
|
496
|
+
if isinstance(cc.RETURN_VAL, SimRegArg):
|
|
497
|
+
retreg_offset = cc.RETURN_VAL.check_offset(self.project.arch)
|
|
498
|
+
ret_reg_offsets.add(retreg_offset)
|
|
499
|
+
if isinstance(cc.OVERFLOW_RETURN_VAL, SimRegArg):
|
|
500
|
+
retreg_offset = cc.OVERFLOW_RETURN_VAL.check_offset(self.project.arch)
|
|
501
|
+
ret_reg_offsets.add(retreg_offset)
|
|
502
|
+
if isinstance(cc.FP_RETURN_VAL, SimRegArg):
|
|
503
|
+
try:
|
|
504
|
+
retreg_offset = cc.FP_RETURN_VAL.check_offset(self.project.arch)
|
|
505
|
+
ret_reg_offsets.add(retreg_offset)
|
|
506
|
+
except KeyError:
|
|
507
|
+
# register name does not exist
|
|
508
|
+
pass
|
|
509
|
+
|
|
510
|
+
return callee_restored_regs.difference(ret_reg_offsets)
|
|
464
511
|
|
|
465
512
|
def _determine_input_args(self, end_states: list[FactCollectorState], callee_restored_regs: set[int]) -> None:
|
|
466
513
|
self.input_args = []
|
|
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
import archinfo
|
|
5
|
-
from archinfo.arch_arm import is_arm_arch, ArchARMHF
|
|
5
|
+
from archinfo.arch_arm import is_arm_arch, ArchARMHF, ArchARMCortexM
|
|
6
6
|
|
|
7
7
|
from angr.calling_conventions import SimCC
|
|
8
8
|
|
|
@@ -37,7 +37,7 @@ def is_sane_register_variable(arch: archinfo.Arch, reg_offset: int, reg_size: in
|
|
|
37
37
|
# 224 <= reg_offset < 480) # xmm0-xmm7
|
|
38
38
|
|
|
39
39
|
if is_arm_arch(arch):
|
|
40
|
-
if isinstance(arch, ArchARMHF):
|
|
40
|
+
if isinstance(arch, (ArchARMHF, ArchARMCortexM)):
|
|
41
41
|
return 8 <= reg_offset < 24 or 128 <= reg_offset < 160 # r0 - 32 # s0 - s7, or d0 - d4
|
|
42
42
|
return 8 <= reg_offset < 24 # r0-r3
|
|
43
43
|
|
angr/analyses/cfg/cfg_fast.py
CHANGED
|
@@ -2819,11 +2819,13 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
2819
2819
|
if sec is not None and sec.is_readable and not sec.is_writable:
|
|
2820
2820
|
# points to a non-writable region. read it out and see if there is another pointer!
|
|
2821
2821
|
v = self._fast_memory_load_pointer(ref.data_addr, ref.data_size)
|
|
2822
|
+
if v is None:
|
|
2823
|
+
return
|
|
2822
2824
|
|
|
2823
2825
|
# this value can either be a pointer or an offset from the pc... we need to try them both
|
|
2824
2826
|
# attempt 1: a direct pointer
|
|
2825
2827
|
sec_2nd = self.project.loader.find_section_containing(v)
|
|
2826
|
-
if sec_2nd is not None and sec_2nd.is_readable
|
|
2828
|
+
if sec_2nd is not None and sec_2nd.is_readable:
|
|
2827
2829
|
# found it!
|
|
2828
2830
|
self._add_data_reference(
|
|
2829
2831
|
irsb_addr,
|
|
@@ -2872,7 +2874,7 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
2872
2874
|
actual_ref_ins_addr = ref.ins_addr + 4
|
|
2873
2875
|
v += 8 + actual_ref_ins_addr
|
|
2874
2876
|
sec_3rd = self.project.loader.find_section_containing(v)
|
|
2875
|
-
if sec_3rd is not None and sec_3rd.is_readable
|
|
2877
|
+
if sec_3rd is not None and sec_3rd.is_readable:
|
|
2876
2878
|
# found it!
|
|
2877
2879
|
self._add_data_reference(
|
|
2878
2880
|
irsb_addr, ref.stmt_idx, actual_ref_ins_addr, v, data_size=None, data_type=MemoryDataSort.Unknown
|
|
@@ -4178,7 +4180,10 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4178
4180
|
for segment in self.project.loader.main_object.segments:
|
|
4179
4181
|
if segment.is_readable and segment.memsize >= 8:
|
|
4180
4182
|
# the gp area is sometimes writable, so we can't test for (not segment.is_writable)
|
|
4181
|
-
|
|
4183
|
+
try:
|
|
4184
|
+
content = self.project.loader.memory.load(segment.vaddr, segment.memsize)
|
|
4185
|
+
except KeyError:
|
|
4186
|
+
continue
|
|
4182
4187
|
content_buf = pyvex.ffi.from_buffer(content)
|
|
4183
4188
|
self._ro_region_cdata_cache.append(content_buf)
|
|
4184
4189
|
pyvex.pvc.register_readonly_region(segment.vaddr, segment.memsize, content_buf)
|
|
@@ -4187,7 +4192,10 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4187
4192
|
# also map .got
|
|
4188
4193
|
for section in self.project.loader.main_object.sections:
|
|
4189
4194
|
if section.name == ".got":
|
|
4190
|
-
|
|
4195
|
+
try:
|
|
4196
|
+
content = self.project.loader.memory.load(section.vaddr, section.memsize)
|
|
4197
|
+
except KeyError:
|
|
4198
|
+
continue
|
|
4191
4199
|
content_buf = pyvex.ffi.from_buffer(content)
|
|
4192
4200
|
self._ro_region_cdata_cache.append(content_buf)
|
|
4193
4201
|
pyvex.pvc.register_readonly_region(section.vaddr, section.memsize, content_buf)
|
|
@@ -102,7 +102,7 @@ class AILSimplifier(Analysis):
|
|
|
102
102
|
self.func = func
|
|
103
103
|
self.func_graph = func_graph if func_graph is not None else func.graph
|
|
104
104
|
self._reaching_definitions: SRDAModel | None = None
|
|
105
|
-
self._propagator = None
|
|
105
|
+
self._propagator: SPropagatorAnalysis | None = None
|
|
106
106
|
|
|
107
107
|
self._remove_dead_memdefs = remove_dead_memdefs
|
|
108
108
|
self._stack_arg_offsets = stack_arg_offsets
|
|
@@ -117,6 +117,7 @@ class AILSimplifier(Analysis):
|
|
|
117
117
|
self._removed_vvar_ids = removed_vvar_ids if removed_vvar_ids is not None else set()
|
|
118
118
|
self._arg_vvars = arg_vvars
|
|
119
119
|
self._avoid_vvar_ids = avoid_vvar_ids
|
|
120
|
+
self._propagator_dead_vvar_ids: set[int] = set()
|
|
120
121
|
|
|
121
122
|
self._calls_to_remove: set[CodeLocation] = set()
|
|
122
123
|
self._assignments_to_remove: set[CodeLocation] = set()
|
|
@@ -231,6 +232,7 @@ class AILSimplifier(Analysis):
|
|
|
231
232
|
only_consts=self._only_consts,
|
|
232
233
|
)
|
|
233
234
|
self._propagator = prop
|
|
235
|
+
self._propagator_dead_vvar_ids = prop.dead_vvar_ids
|
|
234
236
|
return prop
|
|
235
237
|
|
|
236
238
|
def _compute_equivalence(self) -> set[Equivalence]:
|
|
@@ -247,6 +249,9 @@ class AILSimplifier(Analysis):
|
|
|
247
249
|
if isinstance(stmt.ret_expr, (VirtualVariable, Load)):
|
|
248
250
|
codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
|
|
249
251
|
equivalence.add(Equivalence(codeloc, stmt.ret_expr, stmt))
|
|
252
|
+
elif isinstance(stmt.fp_ret_expr, (VirtualVariable, Load)):
|
|
253
|
+
codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
|
|
254
|
+
equivalence.add(Equivalence(codeloc, stmt.fp_ret_expr, stmt))
|
|
250
255
|
elif (
|
|
251
256
|
isinstance(stmt, Store)
|
|
252
257
|
and isinstance(stmt.size, int)
|
|
@@ -1115,7 +1120,10 @@ class AILSimplifier(Analysis):
|
|
|
1115
1120
|
than once after simplification and graph structuring where conditions might be duplicated (e.g., in Dream).
|
|
1116
1121
|
In such cases, the one-use expression folder in RegionSimplifier will perform this transformation.
|
|
1117
1122
|
"""
|
|
1123
|
+
# Disabled until https://github.com/angr/angr/issues/5112 and related folding issues are fixed
|
|
1124
|
+
return False
|
|
1118
1125
|
|
|
1126
|
+
# pylint:disable=unreachable
|
|
1119
1127
|
simplified = False
|
|
1120
1128
|
|
|
1121
1129
|
equivalence = self._compute_equivalence()
|
|
@@ -1326,7 +1334,10 @@ class AILSimplifier(Analysis):
|
|
|
1326
1334
|
if isinstance(def_.atom, atoms.MemoryLocation) and isinstance(def_.atom.addr, int):
|
|
1327
1335
|
continue
|
|
1328
1336
|
if isinstance(def_.atom, atoms.VirtualVariable):
|
|
1329
|
-
if def_.atom.
|
|
1337
|
+
if def_.atom.varid in self._propagator_dead_vvar_ids:
|
|
1338
|
+
# we are definitely removing this variable if it has no uses
|
|
1339
|
+
uses = rd.get_vvar_uses(def_.atom)
|
|
1340
|
+
elif def_.atom.was_stack:
|
|
1330
1341
|
if not self._remove_dead_memdefs:
|
|
1331
1342
|
if rd.is_phi_vvar_id(def_.atom.varid):
|
|
1332
1343
|
# we always remove unused phi variables
|
|
@@ -1540,7 +1551,7 @@ class AILSimplifier(Analysis):
|
|
|
1540
1551
|
if bail:
|
|
1541
1552
|
continue
|
|
1542
1553
|
|
|
1543
|
-
if all(varid in phi_and_dirty_vvar_ids for varid in scc):
|
|
1554
|
+
if all(varid in phi_and_dirty_vvar_ids or rd.varid_to_vvar[varid].was_reg for varid in scc):
|
|
1544
1555
|
cyclic_dependent_phi_varids |= set(scc)
|
|
1545
1556
|
|
|
1546
1557
|
return cyclic_dependent_phi_varids
|
|
@@ -58,7 +58,6 @@ class BlockSimplifier(Analysis):
|
|
|
58
58
|
self,
|
|
59
59
|
block: Block | None,
|
|
60
60
|
func_addr: int | None = None,
|
|
61
|
-
remove_dead_memdefs=False,
|
|
62
61
|
stack_pointer_tracker=None,
|
|
63
62
|
peephole_optimizations: None | (
|
|
64
63
|
Iterable[type[PeepholeOptimizationStmtBase] | type[PeepholeOptimizationExprBase]]
|
|
@@ -74,7 +73,6 @@ class BlockSimplifier(Analysis):
|
|
|
74
73
|
self.block = block
|
|
75
74
|
self.func_addr = func_addr
|
|
76
75
|
|
|
77
|
-
self._remove_dead_memdefs = remove_dead_memdefs
|
|
78
76
|
self._stack_pointer_tracker = stack_pointer_tracker
|
|
79
77
|
|
|
80
78
|
if peephole_optimizations is None:
|
|
@@ -5,9 +5,19 @@ import logging
|
|
|
5
5
|
|
|
6
6
|
import archinfo
|
|
7
7
|
from ailment import Stmt, Expr, Const
|
|
8
|
+
from ailment.manager import Manager
|
|
8
9
|
|
|
9
10
|
from angr.procedures.stubs.format_parser import FormatParser, FormatSpecifier
|
|
10
|
-
from angr.sim_type import
|
|
11
|
+
from angr.sim_type import (
|
|
12
|
+
SimTypeBottom,
|
|
13
|
+
SimTypePointer,
|
|
14
|
+
SimTypeChar,
|
|
15
|
+
SimTypeInt,
|
|
16
|
+
SimTypeFloat,
|
|
17
|
+
dereference_simtype,
|
|
18
|
+
SimTypeFunction,
|
|
19
|
+
SimTypeLongLong,
|
|
20
|
+
)
|
|
11
21
|
from angr.calling_conventions import SimRegArg, SimStackArg, SimCC, SimStructArg, SimComboArg
|
|
12
22
|
from angr.knowledge_plugins.key_definitions.constants import OP_BEFORE
|
|
13
23
|
from angr.analyses import Analysis, register_analysis
|
|
@@ -27,7 +37,7 @@ class CallSiteMaker(Analysis):
|
|
|
27
37
|
Add calling convention, declaration, and args to a call site.
|
|
28
38
|
"""
|
|
29
39
|
|
|
30
|
-
def __init__(self, block, reaching_definitions=None, stack_pointer_tracker=None, ail_manager=None):
|
|
40
|
+
def __init__(self, block, reaching_definitions=None, stack_pointer_tracker=None, ail_manager: Manager = None):
|
|
31
41
|
self.block = block
|
|
32
42
|
|
|
33
43
|
self._reaching_definitions = reaching_definitions
|
|
@@ -60,7 +70,7 @@ class CallSiteMaker(Analysis):
|
|
|
60
70
|
return
|
|
61
71
|
|
|
62
72
|
cc = None
|
|
63
|
-
prototype = None
|
|
73
|
+
prototype: SimTypeFunction | None = None
|
|
64
74
|
func = None
|
|
65
75
|
stack_arg_locs: list[SimStackArg] = []
|
|
66
76
|
stackarg_sp_diff = 0
|
|
@@ -106,7 +116,9 @@ class CallSiteMaker(Analysis):
|
|
|
106
116
|
for typelib_name in prototype_lib.type_collection_names:
|
|
107
117
|
type_collections.append(SIM_TYPE_COLLECTIONS[typelib_name])
|
|
108
118
|
if type_collections:
|
|
109
|
-
prototype = dereference_simtype(prototype, type_collections).with_arch(
|
|
119
|
+
prototype = dereference_simtype(prototype, type_collections).with_arch( # type: ignore
|
|
120
|
+
self.project.arch
|
|
121
|
+
)
|
|
110
122
|
|
|
111
123
|
args = []
|
|
112
124
|
arg_vvars = []
|
|
@@ -120,15 +132,18 @@ class CallSiteMaker(Analysis):
|
|
|
120
132
|
arg_locs = cc.arg_locs(prototype)
|
|
121
133
|
if prototype.variadic:
|
|
122
134
|
# determine the number of variadic arguments
|
|
135
|
+
assert func is not None
|
|
123
136
|
variadic_args = self._determine_variadic_arguments(func, cc, call_stmt)
|
|
124
137
|
if variadic_args:
|
|
125
138
|
callsite_ty = copy.copy(prototype)
|
|
126
|
-
|
|
139
|
+
callsite_args = list(callsite_ty.args)
|
|
140
|
+
base_type = SimTypeInt if self.project.arch.bits == 32 else SimTypeLongLong
|
|
127
141
|
for _ in range(variadic_args):
|
|
128
|
-
|
|
142
|
+
callsite_args.append(base_type().with_arch(self.project.arch))
|
|
143
|
+
callsite_ty.args = tuple(callsite_args)
|
|
129
144
|
arg_locs = cc.arg_locs(callsite_ty)
|
|
130
145
|
|
|
131
|
-
if arg_locs is not None:
|
|
146
|
+
if arg_locs is not None and cc is not None:
|
|
132
147
|
expanded_arg_locs = []
|
|
133
148
|
for arg_loc in arg_locs:
|
|
134
149
|
if isinstance(arg_loc, SimComboArg):
|
|
@@ -155,6 +170,38 @@ class CallSiteMaker(Analysis):
|
|
|
155
170
|
oident=vvar_def.oident,
|
|
156
171
|
**vvar_def.tags,
|
|
157
172
|
)
|
|
173
|
+
vvar_def_reg_offset = None
|
|
174
|
+
if vvar_def.was_reg:
|
|
175
|
+
vvar_def_reg_offset = vvar_def.reg_offset
|
|
176
|
+
elif (
|
|
177
|
+
vvar_def.was_parameter
|
|
178
|
+
and vvar_def.parameter_category == Expr.VirtualVariableCategory.REGISTER
|
|
179
|
+
):
|
|
180
|
+
vvar_def_reg_offset = vvar_def.parameter_reg_offset
|
|
181
|
+
|
|
182
|
+
if vvar_def_reg_offset is not None and offset > vvar_def_reg_offset:
|
|
183
|
+
# we need to shift the value
|
|
184
|
+
vvar_use = Expr.BinaryOp(
|
|
185
|
+
self._ail_manager.next_atom(),
|
|
186
|
+
"Shr",
|
|
187
|
+
[
|
|
188
|
+
vvar_use,
|
|
189
|
+
Expr.Const(
|
|
190
|
+
self._ail_manager.next_atom(), None, (offset - vvar_def_reg_offset) * 8, 8
|
|
191
|
+
),
|
|
192
|
+
],
|
|
193
|
+
**vvar_use.tags,
|
|
194
|
+
)
|
|
195
|
+
if vvar_def.size > arg_loc.size:
|
|
196
|
+
# we need to narrow the value
|
|
197
|
+
vvar_use = Expr.Convert(
|
|
198
|
+
self._ail_manager.next_atom(),
|
|
199
|
+
vvar_use.bits,
|
|
200
|
+
arg_loc.size * self.project.arch.byte_width,
|
|
201
|
+
False,
|
|
202
|
+
vvar_use,
|
|
203
|
+
**vvar_use.tags,
|
|
204
|
+
)
|
|
158
205
|
args.append(vvar_use)
|
|
159
206
|
else:
|
|
160
207
|
reg = Expr.Register(
|
|
@@ -219,6 +266,7 @@ class CallSiteMaker(Analysis):
|
|
|
219
266
|
# calculate stack offsets for arguments that are put on the stack. these offsets will be consumed by
|
|
220
267
|
# simplification steps in the future, which may decide to remove statements that store arguments on the stack.
|
|
221
268
|
if stack_arg_locs:
|
|
269
|
+
assert self._stack_pointer_tracker is not None
|
|
222
270
|
sp_offset = self._stack_pointer_tracker.offset_before(call_stmt.ins_addr, self.project.arch.sp_offset)
|
|
223
271
|
if sp_offset is None:
|
|
224
272
|
l.warning(
|
|
@@ -233,8 +281,22 @@ class CallSiteMaker(Analysis):
|
|
|
233
281
|
}
|
|
234
282
|
|
|
235
283
|
ret_expr = call_stmt.ret_expr
|
|
236
|
-
|
|
237
|
-
#
|
|
284
|
+
fp_ret_expr = call_stmt.fp_ret_expr
|
|
285
|
+
# if ret_expr and fp_ret_expr are None, it means in previous steps (such as during AIL simplification) we have
|
|
286
|
+
# deemed the return value of this call statement as useless and is removed.
|
|
287
|
+
|
|
288
|
+
if (
|
|
289
|
+
ret_expr is not None
|
|
290
|
+
and fp_ret_expr is not None
|
|
291
|
+
and prototype is not None
|
|
292
|
+
and prototype.returnty is not None
|
|
293
|
+
):
|
|
294
|
+
# we need to determine the return type of this call (ret_expr vs fp_ret_expr)
|
|
295
|
+
is_float = isinstance(prototype.returnty, SimTypeFloat)
|
|
296
|
+
if is_float:
|
|
297
|
+
ret_expr = None
|
|
298
|
+
else:
|
|
299
|
+
fp_ret_expr = None
|
|
238
300
|
|
|
239
301
|
if (
|
|
240
302
|
ret_expr is not None
|
|
@@ -243,9 +305,9 @@ class CallSiteMaker(Analysis):
|
|
|
243
305
|
and not isinstance(prototype.returnty, SimTypeBottom)
|
|
244
306
|
and not isinstance(ret_expr, Expr.VirtualVariable)
|
|
245
307
|
):
|
|
246
|
-
# try to narrow the return expression if needed
|
|
308
|
+
# try to narrow the non-float return expression if needed
|
|
247
309
|
ret_type_bits = prototype.returnty.with_arch(self.project.arch).size
|
|
248
|
-
if ret_expr.bits > ret_type_bits:
|
|
310
|
+
if ret_type_bits is not None and ret_expr.bits > ret_type_bits:
|
|
249
311
|
ret_expr = ret_expr.copy()
|
|
250
312
|
ret_expr.bits = ret_type_bits
|
|
251
313
|
# TODO: Support narrowing virtual variables
|
|
@@ -257,6 +319,7 @@ class CallSiteMaker(Analysis):
|
|
|
257
319
|
prototype=prototype,
|
|
258
320
|
args=args,
|
|
259
321
|
ret_expr=ret_expr,
|
|
322
|
+
fp_ret_expr=fp_ret_expr,
|
|
260
323
|
arg_vvars=arg_vvars,
|
|
261
324
|
**call_stmt.tags,
|
|
262
325
|
)
|
|
@@ -291,7 +354,7 @@ class CallSiteMaker(Analysis):
|
|
|
291
354
|
l.warning("TODO: Unsupported statement type %s for definitions.", type(stmt))
|
|
292
355
|
return None
|
|
293
356
|
|
|
294
|
-
def _resolve_register_argument(self, arg_loc) -> tuple[
|
|
357
|
+
def _resolve_register_argument(self, arg_loc) -> tuple[Expr.Expression | None, Expr.VirtualVariable] | None:
|
|
295
358
|
offset = arg_loc.check_offset(self.project.arch)
|
|
296
359
|
|
|
297
360
|
if self._reaching_definitions is not None:
|
|
@@ -310,6 +373,8 @@ class CallSiteMaker(Analysis):
|
|
|
310
373
|
return None
|
|
311
374
|
|
|
312
375
|
def _resolve_stack_argument(self, call_stmt, arg_loc) -> tuple[Any, Any]: # pylint:disable=unused-argument
|
|
376
|
+
assert self._stack_pointer_tracker is not None
|
|
377
|
+
|
|
313
378
|
size = arg_loc.size
|
|
314
379
|
offset = arg_loc.stack_offset
|
|
315
380
|
if self.project.arch.call_pushes_ret:
|
|
@@ -331,6 +396,7 @@ class CallSiteMaker(Analysis):
|
|
|
331
396
|
sp_offset, size, self.block.addr, self.block.idx, len(self.block.statements) - 1, OP_BEFORE
|
|
332
397
|
)
|
|
333
398
|
if vvar is not None:
|
|
399
|
+
# FIXME: vvar may be larger than that we ask; we may need to chop the correct value of vvar
|
|
334
400
|
value = view.get_vvar_value(vvar)
|
|
335
401
|
if value is not None and not isinstance(value, Expr.Phi):
|
|
336
402
|
return None, value
|
|
@@ -391,8 +457,8 @@ class CallSiteMaker(Analysis):
|
|
|
391
457
|
|
|
392
458
|
return s
|
|
393
459
|
|
|
394
|
-
def _determine_variadic_arguments(self, func: Function
|
|
395
|
-
if
|
|
460
|
+
def _determine_variadic_arguments(self, func: Function, cc: SimCC, call_stmt) -> int | None:
|
|
461
|
+
if "printf" in func.name or "scanf" in func.name:
|
|
396
462
|
return self._determine_variadic_arguments_for_format_strings(func, cc, call_stmt)
|
|
397
463
|
return None
|
|
398
464
|
|