The debugging facility in Caml

Contact the author Pierre.Weis@inria.fr

Created November 2000 the first. Let me propose this little tutorial for the debugger...

Launching the debugger

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:
  1. compile the program in debug mode:
    ocamlc -g uncaught.ml
  2. launch the debugger:
ocamldebug a.out Then the debugger writes a banner and a prompt:
        Objective Caml Debugger version 3.1

(ocd)

Finding the cause of a spurious exception

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_found
The 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 221
So 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 l
The function that calls it is in module Uncaught, file uncaught.ml char 221:
print_string (find_address "INRIA"); print_newline ();;
                                  ^

More advanced features

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.

Help and info in the debugger

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

Setting break points

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...

Debugging under Emacs

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...


Caml home page Last modified: jeudi 2 novembre 2000
Copyright © 1995 - 2004, INRIA all rights reserved.

Contact the author Pierre.Weis@inria.fr