• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "base/profiler/suspendable_thread_delegate_mac.h"
11 
12 #include <mach/mach.h>
13 #include <mach/thread_act.h>
14 #include <pthread.h>
15 
16 #include <vector>
17 
18 #include "base/apple/mach_logging.h"
19 #include "base/check.h"
20 #include "base/profiler/profile_builder.h"
21 #include "build/build_config.h"
22 
23 // IMPORTANT NOTE: Some functions within this implementation are invoked while
24 // the target thread is suspended so it must not do any allocation from the
25 // heap, including indirectly via use of DCHECK/CHECK or other logging
26 // statements. Otherwise this code can deadlock on heap locks acquired by the
27 // target thread before it was suspended. These functions are commented with "NO
28 // HEAP ALLOCATIONS".
29 
30 namespace base {
31 
32 namespace {
33 
34 #if defined(ARCH_CPU_X86_64)
35 constexpr mach_msg_type_number_t kThreadStateCount = x86_THREAD_STATE64_COUNT;
36 constexpr thread_state_flavor_t kThreadStateFlavor = x86_THREAD_STATE64;
37 #elif defined(ARCH_CPU_ARM64)
38 constexpr mach_msg_type_number_t kThreadStateCount = ARM_THREAD_STATE64_COUNT;
39 constexpr thread_state_flavor_t kThreadStateFlavor = ARM_THREAD_STATE64;
40 #endif
41 
42 // Fills |state| with |target_thread|'s context. NO HEAP ALLOCATIONS.
GetThreadContextImpl(thread_act_t target_thread,RegisterContext * state)43 bool GetThreadContextImpl(thread_act_t target_thread, RegisterContext* state) {
44   auto count = kThreadStateCount;
45   return thread_get_state(target_thread, kThreadStateFlavor,
46                           reinterpret_cast<thread_state_t>(state),
47                           &count) == KERN_SUCCESS;
48 }
49 
50 }  // namespace
51 
52 // ScopedSuspendThread --------------------------------------------------------
53 
54 // NO HEAP ALLOCATIONS after thread_suspend.
ScopedSuspendThread(mach_port_t thread_port)55 SuspendableThreadDelegateMac::ScopedSuspendThread::ScopedSuspendThread(
56     mach_port_t thread_port)
57     : thread_port_(thread_suspend(thread_port) == KERN_SUCCESS
58                        ? thread_port
59                        : MACH_PORT_NULL) {}
60 
61 // NO HEAP ALLOCATIONS. The MACH_CHECK is OK because it provides a more noisy
62 // failure mode than deadlocking.
~ScopedSuspendThread()63 SuspendableThreadDelegateMac::ScopedSuspendThread::~ScopedSuspendThread() {
64   if (!WasSuccessful())
65     return;
66 
67   kern_return_t kr = thread_resume(thread_port_);
68   MACH_CHECK(kr == KERN_SUCCESS, kr) << "thread_resume";
69 }
70 
WasSuccessful() const71 bool SuspendableThreadDelegateMac::ScopedSuspendThread::WasSuccessful() const {
72   return thread_port_ != MACH_PORT_NULL;
73 }
74 
75 // SuspendableThreadDelegateMac -----------------------------------------------
76 
SuspendableThreadDelegateMac(SamplingProfilerThreadToken thread_token)77 SuspendableThreadDelegateMac::SuspendableThreadDelegateMac(
78     SamplingProfilerThreadToken thread_token)
79     : thread_port_(thread_token.id),
80       thread_stack_base_address_(
81           reinterpret_cast<uintptr_t>(pthread_get_stackaddr_np(
82               pthread_from_mach_thread_np(thread_token.id)))) {
83   // This class suspends threads, and those threads might be suspended in dyld.
84   // Therefore, for all the system functions that might be linked in dynamically
85   // that are used while threads are suspended, make calls to them to make sure
86   // that they are linked up.
87   RegisterContext thread_context;
88   GetThreadContextImpl(thread_port_, &thread_context);
89 }
90 
91 SuspendableThreadDelegateMac::~SuspendableThreadDelegateMac() = default;
92 
93 std::unique_ptr<SuspendableThreadDelegate::ScopedSuspendThread>
CreateScopedSuspendThread()94 SuspendableThreadDelegateMac::CreateScopedSuspendThread() {
95   return std::make_unique<ScopedSuspendThread>(thread_port_);
96 }
97 
GetThreadId() const98 PlatformThreadId SuspendableThreadDelegateMac::GetThreadId() const {
99   return thread_port_;
100 }
101 
102 // NO HEAP ALLOCATIONS.
GetThreadContext(RegisterContext * thread_context)103 bool SuspendableThreadDelegateMac::GetThreadContext(
104     RegisterContext* thread_context) {
105   return GetThreadContextImpl(thread_port_, thread_context);
106 }
107 
108 // NO HEAP ALLOCATIONS.
GetStackBaseAddress() const109 uintptr_t SuspendableThreadDelegateMac::GetStackBaseAddress() const {
110   return thread_stack_base_address_;
111 }
112 
113 // NO HEAP ALLOCATIONS.
CanCopyStack(uintptr_t stack_pointer)114 bool SuspendableThreadDelegateMac::CanCopyStack(uintptr_t stack_pointer) {
115   return true;
116 }
117 
GetRegistersToRewrite(RegisterContext * thread_context)118 std::vector<uintptr_t*> SuspendableThreadDelegateMac::GetRegistersToRewrite(
119     RegisterContext* thread_context) {
120 #if defined(ARCH_CPU_X86_64)
121   return {
122       &AsUintPtr(&thread_context->__rbx), &AsUintPtr(&thread_context->__rbp),
123       &AsUintPtr(&thread_context->__rsp), &AsUintPtr(&thread_context->__r12),
124       &AsUintPtr(&thread_context->__r13), &AsUintPtr(&thread_context->__r14),
125       &AsUintPtr(&thread_context->__r15)};
126 #elif defined(ARCH_CPU_ARM64)  // defined(ARCH_CPU_X86_64)
127   return {
128       &AsUintPtr(&thread_context->__fp),
129       &AsUintPtr(&thread_context->__sp),
130       &AsUintPtr(&thread_context->__x[19]),
131       &AsUintPtr(&thread_context->__x[20]),
132       &AsUintPtr(&thread_context->__x[21]),
133       &AsUintPtr(&thread_context->__x[22]),
134       &AsUintPtr(&thread_context->__x[23]),
135       &AsUintPtr(&thread_context->__x[24]),
136       &AsUintPtr(&thread_context->__x[25]),
137       &AsUintPtr(&thread_context->__x[26]),
138       &AsUintPtr(&thread_context->__x[27]),
139       &AsUintPtr(&thread_context->__x[28]),
140   };
141 #endif                         // defined(ARCH_CPU_ARM64)
142 }
143 
144 }  // namespace base
145