Debuggers, Breakpoints, and Watchpoints
Use a breakpoint when you know where to inspect execution, a condition when only a specific state matters, and a watchpoint when you need to find what changes a value. Begin with a hypothesis about the first incorrect state, not a tour through every line.
Record the running build, input, thread or process context, and observation point. Debugging changes execution conditions, especially timing. A stopped program can explain a state transition while failing to reproduce the scheduling behavior that caused the original fault.
TL;DR
- Use a breakpoint when you know where to look, a condition when only a specific state matters, and a watchpoint to find what changes a value.
- Start from a hypothesis about the first incorrect state, not a tour through every line.
- Record the build, input, thread or process, and stop location for each observation.
- Debugging changes timing: a stopped program can explain a state change without reproducing the race that caused it.
- Confirm that symbols and source match the running artifact before trusting locations.
Quick Example
This program uses Python's actual bdb debugger framework to set a conditional breakpoint in an owned temporary program. The condition selects the loop iteration where value is three. The recorded total belongs to the moment before the statement on that line executes.
The conditional stop records value 3 and total 3, while the completed program's total is 10. It clears its breakpoints and uses a temporary directory whose resolved location and name are checked before automatic cleanup.
This is a real local Python tracing result. It is not a GDB run, native instruction breakpoint, hardware or software watchpoint, multithreaded investigation, remote attachment, or network-security test. Python documents bdb's conditional breakpoints and its line events as occurring before the line is executed. Python bdb framework.
Core Concepts
A stop needs a precise interpretation
A source line, instruction address, function entry, exception, and data change are different observation points. Confirm which one the tool represents. In the example, seeing total equal three at the selected line does not show the result of adding the current value; the addition has not run yet.
Compare expected and actual state at a meaningful boundary. If a value is already wrong, move the observation earlier. If it is correct, move toward the first consumer that misinterprets it. This narrows the interval of interest without assuming that the line where a failure becomes visible caused it.
Conditional breakpoints reduce irrelevant stops
Choose a condition that identifies the relevant request, iteration, object, or state. Keep it simple enough to understand and evaluate safely. A condition can itself perform work, and an expression with side effects can change the program under investigation.
The bdb example evaluates a small local comparison. It does not establish that arbitrary expressions are safe in another debugger or optimized target. Review the selected debugger's expression and calling behavior before invoking functions from a stopped process. Prefer observations that do not mutate the state you are trying to explain.
Watchpoints follow data changes
GDB documents watchpoints for value changes, and read/access variants with target-dependent hardware requirements. Hardware resources, supported sizes, expression complexity, and variable lifetime can constrain what is watched. If hardware support is unavailable, software observation can have different performance and reporting behavior. GDB watchpoint documentation.
Choose the data whose change would distinguish your hypotheses. Watching a pointer value is different from watching the memory it currently points to. If an object moves, is freed, or its storage is reused, revisit the watched expression and its lifetime. A stop on reused memory may be real while no longer belonging to the logical object you intended.
Avoid turning a watchpoint result into a universal concurrency conclusion. Identify which threads and accesses the selected implementation can observe. The local Python example does not exercise those mechanisms; they need tests on the actual debugger and target.
Remote debugging adds another environment boundary
GDB's remote documentation distinguishes remote connection modes and explains host executable and symbol files, target programs, and attachment behavior. The local source tree alone does not identify the code running on the target. GDB remote connections.
Before a remote investigation, confirm the intended process and build, organizational authority, supported secure access path, and consequences of stopping execution. A paused service or control task can affect other systems. Use a designated test target when possible, and keep debugger endpoints within the approved access arrangement rather than exposing them for convenience.
Best Practices
Preserve a reproducible starting point
Retain the exact executable or artifact identity, matching symbols, relevant input, configuration, launch steps, and failure predicate. Record compiler/runtime and optimization settings. A breakpoint that appears on a familiar source line can still be misleading when the executable and local source differ.
Capture observations with enough context to compare runs, while excluding secrets and unnecessary private data. A screenshot of a variable without the build or stop point may be difficult for another engineer to interpret.
Use the least disruptive evidence that answers the question
For a deterministic local defect, a breakpoint may be the quickest route to the first incorrect state. For timing-sensitive behavior, logs, traces, counters, or a controlled recording can preserve more of the relevant execution pattern. Choose according to the hypothesis rather than assuming interactive stepping is always the strongest evidence.
If the defect disappears under the debugger, record that observation. It can guide further investigation, but it does not prove that the defect is a race. Instrumentation, optimization, timeouts, and environment differences can all change the symptom.
Check the fix outside the debugger
Turn the relevant failure into an appropriate regression check or reproducible acceptance case. Run it under the intended execution conditions. A corrected value after an interactive edit is a diagnostic experiment, not a completed fix, and a single successful stepping session is not a production reliability result.
Common Mistakes
Assuming the stopped line already ran
Watching an address after its object dies
Debugging with mismatched symbols
Calling a debugger-only fix done
FAQ
Is a watchpoint the same as a breakpoint?
Both can stop execution, but their trigger differs. A conventional breakpoint identifies a code location or event; a watchpoint follows an expression or memory access/change according to the debugger and target's capabilities.
Can a conditional expression change the program?
Depending on the expression and debugger, evaluation can perform work or invoke behavior. Use simple observations and understand the tool's rules before calling functions or modifying state during an investigation.
Does this example attach to an existing process?
No. It runs an owned temporary Python program under bdb. Native, watchpoint, remote, and existing-process behavior remain untested here.