debugserver arm64 single-step state
The arm64 resume/stop hooks and MDSCR_EL1 single-step control used for source-level stepping and for advancing past a watchpoint before restoring it.
DNBArchMachARM64::ThreadWillResume source
void DNBArchMachARM64::ThreadWillResume() {
// Do we need to step this thread? If so, let the mach thread tell us so.
if (m_thread->IsStepping()) {
EnableHardwareSingleStep(true);
}
// Disable the triggered watchpoint temporarily before we resume.
// Plus, we try to enable hardware single step to execute past the instruction
// which triggered our watchpoint.
if (m_watchpoint_did_occur) {
if (m_watchpoint_hw_index >= 0) {
kern_return_t kret = GetDBGState(false);
if (kret == KERN_SUCCESS &&
!IsWatchpointEnabled(m_state.dbg, m_watchpoint_hw_index)) {
// The watchpoint might have been disabled by the user. We don't need
// to do anything at all
// to enable hardware single stepping.
m_watchpoint_did_occur = false;
m_watchpoint_hw_index = -1;
return;
}
DisableHardwareWatchpoint(m_watchpoint_hw_index, false);
DNBLogThreadedIf(LOG_WATCHPOINTS,
"DNBArchMachARM64::ThreadWillResume() "
"DisableHardwareWatchpoint(%d) called",
m_watchpoint_hw_index);
// Enable hardware single step to move past the watchpoint-triggering
// instruction.
… more in sourceDNBArchMachARM64::ThreadDidStop source
bool DNBArchMachARM64::ThreadDidStop() {
bool success = true;
m_state.InvalidateAllRegisterStates();
if (m_watchpoint_resume_single_step_enabled) {
// Great! We now disable the hardware single step as well as re-enable the
// hardware watchpoint.
// See also ThreadWillResume().
if (EnableHardwareSingleStep(false) == KERN_SUCCESS) {
if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) {
ReenableHardwareWatchpoint(m_watchpoint_hw_index);
m_watchpoint_resume_single_step_enabled = false;
m_watchpoint_did_occur = false;
m_watchpoint_hw_index = -1;
} else {
DNBLogError("internal error detected: m_watchpoint_resume_step_enabled "
"is true but (m_watchpoint_did_occur && "
"m_watchpoint_hw_index >= 0) does not hold!");
}
} else {
DNBLogError("internal error detected: m_watchpoint_resume_step_enabled "
"is true but unable to disable single step!");
}
}
// Are we stepping a single instruction?
if (GetGPRState(true) == KERN_SUCCESS) {
// We are single stepping, was this the primary thread?
if (m_thread->IsStepping()) {
… more in sourceDNBArchMachARM64::EnableHardwareSingleStep source
Set the single step bit in the processor status register.
kern_return_t DNBArchMachARM64::EnableHardwareSingleStep(bool enable) { DNBError err; DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable); err = GetGPRState(false); if (err.Fail()) { err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__); return err.Status(); } err = GetDBGState(false); if (err.Fail()) { err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__); return err.Status(); } #if defined(DEBUGSERVER_IS_ARM64E) uint64_t pc = DNBFixAddress( reinterpret_cast<uint64_t>(m_state.context.gpr.__opaque_pc)); #else uint64_t pc = m_state.context.gpr.__pc; #endif if (enable) { DNBLogThreadedIf(LOG_STEP, "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, pc); m_state.dbg.__mdscr_el1 |= SS_ENABLE; … more in source