12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openDatamoduleMd=MarkdownmoduleJs=Yojson.Basic.UtilmodulePkg=PackageopenCil_typesletpackage=Pkg.package~title:"Ast Services"~name:"ast"~readme:"ast.md"()(* -------------------------------------------------------------------------- *)(* --- Compute Ast --- *)(* -------------------------------------------------------------------------- *)let()=Request.register~package~kind:`EXEC~name:"compute"~descr:(Md.plain"Ensures that AST is computed")~input:(moduleJunit)~output:(moduleJunit)Ast.computeletast_changed_signal=Request.signal~package~name:"changed"~descr:(Md.plain"Emitted when the AST has been changed")letast_changed()=Request.emitast_changed_signalletast_update_hookf=beginAst.add_hook_on_updatef;Ast.apply_after_computed(fun_->f());endlet()=ast_update_hookast_changedlet()=Annotations.add_hook_on_changeast_changed(* -------------------------------------------------------------------------- *)(* --- File Positions --- *)(* -------------------------------------------------------------------------- *)modulePosition=structtypet=Filepos.tletjtype=Data.declare~package~name:"source"~descr:(Md.plain"Source file positions.")(Jrecord["dir",Jstring;"base",Jstring;"file",Jstring;"line",Jnumber;])letto_jsonp=letpath=Filepos.pathp|>Filepath.to_stringinletfile=ifServer_parameters.has_relative_filepath()thenpathelseFilepos.pathp|>Filepath.to_string_absin`Assoc["dir",`String(Filename.dirnamepath);"base",`String(Filename.basenamepath);"file",`Stringfile;"line",`Int(Filepos.linep);]letof_jsonjs=letfail()=failure_from_type_error"Invalid source format"jsinmatchjswith|`Assocassoc->beginmatchList.assoc"file"assoc,List.assoc"line"assocwith|`Stringpath,`Intline->Log.source~file:(Filepath.of_stringpath)~line|_,_->fail()|exceptionNot_found->fail()end|_->fail()end(* -------------------------------------------------------------------------- *)(* --- Generic Markers --- *)(* -------------------------------------------------------------------------- *)moduletypeTagInfo=sigtypetvalname:stringvaldescr:stringvalcreate:t->stringmoduleH:Hashtbl.Swithtypekey=tendmoduletypeTag=sigincludeData.Svalindex:t->stringvalfind:string->tendmoduleMakeTag(T:TagInfo):sigincludeTagwithtypet=T.tvaliter:(t*string->unit)->unitvalhook:(t*string->unit)->unitend=structtypet=T.ttypeindex={tags:stringT.H.t;items:(string,T.t)Hashtbl.t;}letindex()={tags=T.H.create0;items=Hashtbl.create0;}letmodule_name=String.capitalize_asciiT.namemoduleTYPE:Datatype.Swithtypet=index=Datatype.Make(structtypet=indexincludeDatatype.Undefinedletreprs=[index()]letname=Printf.sprintf"Server.Kernel_ast.%s.TYPE"module_nameletmem_project=Datatype.never_any_projectend)moduleSTATE=State_builder.Ref(TYPE)(structletname=Printf.sprintf"Server.Kernel_ast.%s.STATE"module_nameletdependencies=[Ast.self]letdefault=indexend)let()=Ast.add_monotonic_stateSTATE.selfletiterf=T.H.iter(funkeystr->f(key,str))(STATE.get()).tagslethooks=ref[]lethookf=hooks:=!hooks@[f]letindexitem=let{tags;items}=STATE.get()intryT.H.findtagsitemwithNot_found->lettag=T.createiteminT.H.addtagsitemtag;Hashtbl.additemstagitem;List.iter(funfn->fn(item,tag))!hooks;tagletfindtag=Hashtbl.find(STATE.get()).itemstagletjtype=Data.declare~package~name:T.name~descr:(Md.plainT.descr)(Pkg.JkeyT.name)letto_jsonitem=`String(indexitem)letof_jsonjs=tryfind(Js.to_stringjs)withNot_found->Data.failure"invalid %s (%a)"T.nameJson.pp_dumpjsendmoduleDecl=MakeTag(structopenPrinter_tagtypet=declarationletname="decl"letdescr="AST Declarations markers"moduleH=Declaration.Hashtblletkid=ref0letcreate=function|SEnum_->Printf.sprintf"#E%d"(incrkid;!kid)|SComp_->Printf.sprintf"#C%d"(incrkid;!kid)|SType_->Printf.sprintf"#T%d"(incrkid;!kid)|SGlobalvi->Printf.sprintf"#G%d"vi.vid|SFunctionkf->Printf.sprintf"#F%d"@@Kernel_function.get_idkf|SGAnnot_->Printf.sprintf"#A%d"(incrkid;!kid)end)moduleMarker=MakeTag(structopenPrinter_tagtypet=localizableletname="marker"letdescr="Localizable AST markers"moduleH=Localizable.Hashtblletkid=ref0letcreate=function|PStmt(_,s)->Printf.sprintf"#s%d"s.sid|PStmtStart(_,s)->Printf.sprintf"#k%d"s.sid|PVDecl(_,_,v)->Printf.sprintf"#v%d"v.vid|PLval_->Printf.sprintf"#l%d"(incrkid;!kid)|PExp(_,_,e)->Printf.sprintf"#e%d"e.eid|PTermLval_->Printf.sprintf"#t%d"(incrkid;!kid)|PGlobal_->Printf.sprintf"#g%d"(incrkid;!kid)|PIP_->Printf.sprintf"#p%d"(incrkid;!kid)|PType_->Printf.sprintf"#y%d"(incrkid;!kid)end)modulePrinterTag=Printer_tag.Make(structlettag=Marker.indexend)(* -------------------------------------------------------------------------- *)(* --- Ast Data --- *)(* -------------------------------------------------------------------------- *)moduleLval=structopenPrinter_tagtypet=kinstr*lvalletjtype=Marker.jtypeletto_json(kinstr,lval)=letkf=matchkinstrwith|Kglobal->None|Kstmtstmt->Some(Kernel_function.find_englobing_kfstmt)inMarker.to_json(PLval(kf,kinstr,lval))letfind=function|PLval(_,kinstr,lval)->kinstr,lval|PVDecl(_,kinstr,vi)->kinstr,Cil.varvi|PGlobal(GVar(vi,_,_)|GVarDecl(vi,_))->Kglobal,Cil.varvi|_->raiseNot_foundletmemtag=trylet_=findtagintruewithNot_found->falseletof_jsonjs=tryfind(Marker.of_jsonjs)withNot_found->Data.failure"not a lval marker"endmoduleStmt=structtypet=stmtletjtype=Marker.jtypeletto_jsonst=letkf=Kernel_function.find_englobing_kfstinMarker.to_json(PStmtStart(kf,st))letof_jsonjs=letopenPrinter_taginmatchMarker.of_jsonjswith|PStmt(_,st)|PStmtStart(_,st)->st|_->Data.failure"not a stmt marker"endmoduleKinstr=structtypet=kinstrletjtype=Pkg.JoptionMarker.jtypeletto_json=function|Kglobal->`Null|Kstmtst->Stmt.to_jsonstletof_json=function|`Null->Kglobal|js->Kstmt(Stmt.of_jsonjs)end(* -------------------------------------------------------------------------- *)(* --- Declaration Attributes --- *)(* -------------------------------------------------------------------------- *)moduleDeclKind=structopenPrinter_tagtypet=declarationletjtype=Data.declare~package~name:"declKind"~descr:(Md.plain"Declaration kind")(Junion[(* C *)Jkey"ENUM";Jkey"UNION";Jkey"STRUCT";Jkey"TYPEDEF";Jkey"GLOBAL";Jkey"FUNCTION";(* ACSL *)Jkey"LFUNPRED";Jkey"INVARIANT";Jkey"AXIOMATIC";Jkey"MODULE";Jkey"LEMMA";Jkey"EXTENSION";Jkey"VOLATILE";Jkey"LTYPE";Jkey"MODEL";])letglobal_annotation_kind=function|Dfun_or_pred_->"LFUNPRED"|Dinvariant_->"INVARIANT"|Dtype_annot_->"INVARIANT"|Daxiomatic_->"AXIOMATIC"|Dmodule_->"MODULE"|Dlemma_->"LEMMA"|Dextended_->"EXTENSION"|Dvolatile_->"VOLATILE"|Dtype_->"LTYPE"|Dmodel_annot_->"MODEL"letto_json=function|SEnum_->`String"ENUM"|SComp{cstruct=true}->`String"STRUCT"|SComp{cstruct=false}->`String"UNION"|SType_->`String"TYPEDEF"|SGlobal_->`String"GLOBAL"|SFunction_->`String"FUNCTION"|SGAnnota->`String(global_annotation_kinda)endmoduleGAnnotRoots=structincludeState_builder.Hashtbl(Cil_datatype.Global_annotation.Hashtbl)(Datatype.Unit)(structletname="Server.Kernel_ast.GAnnotsRoots"letsize=43letdependencies=[Ast.self]end)letis_rootga=memgaendmoduleDeclAttributes=structopenPrinter_tagletmodel=States.model()(* We must iterate over all known declaration in the Ast, contrarily to
markers, for which we only need attributes of already generated markers. *)letiter_declarationf=ifAst.is_computed()thenletmarked=Declaration.Hashtbl.create0inCil.iterGlobals(Ast.get())(fung->beginmatchgwith|GAnnot(ga,_)->GAnnotRoots.addga()|_->()end;matchdeclaration_of_globalgwith|None->()|Somed->ifnot@@Declaration.Hashtbl.memmarkeddthenbeginDeclaration.Hashtbl.addmarkedd();f(d,Decl.indexd)end)let()=States.column~name:"kind"~descr:(Md.plain"Declaration kind")~data:(moduleDeclKind)~get:fstmodellet()=States.column~name:"self"~descr:(Md.plain"Declaration's marker")~data:(moduleMarker)~get:(fun(decl,_)->localizable_of_declarationdecl)modellet()=States.column~name:"name"~descr:(Md.plain"Declaration identifier")~data:(moduleJstring)~get:(fun(decl,_)->name_of_declarationdecl)modellet()=States.column~name:"label"~descr:(Md.plain"Declaration label (uncapitalized kind & name)")~data:(moduleJstring)~get:(fun(decl,_)->Pretty_utils.to_stringpp_declarationdecl)modellet()=States.column~name:"source"~descr:(Md.plain"Source location")~data:(modulePosition)~get:(fun(decl,_)->fst@@loc_of_declarationdecl)modelletarray=States.register_array~package~name:"declAttributes"~descr:(Md.plain"Declaration attributes")~key:snd~keyName:"decl"~keyType:Decl.jtype~iter:iter_declaration~add_reload_hook:ast_update_hookmodelletupdate(d,s)=matchdwith|SGAnnotgawhennot@@GAnnotRoots.is_rootga->()|_->States.updatearray(d,s)let()=Decl.hookupdateend(* -------------------------------------------------------------------------- *)(* --- Decl Printer --- *)(* -------------------------------------------------------------------------- *)letwith_print_libcf=ifKernel.PrintLibc.get()thenf()elseletfinally=ifKernel.PrintLibc.is_set()thenfun()->Kernel.PrintLibc.unsafe_setfalseelsefun()->Kernel.PrintLibc.clear()inKernel.PrintLibc.unsafe_settrue;Fun.protect~finallyfletprint_global_astglobal=letprinter=PrinterTag.(with_unfold_precond(fun_->true)pp_global)inwith_print_libc(fun()->Jbuffer.to_jsonprinterglobal)let()=Request.register~package~kind:`GET~name:"printDeclaration"~descr:(Md.plain"Prints an AST Declaration")~signals:[ast_changed_signal]~input:(moduleDecl)~output:(moduleJtext)(fund->print_global_ast@@Printer_tag.global_of_declarationd)(* -------------------------------------------------------------------------- *)(* --- Marker Attributes --- *)(* -------------------------------------------------------------------------- *)moduleMarkerKind=structopenPrinter_tagtypet=localizableletjtype=Data.declare~package~name:"markerKind"~descr:(Md.plain"Marker kind")(Junion[Jkey"STMT";Jkey"LFUN";Jkey"DFUN";Jkey"LVAR";Jkey"DVAR";Jkey"LVAL";Jkey"EXP";Jkey"TERM";Jkey"TYPE";Jkey"PROPERTY";Jkey"DECLARATION";])letto_json=function|PStmt_|PStmtStart_->`String"STMT"|PVDecl(_,Kglobal,vi)->`String(ifGlobals.Functions.memvithen"DFUN"else"DVAR")|PVDecl_->`String"DVAR"|PTermLval(_,_,_,(TVar{lv_origin=Somevi},TNoOffset))|PLval(_,_,(Varvi,NoOffset))->`String(ifGlobals.Functions.memvithen"LFUN"else"LVAR")|PLval_->`String"LVAL"|PExp_->`String"EXP"|PTermLval_->`String"TERM"|PType_->`String"TYPE"|PIP_->`String"PROPERTY"|PGlobal_->`String"DECLARATION"endmoduleMarkerAttributes=structopenPrinter_tagletglobal_annotation_label_kindshort=function|Dfun_or_pred({l_type=None},_)->ifshortthen"Pred"else"Predicate"|Dfun_or_pred_->ifshortthen"LFun"else"Logic Function"|Dinvariant_->ifshortthen"Inv"else"Invariant"|Dtype_annot_->ifshortthen"TInv"else"Type Invariant"|Daxiomatic_->ifshortthen"Ax"else"Axiomatic"|Dmodule_->ifshortthen"Mod"else"Module"|Dlemma_->"Lemma"|Dextended_->ifshortthen"Ext"else"Extension"|Dvolatile_->ifshortthen"Vol"else"Volatile"|Dtype_->ifshortthen"LType"else"Logic Type"|Dmodel_annot_->"Model"letlabel_kind~shortm=matchvarinfo_of_localizablemwith|Somevi->ifGlobals.Functions.memvithen"Function"elseifvi.vglobthenifshortthen"Global"else"Global Variable"elseifvi.vformalthenifshortthen"Formal"else"Formal Parameter"elseifvi.vtempthenifshortthen"Temp"else"Temporary Variable (generated)"elseifshortthen"Local"else"Local Variable"|None->matchmwith|PStmt_|PStmtStart_->ifshortthen"Stmt"else"Statement"|PLval_->ifshortthen"Lval"else"L-value"|PTermLval_->ifshortthen"Lval"else"ACSL L-value"|PVDecl_->assertfalse|PExp_->ifshortthen"Expr"else"Expression"|PIP_->ifshortthen"Prop"else"Property"|PGlobal(GType_|GCompTag_|GEnumTag_|GEnumTagDecl_)|PType_->"Type"|PGlobal(GAnnot(ga,_))->global_annotation_label_kindshortga|PGlobal_->ifshortthen"Decl"else"Declaration"letdescr_localizablefmt=function|PGlobal(GType(ti,_))->PrinterTag.pp_typfmt(Cil_const.mk_tnamedti)|PGlobal(GCompTag(ci,_)|GCompTagDecl(ci,_))->PrinterTag.pp_typfmt(Cil_const.mk_tcompci)|PGlobal(GEnumTag(ei,_)|GEnumTagDecl(ei,_))->PrinterTag.pp_typfmt(Cil_const.mk_tenumei)|g->pp_localizablefmtgletmodel=States.model()let()=States.column~name:"kind"~descr:(Md.plain"Marker kind (key)")~data:(moduleMarkerKind)~get:fstmodellet()=States.option~name:"scope"~descr:(Md.plain"Marker Scope (where it is printed in)")~data:(moduleDecl)~get:(fun(tag,_)->declaration_of_localizabletag)modellet()=States.option~name:"definition"~descr:(Md.plain"Marker's Target Definition (when applicable)")~data:(moduleMarker)~get:(fun(tag,_)->definition_of_localizabletag)modellet()=States.column~name:"labelKind"~descr:(Md.plain"Marker kind label")~data:(moduleJalpha)~get:(fun(tag,_)->label_kind~short:truetag)modellet()=States.column~name:"titleKind"~descr:(Md.plain"Marker kind title")~data:(moduleJalpha)~get:(fun(tag,_)->label_kind~short:falsetag)modellet()=States.option~name:"name"~descr:(Md.plain"Marker identifier (when applicable)")~data:(moduleJalpha)~get:(fun(tag,_)->Printer_tag.name_of_localizabletag)modellet()=States.column~name:"descr"~descr:(Md.plain"Marker description")~data:(moduleJstring)~get:(fun(tag,_)->Rich_text.sprintf"%a"descr_localizabletag)modellet()=letget(tag,_)=letpos=fst(Printer_tag.loc_of_localizabletag)inifFilepos.is_emptyposthenNoneelseSomeposinStates.option~name:"sloc"~descr:(Md.plain"Source location")~data:(modulePosition)~getmodelletarray=States.register_array~package~name:"markerAttributes"~descr:(Md.plain"Marker attributes")~key:snd~keyName:"marker"~keyType:Marker.jtype~iter:Marker.iter~add_reload_hook:ast_update_hookmodellet()=Marker.hook(States.updatearray)end(* -------------------------------------------------------------------------- *)(* --- Filters --- *)(* -------------------------------------------------------------------------- *)(* Filters can be defined on elements of type ['a] with a unique name and
a boolean function f: 'a -> bool, allowing the user to show/hide elements
for which f is true or false.
Additional information for each filter includes:
- whether the filter is currently active;
- positive/negative labels shown to the user to show/hide elements
for which f is true/false respectively.
- default values for the filter, i.e. whether elements for which [f] is
true/false are shown or hidden by default.
*)letfilter_jtype=letjtype=Package.Jrecord["id",Jstring;(* Unique name. *)"enabled",Jboolean;(* Is the filter currently enabled? *)"positive_label",Jstring;(* Label for positive elements. *)"negative_label",Jstring;(* Label for negative elements. *)"positive_default",Jboolean;(* Are positive elements shown by default? *)"negative_default",Jboolean;(* Are negative elements shown by default? *)]inletdescr=Md.plain"Type of filters that can be applied to AST elements"inData.declare~package~name:"filter"~descrjtypemoduleMakeFilter(Info:sigtypetvalname:stringend)=structtypefilter={name:string;(* Unique identifiant of the filter *)enable:unit->bool;(* Is the filter currently enabled? *)value:Info.t->bool;(* Compute the filter value for an element *)labels:string*string;(* Positive and negative labels shown to the user *)default:bool*bool;(* Are positive/negative elements shown by default? *)}moduleFilter=structtypet=filterletjtype=filter_jtypeletto_jsonfilter=`Assoc["id",`Stringfilter.name;"enabled",`Bool(filter.enable());"positive_label",`String(fstfilter.labels);"negative_label",`String(sndfilter.labels);"positive_default",`Bool(fstfilter.default);"negative_default",`Bool(sndfilter.default);]letof_json_=Data.failure"Filter.of_json not implemented"end(* List of filters registered via [register] below. *)letfilters_ref:Filter.tlistref=ref[](* List of hooks registered via [register] below, used to refresh filter
requests whenever a filter changes. *)lethooks_ref:((unit->unit)->unit)listref=ref[](* Signal emitted whenever a filter changes. *)letsignal=letname=String.lowercase_asciiInfo.name^"Filters"inletdescr=Md.plain("Signal for "^Info.name^" filters")inRequest.signal~package~name~descr(* Default positive and negative labels for a filter of name [name]. *)letdefault_labelsname=letlower=String.lowercase_asciiinletpositive_label=lowername^" "^lowerInfo.nameinpositive_label,"non-"^positive_label(* Registers a new filter. *)letregistername?(labels=default_labelsname)?default?(enable=fun_->true)?add_hookf=letdefault=Option.folddefault~none:(true,true)~some:(funb->b,notb)inletfilter={name;enable;value=f;labels;default}infilters_ref:=filter::!filters_ref;Option.iter(funf->hooks_ref:=f::!hooks_ref)add_hook;Option.iter(funf->f(fun_->Request.emitsignal))add_hook;Request.emitsignal(* GET request listing all registered filters. *)let()=letname="get"^String.capitalize_asciiInfo.name^"Filters"inletdescr=Md.plain("List of filters for "^Info.name)inRequest.register~package~kind:`GET~name~descr~signals:[signal]~input:(moduleJunit)~output:(moduleJlist(Filter))(fun()->List.rev!filters_ref)(* Compute the value of each registered filter for an element [elt]. *)letcompute_filterselt=letauxaccfilter=iffilter.enable()then(filter.name,filter.valueelt)::accelseaccinList.fold_leftaux[]!filters_refletadd_hook(f:unit->unit)=List.iter(funadd_hook->add_hookf)!hooks_refend(* Filters on functions. *)moduleFctFilters=structincludeMakeFilter(structtypet=kernel_functionletname="functions"end)letget_vi=Kernel_function.get_vilet()=register"builtin"(funkf->Cil_builtins.has_fc_builtin_attr(get_vikf))~labels:("Frama-C builtins","source functions")~default:false;register"stdlib"Kernel_function.is_in_libc~default:false;register"defined"Kernel_function.is_definition~labels:("defined functions","undefined functions");register"extern"(funkf->(get_vikf).vstorage=Extern);register"ghost"Kernel_function.is_ghost;end(* Filters on variables. *)moduleVarFilters=structincludeMakeFilter(structtypet=varinfoletname="variables"end)let()=register"stdlib"((funvi->Cil.is_in_libcvi.vattr))~default:false;register"extern"(funvi->vi.vstorage=Extern);register"const"(funvi->Cil.isGlobalInitConstvi);register"volatile"(funvi->Ast_types.is_volatilevi.vtype);register"ghost"(funvi->Ast_types.is_ghostvi.vtype);register"init"(funvi->Option.is_some(Globals.Vars.findvi).init)~labels:("variables with explicit initializer","variables without explicit initializer");register"source"(funvi->vi.vsource)~default:true~labels:("variables from the source code","variables generated from analyses");endtype'afilter_registration=string->?labels:string*string->?default:bool->?enable:(unit->bool)->?add_hook:((unit->unit)->unit)->('a->bool)->unitletregister_fct_filter=FctFilters.registerletregister_var_filter=VarFilters.register(* -------------------------------------------------------------------------- *)(* --- Functions --- *)(* -------------------------------------------------------------------------- *)let()=Request.register~package~kind:`GET~name:"getMainFunction"~descr:(Md.plain"Get the current 'main' function.")~input:(moduleJunit)~output:(moduleJoption(Decl))beginfun()->trySome(SFunction(fst@@Globals.entry_point()))withGlobals.No_such_entry_point_->Noneendlet()=Request.register~package~kind:`GET~name:"getFunctions"~descr:(Md.plain"Collect all functions in the AST")~input:(moduleJunit)~output:(moduleJlist(Decl))beginfun()->letpool=ref[]inGlobals.Functions.iter(funkf->pool:=Printer_tag.SFunctionkf::!pool);List.rev!poolendmoduleFunctions=structletkeykf=Printf.sprintf"kf#%d"(Kernel_function.get_idkf)letsignaturekf=letg=Printer_tag.PGlobal(Kernel_function.get_globalkf)inletto_string()=Rich_text.sprintf"%a"Printer_tag.pp_localizableginlettxt=with_print_libcto_stringinifKernel_function.is_entry_pointkfthen(txt^" /* main */")elsetxtletis_builtinkf=Cil_builtins.has_fc_builtin_attr(Kernel_function.get_vikf)letis_externkf=letvi=Kernel_function.get_vikfinvi.vstorage=Externletiterf=Globals.Functions.iter(funkf->letname=Kernel_function.get_namekfinifnot(Ast_info.start_with_frama_c_builtinname)thenfkf)letarray:kernel_functionStates.array=beginletmodel=States.model()inStates.columnmodel~name:"decl"~descr:(Md.plain"Declaration Tag")~data:(moduleDecl)~get:(funkf->Printer_tag.SFunctionkf);States.columnmodel~name:"name"~descr:(Md.plain"Name")~data:(moduleData.Jalpha)~get:Kernel_function.get_name;States.columnmodel~name:"signature"~descr:(Md.plain"Signature")~data:(moduleData.Jstring)~get:signature;States.columnmodel~name:"main"~descr:(Md.plain"Is the function the main entry point")~data:(moduleData.Jbool)~default:false~get:Kernel_function.is_entry_point;States.columnmodel~name:"defined"~descr:(Md.plain"Is the function defined?")~data:(moduleData.Jbool)~default:false~get:Kernel_function.is_definition;States.columnmodel~name:"stdlib"~descr:(Md.plain"Is the function from the Frama-C stdlib?")~data:(moduleData.Jbool)~default:false~get:Kernel_function.is_in_libc;States.columnmodel~name:"builtin"~descr:(Md.plain"Is the function a Frama-C builtin?")~data:(moduleData.Jbool)~default:false~get:is_builtin;States.columnmodel~name:"extern"~descr:(Md.plain"Is the function extern?")~data:(moduleData.Jbool)~default:false~get:is_extern;States.columnmodel~name:"sloc"~descr:(Md.plain"Source location")~data:(modulePosition)~get:(funkf->fst(Kernel_function.get_locationkf));States.columnmodel~name:"filters"~descr:(Md.plain"List of filter values")~data:(moduleData.Jlist(Data.Jpair(Data.Jstring)(Data.Jbool)))~get:FctFilters.compute_filters;States.register_arraymodel~package~key~name:"functions"~descr:(Md.plain"AST Functions")~iter~add_reload_hook:(funf->ast_update_hookf;FctFilters.add_hookf)endend(* -------------------------------------------------------------------------- *)(* --- Global variables --- *)(* -------------------------------------------------------------------------- *)moduleGlobalVars=structletkeyvi=Printf.sprintf"vi#%d"vi.vidlet_:varinfoStates.array=letmodel=States.model()inStates.columnmodel~name:"decl"~descr:(Md.plain"Declaration Tag")~data:(moduleDecl)~get:(funvi->Printer_tag.SGlobalvi);States.columnmodel~name:"name"~descr:(Md.plain"Name")~data:(moduleData.Jalpha)~get:(funvi->vi.vname);States.columnmodel~name:"type"~descr:(Md.plain"Type")~data:(moduleJstring)~get:(funvi->Rich_text.sprintf"%a"PrinterTag.pp_typvi.vtype);States.columnmodel~name:"stringLiteral"~descr:(Md.plain"Does the variable represent a string literal?")~data:(moduleData.Jbool)~get:Ast_info.is_string_literal;States.columnmodel~name:"sloc"~descr:(Md.plain"Source location")~data:(modulePosition)~get:(funvi->fstvi.vdecl);States.columnmodel~name:"filters"~descr:(Md.plain"List of filter values")~data:(moduleData.Jlist(Data.Jpair(Data.Jstring)(Data.Jbool)))~get:VarFilters.compute_filters;States.register_arraymodel~package~key~name:"globals"~descr:(Md.plain"AST global variables")~iter:(funf->Globals.Vars.iter(funvi_init->fvi))~add_reload_hook:(funf->ast_update_hookf;VarFilters.add_hookf)end(* -------------------------------------------------------------------------- *)(* --- Marker Information --- *)(* -------------------------------------------------------------------------- *)moduleInformation=structtypeinfo={id:string;rank:int;label:string;(* short name *)title:string;(* full title name *)descr:string;(* description for information values *)enable:unit->bool;pretty:Format.formatter->Printer_tag.localizable->unit}(* Info markers serialization *)moduleS=structtypet=(info*Jtext.t)letjtype=Package.(Jrecord["id",Jstring;"label",Jstring;"title",Jstring;"descr",Jstring;"text",Jtext.jtype;])letof_json_=failwith"Information.Info"letto_json(info,text)=`Assoc["id",`Stringinfo.id;"label",`Stringinfo.label;"title",`Stringinfo.title;"descr",`Stringinfo.descr;"text",text;]end(* Info markers registry *)letrankId=ref0letregistry:(string,info)Hashtbl.t=Hashtbl.create0letjtextppmarker=tryletbuffer=Jbuffer.create()inletfmt=Jbuffer.formatterbufferinppfmtmarker;Format.pp_print_flushfmt();Jbuffer.contentsbufferwithNot_found->`Nullletrank({rank},_)=rankletby_rankab=Stdlib.compare(ranka)(rankb)letget_informationtgt=letinfos=ref[]inHashtbl.iter(fun_info->ifinfo.enable()thenmatchtgtwith|None->infos:=(info,`Null)::!infos|Somemarker->lettext=jtextinfo.prettymarkerinifnot(Jbuffer.is_emptytext)theninfos:=(info,text)::!infos)registry;List.sortby_rank!infosletsignal=Request.signal~package~name:"getInformationUpdate"~descr:(Md.plain"Updated AST information")letupdate()=Request.emitsignalletregister~id~label~title?(descr=title)?(enable=fun_->true)pretty=letrank=incrrankId;!rankIdinletinfo={id;rank;label;title;descr;enable;pretty}inifHashtbl.memregistryidthen(letmsg=Format.sprintf"Server.Kernel_ast.register_info: duplicate %S"idinraise(Invalid_argumentmsg));Hashtbl.addregistryidinfoendlet()=Request.register~package~kind:`GET~name:"getInformation"~descr:(Md.plain"Get available information about markers. \
When no marker is given, returns all kinds \
of information (with empty `descr` field).")~input:(moduleJoption(Marker))~output:(moduleJlist(Information.S))~signals:[Information.signal]Information.get_information(* -------------------------------------------------------------------------- *)(* --- Default Kernel Information --- *)(* -------------------------------------------------------------------------- *)let()=Information.register~id:"kernel.ast.location"~label:"Location"~title:"Source file location"beginfunfmtloc->letpos=fst@@Printer_tag.loc_of_localizablelocinifFilepath.is_empty(Filepos.pathpos)thenraiseNot_found;Filepos.prettyfmtposendlet()=Information.register~id:"kernel.ast.varinfo"~label:"Var"~title:"Variable Information"beginfunfmtloc->matchlocwith|PLval(_,_,(Varx,NoOffset))|PVDecl(_,_,x)->ifnotx.vreferencedthenFormat.pp_print_stringfmt"unused ";beginmatchx.vstoragewith|NoStorage->()|Extern->Format.pp_print_stringfmt"extern "|Static->Format.pp_print_stringfmt"static "|Register->Format.pp_print_stringfmt"register "end;ifx.vghostthenFormat.pp_print_stringfmt"ghost ";ifx.vaddrofthenFormat.pp_print_stringfmt"aliased ";ifx.vformalthenFormat.pp_print_stringfmt"formal"elseifx.vglobthenFormat.pp_print_stringfmt"global"elseifx.vtempthenFormat.pp_print_stringfmt"temporary"elseFormat.pp_print_stringfmt"local";|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.typeinfo"~label:"Type"~title:"Type of C/ACSL expression"beginfunfmtloc->matchlocwith|PExp(_,_,e)->PrinterTag.pp_typfmt(Cil.typeOfe)|PLval(_,_,lval)->PrinterTag.pp_typfmt(Cil.typeOfLvallval)|PVDecl(_,_,vi)->PrinterTag.pp_typfmtvi.vtype|PTermLval(_,_,_,tlval)->PrinterTag.pp_logic_typefmt(Cil.typeOfTermLvaltlval)|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.typedef"~label:"Typedef"~title:"Type Definition"beginfunfmtloc->matchlocwith|PType({tnode=TNamed_}asty)|PGlobal(GType({ttype=ty},_))->PrinterTag.pp_typfmt(Ast_types.unrollty)|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.typesizeof"~label:"Sizeof"~title:"Size of a C-type or C-variable"beginfunfmtloc->lettyp=matchlocwith|PTypetyp->typ|PVDecl(_,_,vi)whenAst_types.is_objectvi.vtype->vi.vtype|PGlobal(GType(ti,_))->ti.ttype|PGlobal(GCompTagDecl(ci,_)|GCompTag(ci,_))->Cil_const.mk_tcompci|PGlobal(GEnumTagDecl(ei,_)|GEnumTag(ei,_))->Cil_const.mk_tenumei|_->raiseNot_foundintryletbits=Cil.bitsSizeOftypinletbytes=bits/8inletrbits=bitsmod8inifrbits>0thenifbytes>0thenFormat.fprintffmt"%d bytes + %d bits"bytesrbitselseFormat.fprintffmt"%d bits"rbitselseFormat.fprintffmt"%d bytes"byteswithCil.SizeOfError(msg,_)->Format.fprintffmt"Unknown size: %s"msgendlet()=Information.register~id:"kernel.ast.alignof"~label:"Alignof"~title:"Alignment of a C type, variable or field"beginfunfmtloc->letprintkindalignofelt=tryFormat.fprintffmt"%d bytes (%s alignment)"(alignofelt)kindwithCil.SizeOfError(msg,_typ)->Format.fprintffmt"Unknown alignment: %s"msginmatchlocwith|PTypetyp|PGlobal(GType({ttype=typ},_))->print"type"Cil.bytesAlignOftyp|PVDecl(_,_,vi)|PLval(_,_,(Varvi,NoOffset))|PGlobal(GVarDecl(vi,_)|GVar(vi,_,_))whenAst_types.is_objectvi.vtype->print"variable"Cil.bytesAlignOfVarinfovi|PLval(_,_,lval)->beginmatchCil.lastOffset(sndlval)with|Field(fi,NoOffset)->print"field"Cil.bytesAlignOfFieldfi|_->raiseNot_foundend|PGlobal(GCompTagDecl(ci,_)|GCompTag(ci,_))->print"type"Cil.bytesAlignOf(Cil_const.mk_tcompci)|PGlobal(GEnumTagDecl(ei,_)|GEnumTag(ei,_))->print"type"Cil.bytesAlignOf(Cil_const.mk_tenumei)|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.propertyStatus"~label:"Status"~title:"Property Consolidated Status"beginfunfmtloc->matchlocwith|PIPpropwhenProperty.has_statusprop->Property_status.Feedback.prettyfmt@@Property_status.Feedback.getprop|_->raiseNot_foundendlet()=Information.register~id:"kernel.ast.marker"~label:"Marker"~title:"Ivette marker (for debugging)"~enable:(fun_->Server_parameters.debug_atleast1)beginfunfmtloc->lettag=Marker.indexlocinFormat.fprintffmt"%S"tagendlet()=Server_parameters.Debug.add_hook_on_update(fun_->Information.update())(* -------------------------------------------------------------------------- *)(* --- Marker at a position --- *)(* -------------------------------------------------------------------------- *)letget_marker_at~file~line~col=iffile=""thenNoneelseletpath=Filepath.of_stringfileinletpos=Filepos.make~path~line~column:col~offset:0()inPrinter_tag.pos_to_localizable~precise_col:trueposlet()=letdescr=Md.plain"Returns the marker and function at a source file position, if any. \
Input: file path, line and column. \
File can be empty, in case no marker is returned."inletsignature=Request.signature~output:(moduleJoption(Marker))()inletget_file=Request.paramsignature~name:"file"~descr:(Md.plain"File path")(moduleJstring)inletget_line=Request.paramsignature~name:"line"~descr:(Md.plain"Line (1-based)")(moduleJint)inletget_col=Request.paramsignature~name:"column"~descr:(Md.plain"Column (0-based)")(moduleJint)inRequest.register_sigsignature~package~descr~kind:`GET~name:"getMarkerAt"~signals:[ast_changed_signal](funrq()->get_marker_at~file:(get_filerq)~line:(get_linerq)~col:(get_colrq))(* -------------------------------------------------------------------------- *)(* --- Files --- *)(* -------------------------------------------------------------------------- *)letget_files()=letfiles=Kernel.Files.get()inList.map(funf->(Filepath.to_string_absf))fileslet()=Request.register~package~descr:(Md.plain"Get the currently analyzed source file names")~kind:`GET~name:"getFiles"~input:(moduleJunit)~output:(moduleJlist(Jstring))get_filesletset_filesfiles=lets=String.concat","filesinKernel.Files.As_string.setslet()=Request.register~package~descr:(Md.plain"Set the source file names to analyze.")~kind:`SET~name:"setFiles"~input:(moduleJlist(Jstring))~output:(moduleJunit)set_files(* -------------------------------------------------------------------------- *)(* --- Build a marker from an ACSL term --- *)(* -------------------------------------------------------------------------- *)letenvironment()=letopenLogic_typinginLenv.empty()|>append_pre_label|>append_here_labelletparse_exprenvkfstmtterm=letterm=Logic_parse_string.term~envkfterminletexp=Logic_to_c.term_to_expterminPrinter_tag.PExp(Somekf,Kstmtstmt,exp)letparse_lvalenvkfstmtterm=letterm=Logic_parse_string.term_lval~envkfterminletlval=Logic_to_c.term_lval_to_lvalterminPrinter_tag.PLval(Somekf,Kstmtstmt,lval)letbuild_markerparsemarkerterm=matchPrinter_tag.ki_of_localizablemarkerwith|Kglobal->Data.failure"No statement at selection point"|Kstmtstmt->letmoduleC=Logic_to_cinletmoduleParser=Logic_parse_stringinletkf()=Kernel_function.find_englobing_kfstmtintryparse(environment())(kf())stmttermwithNot_found|Parser.(Error_|Unbound_)|C.No_conversion->Data.failure"Invalid term"let()=letmoduleMd=Markdowninlets=Request.signature~output:(moduleMarker)()inletget_marker=Request.params~name:"stmt"~descr:(Md.plain"Marker position from where to localize the term")(moduleMarker)inletget_term=Request.params~name:"term"~descr:(Md.plain"ACSL term to parse")(moduleData.Jstring)inRequest.register_sig~packages~kind:`GET~name:"parseExpr"~descr:(Md.plain"Parse a C expression and returns the associated marker")(funrq()->build_markerparse_expr(get_markerrq)(get_termrq))let()=letmoduleMd=Markdowninlets=Request.signature~output:(moduleMarker)()inletget_marker=Request.params~name:"stmt"~descr:(Md.plain"Marker position from where to localize the term")(moduleMarker)inletget_term=Request.params~name:"term"~descr:(Md.plain"ACSL term to parse")(moduleData.Jstring)inRequest.register_sig~packages~kind:`GET~name:"parseLval"~descr:(Md.plain"Parse a C lvalue and returns the associated marker")(funrq()->build_markerparse_lval(get_markerrq)(get_termrq))(* -------------------------------------------------------------------------- *)