2 # This module deals with various "program databases" as required
3 # for analysis passes. Among them: function database (funcdb.yaml),
4 # databases of structures, etc.
14 from utils
import repr_stable
16 from core
import is_addr
, is_value
, is_expr
, EXPR
19 _log
= logging
.getLogger(__name__
)
28 global FUNC_DB
, FUNC_DB_BY_ADDR
29 # index by name in addition to by addr
30 for addr
, props
in list(db
.items()):
31 FUNC_DB
[props
["label"]] = props
36 "callsites_live_out", "modifieds", "preserveds", "reach_exit", "reach_exit_maybe",
37 "params", "estimated_params", "returns",
41 def reglist2set(regs
):
42 return set(core
.REG(x
) for x
in regs
)
45 def preprocess_funcdb(FUNC_DB
):
46 for addr
, props
in FUNC_DB
.items():
47 for prop
in REG_PROPS
:
49 props
[prop
] = reglist2set(props
[prop
])
51 if "calls_live_out" in props
:
52 new
= [(x
, core
.ADDR(y
), reglist2set(z
)) for x
, y
, z
in props
["calls_live_out"]]
53 props
["calls_live_out"] = new
56 def postprocess_funcdb(FUNC_DB
):
57 for addr
, props
in FUNC_DB
.items():
58 for prop
in REG_PROPS
:
60 props
[prop
] = sorted([x
.name
for x
in props
[prop
]], key
=utils
.natural_sort_key
)
63 def load_funcdb(*fnames
):
66 with
open(fname
) as f
:
67 db
= yaml
.safe_load(f
)
70 preprocess_funcdb(FUNC_DB
)
74 def save_funcdb(fname
, backup
=True):
75 db
= copy
.deepcopy(FUNC_DB_BY_ADDR
)
76 postprocess_funcdb(db
)
77 if backup
and os
.path
.exists(fname
):
78 os
.rename(fname
, fname
+ ".bak")
80 with
open(fname
, "w") as f
:
84 def check_invariants(cfg
):
85 if "reach_exit" in cfg
.props
:
86 reach
= cfg
.props
["reach_exit"]
87 reach_maybe
= cfg
.props
.get("reach_exit_maybe", set())
88 assert reach_maybe
.issubset(reach
), "%s: maybe: %s, sure: %s" % (cfg
.props
["name"],
89 repr_stable(reach_maybe
), repr_stable(reach
))
92 def update_funcdb(cfg
):
93 "Aggregate data from each CFG processed into a function DB."
94 if "addr" not in cfg
.props
:
99 func_props
= FUNC_DB_BY_ADDR
.setdefault(cfg
.props
["addr"], {})
100 func_props
["label"] = cfg
.props
["name"]
103 "params", "estimated_params", "params_why", "modifieds", "preserveds",
104 "reach_exit", "reach_exit_maybe", "calls_live_out", "noreturn",
109 if prop
in cfg
.props
:
110 func_props
[prop
] = cfg
.props
[prop
]
112 for prop
in ("calls", "calls_indir", "func_refs", "mmio_refs"):
113 if prop
in cfg
.props
:
120 if x
.op
== "+" and len(x
.args
) == 2:
121 if is_value(x
.args
[1]):
122 x
= EXPR("+", [x
.args
[1], x
.args
[0]])
125 func_props
[prop
] = sorted([ext_repr(x
) for x
in cfg
.props
[prop
]])
128 # Updated funcs tracking
131 UPDATED_FUNCS
= set()
134 UPDATED_FUNCS
.clear()
136 def mark_updated(func
):
137 UPDATED_FUNCS
.add(func
)
139 def update_cfg_prop(cfg
, prop
, new_val
):
140 if cfg
.props
.get(prop
) != new_val
:
141 mark_updated(cfg
.props
["name"])
142 _log
.info("%s: %s updated from %s to %s" % (cfg
.props
["name"], prop
,
143 utils
.repr_stable(cfg
.props
.get(prop
)), utils
.repr_stable(new_val
)))
144 cfg
.props
[prop
] = new_val
152 def load_symtab(fname
):
153 with
open(fname
) as f
:
156 addr
, sym
= l
.split()
157 SYMTAB
[sym
] = int(addr
, 16)
159 # Returns real memory (not symbolic) address, for bindata module.
164 # Struct database functions
167 def set_struct_types(data
):
172 def set_struct_instances(data
):
173 global struct_instances
174 struct_instances
= data
177 def get_struct_types():
182 def get_struct_instances():
183 global struct_instances
184 return struct_instances