blob: c57a2daf22757ffc7d13d3441e52e2b6e78b9db0 [file] [log] [blame]
Pavel Labath605b51b2016-02-23 13:56:30 +00001//===-- SingleStepCheck.cpp ----------------------------------- -*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "SingleStepCheck.h"
11
12#include <sched.h>
13#include <signal.h>
14#include <sys/wait.h>
15#include <unistd.h>
16
17#include "NativeProcessLinux.h"
18
19#include "llvm/Support/Compiler.h"
20
Pavel Labath8abd34f2017-01-25 11:19:45 +000021#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
Pavel Labath605b51b2016-02-23 13:56:30 +000022#include "lldb/Host/linux/Ptrace.h"
Zachary Turner97206d52017-05-12 04:51:55 +000023#include "lldb/Utility/Status.h"
Pavel Labath605b51b2016-02-23 13:56:30 +000024
Pavel Labath8abd34f2017-01-25 11:19:45 +000025using namespace lldb;
26using namespace lldb_private;
Pavel Labath605b51b2016-02-23 13:56:30 +000027using namespace lldb_private::process_linux;
28
29#if defined(__arm64__) || defined(__aarch64__)
Kate Stoneb9c1b512016-09-06 20:57:50 +000030namespace {
Pavel Labath605b51b2016-02-23 13:56:30 +000031
Kate Stoneb9c1b512016-09-06 20:57:50 +000032void LLVM_ATTRIBUTE_NORETURN Child() {
33 if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1)
34 _exit(1);
Pavel Labath605b51b2016-02-23 13:56:30 +000035
Kate Stoneb9c1b512016-09-06 20:57:50 +000036 // We just do an endless loop SIGSTOPPING ourselves until killed. The tracer
Pavel Labath8abd34f2017-01-25 11:19:45 +000037 // will fiddle with our cpu affinities and monitor the behaviour.
Kate Stoneb9c1b512016-09-06 20:57:50 +000038 for (;;) {
39 raise(SIGSTOP);
Pavel Labath605b51b2016-02-23 13:56:30 +000040
Kate Stoneb9c1b512016-09-06 20:57:50 +000041 // Generate a bunch of instructions here, so that a single-step does not
Pavel Labath8abd34f2017-01-25 11:19:45 +000042 // 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.
Kate Stoneb9c1b512016-09-06 20:57:50 +000045 for (volatile unsigned i = 0; i < CPU_SETSIZE; ++i)
46 ;
47 }
Pavel Labath605b51b2016-02-23 13:56:30 +000048}
49
Kate Stoneb9c1b512016-09-06 20:57:50 +000050struct ChildDeleter {
51 ::pid_t pid;
Pavel Labath605b51b2016-02-23 13:56:30 +000052
Kate Stoneb9c1b512016-09-06 20:57:50 +000053 ~ChildDeleter() {
54 int status;
55 kill(pid, SIGKILL); // Kill the child.
56 waitpid(pid, &status, __WALL); // Pick up the remains.
57 }
Pavel Labath605b51b2016-02-23 13:56:30 +000058};
59
Pavel Labath8abd34f2017-01-25 11:19:45 +000060bool WorkaroundNeeded() {
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 // We shall spawn a child, and use it to verify the debug capabilities of the
Adrian Prantl05097242018-04-30 16:49:04 +000062 // cpu. We shall iterate through the cpus, bind the child to each one in
63 // turn, and verify that single-stepping works on that cpu. A workaround is
64 // needed if we find at least one broken cpu.
Pavel Labath605b51b2016-02-23 13:56:30 +000065
Pavel Labath8abd34f2017-01-25 11:19:45 +000066 Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD);
Kate Stoneb9c1b512016-09-06 20:57:50 +000067 ::pid_t child_pid = fork();
68 if (child_pid == -1) {
Zachary Turner41c99362017-05-12 05:48:54 +000069 LLDB_LOG(log, "failed to fork(): {0}", Status(errno, eErrorTypePOSIX));
Kate Stoneb9c1b512016-09-06 20:57:50 +000070 return false;
71 }
72 if (child_pid == 0)
73 Child();
Pavel Labath605b51b2016-02-23 13:56:30 +000074
Kate Stoneb9c1b512016-09-06 20:57:50 +000075 ChildDeleter child_deleter{child_pid};
76 cpu_set_t available_cpus;
77 if (sched_getaffinity(child_pid, sizeof available_cpus, &available_cpus) ==
78 -1) {
Pavel Labath8abd34f2017-01-25 11:19:45 +000079 LLDB_LOG(log, "failed to get available cpus: {0}",
Zachary Turner97206d52017-05-12 04:51:55 +000080 Status(errno, eErrorTypePOSIX));
Kate Stoneb9c1b512016-09-06 20:57:50 +000081 return false;
82 }
83
84 int status;
85 ::pid_t wpid = waitpid(child_pid, &status, __WALL);
86 if (wpid != child_pid || !WIFSTOPPED(status)) {
Pavel Labath8abd34f2017-01-25 11:19:45 +000087 LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status,
Zachary Turner97206d52017-05-12 04:51:55 +000088 Status(errno, eErrorTypePOSIX));
Kate Stoneb9c1b512016-09-06 20:57:50 +000089 return false;
90 }
91
92 unsigned cpu;
93 for (cpu = 0; cpu < CPU_SETSIZE; ++cpu) {
94 if (!CPU_ISSET(cpu, &available_cpus))
95 continue;
96
97 cpu_set_t cpus;
98 CPU_ZERO(&cpus);
99 CPU_SET(cpu, &cpus);
100 if (sched_setaffinity(child_pid, sizeof cpus, &cpus) == -1) {
Pavel Labath8abd34f2017-01-25 11:19:45 +0000101 LLDB_LOG(log, "failed to switch to cpu {0}: {1}", cpu,
Zachary Turner97206d52017-05-12 04:51:55 +0000102 Status(errno, eErrorTypePOSIX));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000103 continue;
Pavel Labath605b51b2016-02-23 13:56:30 +0000104 }
105
106 int status;
Zachary Turner97206d52017-05-12 04:51:55 +0000107 Status error =
Pavel Labath8abd34f2017-01-25 11:19:45 +0000108 NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109 if (error.Fail()) {
Pavel Labath8abd34f2017-01-25 11:19:45 +0000110 LLDB_LOG(log, "single step failed: {0}", error);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111 break;
Pavel Labath605b51b2016-02-23 13:56:30 +0000112 }
113
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114 wpid = waitpid(child_pid, &status, __WALL);
115 if (wpid != child_pid || !WIFSTOPPED(status)) {
Pavel Labath8abd34f2017-01-25 11:19:45 +0000116 LLDB_LOG(log, "waitpid() failed (status = {0:x}): {1}", status,
Zachary Turner97206d52017-05-12 04:51:55 +0000117 Status(errno, eErrorTypePOSIX));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118 break;
Pavel Labath605b51b2016-02-23 13:56:30 +0000119 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120 if (WSTOPSIG(status) != SIGTRAP) {
Pavel Labath8abd34f2017-01-25 11:19:45 +0000121 LLDB_LOG(log, "single stepping on cpu {0} failed with status {1:x}", cpu,
122 status);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123 break;
Pavel Labath605b51b2016-02-23 13:56:30 +0000124 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 }
Pavel Labath605b51b2016-02-23 13:56:30 +0000126
Kate Stoneb9c1b512016-09-06 20:57:50 +0000127 // cpu is either the index of the first broken cpu, or CPU_SETSIZE.
128 if (cpu == 0) {
Pavel Labath8abd34f2017-01-25 11:19:45 +0000129 LLDB_LOG(log,
130 "SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING "
131 "LIKELY TO BE UNRELIABLE.");
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 // No point in trying to fiddle with the affinities, just give it our best
133 // shot and see how it goes.
134 return false;
135 }
136
137 return cpu != CPU_SETSIZE;
Pavel Labath605b51b2016-02-23 13:56:30 +0000138}
139
Pavel Labath8abd34f2017-01-25 11:19:45 +0000140} // end anonymous namespace
141
Pavel Labath72784962017-02-16 18:12:04 +0000142std::unique_ptr<SingleStepWorkaround> SingleStepWorkaround::Get(::pid_t tid) {
Pavel Labath8abd34f2017-01-25 11:19:45 +0000143 Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD);
144
145 static bool workaround_needed = WorkaroundNeeded();
146 if (!workaround_needed) {
147 LLDB_LOG(log, "workaround for thread {0} not needed", tid);
Pavel Labath72784962017-02-16 18:12:04 +0000148 return nullptr;
Pavel Labath8abd34f2017-01-25 11:19:45 +0000149 }
150
151 cpu_set_t original_set;
152 if (sched_getaffinity(tid, sizeof original_set, &original_set) != 0) {
153 // This should really not fail. But, just in case...
154 LLDB_LOG(log, "Unable to get cpu affinity for thread {0}: {1}", tid,
Zachary Turner97206d52017-05-12 04:51:55 +0000155 Status(errno, eErrorTypePOSIX));
Pavel Labath72784962017-02-16 18:12:04 +0000156 return nullptr;
Pavel Labath8abd34f2017-01-25 11:19:45 +0000157 }
158
159 cpu_set_t set;
160 CPU_ZERO(&set);
161 CPU_SET(0, &set);
162 if (sched_setaffinity(tid, sizeof set, &set) != 0) {
163 // This may fail in very locked down systems, if the thread is not allowed
164 // to run on cpu 0. If that happens, only thing we can do is it log it and
165 // continue...
166 LLDB_LOG(log, "Unable to set cpu affinity for thread {0}: {1}", tid,
Zachary Turner97206d52017-05-12 04:51:55 +0000167 Status(errno, eErrorTypePOSIX));
Pavel Labath8abd34f2017-01-25 11:19:45 +0000168 }
169
170 LLDB_LOG(log, "workaround for thread {0} prepared", tid);
Pavel Labath72784962017-02-16 18:12:04 +0000171 return llvm::make_unique<SingleStepWorkaround>(tid, original_set);
Pavel Labath8abd34f2017-01-25 11:19:45 +0000172}
173
174SingleStepWorkaround::~SingleStepWorkaround() {
Pavel Labatha37bbbd2017-02-17 11:48:34 +0000175 Log *log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD);
176 LLDB_LOG(log, "Removing workaround");
Pavel Labath8abd34f2017-01-25 11:19:45 +0000177 if (sched_setaffinity(m_tid, sizeof m_original_set, &m_original_set) != 0) {
Pavel Labath8abd34f2017-01-25 11:19:45 +0000178 LLDB_LOG(log, "Unable to reset cpu affinity for thread {0}: {1}", m_tid,
Zachary Turner97206d52017-05-12 04:51:55 +0000179 Status(errno, eErrorTypePOSIX));
Pavel Labath8abd34f2017-01-25 11:19:45 +0000180 }
181}
Pavel Labath605b51b2016-02-23 13:56:30 +0000182#endif