1. Context and Motivation
Currently, LLDB lacks support for software watchpoints. This gap means that certain debugging functionalities available in GDB are not present in LLDB. As outlined in the GDB Internals Watchpoints documentation, software watchpoints are crucial in several scenarios:
- The watched memory region is too large for the underlying hardware watchpoint support. For example, each x86 debug register can watch up to 4 bytes of memory, so trying to watch data structures larger than 16 bytes will cause GDB to use software watchpoints.
- The value of the expression to be watched depends on data held in registers (as opposed to memory).
- Too many different watchpoints requested. (On some architectures, this situation is impossible to detect until the debugged program is resumed.) Note that x86 debug registers are used for both hardware breakpoints and watchpoints, so setting too many hardware breakpoints might cause watchpoint insertion to fail.
- No hardware-assisted watchpoints provided by the target implementation.
It is important to emphasize that software watchpoints, as implemented in GDB, incur a severe performance penalty, often slowing down program execution by orders of magnitude (tens to hundreds of times). This is a fundamental trade-off stemming from the single-stepping approach. Therefore, enabling this feature represents a significant and heavy trade-off for the user. We believe that despite this cost, the option should be available for debugging scenarios where convenience is critical and performance is secondary. LLDB must provide clear indications of this active âslow modeâ and expose settings to control it.
2. Proposed Implementation
The GDB Remote Serial Protocol (RSP) does not define packets for software watchpoints. Consequently, in GDB, this feature is implemented entirely on the host side, with the gdbserver remaining unaware of it.
We propose a similar approach for LLDB: implementing the logic for software watchpoints entirely on the host side. The core of this implementation is a new ThreadPlan type: WatchpointStepInstructionThreadPlan.
- Inheritance: This plan inherits from
StepInstructionThreadPlan, whose primary function is to execute a single instruction step. - Custom Logic: The
WatchpointStepInstructionThreadPlanoverrides theDoPlanExplainsStopandShouldStopmethods. Within these methods, it checks whether the value of any enabled software watchpoint has changed (indicating a watchpoint hit). If a hit is detected, it sets aWatchpointStopReasonfor the thread.
Workflow:
- Before resuming a thread, if any enabled software watchpoints exist, a
WatchpointStepInstructionThreadPlanis pushed onto the top of the thread plan stack (or just after aStepOverBreakpointplan if one is active). - The thread executes a single instruction and control returns to the debugger.
- The debugger walks the thread plan stack, calling
DoPlanExplainsStop/ShouldStop. Our plan checks all enabled software watchpoints for modifications. - If a hit occurs: Control is returned to the user with the appropriate watchpoint stop reason.
- If no hit occurs and no other thread plans request a stop, execution resumes. In either case, the current
WatchpointStepInstructionThreadPlanis popped from the stack. - On the next resume operation (if software watchpoints are still enabled), a new
WatchpointStepInstructionThreadPlanis pushed, and the cycle repeats for the next instruction.
3. Rationale and Considerations
This is an intrusive solution as it significantly interacts with the thread plan mechanism. However, for a host-side implementation, it is challenging to envision a fundamentally different approach. Implementing this on the server (e.g., in lldb-server) is less desirable, as it would require substantial changes to the gdb-remote protocol. Such changes could also complicate future support for bare-metal targets.
We acknowledge the potential performance impact of single-stepping. To mitigate this, the implementation should include Ńlear performance warnings in the documentation.
4. Questions and Alternatives
We would greatly appreciate feedback on this proposal, specifically regarding alternative, less intrusive methods for implementing this functionality within LLDBâs architecture.
Thank you for your time and consideration. We look forward to your thoughts and suggestions.`
