stack_copier_signal.cc 9.0 KB

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