123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267(**************************************************************************)(* *)(* This file is part of the Frama-C's Luncov plug-in. *)(* *)(* Copyright (C) 2012-2022 *)(* 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 LICENSE) *)(* *)(**************************************************************************)openCil_typesopenCommonstypeid=int(* type used to describe labels *)typelbl_info={li_loc:Cil_types.location;li_tag:string;li_annotable:Cil_types.stmt;li_predicate:Cil_types.exp;li_kf_id:int;}(* type used to describe binding labels *)typebind_info={bi_id:int;bi_loc:Cil_types.location;bi_tag:string;bi_annotable:Cil_types.stmt;bi_predicate:Cil_types.exp;bi_kf_id:int;bi_bindings:(string*Cil_types.exp)list;}typeinfo=Labeloflbl_info|Bindingofbind_infolistmoduleInfo=Datatype.Make(structincludeDatatype.Serializable_undefinedtypet=infoletname="Instr.info"letreprs=[Label({li_loc=Cil_datatype.Location.unknown;li_tag="";li_annotable=Cil.dummyStmt;li_predicate=Cil_datatype.Exp.dummy;li_kf_id=-1;})]letmem_project=Datatype.never_any_projectend)moduleH=Datatype.Int.HashtblmoduleInfos=State_builder.Option_ref(Datatype.Triple(H.Make(Info))(H.Make(Datatype.Int))(H.Make(Datatype.Int)))(structletname="LabelInfos"letdependencies=[Ast.self]end)letwp_emitter=Emitter.create("Luncov_WP")[Emitter.Code_annot]~correctness:[]~tuning:[]leteva_emitter=Emitter.create("Luncov_EVA")[Emitter.Code_annot]~correctness:[]~tuning:[](* Visit the file, and for each label or binding, creates and adds it to
the Instrument hashtbl *)classmapperhblockscalls=object(self)inheritVisitor.frama_c_inplacevalmutableopened_blocks=[]valmutableprevious_binding=[]valmutablecurrent_binding_id=-1method!vfunc_=Cil.DoChildrenPost(funf->self#save_binding();(* Work around for the last binding seen *)f)methodprivatesave_binding()=ifList.lengthprevious_binding>=2thenbeginletfirst_id=(List.hdprevious_binding).bi_idinH.addhfirst_id(Bindingprevious_binding);previous_binding<-[];end(* Used to get the block that contains the label (cf. labels.h) *)methodprivateget_parent_and_current=matchself#current_stmt,opened_blockswith|Somestmt,block::_->Some(block.sid,stmt)|_->Nonemethod!vstmt_auxs=matchs.skindwith|Block_->opened_blocks<-s::opened_blocks;Cil.ChangeDoChildrenPost(s,funs->opened_blocks<-List.tlopened_blocks;s)|_->Cil.DoChildrenmethodprivatemk_labelidexpcondtagexploc=matchCil.isIntegeridexp,cil_isStringtagexp,self#get_parent_and_currentwith|Someid,Sometag,Some(block_sid,call_stmt)->letid=Integer.to_int_exnidinletenglobing_kf=Option.getself#current_kfinH.addblocksblock_sidid;H.addcallscall_stmt.sidid;Datatype.Int.Hashtbl.addhid(Label{li_loc=loc;li_tag=tag;li_annotable=call_stmt;li_predicate=cond;li_kf_id=Kernel_function.get_idenglobing_kf;})|None,_,_->Options.warning"instr: invalid label at line %d [id]"(fstloc).Filepath.pos_lnum|_,None,_->Options.warning"instr: invalid label at line %d [tag]"(fstloc).Filepath.pos_lnum|_,_,None->Options.warning"instr: invalid label at line %d [structure]"(fstloc).Filepath.pos_lnummethodprivatemk_binding_auxbind_listloc=letrecauxaccl=matchlwith|[]->acc|[_]->Options.warning"instr: invalid binding at line %d [(Name,Value)]"(fstloc).Filepath.pos_lnum;[]|x::y::t->beginmatchcil_isStringxwith|None->Options.warning"instr: invalid binding at line %d [Name]"(fstloc).Filepath.pos_lnum;[]|Somen->aux((n,y)::acc)tendinList.rev(aux[]bind_list)methodprivatemk_bindingidexpcondtagexpbindidexpnbBindsexpbind_listloc=matchCil.isIntegeridexp,cil_isStringtagexp,Cil.isIntegerbindidexp,Cil.isIntegernbBindsexp,self#get_parent_and_currentwith|Someid,Sometag,SomebindId,Some_nbBinds,Some(block_sid,call_stmt)->letid=Integer.to_int_exnidinletbindId=Integer.to_int_exnbindIdinletenglobing_kf=Option.getself#current_kfinletbind_list=self#mk_binding_auxbind_listlocinifbind_list<>[]thenbeginH.addblocksblock_sidid;H.addcallscall_stmt.sidid;letbind={bi_id=id;bi_loc=loc;bi_tag=tag;bi_annotable=call_stmt;bi_kf_id=Kernel_function.get_idenglobing_kf;bi_bindings=bind_list;bi_predicate=cond;}inifcurrent_binding_id=-1thencurrent_binding_id<-bindId;ifcurrent_binding_id=bindIdthenprevious_binding<-previous_binding@[bind]elsebeginself#save_binding();current_binding_id<-bindId;previous_binding<-[bind];endend|None,_,_,_,_->Options.warning"instr: invalid binding at line %d [id]"(fstloc).Filepath.pos_lnum|_,None,_,_,_->Options.warning"instr: invalid binding at line %d [tag]"(fstloc).Filepath.pos_lnum|_,_,None,_,_->Options.warning"instr: invalid binding at line %d [realId]"(fstloc).Filepath.pos_lnum|_,_,_,None,_->Options.warning"instr: invalid binding at line %d [nbBinds]"(fstloc).Filepath.pos_lnum|_,_,_,_,None->Options.warning"instr: invalid binding at line %d [structure]"(fstloc).Filepath.pos_lnummethod!vinsti=beginmatchiwith|Call(None,{enode=(Lval(Var{vname=name},NoOffset))},idexp::cond::tagexp::_,loc)whenname=label_function_name->self#mk_labelidexpcondtagexploc|Call(None,{enode=(Lval(Var{vname=name},NoOffset))},idexp::cond::tagexp::bind_id::nbBinds::bind_list,loc)whenname=bind_function_name->self#mk_bindingidexpcondtagexpbind_idnbBindsbind_listloc|_->()end;Cil.SkipChildrenendletsize_table=ref0(* Fill the hashtbl with the visitor, and then fill blocks and calls
Hahstbl depending on label's type *)letcompute():Infos.data=letast=Ast.get()inleth=H.create97inletblocks=H.create97inletcalls=H.create97inVisitor.visitFramacFileSameGlobals(newmapperhblockscalls)ast;size_table:=H.lengthh;h,blocks,callsletcompute()=Infos.memocomputeletgetid=lettable,_,_=compute()inH.findtableidletiterf=lettable,_,_=compute()inH.iterftableletiter_lblsf=lettable,_,_=compute()inletf_auxkeyvalue=matchvaluewith|Labell->fkeyl|_->()inH.iterf_auxtableletiter_bindsf=lettable,_,_=compute()inletf_auxkeyvalue=matchvaluewith|Bindingb->fkeyb|_->()inH.iterf_auxtableletis_annotable_stmt_by_sidsid=let_,_,calls=compute()inifH.memcallssidthenSome(H.findcallssid)elseNoneletis_stmt_by_sidsid=let_,blocks,_=compute()inifH.memblockssidthenH.find_allblockssidelse[]