1 //===-- SingleStepCheck.cpp -----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "SingleStepCheck.h" 10 11 #include <csignal> 12 #include <sched.h> 13 #include <sys/wait.h> 14 #include <unistd.h> 15 16 #include "NativeProcessLinux.h" 17 18 #include "llvm/Support/Compiler.h" 19 #include "llvm/Support/Errno.h" 20 21 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 22 #include "lldb/Host/linux/Ptrace.h" 23 #include "lldb/Utility/Status.h" 24 25 using namespace lldb; 26 using namespace lldb_private; 27 using namespace lldb_private::process_linux; 28 29 #if defined(__arm64__) || defined(__aarch64__) 30 namespace { 31 32 [[noreturn]] void Child() { 33 if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1) 34 _exit(1); 35 36 // We just do an endless loop SIGSTOPPING ourselves until killed. The tracer 37 // will fiddle with our cpu affinities and monitor the behaviour. 38 for (;;) { 39 raise(SIGSTOP); 40 41 // Generate a bunch of instructions here, so that a single-step does not 42 // land in the raise() accidentally. If single-stepping works, we will be 43 // spinning in this loop. If it doesn't, we'll land in the raise() call 44 // above. 45 for (volatile unsigned i = 0; i < CPU_SETSIZE; ++i) 46 ; 47 } 48 } 49 50 struct ChildDeleter { 51 ::pid_t pid; 52 53 ~ChildDeleter() { 54 int status; 55 // Kill the child. 56 kill(pid, SIGKILL); 57 // Pick up the remains. 58 llvm::sys::RetryAfterSignal(-1, waitpid, pid, &status, __WALL); 59 } 60 }; 61 62 bool WorkaroundNeeded() { 63 // We shall spawn a child, and use it to verify the debug capabilities of the 64 // cpu. We shall iterate through the cpus, bind the child to each one in 65 // turn, and verify that single-stepping works on that cpu. A workaround is 66 // needed if we find at least one broken cpu. 67 68 Log *log = GetLog(POSIXLog::Thread); 69 ::pid_t child_pid = fork(); 70 if (child_pid == -1) { 71 LLDB_LOG(log, "failed to fork(): {0}", Status(errno, eErrorTypePOSIX)); 72 return false; 73 } 74 if (child_pid == 0) 75 Child(); 76 77 ChildDeleter child_deleter{child_pid}; 78 cpu_set_t available_cpus; 79 if (sched_getaffinity(child_pid, sizeof available_cpus, &available_cpus) == 80 -1) { 81 LLDB_LOG(log, "failed to get available cpus: {0}", 82 Status(errno, eErrorTypePOSIX)); 83 return false; 84 } 85 86 int status; 87 ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, waitpid, 88 child_pid, &status, __WALL); 89 if (wpid != child_pid || !WIFSTOPPED(status)) { 90 LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status, 91 Status(errno, eErrorTypePOSIX)); 92 return false; 93 } 94 95 unsigned cpu; 96 for (cpu = 0; cpu < CPU_SETSIZE; ++cpu) { 97 if (!CPU_ISSET(cpu, &available_cpus)) 98 continue; 99 100 cpu_set_t cpus; 101 CPU_ZERO(&cpus); 102 CPU_SET(cpu, &cpus); 103 if (sched_setaffinity(child_pid, sizeof cpus, &cpus) == -1) { 104 LLDB_LOG(log, "failed to switch to cpu {0}: {1}", cpu, 105 Status(errno, eErrorTypePOSIX)); 106 continue; 107 } 108 109 int status; 110 Status error = 111 NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid); 112 if (error.Fail()) { 113 LLDB_LOG(log, "single step failed: {0}", error); 114 break; 115 } 116 117 wpid = llvm::sys::RetryAfterSignal(-1, waitpid, 118 child_pid, &status, __WALL); 119 if (wpid != child_pid || !WIFSTOPPED(status)) { 120 LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status, 121 Status(errno, eErrorTypePOSIX)); 122 break; 123 } 124 if (WSTOPSIG(status) != SIGTRAP) { 125 LLDB_LOG(log, "single stepping on cpu {0} failed with status {1:x}", cpu, 126 status); 127 break; 128 } 129 } 130 131 // cpu is either the index of the first broken cpu, or CPU_SETSIZE. 132 if (cpu == 0) { 133 LLDB_LOG(log, 134 "SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING " 135 "LIKELY TO BE UNRELIABLE."); 136 // No point in trying to fiddle with the affinities, just give it our best 137 // shot and see how it goes. 138 return false; 139 } 140 141 return cpu != CPU_SETSIZE; 142 } 143 144 } // end anonymous namespace 145 146 std::unique_ptr<SingleStepWorkaround> SingleStepWorkaround::Get(::pid_t tid) { 147 Log *log = GetLog(POSIXLog::Thread); 148 149 static bool workaround_needed = WorkaroundNeeded(); 150 if (!workaround_needed) { 151 LLDB_LOG(log, "workaround for thread {0} not needed", tid); 152 return nullptr; 153 } 154 155 cpu_set_t original_set; 156 if (sched_getaffinity(tid, sizeof original_set, &original_set) != 0) { 157 // This should really not fail. But, just in case... 158 LLDB_LOG(log, "Unable to get cpu affinity for thread {0}: {1}", tid, 159 Status(errno, eErrorTypePOSIX)); 160 return nullptr; 161 } 162 163 cpu_set_t set; 164 CPU_ZERO(&set); 165 CPU_SET(0, &set); 166 if (sched_setaffinity(tid, sizeof set, &set) != 0) { 167 // This may fail in very locked down systems, if the thread is not allowed 168 // to run on cpu 0. If that happens, only thing we can do is it log it and 169 // continue... 170 LLDB_LOG(log, "Unable to set cpu affinity for thread {0}: {1}", tid, 171 Status(errno, eErrorTypePOSIX)); 172 } 173 174 LLDB_LOG(log, "workaround for thread {0} prepared", tid); 175 return std::make_unique<SingleStepWorkaround>(tid, original_set); 176 } 177 178 SingleStepWorkaround::~SingleStepWorkaround() { 179 Log *log = GetLog(POSIXLog::Thread); 180 LLDB_LOG(log, "Removing workaround"); 181 if (sched_setaffinity(m_tid, sizeof m_original_set, &m_original_set) != 0) { 182 LLDB_LOG(log, "Unable to reset cpu affinity for thread {0}: {1}", m_tid, 183 Status(errno, eErrorTypePOSIX)); 184 } 185 } 186 #endif 187