What is the current state of debugger support for OCaml? I am aware of ocamldebug but every time I’m trying to use it I feel thrown back to 2000 where it essentially existed in the same form (and still has no command line editing built in). Despite the powerful concept of time traveling, it does not seem very useful today. For example, it can’t be attached to a running program and it does not work with native code. What is the state of GDB support? What debugger would one use on macOS?
I looked at it but also haven’t used it. I agree that is looks nice and it would provide a much nicer interface. It seems to depend on compiler internals, based on currently raised issues.
I agree that debugging in OCaml seems to be stuck in time.
This is extremely unfortunate because it is able to do time traveling (as you mention) which is something that many other languages still cannot boast.
ocamldebugdoes not work properly when there is more than 1 OS thread
- As types are erased during compile time in OCaml, it can be difficult to debug polymorphic functions. Rust and C/C++ monomorphise all code so there is never any confusion about the type of anything in the debugger. Golang and Java have type information available during runtime so again, debugging is easy. In this respect OCaml is similar to Haskell while using the byte-code debugger.
- The future of ocamldebug is unknown on multicore
As far as GDB support is concerned, there was a project to improve GDB support (so you could print out variables like in ocamldebug IIUC) but it never got merged into trunk.
However, if you are interested in low level debugging in gdb, here is a recent answer related to this.
My guess is that
ocamldebug will continue to work for the single domain, single thread case in OCaml 5.00 but ocamldebug is currently broken in multicore there (AFAIK).
As types are erased during compile time in OCaml, it can be difficult to debug polymorphic functions.
I am not sure if this would be away around this: a compiler flag that disregards hiding types - similar to removing all MLI files for debugging. The strong information hiding becomes a disadvantage during debugging.
I think it is likely to be very hard to prevent erasure of types. The whole runtime representation of ocaml data types might need to be changed and new fields to hold type information added?
Curious – What flag is this?
It does not exist. But I believe the debugger has more visibility into values if you remove MLI files that would otherwise restrict the view. Given that MLI files are optional and don’t contain information not present in the corresponding ML file, I could imagine that such a flag could help. Pure speculation, though.
I agree that time travel debugging is useful, but is this something really unique to OCaml? when I last tried to read through the ocamldebug source, I recall that the time travelling is implemented by forking the debugger process no? it probably wouldn’t be that hard to add this into the the debuggers of other languages.
One thing I’ve repeatedly heard on these forums is that the OCaml compiler (if we ignore flambda) doesn’t do any crazy optimisations - given this, shouldn’t a benefit of this be that it should be somewhat simpler to map from emitted code back to the AST/Typed AST? Couldn’t that be used to recover type-information somehow?
Going from byte code back to Typed AST is most likely a hard problem. This is basically doing disassembly of sorts. There is a loss of information so I don’t think full reconstruction is possible. Perhaps if more debugging information was embedded with the bytecode (so ensuring no important information was “lost” in the first place) like DWARF does for executables?? I don’t know much about
ocamldebug / bytecode on an internal level though to say much more…
In general I’m sure a lot is possible. There is the small matter of someone doing it
If I remember correctly,
ocamldebug has access to both type and location information already. But the issue is that the type information is local: in the
Set.add function, the type of sets is concrete but the type of elements is abstract, while in the calling function it’s the reverse. So you should be able to print the skeleton of the tree in the
Set.addfunction, but you can’t print the elements themselves.
While working on
gdb support, Mark Shinwell had experimented with combining typing information from different places (typically different stack frames) to reconstruct more useful types. In theory this should allow printing of sets (almost) as if they were regular data structures. In theory the same could be done for
ocamldebug, but no one has been interested in working on this.
You can find more about Mark’s experiment by searching for
libmonda (Mark had a page describing how it works here, but it’s likely outdated).
Adding better support for OCaml in GDB would have been very welcome. GDB also supports debugging mutli-threaded programs. So it’s really unfortunate that the
libmonda work work did not get up-streamed.
Maybe there wasn’t enough time to get it through the compiler review process?
The state of debugger support (especially native debugger support) in OCaml is pretty unfortunate. It’s a major issue mentioned by a lot of people I know. The Tezos Foundation offered to pay for work towards improving that, but as I recall, OCSF had trouble finding anyone interested in the work.
In real world ocaml. it mentions the GDB support for Ocaml native.
I am testing to use GDB to debug one of my hobby projects in ocaml.
As described in real world ocaml, it is possible to set breakpoints on function (though the function names are mangled, it is very easy to recognize them), and step through it.
However, I can’t figure out how to print the value of local variables. Simply using gdb p, or info locals will show that the variables are not in context, or no locals…
I don’t believe that is possible to see the value of ocaml locals, though I would be happy to be corrected! This was the work that was supposed to happen for gdb but got stalled…
As I remember it, the problem was that the patch in question was very large and invasive, raising real questions about whether the benefit was worth the added complexity. On top of the overly invasive nature of this patch, at the time there were no clearly articulated use-cases for “gdb” debugging, given that historically “printf” seems to have sufficed (I am just stating a fact here; I am aware that to those used to using dedicated debuggers, this may sound a bit cavalier).
All said, my recollection from the discussion is that there is no a priori objection to improving gdb support in the compiler, but it would have to be something much more lightweight and self-contained (ie not needing extensive changes throughout the compilation pipeline) than the previous effort. This probably means aiming for a basic level of support inside gdb instead of something more full-featured.
Having looked at other compilers, it seems like preserving debugging information throughout generally involves pervasive record-keeping.
On the usability front, I recognize that to many of us “printf debugging” is enough, but different people have different styles, and I’ve heard people who have tried to use OCaml bitterly complain about the lack of a debugger. There are also people who claim that more modern debugging paradigms than gdb presents are superior to printf debugging, see, for example: Eyes Above The Waves: Print Debugging Should Go Away
Console.log debugging to figure out a broken control flow.
I think printf debugging vs debuggers is kind of a moot point.
Programmers will simply reach for what is fastest to them. Provide the ability to set a breakpoint in the editor or write a
debugger statement to enter the debugger and start exploring, I’m sure these die hard printf debugging proponents will use it. Personally I always do when it’s simple and there’s no setup involved.
Exploring a live program in a debugger is always fun. I fondly remember cracking – in my youth – Macintosh Common Lisp’s copy protection which was, of course, written in lisp by managing to enter the debugger at an appropriate time and alter the check outcome. Couldn’t be bothered by all this low level assembly cracking :–)