[Lldb-commits] [lldb] r293046 - NPL: Compartmentalize arm64 single step workaround better
Pavel Labath via lldb-commits
lldb-commits at lists.llvm.org
Wed Jan 25 03:19:46 PST 2017
Author: labath
Date: Wed Jan 25 05:19:45 2017
New Revision: 293046
URL: http://llvm.org/viewvc/llvm-project?rev=293046&view=rev
Log:
NPL: Compartmentalize arm64 single step workaround better
The main motivation for me doing this is being able to build an arm
android lldb-server against api level 9 headers, but it seems like a
good cleanup nonetheless.
The entirety of the cpu_set_t dance now resides in SingleStepCheck.cpp,
which is only built on arm64.
Modified:
lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp
lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h
lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp
lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h
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=293046&r1=293045&r2=293046&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.cpp Wed Jan 25 05:19:45 2017
@@ -220,63 +220,12 @@ Error NativeThreadLinux::Resume(uint32_t
reinterpret_cast<void *>(data));
}
-void 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();
+ m_step_workaround = SingleStepWorkaround::Get(m_tid);
intptr_t data = 0;
if (signo != LLDB_INVALID_SIGNAL_NUMBER)
@@ -338,7 +287,7 @@ bool NativeThreadLinux::IsStopped(int *s
void NativeThreadLinux::SetStopped() {
if (m_state == StateType::eStateStepping)
- MaybeCleanupSingleStepWorkaround();
+ m_step_workaround.reset();
const StateType new_state = StateType::eStateStopped;
MaybeLogStateChange(new_state);
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=293046&r1=293045&r2=293046&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/NativeThreadLinux.h Wed Jan 25 05:19:45 2017
@@ -10,11 +10,10 @@
#ifndef liblldb_NativeThreadLinux_H_
#define liblldb_NativeThreadLinux_H_
+#include "SingleStepCheck.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/lldb-private-forward.h"
-#include <sched.h>
-
#include <map>
#include <memory>
#include <string>
@@ -94,10 +93,6 @@ private:
void SetStopped();
- inline void MaybePrepareSingleStepWorkaround();
-
- inline void MaybeCleanupSingleStepWorkaround();
-
// ---------------------------------------------------------------------
// Member Variables
// ---------------------------------------------------------------------
@@ -107,7 +102,7 @@ private:
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.
+ llvm::Optional<SingleStepWorkaround> m_step_workaround;
};
typedef std::shared_ptr<NativeThreadLinux> NativeThreadLinuxSP;
Modified: lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp?rev=293046&r1=293045&r2=293046&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.cpp Wed Jan 25 05:19:45 2017
@@ -18,10 +18,12 @@
#include "llvm/Support/Compiler.h"
+#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "lldb/Core/Error.h"
-#include "lldb/Core/Log.h"
#include "lldb/Host/linux/Ptrace.h"
+using namespace lldb;
+using namespace lldb_private;
using namespace lldb_private::process_linux;
#if defined(__arm64__) || defined(__aarch64__)
@@ -32,16 +34,14 @@ void LLVM_ATTRIBUTE_NORETURN Child() {
_exit(1);
// We just do an endless loop SIGSTOPPING ourselves until killed. The tracer
- // will fiddle with our cpu
- // affinities and monitor the behaviour.
+ // 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.
+ // 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)
;
}
@@ -57,25 +57,16 @@ struct ChildDeleter {
}
};
-} // end anonymous namespace
-
-bool impl::SingleStepWorkaroundNeeded() {
+bool WorkaroundNeeded() {
// 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.
+ // 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;
+ Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD);
::pid_t child_pid = fork();
if (child_pid == -1) {
- if (log) {
- error.SetErrorToErrno();
- log->Printf("%s failed to fork(): %s", __FUNCTION__, error.AsCString());
- }
+ LLDB_LOG(log, "failed to fork(): {0}", Error(errno, eErrorTypePOSIX));
return false;
}
if (child_pid == 0)
@@ -85,22 +76,16 @@ bool impl::SingleStepWorkaroundNeeded()
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());
- }
+ LLDB_LOG(log, "failed to get available cpus: {0}",
+ Error(errno, eErrorTypePOSIX));
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());
- }
+ LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status,
+ Error(errno, eErrorTypePOSIX));
return false;
}
@@ -113,46 +98,37 @@ bool impl::SingleStepWorkaroundNeeded()
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());
- }
+ LLDB_LOG(log, "failed to switch to cpu {0}: {1}", cpu,
+ Error(errno, eErrorTypePOSIX));
continue;
}
int status;
- error = NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid);
+ Error error =
+ NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid);
if (error.Fail()) {
- if (log)
- log->Printf("%s single step failed: %s", __FUNCTION__,
- error.AsCString());
+ LLDB_LOG(log, "single step failed: {0}", error);
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());
- }
+ LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status,
+ Error(errno, eErrorTypePOSIX));
break;
}
if (WSTOPSIG(status) != SIGTRAP) {
- if (log)
- log->Printf("%s single stepping on cpu %d failed with status %x",
- __FUNCTION__, cpu, status);
+ LLDB_LOG(log, "single stepping on cpu {0} failed with status {1:x}", 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__);
+ LLDB_LOG(log,
+ "SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING "
+ "LIKELY TO BE UNRELIABLE.");
// No point in trying to fiddle with the affinities, just give it our best
// shot and see how it goes.
return false;
@@ -161,6 +137,45 @@ bool impl::SingleStepWorkaroundNeeded()
return cpu != CPU_SETSIZE;
}
-#else // !arm64
-bool impl::SingleStepWorkaroundNeeded() { return false; }
+} // end anonymous namespace
+
+llvm::Optional<SingleStepWorkaround> SingleStepWorkaround::Get(::pid_t tid) {
+ Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD);
+
+ static bool workaround_needed = WorkaroundNeeded();
+ if (!workaround_needed) {
+ LLDB_LOG(log, "workaround for thread {0} not needed", tid);
+ return llvm::None;
+ }
+
+ cpu_set_t original_set;
+ if (sched_getaffinity(tid, sizeof original_set, &original_set) != 0) {
+ // This should really not fail. But, just in case...
+ LLDB_LOG(log, "Unable to get cpu affinity for thread {0}: {1}", tid,
+ Error(errno, eErrorTypePOSIX));
+ return llvm::None;
+ }
+
+ cpu_set_t set;
+ CPU_ZERO(&set);
+ CPU_SET(0, &set);
+ if (sched_setaffinity(tid, sizeof set, &set) != 0) {
+ // 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...
+ LLDB_LOG(log, "Unable to set cpu affinity for thread {0}: {1}", tid,
+ Error(errno, eErrorTypePOSIX));
+ }
+
+ LLDB_LOG(log, "workaround for thread {0} prepared", tid);
+ return SingleStepWorkaround(tid, original_set);
+}
+
+SingleStepWorkaround::~SingleStepWorkaround() {
+ if (sched_setaffinity(m_tid, sizeof m_original_set, &m_original_set) != 0) {
+ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
+ LLDB_LOG(log, "Unable to reset cpu affinity for thread {0}: {1}", m_tid,
+ Error(errno, eErrorTypePOSIX));
+ }
+}
#endif
Modified: lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h?rev=293046&r1=293045&r2=293046&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/SingleStepCheck.h Wed Jan 25 05:19:45 2017
@@ -10,30 +10,44 @@
#ifndef liblldb_SingleStepCheck_H_
#define liblldb_SingleStepCheck_H_
+#include "sched.h"
+#include "llvm/ADT/Optional.h"
+#include <sys/types.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
+// 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;
-}
+// be removed once these systems become obsolete.
+
+#if defined(__arm64__) || defined(__aarch64__)
+class SingleStepWorkaround {
+ ::pid_t m_tid;
+ cpu_set_t m_original_set;
+
+public:
+ SingleStepWorkaround(::pid_t tid, cpu_set_t original_set)
+ : m_tid(tid), m_original_set(original_set) {}
+ ~SingleStepWorkaround();
+
+ static llvm::Optional<SingleStepWorkaround> Get(::pid_t tid);
+};
+#else
+class SingleStepWorkaround {
+public:
+ static llvm::Optional<SingleStepWorkaround> Get(::pid_t tid) {
+ return llvm::None;
+ }
+};
+#endif
+
} // end namespace process_linux
} // end namespace lldb_private
More information about the lldb-commits
mailing list