123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202(**************************************************************************)(* *)(* 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 *);value_initial_state:Cvalue.Model.t(** State of Eva at the beginning of
the call *);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_fromscallstack_kfcall_typevalue_initial_state=ifFrom_parameters.ForceCallDeps.get()thenbeginletcurrent_function,call_site=List.hdcallstackinletregister_fromfroms=record_callwise_dependencies_in_dbcall_sitefroms;match!call_froms_stackwith|{table_for_calls}::_->merge_call_fromstable_for_callscall_sitefroms;|[]->(* Empty call stack: this is the main entry point with no call site. *)assert(call_site=Cil_types.Kglobal);inletcompute_from_behaviorsbhv=letassigns=Ast_info.merge_assignsbhvinletfroms=From_compute.compute_using_prototype_for_statevalue_initial_statecurrent_functionassignsinregister_fromfromsinmatchcall_typewith|`Def|`Memexec->lettable_for_calls=Kinstr.Hashtbl.create7incall_froms_stack:={current_function;value_initial_state;table_for_calls}::!call_froms_stack|`Builtin(Some(result,_))->register_fromresult|`BuiltinNone->letbehaviors=Eva.Logic_inout.valid_behaviorscurrent_functionvalue_initial_stateincompute_from_behaviorsbehaviors|`Specspec->compute_from_behaviorsspec.Cil_types.spec_behaviorendletend_recordcall_stackfroms=let(current_function_value,call_site)=List.hdcall_stackinrecord_callwise_dependencies_in_dbcall_sitefroms;(* pop + record in top of stack the froms of function that just finished *)match!call_froms_stackwith|{current_function}::({table_for_calls=table}::_astail)->ifcurrent_function_value!=current_functionthenFrom_parameters.fatal"calldeps %a != %a@."Kernel_function.prettycurrent_functionKernel_function.prettycurrent_function_value;call_froms_stack:=tail;merge_call_fromstablecall_sitefroms|_->(* the entry point, probably *)Tbl.mark_as_computed();call_froms_stack:=[]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_fromscallstackcur_kfvalue_res=ifFrom_parameters.ForceCallDeps.get()thenbeginletfroms=matchvalue_reswith|Eva.Cvalue_callbacks.Store({before_stmts},memexec_counter)->letfroms=ifEva.Analysis.save_resultscur_kfthencompute_call_from_value_statescur_kf(Lazy.forcebefore_stmts)elseFunction_Froms.topinletpre_state=match!call_froms_stackwith|[]->assertfalse|{value_initial_state}::_->value_initial_stateinifFrom_parameters.VerifyAssigns.get()thenEva.Logic_inout.verify_assignscur_kf~pre:pre_statefroms;MemExec.replacememexec_counterfroms;froms|Reusecounter->MemExec.findcounterinend_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:
*)