Skip to content

Debug C and C++ with Bugsaur

Adapter: codelldb — the same adapter used for Rust.

No auto-detection

bugsaur init recognises Rust, Go, PHP and Python by their marker files. C and C++ have no such marker — Makefile, CMakeLists.txt, a bare directory of .c files are all plausible and none is definitive — so detection does not attempt it.

Nothing else is missing: the adapter is the same one Rust uses, and it debugs C and C++ perfectly well. You write the profile by hand — and the fixtures below are there to be copied.

Write the profile

Create .bugsaur/config.toml in the project root yourself:

version = 1
default = "app"

[profiles.app]
adapter = "codelldb"
program = "build/app"

program is the compiled binary, as a path relative to the project root. The root is the directory containing .bugsaur/.

A working example in this repository

Two fixtures show the whole setup end to end:

Fixture What it shows
fixtures/c-hello a C program with a nested struct and arrays, built by its own Makefile
fixtures/cpp-hello the same shape in C++, with std::string and std::vector

Each carries the .bugsaur/config.toml above, verbatim. Build and launch them with make fixture-c / make gui-c, and the -cpp counterparts.

Both are covered by live tests against a real CodeLLDB — make live-codelldb-c and make live-codelldb-cpp — so the claim this page makes is checked, not assumed.

Build with debug information

The binary must carry debug info, or the debugger has nothing to work with:

cc -g -O0 -c -o build/main.o src/main.c
cc -g -O0 -o build/app build/main.o
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build

-g produces the debug information; -O0 keeps the optimiser from rearranging the code out from under you. With optimisation on, breakpoints land on unexpected lines, variables read as "optimized out", and stepping jumps around.

On macOS, keep the object files

Compiling and linking in one command works everywhere — except that on macOS it produces a binary the debugger cannot read.

Mach-O does not carry DWARF in the executable. The compiler leaves it in the object files and writes a debug map into the binary: absolute paths pointing back at those .o files. cc -g -O0 -o build/app src/main.c compiles into a temporary directory and deletes the object file right after linking, so every path in the map dangles. The session starts, the process runs, and there are no variables and no line numbers — which reads like a broken debugger rather than a broken build.

Compiling separately, as above, keeps build/main.o in place and the map valid. CMake already does this. To check a binary you did not build yourself, every path here must exist:

dsymutil -s build/app | grep OSO

Linux is unaffected: there the DWARF goes straight into the executable.

Bugsaur does not build C or C++ for you — build first, then launch.

Arguments, working directory, environment

[profiles.app]
adapter = "codelldb"
program = "build/app"
args = ["--config", "${root}/configs/dev.yaml", "--verbose"]
cwd = "."
env_file = ".env"
env = { LOG_LEVEL = "debug" }
  • args — the debuggee's command line. ${root} expands to the absolute project root.
  • cwd — the working directory. Without it, the project root is used, not the directory of the binary.
  • env_file then env, with env winning. A named but missing env_file is a launch error, not a silent skip.

Details: Configuration → Program arguments and Environment variables.

Attach to a running process

[profiles.attach]
adapter = "codelldb"
program = "build/app"
mode = "attach"

[profiles.attach.launch_arguments]
pid = 4242

Nothing is built or launched in attach mode — the process is already running. See Guides → Attach to a running process.

Debugging a core dump or a custom LLDB setup

Anything CodeLLDB accepts that has no field in the profile schema goes through launch_arguments, which is passed to the adapter as-is:

[profiles.core]
adapter = "codelldb"
program = "build/app"

[profiles.core.launch_arguments]
coreDumpPath = "${root}/crash.core"

This is the escape hatch, and it overrides whatever Bugsaur generated for that key. See Configuration → Reference.

Diagnostics

Symptom Likely cause Where to look
program is not readable the binary is not built, or program points elsewhere check the path against the build output
Session never starts codelldb not on PATH Adapter fails to start
Variables show "optimized out" built with optimisation rebuild with -g -O0
No variables and no line numbers at all, on macOS compiled and linked in one command, so the debug map points at deleted object files dsymutil -s <binary> \| grep OSO; compile to .o first
Breakpoint on a line that never binds the line is not executable, or was optimised away Breakpoints not hit
Stack has frames but no source sources moved since the build, or built in a container Source not found