angr 9.2.97__py3-none-manylinux2014_x86_64.whl → 9.2.99__py3-none-manylinux2014_x86_64.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 +14 -1
- angr/analyses/cfg/cfg_fast.py +3 -3
- angr/analyses/cfg/indirect_jump_resolvers/propagator_utils.py +10 -6
- angr/analyses/decompiler/clinic.py +2 -40
- angr/analyses/decompiler/optimization_passes/__init__.py +2 -0
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +380 -0
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +10 -2
- angr/analyses/decompiler/optimization_passes/x86_gcc_getpc_simplifier.py +4 -1
- angr/analyses/decompiler/peephole_optimizations/__init__.py +1 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +71 -3
- angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py +162 -0
- angr/analyses/decompiler/region_simplifiers/expr_folding.py +5 -3
- angr/analyses/decompiler/return_maker.py +71 -0
- angr/analyses/decompiler/structured_codegen/__init__.py +1 -1
- angr/analyses/decompiler/structured_codegen/c.py +72 -99
- angr/analyses/decompiler/utils.py +5 -1
- angr/analyses/propagator/engine_vex.py +15 -0
- angr/analyses/reaching_definitions/engine_vex.py +6 -0
- angr/analyses/variable_recovery/engine_vex.py +6 -0
- angr/analyses/variable_recovery/irsb_scanner.py +12 -0
- angr/engines/light/engine.py +126 -15
- angr/knowledge_plugins/functions/function.py +4 -0
- angr/storage/memory_mixins/paged_memory/pages/list_page.py +20 -5
- angr/storage/memory_mixins/paged_memory/pages/mv_list_page.py +2 -1
- angr/storage/memory_mixins/simple_interface_mixin.py +4 -0
- {angr-9.2.97.dist-info → angr-9.2.99.dist-info}/METADATA +6 -6
- {angr-9.2.97.dist-info → angr-9.2.99.dist-info}/RECORD +32 -29
- {angr-9.2.97.dist-info → angr-9.2.99.dist-info}/LICENSE +0 -0
- {angr-9.2.97.dist-info → angr-9.2.99.dist-info}/WHEEL +0 -0
- {angr-9.2.97.dist-info → angr-9.2.99.dist-info}/entry_points.txt +0 -0
- {angr-9.2.97.dist-info → angr-9.2.99.dist-info}/top_level.txt +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# pylint:disable=arguments-differ
|
|
2
|
-
from typing import Tuple, Optional
|
|
2
|
+
from typing import Tuple, Optional, Dict, List
|
|
3
3
|
import string
|
|
4
4
|
|
|
5
5
|
from archinfo import Endness
|
|
6
6
|
|
|
7
|
-
from ailment.expression import Const
|
|
7
|
+
from ailment.expression import Const, StackBaseOffset
|
|
8
8
|
from ailment.statement import Call, Store
|
|
9
9
|
|
|
10
10
|
from .base import PeepholeOptimizationStmtBase
|
|
@@ -24,7 +24,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
24
24
|
NAME = "Simplifying inlined strcpy"
|
|
25
25
|
stmt_classes = (Store,)
|
|
26
26
|
|
|
27
|
-
def optimize(self, stmt: Store, **kwargs):
|
|
27
|
+
def optimize(self, stmt: Store, stmt_idx: int = None, block=None, **kwargs):
|
|
28
28
|
if isinstance(stmt.data, Const):
|
|
29
29
|
r, s = self.is_integer_likely_a_string(stmt.data.value, stmt.data.size, stmt.endness)
|
|
30
30
|
if r:
|
|
@@ -41,8 +41,76 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
41
41
|
**stmt.tags,
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
+
# scan forward in the current block to find all consecutive constant stores
|
|
45
|
+
if block is not None and stmt_idx is not None:
|
|
46
|
+
all_constant_stores: Dict[int, Tuple[int, Optional[Const]]] = self.collect_constant_stores(
|
|
47
|
+
block, stmt_idx
|
|
48
|
+
)
|
|
49
|
+
if all_constant_stores:
|
|
50
|
+
offsets = sorted(all_constant_stores.keys())
|
|
51
|
+
next_offset = min(offsets)
|
|
52
|
+
stride = []
|
|
53
|
+
for offset in offsets:
|
|
54
|
+
if next_offset is not None and offset != next_offset:
|
|
55
|
+
next_offset = None
|
|
56
|
+
stride = []
|
|
57
|
+
stmt_idx_, v = all_constant_stores[offset]
|
|
58
|
+
if v is not None:
|
|
59
|
+
stride.append((offset, stmt_idx_, v))
|
|
60
|
+
next_offset = offset + v.size
|
|
61
|
+
else:
|
|
62
|
+
next_offset = None
|
|
63
|
+
stride = []
|
|
64
|
+
|
|
65
|
+
integer, size = self.stride_to_int(stride)
|
|
66
|
+
r, s = self.is_integer_likely_a_string(integer, size, Endness.BE)
|
|
67
|
+
if r:
|
|
68
|
+
# we remove all involved statements whose statement IDs are greater than the current one
|
|
69
|
+
for _, stmt_idx_, _ in reversed(stride):
|
|
70
|
+
if stmt_idx_ <= stmt_idx:
|
|
71
|
+
continue
|
|
72
|
+
block.statements[stmt_idx_] = None
|
|
73
|
+
block.statements = [ss for ss in block.statements if ss is not None]
|
|
74
|
+
|
|
75
|
+
str_id = self.kb.custom_strings.allocate(s.encode("ascii"))
|
|
76
|
+
return Call(
|
|
77
|
+
stmt.idx,
|
|
78
|
+
"strncpy",
|
|
79
|
+
args=[
|
|
80
|
+
stmt.addr,
|
|
81
|
+
Const(None, None, str_id, stmt.addr.bits, custom_string=True),
|
|
82
|
+
Const(None, None, len(s), self.project.arch.bits),
|
|
83
|
+
],
|
|
84
|
+
**stmt.tags,
|
|
85
|
+
)
|
|
86
|
+
|
|
44
87
|
return None
|
|
45
88
|
|
|
89
|
+
@staticmethod
|
|
90
|
+
def stride_to_int(stride: List[Tuple[int, int, Const]]) -> Tuple[int, int]:
|
|
91
|
+
stride = sorted(stride, key=lambda x: x[0])
|
|
92
|
+
n = 0
|
|
93
|
+
size = 0
|
|
94
|
+
for _, _, v in stride:
|
|
95
|
+
size += v.size
|
|
96
|
+
n <<= v.bits
|
|
97
|
+
n |= v.value
|
|
98
|
+
return n, size
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def collect_constant_stores(block, starting_stmt_idx: int) -> Dict[int, Tuple[int, Optional[Const]]]:
|
|
102
|
+
r = {}
|
|
103
|
+
for idx, stmt in enumerate(block.statements):
|
|
104
|
+
if idx < starting_stmt_idx:
|
|
105
|
+
continue
|
|
106
|
+
if isinstance(stmt, Store) and isinstance(stmt.addr, StackBaseOffset) and isinstance(stmt.addr.offset, int):
|
|
107
|
+
if isinstance(stmt.data, Const):
|
|
108
|
+
r[stmt.addr.offset] = idx, stmt.data
|
|
109
|
+
else:
|
|
110
|
+
r[stmt.addr.offset] = idx, None
|
|
111
|
+
|
|
112
|
+
return r
|
|
113
|
+
|
|
46
114
|
@staticmethod
|
|
47
115
|
def is_integer_likely_a_string(
|
|
48
116
|
v: int, size: int, endness: Endness, min_length: int = 4
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# pylint:disable=arguments-differ
|
|
2
|
+
from typing import Tuple, Optional, Dict, List
|
|
3
|
+
import string
|
|
4
|
+
|
|
5
|
+
from archinfo import Endness
|
|
6
|
+
|
|
7
|
+
from ailment.expression import Const, StackBaseOffset
|
|
8
|
+
from ailment.statement import Call, Store
|
|
9
|
+
|
|
10
|
+
from .base import PeepholeOptimizationStmtBase
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
ASCII_PRINTABLES = set(string.printable)
|
|
14
|
+
ASCII_DIGITS = set(string.digits)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class InlinedWstrcpy(PeepholeOptimizationStmtBase):
|
|
18
|
+
"""
|
|
19
|
+
Simplifies inlined wide string copying logic into calls to wstrcpy.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
__slots__ = ()
|
|
23
|
+
|
|
24
|
+
NAME = "Simplifying inlined wstrcpy"
|
|
25
|
+
stmt_classes = (Store,)
|
|
26
|
+
|
|
27
|
+
def optimize(self, stmt: Store, stmt_idx: int = None, block=None, **kwargs):
|
|
28
|
+
if isinstance(stmt.data, Const):
|
|
29
|
+
r, s = self.is_integer_likely_a_wide_string(stmt.data.value, stmt.data.size, stmt.endness)
|
|
30
|
+
if r:
|
|
31
|
+
# replace it with a call to strncpy
|
|
32
|
+
str_id = self.kb.custom_strings.allocate(s.encode("ascii"))
|
|
33
|
+
return Call(
|
|
34
|
+
stmt.idx,
|
|
35
|
+
"wstrncpy",
|
|
36
|
+
args=[
|
|
37
|
+
stmt.addr,
|
|
38
|
+
Const(None, None, str_id, stmt.addr.bits, custom_string=True),
|
|
39
|
+
Const(None, None, len(s), self.project.arch.bits),
|
|
40
|
+
],
|
|
41
|
+
**stmt.tags,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# scan forward in the current block to find all consecutive constant stores
|
|
45
|
+
if block is not None and stmt_idx is not None:
|
|
46
|
+
all_constant_stores: Dict[int, Tuple[int, Optional[Const]]] = self.collect_constant_stores(
|
|
47
|
+
block, stmt_idx
|
|
48
|
+
)
|
|
49
|
+
if all_constant_stores:
|
|
50
|
+
offsets = sorted(all_constant_stores.keys())
|
|
51
|
+
next_offset = min(offsets)
|
|
52
|
+
stride = []
|
|
53
|
+
for offset in offsets:
|
|
54
|
+
if next_offset is not None and offset != next_offset:
|
|
55
|
+
next_offset = None
|
|
56
|
+
stride = []
|
|
57
|
+
stmt_idx_, v = all_constant_stores[offset]
|
|
58
|
+
if v is not None:
|
|
59
|
+
stride.append((offset, stmt_idx_, v))
|
|
60
|
+
next_offset = offset + v.size
|
|
61
|
+
else:
|
|
62
|
+
next_offset = None
|
|
63
|
+
stride = []
|
|
64
|
+
|
|
65
|
+
integer, size = self.stride_to_int(stride)
|
|
66
|
+
r, s = self.is_integer_likely_a_wide_string(integer, size, Endness.BE)
|
|
67
|
+
if r:
|
|
68
|
+
# we remove all involved statements whose statement IDs are greater than the current one
|
|
69
|
+
for _, stmt_idx_, _ in reversed(stride):
|
|
70
|
+
if stmt_idx_ <= stmt_idx:
|
|
71
|
+
continue
|
|
72
|
+
block.statements[stmt_idx_] = None
|
|
73
|
+
block.statements = [ss for ss in block.statements if ss is not None]
|
|
74
|
+
|
|
75
|
+
str_id = self.kb.custom_strings.allocate(s.encode("ascii"))
|
|
76
|
+
return Call(
|
|
77
|
+
stmt.idx,
|
|
78
|
+
"wstrncpy",
|
|
79
|
+
args=[
|
|
80
|
+
stmt.addr,
|
|
81
|
+
Const(None, None, str_id, stmt.addr.bits, custom_string=True),
|
|
82
|
+
Const(None, None, len(s), self.project.arch.bits),
|
|
83
|
+
],
|
|
84
|
+
**stmt.tags,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def stride_to_int(stride: List[Tuple[int, int, Const]]) -> Tuple[int, int]:
|
|
91
|
+
stride = sorted(stride, key=lambda x: x[0])
|
|
92
|
+
n = 0
|
|
93
|
+
size = 0
|
|
94
|
+
for _, _, v in stride:
|
|
95
|
+
size += v.size
|
|
96
|
+
n <<= v.bits
|
|
97
|
+
n |= v.value
|
|
98
|
+
return n, size
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def collect_constant_stores(block, starting_stmt_idx: int) -> Dict[int, Tuple[int, Optional[Const]]]:
|
|
102
|
+
r = {}
|
|
103
|
+
for idx, stmt in enumerate(block.statements):
|
|
104
|
+
if idx < starting_stmt_idx:
|
|
105
|
+
continue
|
|
106
|
+
if isinstance(stmt, Store) and isinstance(stmt.addr, StackBaseOffset) and isinstance(stmt.addr.offset, int):
|
|
107
|
+
if isinstance(stmt.data, Const):
|
|
108
|
+
r[stmt.addr.offset] = idx, stmt.data
|
|
109
|
+
else:
|
|
110
|
+
r[stmt.addr.offset] = idx, None
|
|
111
|
+
|
|
112
|
+
return r
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def even_offsets_are_zero(lst: List[str]) -> bool:
|
|
116
|
+
return all(ch == "\x00" for i, ch in enumerate(lst) if i % 2 == 0)
|
|
117
|
+
|
|
118
|
+
@staticmethod
|
|
119
|
+
def odd_offsets_are_zero(lst: List[str]) -> bool:
|
|
120
|
+
return all(ch == "\x00" for i, ch in enumerate(lst) if i % 2 == 1)
|
|
121
|
+
|
|
122
|
+
@staticmethod
|
|
123
|
+
def is_integer_likely_a_wide_string(
|
|
124
|
+
v: int, size: int, endness: Endness, min_length: int = 4
|
|
125
|
+
) -> Tuple[bool, Optional[str]]:
|
|
126
|
+
# we need at least four bytes of printable characters
|
|
127
|
+
|
|
128
|
+
chars = []
|
|
129
|
+
if endness == Endness.LE:
|
|
130
|
+
while v != 0:
|
|
131
|
+
byt = v & 0xFF
|
|
132
|
+
if byt != 0 and chr(byt) not in ASCII_PRINTABLES:
|
|
133
|
+
return False, None
|
|
134
|
+
chars.append(chr(byt))
|
|
135
|
+
v >>= 8
|
|
136
|
+
|
|
137
|
+
elif endness == Endness.BE:
|
|
138
|
+
for _ in range(size):
|
|
139
|
+
byt = v & 0xFF
|
|
140
|
+
v >>= 8
|
|
141
|
+
if byt != 0 and chr(byt) not in ASCII_PRINTABLES:
|
|
142
|
+
return False, None
|
|
143
|
+
chars.append(chr(byt))
|
|
144
|
+
chars = chars[::-1]
|
|
145
|
+
else:
|
|
146
|
+
# unsupported endness
|
|
147
|
+
return False, None
|
|
148
|
+
|
|
149
|
+
if InlinedWstrcpy.even_offsets_are_zero(chars):
|
|
150
|
+
chars = [ch for i, ch in enumerate(chars) if i % 2 == 1]
|
|
151
|
+
elif InlinedWstrcpy.odd_offsets_are_zero(chars):
|
|
152
|
+
chars = [ch for i, ch in enumerate(chars) if i % 2 == 0]
|
|
153
|
+
else:
|
|
154
|
+
return False, None
|
|
155
|
+
|
|
156
|
+
if chars and chars[-1] == "\x00":
|
|
157
|
+
chars = chars[:-1]
|
|
158
|
+
if len(chars) >= min_length and all(ch in ASCII_PRINTABLES for ch in chars):
|
|
159
|
+
if len(chars) <= 4 and all(ch in ASCII_DIGITS for ch in chars):
|
|
160
|
+
return False, None
|
|
161
|
+
return True, "".join(chars)
|
|
162
|
+
return False, None
|
|
@@ -4,6 +4,7 @@ from typing import Optional, Any, Dict, Set, Tuple, Iterable, Union, DefaultDict
|
|
|
4
4
|
|
|
5
5
|
import ailment
|
|
6
6
|
from ailment import Expression, Block, AILBlockWalker
|
|
7
|
+
from ailment.expression import ITE
|
|
7
8
|
from ailment.statement import Statement, Assignment, Call
|
|
8
9
|
|
|
9
10
|
from ..sequence_walker import SequenceWalker
|
|
@@ -385,11 +386,11 @@ class ExpressionReplacer(AILBlockWalker):
|
|
|
385
386
|
return None
|
|
386
387
|
|
|
387
388
|
def _handle_Assignment(self, stmt_idx: int, stmt: Assignment, block: Optional[Block]):
|
|
388
|
-
# override the base handler and make sure we do not replace .dst with a Call expression
|
|
389
|
+
# override the base handler and make sure we do not replace .dst with a Call expression or an ITE expression
|
|
389
390
|
changed = False
|
|
390
391
|
|
|
391
392
|
dst = self._handle_expr(0, stmt.dst, stmt_idx, stmt, block)
|
|
392
|
-
if dst is not None and dst is not stmt.dst and not isinstance(dst, Call):
|
|
393
|
+
if dst is not None and dst is not stmt.dst and not isinstance(dst, (Call, ITE)):
|
|
393
394
|
changed = True
|
|
394
395
|
else:
|
|
395
396
|
dst = stmt.dst
|
|
@@ -446,7 +447,8 @@ class ExpressionFolder(SequenceWalker):
|
|
|
446
447
|
for stmt in node.statements:
|
|
447
448
|
if isinstance(stmt, ailment.Stmt.Assignment):
|
|
448
449
|
if isinstance(stmt.dst, ailment.Expr.Register) and stmt.dst.variable is not None:
|
|
449
|
-
|
|
450
|
+
unified_var = self._u(stmt.dst.variable)
|
|
451
|
+
if unified_var in self._assignments:
|
|
450
452
|
# remove this statement
|
|
451
453
|
continue
|
|
452
454
|
if (
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import ailment
|
|
5
|
+
|
|
6
|
+
from angr.sim_type import SimTypeBottom
|
|
7
|
+
from angr.calling_conventions import SimRegArg
|
|
8
|
+
from .ailgraph_walker import AILGraphWalker
|
|
9
|
+
|
|
10
|
+
l = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ReturnMaker(AILGraphWalker):
|
|
14
|
+
"""
|
|
15
|
+
Traverse the AILBlock graph of a function and update .ret_exprs of all return statements.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, ail_manager, arch, function, ail_graph):
|
|
19
|
+
super().__init__(ail_graph, self._handler, replace_nodes=True)
|
|
20
|
+
self.ail_manager = ail_manager
|
|
21
|
+
self.arch = arch
|
|
22
|
+
self.function = function
|
|
23
|
+
self._new_block = None
|
|
24
|
+
|
|
25
|
+
self.walk()
|
|
26
|
+
|
|
27
|
+
def _next_atom(self) -> int:
|
|
28
|
+
return self.ail_manager.next_atom()
|
|
29
|
+
|
|
30
|
+
def _handle_Return(
|
|
31
|
+
self, stmt_idx: int, stmt: ailment.Stmt.Return, block: Optional[ailment.Block]
|
|
32
|
+
): # pylint:disable=unused-argument
|
|
33
|
+
if (
|
|
34
|
+
block is not None
|
|
35
|
+
and not stmt.ret_exprs
|
|
36
|
+
and self.function.prototype is not None
|
|
37
|
+
and self.function.prototype.returnty is not None
|
|
38
|
+
and type(self.function.prototype.returnty) is not SimTypeBottom
|
|
39
|
+
):
|
|
40
|
+
new_stmt = stmt.copy()
|
|
41
|
+
ret_val = self.function.calling_convention.return_val(self.function.prototype.returnty)
|
|
42
|
+
if isinstance(ret_val, SimRegArg):
|
|
43
|
+
reg = self.arch.registers[ret_val.reg_name]
|
|
44
|
+
new_stmt.ret_exprs.append(
|
|
45
|
+
ailment.Expr.Register(
|
|
46
|
+
self._next_atom(),
|
|
47
|
+
None,
|
|
48
|
+
reg[0],
|
|
49
|
+
ret_val.size * self.arch.byte_width,
|
|
50
|
+
reg_name=self.arch.translate_register_name(reg[0], ret_val.size),
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
else:
|
|
54
|
+
l.warning("Unsupported type of return expression %s.", type(ret_val))
|
|
55
|
+
new_statements = block.statements[::]
|
|
56
|
+
new_statements[stmt_idx] = new_stmt
|
|
57
|
+
self._new_block = block.copy(statements=new_statements)
|
|
58
|
+
|
|
59
|
+
def _handler(self, block):
|
|
60
|
+
walker = ailment.AILBlockWalker()
|
|
61
|
+
# we don't need to handle any statement besides Returns
|
|
62
|
+
walker.stmt_handlers.clear()
|
|
63
|
+
walker.expr_handlers.clear()
|
|
64
|
+
walker.stmt_handlers[ailment.Stmt.Return] = self._handle_Return
|
|
65
|
+
|
|
66
|
+
self._new_block = None
|
|
67
|
+
walker.walk(block)
|
|
68
|
+
|
|
69
|
+
if self._new_block is not None:
|
|
70
|
+
return self._new_block
|
|
71
|
+
return None
|
|
@@ -5,6 +5,6 @@ from .base import (
|
|
|
5
5
|
PositionMappingElement,
|
|
6
6
|
PositionMapping,
|
|
7
7
|
)
|
|
8
|
-
from .c import CStructuredCodeGenerator
|
|
8
|
+
from .c import CStructuredCodeGenerator, CStructuredCodeWalker
|
|
9
9
|
from .dwarf_import import ImportSourceCode
|
|
10
10
|
from .dummy import DummyStructuredCodeGenerator
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint:disable=missing-class-docstring,too-many-boolean-expressions,unused-argument
|
|
1
|
+
# pylint:disable=missing-class-docstring,too-many-boolean-expressions,unused-argument,no-self-use
|
|
2
2
|
from typing import Optional, Dict, List, Tuple, Set, Any, Union, TYPE_CHECKING, Callable
|
|
3
3
|
from collections import defaultdict
|
|
4
4
|
import logging
|
|
@@ -2524,9 +2524,9 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
2524
2524
|
codegen=self,
|
|
2525
2525
|
omit_header=self.omit_func_header,
|
|
2526
2526
|
)
|
|
2527
|
-
self.cfunc = FieldReferenceCleanup.handle(self.cfunc)
|
|
2528
|
-
self.cfunc = PointerArithmeticFixer.handle(self.cfunc)
|
|
2529
|
-
self.cfunc = MakeTypecastsImplicit.handle(self.cfunc)
|
|
2527
|
+
self.cfunc = FieldReferenceCleanup().handle(self.cfunc)
|
|
2528
|
+
self.cfunc = PointerArithmeticFixer().handle(self.cfunc)
|
|
2529
|
+
self.cfunc = MakeTypecastsImplicit().handle(self.cfunc)
|
|
2530
2530
|
|
|
2531
2531
|
# TODO store extern fallback size somewhere lol
|
|
2532
2532
|
self.cexterns = {
|
|
@@ -3554,120 +3554,100 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3554
3554
|
|
|
3555
3555
|
|
|
3556
3556
|
class CStructuredCodeWalker:
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
handler = getattr(cls, "handle_" + type(obj).__name__, cls.handle_default)
|
|
3557
|
+
def handle(self, obj):
|
|
3558
|
+
handler = getattr(self, "handle_" + type(obj).__name__, self.handle_default)
|
|
3560
3559
|
return handler(obj)
|
|
3561
3560
|
|
|
3562
|
-
|
|
3563
|
-
def handle_default(cls, obj):
|
|
3561
|
+
def handle_default(self, obj):
|
|
3564
3562
|
return obj
|
|
3565
3563
|
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
obj.statements = cls.handle(obj.statements)
|
|
3564
|
+
def handle_CFunction(self, obj):
|
|
3565
|
+
obj.statements = self.handle(obj.statements)
|
|
3569
3566
|
return obj
|
|
3570
3567
|
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
obj.statements = [cls.handle(stmt) for stmt in obj.statements]
|
|
3568
|
+
def handle_CStatements(self, obj):
|
|
3569
|
+
obj.statements = [self.handle(stmt) for stmt in obj.statements]
|
|
3574
3570
|
return obj
|
|
3575
3571
|
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
obj.
|
|
3579
|
-
obj.body = cls.handle(obj.body)
|
|
3572
|
+
def handle_CWhileLoop(self, obj):
|
|
3573
|
+
obj.condition = self.handle(obj.condition)
|
|
3574
|
+
obj.body = self.handle(obj.body)
|
|
3580
3575
|
return obj
|
|
3581
3576
|
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
obj.
|
|
3585
|
-
obj.body = cls.handle(obj.body)
|
|
3577
|
+
def handle_CDoWhileLoop(self, obj):
|
|
3578
|
+
obj.condition = self.handle(obj.condition)
|
|
3579
|
+
obj.body = self.handle(obj.body)
|
|
3586
3580
|
return obj
|
|
3587
3581
|
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
obj.
|
|
3591
|
-
obj.
|
|
3592
|
-
obj.
|
|
3593
|
-
obj.body = cls.handle(obj.body)
|
|
3582
|
+
def handle_CForLoop(self, obj):
|
|
3583
|
+
obj.initializer = self.handle(obj.initializer)
|
|
3584
|
+
obj.condition = self.handle(obj.condition)
|
|
3585
|
+
obj.iterator = self.handle(obj.iterator)
|
|
3586
|
+
obj.body = self.handle(obj.body)
|
|
3594
3587
|
return obj
|
|
3595
3588
|
|
|
3596
|
-
|
|
3597
|
-
def handle_CIfElse(cls, obj):
|
|
3589
|
+
def handle_CIfElse(self, obj):
|
|
3598
3590
|
obj.condition_and_nodes = [
|
|
3599
|
-
(
|
|
3591
|
+
(self.handle(condition), self.handle(node)) for condition, node in obj.condition_and_nodes
|
|
3600
3592
|
]
|
|
3601
|
-
obj.else_node =
|
|
3593
|
+
obj.else_node = self.handle(obj.else_node)
|
|
3602
3594
|
return obj
|
|
3603
3595
|
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
obj.condition = cls.handle(obj.condition)
|
|
3596
|
+
def handle_CIfBreak(self, obj):
|
|
3597
|
+
obj.condition = self.handle(obj.condition)
|
|
3607
3598
|
return obj
|
|
3608
3599
|
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
obj.
|
|
3612
|
-
obj.
|
|
3613
|
-
obj.default = cls.handle(obj.default)
|
|
3600
|
+
def handle_CSwitchCase(self, obj):
|
|
3601
|
+
obj.switch = self.handle(obj.switch)
|
|
3602
|
+
obj.cases = [(case, self.handle(body)) for case, body in obj.cases]
|
|
3603
|
+
obj.default = self.handle(obj.default)
|
|
3614
3604
|
return obj
|
|
3615
3605
|
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
obj.
|
|
3619
|
-
obj.rhs = cls.handle(obj.rhs)
|
|
3606
|
+
def handle_CAssignment(self, obj):
|
|
3607
|
+
obj.lhs = self.handle(obj.lhs)
|
|
3608
|
+
obj.rhs = self.handle(obj.rhs)
|
|
3620
3609
|
return obj
|
|
3621
3610
|
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
obj.
|
|
3625
|
-
obj.
|
|
3626
|
-
obj.ret_expr = cls.handle(obj.ret_expr)
|
|
3611
|
+
def handle_CFunctionCall(self, obj):
|
|
3612
|
+
obj.callee_target = self.handle(obj.callee_target)
|
|
3613
|
+
obj.args = [self.handle(arg) for arg in obj.args]
|
|
3614
|
+
obj.ret_expr = self.handle(obj.ret_expr)
|
|
3627
3615
|
return obj
|
|
3628
3616
|
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
obj.retval = cls.handle(obj.retval)
|
|
3617
|
+
def handle_CReturn(self, obj):
|
|
3618
|
+
obj.retval = self.handle(obj.retval)
|
|
3632
3619
|
return obj
|
|
3633
3620
|
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
obj.target = cls.handle(obj.target)
|
|
3621
|
+
def handle_CGoto(self, obj):
|
|
3622
|
+
obj.target = self.handle(obj.target)
|
|
3637
3623
|
return obj
|
|
3638
3624
|
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
obj.
|
|
3642
|
-
obj.index = cls.handle(obj.index)
|
|
3625
|
+
def handle_CIndexedVariable(self, obj):
|
|
3626
|
+
obj.variable = self.handle(obj.variable)
|
|
3627
|
+
obj.index = self.handle(obj.index)
|
|
3643
3628
|
return obj
|
|
3644
3629
|
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
obj.variable = cls.handle(obj.variable)
|
|
3630
|
+
def handle_CVariableField(self, obj):
|
|
3631
|
+
obj.variable = self.handle(obj.variable)
|
|
3648
3632
|
return obj
|
|
3649
3633
|
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
obj.operand = cls.handle(obj.operand)
|
|
3634
|
+
def handle_CUnaryOp(self, obj):
|
|
3635
|
+
obj.operand = self.handle(obj.operand)
|
|
3653
3636
|
return obj
|
|
3654
3637
|
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
obj.
|
|
3658
|
-
obj.rhs = cls.handle(obj.rhs)
|
|
3638
|
+
def handle_CBinaryOp(self, obj):
|
|
3639
|
+
obj.lhs = self.handle(obj.lhs)
|
|
3640
|
+
obj.rhs = self.handle(obj.rhs)
|
|
3659
3641
|
return obj
|
|
3660
3642
|
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
obj.expr = cls.handle(obj.expr)
|
|
3643
|
+
def handle_CTypeCast(self, obj):
|
|
3644
|
+
obj.expr = self.handle(obj.expr)
|
|
3664
3645
|
return obj
|
|
3665
3646
|
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
obj.
|
|
3669
|
-
obj.
|
|
3670
|
-
obj.iffalse = cls.handle(obj.iffalse)
|
|
3647
|
+
def handle_CITE(self, obj):
|
|
3648
|
+
obj.cond = self.handle(obj.cond)
|
|
3649
|
+
obj.iftrue = self.handle(obj.iftrue)
|
|
3650
|
+
obj.iffalse = self.handle(obj.iffalse)
|
|
3671
3651
|
return obj
|
|
3672
3652
|
|
|
3673
3653
|
|
|
@@ -3702,34 +3682,30 @@ class MakeTypecastsImplicit(CStructuredCodeWalker):
|
|
|
3702
3682
|
return cls.collapse(dst_ty, result)
|
|
3703
3683
|
return result
|
|
3704
3684
|
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
obj.rhs = cls.collapse(obj.lhs.type, obj.rhs)
|
|
3685
|
+
def handle_CAssignment(self, obj):
|
|
3686
|
+
obj.rhs = self.collapse(obj.lhs.type, obj.rhs)
|
|
3708
3687
|
return super().handle_CAssignment(obj)
|
|
3709
3688
|
|
|
3710
|
-
|
|
3711
|
-
def handle_CFunctionCall(cls, obj: CFunctionCall):
|
|
3689
|
+
def handle_CFunctionCall(self, obj: CFunctionCall):
|
|
3712
3690
|
for i, (c_arg, arg_ty) in enumerate(zip(obj.args, obj.prototype.args)):
|
|
3713
|
-
obj.args[i] =
|
|
3691
|
+
obj.args[i] = self.collapse(arg_ty, c_arg)
|
|
3714
3692
|
return super().handle_CFunctionCall(obj)
|
|
3715
3693
|
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
obj.retval = cls.collapse(obj.codegen._func.prototype.returnty, obj.retval)
|
|
3694
|
+
def handle_CReturn(self, obj: CReturn):
|
|
3695
|
+
obj.retval = self.collapse(obj.codegen._func.prototype.returnty, obj.retval)
|
|
3719
3696
|
return super().handle_CReturn(obj)
|
|
3720
3697
|
|
|
3721
|
-
|
|
3722
|
-
def handle_CBinaryOp(cls, obj: CBinaryOp):
|
|
3698
|
+
def handle_CBinaryOp(self, obj: CBinaryOp):
|
|
3723
3699
|
obj = super().handle_CBinaryOp(obj)
|
|
3724
3700
|
while True:
|
|
3725
|
-
new_lhs =
|
|
3701
|
+
new_lhs = self.collapse(obj.common_type, obj.lhs)
|
|
3726
3702
|
if (
|
|
3727
3703
|
new_lhs is not obj.lhs
|
|
3728
3704
|
and CBinaryOp.compute_common_type(obj.op, new_lhs.type, obj.rhs.type) == obj.common_type
|
|
3729
3705
|
):
|
|
3730
3706
|
obj.lhs = new_lhs
|
|
3731
3707
|
else:
|
|
3732
|
-
new_rhs =
|
|
3708
|
+
new_rhs = self.collapse(obj.common_type, obj.rhs)
|
|
3733
3709
|
if (
|
|
3734
3710
|
new_rhs is not obj.rhs
|
|
3735
3711
|
and CBinaryOp.compute_common_type(obj.op, obj.lhs.type, new_rhs.type) == obj.common_type
|
|
@@ -3739,11 +3715,10 @@ class MakeTypecastsImplicit(CStructuredCodeWalker):
|
|
|
3739
3715
|
break
|
|
3740
3716
|
return obj
|
|
3741
3717
|
|
|
3742
|
-
|
|
3743
|
-
def handle_CTypeCast(cls, obj: CTypeCast):
|
|
3718
|
+
def handle_CTypeCast(self, obj: CTypeCast):
|
|
3744
3719
|
# note that the expression that this method returns may no longer be a CTypeCast
|
|
3745
3720
|
obj = super().handle_CTypeCast(obj)
|
|
3746
|
-
inner =
|
|
3721
|
+
inner = self.collapse(obj.dst_type, obj.expr)
|
|
3747
3722
|
if inner is not obj.expr:
|
|
3748
3723
|
obj.src_type = inner.type
|
|
3749
3724
|
obj.expr = inner
|
|
@@ -3753,12 +3728,11 @@ class MakeTypecastsImplicit(CStructuredCodeWalker):
|
|
|
3753
3728
|
|
|
3754
3729
|
|
|
3755
3730
|
class FieldReferenceCleanup(CStructuredCodeWalker):
|
|
3756
|
-
|
|
3757
|
-
def handle_CTypeCast(cls, obj):
|
|
3731
|
+
def handle_CTypeCast(self, obj):
|
|
3758
3732
|
if isinstance(obj.dst_type, SimTypePointer) and not isinstance(obj.dst_type.pts_to, SimTypeBottom):
|
|
3759
3733
|
obj = obj.codegen._access_reference(obj.expr, obj.dst_type.pts_to)
|
|
3760
3734
|
if not isinstance(obj, CTypeCast):
|
|
3761
|
-
return
|
|
3735
|
+
return self.handle(obj)
|
|
3762
3736
|
return super().handle_CTypeCast(obj)
|
|
3763
3737
|
|
|
3764
3738
|
|
|
@@ -3776,8 +3750,7 @@ class PointerArithmeticFixer(CStructuredCodeWalker):
|
|
|
3776
3750
|
a_ptr = a_ptr + 1.
|
|
3777
3751
|
"""
|
|
3778
3752
|
|
|
3779
|
-
|
|
3780
|
-
def handle_CBinaryOp(cls, obj):
|
|
3753
|
+
def handle_CBinaryOp(self, obj):
|
|
3781
3754
|
obj: CBinaryOp = super().handle_CBinaryOp(obj)
|
|
3782
3755
|
if (
|
|
3783
3756
|
obj.op in ("Add", "Sub")
|
|
@@ -569,7 +569,10 @@ def peephole_optimize_stmts(block, stmt_opts):
|
|
|
569
569
|
statements = []
|
|
570
570
|
|
|
571
571
|
# run statement optimizers
|
|
572
|
-
|
|
572
|
+
# note that an optimizer may optionally edit or remove statements whose statement IDs are greater than stmt_idx
|
|
573
|
+
stmt_idx = 0
|
|
574
|
+
while stmt_idx < len(block.statements):
|
|
575
|
+
stmt = block.statements[stmt_idx]
|
|
573
576
|
old_stmt = stmt
|
|
574
577
|
redo = True
|
|
575
578
|
while redo:
|
|
@@ -587,6 +590,7 @@ def peephole_optimize_stmts(block, stmt_opts):
|
|
|
587
590
|
any_update = True
|
|
588
591
|
else:
|
|
589
592
|
statements.append(old_stmt)
|
|
593
|
+
stmt_idx += 1
|
|
590
594
|
|
|
591
595
|
return statements, any_update
|
|
592
596
|
|