123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)(** Provides function to extract information from the PDG. *)openCil_typesopenPdg_typesopenPdgIndextypenodes_and_undef=(PdgTypes.Node.t*Locations.Zone.toption)list*Locations.Zone.toptionletget_init_statepdg=tryPdg_state.get_init_state(PdgTypes.Pdg.get_statespdg)withNot_found->assertfalse(** @raise Not_found when no last state (strange !) *)letget_last_statepdg=Pdg_state.get_last_state(PdgTypes.Pdg.get_statespdg)(** @raise Not_found for unreachable stmt *)letget_stmt_statepdgstmt=Pdg_state.get_stmt_state(PdgTypes.Pdg.get_statespdg)stmtletfind_nodepdgkey=FctIndex.find_info(PdgTypes.Pdg.get_indexpdg)key(** notice that there can be several nodes if the statement is a call.
* For If, Switch, ... the node represent only the condition
* (see find_stmt_nodes below).
*)letfind_simple_stmt_nodespdgstmt=letidx=PdgTypes.Pdg.get_indexpdginletkey=Key.stmt_keystmtin(* The call below can raise Not_found if the statement is unreachable *)letnodes=FctIndex.find_allidxkeyinmatchstmt.skindwith|Return_->(* also add OutRet *)(tryletret=FctIndex.find_allidxKey.output_keyinret@nodeswithNot_found->nodes)|_->nodesletrecadd_stmt_nodespdgnodess=lets_nodes=tryfind_simple_stmt_nodespdgswithNot_found->[](* Catch the fact that s may correspond to no node,
for example if [s] is dead code *)inletnodes=s_nodes@nodesinletaddaccstmt=(* Catch the fact that a sub-statement of s may be unreachable *)tryadd_stmt_nodespdgaccstmtwithNot_found->accinletadd_block_stmts_nodesnode_listblk=List.fold_leftaddnode_listblk.bstmtsinmatchs.skindwith|Switch(_,blk,_,_)|Loop(_,blk,_,_,_)|Blockblk->Pdg_parameters.debug~level:2" select_stmt_computation on composed stmt %d@."s.sid;add_block_stmts_nodesnodesblk|UnspecifiedSequenceseq->Pdg_parameters.debug~level:2" select_stmt_computation on composed stmt %d@."s.sid;add_block_stmts_nodesnodes(Cil.block_from_unspecified_sequenceseq)|If(_,bthen,belse,_)->letnodes=add_block_stmts_nodesnodesbtheninadd_block_stmts_nodesnodesbelse|_->nodes(** notice that there can be several nodes if the statement is a call.
* If the stmt is a composed instruction (block, etc), all the nodes of the
* enclosed statements are considered.
*)letfind_stmt_and_blocks_nodespdgstmt=add_stmt_nodespdg[]stmtletfind_stmt_nodepdgstmt=find_nodepdg(Key.stmt_keystmt)letfind_entry_point_nodepdg=tryfind_nodepdgKey.entry_pointwithNot_found->assertfalseletfind_top_input_nodepdg=find_nodepdgKey.top_inputletfind_loc_nodespdgstateloc=letnodes,undef=Pdg_state.get_loc_nodesstatelocinletnodes,undef=matchundefwith|Someundef->letstate=get_init_statepdginletinit_nodes,init_undef=Pdg_state.get_loc_nodesstateundefinletinit_nodes=matchlocwith|Locations.Zone.Top(_,_)->begintry(find_top_input_nodepdg,None)::init_nodeswithNot_found->init_nodesend|_->init_nodesinletnodes=List.fold_left(funaccn->n::acc)nodesinit_nodesinnodes,init_undef|None->nodes,undefinnodes,undefletfind_location_nodes_at_stmtpdgstmt~beforeloc=letget_nodesstate=find_loc_nodespdgstatelocinletget_stmt_nodesstmt=get_nodes(get_stmt_statepdgstmt)inletget_stmts_nodesstmts=letadd(acc_nodes,acc_loc)stmt=letnodes,undef=get_stmt_nodesstmtinletacc_nodes=nodes@acc_nodesinletacc_loc=matchacc_loc,undefwith|_,None->acc_loc|None,_->undef|Someacc_loc,Someundef->Some(Locations.Zone.joinacc_locundef)in(acc_nodes,acc_loc)inList.fold_leftadd([],None)stmtsinletnodes,undef_zone=ifbeforethenget_stmt_nodesstmtelsematchstmt.skind,stmt.succswith|Return_,[]->get_nodes(get_last_statepdg)|_,[]->(* no successors but not a return => unreachable *)raiseNot_found|_,succs->get_stmts_nodessuccsinnodes,undef_zoneletfind_location_nodes_at_endpdgloc=find_loc_nodespdg(get_last_statepdg)loc(* be careful that begin is different from init because
* init_state only contains implicit inputs
* while begin contains only formal arguments *)letfind_location_nodes_at_beginpdgloc=letkf=PdgTypes.Pdg.get_kfpdginletstmts=ifEva.Analysis.use_spec_instead_of_definitionkfthen[]elseletf=Kernel_function.get_definitionkfinf.sbody.bstmtsinletstate=matchstmtswith|[]->get_last_statepdg|stmt::_->get_stmt_statepdgstmtinfind_loc_nodespdgstatelocletfind_label_nodepdglabel_stmtlabel=find_nodepdg(Key.label_keylabel_stmtlabel)letfind_decl_var_nodepdgv=find_nodepdg(Key.decl_var_keyv)letfind_output_nodepdg=find_nodepdgKey.output_keyletfind_input_nodepdgnumin=letsgn=FctIndex.sgn(PdgTypes.Pdg.get_indexpdg)inPdgIndex.Signature.find_inputsgnnuminletfind_all_input_nodespdg=letsgn=FctIndex.sgn(PdgTypes.Pdg.get_indexpdg)inletaddacc(_in_key,info)=info::accinPdgIndex.Signature.fold_all_inputsadd[]sgnletfind_call_input_nodespdg_callercall_stmtin_key=matchin_keywith|PdgIndex.Signature.InCtrl|PdgIndex.Signature.InNum_->letidx=PdgTypes.Pdg.get_indexpdg_callerinlet_,call_sgn=FctIndex.find_callidxcall_stmtinletnode=PdgIndex.Signature.find_in_infocall_sgnin_keyin[node,None],None|PdgIndex.Signature.InImplzone->find_location_nodes_at_stmtpdg_callercall_stmt~before:truezoneletfind_call_ctrl_nodepdgstmt=letkey=Key.call_ctrl_keystmtinfind_nodepdgkeyletfind_call_num_input_nodepdgcallnum_in=ifnum_in=0thenPdg_parameters.fatal"0 is not an input number";letkey=Key.call_input_keycallnum_ininfind_nodepdgkeyletfind_call_output_nodepdgcall=letkey=Key.call_outret_keycallinfind_nodepdgkeyletfind_output_nodescalled_pdgout_key=matchout_keywith|PdgIndex.Signature.OutRet->[find_output_nodecalled_pdg,None],None|PdgIndex.Signature.OutLocout->find_location_nodes_at_endcalled_pdgoutletfind_call_stmtskf~caller=matchList.filter(fun(f,_)->Kernel_function.equalfcaller)(Eva.Results.callsiteskf)with|[]->[]|[_,callsites]->assert(callsites<>[]);callsites|_->assertfalse(** {2 Build sets of nodes}
This parts groups the functions that build sets from the pdg.
Made to answer user questions rather that to build slice marks,
because efficient marking doesn't need to build this sets.
However, it might be useful to prove that it is the same... *)(** add the node in the list if it is not already in. *)letadd_node_in_listnodenode_list=letis_node_innodenode_list=letis_noden=(PdgTypes.Node.comparenoden)=0intrylet_=List.findis_nodenode_listintruewithNot_found->falseinifis_node_innodenode_listthennode_list,falseelse(node::node_list),true(** add the node to the list. It it wasn't already in the list,
* recursively call the same function on the successors or/and predecessors
* according to the flags. *)letrecadd_node_and_custom_dpdsget_dpdsnode_listnode=letnode_list,added=add_node_in_listnodenode_listinifaddedthenletis_block=matchPdgTypes.Node.elem_keynodewith|Key.SigKey(PdgIndex.Signature.InPdgIndex.Signature.InCtrl)->true|Key.Stmtstmt->(matchstmt.skindwithBlock_|UnspecifiedSequence_->true|_->false)|_->falseinifis_blockthennode_list(* blocks are not relevant to propagate information *)elseList.fold_left(add_node_and_custom_dpdsget_dpds)node_list(get_dpdsnode)elsenode_listletadd_nodes_and_custom_dpdsget_dpdsnode_listnodes=List.fold_left(add_node_and_custom_dpdsget_dpds)node_listnodesletcustom_related_nodesget_dpdsnodes=add_nodes_and_custom_dpdsget_dpds[]nodes(** we ignore z_part for the moment. TODO ? *)letfilter_nodesl=List.map(fun(n,_)->n)l(** {3 Backward} build sets of the dependencies of given nodes *)(** gives the list of nodes that the given node depends on,
without looking at the kind of dependency. *)letdirect_dpdspdgnode=filter_nodes(PdgTypes.Pdg.get_all_direct_dpdspdgnode)(** gives the list of nodes that the given node depends on,
with a given kind of dependency. *)letdirect_x_dpdsdpd_typepdgnode=filter_nodes(PdgTypes.Pdg.get_x_direct_dpdsdpd_typepdgnode)letdirect_data_dpds=direct_x_dpdsPdgTypes.Dpd.Dataletdirect_ctrl_dpds=direct_x_dpdsPdgTypes.Dpd.Ctrlletdirect_addr_dpds=direct_x_dpdsPdgTypes.Dpd.Addr(** accumulates in [node_list] the results of [add_node_and_dpds_or_codpds]
for all the [nodes] *)letfind_nodes_all_x_dpdsdpd_typepdgnodes=letmerge_dpdsnode_listnode=letnode_dpds=direct_x_dpdsdpd_typepdgnodeinadd_nodes_and_custom_dpds(direct_dpdspdg)node_listnode_dpdsinList.fold_leftmerge_dpds[]nodesletfind_nodes_all_dpdspdgnodes=letmerge_dpdsnode_listnode=letnode_dpds=direct_dpdspdgnodeinadd_nodes_and_custom_dpds(direct_dpdspdg)node_listnode_dpdsinList.fold_leftmerge_dpds[]nodesletfind_nodes_all_data_dpds=find_nodes_all_x_dpdsPdgTypes.Dpd.Dataletfind_nodes_all_ctrl_dpds=find_nodes_all_x_dpdsPdgTypes.Dpd.Ctrlletfind_nodes_all_addr_dpds=find_nodes_all_x_dpdsPdgTypes.Dpd.Addr(** {3 Forward} build sets of the nodes that depend on given nodes *)(** @return the list of nodes that directly depend on the given node *)letdirect_usespdgnode=filter_nodes(PdgTypes.Pdg.get_all_direct_codpdspdgnode)letdirect_x_usesdpd_typepdgnode=filter_nodes(PdgTypes.Pdg.get_x_direct_codpdsdpd_typepdgnode)letdirect_data_uses=direct_x_usesPdgTypes.Dpd.Dataletdirect_ctrl_uses=direct_x_usesPdgTypes.Dpd.Ctrlletdirect_addr_uses=direct_x_usesPdgTypes.Dpd.Addr(** @return a list containing all the nodes that depend on the given nodes. *)letall_usespdgnodes=letadd_codpdsnode_listnode=letcodpds=PdgTypes.Pdg.get_all_direct_codpdspdgnodeinletcodpds=filter_nodescodpdsinletgetn=filter_nodes(PdgTypes.Pdg.get_all_direct_codpdspdgn)inadd_nodes_and_custom_dpdsgetnode_listcodpdsinList.fold_leftadd_codpds[]nodes(** {3 Others} *)(* VP: unused function *)(*
let node_set_of_list l =
List.fold_left (fun acc n -> NodeSet.add n acc) NodeSet.empty l
*)(** @return the call outputs nodes [out] such that
[find_output_nodes pdg_called out_key]
intersects [called_selected_nodes]. *)letfind_call_out_nodes_to_selectpdg_calledcalled_selected_nodespdg_callercall_stmt=Pdg_parameters.debug~level:2"[pdg:find_call_out_nodes_to_select] for call sid:%d@."call_stmt.sid;let_,call_sgn=FctIndex.find_call(PdgTypes.Pdg.get_indexpdg_caller)call_stmtinlettest_outacc(out_key,call_out_node)=letcalled_out_nodes,_undef=find_output_nodespdg_calledout_keyin(* undef can be ignored in this case because it is taken into account in
* the call part. *)letintersect=List.exists(fun(n,_z)->PdgTypes.NodeSet.memncalled_selected_nodes)called_out_nodesinifintersectthenbeginPdg_parameters.debug~level:2"\t+ %a@."PdgTypes.Node.prettycall_out_node;call_out_node::accendelseaccinPdgIndex.Signature.fold_all_outputstest_out[]call_sgnletfind_in_nodes_to_select_for_this_callpdg_callercaller_selected_nodescall_stmtpdg_called=Pdg_parameters.debug~level:2"[pdg:find_in_nodes_to_select_for_this_call] for call sid:%d@."call_stmt.sid;letsgn=FctIndex.sgn(PdgTypes.Pdg.get_indexpdg_called)inlettest_inacc(in_key,in_node)=letcaller_nodes,_undef=find_call_input_nodespdg_callercall_stmtin_keyin(* undef can be ignored in this case because it is taken into account in
* the call part. *)letintersect=List.exists(fun(n,_z)->PdgTypes.NodeSet.memncaller_selected_nodes)caller_nodesinifintersectthenbeginPdg_parameters.debug~level:2"\t+ %a@."PdgTypes.Node.prettyin_node;in_node::accendelseaccinPdgIndex.Signature.fold_all_inputstest_in[]sgn(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)