1(**************************************************************************)
2(*                                                                        *)
3(*                                 OCaml                                  *)
4(*                                                                        *)
5(*           Jerome Vouillon, projet Cristal, INRIA Rocquencourt          *)
6(*           OCaml port by John Malecki and Xavier Leroy                  *)
7(*                                                                        *)
8(*   Copyright 1996 Institut National de Recherche en Informatique et     *)
9(*     en Automatique.                                                    *)
10(*                                                                        *)
11(*   All rights reserved.  This file is distributed under the terms of    *)
12(*   the GNU Lesser General Public License version 2.1, with the          *)
13(*   special exception on linking described in the file LICENSE.          *)
14(*                                                                        *)
15(**************************************************************************)
16
17(************************ Reading and executing commands ***************)
18
19open Int64ops
20open Format
21open Misc
22open Instruct
23open Unix
24open Debugger_config
25open Types
26open Primitives
27open Unix_tools
28open Parser
29open Parser_aux
30open Lexer
31open Input_handling
32open Question
33open Debugcom
34open Program_loading
35open Program_management
36open Lexing
37open Parameters
38open Show_source
39open Show_information
40open Time_travel
41open Events
42open Symbols
43open Source
44open Breakpoints
45open Checkpoints
46open Frames
47open Printval
48
49(** Instructions, variables and infos lists. **)
50type dbg_instruction =
51  { instr_name: string;                 (* Name of command *)
52    instr_prio: bool;                   (* Has priority *)
53    instr_action: formatter -> lexbuf -> unit;
54                                        (* What to do *)
55    instr_repeat: bool;                 (* Can be repeated *)
56    instr_help: string }                (* Help message *)
57
58let instruction_list = ref ([] : dbg_instruction list)
59
60type dbg_variable =
61  { var_name: string;                   (* Name of variable *)
62    var_action: (lexbuf -> unit) * (formatter -> unit);
63                                        (* Reading, writing fns *)
64    var_help: string }                  (* Help message *)
65
66let variable_list = ref ([] : dbg_variable list)
67
68type dbg_info =
69  { info_name: string;                  (* Name of info *)
70    info_action: lexbuf -> unit;        (* What to do *)
71    info_help: string }                 (* Help message *)
72
73let info_list = ref ([] : dbg_info list)
74
75(** Utilities. **)
76let error text =
77  eprintf "%s@." text;
78  raise Toplevel
79
80let check_not_windows feature =
81  match Sys.os_type with
82  | "Win32" ->
83      error ("\'"^feature^"\' feature not supported on Windows")
84  | _ ->
85      ()
86
87let eol =
88  end_of_line Lexer.lexeme
89
90let matching_elements list name instr =
91  List.filter (function a -> isprefix instr (name a)) !list
92
93let all_matching_instructions =
94  matching_elements instruction_list (fun i -> i.instr_name)
95
96(* itz 04-21-96 don't do priority completion in emacs mode *)
97(* XL 25-02-97 why? I find it very confusing. *)
98
99let matching_instructions instr =
100  let all = all_matching_instructions instr in
101  let prio = List.filter (fun i -> i.instr_prio) all in
102  if prio = [] then all else prio
103
104let matching_variables =
105  matching_elements variable_list (fun v -> v.var_name)
106
107let matching_infos =
108  matching_elements info_list (fun i -> i.info_name)
109
110let find_ident name matcher action alternative ppf lexbuf =
111  match identifier_or_eol Lexer.lexeme lexbuf with
112  | None -> alternative ppf
113  | Some ident ->
114      match matcher ident with
115      | [] -> error ("Unknown " ^ name ^ ".")
116      | [a] -> action a ppf lexbuf
117      | _ -> error ("Ambiguous " ^ name ^ ".")
118
119let find_variable action alternative ppf lexbuf =
120  find_ident "variable name" matching_variables action alternative ppf lexbuf
121
122let find_info action alternative ppf lexbuf =
123  find_ident "info command" matching_infos action alternative ppf lexbuf
124
125let add_breakpoint_at_pc pc =
126  try
127    new_breakpoint (any_event_at_pc pc)
128  with
129  | Not_found ->
130    eprintf "Can\'t add breakpoint at pc %i: no event there.@." pc;
131    raise Toplevel
132
133let add_breakpoint_after_pc pc =
134  let rec try_add n =
135    if n < 3 then begin
136      try
137        new_breakpoint (any_event_at_pc (pc + n * 4))
138      with
139      | Not_found ->
140        try_add (n+1)
141    end else begin
142      error
143        "Can\'t add breakpoint at beginning of function: no event there"
144    end
145  in try_add 0
146
147let module_of_longident id =
148  match id with
149  | Some x -> Some (String.concat "." (Longident.flatten x))
150  | None -> None
151
152let convert_module mdle =
153  match mdle with
154  | Some m ->
155      (* Strip .ml extension if any, and capitalize *)
156      String.capitalize_ascii(if Filename.check_suffix m ".ml"
157                              then Filename.chop_suffix m ".ml"
158                              else m)
159  | None ->
160      try
161        (get_current_event ()).ev_module
162      with
163      | Not_found ->
164          error "Not in a module."
165
166(** Toplevel. **)
167let current_line = ref ""
168
169let interprete_line ppf line =
170  current_line := line;
171  let lexbuf = Lexing.from_string line in
172    try
173      match identifier_or_eol Lexer.lexeme lexbuf with
174      | Some x ->
175          begin match matching_instructions x with
176          | [] ->
177              error "Unknown command."
178          | [i] ->
179              i.instr_action ppf lexbuf;
180              resume_user_input ();
181              i.instr_repeat
182          | _ ->
183              error "Ambiguous command."
184          end
185      | None ->
186          resume_user_input ();
187          false
188    with
189    | Parsing.Parse_error ->
190        error "Syntax error."
191    | Lexer.Int_overflow ->
192      error "Integer overflow"
193
194let line_loop ppf line_buffer =
195  resume_user_input ();
196  let previous_line = ref "" in
197    try
198      while true do
199        if !loaded then
200          History.add_current_time ();
201        let new_line = string_trim (line line_buffer) in
202          let line =
203            if new_line <> "" then
204              new_line
205            else
206              !previous_line
207          in
208            previous_line := "";
209            if interprete_line ppf line then
210              previous_line := line
211      done
212    with
213    | Exit ->
214        stop_user_input ()
215(*    | Sys_error s ->
216        error ("System error: " ^ s) *)
217
218(** Instructions. **)
219let instr_cd _ppf lexbuf =
220  let dir = argument_eol argument lexbuf in
221    if ask_kill_program () then
222      try
223        Sys.chdir (expand_path dir)
224      with
225      | Sys_error s ->
226          error s
227
228let instr_shell _ppf lexbuf =
229  let cmdarg = argument_list_eol argument lexbuf in
230  let cmd = String.concat " " cmdarg in
231  (* perhaps we should use $SHELL -c ? *)
232  let err = Sys.command cmd in
233  if (err != 0) then
234    eprintf "Shell command %S failed with exit code %d\n%!" cmd err
235
236let instr_env _ppf lexbuf =
237  let cmdarg = argument_list_eol argument lexbuf in
238  let cmdarg = string_trim (String.concat " " cmdarg) in
239  if cmdarg <> "" then
240    if ask_kill_program () then begin
241      try
242        let eqpos = String.index cmdarg '=' in
243        if eqpos = 0 then raise Not_found;
244        let name = String.sub cmdarg 0 eqpos in
245        let value =
246          String.sub cmdarg (eqpos + 1) (String.length cmdarg - eqpos - 1)
247        in
248        Debugger_config.environment :=
249          (name, value) :: List.remove_assoc name !Debugger_config.environment
250      with Not_found ->
251        eprintf "Environment variable must be in name=value format\n%!"
252    end
253  else
254    List.iter
255      (fun (vvar, vval) -> printf "%s=%s\n%!" vvar vval)
256      (List.rev !Debugger_config.environment)
257
258let instr_pwd ppf lexbuf =
259  eol lexbuf;
260  fprintf ppf "%s@." (Sys.getcwd ())
261
262let instr_dir ppf lexbuf =
263  let new_directory = argument_list_eol argument lexbuf in
264    if new_directory = [] then begin
265      if yes_or_no "Reinitialize directory list" then begin
266        Config.load_path := !default_load_path;
267        Envaux.reset_cache ();
268        Hashtbl.clear Debugger_config.load_path_for;
269        flush_buffer_list ()
270        end
271      end
272    else begin
273      let new_directory' = List.rev new_directory in
274      match new_directory' with
275      | mdl :: for_keyw :: tl
276        when String.lowercase_ascii for_keyw = "for" && List.length tl > 0 ->
277          List.iter (function x -> add_path_for mdl (expand_path x)) tl
278      | _ ->
279          List.iter (function x -> add_path (expand_path x)) new_directory'
280    end;
281    let print_dirs ppf l = List.iter (function x -> fprintf ppf "@ %s" x) l in
282    fprintf ppf "@[<2>Directories: %a@]@." print_dirs !Config.load_path;
283    Hashtbl.iter
284      (fun mdl dirs ->
285         fprintf ppf "@[<2>Source directories for %s: %a@]@." mdl print_dirs
286                 dirs)
287      Debugger_config.load_path_for
288
289let instr_kill _ppf lexbuf =
290  eol lexbuf;
291  if not !loaded then error "The program is not being run.";
292  if (yes_or_no "Kill the program being debugged") then begin
293    kill_program ();
294    show_no_point()
295  end
296
297let instr_pid ppf lexbuf =
298  eol lexbuf;
299  if not !loaded then error "The program is not being run.";
300  fprintf ppf "@[%d@]@." !current_checkpoint.c_pid
301
302let instr_run ppf lexbuf =
303  eol lexbuf;
304  ensure_loaded ();
305  reset_named_values ();
306  run ();
307  show_current_event ppf;;
308
309let instr_reverse ppf lexbuf =
310  eol lexbuf;
311  check_not_windows "reverse";
312  ensure_loaded ();
313  reset_named_values();
314  back_run ();
315  show_current_event ppf
316
317let instr_step ppf lexbuf =
318  let step_count =
319    match opt_signed_int64_eol Lexer.lexeme lexbuf with
320    | None -> _1
321    | Some x -> x
322  in
323    ensure_loaded ();
324    reset_named_values();
325    step step_count;
326    show_current_event ppf
327
328let instr_back ppf lexbuf =
329  let step_count =
330    match opt_signed_int64_eol Lexer.lexeme lexbuf with
331    | None -> _1
332    | Some x -> x
333  in
334    check_not_windows "backstep";
335    ensure_loaded ();
336    reset_named_values();
337    step (_0 -- step_count);
338    show_current_event ppf
339
340let instr_finish ppf lexbuf =
341  eol lexbuf;
342  ensure_loaded ();
343  reset_named_values();
344  finish ();
345  show_current_event ppf
346
347let instr_next ppf lexbuf =
348  let step_count =
349    match opt_integer_eol Lexer.lexeme lexbuf with
350    | None -> 1
351    | Some x -> x
352  in
353    ensure_loaded ();
354    reset_named_values();
355    next step_count;
356    show_current_event ppf
357
358let instr_start ppf lexbuf =
359  eol lexbuf;
360  check_not_windows "start";
361  ensure_loaded ();
362  reset_named_values();
363  start ();
364  show_current_event ppf
365
366let instr_previous ppf lexbuf =
367  let step_count =
368    match opt_integer_eol Lexer.lexeme lexbuf with
369    | None -> 1
370    | Some x -> x
371  in
372    check_not_windows "previous";
373    ensure_loaded ();
374    reset_named_values();
375    previous step_count;
376    show_current_event ppf
377
378let instr_goto ppf lexbuf =
379  let time = int64_eol Lexer.lexeme lexbuf in
380    ensure_loaded ();
381    reset_named_values();
382    go_to time;
383    show_current_event ppf
384
385let instr_quit _ =
386  raise Exit
387
388let print_variable_list ppf =
389  let pr_vars ppf = List.iter (fun v -> fprintf ppf "%s@ " v.var_name) in
390  fprintf ppf "List of variables: %a@." pr_vars !variable_list
391
392let print_info_list ppf =
393  let pr_infos ppf = List.iter (fun i -> fprintf ppf "%s@ " i.info_name)  in
394  fprintf ppf "List of info commands: %a@." pr_infos !info_list
395
396let instr_complete _ppf lexbuf =
397  let ppf = Format.err_formatter in
398  let rec print_list l =
399    try
400      eol lexbuf;
401      List.iter (function i -> fprintf ppf "%s@." i) l
402    with _ ->
403      remove_file !user_channel
404  and match_list lexbuf =
405    match identifier_or_eol Lexer.lexeme lexbuf with
406    | None ->
407        List.map (fun i -> i.instr_name) !instruction_list
408    | Some x ->
409        match matching_instructions x with
410        | [ {instr_name = ("set" | "show" as i_full)} ] ->
411            if x = i_full then begin
412              match identifier_or_eol Lexer.lexeme lexbuf with
413              | Some ident ->
414                  begin match matching_variables ident with
415                  | [v] -> if v.var_name = ident then [] else [v.var_name]
416                  | l   -> List.map (fun v -> v.var_name) l
417                  end
418              | None ->
419                  List.map (fun v -> v.var_name) !variable_list
420            end
421            else [i_full]
422        | [ {instr_name = "info"} ] ->
423            if x = "info" then begin
424              match identifier_or_eol Lexer.lexeme lexbuf with
425              | Some ident ->
426                  begin match matching_infos ident with
427                  | [i] -> if i.info_name = ident then [] else [i.info_name]
428                  | l   -> List.map (fun i -> i.info_name) l
429                  end
430              | None ->
431                  List.map (fun i -> i.info_name) !info_list
432            end
433            else ["info"]
434        | [ {instr_name = "help"} ] ->
435            if x = "help" then match_list lexbuf else ["help"]
436        | [ i ] ->
437            if x = i.instr_name then [] else [i.instr_name]
438        | l ->
439            List.map (fun i -> i.instr_name) l
440  in
441    print_list(match_list lexbuf)
442
443let instr_help ppf lexbuf =
444  let pr_instrs ppf =
445      List.iter (fun i -> fprintf ppf "%s@ " i.instr_name) in
446  match identifier_or_eol Lexer.lexeme lexbuf with
447  | Some x ->
448      let print_help nm hlp =
449        eol lexbuf;
450        fprintf ppf "%s: %s@." nm hlp in
451      begin match matching_instructions x with
452      | [] ->
453          eol lexbuf;
454          fprintf ppf "No matching command.@."
455      | [ {instr_name = "set"} ] ->
456          find_variable
457            (fun v _ _ ->
458               print_help ("set " ^ v.var_name) ("set " ^ v.var_help))
459            (fun ppf ->
460               print_help "set" "set debugger variable.";
461               print_variable_list ppf)
462            ppf
463            lexbuf
464      | [ {instr_name = "show"} ] ->
465          find_variable
466            (fun v _ _ ->
467               print_help ("show " ^ v.var_name) ("show " ^ v.var_help))
468            (fun _v ->
469               print_help "show" "display debugger variable.";
470               print_variable_list ppf)
471            ppf
472            lexbuf
473      | [ {instr_name = "info"} ] ->
474          find_info
475            (fun i _ _ -> print_help ("info " ^ i.info_name) i.info_help)
476            (fun ppf ->
477               print_help "info"
478                 "display infos about the program being debugged.";
479               print_info_list ppf)
480            ppf
481            lexbuf
482      | [i] ->
483          print_help i.instr_name i.instr_help
484      | l ->
485          eol lexbuf;
486          fprintf ppf "Ambiguous command \"%s\": %a@." x pr_instrs l
487      end
488  | None ->
489      fprintf ppf "List of commands: %a@." pr_instrs !instruction_list
490
491(* Printing values *)
492
493let print_expr depth ev env ppf expr =
494  try
495    let (v, ty) = Eval.expression ev env expr in
496    print_named_value depth expr env v ppf ty
497  with
498  | Eval.Error msg ->
499    Eval.report_error ppf msg;
500    raise Toplevel
501
502let env_of_event =
503  function
504    None    -> Env.empty
505  | Some ev ->
506      Envaux.env_from_summary ev.Instruct.ev_typenv ev.Instruct.ev_typsubst
507
508let print_command depth ppf lexbuf =
509  let exprs = expression_list_eol Lexer.lexeme lexbuf in
510  ensure_loaded ();
511  let env =
512    try
513      env_of_event !selected_event
514    with
515    | Envaux.Error msg ->
516        Envaux.report_error ppf msg;
517        raise Toplevel
518  in
519  List.iter (print_expr depth !selected_event env ppf) exprs
520
521let instr_print ppf lexbuf = print_command !max_printer_depth ppf lexbuf
522
523let instr_display ppf lexbuf = print_command 1 ppf lexbuf
524
525let instr_address ppf lexbuf =
526  let exprs = expression_list_eol Lexer.lexeme lexbuf in
527  ensure_loaded ();
528  let env =
529    try
530      env_of_event !selected_event
531    with
532    | Envaux.Error msg ->
533        Envaux.report_error ppf msg;
534        raise Toplevel
535  in
536  let print_addr expr =
537    let (v, _ty) =
538      try Eval.expression !selected_event env expr
539      with Eval.Error msg ->
540        Eval.report_error ppf msg;
541        raise Toplevel
542    in
543    match Remote_value.pointer v with
544    | "" -> fprintf ppf "[not a remote value]@."
545    | s -> fprintf ppf "0x%s@." s
546  in
547  List.iter print_addr exprs
548
549(* Loading of command files *)
550
551let extract_filename arg =
552  (* Allow enclosing filename in quotes *)
553  let l = String.length arg in
554  let pos1 = if l > 0 && arg.[0] = '\"' then 1 else 0 in
555  let pos2 = if l > 0 && arg.[l-1] = '\"' then l-1 else l in
556  String.sub arg pos1 (pos2 - pos1)
557
558let instr_source ppf lexbuf =
559  let file = extract_filename(argument_eol argument lexbuf)
560  and old_state = !interactif
561  and old_channel = !user_channel in
562    let io_chan =
563      try
564        io_channel_of_descr
565          (openfile (find_in_path !Config.load_path (expand_path file))
566             [O_RDONLY] 0)
567      with
568      | Not_found -> error "Source file not found."
569      | (Unix_error _) as x  -> Unix_tools.report_error x; raise Toplevel
570    in
571      try
572        interactif := false;
573        user_channel := io_chan;
574        line_loop ppf (Lexing.from_function read_user_input);
575        close_io io_chan;
576        interactif := old_state;
577        user_channel := old_channel
578      with
579      | x ->
580          stop_user_input ();
581          close_io io_chan;
582          interactif := old_state;
583          user_channel := old_channel;
584          raise x
585
586let instr_set =
587  find_variable
588    (fun {var_action = (funct, _)} _ppf lexbuf -> funct lexbuf)
589    (function _ppf -> error "Argument required.")
590
591let instr_show =
592  find_variable
593    (fun {var_action = (_, funct)} ppf lexbuf -> eol lexbuf; funct ppf)
594    (function ppf ->
595       List.iter
596         (function {var_name = nm; var_action = (_, funct)} ->
597              fprintf ppf "%s: " nm;
598              funct ppf)
599         !variable_list)
600
601let instr_info =
602  find_info
603    (fun i _ppf lexbuf -> i.info_action lexbuf)
604    (function _ppf ->
605       error "\"info\" must be followed by the name of an info command.")
606
607let instr_break ppf lexbuf =
608  let argument = break_argument_eol Lexer.lexeme lexbuf in
609    ensure_loaded ();
610    match argument with
611    |  BA_none ->                                (* break *)
612        (match !selected_event with
613         | Some ev ->
614             new_breakpoint ev
615         | None ->
616             error "Can\'t add breakpoint at this point.")
617    | BA_pc pc ->                               (* break PC *)
618        add_breakpoint_at_pc pc
619    | BA_function expr ->                       (* break FUNCTION *)
620        let env =
621          try
622            env_of_event !selected_event
623          with
624          | Envaux.Error msg ->
625              Envaux.report_error ppf msg;
626              raise Toplevel
627        in
628        begin try
629          let (v, ty) = Eval.expression !selected_event env expr in
630          match (Ctype.repr ty).desc with
631          | Tarrow _ ->
632              add_breakpoint_after_pc (Remote_value.closure_code v)
633          | _ ->
634              eprintf "Not a function.@.";
635              raise Toplevel
636        with
637        | Eval.Error msg ->
638            Eval.report_error ppf msg;
639            raise Toplevel
640        end
641    | BA_pos1 (mdle, line, column) ->         (* break @ [MODULE] LINE [COL] *)
642        let module_name = convert_module (module_of_longident mdle) in
643        new_breakpoint
644          (try
645            let ev =  event_at_pos module_name 0 in
646            let ev_pos =
647              {Lexing.dummy_pos with
648               pos_fname = (Events.get_pos ev).pos_fname} in
649             let buffer =
650               try get_buffer ev_pos module_name with
651               | Not_found ->
652                  eprintf "No source file for %s.@." module_name;
653                  raise Toplevel
654             in
655             match column with
656             | None ->
657                 event_at_pos module_name (fst (pos_of_line buffer line))
658             | Some col ->
659                 event_near_pos module_name (point_of_coord buffer line col)
660           with
661           | Not_found -> (* event_at_pos / event_near pos *)
662               eprintf "Can\'t find any event there.@.";
663               raise Toplevel
664           | Out_of_range -> (* pos_of_line / point_of_coord *)
665               eprintf "Position out of range.@.";
666               raise Toplevel)
667    | BA_pos2 (mdle, position) ->             (* break @ [MODULE] # POSITION *)
668        try
669          new_breakpoint
670            (event_near_pos (convert_module (module_of_longident mdle))
671                            position)
672        with
673        | Not_found ->
674            eprintf "Can\'t find any event there.@."
675
676let instr_delete _ppf lexbuf =
677  match integer_list_eol Lexer.lexeme lexbuf with
678  | [] ->
679      if breakpoints_count () <> 0 && yes_or_no "Delete all breakpoints"
680      then remove_all_breakpoints ()
681  | breakpoints ->
682      List.iter
683        (function x -> try remove_breakpoint x with | Not_found -> ())
684        breakpoints
685
686let instr_frame ppf lexbuf =
687  let frame_number =
688    match opt_integer_eol Lexer.lexeme lexbuf with
689    | None -> !current_frame
690    | Some x -> x
691  in
692    ensure_loaded ();
693    try
694      select_frame frame_number;
695      show_current_frame ppf true
696    with
697    | Not_found ->
698        error ("No frame number " ^ string_of_int frame_number ^ ".")
699
700let instr_backtrace ppf lexbuf =
701  let number =
702    match opt_signed_integer_eol Lexer.lexeme lexbuf with
703    | None -> 0
704    | Some x -> x in
705  ensure_loaded ();
706  match current_report() with
707  | None | Some {rep_type = Exited | Uncaught_exc} -> ()
708  | Some _ ->
709      let frame_counter = ref 0 in
710      let print_frame first_frame last_frame = function
711      | None ->
712          fprintf ppf
713           "(Encountered a function with no debugging information)@.";
714          false
715      | Some event ->
716          if !frame_counter >= first_frame then
717            show_one_frame !frame_counter ppf event;
718          incr frame_counter;
719          if !frame_counter >= last_frame then begin
720            fprintf ppf "(More frames follow)@."
721          end;
722          !frame_counter < last_frame in
723      fprintf ppf "Backtrace:@.";
724      if number = 0 then
725        do_backtrace (print_frame 0 max_int)
726      else if number > 0 then
727        do_backtrace (print_frame 0 number)
728      else begin
729        let num_frames = stack_depth() in
730        if num_frames < 0 then
731          fprintf ppf
732            "(Encountered a function with no debugging information)@."
733        else
734          do_backtrace (print_frame (num_frames + number) max_int)
735      end
736
737let instr_up ppf lexbuf =
738  let offset =
739    match opt_signed_integer_eol Lexer.lexeme lexbuf with
740    | None -> 1
741    | Some x -> x
742  in
743    ensure_loaded ();
744    try
745      select_frame (!current_frame + offset);
746      show_current_frame ppf true
747    with
748    | Not_found -> error "No such frame."
749
750let instr_down ppf lexbuf =
751  let offset =
752    match opt_signed_integer_eol Lexer.lexeme lexbuf with
753    | None -> 1
754    | Some x -> x
755  in
756    ensure_loaded ();
757    try
758      select_frame (!current_frame - offset);
759      show_current_frame ppf true
760    with
761    | Not_found -> error "No such frame."
762
763let instr_last ppf lexbuf =
764  let count =
765    match opt_signed_int64_eol Lexer.lexeme lexbuf with
766    | None -> _1
767    | Some x -> x
768  in
769    check_not_windows "last";
770    reset_named_values();
771    go_to (History.previous_time count);
772    show_current_event ppf
773
774let instr_list _ppf lexbuf =
775  let (mo, beg, e) = list_arguments_eol Lexer.lexeme lexbuf in
776    let (curr_mod, line, column) =
777      try
778        selected_point ()
779      with
780      | Not_found ->
781          ("", -1, -1)
782    in
783      let mdle =
784        match mo with
785        | None -> curr_mod
786        | _ -> convert_module (module_of_longident mo)
787      in
788      let pos = Lexing.dummy_pos in
789      let buffer =
790        try get_buffer pos mdle with
791        | Not_found -> error ("No source file for " ^ mdle ^ ".") in
792      let point =
793        if column <> -1 then
794          try
795            (point_of_coord buffer line 1) + column
796          with Out_of_range ->
797            -1
798        else
799          -1 in
800        let beginning =
801          match beg with
802          | None when (mo <> None) || (line = -1) ->
803              1
804          | None ->
805              begin try
806                max 1 (line - 10)
807              with Out_of_range ->
808                1
809              end
810          | Some x -> x
811        in
812          let en =
813            match e with
814            | None -> beginning + 20
815            | Some x -> x
816          in
817            if mdle = curr_mod then
818              show_listing pos mdle beginning en point
819                (current_event_is_before ())
820            else
821              show_listing pos mdle beginning en (-1) true
822
823(** Variables. **)
824let raw_variable kill name =
825  (function lexbuf ->
826     let argument = argument_eol argument lexbuf in
827       if (not kill) || ask_kill_program () then name := argument),
828  function ppf -> fprintf ppf "%s@." !name
829
830let raw_line_variable kill name =
831  (function lexbuf ->
832     let argument = argument_eol line_argument lexbuf in
833       if (not kill) || ask_kill_program () then name := argument),
834  function ppf -> fprintf ppf "%s@." !name
835
836let integer_variable kill min msg name =
837  (function lexbuf ->
838     let argument = integer_eol Lexer.lexeme lexbuf in
839       if argument < min then print_endline msg
840       else if (not kill) || ask_kill_program () then name := argument),
841  function ppf -> fprintf ppf "%i@." !name
842
843let int64_variable kill min msg name =
844  (function lexbuf ->
845     let argument = int64_eol Lexer.lexeme lexbuf in
846       if argument < min then print_endline msg
847       else if (not kill) || ask_kill_program () then name := argument),
848  function ppf -> fprintf ppf "%Li@." !name
849
850let boolean_variable kill name =
851  (function lexbuf ->
852     let argument =
853       match identifier_eol Lexer.lexeme lexbuf with
854       | "on" -> true
855       | "of" | "off" -> false
856       | _ -> error "Syntax error."
857     in
858       if (not kill) || ask_kill_program () then name := argument),
859  function ppf -> fprintf ppf "%s@." (if !name then "on" else "off")
860
861let path_variable kill name =
862  (function lexbuf ->
863       let argument = argument_eol argument lexbuf in
864         if (not kill) || ask_kill_program () then
865           name := make_absolute (expand_path argument)),
866  function ppf -> fprintf ppf "%s@." !name
867
868let loading_mode_variable ppf =
869  (find_ident
870     "loading mode"
871     (matching_elements (ref loading_modes) fst)
872     (fun (_, mode) _ppf lexbuf ->
873        eol lexbuf; set_launching_function mode)
874     (function _ppf -> error "Syntax error.")
875     ppf),
876  function ppf ->
877    let rec find = function
878      | [] -> ()
879      | (name, funct) :: l ->
880          if funct == !launching_func then fprintf ppf "%s" name else find l
881    in
882      find loading_modes;
883      fprintf ppf "@."
884
885let follow_fork_variable =
886  (function lexbuf ->
887     let mode =
888       match identifier_eol Lexer.lexeme lexbuf with
889       | "child" -> Fork_child
890       | "parent" -> Fork_parent
891       | _ -> error "Syntax error."
892     in
893       fork_mode := mode;
894       if !loaded then update_follow_fork_mode ()),
895  function ppf ->
896    fprintf ppf "%s@."
897      (match !fork_mode with
898         Fork_child -> "child"
899       | Fork_parent -> "parent")
900
901(** Infos. **)
902
903let pr_modules ppf mods =
904 let pr_mods ppf = List.iter (function x -> fprintf ppf "%s@ " x) in
905 fprintf ppf "Used modules: @.%a@?" pr_mods mods
906
907let info_modules ppf lexbuf =
908  eol lexbuf;
909  ensure_loaded ();
910  pr_modules ppf !modules
911(********
912  print_endline "Opened modules: ";
913  if !opened_modules_names = [] then
914    print_endline "(no module opened)."
915  else
916    (List.iter (function x -> print_string x;print_space) !opened_modules_names;
917     print_newline ())
918*********)
919
920let info_checkpoints ppf lexbuf =
921  eol lexbuf;
922  if !checkpoints = [] then fprintf ppf "No checkpoint.@."
923  else
924    (if !debug_breakpoints then
925       (prerr_endline "               Time   Pid Version";
926        List.iter
927          (function
928             {c_time = time; c_pid = pid; c_breakpoint_version = version} ->
929               Printf.printf "%19Ld %5d %d\n" time pid version)
930          !checkpoints)
931     else
932       (print_endline "               Time   Pid";
933        List.iter
934          (function
935             {c_time = time; c_pid = pid} ->
936               Printf.printf "%19Ld %5d\n" time pid)
937          !checkpoints))
938
939let info_one_breakpoint ppf (num, ev) =
940  fprintf ppf "%3d %10d  %s@." num ev.ev_pos (Pos.get_desc ev);
941;;
942
943let info_breakpoints ppf lexbuf =
944  eol lexbuf;
945  if !breakpoints = [] then fprintf ppf "No breakpoints.@."
946  else begin
947    fprintf ppf "Num    Address  Where@.";
948    List.iter (info_one_breakpoint ppf) (List.rev !breakpoints);
949  end
950;;
951
952let info_events _ppf lexbuf =
953  ensure_loaded ();
954  let mdle =
955    convert_module (module_of_longident (opt_longident_eol Lexer.lexeme lexbuf))
956  in
957    print_endline ("Module: " ^ mdle);
958    print_endline "   Address  Characters        Kind      Repr.";
959    List.iter
960      (function ev ->
961        let start_char, end_char =
962          try
963            let buffer = get_buffer (Events.get_pos ev) ev.ev_module in
964            (snd (start_and_cnum buffer ev.ev_loc.Location.loc_start)),
965            (snd (start_and_cnum buffer ev.ev_loc.Location.loc_end))
966          with _ ->
967            ev.ev_loc.Location.loc_start.Lexing.pos_cnum,
968            ev.ev_loc.Location.loc_end.Lexing.pos_cnum in
969        Printf.printf
970           "%10d %6d-%-6d  %10s %10s\n"
971           ev.ev_pos
972           start_char
973           end_char
974           ((match ev.ev_kind with
975               Event_before   -> "before"
976             | Event_after _  -> "after"
977             | Event_pseudo   -> "pseudo")
978            ^
979            (match ev.ev_info with
980               Event_function -> "/fun"
981             | Event_return _ -> "/ret"
982             | Event_other    -> ""))
983           (match ev.ev_repr with
984              Event_none        -> ""
985            | Event_parent _    -> "(repr)"
986            | Event_child repr  -> string_of_int !repr))
987      (events_in_module mdle)
988
989(** User-defined printers **)
990
991let instr_load_printer ppf lexbuf =
992  let filename = extract_filename(argument_eol argument lexbuf) in
993  try
994    Loadprinter.loadfile ppf filename
995  with Loadprinter.Error e ->
996    Loadprinter.report_error ppf e; raise Toplevel
997
998let instr_install_printer ppf lexbuf =
999  let lid = longident_eol Lexer.lexeme lexbuf in
1000  try
1001    Loadprinter.install_printer ppf lid
1002  with Loadprinter.Error e ->
1003    Loadprinter.report_error ppf e; raise Toplevel
1004
1005let instr_remove_printer ppf lexbuf =
1006  let lid = longident_eol Lexer.lexeme lexbuf in
1007  try
1008    Loadprinter.remove_printer lid
1009  with Loadprinter.Error e ->
1010    Loadprinter.report_error ppf e; raise Toplevel
1011
1012(** Initialization. **)
1013let init ppf =
1014  instruction_list := [
1015     { instr_name = "cd"; instr_prio = false;
1016       instr_action = instr_cd; instr_repeat = true; instr_help =
1017"set working directory to DIR for debugger and program being debugged." };
1018     { instr_name = "complete"; instr_prio = false;
1019       instr_action = instr_complete; instr_repeat = false; instr_help =
1020"complete word at cursor according to context. Useful for Emacs." };
1021     { instr_name = "pwd"; instr_prio = false;
1022       instr_action = instr_pwd; instr_repeat = true; instr_help =
1023"print working directory." };
1024     { instr_name = "directory"; instr_prio = false;
1025       instr_action = instr_dir; instr_repeat = false; instr_help =
1026"add directory DIR to beginning of search path for source and\n\
1027interface files.\n\
1028Forget cached info on source file locations and line positions.\n\
1029With no argument, reset the search path." };
1030     { instr_name = "kill"; instr_prio = false;
1031       instr_action = instr_kill; instr_repeat = true; instr_help =
1032"kill the program being debugged." };
1033     { instr_name = "pid"; instr_prio = false;
1034       instr_action = instr_pid; instr_repeat = true; instr_help =
1035"print the process ID of the current active process." };
1036     { instr_name = "address"; instr_prio = false;
1037       instr_action = instr_address; instr_repeat = true; instr_help =
1038"print the raw address of a value." };
1039     { instr_name = "help"; instr_prio = false;
1040       instr_action = instr_help; instr_repeat = true; instr_help =
1041"print list of commands." };
1042     { instr_name = "quit"; instr_prio = false;
1043       instr_action = instr_quit; instr_repeat = false; instr_help =
1044"exit the debugger." };
1045     { instr_name = "shell"; instr_prio = false;
1046       instr_action = instr_shell; instr_repeat = true; instr_help =
1047"Execute a given COMMAND thru the system shell." };
1048     { instr_name = "environment"; instr_prio = false;
1049       instr_action = instr_env; instr_repeat = false; instr_help =
1050"environment variable to give to program being debugged when it is started." };
1051      (* Displacements *)
1052     { instr_name = "run"; instr_prio = true;
1053       instr_action = instr_run; instr_repeat = true; instr_help =
1054"run the program from current position." };
1055     { instr_name = "reverse"; instr_prio = false;
1056       instr_action = instr_reverse; instr_repeat = true; instr_help =
1057"run the program backward from current position." };
1058     { instr_name = "step"; instr_prio = true;
1059       instr_action = instr_step; instr_repeat = true; instr_help =
1060"step program until it reaches the next event.\n\
1061Argument N means do this N times (or till program stops for another reason)." };
1062     { instr_name = "backstep"; instr_prio = true;
1063       instr_action = instr_back; instr_repeat = true; instr_help =
1064"step program backward until it reaches the previous event.\n\
1065Argument N means do this N times (or till program stops for another reason)." };
1066     { instr_name = "goto"; instr_prio = false;
1067       instr_action = instr_goto; instr_repeat = true; instr_help =
1068"go to the given time." };
1069     { instr_name = "finish"; instr_prio = true;
1070       instr_action = instr_finish; instr_repeat = true; instr_help =
1071"execute until topmost stack frame returns." };
1072     { instr_name = "next"; instr_prio = true;
1073       instr_action = instr_next; instr_repeat = true; instr_help =
1074"step program until it reaches the next event.\n\
1075Skip over function calls.\n\
1076Argument N means do this N times (or till program stops for another reason)." };
1077     { instr_name = "start"; instr_prio = false;
1078       instr_action = instr_start; instr_repeat = true; instr_help =
1079"execute backward until the current function is exited." };
1080     { instr_name = "previous"; instr_prio = false;
1081       instr_action = instr_previous; instr_repeat = true; instr_help =
1082"step program until it reaches the previous event.\n\
1083Skip over function calls.\n\
1084Argument N means do this N times (or till program stops for another reason)." };
1085     { instr_name = "print"; instr_prio = true;
1086       instr_action = instr_print; instr_repeat = true; instr_help =
1087"print value of expressions (deep printing)." };
1088     { instr_name = "display"; instr_prio = true;
1089       instr_action = instr_display; instr_repeat = true; instr_help =
1090"print value of expressions (shallow printing)." };
1091     { instr_name = "source"; instr_prio = false;
1092       instr_action = instr_source; instr_repeat = true; instr_help =
1093"read command from file FILE." };
1094     (* Breakpoints *)
1095     { instr_name = "break"; instr_prio = false;
1096       instr_action = instr_break; instr_repeat = false; instr_help =
1097"Set breakpoint at specified line or function.\
1098\nSyntax: break function-name\
1099\n        break @ [module] linenum\
1100\n        break @ [module] # characternum" };
1101     { instr_name = "delete"; instr_prio = false;
1102       instr_action = instr_delete; instr_repeat = false; instr_help =
1103"delete some breakpoints.\n\
1104Arguments are breakpoint numbers with spaces in between.\n\
1105To delete all breakpoints, give no argument." };
1106     { instr_name = "set"; instr_prio = false;
1107       instr_action = instr_set; instr_repeat = false; instr_help =
1108"--unused--" };
1109     { instr_name = "show"; instr_prio = false;
1110       instr_action = instr_show; instr_repeat = true; instr_help =
1111"--unused--" };
1112     { instr_name = "info"; instr_prio = false;
1113       instr_action = instr_info; instr_repeat = true; instr_help =
1114"--unused--" };
1115     (* Frames *)
1116     { instr_name = "frame"; instr_prio = false;
1117       instr_action = instr_frame; instr_repeat = true; instr_help =
1118"select and print a stack frame.\n\
1119With no argument, print the selected stack frame.\n\
1120An argument specifies the frame to select." };
1121     { instr_name = "backtrace"; instr_prio = false;
1122       instr_action = instr_backtrace; instr_repeat = true; instr_help =
1123"print backtrace of all stack frames, or innermost COUNT frames.\n\
1124With a negative argument, print outermost -COUNT frames." };
1125     { instr_name = "bt"; instr_prio = false;
1126       instr_action = instr_backtrace; instr_repeat = true; instr_help =
1127"print backtrace of all stack frames, or innermost COUNT frames.\n\
1128With a negative argument, print outermost -COUNT frames." };
1129     { instr_name = "up"; instr_prio = false;
1130       instr_action = instr_up; instr_repeat = true; instr_help =
1131"select and print stack frame that called this one.\n\
1132An argument says how many frames up to go." };
1133     { instr_name = "down"; instr_prio = false;
1134       instr_action = instr_down; instr_repeat = true; instr_help =
1135"select and print stack frame called by this one.\n\
1136An argument says how many frames down to go." };
1137     { instr_name = "last"; instr_prio = true;
1138       instr_action = instr_last; instr_repeat = true; instr_help =
1139"go back to previous time." };
1140     { instr_name = "list"; instr_prio = false;
1141       instr_action = instr_list; instr_repeat = true; instr_help =
1142"list the source code." };
1143     (* User-defined printers *)
1144     { instr_name = "load_printer"; instr_prio = false;
1145       instr_action = instr_load_printer; instr_repeat = false; instr_help =
1146"load in the debugger a .cmo or .cma file containing printing functions." };
1147     { instr_name = "install_printer"; instr_prio = false;
1148       instr_action = instr_install_printer; instr_repeat = false; instr_help =
1149"use the given function for printing values of its input type.\n\
1150The code for the function must have previously been loaded in the debugger\n\
1151using \"load_printer\"." };
1152     { instr_name = "remove_printer"; instr_prio = false;
1153       instr_action = instr_remove_printer; instr_repeat = false; instr_help =
1154"stop using the given function for printing values of its input type." }
1155];
1156  variable_list := [
1157    (* variable name, (writing, reading), help reading, help writing *)
1158     { var_name = "arguments";
1159       var_action = raw_line_variable true arguments;
1160       var_help =
1161"arguments to give program being debugged when it is started." };
1162     { var_name = "program";
1163       var_action = path_variable true program_name;
1164       var_help =
1165"name of program to be debugged." };
1166     { var_name = "loadingmode";
1167       var_action = loading_mode_variable ppf;
1168       var_help =
1169"mode of loading.\n\
1170It can be either:\n\
1171  direct: the program is directly called by the debugger.\n\
1172  runtime: the debugger execute `ocamlrun programname arguments\'.\n\
1173  manual: the program is not launched by the debugger,\n\
1174    but manually by the user." };
1175     { var_name = "processcount";
1176       var_action = integer_variable false 1 "Must be >= 1."
1177                                     checkpoint_max_count;
1178       var_help =
1179"maximum number of process to keep." };
1180     { var_name = "checkpoints";
1181       var_action = boolean_variable false make_checkpoints;
1182       var_help =
1183"whether to make checkpoints or not." };
1184     { var_name = "bigstep";
1185       var_action = int64_variable false _1 "Must be >= 1."
1186                                     checkpoint_big_step;
1187       var_help =
1188"step between checkpoints during long displacements." };
1189     { var_name = "smallstep";
1190       var_action = int64_variable false _1 "Must be >= 1."
1191                                     checkpoint_small_step;
1192       var_help =
1193"step between checkpoints during small displacements." };
1194     { var_name = "socket";
1195       var_action = raw_variable true socket_name;
1196       var_help =
1197"name of the socket used by communications debugger-runtime." };
1198     { var_name = "history";
1199       var_action = integer_variable false 0 "" history_size;
1200       var_help =
1201"history size." };
1202     { var_name = "print_depth";
1203       var_action = integer_variable false 1 "Must be at least 1"
1204                                     max_printer_depth;
1205       var_help =
1206"maximal depth for printing of values." };
1207     { var_name = "print_length";
1208       var_action = integer_variable false 1 "Must be at least 1"
1209                                     max_printer_steps;
1210       var_help =
1211"maximal number of value nodes printed." };
1212     { var_name = "follow_fork_mode";
1213       var_action = follow_fork_variable;
1214       var_help =
1215"process to follow after forking.\n\
1216It can be either :\n\
1217  child: the newly created process.\n\
1218  parent: the process that called fork.\n" }];
1219
1220  info_list :=
1221    (* info name, function, help *)
1222    [{ info_name = "modules";
1223       info_action = info_modules ppf;
1224       info_help = "list opened modules." };
1225     { info_name = "checkpoints";
1226       info_action = info_checkpoints ppf;
1227       info_help = "list checkpoints." };
1228     { info_name = "breakpoints";
1229       info_action = info_breakpoints ppf;
1230       info_help = "list breakpoints." };
1231     { info_name = "events";
1232       info_action = info_events ppf;
1233       info_help = "list events in MODULE (default is current module)." }]
1234
1235let _ = init std_formatter
1236