Given the following obviously wrong program written in the file
uncaught.ml
, (the program raises an uncaught exception
Not_found
, when evaluating the expression find_address
"INRIA", since "IRIA" (and not "INRIA") has been added to the list of
adresses):
(* file uncaught.ml *) let l = ref [];; let find_address name = List.assoc name !l;; let add_address name adress = l := (name, address) :: ! l;; add_address "IRIA" "Rocquencourt";; print_string (find_address "INRIA"); print_newline ();;If you want to find where and why this exception has been raised, you have to:
ocamlc -g uncaught.ml
ocamldebug a.out
Then the debugger writes a banner and a prompt:
Objective Caml Debugger version 3.1 (ocd)
Type r
(for run); you get
(ocd) r Loading program... done. Time : 12 Program end. Uncaught exception: Not_found (ocd)Self explanatory, is'nt it ? So, you want to step backward to set the program counter before the time the exception is raised; hence type in
b
as
backstep
, and you get
(ocd) b Time : 11 - pc : 15500 - module List 143 [] -> <|b|>raise Not_foundThe debugger tells you that you are in module
List
,
inside a pattern matching on a list that already chose the
[]
case and is about to execute raise
Not_found
, since the program is stopped just before this
expression (as witnessed by the <|b|>
mark).
But, as you know, you want the debugger to tell you which procedure calls the one from list, and may who calls the procedure that call the one from list; hence, you want a backtrace of the execution stack:
(ocd) bt #0 Pc : 15500 List char 3562 #1 Pc : 19128 Uncaught char 221So the last function called is from module List at charadcter 3562, that is :
let rec assoc x = function [] -> raise Not_found ^ | (a,b)::l -> if a = x then b else assoc x lThe function that calls it is in module
Uncaught
, file
uncaught.ml
char 221:
print_string (find_address "INRIA"); print_newline ();; ^
If you're developping a program you can compile it with the
-g
option, to be ready to debug it if necessary. Hence,
to find your spurious exception you just need to type
ocamldebug
a.out
, then r
,
b
, and bt
gives you the backtrace.
To get more info about the current status of the debugger you can ask it directly at the toplevel prompt of the debugger; for instance:
(ocd) info breakpoints No breakpoint. (ocd) help break 1 15396 in List, character 3539 break : Set breakpoint at specified line or function. Syntax: break function-name break @ [module] linenum break @ [module] # characternum
Let's set up a breakpoint and rerun the entire program from the
beginning ((g)oto 0
then (r)un
):
(ocd) break @Uncaught 9 Breakpoint 3 at 19112 : file Uncaught, line 9 column 34 (ocd) g 0 Time : 0 Beginning of program. (ocd) r Time : 6 - pc : 19112 - module Uncaught Breakpoint : 1 9 add "IRIA" "Rocquencourt"<|a|>;;Then, we can step and find what happens when find_address is about to be called
(ocd) s Time : 7 - pc : 19012 - module Uncaught 5 let find_address name = <|b|>List.assoc name !l;; (ocd) p name name : string = "INRIA" (ocd) p !l $1 : (string * string) list = ["IRIA", "Rocquencourt"] (ocd)Now we can guess why
List.assoc
will fail to find "INRIA"
in the list...
Note also that under Emacs you call the debugger using
ESC-x
camldebug
a.out
. Then
emacs will set you directly to the file and character reported by the
debugger, and you can step back and forth using ESC-b
and
ESC-s
, you can set up break points using
CTRL-X
space, and so on...
Contact the author Pierre.Weis@inria.fr