-
Notifications
You must be signed in to change notification settings - Fork 474
/
simplifier.py
325 lines (273 loc) · 9.35 KB
/
simplifier.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
"""
Apply simplification passes to an IR cfg
"""
import logging
import warnings
from functools import wraps
from miasm.analysis.ssa import SSADiGraph
from miasm.analysis.outofssa import UnSSADiGraph
from miasm.analysis.data_flow import DiGraphLivenessSSA
from miasm.expression.simplifications import expr_simp
from miasm.ir.ir import AssignBlock, IRBlock
from miasm.analysis.data_flow import DeadRemoval, \
merge_blocks, remove_empty_assignblks, \
del_unused_edges, \
PropagateExpressions, DelDummyPhi
log = logging.getLogger("simplifier")
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter("[%(levelname)-8s]: %(message)s"))
log.addHandler(console_handler)
log.setLevel(logging.WARNING)
def fix_point(func):
@wraps(func)
def ret_func(self, ircfg, head):
log.debug('[%s]: start', func.__name__)
has_been_modified = False
modified = True
while modified:
modified = func(self, ircfg, head)
has_been_modified |= modified
log.debug(
'[%s]: stop %r',
func.__name__,
has_been_modified
)
return has_been_modified
return ret_func
class IRCFGSimplifier(object):
"""
Simplify an IRCFG
This class applies passes until reaching a fix point
"""
def __init__(self, lifter):
self.lifter = lifter
self.init_passes()
@property
def ir_arch(self):
warnings.warn('DEPRECATION WARNING: use ".lifter" instead of ".ir_arch"')
return self.lifter
def init_passes(self):
"""
Init the array of simplification passes
"""
self.passes = []
@fix_point
def simplify(self, ircfg, head):
"""
Apply passes until reaching a fix point
Return True if the graph has been modified
@ircfg: IRCFG instance to simplify
@head: Location instance of the ircfg head
"""
modified = False
for simplify_pass in self.passes:
modified |= simplify_pass(ircfg, head)
return modified
def __call__(self, ircfg, head):
return self.simplify(ircfg, head)
class IRCFGSimplifierCommon(IRCFGSimplifier):
"""
Simplify an IRCFG
This class applies following passes until reaching a fix point:
- simplify_ircfg
- do_dead_simp_ircfg
"""
def __init__(self, lifter, expr_simp=expr_simp):
self.expr_simp = expr_simp
super(IRCFGSimplifierCommon, self).__init__(lifter)
self.deadremoval = DeadRemoval(self.lifter)
def init_passes(self):
self.passes = [
self.simplify_ircfg,
self.do_dead_simp_ircfg,
]
@fix_point
def simplify_ircfg(self, ircfg, _head):
"""
Apply self.expr_simp on the @ircfg until reaching fix point
Return True if the graph has been modified
@ircfg: IRCFG instance to simplify
"""
modified = ircfg.simplify(self.expr_simp)
return modified
@fix_point
def do_dead_simp_ircfg(self, ircfg, head):
"""
Apply:
- dead_simp
- remove_empty_assignblks
- merge_blocks
on the @ircfg until reaching fix point
Return True if the graph has been modified
@ircfg: IRCFG instance to simplify
@head: Location instance of the ircfg head
"""
modified = self.deadremoval(ircfg)
modified |= remove_empty_assignblks(ircfg)
modified |= merge_blocks(ircfg, set([head]))
return modified
class IRCFGSimplifierSSA(IRCFGSimplifierCommon):
"""
Simplify an IRCFG.
The IRCF is first transformed in SSA, then apply transformations passes
and apply out-of-ssa. Final passes of IRcfgSimplifier are applied
This class apply following pass until reaching a fix point:
- do_propagate_expressions
- do_dead_simp_ssa
"""
def __init__(self, lifter, expr_simp=expr_simp):
super(IRCFGSimplifierSSA, self).__init__(lifter, expr_simp)
self.lifter.ssa_var = {}
self.all_ssa_vars = {}
self.ssa_forbidden_regs = self.get_forbidden_regs()
self.propag_expressions = PropagateExpressions()
self.del_dummy_phi = DelDummyPhi()
self.deadremoval = DeadRemoval(self.lifter, self.all_ssa_vars)
def get_forbidden_regs(self):
"""
Return a set of immutable register during SSA transformation
"""
regs = set(
[
self.lifter.pc,
self.lifter.IRDst,
self.lifter.arch.regs.exception_flags
]
)
return regs
def init_passes(self):
"""
Init the array of simplification passes
"""
self.passes = [
self.simplify_ssa,
self.do_propagate_expressions,
self.do_del_dummy_phi,
self.do_dead_simp_ssa,
self.do_remove_empty_assignblks,
self.do_del_unused_edges,
self.do_merge_blocks,
]
def ircfg_to_ssa(self, ircfg, head):
"""
Apply the SSA transformation to @ircfg using it's @head
@ircfg: IRCFG instance to simplify
@head: Location instance of the ircfg head
"""
ssa = SSADiGraph(ircfg)
ssa.immutable_ids.update(self.ssa_forbidden_regs)
ssa.ssa_variable_to_expr.update(self.all_ssa_vars)
ssa.transform(head)
self.all_ssa_vars.update(ssa.ssa_variable_to_expr)
self.lifter.ssa_var.update(ssa.ssa_variable_to_expr)
return ssa
def ssa_to_unssa(self, ssa, head):
"""
Apply the out-of-ssa transformation to @ssa using it's @head
@ssa: SSADiGraph instance
@head: Location instance of the graph head
"""
cfg_liveness = DiGraphLivenessSSA(ssa.graph)
cfg_liveness.init_var_info(self.lifter)
cfg_liveness.compute_liveness()
UnSSADiGraph(ssa, head, cfg_liveness)
return ssa.graph
@fix_point
def simplify_ssa(self, ssa, _head):
"""
Apply self.expr_simp on the @ssa.graph until reaching fix point
Return True if the graph has been modified
@ssa: SSADiGraph instance
"""
modified = ssa.graph.simplify(self.expr_simp)
return modified
@fix_point
def do_del_unused_edges(self, ssa, head):
"""
Del unused edges of the ssa graph
@head: Location instance of the graph head
"""
modified = del_unused_edges(ssa.graph, set([head]))
return modified
def do_propagate_expressions(self, ssa, head):
"""
Expressions propagation through ExprId in the @ssa graph
@head: Location instance of the graph head
"""
modified = self.propag_expressions.propagate(ssa, head)
return modified
@fix_point
def do_del_dummy_phi(self, ssa, head):
"""
Del dummy phi
@head: Location instance of the graph head
"""
modified = self.del_dummy_phi.del_dummy_phi(ssa, head)
return modified
@fix_point
def do_remove_empty_assignblks(self, ssa, head):
"""
Remove empty assignblks
@head: Location instance of the graph head
"""
modified = remove_empty_assignblks(ssa.graph)
return modified
@fix_point
def do_merge_blocks(self, ssa, head):
"""
Merge blocks with one parent/son
@head: Location instance of the graph head
"""
modified = merge_blocks(ssa.graph, set([head]))
return modified
@fix_point
def do_dead_simp_ssa(self, ssa, head):
"""
Apply:
- deadrm
- remove_empty_assignblks
- del_unused_edges
- merge_blocks
on the @ircfg until reaching fix point
Return True if the graph has been modified
@ircfg: IRCFG instance to simplify
@head: Location instance of the ircfg head
"""
modified = self.deadremoval(ssa.graph)
return modified
def do_simplify(self, ssa, head):
"""
Apply passes until reaching a fix point
Return True if the graph has been modified
"""
return super(IRCFGSimplifierSSA, self).simplify(ssa, head)
def do_simplify_loop(self, ssa, head):
"""
Apply do_simplify until reaching a fix point
SSA is updated between each do_simplify
Return True if the graph has been modified
"""
modified = True
while modified:
modified = self.do_simplify(ssa, head)
# Update ssa structs
ssa = self.ircfg_to_ssa(ssa.graph, head)
return ssa
def simplify(self, ircfg, head):
"""
Add access to "abi out regs" in each leaf block
Apply SSA transformation to @ircfg
Apply passes until reaching a fix point
Apply out-of-ssa transformation
Apply post simplification passes
Updated simplified IRCFG instance and return it
@ircfg: IRCFG instance to simplify
@head: Location instance of the ircfg head
"""
ssa = self.ircfg_to_ssa(ircfg, head)
ssa = self.do_simplify_loop(ssa, head)
ircfg = self.ssa_to_unssa(ssa, head)
ircfg_simplifier = IRCFGSimplifierCommon(self.lifter)
ircfg_simplifier.deadremoval.add_expr_to_original_expr(self.all_ssa_vars)
ircfg_simplifier.simplify(ircfg, head)
return ircfg