123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: 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, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program 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. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(** Hook for displaying progress of the analysis *)openMopsaopenFormatopenAstmoduleHook=struct(** {2 Hook header} *)(** *************** *)letname="progress"(** {2 Entries of the progress table} *)(** ********************************* *)(** Set of location ranges *)moduleRangeSet=SetExt.Make(structtypet=rangeletcompare=compare_rangeend)(** Entry of the progression table *)typeentry={name:string;(** Name of the function *)mutablerange:rangeoption;(** Location of the currently analyzed statement *)all_stmt_range_set:RangeSet.t;(** Location of all statements in the function body *)mutableanalyzed_stmt_range_set:RangeSet.t;(** Locations of analyzed statements *)nb_all_stmt:int;(** Total number of statements *)mutablenb_analyzed_stmt:int;(** Number of analyzed statements *)}(** Print an entry of the progress table *)letpp_entryfmte=matche.rangewith|None->fprintffmt"%s %d%%"e.name(100*e.nb_analyzed_stmt/e.nb_all_stmt)|Somer->letpos=get_range_startrinfprintffmt"%s:%d %d%%"e.namepos.pos_line(100*e.nb_analyzed_stmt/e.nb_all_stmt)(** {2 Utilities for moving the terminam cursor} *)(** ******************************************** *)(** Clear the current line and move the cursor at its beginning *)letclear_line()=printf"\027[2K\r@?"(** Move the cursor one line above *)letup_line()=printf"\027[1A@?"(** {2 Progression table} *)(** ********************* *)(** Progression table as a stack of entries *)lettable:entryStack.t=Stack.create()(** Return the set of statements in the body of a function *)letget_function_statementsf=Visitor.fold_stmt(funacce->VisitPartsacc)(funaccs->matchskindswith|S_block_->VisitPartsacc|_->VisitParts(RangeSet.adds.srangeacc))RangeSet.emptyf.fun_body(** Insert a new entry in the progress table *)letbefore_callf=letall_stmt_range_set=get_function_statementsfinletentry={name=f.fun_orig_name;range=None;all_stmt_range_set;analyzed_stmt_range_set=RangeSet.empty;nb_all_stmt=RangeSet.cardinalall_stmt_range_set;nb_analyzed_stmt=0;}inStack.pushentrytable;printf"@.%a@?"pp_entryentry(** Remove the head function from the progress table *)letafter_call()=let_=Stack.poptablein(* Clear the current line (displaying the progress of the removed entry)
and move the cursor to the line before.
*)clear_line();ifStack.is_emptytablethen()else(up_line();clear_line();printf"%a@?"pp_entry(Stack.toptable))(** Update the progress table before a statement is analyzed *)letbefore_stmtrange=ifStack.is_emptytablethen()else(letentry=Stack.toptableinifnot@@RangeSet.memrangeentry.all_stmt_range_setthen()else(entry.range<-Somerange;clear_line();printf"%a@?"pp_entryentry))(** Update the progress table after a statement is analyzed *)letafter_stmtrange=ifStack.is_emptytablethen()else(letentry=Stack.toptableinifnot@@RangeSet.memrangeentry.all_stmt_range_setthen()elseifRangeSet.memrangeentry.analyzed_stmt_range_setthen()else(entry.analyzed_stmt_range_set<-RangeSet.addrangeentry.analyzed_stmt_range_set;entry.nb_analyzed_stmt<-entry.nb_analyzed_stmt+1;clear_line();printf"%a@?"pp_entryentry))(** {2 Initialization} *)(** ****************** *)letinitctx=()(** {2 Events handlers} *)(** ******************* *)leton_before_execroutestmtmanflow=before_stmtstmt.srangeleton_after_execroutestmtmanflowpost=after_stmtstmt.srangeleton_before_evalroutesemanticexpmanflow=matchekindexpwith|E_call({ekind=E_function(User_definedf)},args)->before_callf|_->()leton_after_evalroutesemanticexpmanflowevl=matchekindexpwith|E_call({ekind=E_function(User_definedf)},args)->after_call()|_->()leton_finishmanflow=()endlet()=Core.Hook.register_stateless_hook(moduleHook)