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