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 // 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. 8 9 #ifndef BASE_PROFILER_REGISTER_CONTEXT_H_ 10 #define BASE_PROFILER_REGISTER_CONTEXT_H_ 11 12 #include <cstdint> 13 14 #include "build/build_config.h" 15 16 #if BUILDFLAG(IS_WIN) 17 #include <windows.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> 22 #endif 23 24 namespace base { 25 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 30 // Linux. 31 template <typename T> AsUintPtr(T * value)32uintptr_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); 36 } 37 38 #if BUILDFLAG(IS_WIN) 39 40 using RegisterContext = ::CONTEXT; 41 RegisterContextStackPointer(::CONTEXT * context)42inline uintptr_t& RegisterContextStackPointer(::CONTEXT* context) { 43 #if defined(ARCH_CPU_X86_64) 44 return context->Rsp; 45 #elif defined(ARCH_CPU_ARM64) 46 return context->Sp; 47 #else 48 return AsUintPtr(&context->Esp); 49 #endif 50 } 51 RegisterContextFramePointer(::CONTEXT * context)52inline uintptr_t& RegisterContextFramePointer(::CONTEXT* context) { 53 #if defined(ARCH_CPU_X86_64) 54 return context->Rbp; 55 #elif defined(ARCH_CPU_ARM64) 56 return context->Fp; 57 #else 58 return AsUintPtr(&context->Ebp); 59 #endif 60 } 61 RegisterContextInstructionPointer(::CONTEXT * context)62inline uintptr_t& RegisterContextInstructionPointer(::CONTEXT* context) { 63 #if defined(ARCH_CPU_X86_64) 64 return context->Rip; 65 #elif defined(ARCH_CPU_ARM64) 66 return context->Pc; 67 #else 68 return AsUintPtr(&context->Eip); 69 #endif 70 } 71 72 #elif BUILDFLAG(IS_MAC) || BUILDFLAG(IS_IOS) 73 74 #if defined(ARCH_CPU_X86_64) 75 using RegisterContext = x86_thread_state64_t; 76 RegisterContextStackPointer(x86_thread_state64_t * context)77inline uintptr_t& RegisterContextStackPointer(x86_thread_state64_t* context) { 78 return AsUintPtr(&context->__rsp); 79 } 80 RegisterContextFramePointer(x86_thread_state64_t * context)81inline uintptr_t& RegisterContextFramePointer(x86_thread_state64_t* context) { 82 return AsUintPtr(&context->__rbp); 83 } 84 RegisterContextInstructionPointer(x86_thread_state64_t * context)85inline uintptr_t& RegisterContextInstructionPointer( 86 x86_thread_state64_t* context) { 87 return AsUintPtr(&context->__rip); 88 } 89 90 #elif defined(ARCH_CPU_ARM64) // defined(ARCH_CPU_X86_64) 91 using RegisterContext = arm_thread_state64_t; 92 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 RegisterContextStackPointer(arm_thread_state64_t * context)96inline uintptr_t& RegisterContextStackPointer(arm_thread_state64_t* context) { 97 return AsUintPtr(&context->__sp); 98 } 99 RegisterContextFramePointer(arm_thread_state64_t * context)100inline uintptr_t& RegisterContextFramePointer(arm_thread_state64_t* context) { 101 return AsUintPtr(&context->__fp); 102 } 103 RegisterContextInstructionPointer(arm_thread_state64_t * context)104inline uintptr_t& RegisterContextInstructionPointer( 105 arm_thread_state64_t* context) { 106 return AsUintPtr(&context->__pc); 107 } 108 109 #else // defined(ARCH_CPU_ARM64) 110 111 // Placeholders for other cpus. 112 struct RegisterContext { 113 uintptr_t stack_pointer; 114 uintptr_t frame_pointer; 115 uintptr_t instruction_pointer; 116 }; 117 RegisterContextStackPointer(RegisterContext * context)118inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) { 119 return context->stack_pointer; 120 } 121 RegisterContextFramePointer(RegisterContext * context)122inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) { 123 return context->frame_pointer; 124 } 125 RegisterContextInstructionPointer(RegisterContext * context)126inline uintptr_t& RegisterContextInstructionPointer(RegisterContext* context) { 127 return context->instruction_pointer; 128 } 129 130 #endif 131 132 #elif BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 133 134 using RegisterContext = mcontext_t; 135 136 #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) 137 RegisterContextStackPointer(mcontext_t * context)138inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 139 return AsUintPtr(&context->arm_sp); 140 } 141 RegisterContextFramePointer(mcontext_t * context)142inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 143 return AsUintPtr(&context->arm_fp); 144 } 145 RegisterContextInstructionPointer(mcontext_t * context)146inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 147 return AsUintPtr(&context->arm_pc); 148 } 149 150 #elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS) 151 RegisterContextStackPointer(mcontext_t * context)152inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 153 return AsUintPtr(&context->sp); 154 } 155 RegisterContextFramePointer(mcontext_t * context)156inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 157 // r29 is the FP register on 64-bit ARM per the Procedure Call Standard, 158 // section 5.1.1. 159 return AsUintPtr(&context->regs[29]); 160 } 161 RegisterContextInstructionPointer(mcontext_t * context)162inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 163 return AsUintPtr(&context->pc); 164 } 165 166 #elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_32_BITS) 167 RegisterContextStackPointer(mcontext_t * context)168inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 169 return AsUintPtr(&context->gregs[REG_ESP]); 170 } 171 RegisterContextFramePointer(mcontext_t * context)172inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 173 return AsUintPtr(&context->gregs[REG_EBP]); 174 } 175 RegisterContextInstructionPointer(mcontext_t * context)176inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 177 return AsUintPtr(&context->gregs[REG_EIP]); 178 } 179 180 #elif defined(ARCH_CPU_X86_FAMILY) && defined(ARCH_CPU_64_BITS) 181 RegisterContextStackPointer(mcontext_t * context)182inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 183 return AsUintPtr(&context->gregs[REG_RSP]); 184 } 185 RegisterContextFramePointer(mcontext_t * context)186inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 187 return AsUintPtr(&context->gregs[REG_RBP]); 188 } 189 RegisterContextInstructionPointer(mcontext_t * context)190inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 191 return AsUintPtr(&context->gregs[REG_RIP]); 192 } 193 194 #else // defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) 195 196 // Placeholders for other POSIX platforms that just return the first 197 // three register slots in the context. RegisterContextStackPointer(mcontext_t * context)198inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) { 199 return *reinterpret_cast<uintptr_t*>(context); 200 } 201 RegisterContextFramePointer(mcontext_t * context)202inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) { 203 return *(reinterpret_cast<uintptr_t*>(context) + 1); 204 } 205 RegisterContextInstructionPointer(mcontext_t * context)206inline uintptr_t& RegisterContextInstructionPointer(mcontext_t* context) { 207 return *(reinterpret_cast<uintptr_t*>(context) + 2); 208 } 209 210 #endif // defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS) 211 212 #else // BUILDFLAG(IS_WIN) 213 214 // Placeholders for other platforms. 215 struct RegisterContext { 216 uintptr_t stack_pointer; 217 uintptr_t frame_pointer; 218 uintptr_t instruction_pointer; 219 }; 220 RegisterContextStackPointer(RegisterContext * context)221inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) { 222 return context->stack_pointer; 223 } 224 RegisterContextFramePointer(RegisterContext * context)225inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) { 226 return context->frame_pointer; 227 } 228 RegisterContextInstructionPointer(RegisterContext * context)229inline uintptr_t& RegisterContextInstructionPointer(RegisterContext* context) { 230 return context->instruction_pointer; 231 } 232 233 #endif // BUILDFLAG(IS_WIN) 234 235 } // namespace base 236 237 #endif // BASE_PROFILER_REGISTER_CONTEXT_H_ 238