123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)(** Pasting module. *)openCilopenCil_types(*-----------------------------------------------------------------------*)letdkey=Options.register_category"trace-table"lethidden_attr="hidden"let()=Ast_attributes.registerAttrUnknownhidden_attrletloop_body_attr="acsl!loop_body!"letloop_number_attr="acsl!loop_number!"(** To get a fresh attribute name for a loop body inside a function *)letloop_body_attr_namen=loop_body_attr^(string_of_intn)(** To get a fresh attribute name for a loop number inside a function *)letloop_number_attr_namen=loop_number_attr^(string_of_intn)moduleS_Stmt=Cil_datatype.Stmt.SetmoduleStatement:sig(** find the ith loop of a function *)valfind_loop_stmt_set:int->kernel_function->Cil_datatype.Stmt.Set.t(** find the ith loop body of a function *)valfind_body_stmt_set:int->kernel_function->Cil_datatype.Stmt.Set.t(** find the ith asm stmt of a function *)valfind_asm_stmt_set:int->kernel_function->Cil_datatype.Stmt.Set.t(** find the ith call stmt of a function *)valfind_call_stmt_set:int->kernel_function->Cil_datatype.Stmt.Set.t(** find the ith/all direct/indirect call stmt of a function *)valfind_call2_stmt_set:kernel_functionoption->int->kernel_function->Cil_datatype.Stmt.Set.t(** find ith statement of a function *)valfind_stmt:int->kernel_function->stmt(** Clear the memoized tables. *)valclear_temporary_table:unit->unitend=struct(** Iter on statements of a kernel function *)letiter_from_funcfkf=letdefinition=Kernel_function.get_definitionkfandvisitor=objectinheritnopCilVisitorassupermethod!vstmtstmt=fstmt;super#vstmtstmt(* speed up: skip non interesting subtrees *)method!vvdec_=SkipChildren(* via visitCilFunction *)method!vspec_=SkipChildren(* via visitCilFunction *)method!vcode_annot_=SkipChildren(* via Code_annot stmt and Loop stmt *)method!vinst_=SkipChildren(* via stmt such as Instr *)method!vexpr_=SkipChildren(* via stmt such as Return, IF, ... *)method!vlval_=SkipChildren(* via stmt such as Set, Call, Asm, ... *)method!vattr_=SkipChildren(* via Asm stmt *)endinignore(visitCilFunction(visitor:>cilVisitor)definition)exceptionFoundStmtofstmtmoduleH_Int=Datatype.Int.HashtblmoduleH_Int_S_Stmt=H_Int.Make(S_Stmt)letmemoized_findfindcreatefind_kfreplace_kfkfncompute=lettbl=tryfind_kfkfwithNot_found->lettbl=create5incomputetbl;replace_kfkftbl;tblinfindtblnleton_acsl_attrtblattr_regexpstmtbattrs=List.iter(function(attr_name,args)whenattr_name=hidden_attr->List.iter(functionAStr(name)->(try(matchStr.bounded_split_delimattr_regexpname2with["";n]->letn=int_of_stringninletstmts=tryH_Int.findtblnwithNot_found->S_Stmt.emptyinletstmts=S_Stmt.add(stmt())stmtsinH_Int.replacetblnstmts|_->())with_->())|_->())args|_->())battrsletfind_from_funcfkf=letfstmt=iffstmtthenraise(FoundStmtstmt)intryiter_from_funcfkf;raiseNot_foundwithFoundStmtstmt->stmt(** Memoized loop number table. *)moduleSloop=State_builder.Hashtbl(Cil_datatype.Kf.Hashtbl)(H_Int_S_Stmt)(structletname="LoopNumberIndex"letdependencies=[]letsize=7end)let_=Ast.add_linked_stateSloop.selfletfind_loop_stmt_setnkf=memoized_findH_Int.findH_Int.createSloop.findSloop.replacekfn(funtbl->Options.debug~level:2~dkey"Computing loop index table for function \"%a\""Kernel_function.prettykf;letattr_regexp=Str.regexp_stringloop_number_attrinleton_loopstmt=matchstmt.skindwith|Loop(_,{battrs},_,_,_)->on_acsl_attrtblattr_regexp(fun()->stmt)battrs|_->()initer_from_funcon_loopkf)(** Memoized loop body table. *)moduleSbody=State_builder.Hashtbl(Cil_datatype.Kf.Hashtbl)(H_Int_S_Stmt)(structletname="LoopBodyIndex"letdependencies=[]letsize=7end)let_=Ast.add_linked_stateSbody.selfletfind_body_stmt_setnkf=memoized_findH_Int.findH_Int.createSbody.findSbody.replacekfn(funtbl->Options.debug~level:2~dkey"Computing loop body table for function \"%a\""Kernel_function.prettykf;letattr_regexp=Str.regexp_stringloop_body_attrinleton_bodystmt=matchstmt.skindwith|Block{battrs}->on_acsl_attrtblattr_regexp(fun()->stmt)battrs|_->()initer_from_funcon_bodykf)(** Memoized asm table. *)moduleSasm=State_builder.Hashtbl(Cil_datatype.Kf.Hashtbl)(H_Int_S_Stmt)(structletname="AsmIndex"letdependencies=[]letsize=7end)let_=Ast.add_linked_stateSasm.selfletfind_asm_stmt_setnkf=memoized_findH_Int.findH_Int.createSasm.findSasm.replacekfn(funtbl->Options.debug~level:2~dkey"Computing asm call table for function \"%a\""Kernel_function.prettykf;letcpt=ref0inleton_asmstmt=matchstmt.skindwith|Instr(Asm_)->incrcpt;H_Int.replacetbl!cpt(S_Stmt.singletonstmt)|_->()initer_from_funcon_asmkf)(** Memoized call table. *)moduleP_S_Stmt=Datatype.Pair(S_Stmt)(S_Stmt)moduleH_Int_P_S_Stmt=H_Int.Make(P_S_Stmt)moduleScall=State_builder.Hashtbl(Cil_datatype.Kf.Hashtbl)(H_Int_P_S_Stmt)(structletname="CallIndex"letdependencies=[]letsize=7end)let_=Ast.add_linked_stateScall.selfletfind_call_stmtnkf=memoized_findH_Int.findH_Int.createScall.findScall.replacekfn(funtbl->Options.debug~level:2~dkey"Computing call table1 for function \"%a\""Kernel_function.prettykf;letcpt=ref0inletcpt_indirect=ref0inletindirect_calls=refS_Stmt.emptyinletgetn=tryH_Int.findtblnwithNot_found->S_Stmt.empty,S_Stmt.emptyinleton_callstmt=matchstmt.skindwith|Instr(Call(_,f,_,_))->beginmatchKernel_function.get_calledfwith|None->incrcpt_indirect;letall,indirect=get!cpt_indirectinH_Int.replacetbl!cpt_indirect(all,(S_Stmt.addstmtindirect));indirect_calls:=(S_Stmt.addstmt!indirect_calls)|_->incrcpt;letall,indirect=get!cptinH_Int.replacetbl!cpt((S_Stmt.addstmtall),indirect);end|_->()initer_from_funcon_callkf;H_Int.replacetbl0(S_Stmt.empty,!indirect_calls))letfind_call_stmt_setnkf=fst(find_call_stmtnkf)(** Memoized call2 table. *)moduleH_Kf=Cil_datatype.Kf.HashtblmoduleH_Kf_H_Int_S_Stmt=H_Kf.Make(H_Int_S_Stmt)moduleScall2=State_builder.Hashtbl(Cil_datatype.Kf.Hashtbl)(H_Kf_H_Int_S_Stmt)(structletname="Call2Index"letdependencies=[]letsize=7end)let_=Ast.add_linked_stateScall2.selfletfind_call2_stmtcalled_kfkf=memoized_findH_Kf.findH_Kf.createScall2.findScall2.replacekfcalled_kf(funtbl->Options.debug~level:2~dkey"Computing call table2 for function \"%a\""Kernel_function.prettykf;lettbl_cpt=H_Kf.create3inleton_callstmt=matchstmt.skindwith|Instr(Call(_,f,_,_))->beginmatchKernel_function.get_calledfwith|Somecalled_kf->letcpt=letcpt=tryH_Kf.findtbl_cptcalled_kfwithNot_found->0inletcpt=cpt+1inH_Kf.replacetbl_cptcalled_kfcpt;cptinlettbl_stmt=tryH_Kf.findtblcalled_kfwithNot_found->lettbl_stmt=H_Int.create3inH_Kf.replacetblcalled_kftbl_stmt;tbl_stmtinlets=tryH_Int.findtbl_stmtcptwithNot_found->S_Stmt.emptyinH_Int.replacetbl_stmtcpt(S_Stmt.addstmts);lets=tryH_Int.findtbl_stmt0withNot_found->S_Stmt.emptyinH_Int.replacetbl_stmt0(S_Stmt.addstmts)|_->()end|_->()initer_from_funcon_callkf)letfind_call2_stmt_setkf_optnkf=matchkf_optwith|None->snd(find_call_stmtnkf)|Somecalled_kf->H_Int.find(find_call2_stmtcalled_kfkf)nletfind_stmtnkf=letnb=ref0inletis_stmt_stmt=incrnb;!nb=ninfind_from_funcis_stmtkf(** Clear the memoized tables. *)letclear_temporary_table()=Options.debug~level:2~dkey"Clear loop index table";Sloop.clear();Options.debug~level:2~dkey"Clear loop body table";Sbody.clear();Options.debug~level:2~dkey"Clear asm call table";Sasm.clear();Options.debug~level:2~dkey"Clear function call tables";Scall.clear();Scall2.clear()end(*-----------------------------------------------------------------------*)moduleMacroIndex:sig(** Macro table management. *)typescope_t=Sfile|Smodule|Sfunctionvalpp_scope:Format.formatter->scope_t->unitvaldkey:Options.category(* val self : State.t
(** Dependencies of the result of find_xxx functions. *)
*)valclear_macro_table:scope_t->unit(** To clear macro table in order to free memory,
without clearing the result dependencies. *)valadd_macro:scope_t->string->Logic_ptree.lexpr->unit(** Modify the macro table,
without clearing the result dependencies. *)valfind_macro:scope_t->string->Logic_ptree.lexpr(** Find the macro definition.
@raise Not_found for undefined macro.*)end=structtypescope_t=Sfile|Smodule|Sfunctionletpp_scopefmt=function|Sfile->Format.fprintffmt"%s""file"|Smodule->Format.fprintffmt"%s""module"|Sfunction->Format.fprintffmt"%s""function"(** Memoized index macro table. *)moduleSfile=State_builder.Hashtbl(Datatype.String.Hashtbl)(Cil_datatype.Lexpr)(structletname="FileMacroIndex"letdependencies=[Ast.self]letsize=3end)let_=Ast.add_linked_stateSfile.selfmoduleSmodule=State_builder.Hashtbl(Datatype.String.Hashtbl)(Cil_datatype.Lexpr)(structletname="ModuleMacroIndex"letdependencies=[Ast.self]letsize=3end)let_=Ast.add_linked_stateSmodule.selfmoduleSfunction=State_builder.Hashtbl(Datatype.String.Hashtbl)(Cil_datatype.Lexpr)(structletname="FunctionMacroIndex"letdependencies=[Ast.self]letsize=3end)let_=Ast.add_linked_stateSfunction.selfletfind_macroscopem=tryifscope=SfunctionthenSfunction.findmelseraiseNot_foundwithNot_found->tryifscope<>SfilethenSmodule.findmelseraiseNot_foundwithNot_found->Sfile.findmletdkey=Options.register_category"trace-tables"letadd_macroscopemdef=Options.debug~level:2~dkey"Add macro %S at %a scope"mpp_scopescope;letreplace=matchscopewith|Sfile->Sfile.replace|Smodule->Smodule.replace|Sfunction->Sfunction.replaceinreplacemdef(* let self = S.self *)(** Clear the memoized "MacroIndex" table in order to free memory,
without clearing the result dependencies. *)letclear_macro_tablescope=Options.debug~level:2~dkey"Clear macro table from %a scope"pp_scopescope;ifscope=SfilethenSfile.clear();ifscope<>SfunctionthenSmodule.clear();Sfunction.clear();endmoduleA2fc_inner_ast=State_builder.Option_ref(Cil_datatype.File)(structletname="A2fcPaste.A2fc_inner_ast"letdependencies=[Ast.self]end)let_=Ast.add_linked_stateA2fc_inner_ast.selfmoduleSymbolIndex:sig(** Symbol table management. *)valself:State.t(** Dependencies of the result of find_xxx functions. *)valclear_temporary_table:unit->unit(** To clear temporary index table in order to free memory,
without clearing the result dependencies. *)valfind_kf:file:File.toption->string->Kernel_function.t(** Find [Kernel_function] related to a global annotation. *)valfind_var_annot:file:File.toption->Kernel_function.t->stmt->?label:string->string->logic_var(** Find variables related to a code annotation. *)valfind_var_funspec:file:File.toption->Kernel_function.t->string->logic_var(** Find variables related to a function contract. *)valfind_var_global:file:File.toption->string->logic_var(** Find variables related to a global annotation. *)valfind_enum_item:file:File.toption->string->exp*typvalfind_type:file:File.toption->Logic_typing.type_namespace->string->typend=structmoduleSymbolCode=structtypesymbol_code=|SGdef|SGdec|SFdef|SFdec|STdef|SItem|SEdef|SEdec|SSdef|SSdec|SUdef|SUdecincludeDatatype.Make_with_collections(structtypet=symbol_codeletname="SymbolCode"letreprs=[SGdef]letstructural_descr=Structural_descr.t_abstractlethash=function|SGdef->0(* priority max *)|SGdec->1|SFdef->2|SFdec->3|STdef->4|SItem->5|SEdef->6|SEdec->7|SSdef->8|SSdec->9|SUdef->10|SUdec->11letcompares1s2=Stdlib.compare(hashs1)(hashs2)letequals1s2=s1=s2letcopyid=idletrehash=Datatype.identityletpretty=Datatype.undefinedletmem_project=Datatype.never_any_projectend)end(** To encapsulate all global C symbols *)moduleSymbol=structletdkey=Options.register_category"trace-symbols"typesymbol=|Gdefofvarinfo|Gdecofvarinfo|Fdefofvarinfo|Fdecofvarinfo|Tdefoftypeinfo|Itemofenumitem|Edefofenuminfo|Edecofenuminfo|Sdefofcompinfo|Sdecofcompinfo|Udefofcompinfo|Udecofcompinfoletsymbol_code=function|Gdef_->SymbolCode.SGdef|Gdec_->SymbolCode.SGdec|Fdef_->SymbolCode.SFdef|Fdec_->SymbolCode.SFdec|Tdef_->SymbolCode.STdef|Item_->SymbolCode.SItem|Edef_->SymbolCode.SEdef|Edec_->SymbolCode.SEdec|Sdef_->SymbolCode.SSdef|Sdec_->SymbolCode.SSdec|Udef_->SymbolCode.SUdef|Udec_->SymbolCode.SUdecletencode=function|GType(t,_)->Options.debug~level:2~dkey"Type: %S@."t.torig_name;Some(t.torig_name,Tdef(t))|GCompTag(c,_)->Options.debug~level:2~dkey"CompTag: %S@."c.corig_name;Some(c.corig_name,ifc.cstructthenSdef(c)elseUdef(c))|GCompTagDecl(c,_)->Options.debug~level:2~dkey"CompTagDecl: %S@."c.cname;Some(c.cname,ifc.cstructthenSdec(c)elseUdec(c))|GEnumTag(e,_)->Options.debug~level:2~dkey"EnumTag: %S@."e.eorig_name;Some(e.eorig_name,Edef(e))|GEnumTagDecl(e,_)->Options.debug~level:2~dkey"EnumTagDecl: %S@."e.eorig_name;Some(e.eorig_name,Edec(e))|GVarDecl(vi,_)->ifvi.vglobthen(Options.debug~level:2~dkey"VarDecl: %S@."vi.vorig_name;Some(vi.vorig_name,Gdec(vi)))elseNone|GFunDecl(_,vi,_)->ifvi.vglobthen(Options.debug~level:2~dkey"FunDecl: %S@."vi.vorig_name;Some(vi.vorig_name,Fdec(vi)))elseNone|GVar(vi,_,_)->ifvi.vglobthen(Options.debug~level:2~dkey"Var: %S@."vi.vorig_name;Some(vi.vorig_name,Gdef(vi)))elseNone|GFun(f,_)->iff.svar.vglobthen(Options.debug~level:2~dkey"Fun: %S@."f.svar.vorig_name;Some(f.svar.vorig_name,Fdef(f.svar)))elseNone|_->NoneincludeDatatype.Make_with_collections(structtypet=symbolletname="Symbol"letreprs=List.map(funv->Gdefv)Cil_datatype.Varinfo.reprsletstructural_descr=Structural_descr.t_abstractletcompares1s2=matchs1,s2with|(Gdef(v1),Gdef(v2)|Gdec(v1),Gdec(v2)|Fdef(v1),Fdef(v2)|Fdec(v1),Fdec(v2))->Cil_datatype.Varinfo.comparev1v2|Tdef(t1),Tdef(t2)->Cil_datatype.Typeinfo.comparet1t2|Item(i1),Item(i2)->Cil_datatype.Enumitem.comparei1i2|(Edef(e1),Edef(e2)|Edec(e1),Edec(e2))->Cil_datatype.Enuminfo.comparee1e2|(Sdef(c1),Sdef(c2)|Sdec(c1),Sdec(c2)|Udef(c1),Udef(c2)|Udec(c1),Udec(c2))->Cil_datatype.Compinfo.comparec1c2|_,_->SymbolCode.compare(symbol_code(s1))(symbol_code(s2))lethashs1=leth1=matchs1with|(Gdef(v1)|Gdec(v1)|Fdef(v1)|Fdec(v1))->Cil_datatype.Varinfo.hashv1|Tdef(t1)->Cil_datatype.Typeinfo.hasht1|Item(i1)->Cil_datatype.Enumitem.hashi1|(Edef(e1)|Edec(e1))->Cil_datatype.Enuminfo.hashe1|(Sdef(c1)|Sdec(c1)|Udef(c1)|Udec(c1))->Cil_datatype.Compinfo.hashc1inleth2=SymbolCode.hash(symbol_code(s1))inHashtbl.hash(h1,h2)letequals1s2=matchs1,s2with|(Gdef(v1),Gdef(v2)|Gdec(v1),Gdec(v2)|Fdef(v1),Fdef(v2)|Fdec(v1),Fdec(v2))->Cil_datatype.Varinfo.equalv1v2|Tdef(t1),Tdef(t2)->Cil_datatype.Typeinfo.equalt1t2|Item(i1),Item(i2)->Cil_datatype.Enumitem.equali1i2|(Edef(e1),Edef(e2)|Edec(e1),Edec(e2))->Cil_datatype.Enuminfo.equale1e2|(Sdefc1,Sdefc2|Sdecc1,Sdefc2|Udefc1,Udefc2|Udecc1,Udecc2)->Cil_datatype.Compinfo.equalc1c2|_,_->falseletcopy=Datatype.undefinedletrehash=Datatype.identityletpretty=Datatype.undefinedletmem_project=Datatype.never_any_projectend)endmoduleH_String=Datatype.String.HashtblmoduleS_Symbol=Symbol.SetmoduleM_SymbolCode=SymbolCode.MapmoduleS_SymbolCode=SymbolCode.SetmoduleH_String2S_Symbol=Datatype.String.Hashtbl.Make(S_Symbol)moduleM_SymbolCode2H_String2S_Symbol=SymbolCode.Map.Make(H_String2S_Symbol)(** Memoized index symbol table:
orig_name -hash-> SymbolCode.t -map-> filename -hash-> Set of Symbol.t
Note:
-hash-> is used as -map-> (only one binding)
-map -> is used when iteration order should use the key order *)moduleS=State_builder.Hashtbl(Datatype.String.Hashtbl)(M_SymbolCode2H_String2S_Symbol)(structletname="SymbolIndex"letdependencies=[]letsize=7end)let_=Ast.add_linked_stateS.selfmoduleFirst=State_builder.True_ref(structletdependencies=[S.self]letname="SymbolIndex.compute"end)letapply_oncef=(fun()->ifFirst.get()thenbeginFirst.setfalse;tryf();assert(First.get()=false)withexn->First.settrue;raiseexnend),First.self(** Compute once the index symbol table. *)letcompute,self=letcompute()=Options.debug~level:2~dkey:MacroIndex.dkey"Indexing the C symbol table...";letast=tryA2fc_inner_ast.get()withNot_found->Options.fatal"No AST registered in ACSL importer plug-in"initerGlobalsast(funglob->matchSymbol.encodeglobwith|None->()|Some(name,symb)->letfile=Filepath.to_string(fst(Cil_datatype.Global.locglob)).Filepath.pos_pathinletindexnasy=letcode=Symbol.symbol_codesyinletupdate_maphtablesymbolsold_map=H_String.replacehtablefilesymbols;M_SymbolCode.addcodehtableold_mapinletnew_indexold_map=lethtable=H_String.create(5)inupdate_maphtable(S_Symbol.singletonsy)old_mapinignore(S.memo~change:(funold_map->trylethtable=M_SymbolCode.findcodeold_mapinletsymbols=tryH_String.findhtablefilewithNot_found->S_Symbol.emptyinupdate_maphtable(S_Symbol.addsysymbols)old_mapwithNot_found->new_indexold_map)(fun_->new_indexM_SymbolCode.empty)na);inindexnamesymb;(* indexing the symbol *)matchsymbwith|Symbol.Edef(enum)->List.iter(funit->indexit.eiorig_name(Symbol.Item(it)))enum.eitems|_->())inapply_oncecompute(** Clear the memoized [SymbolIndex] table and the fact it hash been computed
in order to free memory. *)letclear_temporary_table()=Options.debug~level:2~dkey"Clear symbol table";First.settrue;S.clear();Statement.clear_temporary_table()exceptionFoundSymbolofSymbol.t(** Find a [Symbol.t] from an original name having the highest priority among
[kinds], and lookup for [Symbol.t] used into [file] first when given. *)letfind~kinds~filename=compute();letmap=S.findnamein(* raises Not_found when there is no symbol
entry for that name *)letfind_first_symbol()=tryS_SymbolCode.iter(* use the priority order *)(funcode->trylethtable=M_SymbolCode.findcodemapinH_String.iter(fun_fset->S_Symbol.iter(funs->raise(FoundSymbols))set)htablewithNot_found->())kinds;raiseNot_foundwithFoundSymbolsymb->symbinmatchfilewith|None->find_first_symbol()|Somefile->letfile=(File.get_namefile)intryS_SymbolCode.iter(* use the priority order *)(funcode->trylethtable=M_SymbolCode.findcodemapinletsymbols=H_String.findhtablefileinS_Symbol.iter(funs->raise(FoundSymbols))symbolswithNot_found->())kinds;find_first_symbol()withFoundSymbolsymb->symbletmake_kindskinds=List.fold_left(funaccsc->S_SymbolCode.addscacc)S_SymbolCode.emptykindsletvar_kinds=make_kinds[SymbolCode.SGdef;SymbolCode.SGdec;SymbolCode.SFdef;SymbolCode.SFdec]letkf_kinds=make_kinds[SymbolCode.SFdef;SymbolCode.SFdec]letitem_kinds=S_SymbolCode.singletonSymbolCode.SItemlettype_kinds=S_SymbolCode.singletonSymbolCode.STdefletstruct_kinds=make_kinds[SymbolCode.SSdef;SymbolCode.SSdec]letunion_kinds=make_kinds[SymbolCode.SUdef;SymbolCode.SUdec]letenum_kinds=make_kinds[SymbolCode.SEdef;SymbolCode.SEdec]letfind_varinfo~filename=matchfind~kinds:var_kinds~filenamewith|(Symbol.Gdef(vi)|Symbol.Gdec(vi)|Symbol.Fdef(vi)|Symbol.Fdec(vi))->vi|_->(* IMPOSSIBLE *)assertfalseletfind_kf_varinfo~filename=matchfind~kinds:kf_kinds~filenamewith|(Symbol.Fdef(vi)|Symbol.Fdec(vi))->vi|_->(* IMPOSSIBLE *)assertfalseletfind_enum_item~filename=matchfind~kinds:item_kinds~filenamewith|Symbol.Item(item)->(* [VP 2013-11-06] an enumerated constant has the corresponding
integral type, not an enumerated type. *)lettyp=Cil_const.mk_tintitem.eihost.ekindinletexp=Cil.new_exp~loc:Cil_datatype.Location.unknown(Const(CEnum(item)))inOptions.debug~level:2~dkey"Found enum item of name %s: symbol=%a type=%a@."namePrinter.pp_expexpPrinter.pp_logic_type(Ctypetyp);exp,typ|_->(* IMPOSSIBLE *)assertfalseletfind_typedef_type~filename=matchfind~kinds:type_kinds~filenamewith|Symbol.Tdef(ti)->ti.ttype|_->(* IMPOSSIBLE *)assertfalseletfind_struct_type~filename=matchfind~kinds:struct_kinds~filenamewith|(Symbol.Sdef(ci)|Symbol.Sdec(ci))->Cil_const.mk_tcompci|_->(* IMPOSSIBLE *)assertfalseletfind_union_type~filename=matchfind~kinds:union_kinds~filenamewith|(Symbol.Udef(ci)|Symbol.Udec(ci))->Cil_const.mk_tcompci|_->(* IMPOSSIBLE *)assertfalseletfind_enum_type~filename=matchfind~kinds:enum_kinds~filenamewith|(Symbol.Edef(e)|Symbol.Edec(e))->Cil_const.mk_tenume|_->(* IMPOSSIBLE *)assertfalseletfind_type~filetkindname=letfind_type=matchtkindwith|Logic_typing.Typedef->find_typedef_type|Logic_typing.Struct->find_struct_type|Logic_typing.Union->find_union_type|Logic_typing.Enum->find_enum_typeinfind_type~filenameletlookupvarsx=List.find(funvi->vi.vorig_name=x)vars(** Find variables related to a global annotation. *)letfind_var_global~filex=letvi=(* look at file first *)find_varinfo~filexincvar_to_lvarvi(** Find [Kernel_function] related to a global annotation. *)letfind_kf~filex=letvi=(* look at file first *)find_kf_varinfo~filexinGlobals.Functions.getvi(** Find variables related to a function contract. *)letfind_var_funspec~filekfx=letvi=trylookup(Kernel_function.get_formalskf)xwithNot_found->find_varinfo~filexincvar_to_lvarvi(** Find variables related to a code annotation. *)letfind_var_annot~filekfstmt?labelvar=letscope=matchlabelwith|None|Some"Here"|Some"Old"|Some"Post"->Block_scopestmt|Some"Pre"->letstmt=Kernel_function.find_first_stmtkfinBlock_scopestmt|Some"Init"->Program|Some"LoopEntry"|Some"LoopCurrent"->letstmt=Kernel_function.find_enclosing_loopkfstmtinBlock_scopestmt|Somelab->letstmt=Kernel_function.find_labelkflabinBlock_scope!stmtinletvi=Globals.Syntactic_search.find_in_scopevarscopeinletvi=matchviwith|Somevi->vi|None->find_varinfo~filevarincvar_to_lvarviend(*-----------------------------------------------------------------------*)letbuffer=Buffer.create80letadd_buffers=Buffer.add_stringbuffers(*-----------------------------------------------------------------------*)letprop_file=refFilepath.empty(* file containing the property *)letprop_line=ref0(* line containing the first property token *)letbuff_line=ref0(* line containing the first character of
the string to parse with acsl parser *)letset_prop_locfileline=prop_file:=file;prop_line:=lineletset_buff_locline=buff_line:=line;Buffer.clearbuffer(** Get location of the first character of
the string to parse with acsl parser *)letget_buff_loc()={Cil_datatype.Position.unknownwithFilepath.pos_path=!prop_file;Filepath.pos_lnum=!buff_line}(** Get location of the first property token *)letget_prop_loc()={Cil_datatype.Position.unknownwithFilepath.pos_path=!prop_file;Filepath.pos_lnum=!prop_line}(*-----------------------------------------------------------------------*)letbasename_chop_extensionfile=letbasename=Filename.basenamefileintryFilename.chop_extensionbasenamewithInvalid_argument_->basenameletcurrent_scope=refMacroIndex.Sfileletcurrent_module=refNoneletcurrent_function=refNoneletdkey=Options.register_category"trace-actions"letset_current_scopescope=Options.debug~level:2~dkey"Set current scope to %a@."MacroIndex.pp_scopescope;MacroIndex.clear_macro_tablescope;current_scope:=scopeletset_current_module~is_from_file_namem=Options.debug~level:2~dkey"Set current module to %S@."m;set_current_scope(ifis_from_file_namethenMacroIndex.SfileelseMacroIndex.Smodule);current_function:=None;current_module:=ifm=""thenNoneelsetryletfile=Some(List.find(funfile->m=basename_chop_extension(File.get_namefile))(File.get_all()))inOptions.debug~level:2~dkey"MODULE %s@."m;filewithNot_found->Noneletfind_kffct=SymbolIndex.find_kf~file:!current_modulefctletset_current_function(fct,(source,_loc2))=set_current_scopeMacroIndex.Sfunction;Options.debug~level:2~dkey"Set current function to %S@."fct;trycurrent_function:=Some(find_kffct);Options.debug~level:2~dkey"FUNCTION %s@."fctwithNot_found->Options.annot_error~source"could not find function %s for ACSL importer."fct;current_function:=NoneexceptionKf_not_foundletwith_current_function?source()=match!current_functionwith|None->Options.annot_warning~raising:(fun()->raiseKf_not_found)?source"no proper function found for ACSL importer."|Somekf->kfletget_current_function?source()=match!current_functionwith|None->Options.abort?source"no proper function found for ACSL importer."|Somekf->kf(*--------*)letinit_ast=letfirst=reftrueinfun~file~init_module_from_file_name~init_typenamesast->A2fc_inner_ast.setast;if!firstthenbeginfirst:=false;Logic_env.builtin_types_as_typenames();end;ifinit_typenamesthen(* looks at type names of the [ast_file] to init the parser *)Cil.iterGlobalsast(function|GType(tn,_loc)->Logic_env.add_typenametn.torig_name|_->());ifinit_module_from_file_namethenset_current_module~is_from_file_name:true(basename_chop_extension(Filepath.to_stringfile))(*-----------------------------------------------------------------------*)(** Parse a global annotation. *)letparse_globals=matchLogic_lexer.annot(get_buff_loc(),s)with|Some(_,Logic_ptree.Adecldecls)->(* update starting annotation location *)List.map(fund->{dwithLogic_ptree.decl_loc=(get_prop_loc(),sndd.Logic_ptree.decl_loc)})decls|_->Options.abort"[Syntax error] Unallowed global annotation."(** Parse a function contract. *)letparse_specs=matchLogic_lexer.spec(get_buff_loc(),s)with|Some(loc2,a)->(* update starting annotation location *)a,(get_prop_loc(),loc2)|None->Options.abort"[Syntax error] Invalid function contract"(** Parse a code annotation. *)letparse_annotss=matchLogic_lexer.annot(get_buff_loc(),s)with|Some(_,Logic_ptree.Acode_annot((_loc1,loc2),a))->(* update starting annotation location *)(get_prop_loc(),loc2),[a]|Some(_,Logic_ptree.Aloop_annot((_loc1,loc2),a))->(* update starting annotation location *)(get_prop_loc(),loc2),a|_->Options.abort"[Syntax error] Unallowed annotation."(** Parse a term/pred. *)letparse_lexprs=matchLogic_lexer.lexpr(get_buff_loc(),s)with|Some(_,t)->t,get_prop_loc()|None->Options.abort"[Syntax error] Invalid logic term"(*-----------------------------------------------------------------------*)exceptionStmt_not_foundofKernel_function.tletfind_stmt_set?sourcefind=letkf=with_current_function?source()inletstmts=tryfindkfwithNot_found->raise(Stmt_not_foundkf)instmtsletfind_loop_stmt_set_from_loop_number?sourcenumber=find_stmt_set?source(Statement.find_loop_stmt_setnumber)letfind_loop_body_set_from_loop_number?sourcenumber=find_stmt_set?source(Statement.find_body_stmt_setnumber)letfind_stmt_set_from_call_to?sourcekf_optnum_opt=find_stmt_set?source(Statement.find_call2_stmt_setkf_optnum_opt)letfind_stmt_set_from_call_number?sourcenumber=find_stmt_set?source(Statement.find_call_stmt_setnumber)letfind_stmt_set_from_asm_number?sourcenumber=find_stmt_set?source(Statement.find_asm_stmt_setnumber)letfind_stmt_set_from_label?sourcelabel=find_stmt_set?source(funkf->S_Stmt.singleton!(Kernel_function.find_labelkflabel))letfind_stmt_set_from_sid?sourcelocal_sid=find_stmt_set?source(funkf->S_Stmt.singleton(Statement.find_stmtlocal_sidkf))letfind_stmt_set_from_return?source()=find_stmt_set?source(funkf->S_Stmt.singleton(Kernel_function.find_returnkf))letfind_stmt_set_from_misc?sourcelabel=letkf=get_current_function?source()inletfind_stmt,otherwise=tryletlocal_sid=int_of_stringlabelin(fun()->Statement.find_stmtlocal_sidkf),(fun()->Options.abort?source"statement ID %s not found into %a function for ACSL import."labelKernel_function.prettykf)with|Failure_->(* label is not a statement number *)letfind_stmt=iflabel="return"then(fun()->Kernel_function.find_returnkf)else(fun()->!(Kernel_function.find_labelkflabel))infind_stmt,(fun()->Options.abort?source"statement label %S not found into %a function for ACSL import."labelKernel_function.prettykf)inletstmt=tryfind_stmt()withNot_found->otherwise()inS_Stmt.singletonstmt(*-----------------------------------------------------------------------*)letadd_macro~is_global_scopem=MacroIndex.add_macro(ifis_global_scopethenMacroIndex.Sfileelse!current_scope)mletintegral_casttyt=ifOptions.AddonIntegerCast.get()thenbeginletloc=t.term_locinletsource=fstlocinletty=Ast_types.remove_attributes_for_logic_typetyinOptions.warning~wkey:Options.wkey_integer_cast~source"Casting term %a of type %a into type %a."Printer.pp_termtPrinter.pp_logic_typeLintegerPrinter.pp_typty;Logic_const.tcast~locttyendelseCabs2cil.integral_casttyt(* messages that leads also to an annor_error in raising Exit*)letlt_error(source,_)fmt=Options.annot_warning~raising:(fun()->raiseExit)~sourcefmtletlt_on_erroractionfinallyarg=tryactionargwithExit->finally(Cil_datatype.Location.unknown,"Error");raiseExit(** Add global annotations. *)letdkey=Options.register_category"trace-pasting"letadd_global_annotg_annots=letfile=!current_moduleinletscope=!current_scopeinletmoduleLT=Logic_typing.Make(structletanonCompFieldName=Cabs2cil.anonCompFieldNameletconditionalConversion=Cabs2cil.logicConditionalConversionletis_loop()=falseletfind_macrom=MacroIndex.find_macroscopemletfind_var?label:_var=SymbolIndex.find_var_global~filevarletfind_enum_tags=SymbolIndex.find_enum_item~filesletfind_comp_fieldinfos=Cabs2cil.find_field_offset(funfi->fi.forig_name=s)(Option.value~default:[]info.cfields)letfind_typetkinds=SymbolIndex.find_type~filetkindsletfind_label_s=raiseNot_foundletintegral_cast=integral_castleterror=lt_errorleton_error=lt_on_errorend)inletadd_globalparsed_g_annot=LT.annotparsed_g_annot|>functionNone->()|Someg_annot->ifOptions.continue_after_typing()thenbeginOptions.debug~level:2~dkey"Adding global annotation:@.%a"Printer.pp_global_annotationg_annot;Annotations.add_globalOptions.emitterg_annotendinletadd_globalparsed_g_annot=tryadd_globalparsed_g_annotwith|Exit->Options.annot_error"global annotation ignored by ACSL import."inList.iteradd_globalg_annots(** Add a function contract. *)letadd_funspecspecloc=tryletkf=with_current_function~source:(fst(loc))()inletfile=!current_moduleinletscope=!current_scopeinletmoduleLT=Logic_typing.Make(structletanonCompFieldName=Cabs2cil.anonCompFieldNameletconditionalConversion=Cabs2cil.logicConditionalConversionletis_loop()=falseletfind_macrom=MacroIndex.find_macroscopemletfind_var?label:_var=SymbolIndex.find_var_funspec~filekfvarletfind_enum_tags=SymbolIndex.find_enum_item~filesletfind_comp_fieldinfos=Cabs2cil.find_field_offset(funfi->fi.forig_name=s)(Option.value~default:[]info.cfields)letfind_typetkinds=SymbolIndex.find_type~filetkindsletfind_labels=Kernel_function.find_labelkfsletintegral_cast=integral_castleterror=lt_errorleton_error=lt_on_errorend)inletvi=Kernel_function.get_vikfinletformals=Some(Kernel_function.get_formalskf)inlettyp=Kernel_function.get_typekfinletold_spec=Annotations.funspeckfinletbehaviors=Logic_utils.get_behavior_namesold_specinlet({spec_behavior;spec_terminates;spec_variant;spec_complete_behaviors;spec_disjoint_behaviors}asspec)=(* typed function contract *)LT.funspecbehaviorsviformalstypspecinifOptions.continue_after_typing()thenbeginOptions.debug~level:2~dkey"Adding function specification:@.%a"Printer.pp_funspecspec;Annotations.add_behaviorsOptions.emitterkfspec_behavior;Option.iter(Annotations.add_terminatesOptions.emitterkf)spec_terminates;Option.iter(Annotations.add_decreasesOptions.emitterkf)spec_variant;List.iter(Annotations.add_completeOptions.emitterkf)spec_complete_behaviors;List.iter(Annotations.add_disjointOptions.emitterkf)spec_disjoint_behaviorsendwith|Kf_not_found|Exit->Options.annot_error"function contract ignored by ACSL import."(** Add code annotations. *)letadd_annots_auxkffile?loop_numberlocannotsstmt=letscope=!current_scopeinletmoduleLT=Logic_typing.Make(structletanonCompFieldName=Cabs2cil.anonCompFieldNameletconditionalConversion=Cabs2cil.logicConditionalConversionletis_loop()=Kernel_function.stmt_in_loopkfstmtletfind_macrom=MacroIndex.find_macroscopemletfind_var?labelvar=SymbolIndex.find_var_annot~filekfstmt?labelvarletfind_enum_tags=SymbolIndex.find_enum_item~filesletfind_comp_fieldinfos=Cabs2cil.find_field_offset(funfi->fi.forig_name=s)(Option.value~default:[]info.cfields)letfind_typetkinds=SymbolIndex.find_type~filetkindsletfind_labels=Kernel_function.find_labelkfsletintegral_cast=integral_castleterror=lt_errorleton_error=lt_on_errorend)inletadd_annotparsed_annot=letspec=Annotations.funspeckfinletannot=(* typed code annotation *)LT.code_annotloc(Logic_utils.get_behavior_namesspec)(Ctype(Kernel_function.get_return_typekf))parsed_annotinletadd_annotstmt=(* we are supposed to fill empty specs. Do not refrain from replacing
WritesAny and FreeAllocAny with actual annotations. *)letkeep_empty=falseinifOptions.continue_after_typing()thenbeginmatchannot.annot_contentwith|AStmtSpec(_bhv,_spec)->(* Merging statement contract *)Options.debug~level:2~dkey"Adding statement contract:@.%a"Printer.pp_code_annotationannot;Annotations.add_code_annot~keep_emptyOptions.emitter~kfstmtannot|AAllocation(_bhv,_fa)->(* Merging loop allocation clause *)Options.debug~level:2~dkey"Adding loop allocation clause:@.%a"Printer.pp_code_annotationannot;Annotations.add_code_annot~keep_emptyOptions.emitter~kfstmtannot|AAssigns(_bhv,_a)->(* Merging loop assigns clause *)Options.debug~level:2~dkey"Adding loop assigns clause:@.%a"Printer.pp_code_annotationannot;Annotations.add_code_annot~keep_emptyOptions.emitter~kfstmtannot|AInvariant(bhv,false,pred)whenloop_number<>None->(* Converting invariant into loop invariant when possible *)Options.debug~level:2~dkey"Adding invariant annotation:@.%a"Printer.pp_code_annotationannot;letloop_number=matchloop_numberwith|Someloop_number->loop_number|_->assertfalseinletadd_invariantloop_stmt=letis_convertible=(* it is convertible when the statement is the first statement of the loop block body
and this block has no local variables *)matchloop_stmt.skindwith|Loop(_li,{blocals=[];bstmts=s::_},_loc,_cont,_brk)whens.sid=stmt.sid->true|Loop_->false|_->assertfalseinletstmt,annot=ifis_convertiblethen(Options.debug~level:2~dkey"Converting invariant into loop invariant for loop #%d"loop_number;loop_stmt,{annotwithannot_content=AInvariant(bhv,true,pred)})elsestmt,annotinAnnotations.add_code_annot~keep_emptyOptions.emitter~kfstmtannotinS_Stmt.iteradd_invariant(tryfind_loop_stmt_set_from_loop_numberloop_numberwithStmt_not_foundkf->lt_errorloc"loop %d not found into %a function for ACSL import"loop_numberKernel_function.prettykf)|_->Options.debug~level:2~dkey"Adding statement annotation:@.%a"Printer.pp_code_annotationannot;Annotations.add_code_annot~keep_emptyOptions.emitter~kfstmtannotendinletloop_stmt=letrecget_loop_stmtstmt=matchstmt.skindwith|Loop_->Somestmt|Block{bstmts=stmt::_}->get_loop_stmtstmt|_->Noneinget_loop_stmtstmtinmatchloop_stmtwith|NonewhenLogic_utils.is_loop_annotannot->lt_errorloc"loop annotations are only allowed for loop statements."|Someloop_stmtwhenLogic_utils.is_loop_annotannot->add_annotloop_stmt|_->add_annotstmtinletadd_annotparsed_annot=tryadd_annotparsed_annotwith|Exit->Options.annot_error"code annotation ignored by ACSL import."inList.iteradd_annotannotsletadd_annots?loop_numberstmtslocannots=tryletkf=with_current_function~source:(fst(loc))()inletfile=!current_moduleinS_Stmt.iter(add_annots_auxkffile?loop_numberlocannots)stmtswith|Kf_not_found->Options.annot_error"code annotation ignored by ACSL import."(** Add Caveat Post clauses as an ensures and an exits clause. *)letadd_postkfid_locpost=letvisitor=object(self)inheritVisitor.frama_c_inplacevalmutablestatus=Nonemethod!vterm_lhostterm_lhost=letchange_tolvar=ChangeDoChildrenPost(TVarlvar,funx->x)inletcontinue()=JustCopyinmatchstatus,term_lhostwith|None,TVar{lv_name="\\exit_status"}->(* meet first "\exit_status" ... *)letlvar=Cil_const.make_logic_var_quant"exit_status"Lintegerin(* ... so, performs transformation for the ensures clause *)status<-Some(Normal,lvar,None);change_tolvar|None,TResult(typ)->(* meet first "\result" so,... *)letlvar=Cil_const.make_logic_var_quant"result"(Ctypetyp)in(* ... so, performs transformation for the exits clause *)status<-Some(Exits,lvar,None);change_tolvar|Some(Normal,lvar,_),TVar{lv_name="\\exit_status"}->(* a second "\\exit_status" ... *)change_tolvar|Some(Exits,lvar,_),TResult(_)->(* a second "\\result" *)change_tolvar|Some(Normal,lvar,None),TResult(typ)->(* first "\result" while transforming "\exit_status" *)status<-Some(Normal,lvar,Some(Cil_const.make_logic_var_quant"result"(Ctypetyp)));continue()|Some(Exits,lvar,None),TVar{lv_name="\\exit_status"}->(* first "\exit_status" while transforming "\result" *)status<-Some(Exits,lvar,Some(Cil_const.make_logic_var_quant"exit_status"Linteger));continue()|_->continue()(** Transform the predicate into two clauses: one ensures + one
exits. *)methodmake_post_condpred=(* look at "\result" and "\exit_status" and transform one of these *)letnew_pred=visitCilPredicate(self:>Cil.cilVisitor)predinletmake_clausepredkindname=letnameid=ifid=""thennameelse(id^"_"^name)inkind,Logic_const.new_predicate{predwithpred_name=nameid::pred.pred_name}inletquantiflvarpred={predwithpred_content=Pforall([lvar],{predwithpred_name=[]})}inletmake_other_clauseotherpredkind=letother_pred=matchotherwith|None->pred|Somelvar->(* a second transformation is needed ... *)status<-Some(kind,lvar,None);(* so, performs that second transformation *)quantiflvar(visitCilPredicate(self:>Cil.cilVisitor)pred)inmake_clauseother_predkindinmatchstatuswith|Some(Normal,lvar,other)->(* "\result" has been transformed *)[make_clause(quantiflvarnew_pred)Normal"at_return";make_other_clauseotherpredExits"at_exit"]|Some(Exits,lvar,other)->(* "\exit_status" has been transformed *)[make_other_clauseotherpredNormal"at_return";make_clause(quantiflvarnew_pred)Exits"at_exit"]|_->[make_clausenew_predNormal"at_return";make_clausepredExits"at_exit"]endinletfile=!current_moduleinletscope=!current_scopeinletmoduleLT=Logic_typing.Make(structletanonCompFieldName=Cabs2cil.anonCompFieldNameletconditionalConversion=Cabs2cil.logicConditionalConversionletis_loop()=falseletfind_macrom=MacroIndex.find_macroscopemletfind_var?label:_var=SymbolIndex.find_var_funspec~filekfvarletfind_enum_tags=SymbolIndex.find_enum_item~filesletfind_comp_fieldinfos=Cabs2cil.find_field_offset(funfi->fi.forig_name=s)(Option.value~default:[]info.cfields)letfind_typetkinds=SymbolIndex.find_type~filetkindsletfind_labels=Kernel_function.find_labelkfsletintegral_cast=integral_castleterror=lt_errorleton_error=lt_on_errorend)inletenv=Logic_typing.post_state_envExits(Ctype(Kernel_function.get_return_typekf))inletadd_formalenvvi=Logic_typing.add_varvi.vorig_name(cvar_to_lvarvi)envinletenv=List.fold_leftadd_formalenv(Kernel_function.get_formalskf)intryletpred=LT.predicateenvpostinifOptions.continue_after_typing()thenbeginletbehavior=Cil.mk_behavior~name:id~post_cond:(visitor#make_post_condpred)()inAnnotations.add_behaviorsOptions.emitterkf[behavior]endwith|Exit->Options.annot_error"extended annotation ignored by ACSL import."(*-----------------------------------------------------------------------*)(** Grammar extension for "ensures_and_exits" clauses given into C files. *)letensures_and_exits_typer~typing_context~locps=matchpswith|[p]->beginletenv=typing_context.Logic_typing.post_state[Normal;Exits]inletpred=typing_context.Logic_typing.type_predicatetyping_contextenvpinletvisitor=object(self)inheritVisitor.frama_c_inplacevalmutablestatus=Nonemethod!vterm_lhostterm_lhost=letchange_tolvar=ChangeDoChildrenPost(TVarlvar,funx->x)andcontinue()=JustCopyinmatchstatus,term_lhostwith|None,TVar{lv_name="\\exit_status"}->(* meet first "\exit_status" ... *)letlvar=Cil_const.make_logic_var_quant"exit_status"Lintegerin(* ... so, performs transformation for the ensures clause *)status<-Some(Normal,lvar,None);change_tolvar|None,TResult(typ)->(* meet first "\result" so,... *)letlvar=Cil_const.make_logic_var_quant"result"(Ctypetyp)in(* ... so, performs transformation for the exits clause *)status<-Some(Exits,lvar,None);change_tolvar|Some(Normal,lvar,_),TVar{lv_name="\\exit_status"}->(* a second "\\exit_status" ... *)change_tolvar|Some(Exits,lvar,_),TResult(_)->(* a second "\\result" *)change_tolvar|Some(Normal,lvar,None),TResult(typ)->(* first "\result" while transforming "\exit_status" *)status<-Some(Normal,lvar,Some(Cil_const.make_logic_var_quant"result"(Ctypetyp)));continue()|Some(Exits,lvar,None),TVar{lv_name="\\exit_status"}->(* first "\exit_status" while transforming "\result" *)status<-Some(Exits,lvar,Some(Cil_const.make_logic_var_quant"exit_status"Linteger));continue()|_->continue()(** Transform the predicate into two clauses: one ensures + one
exits. *)methodmake_post_condpred=(* look at "\result" and "\exit_status" and transform one of these *)letnew_pred=visitCilPredicate(self:>Cil.cilVisitor)predandmake_clausepredname=letpred_name=name::pred.pred_namein{predwithpred_name}andquantiflvarpred={predwithpred_content=Pforall([lvar],{predwithpred_name=[]})}inletmake_other_clauseotherpredkind=letother_pred=matchotherwith|None->pred|Somelvar->(* a second transformation is needed ... *)status<-Some(kind,lvar,None);(* so, performs that second transformation *)quantiflvar(visitCilPredicate(self:>Cil.cilVisitor)pred)inmake_clauseother_predinmatchstatuswith|Some(Normal,lvar,other)->(* "\result" has been transformed *)[make_clause(quantiflvarnew_pred)"at_return";make_other_clauseotherpredExits"at_exit"]|Some(Exits,lvar,other)->(* "\exit_status" has been transformed*)[make_other_clauseotherpredNormal"at_return";make_clause(quantiflvarnew_pred)"at_exit"]|_->[make_clausenew_pred"at_return";make_clausepred"at_exit"]endin(* transform the predicate into two new clauses *)Ext_preds(visitor#make_post_condpred)end|_->typing_context.Logic_typing.errorloc"[Syntax error] Expecting a predicate after keyword ensures_and_exits."letclause_extension="ensures_and_exits"(* Register the grammar extension for "ensures_and_exits" clauses. *)let()=letclause_typertyping_contextlocps=ifOptions.AddonEnsuresAndExits.get()thenensures_and_exits_typer~typing_context~locpselsetyping_context.Logic_typing.errorloc"[Setting error] Rejected clause extension: %s."clause_extensioninAcsl_extension.register_behavior~plugin:"acsl_importer"clause_extensionclause_typerfalselet()=letdkey=Options.register_category"trace-ensures-and-exits"inletcode_transformation=File.register_code_transformation_categoryclause_extensioninletmk_clausep=letkind=matchp.pred_namewith|"at_exit"::_->Exits|"at_return"::_->Normal|_->Options.fatal"Unrecognized predicate in %s extension %a"clause_extensionPrinter.pp_predicatepinletpred_name=matchp.pred_namewith|name::first::tl->(name^"_"^first)::tl|_->p.pred_nameinletpred=Logic_const.new_predicate{pwithpred_name}inOptions.debug~level:2~dkey"Adding clause: %s %a@."(Cil_printer.get_termination_kind_namekind)Cil_printer.pp_identified_predicatepred;kind,predinlettransformast=letvis=object(self)inheritVisitor.frama_c_inplacevalmutableactive=Nonemethod!vcode_annotca=matchca.annot_contentwith|AStmtSpec(a,_)->active<-Somea;DoChildrenPost(funr->active<-None;r)|_->SkipChildren(* nothing to do outside of contract. *)method!vbehaviorbhv=letmy_ext=List.filter(fun{ext_name}->ext_name=clause_extension)bhv.b_extendedinmatchmy_extwith|[]->SkipChildren|_->List.iter(funclause_extension->Options.debug~level:2~dkey"Removing clause: %a@."Cil_printer.pp_extendedclause_extension;(* note: the remove_extended never fails even if the clause
is not found and there are two possible emiter for it. *)Annotations.remove_extendedEmitter.end_user(*from C file*)(Option.getself#current_kf)clause_extension;Annotations.remove_extendedOptions.emitter(*imported*)(Option.getself#current_kf)clause_extension)my_ext;letclauses=List.concat(List.map(function|{ext_kind=Ext_predsl}->List.mapmk_clausel|_->Options.fatal"Unrecognized content of extension %s"clause_extension)my_ext)inletkf=Option.getself#current_kfinletstmt=self#current_stmtinletbehavior=ifCil.is_default_behaviorbhvthenNoneelseSomebhv.b_nameinAnnotations.add_ensuresOptions.emitterkf?stmt?active?behaviorclauses;SkipChildrenendinVisitor.visitFramacFileSameGlobalsvisastinletdeps=(* extension only active when this option is given. *)[(moduleOptions.AddonEnsuresAndExits:Parameter_sig.S)]inletafter=[Options.main_import]inFile.add_code_transformation_after_cleanup~deps~aftercode_transformationtransform(*-----------------------------------------------------------------------*)(* "Implicit state variables"
!prop_file: file containing the property
!prop_line: line containing the first property token
!buff_line: line containing the first character of
the string to parse with acsl parser
!current_module: None -> lookup into all files
Some file -> lookup first into file (with its full path)
*)(** Do not forget "Implicit state variables" for plug-in API: *)letpaste_global_annots=letglobal_annot=parse_globalsinadd_global_annotglobal_annot(** Do not forget "Implicit state variables" for plug-in API: *)letpaste_fun_specs=letfun_spec,loc=parse_specsinadd_funspecfun_specloc(** Do not forget "Implicit state variables" for plug-in API: *)letpaste_postcondkfids=letpost,loc=parse_lexprsinadd_postkfidlocpost(** Do not forget "Implicit state variables" for plug-in API: *)letpaste_code_annot?loop_numberstmtss=letloc,annots=parse_annotssinadd_annots?loop_numberstmtslocannots(*-- Pasting global annotations from buffer --*)letdkey=Options.register_category"trace-importations"letpaste_at_global~clause=letprop=Buffer.contentsbufferinOptions.debug~level:2~dkey"Importing %s %s;@."clauseprop;paste_global_annot(clause^" "^prop^";")(*-- Pasting function contracts from buffer --*)letpaste_at_func~clause=letprop=Buffer.contentsbufferinOptions.debug~level:2~dkey"Importing %s %s;@."clauseprop;paste_fun_spec(clause^" "^prop^";")letpaste_at_func_behavior~clause~behav=letprop=Buffer.contentsbufferinletprop=clause^" "^prop^";"inletprop=ifbehav=""thenpropelse("behavior "^behav^": "^prop)inOptions.debug~level:2~dkey"Importing %s@."prop;paste_fun_specpropletpaste_post~behav=letprop=Buffer.contentsbufferinOptions.debug~level:2~dkey"Importing ensures_and_exits %s: %s;@."behavprop;letkf=get_current_function()inpaste_postcondkfbehavprop(*-- Pasting code annotations from buffer --*)letpaste_loop_body~clause~loop=letprop=Buffer.contentsbufferinOptions.debug~level:2~dkey"Importing AT loop %s: %s %s;@."loopclauseprop;letloop_number=int_of_stringloopinletstmts=tryfind_loop_body_set_from_loop_numberloop_numberwithStmt_not_foundkf->Options.abort"loop body %d not found into %a function for ACSL import."loop_numberKernel_function.prettykfinpaste_code_annot~loop_numberstmts(clause^" "^prop^";")letpaste_code~clause~label=letprop=Buffer.contentsbufferinOptions.debug~level:2~dkey"Importing AT %s: %s %s;@."labelclauseprop;letstmts=find_stmt_set_from_misclabelinpaste_code_annotstmts(clause^" "^prop^";")letpaste_at_stmt~clause~loop~label=ifloop=""thenpaste_code~clause~labelelsepaste_loop_body~clause~loopletpaste_at_loop~clause~loop=letprop=Buffer.contentsbufferinOptions.debug~level:2~dkey"Importing AT loop %s: loop %s %s;@."loopclauseprop;letloop_number=int_of_stringloopinletstmts=tryfind_loop_stmt_set_from_loop_numberloop_numberwithStmt_not_foundkf->Options.abort"loop %d not found into %a function for ACSL import."loop_numberKernel_function.prettykfinpaste_code_annotstmts("loop "^clause^" "^prop^";")(*-----------------------------------------------------------------------*)letinit_pasting~pfile~pline?(bline=pline)~cfileast=init_ast~file:cfile~init_module_from_file_name:true~init_typenames:trueast;prop_file:=(Filepath.of_stringpfile);prop_line:=pline;buff_line:=bline(** For external plug-in API: *)letpaste_global_annot~pfile~pline~cfilesast=init_pasting~pfile~pline~cfileast;paste_global_annotsletdkey=Options.register_category"trace-actions"(** For external plug-in API: *)letpaste_fun_speckf~pfile~pline~cfilesast=init_pasting~pfile~pline~cfileast;Options.debug~level:2~dkey"Set current function to %a@."Kernel_function.prettykf;current_function:=Somekf;paste_fun_specs(** For external plug-in API: *)letpaste_code_annotkfstmt~pfile~pline~cfilesast=init_pasting~pfile~pline~cfileast;Options.debug~level:2~dkey"Set current function to %a@."Kernel_function.prettykf;current_function:=Somekf;paste_code_annot(S_Stmt.singletonstmt)s(*-----------------------------------------------------------------------*)