register_context.h 6.6 KB

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