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.
5 // This file provides the RegisterContext cross-platform typedef that represents
6 // the native register context for the platform, plus functions that provide
7 // access to key registers in the context.
9 #ifndef BASE_PROFILER_REGISTER_CONTEXT_H_
10 #define BASE_PROFILER_REGISTER_CONTEXT_H_
14 #include "build/build_config.h"
18 #elif BUILDFLAG(IS_APPLE)
19 #include <mach/machine/thread_status.h>
20 #elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
21 #include <sys/ucontext.h>
26 // Helper function to account for the fact that platform-specific register state
27 // types may be of the same size as uintptr_t, but not of the same type or
28 // signedness -- e.g. unsigned int vs. unsigned long on 32-bit Windows, unsigned
29 // long vs. unsigned long long on Mac, long long vs. unsigned long long on
32 uintptr_t& AsUintPtr(T* value) {
33 static_assert(sizeof(T) == sizeof(uintptr_t),
34 "register state type must be of equivalent size to uintptr_t");
35 return *reinterpret_cast<uintptr_t*>(value);
40 using RegisterContext = ::CONTEXT;
42 inline uintptr_t& RegisterContextStackPointer(::CONTEXT* context) {
43 #if defined(ARCH_CPU_X86_64)
45 #elif defined(ARCH_CPU_ARM64)
48 return AsUintPtr(&context->Esp);
52 inline uintptr_t& RegisterContextFramePointer(::CONTEXT* context) {
53 #if defined(ARCH_CPU_X86_64)
55 #elif defined(ARCH_CPU_ARM64)
58 return AsUintPtr(&context->Ebp);
62 inline uintptr_t& RegisterContextInstructionPointer(::CONTEXT* context) {
63 #if defined(ARCH_CPU_X86_64)
65 #elif defined(ARCH_CPU_ARM64)
68 return AsUintPtr(&context->Eip);
72 #elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_IOS)
74 #if defined(ARCH_CPU_X86_64)
75 using RegisterContext = x86_thread_state64_t;
77 inline uintptr_t& RegisterContextStackPointer(x86_thread_state64_t* context) {
78 return AsUintPtr(&context->__rsp);
81 inline uintptr_t& RegisterContextFramePointer(x86_thread_state64_t* context) {
82 return AsUintPtr(&context->__rbp);
85 inline uintptr_t& RegisterContextInstructionPointer(
86 x86_thread_state64_t* context) {
87 return AsUintPtr(&context->__rip);
90 #elif defined(ARCH_CPU_ARM64) // defined(ARCH_CPU_X86_64)
91 using RegisterContext = arm_thread_state64_t;
93 // TODO(thakis): Have getter/setter functions instead of returning a ref to
94 // prepare for arm64e. See __DARWIN_OPAQUE_ARM_THREAD_STATE6 in
95 // mach/arm/_structs.h
96 inline uintptr_t& RegisterContextStackPointer(arm_thread_state64_t* context) {
97 return AsUintPtr(&context->__sp);
100 inline uintptr_t& RegisterContextFramePointer(arm_thread_state64_t* context) {
101 return AsUintPtr(&context->__fp);
104 inline uintptr_t& RegisterContextInstructionPointer(
105 arm_thread_state64_t* context) {
106 return AsUintPtr(&context->__pc);
109 #else // defined(ARCH_CPU_ARM64)
111 // Placeholders for other cpus.
112 struct RegisterContext {
113 uintptr_t stack_pointer;
114 uintptr_t frame_pointer;
115 uintptr_t instruction_pointer;
118 inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) {
119 return context->stack_pointer;
122 inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) {
123 return context->frame_pointer;
126 inline uintptr_t& RegisterContextInstructionPointer(RegisterContext* context) {
127 return context->instruction_pointer;
132 #elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
134 using RegisterContext = mcontext_t;
136 #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
138 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
139 return AsUintPtr(&context->arm_sp);
142 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
143 return AsUintPtr(&context->arm_fp);
146 inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) {
147 return AsUintPtr(&context->arm_pc);
150 #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
152 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
153 return AsUintPtr(&context->sp);
156 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
157 // r29 is the FP register on 64-bit ARM per the Procedure Call Standard,
159 return AsUintPtr(&context->regs[29]);
162 inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) {
163 return AsUintPtr(&context->pc);
166 #elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_32_BITS)
168 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
169 return AsUintPtr(&context->gregs[REG_ESP]);
172 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
173 return AsUintPtr(&context->gregs[REG_EBP]);
176 inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) {
177 return AsUintPtr(&context->gregs[REG_EIP]);
180 #elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_64_BITS)
182 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
183 return AsUintPtr(&context->gregs[REG_RSP]);
186 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
187 return AsUintPtr(&context->gregs[REG_RBP]);
190 inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) {
191 return AsUintPtr(&context->gregs[REG_RIP]);
194 #else // defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
196 // Placeholders for other POSIX platforms that just return the first
197 // three register slots in the context.
198 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
199 return *reinterpret_cast<uintptr_t*>(context);
202 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
203 return *(reinterpret_cast<uintptr_t*>(context) + 1);
206 inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) {
207 return *(reinterpret_cast<uintptr_t*>(context) + 2);
210 #endif // defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
212 #else // BUILDFLAG(IS_WIN)
214 // Placeholders for other platforms.
215 struct RegisterContext {
216 uintptr_t stack_pointer;
217 uintptr_t frame_pointer;
218 uintptr_t instruction_pointer;
221 inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) {
222 return context->stack_pointer;
225 inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) {
226 return context->frame_pointer;
229 inline uintptr_t& RegisterContextInstructionPointer(RegisterContext* context) {
230 return context->instruction_pointer;
233 #endif // BUILDFLAG(IS_WIN)
237 #endif // BASE_PROFILER_REGISTER_CONTEXT_H_