123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/profiler/suspendable_thread_delegate_mac.h"
- #include <mach/mach.h>
- #include <mach/thread_act.h>
- #include <pthread.h>
- #include <vector>
- #include "base/check.h"
- #include "base/mac/mach_logging.h"
- #include "base/profiler/profile_builder.h"
- #include "build/build_config.h"
- // IMPORTANT NOTE: Some functions within this implementation are invoked while
- // the target thread is suspended so it must not do any allocation from the
- // heap, including indirectly via use of DCHECK/CHECK or other logging
- // statements. Otherwise this code can deadlock on heap locks acquired by the
- // target thread before it was suspended. These functions are commented with "NO
- // HEAP ALLOCATIONS".
- namespace base {
- namespace {
- #if defined(ARCH_CPU_X86_64)
- constexpr mach_msg_type_number_t kThreadStateCount = x86_THREAD_STATE64_COUNT;
- constexpr thread_state_flavor_t kThreadStateFlavor = x86_THREAD_STATE64;
- #elif defined(ARCH_CPU_ARM64)
- constexpr mach_msg_type_number_t kThreadStateCount = ARM_THREAD_STATE64_COUNT;
- constexpr thread_state_flavor_t kThreadStateFlavor = ARM_THREAD_STATE64;
- #endif
- // Fills |state| with |target_thread|'s context. NO HEAP ALLOCATIONS.
- bool GetThreadContextImpl(thread_act_t target_thread, RegisterContext* state) {
- auto count = kThreadStateCount;
- return thread_get_state(target_thread, kThreadStateFlavor,
- reinterpret_cast<thread_state_t>(state),
- &count) == KERN_SUCCESS;
- }
- } // namespace
- // ScopedSuspendThread --------------------------------------------------------
- // NO HEAP ALLOCATIONS after thread_suspend.
- SuspendableThreadDelegateMac::ScopedSuspendThread::ScopedSuspendThread(
- mach_port_t thread_port)
- : thread_port_(thread_suspend(thread_port) == KERN_SUCCESS
- ? thread_port
- : MACH_PORT_NULL) {}
- // NO HEAP ALLOCATIONS. The MACH_CHECK is OK because it provides a more noisy
- // failure mode than deadlocking.
- SuspendableThreadDelegateMac::ScopedSuspendThread::~ScopedSuspendThread() {
- if (!WasSuccessful())
- return;
- kern_return_t kr = thread_resume(thread_port_);
- MACH_CHECK(kr == KERN_SUCCESS, kr) << "thread_resume";
- }
- bool SuspendableThreadDelegateMac::ScopedSuspendThread::WasSuccessful() const {
- return thread_port_ != MACH_PORT_NULL;
- }
- // SuspendableThreadDelegateMac -----------------------------------------------
- SuspendableThreadDelegateMac::SuspendableThreadDelegateMac(
- SamplingProfilerThreadToken thread_token)
- : thread_port_(thread_token.id),
- thread_stack_base_address_(
- reinterpret_cast<uintptr_t>(pthread_get_stackaddr_np(
- pthread_from_mach_thread_np(thread_token.id)))) {
- // This class suspends threads, and those threads might be suspended in dyld.
- // Therefore, for all the system functions that might be linked in dynamically
- // that are used while threads are suspended, make calls to them to make sure
- // that they are linked up.
- RegisterContext thread_context;
- GetThreadContextImpl(thread_port_, &thread_context);
- }
- SuspendableThreadDelegateMac::~SuspendableThreadDelegateMac() = default;
- std::unique_ptr<SuspendableThreadDelegate::ScopedSuspendThread>
- SuspendableThreadDelegateMac::CreateScopedSuspendThread() {
- return std::make_unique<ScopedSuspendThread>(thread_port_);
- }
- PlatformThreadId SuspendableThreadDelegateMac::GetThreadId() const {
- return thread_port_;
- }
- // NO HEAP ALLOCATIONS.
- bool SuspendableThreadDelegateMac::GetThreadContext(
- RegisterContext* thread_context) {
- return GetThreadContextImpl(thread_port_, thread_context);
- }
- // NO HEAP ALLOCATIONS.
- uintptr_t SuspendableThreadDelegateMac::GetStackBaseAddress() const {
- return thread_stack_base_address_;
- }
- // NO HEAP ALLOCATIONS.
- bool SuspendableThreadDelegateMac::CanCopyStack(uintptr_t stack_pointer) {
- return true;
- }
- std::vector<uintptr_t*> SuspendableThreadDelegateMac::GetRegistersToRewrite(
- RegisterContext* thread_context) {
- #if defined(ARCH_CPU_X86_64)
- return {
- &AsUintPtr(&thread_context->__rbx), &AsUintPtr(&thread_context->__rbp),
- &AsUintPtr(&thread_context->__rsp), &AsUintPtr(&thread_context->__r12),
- &AsUintPtr(&thread_context->__r13), &AsUintPtr(&thread_context->__r14),
- &AsUintPtr(&thread_context->__r15)};
- #elif defined(ARCH_CPU_ARM64) // defined(ARCH_CPU_X86_64)
- return {
- &AsUintPtr(&thread_context->__fp),
- &AsUintPtr(&thread_context->__sp),
- &AsUintPtr(&thread_context->__x[19]),
- &AsUintPtr(&thread_context->__x[20]),
- &AsUintPtr(&thread_context->__x[21]),
- &AsUintPtr(&thread_context->__x[22]),
- &AsUintPtr(&thread_context->__x[23]),
- &AsUintPtr(&thread_context->__x[24]),
- &AsUintPtr(&thread_context->__x[25]),
- &AsUintPtr(&thread_context->__x[26]),
- &AsUintPtr(&thread_context->__x[27]),
- &AsUintPtr(&thread_context->__x[28]),
- };
- #endif // defined(ARCH_CPU_ARM64)
- }
- } // namespace base
|