package frama-c
Platform dedicated to the analysis of source code written in C
Install
Dune Dependency
Authors
-
MMichele Alberti
-
TThibaud Antignac
-
GGergö Barany
-
PPatrick Baudin
-
NNicolas Bellec
-
TThibaut Benjamin
-
AAllan Blanchard
-
LLionel Blatter
-
FFrançois Bobot
-
RRichard Bonichon
-
VVincent Botbol
-
QQuentin Bouillaguet
-
DDavid Bühler
-
ZZakaria Chihani
-
LLoïc Correnson
-
JJulien Crétin
-
PPascal Cuoq
-
ZZaynah Dargaye
-
BBasile Desloges
-
JJean-Christophe Filliâtre
-
PPhilippe Herrmann
-
MMaxime Jacquemin
-
FFlorent Kirchner
-
AAlexander Kogtenkov
-
RRemi Lazarini
-
TTristan Le Gall
-
JJean-Christophe Léchenet
-
MMatthieu Lemerre
-
DDara Ly
-
DDavid Maison
-
CClaude Marché
-
AAndré Maroneze
-
TThibault Martin
-
FFonenantsoa Maurica
-
MMelody Méaulle
-
BBenjamin Monate
-
YYannick Moy
-
PPierre Nigron
-
AAnne Pacalet
-
VValentin Perrelle
-
GGuillaume Petiot
-
DDario Pinto
-
VVirgile Prevosto
-
AArmand Puccetti
-
FFélix Ridoux
-
VVirgile Robles
-
JJan Rochel
-
MMuriel Roger
-
JJulien Signoles
-
NNicolas Stouls
-
KKostyantyn Vorobyov
-
BBoris Yakobowski
Maintainers
Sources
frama-c-29.0-Copper.tar.gz
sha256=d2fbb3b8d0ff83945872e9e6fa258e934a706360e698dae3b4d5f971addf7493
doc/src/frama-c-slicing.core/slicingProject.ml.html
Source file slicingProject.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 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 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
(**************************************************************************) (* *) (* This file is part of Frama-C. *) (* *) (* Copyright (C) 2007-2024 *) (* CEA (Commissariat à l'énergie atomique et aux énergies *) (* alternatives) *) (* *) (* you can redistribute it and/or modify it under the terms of the GNU *) (* Lesser General Public License as published by the Free Software *) (* Foundation, version 2.1. *) (* *) (* It 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 Lesser General Public License for more details. *) (* *) (* See the GNU Lesser General Public License version 2.1 *) (* for more details (enclosed in the file licenses/LGPLv2.1). *) (* *) (**************************************************************************) (** Handle the project global object. *) (**/**) open Pdg_types module T = SlicingInternals module M = SlicingMacros (**/**) (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*) (** {2 Managing the slices} *) let add_proj_actions actions = let proj = SlicingState.get () in proj.T.actions <- actions @ proj.T.actions (** Add a new slice for the function. It can be the case that it create actions * if the function has some persistent selection, that make function calls to * choose. * @raise SlicingTypes.NoPdg when the function has no PDG. * *) let create_slice kf = let ff, actions = Fct_slice.make_new_ff (M.get_kf_fi kf) true in add_proj_actions actions; ff (** Delete [ff_to_remove] if it is not called. * @raise T.CantRemoveCalledFf if it is. *) let remove_ff ff_to_remove = let rec remove ff_list ff_num = match ff_list with | [] -> raise Not_found | ff :: tail -> if ff.T.ff_id = ff_num then (Fct_slice.clear_ff ff; tail) else ff :: (remove tail ff_num) in let fi = ff_to_remove.T.ff_fct in let ff_num = ff_to_remove.T.ff_id in let new_ff_list = remove fi.T.fi_slices ff_num in fi.T.fi_slices <- new_ff_list let call_src_and_remove_all_ff fi = let do_call actions (ff_caller, call_id) = let new_actions = Fct_slice.apply_change_call ff_caller call_id (T.CallSrc (Some fi)) in new_actions @ actions in let do_ff actions ff = let calls = ff.SlicingInternals.ff_called_by in let actions = List.fold_left do_call actions calls in remove_ff ff; actions in List.fold_left do_ff [] fi.T.fi_slices let rec remove_uncalled_slices () = let kf_entry, _ = Globals.entry_point () in let entry_name = Kernel_function.get_name kf_entry in let check_ff changes ff = match ff.T.ff_called_by with [] -> remove_ff ff; true | _ -> changes in let check_fi changes fi = if (M.fi_name fi) <> entry_name then List.fold_left check_ff changes (M.fi_slices fi) else changes in let changes = M.fold_fi check_fi false in if changes then remove_uncalled_slices () else () (** Build a new slice [ff] which contains the marks of [ff1] and [ff2] * and generate everything that is needed to choose the calls in [ff]. * If [replace] also generate requests call [ff] instead of [ff1] and [ff2]. *) let merge_slices ff1 ff2 replace = let ff, ff_actions = Fct_slice.merge_slices ff1 ff2 in if replace then begin let add actions (caller, call) = let rq = SlicingActions.mk_crit_change_call caller call (T.CallSlice ff) in rq :: actions in let actions = List.fold_left add [] ff2.T.ff_called_by in let actions = List.fold_left add actions ff1.T.ff_called_by in add_proj_actions actions end; add_proj_actions ff_actions; ff let split_slice ff = let add (actions, slices) (caller, call) = let new_ff = Fct_slice.copy_slice ff in let rq = SlicingActions.mk_crit_change_call caller call (T.CallSlice new_ff) in rq::actions, new_ff::slices in let calls = List.tl ff.T.ff_called_by in (* keep ff for the first call *) let actions, slices = List.fold_left add ([], [ff]) calls in add_proj_actions actions; slices (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*) (** {2 Getting information } *) let get_slices kf = M.fi_slices (M.get_kf_fi kf) let get_slice_callers ff = List.map (fun (ff, _) -> ff) ff.T.ff_called_by (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*) (** {2 Adding requests } *) let add_filter filter = let proj = SlicingState.get () in proj.T.actions <- filter :: proj.T.actions (* let add_fct_filter proj f_id criterion = let ff_res = match f_id with | T.FctSrc fi -> Fct_slice.make_new_ff fi | T.FctSliced ff -> ff in let filter = SlicingActions.mk_ff_user_crit ff_res criterion in let _ = add_filter proj filter in ff_res *) (** Add an action to the action list to filter the function [fct_id] with the given criterion. The filter gives a name to the result of the filter which is a new slice if the function to filter is the source one, or the given slice otherwise. *) let add_fct_src_filter fi to_select = match to_select with (* T.CuSelect [] : don't ignore empty selection because the input control node has to be selected anyway... *) | T.CuSelect select -> let filter = SlicingActions.mk_crit_fct_user_select fi select in add_filter filter | T.CuTop m -> let filter = SlicingActions.mk_crit_fct_top fi m in add_filter filter (* let add_fct_src_filters proj fi actions = List.iter (fun a -> ignore (add_fct_src_filter proj fi a)) actions *) let add_fct_ff_filter ff to_select = match to_select with | T.CuSelect [] -> SlicingParameters.debug ~level:1 "[SlicingProject.add_fct_ff_filter] (ignored empty selection)" | T.CuSelect select -> let filter = SlicingActions.mk_ff_user_select ff select in add_filter filter | T.CuTop _ -> assert false (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*) (** {2 Print} *) let print_project fmt = let get_slices var_fct = let kf = Globals.Functions.get var_fct in let fct_info = M.get_kf_fi kf in M.fi_slices fct_info in let print glob = match glob with | Cil_types.GFun (func, _) -> (* function definition *) let slices = get_slices func.Cil_types.svar in List.iter (PrintSlice.print_marked_ff fmt) slices (* TODO see if we have to print the original function *) | _ -> PrintSlice.print_original_glob fmt glob in let source = Ast.get () in let global_decls = source.Cil_types.globals in List.iter print global_decls let print_proj_worklist fmt = let proj = SlicingState.get () in Format.fprintf fmt "Slicing project worklist [%s] =@\n%a@.@." (Project.get_name (Project.current ())) SlicingActions.print_list_crit proj.T.actions let print_project_and_worklist fmt = print_project fmt; print_proj_worklist fmt let pretty_slice fmt ff = PrintSlice.print_marked_ff fmt ff; Format.pp_print_newline fmt () (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*) (** {2 Managing (and applying) requests} *) (** apply the given criterion and returns the list of new criteria to add to the project worklist. *) let apply_fct_crit ff to_select = let actions = Fct_slice.apply_add_marks ff to_select in actions let apply_appli_crit appli_crit = match appli_crit with | T.CaCall fi_to_call -> let kf_to_call = M.get_fi_kf fi_to_call in let add_actions actions kf_caller = let fi_caller = M.get_kf_fi kf_caller in let mark = SlicingMarks.mk_user_spare in let action = SlicingActions.mk_crit_mark_calls fi_caller kf_to_call mark in action :: actions in List.fold_left add_actions [] (Eva.Results.callers kf_to_call) | _ -> SlicingParameters.not_yet_implemented "This slicing criterion on application" (** Add persistent the marks [node_marks] in [fi] and also add the marks * to existing slices if any. * If the propagation is ON, some actions are generated to propagate the * persistent marks to the callers, and other actions are generated to * make all the calls to [fi] visible. * If there is no slice for [fi] we create a new one * if it is the original request. * It will be automatically created with the persistent marks. * If it is a propagation, no need to create a new slice * because it will be created when the call will be selected anyway. * *) let add_persistent_marks fi node_marks orig propagate actions = let new_fi_marks, actions = Fct_slice.add_marks_to_fi fi node_marks propagate actions in let actions = match M.fi_slices fi with | [] -> (* no slice *) let actions = if orig then let _ff, new_actions = Fct_slice.make_new_ff fi true in (* TODO catch NoPdg and mark fi as Top *) new_actions @ actions else actions in actions | slices -> let add_filter acc ff = let a = SlicingActions.mk_ff_user_select ff node_marks in a::acc in List.fold_left add_filter actions slices in let actions = if propagate && new_fi_marks then let a = SlicingActions.mk_appli_select_calls fi in actions @ [a] else actions in actions let apply_fct_action fct_crit = match fct_crit.T.cf_fct with | T.FctSliced ff -> let _ = M.get_ff_pdg ff in let new_filters = match fct_crit.T.cf_info with | T.CcUserMark (T.CuSelect []) -> SlicingParameters.debug ~level:1 "[apply_fct_action] ignore empty selection on existing slice"; [] | T.CcUserMark (T.CuSelect crit) -> apply_fct_crit ff crit | T.CcUserMark (T.CuTop _) -> assert false (* impossible on ff ! *) | T.CcChangeCall (call, f) -> Fct_slice.apply_change_call ff call f | T.CcChooseCall call -> Fct_slice.apply_choose_call ff call | T.CcMissingInputs (call, input_marks, more_inputs) -> Fct_slice.apply_missing_inputs ff call (input_marks, more_inputs) | T.CcMissingOutputs (call, output_marks, more_outputs) -> Fct_slice.apply_missing_outputs ff call output_marks more_outputs | T.CcPropagate _ -> assert false (* not for ff at the moment *) | T.CcExamineCalls marks -> Fct_slice.apply_examine_calls ff marks in SlicingParameters.debug ~level:4 "[slicingProject.apply_fct_action] result =@\n%a" PrintSlice.print_marked_ff ff; new_filters | T.FctSrc fi -> (* the marks have to be added to all slices *) let propagate = SlicingParameters.Mode.Callers.get () in match fct_crit.T.cf_info with | T.CcUserMark (T.CuSelect to_select) -> add_persistent_marks fi to_select true propagate [] | T.CcUserMark (T.CuTop m) -> SlicingParameters.result ~level:1 "unable to slice %s (-> TOP)" (M.fi_name fi); let filters = call_src_and_remove_all_ff fi in Fct_slice.add_top_mark_to_fi fi m propagate filters | T.CcPropagate [] -> SlicingParameters.debug ~level:1 "[apply_fct_action] nothing to propagate"; [] | T.CcPropagate node_marks -> add_persistent_marks fi node_marks false propagate [] | T.CcExamineCalls _ | _ -> SlicingParameters.not_yet_implemented "This slicing criterion on source function" (** apply [filter] and return a list of generated filters *) let apply_action filter = SlicingParameters.debug ~level:1 "[SlicingProject.apply_action] : %a" SlicingActions.print_crit filter; let new_filters = try match filter with | T.CrFct fct_crit -> begin try (apply_fct_action fct_crit) with PdgTypes.Pdg.Bottom -> SlicingParameters.debug ~level:1 " -> action ABORTED (PDG is bottom)" ; [] end | T.CrAppli appli_crit -> apply_appli_crit appli_crit with Not_found -> (* catch unprocessed Not_found here *) assert false in SlicingParameters.debug ~level:1 " -> %d generated filters : %a@." (List.length new_filters) SlicingActions.print_list_crit new_filters; new_filters let get_next_filter () = let proj = SlicingState.get () in match proj.T.actions with | [] -> SlicingParameters.debug ~level:2 "[SlicingProject.get_next_filter] No more filter"; raise Not_found | f :: tail -> proj.T.actions <- tail; f let apply_next_action () = SlicingParameters.debug ~level:2 "[SlicingProject.apply_next_action]"; let proj = SlicingState.get () in let filter = get_next_filter () in let new_filters = apply_action filter in proj.T.actions <- new_filters @ proj.T.actions let is_request_empty () = let proj = SlicingState.get () in proj.T.actions = [] let apply_all_actions () = let proj = SlicingState.get () in let nb_actions = List.length proj.T.actions in let rec apply actions = match actions with [] -> () | a::actions -> SlicingParameters.feedback ~level:2 "applying sub action..."; let new_filters = apply_action a in apply new_filters; apply actions in SlicingParameters.feedback ~level:1 "applying %d actions..." nb_actions; let rec apply_user n = try let a = get_next_filter () in SlicingParameters.feedback ~level:1 "applying actions: %d/%d..." n nb_actions; let new_filters = apply_action a in apply new_filters; apply_user (n+1) with Not_found -> if nb_actions > 0 then SlicingParameters.feedback ~level:2 "done (applying %d actions." nb_actions in apply_user 1 (* Local Variables: compile-command: "make -C ../../.." End: *)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>