Do you use a debugger?

I’ve never used debuggers, and that’s not to say I don’t write bugs…I’ve just never developed skills with them, so I do a lot of print debugging.

  1. Who’s using a debugger? What’s you setup?
  2. What useful information does a debugger offer that I otherwise might not see?
  3. What’s debug info?
  4. Are debuggers only for IDEs, or are there standalone debugging tools?
  5. What are the legacy debugging tools?
  6. What are the solidly useful and standard debugging tools?
  7. What would you consider are the new / up and coming / promising debugging tools and what do they do differently?

I really like nnd.
It’s fast, it supports watchers, registers etc… It shows both source code and assembly at the same time.
It also easy to use. In my programs i put a @breakpoint() and then just nnd your_program your arguments.

3 Likes

I was a heavy user of “Debugger as a REPL with context” when I was writing Kotlin/Java :scream: 10 years ago:

I mostly avoided debuggers since, as I switched to native languages, and debuggers for native languages are abysmal.

I do occasionally still reach for a debugger when something goes really wrong (“I am in a signal handler, but where’s my stack?” kind of wrong), and its been a uniformly mixed experience — half of the time debugger itself crashes on you, and the other half it prints random garbage, and anything more complicated than “what’s the contents of this register/memory” is untrustworthy.

I’ve been using CodeLLDB with VS Code.

On x86_64, Zig no longer uses the LLVM backend by default, so I currently need to build with -fllvm for CodeLLDB to work properly.

Sometimes I also install the unit test artifact from build.zig so I can debug tests directly:

test_step.dependOn(&b.addInstallArtifact(mod_test, .{
    .dest_sub_path = "../test/test",
}).step);

This generates a standalone test executable that can be launched directly from the debugger.

In cases that lead to segmentation faults, variables in memory are often already corrupted by the time the crash happens.

I use the debugger to inspect how badly the memory is corrupted and try to infer when and where things first went wrong.

Heya !

  1. I’m mainly using gdb by hand, aka. running gdb zig-out/bin/program. I’ve recently added nvim-dap (like a plugin to your editor you can think) to my nvim workflow to have integrations in my editor. DAP is a protocol for an editor / client to communicate with the debugger.
  2. In your debugger it is easier to see, step by step, what is your program doing. It avoids to add multiple print statement and recompile each time. You have also the ability to modify values on the fly, add breakpoints if and only if a values has changed to something, etc. It is a very powerful tool.
  3. Debug info is information attached to a binary that helps the debugger know what bytes in the compiled code correspond to what code in text in your files
  4. There are a lot of standalone debugging tools, most of them I would say are standalone. For zig / c / c++ / rust you might consider lldb (llvm’s debugger, preferred) or gdb (I chose it just because I have familiarity with it)
  5. I don’t know ? I’m not really sure what you refer by that
  6. I would advise lldb, don’t forget that you need to compile the binary using llvm (change your build.zig) to see correct information
  7. I’m not aware of new and upcoming debuggers, but others will know more about that subject than me
1 Like

additional 2 cents to the picture

2 main flows of debugger usage:

  • walking
  • catching

First one I walking within code, step by step, check logic, routing, values of variables, stack and so on

Second - run whole application or test and when breakpoint raised or debugger catched segfaults and so on - check status of program…

I always use debuggers, it does not mean that my code does not contain prints…

As you can see my Zig dev. env - JetBrains CLion (free for oss) + ZigBrains plugin + Gdb - Linux

On Windows - almost the same , just lldb instead of gdb (iirc)

CLion Debug configurations

take a look Debugging Zig (with a debugger) - it contains a lot of information

Happy debugging

I only use them for strange bugs in in pretty much all cases I use a time travelling debugger for these cases.

Sadly there are no good ones with wide platform support except Undo UDB (which isn’t free).

Not very “general purpose”, but when I’m doing embedded Zig on an stm32 I use the Stm32CubeProgrammer debugger window to get some clues as to what’s gone horribly wrong. It typically will give a code for what has caused a hard fault if one has gone off, as well as the instruction address that may have lead to the fault.

It also gives register values which has made it nice to see when a sentinel value is showing up, yet again cluing me in to what has gone horribly wrong.

I can second this, although it has some quirks regarding some Zig language constructs its an amazing debugging experience.

With all due respect to those who like to debug Zig, it’s just a nightmare. My only experience with Zig debugging was based on the invisibility of variables after exiting the main function and entering another one. Therefore, I gave up on these futile attempts to debug. I hope that this will be fixed someday.