ProbeContext.h
1 /* 2 * Copyright (C) 2017 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #pragma once 27 28 #include "MacroAssembler.h" 29 #include "ProbeStack.h" 30 31 #if ENABLE(MASM_PROBE) 32 33 namespace JSC { 34 namespace Probe { 35 36 struct CPUState { 37 using RegisterID = MacroAssembler::RegisterID; 38 using SPRegisterID = MacroAssembler::SPRegisterID; 39 using FPRegisterID = MacroAssembler::FPRegisterID; 40 41 static inline const char* gprName(RegisterID id) { return MacroAssembler::gprName(id); } 42 static inline const char* sprName(SPRegisterID id) { return MacroAssembler::sprName(id); } 43 static inline const char* fprName(FPRegisterID id) { return MacroAssembler::fprName(id); } 44 inline UCPURegister& gpr(RegisterID); 45 inline UCPURegister& spr(SPRegisterID); 46 inline double& fpr(FPRegisterID); 47 48 template<typename T> T gpr(RegisterID) const; 49 template<typename T> T spr(SPRegisterID) const; 50 template<typename T> T fpr(FPRegisterID) const; 51 52 void*& pc(); 53 void*& fp(); 54 void*& sp(); 55 template<typename T> T pc() const; 56 template<typename T> T fp() const; 57 template<typename T> T sp() const; 58 59 UCPURegister gprs[MacroAssembler::numberOfRegisters()]; 60 UCPURegister sprs[MacroAssembler::numberOfSPRegisters()]; 61 double fprs[MacroAssembler::numberOfFPRegisters()]; 62 }; 63 64 inline UCPURegister& CPUState::gpr(RegisterID id) 65 { 66 ASSERT(id >= MacroAssembler::firstRegister() && id <= MacroAssembler::lastRegister()); 67 return gprs[id]; 68 } 69 70 inline UCPURegister& CPUState::spr(SPRegisterID id) 71 { 72 ASSERT(id >= MacroAssembler::firstSPRegister() && id <= MacroAssembler::lastSPRegister()); 73 return sprs[id]; 74 } 75 76 inline double& CPUState::fpr(FPRegisterID id) 77 { 78 ASSERT(id >= MacroAssembler::firstFPRegister() && id <= MacroAssembler::lastFPRegister()); 79 return fprs[id]; 80 } 81 82 template<typename T> 83 T CPUState::gpr(RegisterID id) const 84 { 85 CPUState* cpu = const_cast<CPUState*>(this); 86 auto& from = cpu->gpr(id); 87 typename std::remove_const<T>::type to { }; 88 std::memcpy(static_cast<void*>(&to), &from, sizeof(to)); // Use std::memcpy to avoid strict aliasing issues. 89 return to; 90 } 91 92 template<typename T> 93 T CPUState::spr(SPRegisterID id) const 94 { 95 CPUState* cpu = const_cast<CPUState*>(this); 96 auto& from = cpu->spr(id); 97 typename std::remove_const<T>::type to { }; 98 std::memcpy(static_cast<void*>(&to), &from, sizeof(to)); // Use std::memcpy to avoid strict aliasing issues. 99 return to; 100 } 101 102 template<typename T> 103 T CPUState::fpr(FPRegisterID id) const 104 { 105 CPUState* cpu = const_cast<CPUState*>(this); 106 return bitwise_cast<T>(cpu->fpr(id)); 107 } 108 109 inline void*& CPUState::pc() 110 { 111 #if CPU(X86) || CPU(X86_64) 112 return *reinterpret_cast<void**>(&spr(X86Registers::eip)); 113 #elif CPU(ARM64) 114 return *reinterpret_cast<void**>(&spr(ARM64Registers::pc)); 115 #elif CPU(ARM_THUMB2) 116 return *reinterpret_cast<void**>(&gpr(ARMRegisters::pc)); 117 #elif CPU(MIPS) 118 return *reinterpret_cast<void**>(&spr(MIPSRegisters::pc)); 119 #else 120 #error "Unsupported CPU" 121 #endif 122 } 123 124 inline void*& CPUState::fp() 125 { 126 #if CPU(X86) || CPU(X86_64) 127 return *reinterpret_cast<void**>(&gpr(X86Registers::ebp)); 128 #elif CPU(ARM64) 129 return *reinterpret_cast<void**>(&gpr(ARM64Registers::fp)); 130 #elif CPU(ARM_THUMB2) 131 return *reinterpret_cast<void**>(&gpr(ARMRegisters::fp)); 132 #elif CPU(MIPS) 133 return *reinterpret_cast<void**>(&gpr(MIPSRegisters::fp)); 134 #else 135 #error "Unsupported CPU" 136 #endif 137 } 138 139 inline void*& CPUState::sp() 140 { 141 #if CPU(X86) || CPU(X86_64) 142 return *reinterpret_cast<void**>(&gpr(X86Registers::esp)); 143 #elif CPU(ARM64) 144 return *reinterpret_cast<void**>(&gpr(ARM64Registers::sp)); 145 #elif CPU(ARM_THUMB2) 146 return *reinterpret_cast<void**>(&gpr(ARMRegisters::sp)); 147 #elif CPU(MIPS) 148 return *reinterpret_cast<void**>(&gpr(MIPSRegisters::sp)); 149 #else 150 #error "Unsupported CPU" 151 #endif 152 } 153 154 template<typename T> 155 T CPUState::pc() const 156 { 157 CPUState* cpu = const_cast<CPUState*>(this); 158 return reinterpret_cast<T>(cpu->pc()); 159 } 160 161 template<typename T> 162 T CPUState::fp() const 163 { 164 CPUState* cpu = const_cast<CPUState*>(this); 165 return reinterpret_cast<T>(cpu->fp()); 166 } 167 168 template<typename T> 169 T CPUState::sp() const 170 { 171 CPUState* cpu = const_cast<CPUState*>(this); 172 return reinterpret_cast<T>(cpu->sp()); 173 } 174 175 struct State; 176 typedef void (*StackInitializationFunction)(State*); 177 178 #if CPU(ARM64E) 179 #define PROBE_FUNCTION_PTRAUTH __ptrauth(ptrauth_key_process_dependent_code, 0, JITProbePtrTag) 180 #define PROBE_STACK_INITIALIZATION_FUNCTION_PTRAUTH __ptrauth(ptrauth_key_process_dependent_code, 0, JITProbeStackInitializationFunctionPtrTag) 181 #else 182 #define PROBE_FUNCTION_PTRAUTH 183 #define PROBE_STACK_INITIALIZATION_FUNCTION_PTRAUTH 184 #endif 185 186 struct State { 187 Probe::Function PROBE_FUNCTION_PTRAUTH probeFunction; 188 void* arg; 189 StackInitializationFunction PROBE_STACK_INITIALIZATION_FUNCTION_PTRAUTH initializeStackFunction; 190 void* initializeStackArg; 191 CPUState cpu; 192 }; 193 194 class Context { 195 WTF_MAKE_FAST_ALLOCATED; 196 public: 197 using RegisterID = MacroAssembler::RegisterID; 198 using SPRegisterID = MacroAssembler::SPRegisterID; 199 using FPRegisterID = MacroAssembler::FPRegisterID; 200 201 Context(State* state) 202 : cpu(state->cpu) 203 , m_state(state) 204 { } 205 206 template<typename T> 207 T arg() { return reinterpret_cast<T>(m_state->arg); } 208 209 UCPURegister& gpr(RegisterID id) { return cpu.gpr(id); } 210 UCPURegister& spr(SPRegisterID id) { return cpu.spr(id); } 211 double& fpr(FPRegisterID id) { return cpu.fpr(id); } 212 const char* gprName(RegisterID id) { return cpu.gprName(id); } 213 const char* sprName(SPRegisterID id) { return cpu.sprName(id); } 214 const char* fprName(FPRegisterID id) { return cpu.fprName(id); } 215 216 template<typename T> T gpr(RegisterID id) const { return cpu.gpr<T>(id); } 217 template<typename T> T spr(SPRegisterID id) const { return cpu.spr<T>(id); } 218 template<typename T> T fpr(FPRegisterID id) const { return cpu.fpr<T>(id); } 219 220 void*& pc() { return cpu.pc(); } 221 void*& fp() { return cpu.fp(); } 222 void*& sp() { return cpu.sp(); } 223 224 template<typename T> T pc() { return cpu.pc<T>(); } 225 template<typename T> T fp() { return cpu.fp<T>(); } 226 template<typename T> T sp() { return cpu.sp<T>(); } 227 228 Stack& stack() 229 { 230 ASSERT(m_stack.isValid()); 231 return m_stack; 232 }; 233 234 bool hasWritesToFlush() { return m_stack.hasWritesToFlush(); } 235 Stack* releaseStack() { return new Stack(WTFMove(m_stack)); } 236 237 CPUState& cpu; 238 239 private: 240 State* m_state; 241 Stack m_stack; 242 243 friend JS_EXPORT_PRIVATE void* probeStateForContext(Context&); // Not for general use. This should only be for writing tests. 244 }; 245 246 void executeProbe(State*); 247 248 } // namespace Probe 249 } // namespace JSC 250 251 #endif // ENABLE(MASM_PROBE)