• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)37 uintptr_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)47 inline 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)57 inline 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)67 inline 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)82 inline uintptr_t& RegisterContextStackPointer(x86_thread_state64_t* context) {
83   return AsUintPtr(&context->__rsp);
84 }
85 
RegisterContextFramePointer(x86_thread_state64_t * context)86 inline uintptr_t& RegisterContextFramePointer(x86_thread_state64_t* context) {
87   return AsUintPtr(&context->__rbp);
88 }
89 
RegisterContextInstructionPointer(x86_thread_state64_t * context)90 inline 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)101 inline uintptr_t& RegisterContextStackPointer(arm_thread_state64_t* context) {
102   return AsUintPtr(&context->__sp);
103 }
104 
RegisterContextFramePointer(arm_thread_state64_t * context)105 inline uintptr_t& RegisterContextFramePointer(arm_thread_state64_t* context) {
106   return AsUintPtr(&context->__fp);
107 }
108 
RegisterContextInstructionPointer(arm_thread_state64_t * context)109 inline 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)123 inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) {
124   return context->stack_pointer;
125 }
126 
RegisterContextFramePointer(RegisterContext * context)127 inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) {
128   return context->frame_pointer;
129 }
130 
RegisterContextInstructionPointer(RegisterContext * context)131 inline 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)143 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
144   return AsUintPtr(&context->arm_sp);
145 }
146 
RegisterContextFramePointer(mcontext_t * context)147 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
148   return AsUintPtr(&context->arm_fp);
149 }
150 
RegisterContextInstructionPointer(mcontext_t * context)151 inline 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)157 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
158   return AsUintPtr(&context->sp);
159 }
160 
RegisterContextFramePointer(mcontext_t * context)161 inline 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)167 inline 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)173 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
174   return AsUintPtr(&context->gregs[REG_ESP]);
175 }
176 
RegisterContextFramePointer(mcontext_t * context)177 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
178   return AsUintPtr(&context->gregs[REG_EBP]);
179 }
180 
RegisterContextInstructionPointer(mcontext_t * context)181 inline 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)187 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
188   return AsUintPtr(&context->gregs[REG_RSP]);
189 }
190 
RegisterContextFramePointer(mcontext_t * context)191 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
192   return AsUintPtr(&context->gregs[REG_RBP]);
193 }
194 
RegisterContextInstructionPointer(mcontext_t * context)195 inline 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)203 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
204   return *reinterpret_cast<uintptr_t*>(context);
205 }
206 
RegisterContextFramePointer(mcontext_t * context)207 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
208   return *(reinterpret_cast<uintptr_t*>(context) + 1);
209 }
210 
RegisterContextInstructionPointer(mcontext_t * context)211 inline 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)226 inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) {
227   return context->stack_pointer;
228 }
229 
RegisterContextFramePointer(RegisterContext * context)230 inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) {
231   return context->frame_pointer;
232 }
233 
RegisterContextInstructionPointer(RegisterContext * context)234 inline 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