The call stack in ocamldebug is the real call stack, so functions that have made a tail call don't show up in it. This is confusing. How can I get a backtrace that includes tail calls?

- 5,047
- 19
- 30

- 32,079
- 16
- 104
- 187
-
Interesting question. I am guessing that it would involve disabling the tail-call optimization, since the program can hardly show stack frames that have been completely overwritten. If someone finds how to do that, you'll probably need to raise the stack limit, too (`ulimit -s` in Bash). – Pascal Cuoq Sep 03 '11 at 17:58
2 Answers
The easiest way is to change your function so that it is not tail-recursive anymore. This is what I use when I want good backtraces displayed when an exception aborts the program (no need for ocamldebug in this case, running the program under OCAMLRUNPARAM="b"
is enough; documentation).
My personal technique is to change the tail call into
let result = <tail call> in result
Ocaml mostly compile the code as it is written, and in this case it's great: the compiler doesn't inline this and you get a nice-looking backtrace. Of course you can easily remove this deoptimization once the bug is found.
(This works fine when you have only a few tail calls; if you have a lot of them, you can wrap the whole function body into a let result = <body> in result
, but I find it a bit less convenient and clear.)
If you need the function to still be taill-call (e.g., you have a OS-set stack size limit that you may exhaust), you could reify the call stack for this function into a data structure, turning
let rec f arg1 arg2 .. argN =
...
f arg1' arg2' .. argN'
into
let rec f stack arg1 arg2 .. argN =
let stack' = (arg1,arg2,..,argN)::stack in
...
f stack' arg1' arg2' .. argN'
Then you can, in a ocamldebug, examine the value of the stack
variable, to get a function-specific stack trace.

- 31,259
- 3
- 78
- 100
-
1Unfortunately I am actually exploring an unfamiliar codebase (Coq), so I don't immediately know which of the possible callers of a function I can see in the backtrace, is the real caller. – Robin Green Sep 04 '11 at 07:54
To see where the real tail call is, I can repeatedly type "start" to reverse execute and pop the stack until I get to the call destination of interest, and then backstep. Laborious, and has to be done on a call-by-call basis, but it works.

- 32,079
- 16
- 104
- 187