blob: d3e1265c629c893db929b7531cdbbc3f327b65c6 [file]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/profiler/thread_delegate_posix.h"
#include <inttypes.h>
#include <pthread.h>
#include <stdio.h>
#include <optional>
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/memory/ptr_util.h"
#include "base/process/process_handle.h"
#include "build/build_config.h"
#if !(BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))
#include "base/profiler/stack_base_address_posix.h"
#endif
namespace base {
// static
std::unique_ptr<ThreadDelegatePosix> ThreadDelegatePosix::Create(
SamplingProfilerThreadToken thread_token) {
std::optional<uintptr_t> base_address;
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
base_address = thread_token.stack_base_address;
#else
base_address =
GetThreadStackBaseAddress(thread_token.id, thread_token.pthread_id);
#endif
if (!base_address) {
return nullptr;
}
return base::WrapUnique(
new ThreadDelegatePosix(thread_token.id, *base_address));
}
ThreadDelegatePosix::~ThreadDelegatePosix() = default;
PlatformThreadId ThreadDelegatePosix::GetThreadId() const {
return thread_id_;
}
uintptr_t ThreadDelegatePosix::GetStackBaseAddress() const {
return thread_stack_base_address_;
}
std::vector<uintptr_t> ThreadDelegatePosix::GetRegisters(
RegisterContext* thread_context) {
#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
return {
static_cast<uintptr_t>(thread_context->arm_r0),
static_cast<uintptr_t>(thread_context->arm_r1),
static_cast<uintptr_t>(thread_context->arm_r2),
static_cast<uintptr_t>(thread_context->arm_r3),
static_cast<uintptr_t>(thread_context->arm_r4),
static_cast<uintptr_t>(thread_context->arm_r5),
static_cast<uintptr_t>(thread_context->arm_r6),
static_cast<uintptr_t>(thread_context->arm_r7),
static_cast<uintptr_t>(thread_context->arm_r8),
static_cast<uintptr_t>(thread_context->arm_r9),
static_cast<uintptr_t>(thread_context->arm_r10),
static_cast<uintptr_t>(thread_context->arm_fp),
static_cast<uintptr_t>(thread_context->arm_ip),
static_cast<uintptr_t>(thread_context->arm_sp),
// arm_lr and arm_pc do not require rewriting because they contain
// addresses of executable code, not addresses in the stack.
};
#elif defined(ARCH_CPU_ARM_FAMILY) && \
defined(ARCH_CPU_64_BITS) // #if defined(ARCH_CPU_ARM_FAMILY) &&
// defined(ARCH_CPU_32_BITS)
return {
// Return the set of callee-save registers per the ARM 64-bit Procedure
// Call
// Standard section 5.1.1, plus the stack pointer.
static_cast<uintptr_t>(thread_context->sp),
static_cast<uintptr_t>(thread_context->regs[19]),
static_cast<uintptr_t>(thread_context->regs[20]),
static_cast<uintptr_t>(thread_context->regs[21]),
static_cast<uintptr_t>(thread_context->regs[22]),
static_cast<uintptr_t>(thread_context->regs[23]),
static_cast<uintptr_t>(thread_context->regs[24]),
static_cast<uintptr_t>(thread_context->regs[25]),
static_cast<uintptr_t>(thread_context->regs[26]),
static_cast<uintptr_t>(thread_context->regs[27]),
static_cast<uintptr_t>(thread_context->regs[28]),
static_cast<uintptr_t>(thread_context->regs[29]),
};
#elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_32_BITS)
return {
// Return the set of callee-save registers per the i386 System V ABI
// section 2.2.3, plus the stack pointer.
static_cast<uintptr_t>(thread_context->gregs[REG_EBX]),
static_cast<uintptr_t>(thread_context->gregs[REG_EBP]),
static_cast<uintptr_t>(thread_context->gregs[REG_ESI]),
static_cast<uintptr_t>(thread_context->gregs[REG_EDI]),
static_cast<uintptr_t>(thread_context->gregs[REG_ESP]),
};
#elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_64_BITS)
return {
// Return the set of callee-save registers per the x86-64 System V ABI
// section 3.2.1, plus the stack pointer.
static_cast<uintptr_t>(thread_context->gregs[REG_RBP]),
static_cast<uintptr_t>(thread_context->gregs[REG_RBX]),
static_cast<uintptr_t>(thread_context->gregs[REG_R12]),
static_cast<uintptr_t>(thread_context->gregs[REG_R13]),
static_cast<uintptr_t>(thread_context->gregs[REG_R14]),
static_cast<uintptr_t>(thread_context->gregs[REG_R15]),
static_cast<uintptr_t>(thread_context->gregs[REG_RSP]),
};
#else // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
// Unimplemented for other architectures.
return {};
#endif
}
void ThreadDelegatePosix::SetRegisters(
RegisterContext* thread_context,
const std::vector<uintptr_t>& registers) {
#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
CHECK_EQ(registers.size(), 14u);
thread_context->arm_r0 = registers[0];
thread_context->arm_r1 = registers[1];
thread_context->arm_r2 = registers[2];
thread_context->arm_r3 = registers[3];
thread_context->arm_r4 = registers[4];
thread_context->arm_r5 = registers[5];
thread_context->arm_r6 = registers[6];
thread_context->arm_r7 = registers[7];
thread_context->arm_r8 = registers[8];
thread_context->arm_r9 = registers[9];
thread_context->arm_r10 = registers[10];
thread_context->arm_fp = registers[11];
thread_context->arm_ip = registers[12];
thread_context->arm_sp = registers[13];
#elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
CHECK_EQ(registers.size(), 12u);
thread_context->sp = registers[0];
thread_context->regs[19] = registers[1];
thread_context->regs[20] = registers[2];
thread_context->regs[21] = registers[3];
thread_context->regs[22] = registers[4];
thread_context->regs[23] = registers[5];
thread_context->regs[24] = registers[6];
thread_context->regs[25] = registers[7];
thread_context->regs[26] = registers[8];
thread_context->regs[27] = registers[9];
thread_context->regs[28] = registers[10];
thread_context->regs[29] = registers[11];
#elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_32_BITS)
CHECK_EQ(registers.size(), 5u);
thread_context->gregs[REG_EBX] = static_cast<intptr_t>(registers[0]);
thread_context->gregs[REG_EBP] = static_cast<intptr_t>(registers[1]);
thread_context->gregs[REG_ESI] = static_cast<intptr_t>(registers[2]);
thread_context->gregs[REG_EDI] = static_cast<intptr_t>(registers[3]);
thread_context->gregs[REG_ESP] = static_cast<intptr_t>(registers[4]);
#elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_64_BITS)
CHECK_EQ(registers.size(), 7u);
thread_context->gregs[REG_RBP] = static_cast<intptr_t>(registers[0]);
thread_context->gregs[REG_RBX] = static_cast<intptr_t>(registers[1]);
thread_context->gregs[REG_R12] = static_cast<intptr_t>(registers[2]);
thread_context->gregs[REG_R13] = static_cast<intptr_t>(registers[3]);
thread_context->gregs[REG_R14] = static_cast<intptr_t>(registers[4]);
thread_context->gregs[REG_R15] = static_cast<intptr_t>(registers[5]);
thread_context->gregs[REG_RSP] = static_cast<intptr_t>(registers[6]);
#endif
}
ThreadDelegatePosix::ThreadDelegatePosix(PlatformThreadId id,
uintptr_t base_address)
: thread_id_(id), thread_stack_base_address_(base_address) {}
} // namespace base