123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* 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). *)(* *)(**************************************************************************)openCil_datatypemoduleTbl=Cil_state_builder.Kinstr_hashtbl(Function_Froms)(structletname="Callwise dependencies"letsize=17letdependencies=[Eva.Analysis.self]end)let()=From_parameters.ForceCallDeps.set_output_dependencies[Tbl.self]letmerge_call_fromstablecallsitefroms=tryletcurrent=Kinstr.Hashtbl.findtablecallsiteinletnew_froms=Function_Froms.joinfromscurrentinKinstr.Hashtbl.replacetablecallsitenew_fromswithNot_found->Kinstr.Hashtbl.addtablecallsitefroms(** State for the analysis of one function call *)typefrom_state={current_function:Kernel_function.t(** Function being analyzed *);table_for_calls:Function_Froms.tKinstr.Hashtbl.t(** State of the From plugin for each statement containing a function call
in the body of [current_function]. Updated incrementally each time
Value analyses such a statement *);}(** The state of the callwise From analysis. Only the top of this callstack
is accessed. New calls are pushed on the stack when Value starts the
analysis of a function, and popped when the analysis finishes. This
stack is manually synchronized with Value's callstack. *)letcall_froms_stack:from_statelistref=ref[]letrecord_callwise_dependencies_in_dbcall_sitefroms=tryletprevious=Tbl.findcall_siteinTbl.replacecall_site(Function_Froms.joinpreviousfroms)withNot_found->Tbl.addcall_sitefromsletcall_for_individual_froms_callstackcurrent_function_statecall_type=ifFrom_parameters.ForceCallDeps.get()thenbeginmatchcall_typewith|`Body->lettable_for_calls=Kinstr.Hashtbl.create7incall_froms_stack:={current_function;table_for_calls}::!call_froms_stack|`Reuse|`Builtin|`Spec->()endletpop_local_tablekf=match!call_froms_stackwith|{current_function}::tail->ifkf!=current_functionthenFrom_parameters.fatal"calldeps %a != %a@."Kernel_function.prettycurrent_functionKernel_function.prettykf;call_froms_stack:=tail|_->From_parameters.fatal"calldeps: internal stack is empty"letend_recordcallstackfroms=letcallsite=Eva.Callstack.top_callsitecallstackinrecord_callwise_dependencies_in_dbcallsitefroms;matchcallsite,!call_froms_stackwith|Kstmt_,{table_for_calls}::_->merge_call_fromstable_for_callscallsitefroms|Kglobal,[]->(* the entry point *)Tbl.mark_as_computed()|_->From_parameters.fatal"calldeps: internal stack is inconsistent with Eva callstack"moduleMemExec=State_builder.Hashtbl(Datatype.Int.Hashtbl)(Function_Froms)(structletsize=17letdependencies=[Tbl.self]letname="From.Callwise.MemExec"end)letcompute_call_from_value_statescurrent_functionstates=letmoduleTo_Use=structletget_from_call_fcallsite=let{table_for_calls}=List.hd!call_froms_stackintryKinstr.Hashtbl.findtable_for_calls(Cil_types.Kstmtcallsite)withNot_found->raiseFrom_compute.Call_did_not_take_placeletstmt_requeststmt=Eva.Results.in_cvalue_state(tryStmt.Hashtbl.findstatesstmtwithNot_found->Cvalue.Model.bottom)letkeep_basekfbase=letfundec=Kernel_function.get_definitionkfinnot(Base.is_formal_or_localbasefundec)letcleanup_and_save_kffroms=fromsendinletmoduleCallwise_Froms=From_compute.Make(To_Use)inCallwise_Froms.compute_and_returncurrent_functionletrecord_for_individual_fromscallstackkfpre_statevalue_res=ifFrom_parameters.ForceCallDeps.get()thenbeginletfroms=matchvalue_reswith|`Body(Eva.Cvalue_callbacks.{before_stmts},memexec_counter)->letfroms=ifEva.Analysis.save_resultskfthencompute_call_from_value_stateskf(Lazy.forcebefore_stmts)elseFunction_Froms.topinifFrom_parameters.VerifyAssigns.get()thenEva.Logic_inout.verify_assignskf~pre:pre_statefroms;MemExec.replacememexec_counterfroms;pop_local_tablekf;froms|`Reusecounter->MemExec.findcounter|`Builtin(_states,Some(result,_))->result|`Builtin(_states,None)|`Spec_states->letbhv=Eva.Logic_inout.valid_behaviorskfpre_stateinletassigns=Ast_info.merge_assignsbhvinFrom_compute.compute_using_prototype_for_statepre_statekfassignsinend_recordcallstackfromsend(* Register our callbacks inside the value analysis *)let()=Eva.Cvalue_callbacks.register_call_hookcall_for_individual_froms;Eva.Cvalue_callbacks.register_call_results_hookrecord_for_individual_fromsletiter=Tbl.iterletfind=Tbl.findletcompute_all_calldeps()=ifnot(Tbl.is_computed())thenbeginifEva.Analysis.is_computed()thenProject.clear~selection:(State_selection.with_dependenciesEva.Analysis.self)();Eva.Analysis.compute()end(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)