123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251openGoblintCilmoduleE=Errormsg(** compute use/def information *)moduleVS=Set.Make(structtypet=Cil.varinfo(* Subtraction is safe since vids are always positive*)letcomparev1v2=v1.vid-v2.vidend)(** Set this global to how you want to handle function calls.
This also returns a modified argument list which will be used for the
purpose of Use analysis, in case you have a function that needs special
treatment of its args. *)letgetUseDefFunctionRef:(exp->explist->VS.t*VS.t*explist)ref=ref(funfuncargs->(VS.empty,VS.empty,args))(** Say if you want to consider a variable use. This applies to
variable reads only; see also considerVariableAddrOfAsUse *)letconsiderVariableUse:(varinfo->bool)ref=ref(fun_->true)(** Say if you want to consider a variable def *)letconsiderVariableDef:(varinfo->bool)ref=ref(fun_->true)(** Say if you want to consider a variable addrof as a use *)letconsiderVariableAddrOfAsUse:(varinfo->bool)ref=ref(fun_->true)(** Say if you want to consider a variable addrof as a def *)letconsiderVariableAddrOfAsDef:(varinfo->bool)ref=ref(fun_->false)(** Return any vars that should be considered "used" by an expression,
other than the ones it refers to directly. Deputy uses this for
variables in Cast annotations. *)letextraUsesOfExpr:(exp->VS.t)ref=ref(fun_->VS.empty)(* When this is true, only definitions of a variable without
an offset are counted as definitions. So:
a = 5; would be a definition, but
a[1] = 5; would not.
Exception: writing to a union field is considered to be a definition of
the union even if this is set to true.*)letonlyNoOffsetsAreDefs:boolref=reffalse(** Should we ignore the contents of sizeof and alignof? *)letignoreSizeof:boolref=reftrueletvarUsed:VS.tref=refVS.emptyletvarDefs:VS.tref=refVS.emptyclassuseDefVisitorClass:cilVisitor=object(self)inheritnopCilVisitor(** this will be invoked on variable definitions only because we intercept
all uses of variables in expressions ! *)method!vvrbl(v:varinfo)=if(!considerVariableDef)v&¬(!onlyNoOffsetsAreDefs)thenvarDefs:=VS.addv!varDefs;if(!considerVariableDef)v&&!onlyNoOffsetsAreDefsthenvarUsed:=VS.addv!varUsed;SkipChildren(** If l is a variable, this means we are in a def, not a use!
Other cases are handled by vexpr.
If onlyNoOffsetsAreDefs is true, then we need to see the
varinfo in an lval along with the offset. Otherwise just
DoChildren *)method!vlval(l:lval)=if!onlyNoOffsetsAreDefsthenmatchlwith(Varvi,NoOffset)->if(!considerVariableDef)vithenvarDefs:=VS.addvi!varDefs;SkipChildren|(Varvi,Field(fi,NoOffset))whennotfi.fcomp.cstruct->(* If we are writing to a union field, treat that the same
as a write to a union. *)if(!considerVariableDef)vithenvarDefs:=VS.addvi!varDefs;SkipChildren|_->DoChildrenelseDoChildrenmethod!vexpr(e:exp)=letextra=(!extraUsesOfExpr)einifnot(VS.is_emptyextra)thenvarUsed:=VS.unionextra!varUsed;matchewithLval(Varv,off)->ignore(visitCilOffset(self:>cilVisitor)off);if(!considerVariableUse)vthenbeginvarUsed:=VS.addv!varUsedend;SkipChildren(* So that we do not see the v *)|AddrOf(Varv,off)|StartOf(Varv,off)->ignore(visitCilOffset(self:>cilVisitor)off);if(!considerVariableAddrOfAsUse)vthenvarUsed:=VS.addv!varUsed;if(!considerVariableAddrOfAsDef)vthenvarDefs:=VS.addv!varDefs;SkipChildren|SizeOfE_|AlignOfE_when!ignoreSizeof->SkipChildren|_->DoChildren(* For function calls, do the transitive variable read/defs *)method!vinsti=letdoCallfdestoargs=(* we will compute the use and def that appear in
this instruction. We also add in the stuff computed by
getUseDefFunctionRef *)letuse,def,args'=!getUseDefFunctionReffargsinvarUsed:=VS.union!varUseduse;varDefs:=VS.union!varDefsdef;(* Now visit the children of "Call (lvo, f, args', _)" *)letself:cilVisitor=(self:>cilVisitor)in(matchdestowithNone->()|Somelv->ignore(visitCilLvalselflv));ignore(visitCilExprselff);List.iter(funarg->ignore(visitCilExprselfarg))args';SkipChildreninmatchiwithCall(None,(Lval(Varvi,NoOffset)asf),[valist;SizeOft;adest],_,_)(* __builtin_va_arg is special: in CIL, the left hand side is stored
as the last argument. *)whenvi.vname="__builtin_va_arg"->letdest'=matchstripCastsadestwithAddrOflv->lv|_->E.s(bug"bad call to %s"vi.vname)indoCallf(Somedest')[valist;SizeOft]|Call(_,Lval(Varvi,_),_,_,_)whenvi.vname="__builtin_va_arg"->E.s(bug"bad call to %s"vi.vname)|Call(lvo,f,args,_,_)->doCallflvoargs|Asm(_,_,slvl,_,_,_)->List.iter(fun(_,s,lv)->matchlvwith(Varv,off)->ifs.[0]='+'thenvarUsed:=VS.addv!varUsed;|_->())slvl;DoChildren|_->DoChildrenendletuseDefVisitor=newuseDefVisitorClass(** Compute the use information for an expression (accumulate to an existing
set) *)letcomputeUseExp?(acc=VS.empty)(e:exp):VS.t=varUsed:=acc;ignore(visitCilExpruseDefVisitore);!varUsed(** Compute the use/def information for an instruction *)letcomputeUseDefInstr?(acc_used=VS.empty)?(acc_defs=VS.empty)(i:instr):VS.t*VS.t=varUsed:=acc_used;varDefs:=acc_defs;ignore(visitCilInstruseDefVisitori);!varUsed,!varDefs(** Compute the use/def information for a statement kind. Do not descend into
the nested blocks. *)letcomputeUseDefStmtKind?(acc_used=VS.empty)?(acc_defs=VS.empty)(sk:stmtkind):VS.t*VS.t=varUsed:=acc_used;varDefs:=acc_defs;letvee=ignore(visitCilExpruseDefVisitore)inlet_=matchskwithReturn(None,_,_)->()|Return(Somee,_,_)->vee|If(e,_,_,_,_)->vee|Break_|Goto_|Continue_->()|ComputedGoto(e,_)->vee|Loop(_,_,_,_,_)->()|Switch(e,_,_,_,_)->vee|Instril->List.iter(funi->ignore(visitCilInstruseDefVisitori))il|Block_->()in!varUsed,!varDefs(* Compute the use/def information for a statement kind.
DO descend into nested blocks *)letreccomputeDeepUseDefStmtKind?(acc_used=VS.empty)?(acc_defs=VS.empty)(sk:stmtkind):VS.t*VS.t=lethandle_blockb=List.fold_left(fun(u,d)s->letu',d'=computeDeepUseDefStmtKinds.skindin(VS.unionuu',VS.uniondd'))(VS.empty,VS.empty)b.bstmtsinvarUsed:=acc_used;varDefs:=acc_defs;letvee=ignore(visitCilExpruseDefVisitore)inmatchskwithReturn(None,_,_)->!varUsed,!varDefs|Return(Somee,_,_)->let_=veein!varUsed,!varDefs|If(e,tb,fb,_,_)->let_=veeinletu,d=!varUsed,!varDefsinletu',d'=handle_blocktbinletu'',d''=handle_blockfbin(VS.union(VS.unionuu')u'',VS.union(VS.uniondd')d'')|Break_|Goto_|Continue_->!varUsed,!varDefs|ComputedGoto(e,_)->let_=veein!varUsed,!varDefs|Loop(b,_,_,_,_)->handle_blockb|Switch(e,b,_,_,_)->let_=veeinletu,d=!varUsed,!varDefsinletu',d'=handle_blockbin(VS.unionuu',VS.uniondd')|Instril->List.iter(funi->ignore(visitCilInstruseDefVisitori))il;!varUsed,!varDefs|Blockb->handle_blockbletcomputeUseLocalTypes?(acc_used=VS.empty)(fd:fundec)=List.fold_left(funuvi->ignore(visitCilTypeuseDefVisitorvi.vtype);VS.unionu(!varUsed))acc_usedfd.slocals