Things you can do with a debugger but not with print debugging
Hardware breakpoints & watchpoints
- Several commenters highlight hardware watchpoints (aka data breakpoints) as a killer feature: break on read/write/exec of a specific memory address or symbol, ideal for tracking memory corruption or invariant violations.
- On common MCUs and CPUs, a debug unit can raise an interrupt when a watched address is touched; debuggers surface this directly at the offending instruction.
- Expression/watch debugging (e.g., breaking when
bufpos < buflenis violated) is cited as another powerful capability, especially combined with reverse execution.
Time‑travel & historical debugging
- Time‑travel / record‑replay tools (rr, UndoDB, WinDbg TTD) are repeatedly praised: record once, then step backward in time to see when corruption occurred.
- This is contrasted with logging, where you often need multiple “add logs, rerun many times” iterations.
- Some note “offline” debugging systems that log everything (or traces with GUIDs per scope) to reconstruct and compare runs over long periods.
Print vs debugger: tradeoffs
- One camp treats debuggers as essential, faster than iterating on
printfonce configured, especially for unknown codebases, third‑party libraries, and large projects where rebuilds are slow. - Another camp prefers print/logging for most bugs, using debuggers only for very low‑level or hard‑to-isolate issues (assembly, watchpoints). Arguments:
- Logs persist, diff easily, can be shared with others or from production.
- Printing is universal across languages and environments.
- Debugger UIs/CLIs can be clumsy or unreliable.
- Some emphasize tracepoints/logpoints as a “best of both worlds”: debugger-managed printing without code edits or cleanup.
Race conditions & timing effects
- Multiple commenters note that both debuggers and print statements can perturb timing and hide races; prints are often seen as less intrusive, but not always.
- Suggestions include ring-buffer logging, binary logs formatted off-device, ftrace/defmt-style approaches, and hardware tools (ICE) for precise timing.
Tooling quality & environment constraints
- Debugger experience varies widely: Visual Studio and browser debuggers are praised; gdb/lldb CLIs and some language ecosystems are seen as painful.
- Constraints cited: remote/locked-down systems, kernels and drivers, embedded targets, proprietary libraries, multi-language stacks, and enormous debug builds.
- In such cases, logging, REPLs, structured tracing, and profilers (time/memory, SQL planners, GPU tools, etc.) often become primary tools.
Culture, learning & mindset
- Many remark that debuggers are under-taught; some developers simply don’t know modern features (watchpoints, conditional breakpoints, tracepoints).
- Others frame the debate as mindset: understanding systems via interactive introspection vs encoding that understanding into persistent logs/tests.
- Broad consensus: both debuggers and print/logging are important; effective engineers know when to reach for which.