diff --git a/lldb/include/lldb/Target/ThreadPlanStepOverBreakpoint.h b/lldb/include/lldb/Target/ThreadPlanStepOverBreakpoint.h index 86f7798487c305be1fc275acba8602a28dcbc4b7..0cc17d3672739eaf54f8e4dfe85935a76fb4f22c 100644 --- a/lldb/include/lldb/Target/ThreadPlanStepOverBreakpoint.h +++ b/lldb/include/lldb/Target/ThreadPlanStepOverBreakpoint.h @@ -46,6 +46,8 @@ private: lldb::user_id_t m_breakpoint_site_id; bool m_auto_continue; bool m_reenabled_breakpoint_site; + bool m_stopped_at_my_breakpoint; + bool m_handling_signal; ThreadPlanStepOverBreakpoint(const ThreadPlanStepOverBreakpoint &) = delete; const ThreadPlanStepOverBreakpoint & diff --git a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp index f188d827faae4ea91f8adcb47b9590fa740309d0..59fa6f3ecb541108ca091cd834b48e661dcaa7af 100644 --- a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp +++ b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp @@ -27,8 +27,9 @@ ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint(Thread &thread) // first in the thread plan stack when stepping over // a breakpoint m_breakpoint_addr(LLDB_INVALID_ADDRESS), - m_auto_continue(false), m_reenabled_breakpoint_site(false) - + m_auto_continue(false), m_reenabled_breakpoint_site(false), + m_stopped_at_my_breakpoint(false), + m_handling_signal(false) { m_breakpoint_addr = thread.GetRegisterContext()->GetPC(); m_breakpoint_site_id = @@ -47,6 +48,8 @@ void ThreadPlanStepOverBreakpoint::GetDescription( bool ThreadPlanStepOverBreakpoint::ValidatePlan(Stream *error) { return true; } bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) { + m_stopped_at_my_breakpoint = false; + StopInfoSP stop_info_sp = GetPrivateStopInfo(); if (stop_info_sp) { // It's a little surprising that we stop here for a breakpoint hit. @@ -89,16 +92,29 @@ bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) { lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC(); if (pc_addr == m_breakpoint_addr) { + m_stopped_at_my_breakpoint = true; + // If we came from a signal handler, just reset the flag and try again. + m_handling_signal = false; LLDB_LOGF(log, "Got breakpoint stop reason but pc: 0x%" PRIx64 - "hasn't changed.", + " hasn't changed, resetting m_handling_signal." + " If we came from a signal handler, trying again.", pc_addr); return true; } + // Even if we are in a signal handler, handle the breakpoint as usual + SetAutoContinue(false); return false; } + case eStopReasonSignal: + if (!m_handling_signal) { + // Next stop may be a signal handler. + LLDB_LOG(log, "Preparing for signal handler handling."); + m_handling_signal = true; + } + return false; default: return false; } @@ -113,6 +129,12 @@ bool ThreadPlanStepOverBreakpoint::ShouldStop(Event *event_ptr) { bool ThreadPlanStepOverBreakpoint::StopOthers() { return true; } StateType ThreadPlanStepOverBreakpoint::GetPlanRunState() { + if (m_handling_signal) { + // Resume & wait to hit our initial breakpoint + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + LLDB_LOG(log, "Step over breakpoint resuming through a potential signal handler."); + return eStateRunning; + } return eStateStepping; } @@ -121,9 +143,19 @@ bool ThreadPlanStepOverBreakpoint::DoWillResume(StateType resume_state, if (current_plan) { BreakpointSiteSP bp_site_sp( m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr)); - if (bp_site_sp && bp_site_sp->IsEnabled()) { - m_process.DisableBreakpointSite(bp_site_sp.get()); - m_reenabled_breakpoint_site = false; + if (bp_site_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (m_handling_signal) { + // Turn the breakpoint back on and wait to hit it. + // Even if there is no userspace signal handler, we'll immediately stop + // on the breakpoint and try again. + LLDB_LOG(log, "Step over breakpoint reenabling breakpoint to try again after a potential signal handler"); + ReenableBreakpointSite(); + } else if (bp_site_sp->IsEnabled()) { + LLDB_LOG(log, "Step over breakpoint disabling breakpoint."); + m_process.DisableBreakpointSite(bp_site_sp.get()); + m_reenabled_breakpoint_site = false; + } } } return true; @@ -143,7 +175,7 @@ bool ThreadPlanStepOverBreakpoint::MischiefManaged() { if (pc_addr == m_breakpoint_addr) { // If we are still at the PC of our breakpoint, then for some reason we - // didn't get a chance to run. + // didn't get a chance to run, or we received a signal and want to try again. return false; } else { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); @@ -175,9 +207,16 @@ void ThreadPlanStepOverBreakpoint::SetAutoContinue(bool do_it) { } bool ThreadPlanStepOverBreakpoint::ShouldAutoContinue(Event *event_ptr) { + if (m_stopped_at_my_breakpoint) { + // Do not stop again at the breakpoint we are trying to step over + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + LLDB_LOG(log, "Stopped step over breakpoint plan on its own breakpoint, auto-continue."); + return true; + } return m_auto_continue; } bool ThreadPlanStepOverBreakpoint::IsPlanStale() { - return GetThread().GetRegisterContext()->GetPC() != m_breakpoint_addr; + // TODO: validate + return !m_handling_signal && GetThread().GetRegisterContext()->GetPC() != m_breakpoint_addr; }