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:
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:
-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:
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_filethenenv, withenvwinning. A named but missingenv_fileis 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 |