1 # ScratchABlock - Program analysis and decompilation framework
3 # Copyright (c) 2015-2018 Paul Sokolovsky
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
18 """Interprocedural transformation passes"""
20 from graph
import Graph
21 from core
import is_addr
23 from utils
import maybesorted
27 def build_callgraph():
28 "Build program callgraph from progdb."
32 for addr
, props
in progdb
.FUNC_DB_BY_ADDR
.items():
33 callgraph
.add_node(props
["label"])
35 for addr
, props
in progdb
.FUNC_DB_BY_ADDR
.items():
36 for callee
in props
.get("calls", []):
37 if callee
in callgraph
:
38 callgraph
.add_edge(props
["label"], callee
)
40 callgraph
.number_postorder_forest()
45 def calc_callsites_live_out(cg
, callee
):
46 """Calculate function's callsites_live_out property.
48 Go thru function's callers (using callgraph), and union their
49 calls_live_out information pertinent to this function.
52 callers
= maybesorted(cg
.pred(callee
))
53 # If there're no callers, will return empty set, which
54 # is formally correct - if there're no callers, the
55 # function is dead. However, realistically that means
56 # that callers aren't known, and we should treat that
60 clo
= progdb
.FUNC_DB
[c
].get("calls_live_out", [])
61 #print(" %s: calls_live_out: %s" % (c, utils.repr_stable(clo)))
62 for bbaddr
, callee_expr
, live_out
in clo
:
63 if is_addr(callee_expr
) and callee_expr
.addr
== callee
:
64 print(" %s: calls_live_out[%s]: %s" % (c
, callee
, utils
.repr_stable((bbaddr
, callee_expr
, live_out
))))
65 call_lo_union
.update(live_out
)
67 progdb
.FUNC_DB
[callee
]["callsites_live_out"] = call_lo_union
72 def collect_returns():
75 for addr
, props
in progdb
.FUNC_DB
.items():
76 if "modifieds" in props
and "callsites_live_out" in props
:
77 props
["returns"] = arch
.ret_filter(set(props
["modifieds"]) & set(props
["callsites_live_out"]))