123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)openPrinter_tagopenCil_typesopenCil_datatypeletupdate_column=ref(fun_->())letadd_tagbuffer(name,tag_prop)startstop=lettag=Gtk_helper.make_tagbuffer~nametag_propinGtk_helper.apply_tagbuffertagstartstopletscope_start_tag=("startscope",[`UNDERLINE`DOUBLE])letzones_used_tag=("zones",[`BACKGROUND"#FFeeCC"])letshow_def_direct_tag=("show_def",[`BACKGROUND"#FFca63"])letshow_def_indirect_tag=("show_def_indirect",[`BACKGROUND"#FFdb74"])letscope_b_tag=("b_scope",[`BACKGROUND"#CCFFff"])letscope_fb_tag=("fb_scope",[`BACKGROUND"#CCFFee"])letscope_f_tag=("f_scope",[`BACKGROUND"#CCFFbb"])letscope_p_tag=("p_scope",[`BACKGROUND"#FFFFab"])letscope_p_warn_tag=("p_warn_scope",[`BACKGROUND"#D5FFAb"])letempty_tag=("",[])letadd_msg(main_ui:Design.main_window_extension_points)txt=main_ui#pretty_information"%s@."txtletpretty_zonefmtz=Format.fprintffmt"@[<h 1>%a@]"Locations.Zone.prettyzletask_for_lval(main_ui:Design.main_window_extension_points)kf=lettxt=Gtk_helper.input_string~parent:main_ui#main_window~title:"Input lvalue expression"""inmatchtxtwithNone|Some""->None|Sometxt->tryletterm_lval=Logic_parse_string.term_lvalkftxtinletlval=Logic_to_c.term_lval_to_lvalterm_lvalinSome(txt,lval)withe->main_ui#error"[ask for lval] '%s' invalid expression: %s@."txt(Printexc.to_stringe);Noneletget_annot_optlocalizable=matchlocalizablewith|PIP(Property.(IPCodeAnnot{ica_ca}))->Someica_ca|_->None(** [kf_opt] is used if we want to ask the lval to the user in a popup *)letget_lval_optmain_uikf_optlocalizable=matchlocalizablewith|PLval(Some_kf,(Kstmt_stmt),lv)->letlv_txt=Format.asprintf"%a"Printer.pp_lvallvinSome(lv_txt,lv)|PTermLval(Some_kf,Kstmt_stmt,_,tlv)->begintryletlv=Logic_to_c.term_lval_to_lvaltlvinletlv_txt=Format.asprintf"%a"Printer.pp_term_lvaltlvinSome(lv_txt,lv)withInvalid_argument_->Noneend|_->(matchkf_optwithNone->None|Somekf->match(ask_for_lvalmain_uikf)withNone->None|Some(lv_txt,lv)->Some(lv_txt,lv))leteval_lval=lettyp_lval_to_zone_gui=Datatype.func2Stmt.tyLval.tyLocations.Zone.tyinDynamic.get~plugin:"Value""lval_to_zone_gui"typ_lval_to_zone_guimoduleKf_containing_highlighted_stmt=Kernel_function.Make_Table(Datatype.String.Set)(structletname="Dpds_gui.Kf_containing_highlighted_stmt"letsize=7letdependencies=[(*Dependencies are managed manually by Make_StmtSetState*)]end)letdefault_icon_name="gtk-apply"letdefault_icon=Datatype.String.Set.singletondefault_icon_namemoduleMake_StmtSetState(Info:sigvalname:stringend)=structincludeState_builder.Ref(Stmt.Hptset)(structletname=Info.nameletdependencies=[Eva.Analysis.self]letdefault()=Stmt.Hptset.emptyend)letsets=sets;Kf_containing_highlighted_stmt.clear();Stmt.Hptset.iter(funstmt->Kf_containing_highlighted_stmt.replace(Kernel_function.find_englobing_kfstmt)default_icon)s;!update_column`ContentsendmoduleMake_StmtMapState(Info:sigvalname:stringend)=structmoduleD=DatatypeincludeState_builder.Ref(Stmt.Map.Make(Datatype.String.Set))(structletname=Info.nameletdependencies=[Eva.Analysis.self]letdefault()=Stmt.Map.emptyend)letsets=sets;Kf_containing_highlighted_stmt.clear();Stmt.Map.iter(funstmts->letkf=Kernel_function.find_englobing_kfstmtinletprev=tryKf_containing_highlighted_stmt.findkfwithNot_found->D.String.Set.emptyinletunion=D.String.Set.unionprevsinKf_containing_highlighted_stmt.replacekfunion)s;!update_column`ContentsendmoduletypeDpdCmdSig=sigtypet_invalhelp:stringval_get_info:(Kernel_function.t*Cil_types.stmt)option->stringvalcompute:Kernel_function.t->Cil_types.stmt->t_in->stringvaltag_stmt:Cil_types.stmt->(string*GText.tag_propertylist)valclear:unit->unitendmoduleDataScope:(DpdCmdSigwithtypet_in=lval)=structtypet_in=lvalmoduleFscope=Make_StmtSetState(structletname="Dpds_gui.Highlighter.Fscope"end)moduleFBscope=Make_StmtSetState(structletname="Dpds_gui.Highlighter.FBscope"end)moduleBscope=Make_StmtSetState(structletname="Dpds_gui.Highlighter.Bscope"end)letclear()=Fscope.clear();FBscope.clear();Bscope.clear()lethelp=("[data_scope] "^"highlight the statements where the value of D is the same "^"than at its value at L.\n\t"^"For more information, please look at the Scope plugin documentation.")let_get_info_kf_stmt_opt=ifStmt.Hptset.is_empty(Fscope.get())&&Stmt.Hptset.is_empty(FBscope.get())&&Stmt.Hptset.is_empty(Bscope.get())then""else"[scope] selected"letcomputekfstmtlval=letf,(fb,b)=Datascope.get_data_scope_at_stmtkfstmtlvalinFscope.setf;FBscope.setfb;Bscope.setb;"[scope] computed"lettag_stmtstmt=ifStmt.Hptset.memstmt(Fscope.get())thenscope_f_tagelseifStmt.Hptset.memstmt(FBscope.get())thenscope_fb_tagelseifStmt.Hptset.memstmt(Bscope.get())thenscope_b_tagelseempty_tagendmodulePscope(* : (DpdCmdSig with type t_in = code_annotation) *)=structmodulePscope=Make_StmtSetState(structletname="Dpds_gui.Highlighter.Pscope"end)modulePscope_warn=State_builder.List_ref(Code_annotation)(structletname="Dpds_gui.Highlighter.Pscope_warn"letdependencies=[Eva.Analysis.self]end)letclear()=Pscope.clear();Pscope_warn.clear()lethelp=("[prop_scope] "^"highlight the statements where the value of the assertion is also ok\n\t"^"For more information, please look at the Scope plugin documentation.")let_get_info_kf_stmt_opt=ifStmt.Hptset.is_empty(Pscope.get())then""else"[prop_scope] selected"letcomputekfstmtannot=lets1,s2=Datascope.get_prop_scope_at_stmtkfstmtannotinPscope.sets1;Pscope_warn.sets2;"[prop_scope] computed"lettag_stmtstmt=(*if Stmt.Hptset.mem stmt (Pscope_warn.get()) then scope_p_warn_tag
else*)ifStmt.Hptset.memstmt(Pscope.get())thenscope_p_tagelseempty_taglettag_annotannot=lettag=List.exists(funa->a.annot_id=annot.annot_id)(Pscope_warn.get())iniftagthenscope_p_warn_tagelseempty_tagendmoduleShowDef:(DpdCmdSigwithtypet_in=lval)=structtypet_in=lvalmoduleShowDefState=Make_StmtMapState(structletname="Dpds_gui.Highlighter.ShowDef"end)letclear()=ShowDefState.clear()lethelp=("[show_def] "^"highlight the statements that define the value of D at L,\n\t"^"and print a message if a part of D might be undefined.\n\t"^"Notice that 'undefined' only means here "^"not defined on some path from the beginning of the function.")let_get_info_kf_stmt_opt=ifStmt.Map.is_empty(ShowDefState.get())then""else"[show_def] selected"letindirect_icon=Datatype.String.Set.singleton"gtk-jump-to"letconvm=letauxstmt(direct,indirect)acc=letempty=Datatype.String.Set.emptyinletdirect=ifdirectthendefault_iconelseemptyinletindirect=ifindirectthenindirect_iconelseemptyinlets=Datatype.String.Set.uniondirectindirectinifDatatype.String.Set.is_emptysthenaccelseStmt.Map.addstmtsaccinStmt.Map.foldauxmStmt.Map.emptyletcomputekfstmtlv=letz=eval_lvalstmtlvinletr=Defs.compute_with_def_type_zonekfstmtzinDatascope.R.feedback"Defs computed";matchrwith|None->clear();"[Show Defs] nothing found. The information about some functions \
may be missing."|Some(defs,undef)->letmsg=matchundefwith|None->""|Someundef->Format.asprintf"[Show Defs] notice that %a %s"pretty_zoneundef"may not be defined by this function at this point"inShowDefState.set(convdefs);msglettag_stmtstmt=trylets=Stmt.Map.findstmt(ShowDefState.get())inifDatatype.String.Set.memdefault_icon_namesthenshow_def_direct_tagelseshow_def_indirect_tagwithNot_found->empty_tagendmoduleZones:(DpdCmdSigwithtypet_in=lval)=structtypet_in=lvalmoduleZonesState=structincludeState_builder.Option_ref(Datatype.Pair(Stmt.Hashtbl.Make(Locations.Zone))(Stmt.Hptset))(structletname="Dpds_gui.Highlighter.ZonesState"letdependencies=[Eva.Analysis.self]end)letsets=sets;Kf_containing_highlighted_stmt.clear();Stmt.Hptset.iter(funstmt->Kf_containing_highlighted_stmt.replace(Kernel_function.find_englobing_kfstmt)default_icon)(snds);!update_column`Contentsendletclear()=ZonesState.clear()lethelp=("[zones] computes, for each point Li of the function, "^"the data Di needed to know the value of D at L.\n"^"\tAfter this computation, the result Di will be printed in the "^" information window each time a statement Li is selected.")let_get_infokf_stmt_opt=tryletzones,_=ZonesState.get()inmatchkf_stmt_optwith|None->"[zones] no information for this point"|Some(_kf,stmt)->letz=Zones.get_zoneszonesstmtinlettxt=Format.asprintf"[zones] needed before stmt %d = %a"stmt.sidpretty_zonezintxtwithNot_found->""letcomputekfstmtlval=letused_stmts,zones=Zones.build_zoneskfstmtlvalinZonesState.set(zones,used_stmts);"[zones] computed"lettag_stmtstmt=letis_used=trylet_zones,used=ZonesState.get()inStmt.Hptset.memstmtusedwithNot_found->falseinifis_usedthenzones_used_tagelseempty_tagendlethelp(main_ui:Design.main_window_extension_points)=letaddtxt=add_msgmain_uitxtinadd("General : "^"each of these commands starts from a data D at a program point L.\n\t"^"The program point is the one that is before the selected statement,\n\t"^"and the data is the one that is selected if any, "^"or it can be given via a popup.\n"^"\tIf the text given in the popup is empty, or 'Cancel' is chosen, "^"the selection of the command is reset.");add(ShowDef.help);add(Zones.help);add(DataScope.help);add(Pscope.help);add("Reset : reset the internal state for all the previous commands.")moduleDpdsState=State_builder.Option_ref(Stmt)(structletname="Dpds_gui.Highlighter.DpdsState"letdependencies=[Eva.Analysis.self]end)letreset()=DpdsState.clear();ShowDef.clear();Zones.clear();DataScope.clear();Pscope.clear();Kf_containing_highlighted_stmt.clear();!update_column`Contents(* Functions available in the contextual menu. One function disables the
others *)typefunct=Defs|Zones|Scope|Pscopeletcallbacksfunctmain_ui(kf,stmt,localizable)=(* The messages printed here are (1) not really informative; (2) too short
lived: after the 'information' panel has been cleared, they are never
printed again. (And if the filetree filter is active, they are cleared just
after having been written.) Because of (1), no effort has been made to
correct (2). *)letcomputefarg=letmsg=fkfstmtarginifmsg<>""thenadd_msgmain_uimsginletset_txtx=lettxt=Format.asprintf"[dependencies] for %s before stmt %d in %a"xstmt.sidKernel_function.prettykfinDpdsState.setstmt;add_msgmain_uitxtinletaux_on_lvalfunct_compute=matchget_lval_optmain_ui(Somekf)localizablewith|None->()|Some(lval_txt,lval)->set_txtlval_txt;computefunct_computelvalinreset();beginmatchfunctwith|Pscope->beginmatchget_annot_optlocalizablewith|Some({annot_content=(AAssert_)}asannot)->set_txt("annotation "^(string_of_intannot.annot_id));computePscope.computeannot|_->()end|Defs->aux_on_lvalShowDef.compute|Zones->aux_on_lvalZones.compute|Scope->aux_on_lvalDataScope.computeend;main_ui#rehighlight()lethighlighter(buffer:Design.reactive_buffer)localizable~start~stop=tryletbuffer=buffer#bufferinletstart_s=DpdsState.get()inletput_tagtag=matchtagwith("",[])->()|_->add_tagbuffertagstartstopinmatchlocalizablewith|PStmt(_,stmt)->ifstart_s.sid=stmt.sidthenput_tagscope_start_tag;put_tag(Pscope.tag_stmtstmt);put_tag(DataScope.tag_stmtstmt);put_tag(Zones.tag_stmtstmt);put_tag(ShowDef.tag_stmtstmt)|PIP(Property.(IPCodeAnnot{ica_ca}))->put_tag(Pscope.tag_annotica_ca)|PStmtStart_|PExp_|PVDecl_|PTermLval_|PLval_|PGlobal_|PIP_|PType_->()withNot_found->()letcheck_value(main_ui:Design.main_window_extension_points)=ifEva.Analysis.is_computed()thentrueelseletanswer=GToolbox.question_box~title:("Eva Needed")~buttons:["Run";"Cancel"]("Eva has to be run first.\nThis can take some time.\n"^"Do you want to run Eva with its current settings now?")inifanswer=1thenmatchmain_ui#full_protect~cancelable:trueEva.Analysis.computewith|Some_->main_ui#redisplay();(* New alarms *)true|None->falseelsefalse(** To add a sensitive/insensitive menu item to a [factory].
* The menu item is insensitive when [arg_opt = None],
* else, when the item is selected, the callback is called with the argument.
* If [~use_values], check if the value analysis has been computed.
*)letadd_item(main_ui:Design.main_window_extension_points)~use_values(factory:GMenu.menuGMenu.factory)namearg_optcallback=matcharg_optwith|None->(* add the menu item, but it isn't sensitive *)letitem=factory#add_itemname~callback:(fun()->())initem#misc#set_sensitivefalse|Somearg->(* add the menu item with its callback *)letcbarg=ifuse_valuesthenifcheck_valuemain_uithencallbackargelse()elsecallbackarginignore(factory#add_itemname~callback:(fun()->cbarg))letselector(popup_factory:GMenu.menuGMenu.factory)(main_ui:Design.main_window_extension_points)~buttonlocalizable=ifbutton=3thenbeginletsubmenu=popup_factory#add_submenu"Dependencies"inletsubmenu_factory=newGMenu.factorysubmenuinletarg=match(Pretty_source.kf_of_localizablelocalizable,Pretty_source.ki_of_localizablelocalizable)with|Somekf,Kstmtst->Some(kf,st,localizable)|Some_,Kglobal|None,_->Noneinletadd_zones_itemnamefunct=add_itemmain_ui~use_values:truesubmenu_factorynamearg(funarg->main_ui#protect~cancelable:true(fun()->callbacksfunctmain_uiarg))inadd_zones_item"Show defs"Defs;add_zones_item"Zones"Zones;add_zones_item"DataScope"Scope;add_zones_item"PropScope"Pscope;ignore(submenu_factory#add_separator());add_itemmain_ui~use_values:falsesubmenu_factory"Reset All"(Some())(fun_->reset();main_ui#rehighlight());ignore(submenu_factory#add_separator());add_itemmain_ui~use_values:falsesubmenu_factory"Help"(Some())(fun_->helpmain_ui);endletfiletree_decoratemain_ui=main_ui#file_tree#append_pixbuf_column~title:"Scope"(funglobs->leticons=function|GFun({svar=v},_)->(tryKf_containing_highlighted_stmt.find(Globals.Functions.getv)withNot_found->Datatype.String.Set.empty)|_->Datatype.String.Set.emptyinletids=ifKf_containing_highlighted_stmt.length()<>0thenleticons=List.fold_left(funaccglob->Datatype.String.Set.union(iconsglob)acc)Datatype.String.Set.emptyglobsinifDatatype.String.Set.is_emptyiconsthenDatatype.String.Set.singleton""elseiconselseDatatype.String.Set.singleton""inleticons=ifDatatype.String.Set.memdefault_icon_nameidsthen[default_icon_name]elseDatatype.String.Set.elements(Datatype.String.Set.removedefault_icon_nameids)inList.map(funicon->`STOCK_IDicon)icons)(fun_->Kf_containing_highlighted_stmt.length()<>0)letmainmain_ui=main_ui#register_source_selectorselector;main_ui#register_source_highlighterhighlighter;update_column:=(filetree_decoratemain_ui)let()=Design.register_extensionmain