/ assembler / ProbeContext.h
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)