1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/profiler/stack_copier_signal.h"
6 
7 #if defined(OS_LINUX)
8 #include <linux/futex.h>
9 #include <syscall.h>
10 #elif defined(OS_FREEBSD)
11 #include <sys/types.h>
12 #include <sys/thr.h>
13 #include <sys/umtx.h>
14 #endif
15 #include <signal.h>
16 #include <sys/ucontext.h>
17 #include <syscall.h>
18 
19 #include <atomic>
20 
21 #include "base/notreached.h"
22 #include "base/profiler/register_context.h"
23 #include "base/profiler/stack_buffer.h"
24 #include "base/profiler/suspendable_thread_delegate.h"
25 #include "base/trace_event/base_tracing.h"
26 #include "build/build_config.h"
27 
28 namespace base {
29 
30 namespace {
31 
32 // Waitable event implementation with futex and without DCHECK(s), since signal
33 // handlers cannot allocate memory or use pthread api.
34 class AsyncSafeWaitableEvent {
35  public:
AsyncSafeWaitableEvent()36   AsyncSafeWaitableEvent() { futex_.store(0, std::memory_order_release); }
~AsyncSafeWaitableEvent()37   ~AsyncSafeWaitableEvent() {}
38 
Wait()39   bool Wait() {
40     // futex() can wake up spuriously if this memory address was previously used
41     // for a pthread mutex. So, also check the condition.
42     while (true) {
43       int res =
44 #if defined(OS_LINUX)
45           syscall(SYS_futex, futex_int_ptr(), FUTEX_WAIT | FUTEX_PRIVATE_FLAG,
46                   0, nullptr, nullptr, 0);
47 #elif defined(OS_FREEBSD)
48           _umtx_op(futex_int_ptr(), UMTX_OP_WAIT_UINT_PRIVATE, 0, nullptr,
49                    nullptr);
50 #endif
51       if (futex_.load(std::memory_order_acquire) != 0)
52         return true;
53       if (res != 0)
54         return false;
55     }
56   }
57 
Signal()58   void Signal() {
59     futex_.store(1, std::memory_order_release);
60 #if defined(OS_LINUX)
61     syscall(SYS_futex, futex_int_ptr(), FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1,
62             nullptr, nullptr, 0);
63 #elif defined(OS_FREEBSD)
64     _umtx_op(futex_int_ptr(), UMTX_OP_WAKE_PRIVATE, 1, nullptr, nullptr);
65 #endif
66   }
67 
68  private:
69   // Provides a pointer to the atomic's storage. std::atomic_int has standard
70   // layout so its address can be used for the pointer as long as it only
71   // contains the int.
futex_int_ptr()72   int* futex_int_ptr() {
73     static_assert(sizeof(futex_) == sizeof(int),
74                   "Expected std::atomic_int to be the same size as int");
75     return reinterpret_cast<int*>(&futex_);
76   }
77 
78   std::atomic_int futex_{0};
79 };
80 
81 // Scoped signal event that calls Signal on the AsyncSafeWaitableEvent at
82 // destructor.
83 class ScopedEventSignaller {
84  public:
ScopedEventSignaller(AsyncSafeWaitableEvent * event)85   ScopedEventSignaller(AsyncSafeWaitableEvent* event) : event_(event) {}
~ScopedEventSignaller()86   ~ScopedEventSignaller() { event_->Signal(); }
87 
88  private:
89   AsyncSafeWaitableEvent* event_;
90 };
91 
92 // Struct to store the arguments to the signal handler.
93 struct HandlerParams {
94   uintptr_t stack_base_address;
95 
96   // The event is signalled when signal handler is done executing.
97   AsyncSafeWaitableEvent* event;
98 
99   // Return values:
100 
101   // Successfully copied the stack segment.
102   bool* success;
103 
104   // The thread context of the leaf function.
105   mcontext_t* context;
106 
107   // Buffer to copy the stack segment.
108   StackBuffer* stack_buffer;
109   const uint8_t** stack_copy_bottom;
110 
111   // The timestamp when the stack was copied.
112   TimeTicks* timestamp;
113 
114   // The delegate provided to the StackCopier.
115   StackCopier::Delegate* stack_copier_delegate;
116 };
117 
118 // Pointer to the parameters to be "passed" to the CopyStackSignalHandler() from
119 // the sampling thread to the sampled (stopped) thread. This value is set just
120 // before sending the signal to the thread and reset when the handler is done.
121 std::atomic<HandlerParams*> g_handler_params;
122 
123 // CopyStackSignalHandler is invoked on the stopped thread and records the
124 // thread's stack and register context at the time the signal was received. This
125 // function may only call reentrant code.
CopyStackSignalHandler(int n,siginfo_t * siginfo,void * sigcontext)126 void CopyStackSignalHandler(int n, siginfo_t* siginfo, void* sigcontext) {
127   HandlerParams* params = g_handler_params.load(std::memory_order_acquire);
128 
129   // TimeTicks::Now() is implemented in terms of clock_gettime on Linux, which
130   // is signal safe per the signal-safety(7) man page.
131   *params->timestamp = TimeTicks::Now();
132 
133   ScopedEventSignaller e(params->event);
134   *params->success = false;
135 
136   const ucontext_t* ucontext = static_cast<ucontext_t*>(sigcontext);
137   memcpy(params->context, &ucontext->uc_mcontext, sizeof(mcontext_t));
138 
139   const uintptr_t bottom = RegisterContextStackPointer(params->context);
140   const uintptr_t top = params->stack_base_address;
141   if ((top - bottom) > params->stack_buffer->size()) {
142     // The stack exceeds the size of the allocated buffer. The buffer is sized
143     // such that this shouldn't happen under typical execution so we can safely
144     // punt in this situation.
145     return;
146   }
147 
148   params->stack_copier_delegate->OnStackCopy();
149 
150   *params->stack_copy_bottom =
151       StackCopierSignal::CopyStackContentsAndRewritePointers(
152           reinterpret_cast<uint8_t*>(bottom), reinterpret_cast<uintptr_t*>(top),
153           StackBuffer::kPlatformStackAlignment, params->stack_buffer->buffer());
154 
155   *params->success = true;
156 }
157 
158 // Sets the global handler params for the signal handler function.
159 class ScopedSetSignalHandlerParams {
160  public:
ScopedSetSignalHandlerParams(HandlerParams * params)161   ScopedSetSignalHandlerParams(HandlerParams* params) {
162     g_handler_params.store(params, std::memory_order_release);
163   }
164 
~ScopedSetSignalHandlerParams()165   ~ScopedSetSignalHandlerParams() {
166     g_handler_params.store(nullptr, std::memory_order_release);
167   }
168 };
169 
170 class ScopedSigaction {
171  public:
ScopedSigaction(int signal,struct sigaction * action,struct sigaction * original_action)172   ScopedSigaction(int signal,
173                   struct sigaction* action,
174                   struct sigaction* original_action)
175       : signal_(signal),
176         action_(action),
177         original_action_(original_action),
178         succeeded_(sigaction(signal, action, original_action) == 0) {}
179 
succeeded() const180   bool succeeded() const { return succeeded_; }
181 
~ScopedSigaction()182   ~ScopedSigaction() {
183     if (!succeeded_)
184       return;
185 
186     bool reset_succeeded = sigaction(signal_, original_action_, action_) == 0;
187     DCHECK(reset_succeeded);
188   }
189 
190  private:
191   const int signal_;
192   struct sigaction* const action_;
193   struct sigaction* const original_action_;
194   const bool succeeded_;
195 };
196 
197 }  // namespace
198 
StackCopierSignal(std::unique_ptr<ThreadDelegate> thread_delegate)199 StackCopierSignal::StackCopierSignal(
200     std::unique_ptr<ThreadDelegate> thread_delegate)
201     : thread_delegate_(std::move(thread_delegate)) {}
202 
203 StackCopierSignal::~StackCopierSignal() = default;
204 
CopyStack(StackBuffer * stack_buffer,uintptr_t * stack_top,TimeTicks * timestamp,RegisterContext * thread_context,Delegate * delegate)205 bool StackCopierSignal::CopyStack(StackBuffer* stack_buffer,
206                                   uintptr_t* stack_top,
207                                   TimeTicks* timestamp,
208                                   RegisterContext* thread_context,
209                                   Delegate* delegate) {
210   AsyncSafeWaitableEvent wait_event;
211   bool copied = false;
212   const uint8_t* stack_copy_bottom = nullptr;
213   const uintptr_t stack_base_address = thread_delegate_->GetStackBaseAddress();
214   HandlerParams params = {stack_base_address, &wait_event,  &copied,
215                           thread_context,     stack_buffer, &stack_copy_bottom,
216                           timestamp,          delegate};
217   {
218     ScopedSetSignalHandlerParams scoped_handler_params(&params);
219 
220     // Set the signal handler for the thread to the stack copy function.
221     struct sigaction action;
222     struct sigaction original_action;
223     memset(&action, 0, sizeof(action));
224     action.sa_sigaction = CopyStackSignalHandler;
225     action.sa_flags = SA_RESTART | SA_SIGINFO;
226     sigemptyset(&action.sa_mask);
227     TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
228                        "StackCopierSignal copy stack");
229     // SIGURG is chosen here because we observe no crashes with this signal and
230     // neither Chrome or the AOSP sets up a special handler for this signal.
231     ScopedSigaction scoped_sigaction(SIGURG, &action, &original_action);
232     if (!scoped_sigaction.succeeded())
233       return false;
234 
235 #if defined(OS_LINUX)
236     if (syscall(SYS_tgkill, getpid(), thread_delegate_->GetThreadId(),
237                 SIGURG) != 0) {
238       NOTREACHED();
239       return false;
240     }
241 #elif defined(OS_FREEBSD)
242     if (thr_kill2(getpid(), thread_delegate_->GetThreadId(), SIGURG) != 0) {
243       NOTREACHED();
244       return false;
245     }
246 #endif
247     bool finished_waiting = wait_event.Wait();
248     TRACE_EVENT_END0(TRACE_DISABLED_BY_DEFAULT("cpu_profiler.debug"),
249                      "StackCopierSignal copy stack");
250     if (!finished_waiting) {
251       NOTREACHED();
252       return false;
253     }
254   }
255 
256   const uintptr_t bottom = RegisterContextStackPointer(params.context);
257   for (uintptr_t* reg :
258        thread_delegate_->GetRegistersToRewrite(thread_context)) {
259     *reg = StackCopierSignal::RewritePointerIfInOriginalStack(
260         reinterpret_cast<uint8_t*>(bottom),
261         reinterpret_cast<uintptr_t*>(stack_base_address), stack_copy_bottom,
262         *reg);
263   }
264 
265   *stack_top = reinterpret_cast<uintptr_t>(stack_copy_bottom) +
266                (stack_base_address - bottom);
267 
268   return copied;
269 }
270 
271 }  // namespace base
272