123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742(**************************************************************************)(* *)(* This file is part of the Frama-C's Lannotate plug-in. *)(* *)(* Copyright (C) 2012-2025 *)(* 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_typesopenCil_datatypeopenAst_const(** This file is used to generate dataflow criteria and is structured this way :
The main AST visitor is addSequences :
1- For each function, before visiting it, we perform a dataflow analysis
(cf. dataflow analysis part).
2- After the dataflow analysis, we visit the function, and add all annotations
created by the dataflow analysis (Def / Use / Status variable)
a) to_add_defs, to_add_uses, to_add_conds and to_add_fun are used to place
created def/use from visit_defuse
b) If the statement is a Def of V
* find in to_add_conds_stmt all preceding defs of V
* for each def, find in def_to_conds all conditions for this def
* Remember these conditions for this statement in to_add_conds
Data flow analysis (do_function) :
3- Initialize the initial state for the analysis (containing definitions from
function's parameters)
4- Perform the analysis by propagating a state (Defs set, Uses set) :
a) Visit all expressions to find all uses in the function, and put them in
the set Uses in our state. Join with intersection.
b) Visit all definitions to find all defs in the function, and put them in
the set Defs in our state. Join with union.
When computing a Def of V, remove V from Uses, and remove V from Defs if
CleanDataflow is true
5- Then we iterate on all statements with their corresponding
state, and visit (visit_defuse) this statement.
a) For each use of V, we create a sequence for each Def of V is our
state
b) If this statement is a Def of V, we remember in to_add_conds_stmt
all defs of V that can reach this statements, which will be used in
addSequences to create condition statements, i.e. reset of status
variables
*)(** Used to represent a Lval with a truncated offset (trunc at first Index) *)moduleVarOfst=Datatype.Pair_with_collections(Varinfo)(Offset)(** Used to represent a definition *)moduleDef=Datatype.Triple_with_collections(Datatype.Int)(* Unique ID for each different definition of VarOfst *)(VarOfst)(* Store varinfo and truncated offset of this definition *)(Kinstr)(* KGlobal for function's parameters, KStmt otherwise *)(** Used to represent a use *)moduleUse=Datatype.Pair_with_collections(VarOfst)(* Store varinfo and truncated offset of this use *)(Stmt)(* Use's statement *)(** Module to add 2 tool functions *)moduleListtbl(T:Hashtbl.S)=structincludeT(** Add an element in front of the existing binding, else bind to a new list
containing this element *)letaddtblkeyelt=ifT.memtblkeythenletold=T.findtblkeyinT.replacetblkey(elt::old)elseT.addtblkey[elt](** Add a list in front of the existing binding, else create a new binding *)letadd_listtblkeyelt=ifT.memtblkeythenletold=T.findtblkeyinT.replacetblkey(elt@old)elseT.addtblkeyeltendmoduleStmt_lst=Listtbl(Stmt.Hashtbl)moduleDef_lst=Listtbl(Def.Hashtbl)(** Represent states in our dataflow analysis *)typet=|Bottom|NonBottomof(Def.Set.t*Use.Set.t)(** For each VarOfst, keep the number of assignment seen for this VarOfst
key : VarOfst.t
value : int
*)letdef_id=VarOfst.Hashtbl.create32(** each def is registered to avoid creating them more than once
key : stmt
value : Def.t
*)letseen_def=Stmt.Hashtbl.create32letpostpone_def=Def.Hashtbl.create32(** bind each new sequence to its corresponding statement, sequence id (int) is
used to sort them at the end
key : statement
value : (int * stmt) list
*)letto_add_defs=Stmt.Hashtbl.create32letto_add_uses=Stmt.Hashtbl.create32letto_add_conds_stmt=Stmt.Hashtbl.create32(** Bind to each def the list of conditions related to it
key : Def.t
value : (int * stmt) list
*)letdef_to_conds=Def.Hashtbl.create32(** Used to create hyperlabels, bind to each def the list of sequences related to it
key : Def.t
value : int list
*)lethyperlabels=Def.Hashtbl.create32(** Clear all hashtbls after each function in addSequences *)letreset_all()=VarOfst.Hashtbl.resetdef_id;Stmt.Hashtbl.resetseen_def;Stmt.Hashtbl.resetto_add_defs;Stmt.Hashtbl.resetto_add_uses;Stmt.Hashtbl.resetto_add_conds_stmt;Def.Hashtbl.resetdef_to_conds(** Given a VarOfst, increment the number of defs seen
and returns it. If it is the first return 1. *)letget_next_def_idvarofst=ifVarOfst.Hashtbl.memdef_idvarofstthenletn=(VarOfst.Hashtbl.finddef_idvarofst)+1inVarOfst.Hashtbl.replacedef_idvarofstn;nelse(VarOfst.Hashtbl.adddef_idvarofst1;1)(** Given an offset, truncate it before the first Index
var->field1->filed2[42]->field3
will become
var->field1->field2
*)letrectrunc_fieldsoffset=matchoffsetwith|Field(f_info,offset')->letoffset'=trunc_fieldsoffset'inField(f_info,offset')|Index_|NoOffset->NoOffset(** For a given VarOfst V, statement S1 and set of Uses (from dataflow analysis state)
Try to find a match (V', S2) in Uses such that
V equals V' and S1 post-dominate S2
*)letis_equivalentvarofststmtuses=Use.Set.exists(fun(varofst',stmtUse)->leteq=VarOfst.equalvarofst'varofstin(* Our dataflow analysis garanty that uses in state always dominate the
current statement S1 *)ifeq&¬(Dominators.dominatesstmtUsestmt)thenOptions.fatal"Discrepancy: This should not happen";eq&&Dominators.postdominatesstmtstmtUse)uses(** Consider uses of V in an expression only once.
In v2 = v1 + v1, we will consider 1 use of v1
*)letis_triv_equivvarofstvisited=Options.CleanEquiv.get()&&List.exists(funvarofst'->VarOfst.equalvarofst'varofst)visitedletseq_status_prefix="__SEQ_STATUS"letseq_tmp_prefix="__SEQ_TMP"letmk_name?(pre=seq_status_prefix)sid=pre^"_"^s^"_"^string_of_intid(** Test if a VarOfst V should be instrumented, i.e. if it's not a global,
a temp variable or if it's the first time we see it in the current
expr/instr (except if CleanDuplicate is false) *)letshould_instrument?visited(v,offset)=notv.vglob&¬v.vtemp&¬(Datatype.String.equalv.vname"__retres")&¬@@String.starts_with~prefix:seq_status_prefixv.vname&&Annotators.shouldInstrumentVarv&&matchvisitedwith|None->true|Somevisited->not(is_triv_equiv(v,offset)visited)letunk_loc=Location.unknown(***********************************)(********* Defuse Criteria *********)(***********************************)(** Perform the part 5- of the heading comment *)classvisit_defuse~annot_bound(defs_set,uses_set)current_stmt(mk_label:exp->'alist->location->stmt)to_add_fun=object(self)inheritVisitor.frama_c_inplace(** Used to avoid trivially equivalent uses *)valmutablevisited=[](** Create a new varinfo *)methodprivateinit_vinfo?(typ=Cil_const.intType)name=Cil.makeVarinfofalsefalsenametyp(** Create a statement : vi = value; *)methodprivatemk_set?(loc=unk_loc)vivalue=Ast_info.mkassign(Varvi,NoOffset)valueloc|>Stmt_builder.instr(** Create a expression : Lval(vi,offset) == value *)methodprivatemk_comp?(loc=unk_loc)?(op=Cil_types.Eq)?(offset=NoOffset)vivalue=letnew_exp=Exp_builder.mk~loc(Lval(Varvi,offset))inExp_builder.binopopnew_expvalue(** Create a statement : typ vi = value; where typ is the type of vi *)methodprivatemk_init?(loc=unk_loc)vivalue=Local_init(vi,AssignInit(SingleInit(value)),loc)|>Stmt_builder.instr(** Register in Hashtbls the different parts of our sequences (Def / Use / Cond)
Plus the initialization (depending on the type of stmtDef, cf. Def type)
and add this sequence id to its hyperlabel
*)methodprivateregister_seqdefid_seqsto_registerconduse_lbl=let_,_,stmtDef=definList.iter(fun(vInfo,def_exp)->matchstmtDefwith|Kglobal->letinit=self#mk_initvInfodef_expinto_add_fun:=(id_seqs,init)::!to_add_fun|Kstmtstmt->letinit=self#mk_initvInfo(Exp_builder.zero())into_add_fun:=(id_seqs,init)::!to_add_fun;Stmt_lst.addto_add_defsstmt(id_seqs,self#mk_setvInfodef_exp))to_register;Def_lst.adddef_to_condsdef(id_seqs,cond);Stmt_lst.addto_add_usescurrent_stmt(id_seqs,use_lbl);Def_lst.addhyperlabelsdefid_seqs(** Create a def-use sequence for the given def/bounds
and register it in Hashtbls
*)methodprivatemkSeq_auxlocdefbound=let_,(vi,offset),_=definletid_seq=Annotators.getCurrentLabelId()+1in(* sequence id *)letvInfo=self#init_vinfo(mk_namevi.vnameid_seq)inletuse=self#mk_compvInfo(Exp_builder.one())inletuse,to_register=matchbound,Options.BoundPostpone.get()with|None,_->use,[vInfo,Exp_builder.one()]|Some(op,bound),true->lettmp_vInfo,init=ifDef.Hashtbl.mempostpone_defdefthenDef.Hashtbl.findpostpone_defdef,[]elsebeginletvt=Cil.typeOfLval(Varvi,offset)inlettmp_vInfo=self#init_vinfo~typ:(Ast_types.remove_attributes["const"]vt)(mk_name~pre:seq_tmp_prefixvi.vnameid_seq)inDef.Hashtbl.addpostpone_defdeftmp_vInfo;letexp_vInfo=Exp_builder.mk(Lval(Varvi,offset))intmp_vInfo,[(tmp_vInfo,exp_vInfo)]endinletpred=self#mk_comp~optmp_vInfoboundinExp_builder.binopCil_types.LAndusepred,[(vInfo,Exp_builder.one())]@init|Some(op,bound),false->use,[(vInfo,self#mk_comp~offset~opvibound)]inletbreak_seq=self#mk_setvInfo(Exp_builder.zero())inletuse_lbl=mk_labeluse[]locinself#register_seqdefid_seqto_registerbreak_sequse_lbl(** Create a def-use sequence for the given def and bounds *)methodprivatemkSeqlocdef=let_,(vi,offset),_=definmatch(Cil.typeOfLval(Varvi,offset)|>Ast_types.unroll).tnodewith|TIntkind|TEnum{ekind=kind}whenannot_bound->Utils.get_boundskind|>List.iter(funb->self#mkSeq_auxlocdef(Someb))|_whenannot_bound->()|_->self#mkSeq_auxlocdefNone(** Part 5- b) of the heading comment *)method!vstmt_auxstmt=matchstmt.skindwith|Instriwhennot(Utils.is_labeli)->beginmatchiwith|Set((Varv,offset),_,_)|Call(Some(Varv,offset),_,_,_)->letvarofst=(v,trunc_fieldsoffset)inifshould_instrumentvarofstthenbeginlett=Def.Set.filter(fun(_,varData,_)->VarOfst.equalvarDatavarofst)defs_setinifnot@@Def.Set.is_emptytthenStmt.Hashtbl.addto_add_conds_stmtstmtt;end;Cil.DoChildren|_->Cil.DoChildrenend|_->assertfalse(** Part 5- a) of the heading comment *)method!vexprexpr=matchexpr.enodewith|Lval(Varv,offset)->letvarofst=(v,trunc_fieldsoffset)inifshould_instrument~visitedvarofstthenbeginvisited<-varofst::visited;(* Keeps defs related to this variable *)letall_varofst_defs=Def.Set.filter(fun(_,varData,_)->VarOfst.equalvarDatavarofst)defs_setinifnot(Def.Set.is_emptyall_varofst_defs)thenifnot(Options.CleanEquiv.get())||not(is_equivalentvarofstcurrent_stmtuses_set)thenDef.Set.iter(self#mkSeqexpr.eloc)all_varofst_defs;end;Cil.DoChildren|_->Cil.DoChildrenend(******************************)(***** Dataflow analysis ******)(******************************)(** Part 4- a) of the heading comment *)classvisit_usestatestmt=object(_)inheritVisitor.frama_c_inplacevalmutablevisited=[]method!vexprexpr=match!statewith|Bottom->Cil.SkipChildren|NonBottom(defs,uses)->matchexpr.enodewith|Lval(Varv,offset)->letvarofst=(v,trunc_fieldsoffset)inifshould_instrument~visitedvarofstthenbeginvisited<-varofst::visited;letnew_uses=Use.Set.add(varofst,stmt)usesinstate:=NonBottom(defs,new_uses);end;Cil.DoChildren|_->Cil.DoChildrenend(** Part 4- of the heading comment *)moduleDataflow(B:sigvalbounded:boolend):Interpreted_automata.Domainwithtypet=t=structtypenonrect=tletpretty_deffmt(defId,(vi,ofst),stmt)=letstmt=matchstmtwith|Kglobal->"Function parameter"|Kstmtstmt->Format.asprintf"Stmt %a"Printer.pp_stmtstmtinFormat.fprintffmt"defId: %d / var : %a / %s@."defIdCil_printer.pp_lval(Varvi,ofst)stmtletpretty_usefmt((vi,ofst),stmt)=Format.fprintffmt"var: %a / Stmt: %a@."Printer.pp_lval(Varvi,ofst)Printer.pp_stmtstmtletpretty_usesfmtset=Format.fprintffmt" Uses :@.";Use.Set.iter(funelt->Format.fprintffmt" ";pretty_usefmtelt)setletpretty_defsfmtset=Format.fprintffmt" Defs :@.";Def.Set.iter(funelt->Format.fprintffmt" ";pretty_deffmtelt)setlet_prettyfmt=function|Bottom->Format.fprintffmt"Bottom@."|NonBottom(defs,uses)->Format.fprintffmt"NonBottom :@.";pretty_defsfmtdefs;pretty_usesfmtuses(** Return a new set after removing all definitions of a given VarOfst *)letremove_defvarofsts=Def.Set.filter(fun(_,varData,_)->not(VarOfst.equalvarDatavarofst))s(** Return a new set after removing all uses of a given VarOfst *)letremove_usevarofsts=Use.Set.filter(fun(var,_)->not(VarOfst.equalvarvarofst))s(** Function called to join 2 states *)letjoinab=matcha,bwith|Bottom,x|x,Bottom->x|NonBottom(d,u),NonBottom(d',u')->NonBottom(Def.Set.uniondd',Use.Set.interuu')letis_equalab=matcha,bwith|Bottom,NonBottom_|NonBottom_,Bottom->false|Bottom,Bottom->true|NonBottom(d,u),NonBottom(d',u')->Def.Set.equaldd'&&Use.Set.equaluu'letwidenab=letc=joinabinifis_equalacthenInterpreted_automata.FixpointelseInterpreted_automata.Wideningc(** Part 4- b) of the heading comment *)letdo_def?(local=false)voffsetstmt=function|Bottom->SomeBottom|NonBottom(defs,uses)->letvarofst=(v,trunc_fieldsoffset)inletdefs_clean=iflocal||Options.CleanDataflow.get()thenremove_defvarofstdefselsedefsinletuses_clean=remove_usevarofstusesinletnew_defs=ifStmt.Hashtbl.memseen_defstmtthenDef.Set.add(Stmt.Hashtbl.findseen_defstmt)defs_cleanelsebeginletdefId=get_next_def_idvarofstinletnew_def=(defId,varofst,(Kstmtstmt))inStmt.Hashtbl.addseen_defstmtnew_def;Def.Set.addnew_defdefs_cleanendinSome(NonBottom(new_defs,uses_clean))letrecisConstante=matche.enodewith|Const_->true|UnOp(LNot,_,_)->true|UnOp(_,e,_)->isConstante|BinOp((Lt|Gt|Le|Ge|Eq|Ne|LAnd|LOr),_,_,_)->true|BinOp_->false|Lval_->false|SizeOf_|SizeOfE_|SizeOfStr_|AlignOf_|AlignOfE_->true|CastE(_,e)->isConstante|AddrOf_|StartOf_->false(** Function called for each stmt and propagating new states to each succs of
stmt
*)lettransfer(_,edge,_)state=letopenInterpreted_automatainmatchedge.edge_transitionwith|Skip|Prop_|Enter_|Leave_|Return(None,_)->Somestate|Return(Somee,stmt)|Guard(e,_,stmt)->letstate=refstateinignore(Cil.visitCilExpr(newvisit_usestatestmt:>Cil.cilVisitor)e);Some!state|Instr(i,stmt)whennot(Utils.is_labeli)->letstate=refstateinignore(Cil.visitCilInstr(newvisit_usestatestmt:>Cil.cilVisitor)i);beginmatchiwith|Set(_,e,_)|Local_init(_,AssignInit(SingleInite),_)whenisConstante&&B.bounded->Some!state|Set((Varvi,offset),_,_)|Call(Some(Varvi,offset),_,_,_)->ifshould_instrument(vi,offset)thendo_defvioffsetstmt!stateelseSome!state|Local_init(vi,_,_)->ifshould_instrument(vi,NoOffset)thendo_def~local:trueviNoOffsetstmt!stateelseSome!state|Call_|Set_|Asm_|Cil_types.Skip_|Code_annot_->Some!stateend|Instr_->Somestateend(** Dataflow analysis, Part 3-,4-,5- of the heading comment *)letdo_function~annot_boundkfmk_labelto_add_fun=letmoduleDataflowAnalysis=Interpreted_automata.ForwardAnalysis(Dataflow(structletbounded=annot_boundend))inletargs=Kernel_function.get_formalskfinletfaccarg=letdefId=get_next_def_id(arg,NoOffset)inDef.Set.add(defId,(arg,NoOffset),Kglobal)accinletinit_d=List.fold_leftfDef.Set.emptyargsinletinit_state=NonBottom(init_d,Use.Set.empty)inletresult=DataflowAnalysis.fixpointkfinit_stateinletvisit_stmtstmtstate=matchstatewith|Bottom->()|NonBottomt->beginmatchstmt.skindwith|Instriwhennot(Utils.is_labeli)->ignore(Cil.visitCilStmt(newvisit_defuse~annot_boundtstmtmk_labelto_add_fun:>Cil.cilVisitor)stmt);|Return(Somee,_)|If(e,_,_,_)|Switch(e,_,_,_)->ignore(Cil.visitCilExpr(newvisit_defuse~annot_boundtstmtmk_labelto_add_fun:>Cil.cilVisitor)e);|_->()endinDataflowAnalysis.Result.iter_stmt_ascvisit_stmtresult(** Part 1- and 2- of the heading comment *)classaddSequences~annot_boundmk_label=object(self)inheritVisitor.frama_c_inplacevalto_add_conds=Stmt.Hashtbl.create17(* get all sequences, sort defs and uses by sequence ID, and returns
a pair of list (before,after) with sequences to add before & after the current statement *)methodprivateget_seqs_sortedstmt=letdefs=ifStmt.Hashtbl.memto_add_defsstmtthenList.sortcompare@@Stmt.Hashtbl.findto_add_defsstmtelse[]inletuses=ifStmt.Hashtbl.memto_add_usesstmtthenList.sortcompare@@Stmt.Hashtbl.findto_add_usesstmtelse[]inletconds=ifStmt.Hashtbl.memto_add_condsstmtthenList.sortcompare@@Stmt.Hashtbl.findto_add_condsstmtelse[]in(List.map(fun(_,s)->s)uses)@(List.map(fun(_,s)->Stmt_builder.mks.skind)conds),List.map(fun(_,s)->s)defs(** Part 1- and 2- of the heading comment *)method!vfuncdec=letkf=Option.getself#current_kfinifKernel_function.is_definitionkf&&Annotators.shouldInstrumentFundec.svarthenbeginletto_add_fun=ref[]indo_function~annot_boundkfmk_labelto_add_fun;Cil.DoChildrenPost(funnew_dec->letdefs=List.sortcompare!to_add_funinnew_dec.sbody.bstmts<-(List.map(fun(_,s)->s)defs)@new_dec.sbody.bstmts;Stmt.Hashtbl.resetto_add_conds;reset_all();Cfg.clearCFGinfo~clear_id:falsenew_dec;Cfg.cfgFunnew_dec;new_dec)endelseCil.SkipChildren(** Part 2- a) of the heading comment *)method!vblock_=Cil.DoChildrenPost(funblock->letrecauxlacc=matchlwith|[]->acc|s::t->letbefore,after=self#get_seqs_sortedsins.skind<-Block(Cil.mkBlock(before@[Stmt_builder.mks.skind]));auxt(acc@[s]@after)inblock.bstmts<-auxblock.bstmts[];block)(** Part 2- b) of the heading comment *)method!vstmt_auxs=ifStmt.Hashtbl.memto_add_conds_stmtsthenmatchs.skindwith|Instriwhennot(Utils.is_labeli)->beginmatchiwith|Set((Var_,_),_,_)|Call(Some(Var_,_),_,_,_)->letdef_set=Stmt.Hashtbl.findto_add_conds_stmtsinDef.Set.iter(fundef->ifDef.Hashtbl.memdef_to_condsdefthenDef.Hashtbl.finddef_to_condsdef|>Stmt_lst.add_listto_add_condss)def_set;Cil.DoChildren|_->assertfalseend|_->assertfalseelsematchs.skindwith|UnspecifiedSequencev->s.skind<-Block(Cil.block_from_unspecified_sequencev);Cil.DoChildren|_->Cil.DoChildrenendtypecriterion=ADC|AUC|DUC|BADC|BAUC|BDUCletoperator_of_criterioncrit=matchcritwith|ADC|BADC->"+"|AUC|BAUC->"."|DUC|BDUC->assertfalse(** Create all hyperlabels *)letcompute_hlcrit=matchcritwith|DUC|BDUC->Def.Hashtbl.fold_sorted(fun_seqsstr->letseqs=List.sortcompareseqsinList.fold_left(funaccs->acc^Annotators.next_hl()^") <s"^string_of_ints^"|; ;>,\n")strseqs)hyperlabels""|_->letsymb=operator_of_criterioncritinDef.Hashtbl.fold_sorted(fun_seqsstr->letseqs=List.sortcompareseqsinstr^Annotators.next_hl()^") <"^(String.concatsymb(List.map(funs->"s"^string_of_ints)seqs))^"|; ;>,\n")hyperlabels""(** Generate/Append in .hyperlabels file our hyperlabels data *)letgen_hyperlabelscrit=letdata_filename=(Filename.chop_extension(Annotators.get_file_name()))^".hyperlabels"inOptions.feedback"write hyperlabel data (to %s)"data_filename;letdata=compute_hlcritinletout=open_out_gen[Open_creat;Open_append]0o644data_filenameinoutput_stringoutdata;close_outout;Options.feedback"Total number of hyperlabels = %d"(Annotators.getCurrentHLId())letvisited=ref(false,false)letis_visitedcrit=matchcrit,!visitedwith|(ADC|AUC|DUC),(v,_)->v|(BADC|BAUC|BDUC),(_,v)->vletset_visitedcrit=matchcrit,!visitedwith|(ADC|AUC|DUC),(_,old)->visited:=(true,old)|(BADC|BAUC|BDUC),(old,_)->visited:=(old,true)(** Visit the file with our main visitor addSequences, and mark the new AST as
changed *)letvisite?(annot_bound=false)critfilemk_label:unit=ifnot(is_visitedcrit)thenbeginVisitor.visitFramacFileSameGlobals(newaddSequences~annot_boundmk_label:>Visitor.frama_c_visitor)file;set_visitedcritendelseOptions.feedback"Avoid annotating with 2 dataflow criteria at the same time"(** All-defs annotator *)moduleADC=Annotators.Register(structletname="ADC"lethelp="All-Definitions Coverage"letapplymk_labelfile=visiteADCfilemk_label;gen_hyperlabelsADCend)(** All-uses annotator *)moduleAUC=Annotators.Register(structletname="AUC"lethelp="All-Uses Coverage"letapplymk_labelfile=visiteAUCfilemk_label;gen_hyperlabelsAUCend)(** Def-Use annotator *)moduleDUC=Annotators.Register(structletname="DUC"lethelp="Definition-Use Coverage"letapplymk_labelfile=visiteDUCfilemk_label;gen_hyperlabelsDUCend)(** Boundary All-defs annotator *)moduleBADC=Annotators.Register(structletname="BADC"lethelp="Boundary All-Definitions Coverage"letapplymk_labelfile=visite~annot_bound:trueBADCfilemk_label;gen_hyperlabelsBADCend)(** Boundary All-uses annotator *)moduleBAUC=Annotators.Register(structletname="BAUC"lethelp="Boundary All-Uses Coverage"letapplymk_labelfile=visite~annot_bound:trueBAUCfilemk_label;gen_hyperlabelsBAUCend)(** Boundary Def-Use annotator *)moduleBDUC=Annotators.Register(structletname="BDUC"lethelp="Boundary Definition-Use Coverage"letapplymk_labelfile=visite~annot_bound:trueBDUCfilemk_label;gen_hyperlabelsBDUCend)