diff options
Diffstat (limited to 'source/Plugins/Process/Linux/NativeThreadLinux.cpp')
-rw-r--r-- | source/Plugins/Process/Linux/NativeThreadLinux.cpp | 143 |
1 files changed, 106 insertions, 37 deletions
diff --git a/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/source/Plugins/Process/Linux/NativeThreadLinux.cpp index cbf82885e23a6..070b1bcda3b87 100644 --- a/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ b/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -14,10 +14,12 @@ #include "NativeProcessLinux.h" #include "NativeRegisterContextLinux.h" +#include "SingleStepCheck.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" #include "lldb/Host/HostNativeThread.h" +#include "lldb/Host/linux/Ptrace.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-enumerations.h" @@ -199,8 +201,8 @@ NativeThreadLinux::RemoveWatchpoint (lldb::addr_t addr) return Error ("Clearing hardware watchpoint failed."); } -void -NativeThreadLinux::SetRunning () +Error +NativeThreadLinux::Resume(uint32_t signo) { const StateType new_state = StateType::eStateRunning; MaybeLogStateChange (new_state); @@ -213,29 +215,92 @@ NativeThreadLinux::SetRunning () // then this is a new thread. So set all existing watchpoints. if (m_watchpoint_index_map.empty()) { - const auto process_sp = GetProcess(); - if (process_sp) + NativeProcessLinux &process = GetProcess(); + + const auto &watchpoint_map = process.GetWatchpointMap(); + GetRegisterContext()->ClearAllHardwareWatchpoints(); + for (const auto &pair : watchpoint_map) { - const auto &watchpoint_map = process_sp->GetWatchpointMap(); - if (watchpoint_map.empty()) return; - GetRegisterContext()->ClearAllHardwareWatchpoints(); - for (const auto &pair : watchpoint_map) - { - const auto& wp = pair.second; - SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); - } + const auto &wp = pair.second; + SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); } } + + intptr_t data = 0; + + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + return NativeProcessLinux::PtraceWrapper(PTRACE_CONT, GetID(), nullptr, reinterpret_cast<void *>(data)); } void -NativeThreadLinux::SetStepping () +NativeThreadLinux::MaybePrepareSingleStepWorkaround() +{ + if (!SingleStepWorkaroundNeeded()) + return; + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + + if (sched_getaffinity(static_cast<::pid_t>(m_tid), sizeof m_original_cpu_set, &m_original_cpu_set) != 0) + { + // This should really not fail. But, just in case... + if (log) + { + Error error(errno, eErrorTypePOSIX); + log->Printf("NativeThreadLinux::%s Unable to get cpu affinity for thread %" PRIx64 ": %s", __FUNCTION__, + m_tid, error.AsCString()); + } + return; + } + + cpu_set_t set; + CPU_ZERO(&set); + CPU_SET(0, &set); + if (sched_setaffinity(static_cast<::pid_t>(m_tid), sizeof set, &set) != 0 && log) + { + // This may fail in very locked down systems, if the thread is not allowed to run on + // cpu 0. If that happens, only thing we can do is it log it and continue... + Error error(errno, eErrorTypePOSIX); + log->Printf("NativeThreadLinux::%s Unable to set cpu affinity for thread %" PRIx64 ": %s", __FUNCTION__, m_tid, + error.AsCString()); + } +} + +void +NativeThreadLinux::MaybeCleanupSingleStepWorkaround() +{ + if (!SingleStepWorkaroundNeeded()) + return; + + if (sched_setaffinity(static_cast<::pid_t>(m_tid), sizeof m_original_cpu_set, &m_original_cpu_set) != 0) + { + Error error(errno, eErrorTypePOSIX); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + log->Printf("NativeThreadLinux::%s Unable to reset cpu affinity for thread %" PRIx64 ": %s", __FUNCTION__, + m_tid, error.AsCString()); + } +} + +Error +NativeThreadLinux::SingleStep(uint32_t signo) { const StateType new_state = StateType::eStateStepping; MaybeLogStateChange (new_state); m_state = new_state; - m_stop_info.reason = StopReason::eStopReasonNone; + + MaybePrepareSingleStepWorkaround(); + + intptr_t data = 0; + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + data = signo; + + // If hardware single-stepping is not supported, we just do a continue. The breakpoint on the + // next instruction has been setup in NativeProcessLinux::Resume. + return NativeProcessLinux::PtraceWrapper(GetProcess().SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP + : PTRACE_CONT, + m_tid, nullptr, reinterpret_cast<void *>(data)); } void @@ -245,9 +310,7 @@ NativeThreadLinux::SetStoppedBySignal(uint32_t signo, const siginfo_t *info) if (log) log->Printf ("NativeThreadLinux::%s called with signal 0x%02" PRIx32, __FUNCTION__, signo); - const StateType new_state = StateType::eStateStopped; - MaybeLogStateChange (new_state); - m_state = new_state; + SetStopped(); m_stop_info.reason = StopReason::eStopReasonSignal; m_stop_info.details.signal.signo = signo; @@ -288,6 +351,17 @@ NativeThreadLinux::IsStopped (int *signo) return true; } +void +NativeThreadLinux::SetStopped() +{ + if (m_state == StateType::eStateStepping) + MaybeCleanupSingleStepWorkaround(); + + const StateType new_state = StateType::eStateStopped; + MaybeLogStateChange(new_state); + m_state = new_state; + m_stop_description.clear(); +} void NativeThreadLinux::SetStoppedByExec () @@ -296,9 +370,7 @@ NativeThreadLinux::SetStoppedByExec () if (log) log->Printf ("NativeThreadLinux::%s()", __FUNCTION__); - const StateType new_state = StateType::eStateStopped; - MaybeLogStateChange (new_state); - m_state = new_state; + SetStopped(); m_stop_info.reason = StopReason::eStopReasonExec; m_stop_info.details.signal.signo = SIGSTOP; @@ -307,9 +379,7 @@ NativeThreadLinux::SetStoppedByExec () void NativeThreadLinux::SetStoppedByBreakpoint () { - const StateType new_state = StateType::eStateStopped; - MaybeLogStateChange (new_state); - m_state = new_state; + SetStopped(); m_stop_info.reason = StopReason::eStopReasonBreakpoint; m_stop_info.details.signal.signo = SIGTRAP; @@ -319,10 +389,7 @@ NativeThreadLinux::SetStoppedByBreakpoint () void NativeThreadLinux::SetStoppedByWatchpoint (uint32_t wp_index) { - const StateType new_state = StateType::eStateStopped; - MaybeLogStateChange (new_state); - m_state = new_state; - m_stop_description.clear (); + SetStopped(); lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); @@ -363,9 +430,7 @@ NativeThreadLinux::IsStoppedAtWatchpoint () void NativeThreadLinux::SetStoppedByTrace () { - const StateType new_state = StateType::eStateStopped; - MaybeLogStateChange (new_state); - m_state = new_state; + SetStopped(); m_stop_info.reason = StopReason::eStopReasonTrace; m_stop_info.details.signal.signo = SIGTRAP; @@ -374,9 +439,7 @@ NativeThreadLinux::SetStoppedByTrace () void NativeThreadLinux::SetStoppedWithNoReason () { - const StateType new_state = StateType::eStateStopped; - MaybeLogStateChange (new_state); - m_state = new_state; + SetStopped(); m_stop_info.reason = StopReason::eStopReasonNone; m_stop_info.details.signal.signo = 0; @@ -397,11 +460,9 @@ NativeThreadLinux::RequestStop () { Log* log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - const auto process_sp = GetProcess(); - if (! process_sp) - return Error("Process is null."); + NativeProcessLinux &process = GetProcess(); - lldb::pid_t pid = process_sp->GetID(); + lldb::pid_t pid = process.GetID(); lldb::tid_t tid = GetID(); if (log) @@ -438,3 +499,11 @@ NativeThreadLinux::MaybeLogStateChange (lldb::StateType new_state) // Log it. log->Printf ("NativeThreadLinux: thread (pid=%" PRIu64 ", tid=%" PRIu64 ") changing from state %s to %s", pid, GetID (), StateAsCString (old_state), StateAsCString (new_state)); } + +NativeProcessLinux & +NativeThreadLinux::GetProcess() +{ + auto process_sp = std::static_pointer_cast<NativeProcessLinux>(NativeThreadProtocol::GetProcess()); + assert(process_sp); + return *process_sp; +} |