-
Notifications
You must be signed in to change notification settings - Fork 23
/
xform_inter.py
77 lines (60 loc) · 2.64 KB
/
xform_inter.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
# ScratchABlock - Program analysis and decompilation framework
#
# Copyright (c) 2015-2018 Paul Sokolovsky
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Interprocedural transformation passes"""
from graph import Graph
from core import is_addr
import progdb
from utils import maybesorted
import utils
def build_callgraph():
"Build program callgraph from progdb."
callgraph = Graph()
for addr, props in progdb.FUNC_DB_BY_ADDR.items():
callgraph.add_node(props["label"])
for addr, props in progdb.FUNC_DB_BY_ADDR.items():
for callee in props.get("calls", []):
if callee in callgraph:
callgraph.add_edge(props["label"], callee)
callgraph.number_postorder_forest()
return callgraph
def calc_callsites_live_out(cg, callee):
"""Calculate function's callsites_live_out property.
Go thru function's callers (using callgraph), and union their
calls_live_out information pertinent to this function.
"""
callers = maybesorted(cg.pred(callee))
# If there're no callers, will return empty set, which
# is formally correct - if there're no callers, the
# function is dead. However, realistically that means
# that callers aren't known, and we should treat that
# specially.
call_lo_union = set()
for c in callers:
clo = progdb.FUNC_DB[c].get("calls_live_out", [])
#print(" %s: calls_live_out: %s" % (c, utils.repr_stable(clo)))
for bbaddr, callee_expr, live_out in clo:
if is_addr(callee_expr) and callee_expr.addr == callee:
print(" %s: calls_live_out[%s]: %s" % (c, callee, utils.repr_stable((bbaddr, callee_expr, live_out))))
call_lo_union.update(live_out)
progdb.FUNC_DB[callee]["callsites_live_out"] = call_lo_union
return call_lo_union
def collect_returns():
import progdb
import arch
for addr, props in progdb.FUNC_DB.items():
if "modifieds" in props and "callsites_live_out" in props:
props["returns"] = arch.ret_filter(set(props["modifieds"]) & set(props["callsites_live_out"]))