123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258(**************************************************************************)(* *)(* 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_typesopenCil_datatypeopenCilopenVisitoropenOptionsmoduleOccurrence_datatype=Datatype.Triple(Datatype.Option(Kernel_function))(Kinstr)(Lval)moduleOccurrences:sigvaladd:varinfo->kernel_functionoption->kinstr->lval->unitvalget:varinfo->(kernel_functionoption*kinstr*lval)listvalself:State.tvalget_last_result:unit->((Kernel_function.toption*Cil_types.kinstr*(Cil_types.lhost*Cil_types.offset))list*Cil_types.varinfo)optionvaliter_sorted:(varinfo->(kernel_functionoption*kinstr*lval)list->unit)->unitend=structmoduleIState=Cil_state_builder.Varinfo_hashtbl(Occurrence_datatype)(structletsize=17letname="Occurrences.State"letdependencies=[Eva.Analysis.self]end)moduleLastResult=State_builder.Option_ref(Varinfo)(structletname="Occurrences.LastResult"letdependencies=[Ast.self;IState.self]end)letaddvikfkilv=IState.addvi(kf,ki,lv)letunsafe_getvi=tryIState.find_allviwithNot_found->[]letgetvi=LastResult.setvi;unsafe_getviletget_last_result()=tryletvi=LastResult.get()inSome(unsafe_getvi,vi)withNot_found->Noneletiter_auxfoldf=letold,l=fold(funvelt(old,l)->matchv,oldwith|v,None->assert(l=[]);Somev,[elt]|v,(Someoldassome)whenVarinfo.equalvold->some,elt::l|v,Someold->foldl;Somev,[elt])(None,[])inOption.iter(funv->fvl)oldletfold_sortedfinit=letmap=IState.foldVarinfo.Map.addVarinfo.Map.emptyinVarinfo.Map.foldfmapinitletiter_sorted=iter_auxfold_sortedletself=IState.selfendclassoccurrence=object(self)inheritVisitor.frama_c_inplaceassupermethod!vlvallv=letki=self#current_kinstrinbeginletz=Eva.Results.(before_kinstrki|>eval_addresslv|>as_zone)intryLocations.Zone.fold_topset_ok(funb_()->matchbwith|Base.Var(vi,_)|Base.Allocated(vi,_,_)->Occurrences.addviself#current_kfkilv|_->())z()withAbstract_interp.Error_Top->error~current:true"Found completely imprecise value (%a). Ignoring@."Printer.pp_lvallvend;DoChildrenmethod!vterm_lvaltlv=(tryletlv=Logic_to_c.term_lval_to_lvaltlvinignore(self#vlvallv)with(* Translation to lval failed.*)|Logic_to_c.No_conversion->());DoChildrenmethod!vstmt_auxs=Db.yield();super#vstmt_auxsinitializerEva.Analysis.compute()endtypeaccess_type=Read|Write|Both(** Try to find [lv] somewhere within a Cil value *)classis_sub_lvallv=objectinheritCil.nopCilVisitormethod!vlvallv'=ifCil_datatype.Lval.equallvlv'thenraiseExit;DoChildrenend(** Occurrence has found the given [lv] somewhere inside [ki]. We try to find
whether this was inside a read or a write operation. This is difficult to
do directly inside the {!occurrence} class, as the [vlval] method
has no information about the origin of the lval it was called on *)letclassify_accesses(_kf,ki,lv)=letvis=newis_sub_lvallvinletauxfv=tryignore(fvisv);falsewithExit->trueinletis_lv=Cil_datatype.Lval.equallvinletcontained_exp=auxCil.visitCilExprinmatchkiwith|Kglobal->(* Probably initializers *)Read|Kstmt{skind=Instri}->(matchiwith|Set(lv',e,_)->ifis_lvlv'thenifcontained_expethenBothelseWriteelseRead|Call(Somelv',f,args,_)->ifis_lvlv'thenifcontained_expf||List.existscontained_expargsthenBothelseWriteelseRead|Local_init(v,_,_)->(matchlvwith|Varv',_whenCil_datatype.Varinfo.equalvv'->(* We are initializing v. We can't read from it at the same time.
Hence, there's no need to perform the additional checks done
in the cases above. *)Write|_->Read)|Asm(_,_,Some{asm_outputs;asm_inputs},_)->ifList.exists(fun(_,_,out)->is_lvout)asm_outputsthenifList.exists(fun(_,_,inp)->contained_expinp)asm_inputsthenBothelseWriteelseRead|_->Read)|_->Readletcompute,_self=letrun()=feedback"beginning analysis";ignore(visitFramacFile(newoccurrence)(Ast.get()));feedback"analysis done"inState_builder.apply_once"Occurrence.compute"[Occurrences.self]runletgetvi=compute();tryOccurrences.getviwithNot_found->assertfalseletd_kifmt=function|None,Kglobal->Format.fprintffmt"global"|Somekf,Kglobal->Format.fprintffmt"specification of %a"Kernel_function.prettykf|_,Kstmts->Format.fprintffmt"sid %d"s.sidletprint_onefmtvl=Format.fprintffmt"variable %s (%s):@\n"v.vname(ifv.vglobthen"global"elseletkf_name=matchlwith|[]->assertfalse|(Somekf,_,_)::_->Kernel_function.get_namekf|(None,Kstmt_,_)::_->assertfalse|(None,Kglobal,_)::_->fatal"inconsistent context for occurrence of variable %s"v.vnameinifv.vformalthen"parameter of "^kf_nameelse"local of "^kf_name);List.iter(fun(kf,ki,lv)->Format.fprintffmt" %a: %a@\n"d_ki(kf,ki)Printer.pp_lvallv)lletprint_all()=compute();result"%t"(funfmt->Occurrences.iter_sorted(print_onefmt))(* ************************************************************************** *)(* Exported API *)(* ************************************************************************** *)letself=Occurrences.selfletget_last_result=Occurrences.get_last_resultletget=getletprint_all=print_all(* ************************************************************************** *)(* Main *)(* ************************************************************************** *)letmain_fmt=ifPrint.get()thenprint_all()let()=Db.Main.extendmain(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)