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 // This file provides the RegisterContext cross-platform typedef that represents 11 // the native register context for the platform, plus functions that provide 12 // access to key registers in the context. 13 14 #ifndef BASE_PROFILER_REGISTER_CONTEXT_H_ 15 #define BASE_PROFILER_REGISTER_CONTEXT_H_ 16 17 #include <cstdint> 18 19 #include "build/build_config.h" 20 21 #if BUILDFLAG(IS_WIN) 22 #include <windows.h> 23 #elif BUILDFLAG(IS_APPLE) 24 #include <mach/machine/thread_status.h> 25 #elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 26 #include <sys/ucontext.h> 27 #endif 28 29 namespace base { 30 31 // Helper function to account for the fact that platform-specific register state 32 // types may be of the same size as uintptr_t, but not of the same type or 33 // signedness -- e.g. unsigned int vs. unsigned long on 32-bit Windows, unsigned 34 // long vs. unsigned long long on Mac, long long vs. unsigned long long on 35 // Linux. 36 template <typename T> AsUintPtr(T * value)37uintptr_t& AsUintPtr(T* value) { 38 static_assert(sizeof(T) == sizeof(uintptr_t), 39 "register state type must be of equivalent size to uintptr_t"); 40 return *reinterpret_cast<uintptr_t*>(value); 41 } 42 43 #if BUILDFLAG(IS_WIN) 44 45 using RegisterContext = ::CONTEXT; 46 RegisterContextStackPointer(::CONTEXT * context)47inline uintptr_t& RegisterContextStackPointer(::CONTEXT* context) { 48 #if defined(ARCH_CPU_X86_64) 49 return context->Rsp; 50 #elif defined(ARCH_CPU_ARM64) 51 return context->Sp; 52 #else 53 return AsUintPtr(&context->Esp); 54 #endif 55 } 56 RegisterContextFramePointer(::CONTEXT * context)57inline uintptr_t& RegisterContextFramePointer(::CONTEXT* context) { 58 #if defined(ARCH_CPU_X86_64) 59 return context->Rbp; 60 #elif defined(ARCH_CPU_ARM64) 61 return context->Fp; 62 #else 63 return AsUintPtr(&context->Ebp); 64 #endif 65 } 66 RegisterContextInstructionPointer(::CONTEXT * context)67inline uintptr_t& RegisterContextInstructionPointer(::CONTEXT* context) { 68 #if defined(ARCH_CPU_X86_64) 69 return context->Rip; 70 #elif defined(ARCH_CPU_ARM64) 71 return context->Pc; 72 #else 73 return AsUintPtr(&context->Eip); 74 #endif 75 } 76 77 #elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_IOS) 78 79 #if defined(ARCH_CPU_X86_64) 80 using RegisterContext = x86_thread_state64_t; 81 RegisterContextStackPointer(x86_thread_state64_t * context)82inline uintptr_t& RegisterContextStackPointer(x86_thread_state64_t* context) { 83 return AsUintPtr(&context->__rsp); 84 } 85 RegisterContextFramePointer(x86_thread_state64_t * context)86inline uintptr_t& RegisterContextFramePointer(x86_thread_state64_t* context) { 87 return AsUintPtr(&context->__rbp); 88 } 89 RegisterContextInstructionPointer(x86_thread_state64_t * context)90inline uintptr_t& RegisterContextInstructionPointer( 91 x86_thread_state64_t* context) { 92 return AsUintPtr(&context->__rip); 93 } 94 95 #elif defined(ARCH_CPU_ARM64) // defined(ARCH_CPU_X86_64) 96 using RegisterContext = arm_thread_state64_t; 97 98 // TODO(thakis): Have getter/setter functions instead of returning a ref to 99 // prepare for arm64e. See __DARWIN_OPAQUE_ARM_THREAD_STATE6 in 100 // mach/arm/_structs.h RegisterContextStackPointer(arm_thread_state64_t * context)101inline uintptr_t& RegisterContextStackPointer(arm_thread_state64_t* context) { 102 return AsUintPtr(&context->__sp); 103 } 104 RegisterContextFramePointer(arm_thread_state64_t * context)105inline uintptr_t& RegisterContextFramePointer(arm_thread_state64_t* context) { 106 return AsUintPtr(&context->__fp); 107 } 108 RegisterContextInstructionPointer(arm_thread_state64_t * context)109inline uintptr_t& RegisterContextInstructionPointer( 110 arm_thread_state64_t* context) { 111 return AsUintPtr(&context->__pc); 112 } 113 114 #else // defined(ARCH_CPU_ARM64) 115 116 // Placeholders for other cpus. 117 struct RegisterContext { 118 uintptr_t stack_pointer; 119 uintptr_t frame_pointer; 120 uintptr_t instruction_pointer; 121 }; 122 RegisterContextStackPointer(RegisterContext * context)123inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) { 124 return context->stack_pointer; 125 } 126 RegisterContextFramePointer(RegisterContext * context)127inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) { 128 return context->frame_pointer; 129 } 130 RegisterContextInstructionPointer(RegisterContext * context)131inline uintptr_t& RegisterContextInstructionPointer(RegisterContext* context) { 132 return context->instruction_pointer; 133 } 134 135 #endif 136 137 #elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 138 139 using RegisterContext = mcontext_t; 140 141 #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) 142 RegisterContextStackPointer(mcontext_t * context)143inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 144 return AsUintPtr(&context->arm_sp); 145 } 146 RegisterContextFramePointer(mcontext_t * context)147inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 148 return AsUintPtr(&context->arm_fp); 149 } 150 RegisterContextInstructionPointer(mcontext_t * context)151inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 152 return AsUintPtr(&context->arm_pc); 153 } 154 155 #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS) 156 RegisterContextStackPointer(mcontext_t * context)157inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 158 return AsUintPtr(&context->sp); 159 } 160 RegisterContextFramePointer(mcontext_t * context)161inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 162 // r29 is the FP register on 64-bit ARM per the Procedure Call Standard, 163 // section 5.1.1. 164 return AsUintPtr(&context->regs[29]); 165 } 166 RegisterContextInstructionPointer(mcontext_t * context)167inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 168 return AsUintPtr(&context->pc); 169 } 170 171 #elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_32_BITS) 172 RegisterContextStackPointer(mcontext_t * context)173inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 174 return AsUintPtr(&context->gregs[REG_ESP]); 175 } 176 RegisterContextFramePointer(mcontext_t * context)177inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 178 return AsUintPtr(&context->gregs[REG_EBP]); 179 } 180 RegisterContextInstructionPointer(mcontext_t * context)181inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 182 return AsUintPtr(&context->gregs[REG_EIP]); 183 } 184 185 #elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_64_BITS) 186 RegisterContextStackPointer(mcontext_t * context)187inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 188 return AsUintPtr(&context->gregs[REG_RSP]); 189 } 190 RegisterContextFramePointer(mcontext_t * context)191inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 192 return AsUintPtr(&context->gregs[REG_RBP]); 193 } 194 RegisterContextInstructionPointer(mcontext_t * context)195inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 196 return AsUintPtr(&context->gregs[REG_RIP]); 197 } 198 199 #else // defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) 200 201 // Placeholders for other POSIX platforms that just return the first 202 // three register slots in the context. RegisterContextStackPointer(mcontext_t * context)203inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 204 return *reinterpret_cast<uintptr_t*>(context); 205 } 206 RegisterContextFramePointer(mcontext_t * context)207inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 208 return *(reinterpret_cast<uintptr_t*>(context) + 1); 209 } 210 RegisterContextInstructionPointer(mcontext_t * context)211inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 212 return *(reinterpret_cast<uintptr_t*>(context) + 2); 213 } 214 215 #endif // defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) 216 217 #else // BUILDFLAG(IS_WIN) 218 219 // Placeholders for other platforms. 220 struct RegisterContext { 221 uintptr_t stack_pointer; 222 uintptr_t frame_pointer; 223 uintptr_t instruction_pointer; 224 }; 225 RegisterContextStackPointer(RegisterContext * context)226inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) { 227 return context->stack_pointer; 228 } 229 RegisterContextFramePointer(RegisterContext * context)230inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) { 231 return context->frame_pointer; 232 } 233 RegisterContextInstructionPointer(RegisterContext * context)234inline uintptr_t& RegisterContextInstructionPointer(RegisterContext* context) { 235 return context->instruction_pointer; 236 } 237 238 #endif // BUILDFLAG(IS_WIN) 239 240 } // namespace base 241 242 #endif // BASE_PROFILER_REGISTER_CONTEXT_H_ 243