blob: b23c1bd245d5380b569928a517a85eed90a1fdc1 [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
21#include "lldb/Core/Error.h"
22#include "lldb/Core/Log.h"
23#include "lldb/Host/linux/Ptrace.h"
24
25using namespace lldb_private::process_linux;
26
27#if defined(__arm64__) || defined(__aarch64__)
Kate Stoneb9c1b512016-09-06 20:57:50 +000028namespace {
Pavel Labath605b51b2016-02-23 13:56:30 +000029
Kate Stoneb9c1b512016-09-06 20:57:50 +000030void LLVM_ATTRIBUTE_NORETURN Child() {
31 if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1)
32 _exit(1);
Pavel Labath605b51b2016-02-23 13:56:30 +000033
Kate Stoneb9c1b512016-09-06 20:57:50 +000034 // We just do an endless loop SIGSTOPPING ourselves until killed. The tracer
35 // will fiddle with our cpu
36 // affinities and monitor the behaviour.
37 for (;;) {
38 raise(SIGSTOP);
Pavel Labath605b51b2016-02-23 13:56:30 +000039
Kate Stoneb9c1b512016-09-06 20:57:50 +000040 // Generate a bunch of instructions here, so that a single-step does not
41 // land in the
42 // raise() accidentally. If single-stepping works, we will be spinning in
43 // this loop. If
44 // it doesn't, we'll land in the raise() call above.
45 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
60} // end anonymous namespace
61
Kate Stoneb9c1b512016-09-06 20:57:50 +000062bool impl::SingleStepWorkaroundNeeded() {
63 // We shall spawn a child, and use it to verify the debug capabilities of the
64 // cpu. We shall
65 // iterate through the cpus, bind the child to each one in turn, and verify
66 // that
67 // single-stepping works on that cpu. A workaround is needed if we find at
68 // least one broken
69 // cpu.
Pavel Labath605b51b2016-02-23 13:56:30 +000070
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
72 Error error;
73 ::pid_t child_pid = fork();
74 if (child_pid == -1) {
75 if (log) {
76 error.SetErrorToErrno();
77 log->Printf("%s failed to fork(): %s", __FUNCTION__, error.AsCString());
Pavel Labath605b51b2016-02-23 13:56:30 +000078 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000079 return false;
80 }
81 if (child_pid == 0)
82 Child();
Pavel Labath605b51b2016-02-23 13:56:30 +000083
Kate Stoneb9c1b512016-09-06 20:57:50 +000084 ChildDeleter child_deleter{child_pid};
85 cpu_set_t available_cpus;
86 if (sched_getaffinity(child_pid, sizeof available_cpus, &available_cpus) ==
87 -1) {
88 if (log) {
89 error.SetErrorToErrno();
90 log->Printf("%s failed to get available cpus: %s", __FUNCTION__,
91 error.AsCString());
92 }
93 return false;
94 }
95
96 int status;
97 ::pid_t wpid = waitpid(child_pid, &status, __WALL);
98 if (wpid != child_pid || !WIFSTOPPED(status)) {
99 if (log) {
100 error.SetErrorToErrno();
101 log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__, status,
102 error.AsCString());
103 }
104 return false;
105 }
106
107 unsigned cpu;
108 for (cpu = 0; cpu < CPU_SETSIZE; ++cpu) {
109 if (!CPU_ISSET(cpu, &available_cpus))
110 continue;
111
112 cpu_set_t cpus;
113 CPU_ZERO(&cpus);
114 CPU_SET(cpu, &cpus);
115 if (sched_setaffinity(child_pid, sizeof cpus, &cpus) == -1) {
116 if (log) {
117 error.SetErrorToErrno();
118 log->Printf("%s failed to switch to cpu %u: %s", __FUNCTION__, cpu,
119 error.AsCString());
120 }
121 continue;
Pavel Labath605b51b2016-02-23 13:56:30 +0000122 }
123
124 int status;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 error = NativeProcessLinux::PtraceWrapper(PTRACE_SINGLESTEP, child_pid);
126 if (error.Fail()) {
127 if (log)
128 log->Printf("%s single step failed: %s", __FUNCTION__,
129 error.AsCString());
130 break;
Pavel Labath605b51b2016-02-23 13:56:30 +0000131 }
132
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133 wpid = waitpid(child_pid, &status, __WALL);
134 if (wpid != child_pid || !WIFSTOPPED(status)) {
135 if (log) {
136 error.SetErrorToErrno();
137 log->Printf("%s waitpid() failed (status = %x): %s", __FUNCTION__,
138 status, error.AsCString());
139 }
140 break;
Pavel Labath605b51b2016-02-23 13:56:30 +0000141 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000142 if (WSTOPSIG(status) != SIGTRAP) {
143 if (log)
144 log->Printf("%s single stepping on cpu %d failed with status %x",
145 __FUNCTION__, cpu, status);
146 break;
Pavel Labath605b51b2016-02-23 13:56:30 +0000147 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 }
Pavel Labath605b51b2016-02-23 13:56:30 +0000149
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150 // cpu is either the index of the first broken cpu, or CPU_SETSIZE.
151 if (cpu == 0) {
152 if (log)
153 log->Printf("%s SINGLE STEPPING ON FIRST CPU IS NOT WORKING. DEBUGGING "
154 "LIKELY TO BE UNRELIABLE.",
155 __FUNCTION__);
156 // No point in trying to fiddle with the affinities, just give it our best
157 // shot and see how it goes.
158 return false;
159 }
160
161 return cpu != CPU_SETSIZE;
Pavel Labath605b51b2016-02-23 13:56:30 +0000162}
163
164#else // !arm64
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165bool impl::SingleStepWorkaroundNeeded() { return false; }
Pavel Labath605b51b2016-02-23 13:56:30 +0000166#endif