summaryrefslogtreecommitdiff
path: root/source/Plugins/Process/Linux/SingleStepCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins/Process/Linux/SingleStepCheck.cpp')
-rw-r--r--source/Plugins/Process/Linux/SingleStepCheck.cpp182
1 files changed, 0 insertions, 182 deletions
diff --git a/source/Plugins/Process/Linux/SingleStepCheck.cpp b/source/Plugins/Process/Linux/SingleStepCheck.cpp
deleted file mode 100644
index c57a2daf2275..000000000000
--- a/source/Plugins/Process/Linux/SingleStepCheck.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-//===-- 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 "Plugins/Process/POSIX/ProcessPOSIXLog.h"
-#include "lldb/Host/linux/Ptrace.h"
-#include "lldb/Utility/Status.h"
-
-using namespace lldb;
-using namespace lldb_private;
-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.
- }
-};
-
-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.
-
- Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD);
- ::pid_t child_pid = fork();
- if (child_pid == -1) {
- LLDB_LOG(log, "failed to fork(): {0}", Status(errno, eErrorTypePOSIX));
- 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) {
- LLDB_LOG(log, "failed to get available cpus: {0}",
- Status(errno, eErrorTypePOSIX));
- return false;
- }
-
- int status;
- ::pid_t wpid = waitpid(child_pid, &status, __WALL);
- if (wpid != child_pid || !WIFSTOPPED(status)) {
- LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status,
- Status(errno, eErrorTypePOSIX));
- 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) {
- LLDB_LOG(log, "failed to switch to cpu {0}: {1}", cpu,
- Status(errno, eErrorTypePOSIX));
- continue;
- }
-
- int status;
- Status error =
- NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid);
- if (error.Fail()) {
- LLDB_LOG(log, "single step failed: {0}", error);
- break;
- }
-
- wpid = waitpid(child_pid, &status, __WALL);
- if (wpid != child_pid || !WIFSTOPPED(status)) {
- LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status,
- Status(errno, eErrorTypePOSIX));
- break;
- }
- if (WSTOPSIG(status) != SIGTRAP) {
- 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) {
- 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;
- }
-
- return cpu != CPU_SETSIZE;
-}
-
-} // end anonymous namespace
-
-std::unique_ptr<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 nullptr;
- }
-
- 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,
- Status(errno, eErrorTypePOSIX));
- return nullptr;
- }
-
- 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,
- Status(errno, eErrorTypePOSIX));
- }
-
- LLDB_LOG(log, "workaround for thread {0} prepared", tid);
- return llvm::make_unique<SingleStepWorkaround>(tid, original_set);
-}
-
-SingleStepWorkaround::~SingleStepWorkaround() {
- Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD);
- LLDB_LOG(log, "Removing workaround");
- if (sched_setaffinity(m_tid, sizeof m_original_set, &m_original_set) != 0) {
- LLDB_LOG(log, "Unable to reset cpu affinity for thread {0}: {1}", m_tid,
- Status(errno, eErrorTypePOSIX));
- }
-}
-#endif