123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openServerletpackage=lettitle="Callstacks analyzed by Eva"inPackage.package~plugin:"eva"~name:"callstack"~title()moduleResults=Eva__Resultsletrecis_compatible_stackst1st2=matchst1,st2with|[],_|_,[]->true|(kf1,stmt1)::st1,(kf2,stmt2)::st2->Kernel_function.equalkf1kf2&&Cil_datatype.Stmt.equalstmt1stmt2&&is_compatible_stackst1st2(* Returns true if one callstack is prefix of the other. *)letis_compatible_callstackcs1cs2=letopenCallstackincs1.thread=cs2.thread&&Kernel_function.equalcs1.entry_pointcs2.entry_point&&is_compatible_stack(List.revcs1.stack)(List.revcs2.stack)letis_compatiblecallstackscs=List.exists(funcs'->is_compatible_callstackcscs')callstacksletcompatible_filter()=matchUpdate.CurrentCallstacks.get()with|[]->None|callstacks->Some(is_compatiblecallstacks)letcompare_call(kf1,stmt1)(kf2,stmt2)=letc=Int.comparestmt1.Cil_types.sidstmt2.Cil_types.sidinifc<>0thencelseKernel_function.comparekf1kf2letcompare_reversed_callstack(cs1:Callstack.t)(cs2:Callstack.t)=letc=Int.comparecs1.threadcs2.threadinifc<>0thencelseletc=Kernel_function.comparecs1.entry_pointcs2.entry_pointinifc<>0thencelseList.comparecompare_call(cs1.stack)(cs2.stack)letsort_callstackslist=letreverse_stackcs=Callstack.{cswithstack=List.revcs.stack}inList.mapreverse_stacklist|>List.fast_sortcompare_reversed_callstack|>List.mapreverse_stack(* -------------------------------------------------------------------------- *)(* ----- Callstack info ----- *)(* -------------------------------------------------------------------------- *)letfct_declkf=Kernel_ast.Decl.to_json(Printer_tag.SFunctionkf)moduleJCallsite=structtypet=Callstack.callletjtype=Server.Data.declare~package~name:"callsite"~descr:(Markdown.plain"Call site infos")(Jrecord["caller",Kernel_ast.Decl.jtype;"callee",Kernel_ast.Decl.jtype;"stmt",Kernel_ast.Stmt.jtype;"rank",Jnumber;])letto_json'~caller(callee,stmt)=`Assoc["caller",fct_declcaller;"callee",fct_declcallee;"stmt",Kernel_ast.Stmt.to_jsonstmt;"rank",Data.Jint.to_jsonstmt.sid;]letto_json(callee,stmt)=letcaller=Kernel_function.find_englobing_kfstmtinto_json'~caller(callee,stmt)letof_json_=Data.failure"JCallsite.of_json not implemented"endmoduleJStack=structletjtype=Package.(JarrayJCallsite.jtype)letto_json~entry_pointstack=letaux(acc,caller)(callee,stmt)=JCallsite.to_json'~caller(callee,stmt)::acc,calleeinletl,_last_callee=List.fold_leftaux([],entry_point)stackin`ListlendmoduleJCallstackData=structtypet=Callstack.tletjtype=Server.Data.declare~package~name:"callstackInfo"~descr:(Markdown.plain"Callstack infos")(Jrecord["thread",Jstring;"entryPoint",Kernel_ast.Decl.jtype;"stack",JStack.jtype;"analyzed",Jboolean;])letthread_labelid=matchThread.findidwith|Somethread->Thread.labelthread|None->string_of_intidletanalyzedcallstack=letkf=Callstack.top_kfcallstackinmatchAnalysis.statuskfwith|Analyzed_->not(Kernel_function.is_in_libckf)|Unreachable|SpecUsed|Builtin_->falseletto_json(cs:t)=letentry_point=cs.entry_pointin`Assoc["thread",Data.Jstring.to_json(thread_labelcs.thread);"entryPoint",fct_declentry_point;"stack",JStack.to_json~entry_point(List.revcs.stack);"analyzed",Data.Jbool.to_json(analyzedcs);]end(* -------------------------------------------------------------------------- *)(* ----- Requests ----- *)(* -------------------------------------------------------------------------- *)moduleJCallstack:Data.Swithtypet=Callstack.t=Data.Index(Callstack.Map)(structletpackage=packageletname="callstack"letdescr=Markdown.plain"Callstack identifier"end)let()=Request.register~package~kind:`GET~name:"getCallstackInfo"~descr:(Markdown.plain"Callstack Description")~signals:[Update.computation_signal]~input:(moduleJCallstack)~output:(moduleJCallstackData)(funcs->cs)(* Registers a request returning a sorted list of callstacks. *)letregister_list_request~descrf=Request.register~package~kind:`GET~descr:(Markdown.plaindescr)~signals:[Update.computation_signal]~output:(moduleData.Jlist(JCallstack))(funelt->felt|>sort_callstacks)letall_callstacks()=letauxkfacc=ifResults.is_calledkfthenResults.(at_start_ofkf|>callstacks)@accelseaccinGlobals.Functions.foldaux[]let()=register_list_request~name:"getAllCallstacks"~descr:"Returns the list of all callstacks analyzed"~input:(moduleData.Junit)all_callstacksletfct_callstacks=function|Printer_tag.SFunctionkf->Results.(at_start_ofkf|>callstacks)|_->[]let()=register_list_request~name:"getFunctionCallstacks"~descr:"Returns the list of all callstacks analyzed for a given function"~input:(moduleKernel_ast.Decl)fct_callstacksletmarker_callstacksmarker=matchPrinter_tag.ki_of_localizablemarkerwith|Kstmtstmt->Results.(beforestmt|>callstacks)|Kglobal->matchPrinter_tag.kf_of_localizablemarkerwith|Somekf->Results.(at_start_ofkf|>callstacks)|None->[]letmarkers_callstacksmarkers=letauxaccmarker=marker_callstacksmarker|>Callstack.Set.of_list|>Callstack.Set.unionaccinletcallstack_set=List.fold_leftauxCallstack.Set.emptymarkersinletcallstack_list=Callstack.Set.elementscallstack_setinmatchcompatible_filter()with|None->callstack_list|Somefilter->List.filterfiltercallstack_listlet()=register_list_request~name:"getMarkersCallstacks"~descr:"Return the list of analyzed callstacks for the selected markers, \
filtered by the selected callstacks."~input:(moduleData.Jlist(Kernel_ast.Marker))markers_callstacks(* -------------------------------------------------------------------------- *)(* ----- Current callstacks ----- *)(* -------------------------------------------------------------------------- *)let_current_callstack_signal=States.register_framac_state~package~name:"currentCallstacks"~descr:(Markdown.plain"List of the currently selected callstacks, if any")~data:(Data.jlist(moduleJCallstack))(moduleUpdate.CurrentCallstacks)