123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155(**************************************************************************)(* *)(* 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_typesopenAst_const(* For each exp, limits equals [min;max] (signed) or [max] (unsigned)
We create a label for each bound, plus a label for zero (which is
min for unsigned types) *)letmk_boundsmk_label(loc:location)(exp:exp):stmtlist=match(Cil.typeOfexp).tnodewith|TIntkind->Utils.get_boundskind|>List.map(fun(op,exp')->mk_label(Exp_builder.binopopexpexp')[]loc)|_->[](** Input Output Bound Visitor **)classio_visitormk_label=object(self)inheritVisitor.frama_c_inplace(* visit each function and annotate formals and return statement*)method!vfuncdec=ifnot@@Annotators.shouldInstrumentFundec.svarthenCil.SkipChildrenelseletkf=Option.getself#current_kfinletargs=Kernel_function.get_formalskfinletexp_args=List.map(funarg->Exp_builder.lval(Cil.vararg))argsinletloc=Kernel_function.get_locationkfinletbounds_labels=List.concat_map(mk_boundsmk_labelloc)exp_argsinCil.DoChildrenPost(funfdec->fdec.sbody.bstmts<-bounds_labels@fdec.sbody.bstmts;fdec)(* Create bound labels for return statement *)method!vstmt_auxstmt=beginmatchstmt.skindwith|Return(Someexp,loc)->letbounds_labels=mk_boundsmk_labellocexpinstmt.skind<-Block(Cil.mkBlock(bounds_labels@[Stmt_builder.mkstmt.skind]));Cil.SkipChildren|_->Cil.DoChildrenendend(** Condition Bound Visitor **)classatom_visitormk_labellabels=object(self)inheritVisitor.frama_c_inplacemethod!vexprexp=matchexp.enodewith|Lval_->labels:=List.rev(mk_boundsmk_labelexp.elocexp)@!labels;Cil.SkipChildren|BinOp((Lt|Gt|Le|Ge|Eq|Ne),e1,e2,_)->ignore(Cil.visitCilExpr(self:>Cil.cilVisitor)e1);ignore(Cil.visitCilExpr(self:>Cil.cilVisitor)e2);letnew_exp=Exp_builder.binopEqe1e2inlabels:=(mk_labelnew_exp[]exp.eloc)::!labels;Cil.SkipChildren|BinOp((LAnd|LOr),e1,e2,_)->ignore(Cil.visitCilExpr(self:>Cil.cilVisitor)e1);ignore(Cil.visitCilExpr(self:>Cil.cilVisitor)e2);letnew_exp1=Exp_builder.lnote1inletnew_exp2=Exp_builder.lnote2inlabels:=(mk_labelnew_exp2[]exp.eloc)::(mk_labelnew_exp1[]exp.eloc)::!labels;Cil.SkipChildren|UnOp(LNot,e1,_)->ignore(Cil.visitCilExpr(self:>Cil.cilVisitor)e1);letnew_exp=Exp_builder.binopEqe1(Exp_builder.zero())inlabels:=(mk_labelnew_exp[]exp.eloc)::!labels;Cil.SkipChildren|_->Cil.DoChildrenend(** Condition Bound Visitor **)classc_visitormk_label=object(self)inheritVisitor.frama_c_inplacemethod!vfuncdec=ifAnnotators.shouldInstrumentFundec.svarthenCil.DoChildrenelseCil.SkipChildren(* Create bound labels for return statement *)method!vstmt_auxstmt=beginmatchstmt.skindwith|If(e,thenb,elseb,loc)->letatoms_labels=ref[]inignore(Cil.visitCilExpr(newatom_visitormk_labelatoms_labels:>Cil.cilVisitor)e);(* handle visits manually to skip visit of e *)letthenb=Visitor.visitFramacBlock(self:>Visitor.frama_c_visitor)thenbinletelseb=Visitor.visitFramacBlock(self:>Visitor.frama_c_visitor)elsebinletold_stmt=Stmt_builder.mk(If(e,thenb,elseb,loc))instmt.skind<-Block(Cil.mkBlock(List.rev!atoms_labels@[old_stmt]));Cil.SkipChildren|_->Cil.DoChildrenendend(**
Input Output Bound annotator
*)moduleInOutBound=Annotators.Register(structletname="IOB"lethelp="Input Output Bound Coverage"letapplymk_labelfile=Visitor.visitFramacFileSameGlobals(newio_visitormk_label:>Visitor.frama_c_visitor)fileend)(**
Condition Bound annotator
*)moduleCondBound=Annotators.Register(structletname="CB"lethelp="Condition Bound Coverage"letapplymk_labelfile=Visitor.visitFramacFileSameGlobals(newc_visitormk_label:>Visitor.frama_c_visitor)fileend)(**
Bound annotator
*)moduleBound=Annotators.Register(structletname="BC"lethelp="Bound Coverage (IOB + CB)"letapplymk_labelfile=Visitor.visitFramacFileSameGlobals(newio_visitormk_label:>Visitor.frama_c_visitor)file;Visitor.visitFramacFileSameGlobals(newc_visitormk_label:>Visitor.frama_c_visitor)fileend)