1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)(** Pasting module. *)openCil_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=objectinheritCil.nopCilVisitorassupermethod!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(Cil.visitCilFunction(visitor:>Cil.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"inCil.iterGlobalsast(funglob->matchSymbol.encodeglobwith|None->()|Some(name,symb)->letfile=Filepath.to_stringCil_datatype.(Global.locglob|>Fileloc.path)inletindexnasy=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:Fileloc.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~filexinCil.cvar_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~filexinCil.cvar_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~filevarinCil.cvar_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()=Filepos.make~path:!prop_file~line:!buff_line~column:0~offset:0()(** Get location of the first property token *)letget_prop_loc()=Filepos.make~path:!prop_file~line:!prop_line~column:0~offset:0()(*-----------------------------------------------------------------------*)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(Fileloc.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=Cil.ChangeDoChildrenPost(TVarlvar,funx->x)inletcontinue()=Cil.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=Cil.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(Cil.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(Cil.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=Cil.ChangeDoChildrenPost(TVarlvar,funx->x)andcontinue()=Cil.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=Cil.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(Cil.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(*-----------------------------------------------------------------------*)