Author: Christian.Queinnec@lip6.fr

## Debugging Tools

There are two debugging tools. The first is a trace mechanism that can be used on the global functions in the toplevel loop. The second tool is a debugger that is not used in the normal toplevel loop. After a first program run it is possible to go back to breakpoints, and to inspect values or to restart certain functions with different arguments. This second tool only runs under Unix, because it duplicates the running process via a `fork` (see page ??).

### Trace

The trace of a function is the list of the values of its parameters together with its result in the course of a program run.
The trace commands are directives in the toplevel loop. They allow to trace a function, stop its trace or to stop all active traces. These three directives are shown in the table below.

#trace `name` | trace function `name`
#untrace `name` | stop tracing function `name`
#untrace_all | stop all traces

Here is a first example of the definition of a function `f`:

    # let f x = x + 1;;
    val f : int -> int = <fun>
    # f 4;;
    - : int = 5

Now we will trace this function, so that its arguments and its return value will be shown.

    #  #trace f;;
    f is now traced.
    # f 4;;
    f <-- 4
    f --> 5
    - : int = 5

Passing of the argument 4 to `f` is shown, then the function `f` calculates the desired value and the result is returned and also shown. The arguments of a function call are indicated by a left arrow and the return value by an arrow to the right.

#### Functions of Several Arguments

Functions of several arguments (or functions returning a closure) are also traceable. Each argument passed is shown. To distinguish the different closures, the number of arguments already passed to the closures is marked with a `*`. Let the function `verif_div` take 4 numbers (a, b, q, r) corresponding to the integer division: a = bq + r.

    # let verif_div a b q r =
       a = b*q + r;;
    val verif_div : int -> int -> int -> int -> bool = <fun>
    # verif_div 11 5 2 1;;
    - : bool = true

Its trace shows the passing of 4 arguments:

    #  #trace verif_div;;
    verif_div is now traced.
    # verif_div 11 5 2 1;;
    verif_div <-- 11
    verif_div --> <fun>
    verif_div* <-- 5
    verif_div* --> <fun>
    verif_div** <-- 2
    verif_div** --> <fun>
    verif_div*** <-- 1
    verif_div*** --> true
    - : bool = true

#### Recursive Functions

The trace gives valuable information about recursive functions, e.g. poor stopping criteria are easily detected.
Let the function `belongs_to` which tests whether an integer belongs to a list of integers be defined in the following manner:

    # let rec belongs_to (e : int) l = match l with
       [] -> false
     | t::q -> (e = t) || belongs_to e q ;;
    val belongs_to : int -> int list -> bool = <fun>
    # belongs_to 4 [3;5;7] ;;
    - : bool = false
    # belongs_to 4 [1; 2; 3; 4; 5; 6; 7; 8] ;;
    - : bool = true

The trace of the function invocation belongs_to 4 [3;5;7] will show the four calls of this function and the results returned.

    #  #trace belongs_to ;;
    belongs_to is now traced.
    # belongs_to 4 [3;5;7] ;;
    belongs_to <-- 4
    belongs_to --> <fun>
    belongs_to* <-- [3; 5; 7]
    belongs_to <-- 4
    belongs_to --> <fun>
    belongs_to* <-- [5; 7]
    belongs_to <-- 4
    belongs_to --> <fun>
    belongs_to* <-- [7]
    belongs_to <-- 4
    belongs_to --> <fun>
    belongs_to* <-- []
    belongs_to* --> false
    belongs_to* --> false
    belongs_to* --> false
    belongs_to* --> false
    - : bool = false

At each call of the function `belongs_to` the argument 4 and the list to search in are passed as arguments. When the list becomes empty, the functions return `false` as a return value which is passed along to each waiting recursive invocation.
The following example shows the section of the list when the element searched for appears:

    # belongs_to 4 [1; 2; 3; 4; 5; 6; 7; 8] ;;
    belongs_to <-- 4
    belongs_to --> <fun>
    belongs_to* <-- [1; 2; 3; 4; 5; 6; 7; 8]
    belongs_to <-- 4
    belongs_to --> <fun>
    belongs_to* <-- [2; 3; 4; 5; 6; 7; 8]
    belongs_to <-- 4
    belongs_to --> <fun>
    belongs_to* <-- [3; 4; 5; 6; 7; 8]
    belongs_to <-- 4
    belongs_to --> <fun>
    belongs_to* <-- [4; 5; 6; 7; 8]
    belongs_to* --> true
    belongs_to* --> true
    belongs_to* --> true
    belongs_to* --> true
    - : bool = true

As soon as `4` becomes head of the list, the functions return `true` which gets passed along to each waiting recursive invocation.
If the sequence of statements around `||` were changed, the function `belongs_to` would still return the right result but would always have to go over the complete list.

    # let rec belongs_to (e : int) = function
         [] -> false
       | t::q ->   belongs_to e q || (e = t) ;;
    val belongs_to : int -> int list -> bool = <fun>
    # #trace belongs_to ;;
    belongs_to is now traced.
    # belongs_to 3 [3;5;7] ;;
    belongs_to <-- 3
    belongs_to --> <fun>
    belongs_to* <-- [3; 5; 7]
    belongs_to <-- 3
    belongs_to --> <fun>
    belongs_to* <-- [5; 7]
    belongs_to <-- 3
    belongs_to --> <fun>
    belongs_to* <-- [7]
    belongs_to <-- 3
    belongs_to --> <fun>
    belongs_to* <-- []
    belongs_to* --> false
    belongs_to* --> false
    belongs_to* --> false
    belongs_to* --> true
    - : bool = true

Even though `3` is the first element of the list, it is traversed completely. So, trace also provides a mechanism for the efficiency analysis of recursive functions.

#### Polymorphic Functions

The trace does not show the value corresponding to an argument of a parameterized type. If for example the function `belongs_to` can be written without an explicit type constraint:

    # let rec belongs_to e l = match l with
       [] -> false
     | t::q -> (e = t) || belongs_to e q ;;
    val belongs_to : 'a -> 'a list -> bool = <fun>

The type of the function `belongs_to` is now polymorphic, and the trace does no longer show the value of its arguments but replaces them with the indication (`poly`).

    #  #trace belongs_to ;;
    belongs_to is now traced.
    # belongs_to 3 [2;3;4] ;;
    belongs_to <-- <poly>
    belongs_to --> <fun>
    belongs_to* <-- [<poly>; <poly>; <poly>]
    belongs_to <-- <poly>
    belongs_to --> <fun>
    belongs_to* <-- [<poly>; <poly>]
    belongs_to* --> true
    belongs_to* --> true
    - : bool = true

The Objective CAML toplevel loop can only show monomorphic types. Moreover, it only keeps the inferred types of global declarations. Therefore, after compilation of the expression belongs_to 3 [2;3;4], the toplevel loop in fact no longer possesses any further type information about the function `belongs_to` apart form the type 'a -> 'a list -> bool. The (monomorphic) types of 3 and [2;3;4] are lost, because the values do not keep any type information: this is static typing. This is the reason why the trace mechanism attributes the polymorphic types 'a and 'a list to the arguments of the function `belongs_to` and does not show their values.
It is this absence of typing information in values that entails the impossibility of constructing a generic `print` function of type 'a -> unit.

#### Local Functions

Local functions cannot be traced for the same reasons as above, relating again to static typing. Only global type declarations are kept in the environment of the toplevel loop. Still the following programming style is common:

    # let belongs_to e l =
       let rec bel_aux l = match l with
         [] -> false
       | t::q -> (e = t) || (bel_aux q)
       in
         bel_aux l;;
    val belongs_to : 'a -> 'a list -> bool = <fun>

The global function only calls on the local function, which does the interesting part of the work.

#### Notes on Tracing

Tracing is actually the only multi-platform debugging tool. Its two weaknesses are the absence of tracing information for local functions and the inability to show the value of polymorphic parameters. This strongly restricts its usage, mainly during the first steps with the language.

### Debug

`ocamldebug`, is a debugger in the usual sense of the word. It permits step-by-step execution, the insertion of breakpoints and the inspection and modification of values in the environment.
Single-stepping a program presupposes the knowledge of what comprises a program step. In imperative programming this is an easy enough notion: a step corresponds (more or less) to a single instruction of the language. But this definition does not make much sense in functional programming; one instead speaks of program events. These are applications, entries to functions, pattern matching, a conditional, a loop, an element of a sequence, etc.

### Warning

This tool only runs under Unix.

#### Compiling with Debugging Mode

The `-g` compiler option produces a `.cmo` file that allows the generation of the necessary instructions for debugging. Only the bytecode compiler knows about this option. It is necessary to set this option during compilation of the files encompassing an application. Once the executable is produced, execution in debug mode can be accomplished with the following `ocamldebug` command:
`ocamldebug [``options``] executable [``arguments``]`
Take the following example file `fact.ml` which calculates the factorial function:

    let fact n =
      let rec fact_aux p q n =
        if n = 0 then p
        else fact_aux (p+q) p (n-1)
      in
    fact_aux 1 1 n;;

The main program in the file `main.ml` goes off on a long recursion after the call of `Fact.fact` on -1.

    let x = ref 4;;
    let go () =
      x :=  -1;
      Fact.fact !x;;
    go();;

The two files are compiled with the `-g` option:

    $ ocamlc -g -i -o fact.exe fact.ml main.ml
    val fact : int -> int
    val x : int ref
    val go : unit -> int

#### Starting the Debugger

Once an executable is compiled with debug mode, it can be run in this mode.

    $ ocamldebug fact.exe
            Objective Caml Debugger version 3.00

    (ocd)

### Execution Control

Execution control is done via program events. It is possible to go forward and backwards by n program events, or to go forward or backwards to the next breakpoint (or the nth breakpoint). A breakpoint can be set on a function or a program event. The choice of language element is shown by line and column number or the number of characters. This locality may be relative to a module.
In the example below, a breakpoint is set at the fourth line of module `Main`:

    (ocd) step 0
    Loading program... done.
    Time : 0
    Beginning of program.
    (ocd)  break @ Main 4
    Breakpoint 1 at 5028 : file Main, line 4 column 3

The initialisations of the module are done before the actual program. This is the reason the breakpoint at line 4 occurs only after 5028 instructions.
We go forward or backwards in the execution either by program elements or by breakpoints. `run` and `reverse` run the program just to the next breakpoint. The first in the direction of program execution, the second in the backwards direction. The `step` command advanced by 1 or n program elements, entering into functions, `next` steps over them. `backstep` and `previous` respectively do the same in the backwards direction. `finish` finally completes the current functions invocations, whereas `start` returns to the program element before the function invocation.
To continue our example, we go forward to the breakpoint and then execute three program instructions:

    (ocd) run
    Time : 6 - pc : 4964 - module Main
    Breakpoint : 1
    4   <|b|>Fact.fact !x;;
    (ocd) step
    Time : 7 - pc : 4860 - module Fact
    2   <|b|>let rec fact_aux p q n =
    (ocd) step
    Time : 8 - pc : 4876 - module Fact
    6 <|b|>fact_aux 1 1 n;;
    (ocd) step
    Time : 9 - pc : 4788 - module Fact
    3     <|b|>if n = 0 then p

#### Inspection of Values

At a breakpoint, the values of variables in the activation record can be inspected. The `print` and `display` commands output the values associated with a variable according to the different depths.
We will print the value of `n`, then go back three steps to print the contents of `x`:

    (ocd) print n
    n : int = -1
    (ocd) backstep 3
    Time : 6 - pc : 4964 - module Main
    Breakpoint : 1
    4   <|b|>Fact.fact !x;;
    (ocd) print x
    x : int ref = {contents=-1}

Access to the fields of a record or via the index of an array is accepted by the printing commands.

    (ocd) print x.contents
    1 : int = -1

#### Execution Stack

The execution stack permits a visualization of the entanglement of function invocations. The `backtrace` or `bt` command shows the stack of calls. The `up` and `down` commands select the next or preceding activation record. Finally, the `frame` command gives a description of the current record.