123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456(*
*
* Copyright (c) 2004,
* Jeremy Condit <jcondit@cs.berkeley.edu>
* George C. Necula <necula@cs.berkeley.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*)openCilopenFeaturemoduleE=Errormsgletdebug=falseletnumRegions:int=2letnewGlobals:globallistref=ref[]letcurFundec:fundecref=refdummyFunDecletcurLocation:locationref=reflocUnknownletapplyOption(fn:'a->'b)(ao:'aoption):'boption=matchaowith|Somea->Some(fna)|None->NoneletgetRegion(attrs:attributes):int=trymatchList.hd(filterAttributes"region"attrs)with|Attr(_,[AInti])->i|_->E.s(bug"bad region attribute")withFailure_->1letcheckRegion(i:int)(attrs:attributes):bool=(getRegionattrs)=iletregionField(i:int):string="r"^(string_of_inti)letregionStruct(i:int)(name:string):string=name^"_r"^(string_of_inti)letfoldRegions(fn:int->'a->'a)(base:'a):'a=letrechelper(i:int):'a=ifi<=numRegionsthenfni(helper(i+1))elsebaseinhelper1letrecgetTypeName(t:typ):string=matchtwith|TVoid_->"void"|TInt_->"int"|TFloat_->"float"|TComp(cinfo,_)->"comp_"^cinfo.cname|TNamed(tinfo,_)->"td_"^tinfo.tname|TPtr(bt,_)->"ptr_"^(getTypeNamebt)|TArray(bt,_,_)->"array_"^(getTypeNamebt)|TFun_->"fn"|_->E.s(unimp"typename")letisAllocFunction(fn:exp):bool=matchfnwith|Lval(Varvinfo,NoOffset)whenvinfo.vname="malloc"->true|_->falseletisExternalFunction(fn:exp):bool=matchfnwith|Lval(Varvinfo,NoOffset)whenvinfo.vstorage=Extern->true|_->falselettypes:(int*typsig,typ)Hashtbl.t=Hashtbl.create113lettypeInfos:(int*string,typeinfo)Hashtbl.t=Hashtbl.create113letcompInfos:(int*int,compinfo)Hashtbl.t=Hashtbl.create113letvarTypes:(typsig,typ)Hashtbl.t=Hashtbl.create113letvarCompInfos:(typsig,compinfo)Hashtbl.t=Hashtbl.create113letrecsliceCompInfo(i:int)(cinfo:compinfo):compinfo=tryHashtbl.findcompInfos(i,cinfo.ckey)withNot_found->mkCompInfocinfo.cstruct(regionStructicinfo.cname)(funcinfo'->Hashtbl.addcompInfos(i,cinfo.ckey)cinfo';List.fold_right(funfinforest->lett=sliceTypeifinfo.ftypeinifnot(isVoidTypet)then(finfo.fname,t,finfo.fbitfield,finfo.fattr,finfo.floc)::restelserest)cinfo.cfields[])cinfo.cattrandsliceTypeInfo(i:int)(tinfo:typeinfo):typeinfo=tryHashtbl.findtypeInfos(i,tinfo.tname)withNot_found->letresult={tinfowithtname=regionStructitinfo.tname;ttype=sliceTypeitinfo.ttype;}inHashtbl.addtypeInfos(i,tinfo.tname)result;resultandsliceType(i:int)(t:typ):typ=letts=typeSigtintryHashtbl.findtypes(i,ts)withNot_found->letresult=matchtwith|TVoid_->t|TInt(_,attrs)->ifcheckRegioniattrsthentelseTVoid[]|TFloat(_,attrs)->ifcheckRegioniattrsthentelseTVoid[]|TComp(cinfo,attrs)->TComp(sliceCompInfoicinfo,attrs)|TNamed(tinfo,attrs)->TNamed(sliceTypeInfoitinfo,attrs)|TPtr(TVoid_,_)->t(* Avoid discarding void*. *)|TPtr(bt,attrs)->letbt'=sliceTypeibtinifnot(isVoidTypebt')thenTPtr(bt',attrs)elseTVoid[]|TArray(bt,eo,attrs)->TArray(sliceTypeibt,applyOption(sliceExp1)eo,attrs)|TFun(ret,args,va,attrs)->ifcheckRegioniattrsthenTFun(sliceTypeAllret,applyOption(Util.list_map(fun(aname,atype,aattrs)->(aname,sliceTypeAllatype,aattrs)))args,va,attrs)elseTVoid[]|TBuiltin_va_list_->t|_->E.s(unimp"type %a"d_typet)inHashtbl.addtypes(i,ts)result;resultandsliceTypeAll(t:typ):typ=beginmatchtwith|TComp(cinfo,_)whenhasAttribute"var_type_sliced"cinfo.cattr->E.s(bug"tried to slice twice")|_->()end;letts=typeSigtintryHashtbl.findvarTypestswithNot_found->letcinfo=letname=("var_"^(getTypeNamet))inifdebugthenignore(E.log"creating %s\n"name);tryHashtbl.findvarCompInfostswithNot_found->mkCompInfotruename(funcinfo->Hashtbl.addvarCompInfostscinfo;foldRegions(funirest->lett'=sliceTypeitinifnot(isVoidTypet')then(regionFieldi,t',None,[],!curLocation)::restelserest)[])[Attr("var_type_sliced",[])]inlett'=ifList.lengthcinfo.cfields>1thenbeginnewGlobals:=GCompTag(cinfo,!curLocation)::!newGlobals;TComp(cinfo,[])endelsetinHashtbl.addvarTypestst';t'andsliceLval(i:int)(lv:lval):lval=ifdebugthenignore(E.log"lval %a\n"d_lvallv);letlh,offset=lvinmatchlhwith|Varvinfo->lett=sliceTypeAllvinfo.vtypeinletoffset'=matchtwith|TComp(cinfo,_)whenhasAttribute"var_type_sliced"cinfo.cattr->Field(getCompFieldcinfo(regionFieldi),offset)|_->offsetinVarvinfo,offset'|Meme->Mem(sliceExpie),offsetandsliceExp(i:int)(e:exp):exp=ifdebugthenignore(E.log"exp %a\n"d_expe);matchewith|Constc->Constc|Lvallv->Lval(sliceLvalilv)|UnOp(op,e1,t)->UnOp(op,sliceExpie1,sliceTypeit)|BinOp(op,e1,e2,t)->BinOp(op,sliceExpie1,sliceExpie2,sliceTypeit)|CastE(t,e)->sliceCastite|AddrOflv->AddrOf(sliceLvalilv)|StartOflv->StartOf(sliceLvalilv)|SizeOft->SizeOf(sliceTypeAllt)|_->E.s(unimp"exp %a"d_expe)andsliceCast(i:int)(t:typ)(e:exp):exp=lette=typeOfeinmatcht,tewith|TInt(k1,_),TInt(k2,attrs2)whenk1=k2->(* Note: We strip off integer cast operations. *)sliceExp(getRegionattrs2)e|TInt(k1,_),TPtr_->(* Note: We strip off integer cast operations. *)sliceExpie|TPtr_,_whenisZeroe->CastE(sliceTypeit,sliceExpie)|TPtr(bt1,_),TPtr(bt2,_)when(typeSigbt1)=(typeSigbt2)->CastE(sliceTypeit,sliceExpie)|_->E.s(unimp"sketchy cast (%a) -> (%a)\n"d_typeted_typet)andsliceExpAll(e:exp)(l:location):instrlist*exp=lett=typeOfeinlett'=sliceTypeAlltinmatcht'with|TComp(cinfo,_)whenhasAttribute"var_type_sliced"cinfo.cattr->letvinfo=makeTempVar!curFundectinletinstrs=foldRegions(funirest->tryletfinfo=getCompFieldcinfo(regionFieldi)inifnot(isVoidTypefinfo.ftype)thenSet((Varvinfo,Field(finfo,NoOffset)),sliceExpie,l)::restelserestwithNot_found->rest)[]ininstrs,Lval(varvinfo)|_->[],sliceExp1eletsliceVar(vinfo:varinfo):unit=ifhasAttribute"var_sliced"vinfo.vattrthenE.s(bug"tried to slice a var twice");lett=sliceTypeAllvinfo.vtypeinifdebugthenignore(E.log"setting %s type to %a\n"vinfo.vnamed_typet);vinfo.vattr<-addAttribute(Attr("var_sliced",[]))vinfo.vattr;vinfo.vtype<-tletsliceInstr(inst:instr):instrlist=matchinstwith|Set(lv,e,loc)->ifdebugthenignore(E.log"set %a %a\n"d_lvallvd_expe);lett=typeOfLvallvinfoldRegions(funirest->ifnot(isVoidType(sliceTypeit))thenSet(sliceLvalilv,sliceExpie,loc)::restelserest)[]|Call(ret,fn,args,l)whenisAllocFunctionfn->letlv=matchretwith|Somelv->lv|None->E.s(bug"malloc call has no return lval")inlett=typeOfLvallvinfoldRegions(funirest->ifnot(isVoidType(sliceTypeit))thenCall(Some(sliceLvalilv),sliceExp1fn,Util.list_map(sliceExpi)args,l)::restelserest)[]|Call(ret,fn,args,l)whenisExternalFunctionfn->[Call(applyOption(sliceLval1)ret,sliceExp1fn,Util.list_map(sliceExp1)args,l)]|Call(ret,fn,args,l)->letret',set=matchretwith|Somelv->letvinfo=makeTempVar!curFundec(typeOfLvallv)inSome(varvinfo),[Set(lv,Lval(varvinfo),l)]|None->None,[]inletinstrs,args'=List.fold_right(funarg(restInstrs,restArgs)->letinstrs,arg'=sliceExpAllarglininstrs@restInstrs,(arg'::restArgs))args([],[])ininstrs@(Call(ret',sliceExp1fn,args',l)::set)|_->E.s(unimp"inst %a"d_instrinst)letsliceReturnExp(eo:expoption)(l:location):stmtkind=matcheowith|Somee->beginmatchsliceExpAllelwith|[],e'->Return(Somee',l)|instrs,e'->Block(mkBlock[mkStmt(Instrinstrs);mkStmt(Return(Somee',l))])end|None->Return(None,l)letrecsliceStmtKind(sk:stmtkind):stmtkind=matchskwith|Instrinstrs->Instr(List.flatten(Util.list_mapsliceInstrinstrs))|Blockb->Block(sliceBlockb)|If(e,b1,b2,l)->If(sliceExp1e,sliceBlockb1,sliceBlockb2,l)|Breakl->Breakl|Continuel->Continuel|Return(eo,l)->sliceReturnExpeol|Switch(e,b,sl,l)->Switch(sliceExp1e,sliceBlockb,Util.list_mapsliceStmtsl,l)|Loop(b,l,so1,so2)->Loop(sliceBlockb,l,applyOptionsliceStmtso1,applyOptionsliceStmtso2)|Goto_->sk|_->E.s(unimp"statement")andsliceStmt(s:stmt):stmt=(* Note: We update statements destructively so that goto/switch work. *)s.skind<-sliceStmtKinds.skind;sandsliceBlock(b:block):block=ignore(Util.list_mapsliceStmtb.bstmts);bletsliceFundec(fd:fundec)(l:location):unit=curFundec:=fd;curLocation:=l;ignore(sliceBlockfd.sbody);curFundec:=dummyFunDec;curLocation:=locUnknownletsliceGlobal(g:global):unit=matchgwith|GType(tinfo,l)->newGlobals:=foldRegions(funirest->GType(sliceTypeInfoitinfo,l)::rest)!newGlobals|GCompTag(cinfo,l)->newGlobals:=foldRegions(funirest->GCompTag(sliceCompInfoicinfo,l)::rest)!newGlobals|GCompTagDecl(cinfo,l)->newGlobals:=foldRegions(funirest->GCompTagDecl(sliceCompInfoicinfo,l)::rest)!newGlobals|GFun(fd,l)->sliceFundecfdl;newGlobals:=GFun(fd,l)::!newGlobals|GVarDecl_|GVar_->(* Defer processing of vars until end. *)newGlobals:=g::!newGlobals|_->E.s(unimp"global %a\n"d_globalg)letsliceGlobalVars(g:global):unit=matchgwith|GFun(fd,l)->curFundec:=fd;curLocation:=l;List.itersliceVarfd.slocals;List.itersliceVarfd.sformals;setFunctionTypefd(sliceType1fd.svar.vtype);curFundec:=dummyFunDec;curLocation:=locUnknown;|GVar(vinfo,_,l)->curLocation:=l;sliceVarvinfo;curLocation:=locUnknown|_->()classdropAttrsVisitor=objectinheritnopCilVisitormethod!vvrbl(vinfo:varinfo)=vinfo.vattr<-dropAttribute"var_sliced"vinfo.vattr;DoChildrenmethod!vglob(g:global)=beginmatchgwith|GCompTag(cinfo,_)->cinfo.cattr<-dropAttribute"var_type_sliced"cinfo.cattr;|_->()end;DoChildrenendletsliceFile(f:file):unit=newGlobals:=[];List.itersliceGlobalf.globals;List.itersliceGlobalVarsf.globals;f.globals<-List.rev!newGlobals;visitCilFile(newdropAttrsVisitor)fletfeature={fd_name="DataSlicing";fd_enabled=false;fd_description="data slicing";fd_extraopt=[];fd_doit=sliceFile;fd_post_check=true;}let()=Feature.registerfeature