Source file defs.ml
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
(** Find the statements that defines a given data at a program point,
* ie. in each backward path starting from this point, find the statement
* the the data has been assigned for the last time. *)
open Cil_datatype
open Cil_types
open Pdg_types
let debug1 fmt = Datascope.R.debug ~level:1 fmt
module Interproc =
Datascope.R.True(struct
let option_name = "-scope-defs-interproc"
let help = "interprocedural defs computation"
end)
module NSet = PdgTypes.Node.Set
let add_list_to_set l s = List.fold_left (fun r n -> NSet.add n r) s l
let _pp_list_node_underout prefix fmt =
Pretty_utils.pp_list ~pre:(prefix ^^ " @[") ~suf:"@]@." ~sep:"@ "
(fun fmt (n, undef) ->
match undef with
| None -> PdgTypes.Node.pretty fmt n
| Some undef ->
Format.fprintf fmt "%a {underout %a}"
PdgTypes.Node.pretty n Locations.Zone.pretty undef)
fmt
let _pp_set prefix fmt =
Pretty_utils.pp_iter ~pre:(prefix ^^ " @[") ~suf:"@]@." ~sep:"@ "
NSet.iter PdgTypes.Node.pretty fmt
(** The nodes [nodes] define the searched location [z]. If those nodes are calls
to functions, go inside those calls, and find which nodes are relevant. *)
let rec add_callee_nodes z acc nodes =
let new_nodes, acc = NSet.fold
(fun node acc2 ->
match Pdg.Api.node_key node with
| PdgIndex.Key.SigCallKey (cid, PdgIndex.Signature.Out out_key) ->
let callees = Eva.Results.callee (PdgIndex.Key.call_from_id cid) in
List.fold_left (fun (new_nodes, acc) kf ->
let callee_pdg = Pdg.Api.get kf in
let outputs = match out_key with
| PdgIndex.Signature.OutLoc out ->
let z = Locations.Zone.narrow out z in
fst (Pdg.Api.find_location_nodes_at_end callee_pdg z)
| PdgIndex.Signature.OutRet ->
fst (Pdg.Api.find_output_nodes callee_pdg out_key)
in
let outputs = List.map fst outputs in
add_list_to_set outputs new_nodes, add_list_to_set outputs acc)
acc2
callees
| _ -> acc2)
nodes
(NSet.empty, acc)
in if NSet.is_empty new_nodes then acc else add_callee_nodes z acc new_nodes
(** [kf] doesn't define all the data that we are looking for: the [undef]
zone must have been defined in its caller, let's find it. [z] is the
initial zone that we are looking for, so that we do not look for more
than it. *)
let rec add_caller_nodes z kf acc (undef, nodes) =
let join_undef u u' = match u, u' with
| _, None -> u
| None, Some _ -> u'
| Some z, Some z' -> Some (Locations.Zone.join z z')
in
let add_one_call_nodes pdg (acc_undef, acc) stmt =
let acc_undef, acc = match undef with
| None -> acc_undef, acc
| Some undef ->
let nodes_for_undef, undef' =
Pdg.Api.find_location_nodes_at_stmt pdg stmt ~before:true undef
in
let acc_undef = join_undef acc_undef undef' in
let acc = add_list_to_set (List.map fst nodes_for_undef) acc in
acc_undef, acc
in
let add_call_input_nodes node (acc_undef, acc) =
match Pdg.Api.node_key node with
| PdgIndex.Key.SigKey (PdgIndex.Signature.In in_key) ->
begin match in_key with
| PdgIndex.Signature.InCtrl ->
acc_undef, acc
| PdgIndex.Signature.InNum n_param ->
let n = Pdg.Api.find_call_input_node pdg stmt n_param in
acc_undef, NSet.add n acc
| PdgIndex.Signature.InImpl z' ->
let z = Locations.Zone.narrow z z' in
let nodes, undef'= Pdg.Api.find_location_nodes_at_stmt
pdg stmt ~before:true z
in
let acc_undef = join_undef acc_undef undef' in
acc_undef, add_list_to_set (List.map fst nodes) acc
end
| _ -> acc_undef, acc
in
NSet.fold add_call_input_nodes nodes (acc_undef, acc)
in
let add_one_caller_nodes acc (kf, stmts) =
let pdg = Pdg.Api.get kf in
let acc_undef, caller_nodes =
List.fold_left (add_one_call_nodes pdg) (None, NSet.empty) stmts
in add_caller_nodes z kf (NSet.union caller_nodes acc) (acc_undef, caller_nodes)
in List.fold_left add_one_caller_nodes acc (Eva.Results.callsites kf)
let compute_aux kf stmt zone =
debug1 "[Defs.compute] for %a at sid:%d in '%a'@."
Locations.Zone.pretty zone stmt.sid Kernel_function.pretty kf;
try
let pdg = Pdg.Api.get kf in
let nodes, undef =
Pdg.Api.find_location_nodes_at_stmt pdg stmt ~before:true zone
in
let nodes = add_list_to_set (List.map fst nodes) NSet.empty in
let nodes =
if Interproc.get () then
begin
let caller_nodes = add_caller_nodes zone kf nodes (undef, nodes) in
add_callee_nodes zone caller_nodes caller_nodes
end
else nodes
in
Some (nodes, undef)
with Pdg.Api.Bottom | Pdg.Api.Top | Not_found ->
None
let compute kf stmt lval =
let (nodes, undef) =
let add_node node defs =
match PdgIndex.Key.stmt (Pdg.Api.node_key node) with
| None -> defs
| Some s -> Stmt.Hptset.add s defs
in
let defs = NSet.fold add_node nodes Stmt.Hptset.empty in
(defs, undef)
in
Eva.Analysis.compute ();
let zone = Eva.Results.(before stmt |> eval_address lval |> as_zone) in
compute_aux kf stmt zone |> Option.map extract
let compute_with_def_type_zone kf stmt zone =
let (nodes, undef) =
let add_node node acc =
let change stmt (direct, indirect) =
let (prev_d, pred_i) =
try Stmt.Map.find stmt acc
with Not_found -> (false, false)
in
let after = (direct || prev_d, indirect || pred_i) in
Stmt.Map.add stmt after acc
in
match Pdg.Api.node_key node with
| PdgIndex.Key.Stmt s -> change s (true, false)
| PdgIndex.Key.CallStmt _ -> assert false
| PdgIndex.Key.SigCallKey (s, sign) ->
(match sign with
| PdgIndex.Signature.Out (PdgIndex.Signature.OutRet) ->
change s (true, false)
| PdgIndex.Signature.In _ ->
change s (true, false)
| PdgIndex.Signature.Out (PdgIndex.Signature.OutLoc _) -> begin
match s.skind with
| Instr (Call (_, { enode = Lval (Var vi, NoOffset)}, _, _)
| Local_init (_, ConsInit(vi,_,_),_))
when let kf = Globals.Functions.get vi in
Eva.Analysis.use_spec_instead_of_definition kf
->
change s (true, false)
| _ ->
change s (false, true)
end
)
| PdgIndex.Key.SigKey _ -> acc
| s -> Format.printf "## %a@." PdgIndex.Key.pretty s; acc
in
let stmts = NSet.fold add_node nodes Stmt.Map.empty in
(stmts, undef)
in
Option.map extract (compute_aux kf stmt zone)
let compute_with_def_type kf stmt lval =
Eva.Analysis.compute ();
let zone =
Eva.Results.(before stmt |> eval_address lval |> as_zone)
in
compute_with_def_type_zone kf stmt zone
let get_defs = compute
let get_defs_with_type = compute_with_def_type