5757
5858(* * MCP Server state *)
5959type t = {
60- server : Server .t ;
60+ mutable file : Cil .file option ;
61+ mutable max_ids : MaxIdUtil .max_ids ;
6162 mutable analyzed : bool ;
63+ arg_wrapper : (module Server .ArgWrapper ) ResettableLazy .t ;
64+ invariant_parser : WitnessUtil.InvariantParser .t ResettableLazy .t ;
65+ node_locator : WitnessUtil .Locator (Node ).t ResettableLazy .t ;
6266}
6367
68+ (* * Is node valid for lookup by location? *)
69+ let is_server_node cfgnode =
70+ let loc = UpdateCil. getLoc cfgnode in
71+ not loc.synthetic
72+
6473let make () : t =
65- (* Create server with stdin/stdout streams *)
66- let server = Server. make None in
74+ (* Create arg_wrapper lazily *)
75+ let arg_wrapper = ResettableLazy. from_fun (fun () ->
76+ let module Arg = (val (Option. get_exn ! ArgTools. current_arg (Failure " not analyzed or arg disabled" ))) in
77+ let module Locator = WitnessUtil. Locator (Arg. Node ) in
78+ let module StringH = Hashtbl. Make (Printable. Strings ) in
79+
80+ let locator = Locator. create () in
81+ let ids = StringH. create 113 in
82+ let cfg_nodes = StringH. create 113 in
83+ Arg. iter_nodes (fun n ->
84+ let cfgnode = Arg.Node. cfgnode n in
85+ let loc = UpdateCil. getLoc cfgnode in
86+ if is_server_node cfgnode then
87+ Locator. add locator loc n;
88+ StringH. replace ids (Arg.Node. to_string n) n;
89+ StringH. add cfg_nodes (Node. show_id cfgnode) n
90+ );
91+
92+ let module ArgWrapper =
93+ struct
94+ module Arg = Arg
95+ module Locator = Locator
96+ let locator = locator
97+ let find_node = StringH. find ids
98+ let find_cfg_node = StringH. find_all cfg_nodes
99+ end
100+ in
101+ (module ArgWrapper : Server.ArgWrapper )
102+ )
103+ in
104+
105+ (* Create invariant_parser lazily *)
106+ let invariant_parser = ResettableLazy. from_fun (fun () ->
107+ WitnessUtil.InvariantParser. create ! Cilfacade. current_file
108+ )
109+ in
110+
111+ (* Create node_locator lazily *)
112+ let node_locator = ResettableLazy. from_fun (fun () ->
113+ let module Cfg = (val ! MyCFG. current_cfg) in
114+ let module Locator = WitnessUtil. Locator (Node ) in
115+ let locator = Locator. create () in
116+
117+ (* DFS, copied from CfgTools.find_backwards_reachable *)
118+ let module NH = MyCFG. NodeH in
119+ let reachable = NH. create 100 in
120+ let rec iter_node node =
121+ if not (NH. mem reachable node) then begin
122+ NH. replace reachable node () ;
123+ let loc = UpdateCil. getLoc node in
124+ if is_server_node node then
125+ Locator. add locator loc node;
126+ List. iter (fun (_ , prev_node ) ->
127+ iter_node prev_node
128+ ) (Cfg. prev node)
129+ end
130+ in
131+
132+ Cil. iterGlobals ! Cilfacade. current_file (function
133+ | GFun (fd , _ ) ->
134+ let return_node = Node. Function fd in
135+ iter_node return_node
136+ | _ -> ()
137+ );
138+
139+ locator
140+ )
141+ in
142+
67143 {
68- server;
144+ file = None ;
145+ max_ids = MaxIdUtil. get_file_max_ids Cil. dummyFile;
69146 analyzed = false ;
147+ arg_wrapper;
148+ invariant_parser;
149+ node_locator;
70150 }
71151
152+ (* * Analyze the configured files directly *)
153+ let analyze ?(reset =false ) (mcp_serv : t ) =
154+ Messages.Table. (MH. clear messages_table);
155+ Messages. (Table.MH. clear final_table);
156+ Messages.Table. messages_list := [] ;
157+
158+ (* Preprocess and parse files *)
159+ GoblintDir. init () ;
160+ let file = Fun. protect ~finally: GoblintDir. finalize Maingoblint. preprocess_parse_merge in
161+
162+ if reset then (
163+ let max_ids = MaxIdUtil. get_file_max_ids file in
164+ mcp_serv.max_ids < - max_ids;
165+ Serialize.Cache. reset_data SolverData ;
166+ Serialize.Cache. reset_data AnalysisData ;
167+ );
168+
169+ (* Reset lazy modules *)
170+ ResettableLazy. reset mcp_serv.node_locator;
171+ ResettableLazy. reset mcp_serv.arg_wrapper;
172+ ResettableLazy. reset mcp_serv.invariant_parser;
173+ Cilfacade. reset_lazy () ;
174+ InvariantCil. reset_lazy () ;
175+ WideningThresholds. reset_lazy () ;
176+ IntDomain. reset_lazy () ;
177+ FloatDomain. reset_lazy () ;
178+ StringDomain. reset_lazy () ;
179+ PrecisionUtil. reset_lazy () ;
180+ ApronDomain. reset_lazy () ;
181+ AutoTune. reset_lazy () ;
182+ LibraryFunctions. reset_lazy () ;
183+ Access. reset () ;
184+
185+ mcp_serv.file < - Some file;
186+
187+ (* Run analysis *)
188+ Maingoblint. do_analyze None file;
189+ Maingoblint. do_gobview file;
190+
72191(* * JSON Schema helpers *)
73192let string_schema = `Assoc [(" type" , `String " string" )]
74193let bool_schema = `Assoc [(" type" , `String " boolean" )]
@@ -284,8 +403,8 @@ let handle_tools_call (mcp_serv: t) (call: ToolCall.t) =
284403 (* Set the file to analyze *)
285404 GobConfig. set_list " files" [`String file];
286405
287- (* Run analysis *)
288- Server. analyze mcp_serv.server ~reset ;
406+ (* Run analysis directly *)
407+ analyze mcp_serv ~reset ;
289408 mcp_serv.analyzed < - true ;
290409
291410 let status = if ! AnalysisState. verified = Some false then " VerifyError" else " Success" in
@@ -302,8 +421,8 @@ let handle_tools_call (mcp_serv: t) (call: ToolCall.t) =
302421 (* Set compilation database *)
303422 GobConfig. set_string " pre.compdb.file" comp_db;
304423
305- (* Run analysis *)
306- Server. analyze mcp_serv.server ~reset ;
424+ (* Run analysis directly *)
425+ analyze mcp_serv ~reset ;
307426 mcp_serv.analyzed < - true ;
308427
309428 let status = if ! AnalysisState. verified = Some false then " VerifyError" else " Success" in
@@ -320,11 +439,17 @@ let handle_tools_call (mcp_serv: t) (call: ToolCall.t) =
320439 ToolResult. make_text (Yojson.Safe. to_string files_json)
321440
322441 | "get_functions" ->
323- begin match mcp_serv.server. file with
442+ begin match mcp_serv.file with
324443 | Some file ->
325- let functions = Server.Function. getFunctionsList file.globals in
326- let json = `List (List. map Server.Function. to_yojson functions) in
327- ToolResult. make_text (Yojson.Safe. to_string json)
444+ let functions = List. filter_map (function
445+ | Cil. GFun (fd , loc ) -> Some `Assoc [
446+ (" funName" , `String fd.svar.vname);
447+ (" location" , CilType.Location. to_yojson loc)
448+ ]
449+ | _ -> None
450+ ) file.globals
451+ in
452+ ToolResult. make_text (Yojson.Safe. to_string (`List functions))
328453 | None ->
329454 ToolResult. make_error " No file has been analyzed yet"
330455 end
@@ -380,10 +505,11 @@ let handle_tools_call (mcp_serv: t) (call: ToolCall.t) =
380505 | Some node_id , None ->
381506 Node. of_id node_id
382507 | None , Some location ->
508+ let module Locator = WitnessUtil. Locator (Node ) in
383509 let node_opt =
384510 let open GobOption.Syntax in
385- let * nodes = Server. Locator. find_opt (ResettableLazy. force Server . node_locator) location in
386- Server. Locator.ES. choose_opt nodes
511+ let * nodes = Locator. find_opt (ResettableLazy. force mcp_serv .node_locator) location in
512+ Locator.ES. choose_opt nodes
387513 in
388514 Option. get_exn node_opt (Failure " cannot find node for location" )
389515 | _ , _ ->
@@ -490,7 +616,7 @@ let handle_tools_call (mcp_serv: t) (call: ToolCall.t) =
490616 let cfg_node = Arg.Node. cfgnode n in
491617 let fundec = Node. find_fundec cfg_node in
492618 let loc = UpdateCil. getLoc cfg_node in
493- begin match WitnessUtil.InvariantParser. parse_cil (ResettableLazy. force mcp_serv.server. invariant_parser) ~fundec ~loc exp_cabs with
619+ begin match WitnessUtil.InvariantParser. parse_cil (ResettableLazy. force mcp_serv.invariant_parser) ~fundec ~loc exp_cabs with
494620 | Ok exp -> exp
495621 | Error _ -> raise (Failure " CIL couldn't parse expression" )
496622 end
@@ -516,7 +642,7 @@ let handle_tools_call (mcp_serv: t) (call: ToolCall.t) =
516642 let cfg_node = Arg.Node. cfgnode n in
517643 let fundec = Node. find_fundec cfg_node in
518644 let loc = UpdateCil. getLoc cfg_node in
519- begin match WitnessUtil.InvariantParser. parse_cil (ResettableLazy. force mcp_serv.server. invariant_parser) ~fundec ~loc exp_cabs with
645+ begin match WitnessUtil.InvariantParser. parse_cil (ResettableLazy. force mcp_serv.invariant_parser) ~fundec ~loc exp_cabs with
520646 | Ok exp ->
521647 let x = Arg. query n (Queries. EvalInt exp) in
522648 let result = `Assoc [
0 commit comments