123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)(** 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. *)openCil_datatypeopenCil_typesopenPdg_typesletdebug1fmt=Datascope.R.debug~level:1fmtmoduleInterproc=Datascope.R.True(structletoption_name="-scope-defs-interproc"lethelp="interprocedural defs computation"end)moduleNSet=PdgTypes.Node.Setletadd_list_to_setls=List.fold_left(funrn->NSet.addnr)sllet_pp_list_node_underoutprefixfmt=Pretty_utils.pp_list~pre:(prefix^^" @[")~suf:"@]@."~sep:"@ "(funfmt(n,undef)->matchundefwith|None->PdgTypes.Node.prettyfmtn|Someundef->Format.fprintffmt"%a {underout %a}"PdgTypes.Node.prettynLocations.Zone.prettyundef)fmtlet_pp_setprefixfmt=Pretty_utils.pp_iter~pre:(prefix^^" @[")~suf:"@]@."~sep:"@ "NSet.iterPdgTypes.Node.prettyfmt(** 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. *)letrecadd_callee_nodeszaccnodes=letnew_nodes,acc=NSet.fold(funnodeacc2->matchPdg.Api.node_keynodewith|PdgIndex.Key.SigCallKey(cid,PdgIndex.Signature.Outout_key)->letcallees=Eva.Results.callee(PdgIndex.Key.call_from_idcid)inList.fold_left(fun(new_nodes,acc)kf->letcallee_pdg=Pdg.Api.getkfinletoutputs=matchout_keywith|PdgIndex.Signature.OutLocout->(* [out] might be an over-approximation of the location
we are searching for. We refine the search if needed. *)letz=Locations.Zone.narrowoutzinfst(Pdg.Api.find_location_nodes_at_endcallee_pdgz)|PdgIndex.Signature.OutRet->(* probably never occurs *)fst(Pdg.Api.find_output_nodescallee_pdgout_key)inletoutputs=List.mapfstoutputsinadd_list_to_setoutputsnew_nodes,add_list_to_setoutputsacc)acc2callees|_->acc2)nodes(NSet.empty,acc)inifNSet.is_emptynew_nodesthenaccelseadd_callee_nodeszaccnew_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. *)(* BYTODO: maybe [undef] could be used instead of [z] altogether *)letrecadd_caller_nodeszkfacc(undef,nodes)=letjoin_undefuu'=matchu,u'with|_,None->u|None,Some_->u'|Somez,Somez'->Some(Locations.Zone.joinzz')inletadd_one_call_nodespdg(acc_undef,acc)stmt=letacc_undef,acc=matchundefwith|None->acc_undef,acc|Someundef->letnodes_for_undef,undef'=Pdg.Api.find_location_nodes_at_stmtpdgstmt~before:trueundefinletacc_undef=join_undefacc_undefundef'inletacc=add_list_to_set(List.mapfstnodes_for_undef)accinacc_undef,accinletadd_call_input_nodesnode(acc_undef,acc)=matchPdg.Api.node_keynodewith|PdgIndex.Key.SigKey(PdgIndex.Signature.Inin_key)->beginmatchin_keywith|PdgIndex.Signature.InCtrl->(* We only look for the values *)acc_undef,acc|PdgIndex.Signature.InNumn_param->letn=Pdg.Api.find_call_input_nodepdgstmtn_paraminacc_undef,NSet.addnacc|PdgIndex.Signature.InImplz'->letz=Locations.Zone.narrowzz'inletnodes,undef'=Pdg.Api.find_location_nodes_at_stmtpdgstmt~before:truezinletacc_undef=join_undefacc_undefundef'inacc_undef,add_list_to_set(List.mapfstnodes)accend|_->acc_undef,accinNSet.foldadd_call_input_nodesnodes(acc_undef,acc)inletadd_one_caller_nodesacc(kf,stmts)=letpdg=Pdg.Api.getkfinletacc_undef,caller_nodes=List.fold_left(add_one_call_nodespdg)(None,NSet.empty)stmtsinadd_caller_nodeszkf(NSet.unioncaller_nodesacc)(acc_undef,caller_nodes)inList.fold_leftadd_one_caller_nodesacc(Eva.Results.callsiteskf)letcompute_auxkfstmtzone=debug1"[Defs.compute] for %a at sid:%d in '%a'@."Locations.Zone.prettyzonestmt.sidKernel_function.prettykf;tryletpdg=Pdg.Api.getkfinletnodes,undef=Pdg.Api.find_location_nodes_at_stmtpdgstmt~before:truezoneinletnodes=add_list_to_set(List.mapfstnodes)NSet.emptyinletnodes=ifInterproc.get()thenbeginletcaller_nodes=add_caller_nodeszonekfnodes(undef,nodes)inadd_callee_nodeszonecaller_nodescaller_nodesendelsenodesinSome(nodes,undef)withPdg.Api.Bottom|Pdg.Api.Top|Not_found->Noneletcomputekfstmtlval=letextract(nodes,undef)=letadd_nodenodedefs=matchPdgIndex.Key.stmt(Pdg.Api.node_keynode)with|None->defs|Somes->Stmt.Hptset.addsdefsin(* select corresponding stmts *)letdefs=NSet.foldadd_nodenodesStmt.Hptset.emptyin(defs,undef)inEva.Analysis.compute();letzone=Eva.Results.(beforestmt|>eval_addresslval|>as_zone)incompute_auxkfstmtzone|>Option.mapextract(* Variation of the function above. For each PDG node that has been found,
we find whether it directly modifies [zone] through an affectation
(statements [Set] or [Call (lv, _)], or if the change is indirect
through the body of a call. *)letcompute_with_def_type_zonekfstmtzone=letextract(nodes,undef)=letadd_nodenodeacc=letchangestmt(direct,indirect)=let(prev_d,pred_i)=tryStmt.Map.findstmtaccwithNot_found->(false,false)inletafter=(direct||prev_d,indirect||pred_i)inStmt.Map.addstmtafteraccinmatchPdg.Api.node_keynodewith|PdgIndex.Key.Stmts->changes(true,false)|PdgIndex.Key.CallStmt_->assertfalse|PdgIndex.Key.SigCallKey(s,sign)->(matchsignwith|PdgIndex.Signature.Out(PdgIndex.Signature.OutRet)->changes(true,false)(* defined by affectation in 'v = f()' *)|PdgIndex.Signature.In_->changes(true,false)(* defined by formal v in 'f(v)' *)|PdgIndex.Signature.Out(PdgIndex.Signature.OutLoc_)->beginmatchs.skindwith|Instr(Call(_,{enode=Lval(Varvi,NoOffset)},_,_)|Local_init(_,ConsInit(vi,_,_),_))whenletkf=Globals.Functions.getviinEva.Analysis.use_spec_instead_of_definitionkf->(* defined through a call, but function has no body *)changes(true,false)|_->(* defined within call to a function with a body*)changes(false,true)end)|PdgIndex.Key.SigKey_->acc|s->Format.printf"## %a@."PdgIndex.Key.prettys;accinletstmts=NSet.foldadd_nodenodesStmt.Map.emptyin(stmts,undef)inOption.mapextract(compute_auxkfstmtzone)letcompute_with_def_typekfstmtlval=Eva.Analysis.compute();letzone=Eva.Results.(beforestmt|>eval_addresslval|>as_zone)incompute_with_def_type_zonekfstmtzone(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)letget_defs=computeletget_defs_with_type=compute_with_def_type