[Lldb-commits] [lldb] r261636 - Work around a stepping bug in arm64 android M
Pavel Labath via lldb-commits
lldb-commits at lists.llvm.org
Tue Feb 23 05:56:30 PST 2016
Author: labath
Date: Tue Feb 23 07:56:30 2016
New Revision: 261636
URL: http://llvm.org/viewvc/llvm-project?rev=261636&view=rev
Log:
Work around a stepping bug in arm64 android M
Summary:
On arm64, linux<=4.4 and Android<=M there is a bug, which prevents single-stepping from working when
the system comes back from suspend, because of incorrectly initialized CPUs. This did not really
affect Android<M, because it did not use software suspend, but it is a problem for M, which uses
suspend (doze) quite extensively. Fortunately, it seems that the first CPU is not affected by
this bug, so this commit implements a workaround by forcing the inferior to execute on the first
cpu whenever we are doing single stepping.
While inside, I have moved the implementations of Resume() and SingleStep() to the thread class
(instead of process).
Reviewers: tberghammer, ovyalov
Subscribers: aemerson, rengolin, tberghammer, danalbert, srhines, lldb-commits
Differential Revision: http://reviews.llvm.org/D17509
Added:
lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp
lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h
Modified:
lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
Modified: lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt?rev=261636&r1=261635&r2=261636&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/Process/Linux/CMakeLists.txt Tue Feb 23 07:56:30 2016
@@ -11,4 +11,5 @@ add_lldb_library(lldbPluginProcessLinux
NativeRegisterContextLinux_mips64.cpp
NativeThreadLinux.cpp
ProcFileReader.cpp
+ SingleStepCheck.cpp
)
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=261636&r1=261635&r2=261636&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Tue Feb 23 07:56:30 2016
@@ -2655,43 +2655,6 @@ NativeProcessLinux::WriteMemory(lldb::ad
}
Error
-NativeProcessLinux::Resume (lldb::tid_t tid, uint32_t signo)
-{
- Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
-
- if (log)
- log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid,
- Host::GetSignalAsCString(signo));
-
-
-
- intptr_t data = 0;
-
- if (signo != LLDB_INVALID_SIGNAL_NUMBER)
- data = signo;
-
- Error error = PtraceWrapper(PTRACE_CONT, tid, nullptr, (void*)data);
-
- if (log)
- log->Printf ("NativeProcessLinux::%s() resuming thread = %" PRIu64 " result = %s", __FUNCTION__, tid, error.Success() ? "true" : "false");
- return error;
-}
-
-Error
-NativeProcessLinux::SingleStep(lldb::tid_t tid, uint32_t signo)
-{
- 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 PtraceWrapper(SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT,
- tid, nullptr, (void*)data);
-}
-
-Error
NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo)
{
return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo);
@@ -2979,16 +2942,14 @@ NativeProcessLinux::ResumeThread(NativeT
{
case eStateRunning:
{
- thread.SetRunning();
- const auto resume_result = Resume(thread.GetID(), signo);
+ const auto resume_result = thread.Resume(signo);
if (resume_result.Success())
SetState(eStateRunning, true);
return resume_result;
}
case eStateStepping:
{
- thread.SetStepping();
- const auto step_result = SingleStep(thread.GetID(), signo);
+ const auto step_result = thread.SingleStep(signo);
if (step_result.Success())
SetState(eStateRunning, true);
return step_result;
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h?rev=261636&r1=261635&r2=261636&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.h Tue Feb 23 07:56:30 2016
@@ -127,6 +127,9 @@ namespace process_linux {
size_t data_size = 0,
long *result = nullptr);
+ bool
+ SupportHardwareSingleStepping() const;
+
protected:
// ---------------------------------------------------------------------
// NativeProcessProtocol protected interface
@@ -239,9 +242,6 @@ namespace process_linux {
void
MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread, bool exited);
- bool
- SupportHardwareSingleStepping() const;
-
Error
SetupSoftwareSingleStepping(NativeThreadLinux &thread);
@@ -285,16 +285,6 @@ namespace process_linux {
Error
GetEventMessage(lldb::tid_t tid, unsigned long *message);
- /// Resumes the given thread. If @p signo is anything but
- /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
- Error
- Resume(lldb::tid_t tid, uint32_t signo);
-
- /// Single steps the given thread. If @p signo is anything but
- /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
- Error
- SingleStep(lldb::tid_t tid, uint32_t signo);
-
void
NotifyThreadDeath (lldb::tid_t tid);
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp?rev=261636&r1=261635&r2=261636&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp Tue Feb 23 07:56:30 2016
@@ -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 (lld
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(ui
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::SetStoppedByBreakpoin
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 (
// 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;
+}
Modified: lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h?rev=261636&r1=261635&r2=261636&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h Tue Feb 23 07:56:30 2016
@@ -13,6 +13,8 @@
#include "lldb/lldb-private-forward.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
+#include <sched.h>
+
#include <map>
#include <memory>
#include <string>
@@ -54,11 +56,16 @@ namespace process_linux {
// ---------------------------------------------------------------------
// Interface for friend classes
// ---------------------------------------------------------------------
- void
- SetRunning ();
- void
- SetStepping ();
+ /// Resumes the thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ Error
+ Resume(uint32_t signo);
+
+ /// Single steps the thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ Error
+ SingleStep(uint32_t signo);
void
SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);
@@ -102,6 +109,18 @@ namespace process_linux {
void
MaybeLogStateChange (lldb::StateType new_state);
+ NativeProcessLinux &
+ GetProcess();
+
+ void
+ SetStopped();
+
+ inline void
+ MaybePrepareSingleStepWorkaround();
+
+ inline void
+ MaybeCleanupSingleStepWorkaround();
+
// ---------------------------------------------------------------------
// Member Variables
// ---------------------------------------------------------------------
@@ -111,6 +130,7 @@ namespace process_linux {
std::string m_stop_description;
using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
WatchpointIndexMap m_watchpoint_index_map;
+ cpu_set_t m_original_cpu_set; // For single-step workaround.
};
typedef std::shared_ptr<NativeThreadLinux> NativeThreadLinuxSP;
Added: lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp?rev=261636&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp (added)
+++ lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp Tue Feb 23 07:56:30 2016
@@ -0,0 +1,177 @@
+//===-- SingleStepCheck.cpp ----------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SingleStepCheck.h"
+
+#include <sched.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "NativeProcessLinux.h"
+
+#include "llvm/Support/Compiler.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/linux/Ptrace.h"
+
+using namespace lldb_private::process_linux;
+
+#if defined(__arm64__) || defined(__aarch64__)
+namespace
+{
+
+void LLVM_ATTRIBUTE_NORETURN
+Child()
+{
+ if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1)
+ _exit(1);
+
+ // We just do an endless loop SIGSTOPPING ourselves until killed. The tracer will fiddle with our cpu
+ // affinities and monitor the behaviour.
+ for (;;)
+ {
+ raise(SIGSTOP);
+
+ // Generate a bunch of instructions here, so that a single-step does not land in the
+ // raise() accidentally. If single-stepping works, we will be spinning in this loop. If
+ // it doesn't, we'll land in the raise() call above.
+ for (volatile unsigned i = 0; i < CPU_SETSIZE; ++i)
+ ;
+ }
+}
+
+struct ChildDeleter
+{
+ ::pid_t pid;
+
+ ~ChildDeleter()
+ {
+ int status;
+ kill(pid, SIGKILL); // Kill the child.
+ waitpid(pid, &status, __WALL); // Pick up the remains.
+ }
+};
+
+} // end anonymous namespace
+
+bool
+impl::SingleStepWorkaroundNeeded()
+{
+ // We shall spawn a child, and use it to verify the debug capabilities of the cpu. We shall
+ // iterate through the cpus, bind the child to each one in turn, and verify that
+ // single-stepping works on that cpu. A workaround is needed if we find at least one broken
+ // cpu.
+
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+ Error error;
+ ::pid_t child_pid = fork();
+ if (child_pid == -1)
+ {
+ if (log)
+ {
+ error.SetErrorToErrno();
+ log->Printf("%s failed to fork(): %s", __FUNCTION__, error.AsCString());
+ }
+ return false;
+ }
+ if (child_pid == 0)
+ Child();
+
+ ChildDeleter child_deleter{child_pid};
+ cpu_set_t available_cpus;
+ if (sched_getaffinity(child_pid, sizeof available_cpus, &available_cpus) == -1)
+ {
+ if (log)
+ {
+ error.SetErrorToErrno();
+ log->Printf("%s failed to get available cpus: %s", __FUNCTION__, error.AsCString());
+ }
+ return false;
+ }
+
+ int status;
+ ::pid_t wpid = waitpid(child_pid, &status, __WALL);
+ if (wpid != child_pid || !WIFSTOPPED(status))
+ {
+ if (log)
+ {
+ error.SetErrorToErrno();
+ log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__, status, error.AsCString());
+ }
+ return false;
+ }
+
+ unsigned cpu;
+ for (cpu = 0; cpu < CPU_SETSIZE; ++cpu)
+ {
+ if (!CPU_ISSET(cpu, &available_cpus))
+ continue;
+
+ cpu_set_t cpus;
+ CPU_ZERO(&cpus);
+ CPU_SET(cpu, &cpus);
+ if (sched_setaffinity(child_pid, sizeof cpus, &cpus) == -1)
+ {
+ if (log)
+ {
+ error.SetErrorToErrno();
+ log->Printf("%s failed to switch to cpu %u: %s", __FUNCTION__, cpu, error.AsCString());
+ }
+ continue;
+ }
+
+ int status;
+ error = NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf("%s single step failed: %s", __FUNCTION__, error.AsCString());
+ break;
+ }
+
+ wpid = waitpid(child_pid, &status, __WALL);
+ if (wpid != child_pid || !WIFSTOPPED(status))
+ {
+ if (log)
+ {
+ error.SetErrorToErrno();
+ log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__, status, error.AsCString());
+ }
+ break;
+ }
+ if (WSTOPSIG(status) != SIGTRAP)
+ {
+ if (log)
+ log->Printf("%s single stepping on cpu %d failed with status %x", __FUNCTION__, cpu, status);
+ break;
+ }
+ }
+
+ // cpu is either the index of the first broken cpu, or CPU_SETSIZE.
+ if (cpu == 0)
+ {
+ if (log)
+ log->Printf("%s SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING LIKELY TO BE UNRELIABLE.",
+ __FUNCTION__);
+ // No point in trying to fiddle with the affinities, just give it our best shot and see how it goes.
+ return false;
+ }
+
+ return cpu != CPU_SETSIZE;
+}
+
+#else // !arm64
+bool
+impl::SingleStepWorkaroundNeeded()
+{
+ return false;
+}
+#endif
Added: lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h?rev=261636&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h (added)
+++ lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h Tue Feb 23 07:56:30 2016
@@ -0,0 +1,41 @@
+//===-- SingleStepCheck.h ------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_SingleStepCheck_H_
+#define liblldb_SingleStepCheck_H_
+
+namespace lldb_private
+{
+namespace process_linux
+{
+
+namespace impl
+{
+extern bool
+SingleStepWorkaroundNeeded();
+}
+
+// arm64 linux had a bug which prevented single-stepping and watchpoints from working on non-boot
+// cpus, due to them being incorrectly initialized after coming out of suspend. This issue is
+// particularly affecting android M, which uses suspend ("doze mode") quite aggressively. This
+// code detects that situation and makes single-stepping work by doing all the step operations on
+// the boot cpu.
+//
+// The underlying issue has been fixed in android N and linux 4.4. This code can be removed once
+// these systems become obsolete.
+inline bool
+SingleStepWorkaroundNeeded()
+{
+ static bool value = impl::SingleStepWorkaroundNeeded();
+ return value;
+}
+} // end namespace process_linux
+} // end namespace lldb_private
+
+#endif // #ifndef liblldb_SingleStepCheck_H_
More information about the lldb-commits
mailing list