1995-08-09 08:06:35 -07:00
|
|
|
(***********************************************************************)
|
|
|
|
(* *)
|
1996-04-30 07:53:58 -07:00
|
|
|
(* Objective Caml *)
|
1995-08-09 08:06:35 -07:00
|
|
|
(* *)
|
|
|
|
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
|
|
|
|
(* *)
|
1996-04-30 07:53:58 -07:00
|
|
|
(* Copyright 1996 Institut National de Recherche en Informatique et *)
|
1999-11-17 10:59:06 -08:00
|
|
|
(* en Automatique. All rights reserved. This file is distributed *)
|
|
|
|
(* under the terms of the Q Public License version 1.0. *)
|
1995-08-09 08:06:35 -07:00
|
|
|
(* *)
|
|
|
|
(***********************************************************************)
|
|
|
|
|
|
|
|
(* $Id$ *)
|
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
(* Toplevel directives *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
open Format
|
1995-05-04 03:15:53 -07:00
|
|
|
open Misc
|
|
|
|
open Longident
|
|
|
|
open Path
|
1996-09-23 04:32:19 -07:00
|
|
|
open Types
|
1995-05-04 03:15:53 -07:00
|
|
|
open Emitcode
|
1995-09-14 04:53:55 -07:00
|
|
|
open Trace
|
1995-05-04 03:15:53 -07:00
|
|
|
open Toploop
|
|
|
|
|
2000-04-10 07:59:29 -07:00
|
|
|
(* The standard output formatter *)
|
|
|
|
let std_out = std_formatter
|
2000-03-06 14:12:09 -08:00
|
|
|
|
1995-05-04 03:15:53 -07:00
|
|
|
(* To quit *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_quit () = exit 0
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
let _ = Hashtbl.add directive_table "quit" (Directive_none dir_quit)
|
|
|
|
|
|
|
|
(* To add a directory to the load path *)
|
|
|
|
|
|
|
|
let dir_directory s =
|
2001-08-28 07:47:48 -07:00
|
|
|
let d = expand_directory Config.standard_library s in
|
|
|
|
Config.load_path := d :: !Config.load_path;
|
|
|
|
Dll.add_path [d];
|
1995-05-04 03:15:53 -07:00
|
|
|
Env.reset_cache()
|
|
|
|
|
|
|
|
let _ = Hashtbl.add directive_table "directory" (Directive_string dir_directory)
|
|
|
|
|
|
|
|
(* To change the current directory *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_cd s = Sys.chdir s
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
let _ = Hashtbl.add directive_table "cd" (Directive_string dir_cd)
|
|
|
|
|
|
|
|
(* Load in-core a .cmo file *)
|
|
|
|
|
1996-02-18 06:46:22 -08:00
|
|
|
exception Load_failed
|
|
|
|
|
2000-03-26 07:50:58 -08:00
|
|
|
let check_consistency ppf filename compunit =
|
2000-03-27 06:10:46 -08:00
|
|
|
Bytelink.check_consistency filename compunit;
|
|
|
|
(* Check consistency of unit against its .cmi, if it can be found *)
|
|
|
|
try
|
|
|
|
let crc_intf = Env.crc_of_unit compunit.cu_name in
|
|
|
|
let crc_impl =
|
|
|
|
try List.assoc compunit.cu_name compunit.cu_imports
|
|
|
|
with Not_found -> assert false in
|
|
|
|
if crc_intf <> crc_impl then begin
|
|
|
|
fprintf ppf "@[<hv 0>File %s is not up-to-date with respect to@ \
|
|
|
|
interface %s@]@."
|
|
|
|
filename compunit.cu_name;
|
2000-03-26 07:50:58 -08:00
|
|
|
raise Load_failed
|
2000-03-27 06:10:46 -08:00
|
|
|
end
|
|
|
|
with Not_found ->
|
|
|
|
(* Couldn't find .cmi, ignore it (or should we print a warning?) *)
|
|
|
|
()
|
2000-03-26 07:50:58 -08:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let load_compunit ic filename ppf compunit =
|
2000-03-26 07:50:58 -08:00
|
|
|
check_consistency ppf filename compunit;
|
1996-02-18 06:46:22 -08:00
|
|
|
seek_in ic compunit.cu_pos;
|
1996-05-28 05:43:41 -07:00
|
|
|
let code_size = compunit.cu_codesize + 8 in
|
1996-02-18 06:46:22 -08:00
|
|
|
let code = Meta.static_alloc code_size in
|
|
|
|
unsafe_really_input ic code 0 compunit.cu_codesize;
|
1996-05-28 05:43:41 -07:00
|
|
|
String.unsafe_set code compunit.cu_codesize (Char.chr Opcodes.opRETURN);
|
1997-07-03 07:32:35 -07:00
|
|
|
String.unsafe_blit "\000\000\000\001\000\000\000" 0
|
|
|
|
code (compunit.cu_codesize + 1) 7;
|
1996-02-18 06:46:22 -08:00
|
|
|
let initial_symtable = Symtable.current_state() in
|
|
|
|
Symtable.patch_object code compunit.cu_reloc;
|
|
|
|
Symtable.update_global_table();
|
|
|
|
begin try
|
2001-02-12 06:32:38 -08:00
|
|
|
may_trace := true;
|
|
|
|
ignore((Meta.reify_bytecode code code_size) ());
|
|
|
|
may_trace := false;
|
1996-02-18 06:46:22 -08:00
|
|
|
with exn ->
|
2001-02-12 06:32:38 -08:00
|
|
|
may_trace := false;
|
1996-02-18 06:46:22 -08:00
|
|
|
Symtable.restore_state initial_symtable;
|
2000-03-06 14:12:09 -08:00
|
|
|
print_exception_outcome ppf exn;
|
1996-02-18 06:46:22 -08:00
|
|
|
raise Load_failed
|
|
|
|
end
|
|
|
|
|
2002-02-07 18:56:04 -08:00
|
|
|
let load_file ppf name =
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
|
|
|
let filename = find_in_path !Config.load_path name in
|
|
|
|
let ic = open_in_bin filename in
|
|
|
|
let buffer = String.create (String.length Config.cmo_magic_number) in
|
|
|
|
really_input ic buffer 0 (String.length Config.cmo_magic_number);
|
2002-02-07 18:56:04 -08:00
|
|
|
let success = try
|
1996-02-18 06:46:22 -08:00
|
|
|
if buffer = Config.cmo_magic_number then begin
|
|
|
|
let compunit_pos = input_binary_int ic in (* Go to descriptor *)
|
|
|
|
seek_in ic compunit_pos;
|
2002-02-07 18:56:04 -08:00
|
|
|
load_compunit ic filename ppf (input_value ic : compilation_unit);
|
|
|
|
true
|
1996-02-18 06:46:22 -08:00
|
|
|
end else
|
|
|
|
if buffer = Config.cma_magic_number then begin
|
|
|
|
let toc_pos = input_binary_int ic in (* Go to table of contents *)
|
|
|
|
seek_in ic toc_pos;
|
2001-08-28 07:47:48 -07:00
|
|
|
let lib = (input_value ic : library) in
|
|
|
|
begin try
|
2001-10-30 01:32:32 -08:00
|
|
|
Dll.open_dlls (List.map Dll.extract_dll_name lib.lib_dllibs)
|
2001-08-28 07:47:48 -07:00
|
|
|
with Failure reason ->
|
|
|
|
fprintf ppf "Cannot load required shared library: %s.@." reason;
|
|
|
|
raise Load_failed
|
|
|
|
end;
|
2002-02-07 18:56:04 -08:00
|
|
|
List.iter (load_compunit ic filename ppf) lib.lib_units;
|
|
|
|
true
|
|
|
|
end else begin
|
|
|
|
fprintf ppf "File %s is not a bytecode object file.@." name;
|
|
|
|
false
|
|
|
|
end
|
|
|
|
with Load_failed -> false in
|
|
|
|
close_in ic;
|
|
|
|
success
|
|
|
|
with Not_found -> fprintf ppf "Cannot find file %s.@." name; false
|
|
|
|
|
|
|
|
let dir_load ppf name = ignore (load_file ppf name)
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-04-10 07:59:29 -07:00
|
|
|
let _ = Hashtbl.add directive_table "load" (Directive_string (dir_load std_out))
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
(* Load commands from a file *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_use ppf name = ignore(Toploop.use_file ppf name)
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-04-10 07:59:29 -07:00
|
|
|
let _ = Hashtbl.add directive_table "use" (Directive_string (dir_use std_out))
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
(* Install, remove a printer *)
|
|
|
|
|
2001-07-03 04:04:10 -07:00
|
|
|
type 'a printer_type_new = Format.formatter -> 'a -> unit
|
|
|
|
type 'a printer_type_old = 'a -> unit
|
|
|
|
|
|
|
|
let match_printer_type ppf desc typename =
|
|
|
|
let (printer_type, _) =
|
|
|
|
try
|
|
|
|
Env.lookup_type (Ldot(Lident "Topdirs", typename)) !toplevel_env
|
|
|
|
with Not_found ->
|
|
|
|
fprintf ppf "Cannot find type Topdirs.%s.@." typename;
|
|
|
|
raise Exit in
|
|
|
|
Ctype.init_def(Ident.current_time());
|
|
|
|
Ctype.begin_def();
|
|
|
|
let ty_arg = Ctype.newvar() in
|
|
|
|
Ctype.unify !toplevel_env
|
|
|
|
(Ctype.newconstr printer_type [ty_arg])
|
|
|
|
(Ctype.instance desc.val_type);
|
|
|
|
Ctype.end_def();
|
|
|
|
Ctype.generalize ty_arg;
|
|
|
|
ty_arg
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let find_printer_type ppf lid =
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
|
|
|
let (path, desc) = Env.lookup_value lid !toplevel_env in
|
2001-07-03 04:04:10 -07:00
|
|
|
let (ty_arg, is_old_style) =
|
|
|
|
try
|
|
|
|
(match_printer_type ppf desc "printer_type_new", false)
|
|
|
|
with Ctype.Unify _ ->
|
|
|
|
(match_printer_type ppf desc "printer_type_old", true) in
|
|
|
|
(ty_arg, path, is_old_style)
|
1995-05-04 03:15:53 -07:00
|
|
|
with
|
2000-03-06 14:12:09 -08:00
|
|
|
| Not_found ->
|
|
|
|
fprintf ppf "Unbound value %a.@." Printtyp.longident lid;
|
|
|
|
raise Exit
|
1996-05-20 09:43:29 -07:00
|
|
|
| Ctype.Unify _ ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "%a has a wrong type for a printing function.@."
|
1995-05-04 03:15:53 -07:00
|
|
|
Printtyp.longident lid;
|
2000-03-06 14:12:09 -08:00
|
|
|
raise Exit
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_install_printer ppf lid =
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
2001-07-03 04:04:10 -07:00
|
|
|
let (ty_arg, path, is_old_style) = find_printer_type ppf lid in
|
|
|
|
let v = eval_path path in
|
|
|
|
let print_function =
|
|
|
|
if is_old_style then
|
|
|
|
(fun formatter repr -> (Obj.obj v) (Obj.obj repr))
|
|
|
|
else
|
|
|
|
(fun formatter repr -> (Obj.obj v) formatter (Obj.obj repr)) in
|
|
|
|
install_printer path ty_arg print_function
|
2000-03-06 14:12:09 -08:00
|
|
|
with Exit -> ()
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_remove_printer ppf lid =
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
2001-07-03 04:04:10 -07:00
|
|
|
let (ty_arg, path, is_old_style) = find_printer_type ppf lid in
|
1997-03-22 12:16:52 -08:00
|
|
|
begin try
|
2000-11-07 05:18:20 -08:00
|
|
|
remove_printer path
|
1997-03-22 12:16:52 -08:00
|
|
|
with Not_found ->
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "No printer named %a.@." Printtyp.longident lid
|
1997-03-22 12:16:52 -08:00
|
|
|
end
|
2000-03-06 14:12:09 -08:00
|
|
|
with Exit -> ()
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
let _ = Hashtbl.add directive_table "install_printer"
|
2000-04-10 07:59:29 -07:00
|
|
|
(Directive_ident (dir_install_printer std_out))
|
1995-05-04 03:15:53 -07:00
|
|
|
let _ = Hashtbl.add directive_table "remove_printer"
|
2000-04-10 07:59:29 -07:00
|
|
|
(Directive_ident (dir_remove_printer std_out))
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
(* The trace *)
|
|
|
|
|
1995-09-14 04:53:55 -07:00
|
|
|
external current_environment: unit -> Obj.t = "get_current_environment"
|
1995-05-04 03:15:53 -07:00
|
|
|
|
1998-09-07 00:55:38 -07:00
|
|
|
let tracing_function_ptr =
|
|
|
|
get_code_pointer
|
|
|
|
(Obj.repr (fun arg -> Trace.print_trace (current_environment()) arg))
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_trace ppf lid =
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
|
|
|
let (path, desc) = Env.lookup_value lid !toplevel_env in
|
1996-05-22 09:21:53 -07:00
|
|
|
(* Check if this is a primitive *)
|
|
|
|
match desc.val_kind with
|
2000-03-06 14:12:09 -08:00
|
|
|
| Val_prim p ->
|
|
|
|
fprintf ppf "%a is an external function and cannot be traced.@."
|
|
|
|
Printtyp.longident lid
|
1996-05-22 09:21:53 -07:00
|
|
|
| _ ->
|
|
|
|
let clos = eval_path path in
|
|
|
|
(* Nothing to do if it's not a closure *)
|
2002-02-08 22:44:14 -08:00
|
|
|
if Obj.is_block clos && Obj.tag clos = Obj.closure_tag then begin
|
1996-05-22 09:21:53 -07:00
|
|
|
match is_traced clos with
|
2000-03-06 14:12:09 -08:00
|
|
|
| Some opath ->
|
|
|
|
fprintf ppf "%a is already traced (under the name %a).@."
|
|
|
|
Printtyp.path path
|
|
|
|
Printtyp.path opath
|
1996-05-22 09:21:53 -07:00
|
|
|
| None ->
|
|
|
|
(* Instrument the old closure *)
|
|
|
|
traced_functions :=
|
|
|
|
{ path = path;
|
|
|
|
closure = clos;
|
1998-09-07 00:55:38 -07:00
|
|
|
actual_code = get_code_pointer clos;
|
1996-05-22 09:21:53 -07:00
|
|
|
instrumented_fun =
|
2000-03-06 14:12:09 -08:00
|
|
|
instrument_closure !toplevel_env lid ppf desc.val_type }
|
1996-05-22 09:21:53 -07:00
|
|
|
:: !traced_functions;
|
1998-09-07 00:55:38 -07:00
|
|
|
(* Redirect the code field of the closure to point
|
|
|
|
to the instrumentation function *)
|
|
|
|
set_code_pointer clos tracing_function_ptr;
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "%a is now traced.@." Printtyp.longident lid
|
|
|
|
end else fprintf ppf "%a is not a function.@." Printtyp.longident lid
|
|
|
|
with
|
|
|
|
| Not_found -> fprintf ppf "Unbound value %a.@." Printtyp.longident lid
|
|
|
|
|
|
|
|
let dir_untrace ppf lid =
|
1995-05-04 03:15:53 -07:00
|
|
|
try
|
|
|
|
let (path, desc) = Env.lookup_value lid !toplevel_env in
|
|
|
|
let rec remove = function
|
2000-03-06 14:12:09 -08:00
|
|
|
| [] ->
|
|
|
|
fprintf ppf "%a was not traced.@." Printtyp.longident lid;
|
1995-05-04 03:15:53 -07:00
|
|
|
[]
|
1995-09-14 04:53:55 -07:00
|
|
|
| f :: rem ->
|
|
|
|
if Path.same f.path path then begin
|
1998-09-07 00:55:38 -07:00
|
|
|
set_code_pointer (eval_path path) f.actual_code;
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "%a is no longer traced.@." Printtyp.longident lid;
|
1995-05-04 03:15:53 -07:00
|
|
|
rem
|
1995-09-14 04:53:55 -07:00
|
|
|
end else f :: remove rem in
|
|
|
|
traced_functions := remove !traced_functions
|
2000-03-06 14:12:09 -08:00
|
|
|
with
|
|
|
|
| Not_found -> fprintf ppf "Unbound value %a.@." Printtyp.longident lid
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
let dir_untrace_all ppf () =
|
1995-05-04 03:15:53 -07:00
|
|
|
List.iter
|
1995-09-14 04:53:55 -07:00
|
|
|
(fun f ->
|
1998-09-07 00:55:38 -07:00
|
|
|
set_code_pointer (eval_path f.path) f.actual_code;
|
2000-03-06 14:12:09 -08:00
|
|
|
fprintf ppf "%a is no longer traced.@." Printtyp.path f.path)
|
1995-09-14 04:53:55 -07:00
|
|
|
!traced_functions;
|
|
|
|
traced_functions := []
|
1995-05-04 03:15:53 -07:00
|
|
|
|
2000-08-23 10:13:09 -07:00
|
|
|
let parse_warnings ppf iserr s =
|
|
|
|
try Warnings.parse_options iserr s
|
2000-03-06 14:12:09 -08:00
|
|
|
with Arg.Bad err -> fprintf ppf "%s.@." err
|
|
|
|
|
|
|
|
let _ =
|
2000-04-10 07:59:29 -07:00
|
|
|
Hashtbl.add directive_table "trace" (Directive_ident (dir_trace std_out));
|
|
|
|
Hashtbl.add directive_table "untrace" (Directive_ident (dir_untrace std_out));
|
2000-03-06 14:12:09 -08:00
|
|
|
Hashtbl.add directive_table
|
2000-04-10 07:59:29 -07:00
|
|
|
"untrace_all" (Directive_none (dir_untrace_all std_out));
|
1995-05-04 03:15:53 -07:00
|
|
|
|
|
|
|
(* Control the printing of values *)
|
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
Hashtbl.add directive_table "print_depth"
|
|
|
|
(Directive_int(fun n -> max_printer_depth := n));
|
|
|
|
Hashtbl.add directive_table "print_length"
|
|
|
|
(Directive_int(fun n -> max_printer_steps := n));
|
1999-12-03 02:26:08 -08:00
|
|
|
|
|
|
|
(* Set various compiler flags *)
|
|
|
|
|
2000-03-24 11:31:25 -08:00
|
|
|
Hashtbl.add directive_table "labels"
|
2000-03-06 14:12:09 -08:00
|
|
|
(Directive_bool(fun b -> Clflags.classic := not b));
|
1999-12-03 02:26:08 -08:00
|
|
|
|
2000-03-06 14:12:09 -08:00
|
|
|
Hashtbl.add directive_table "warnings"
|
2000-08-23 10:13:09 -07:00
|
|
|
(Directive_string (parse_warnings std_out false));
|
|
|
|
|
|
|
|
Hashtbl.add directive_table "warn_error"
|
|
|
|
(Directive_string (parse_warnings std_out true));
|