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.
llvm-svn: 293046
diff --git a/lldb/source/Plugins/Process/Linux/SingleStepCheck.cpp b/lldb/source/Plugins/Process/Linux/SingleStepCheck.cpp
index b23c1bd..f3a07e0 100644
--- a/lldb/source/Plugins/Process/Linux/SingleStepCheck.cpp
+++ b/lldb/source/Plugins/Process/Linux/SingleStepCheck.cpp
@@ -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 @@
_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 @@
}
};
-} // 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 @@
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 @@
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 @@
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