xref: /aosp_15_r20/external/cronet/base/profiler/register_context.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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)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);
36 }
37 
38 #if BUILDFLAG(IS_WIN)
39 
40 using RegisterContext = ::CONTEXT;
41 
RegisterContextStackPointer(::CONTEXT * context)42 inline 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)52 inline 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)62 inline 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)77 inline uintptr_t& RegisterContextStackPointer(x86_thread_state64_t* context) {
78   return AsUintPtr(&context->__rsp);
79 }
80 
RegisterContextFramePointer(x86_thread_state64_t * context)81 inline uintptr_t& RegisterContextFramePointer(x86_thread_state64_t* context) {
82   return AsUintPtr(&context->__rbp);
83 }
84 
RegisterContextInstructionPointer(x86_thread_state64_t * context)85 inline 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)96 inline uintptr_t& RegisterContextStackPointer(arm_thread_state64_t* context) {
97   return AsUintPtr(&context->__sp);
98 }
99 
RegisterContextFramePointer(arm_thread_state64_t * context)100 inline uintptr_t& RegisterContextFramePointer(arm_thread_state64_t* context) {
101   return AsUintPtr(&context->__fp);
102 }
103 
RegisterContextInstructionPointer(arm_thread_state64_t * context)104 inline 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)118 inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) {
119   return context->stack_pointer;
120 }
121 
RegisterContextFramePointer(RegisterContext * context)122 inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) {
123   return context->frame_pointer;
124 }
125 
RegisterContextInstructionPointer(RegisterContext * context)126 inline 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)138 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
139   return AsUintPtr(&context->arm_sp);
140 }
141 
RegisterContextFramePointer(mcontext_t * context)142 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
143   return AsUintPtr(&context->arm_fp);
144 }
145 
RegisterContextInstructionPointer(mcontext_t * context)146 inline 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)152 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
153   return AsUintPtr(&context->sp);
154 }
155 
RegisterContextFramePointer(mcontext_t * context)156 inline 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)162 inline 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)168 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
169   return AsUintPtr(&context->gregs[REG_ESP]);
170 }
171 
RegisterContextFramePointer(mcontext_t * context)172 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
173   return AsUintPtr(&context->gregs[REG_EBP]);
174 }
175 
RegisterContextInstructionPointer(mcontext_t * context)176 inline 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)182 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
183   return AsUintPtr(&context->gregs[REG_RSP]);
184 }
185 
RegisterContextFramePointer(mcontext_t * context)186 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
187   return AsUintPtr(&context->gregs[REG_RBP]);
188 }
189 
RegisterContextInstructionPointer(mcontext_t * context)190 inline 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)198 inline uintptr_t& RegisterContextStackPointer(mcontext_t* context) {
199   return *reinterpret_cast<uintptr_t*>(context);
200 }
201 
RegisterContextFramePointer(mcontext_t * context)202 inline uintptr_t& RegisterContextFramePointer(mcontext_t* context) {
203   return *(reinterpret_cast<uintptr_t*>(context) + 1);
204 }
205 
RegisterContextInstructionPointer(mcontext_t * context)206 inline 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)221 inline uintptr_t& RegisterContextStackPointer(RegisterContext* context) {
222   return context->stack_pointer;
223 }
224 
RegisterContextFramePointer(RegisterContext * context)225 inline uintptr_t& RegisterContextFramePointer(RegisterContext* context) {
226   return context->frame_pointer;
227 }
228 
RegisterContextInstructionPointer(RegisterContext * context)229 inline 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