There are some typical workflows in debugging, such as:
- Backwards traversal:
- Determine the symptoms of the issue.
- Place a breakpoint at the place where the symptoms become apparent.
- Retrace the execution backwards by unwinding the call stack and checking callers.
- Forward traversal:
- Determine the hierarchy of function calls that lead to the symptom of the issue.
- Place a breakpoint at a function that leads to the issue.
- Single-step the execution until the symptoms are apparent.
In some cases looking at the call stack might not help to identify the issue, because it might have originated in a separate execution branch.
Forward traversal might not work if you would have to step through a large number of executions of a piece of code to identify the issue. It can also be destructive to issues like race conditions, deadlocks, etc.
Execution trace can be helpful in such cases. Using execution trace, you can place a breakpoint at the location where the issues become apparent and review the code lines that were executed up to this point.