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
33namespace JSC {
34namespace Probe {
35
36struct 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
64inline UCPURegister& CPUState::gpr(RegisterID id)
65{
66 ASSERT(id >= MacroAssembler::firstRegister() && id <= MacroAssembler::lastRegister());
67 return gprs[id];
68}
69
70inline UCPURegister& CPUState::spr(SPRegisterID id)
71{
72 ASSERT(id >= MacroAssembler::firstSPRegister() && id <= MacroAssembler::lastSPRegister());
73 return sprs[id];
74}
75
76inline double& CPUState::fpr(FPRegisterID id)
77{
78 ASSERT(id >= MacroAssembler::firstFPRegister() && id <= MacroAssembler::lastFPRegister());
79 return fprs[id];
80}
81
82template<typename T>
83T 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
92template<typename T>
93T 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
102template<typename T>
103T CPUState::fpr(FPRegisterID id) const
104{
105 CPUState* cpu = const_cast<CPUState*>(this);
106 return bitwise_cast<T>(cpu->fpr(id));
107}
108
109inline 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
124inline 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
139inline 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
154template<typename T>
155T CPUState::pc() const
156{
157 CPUState* cpu = const_cast<CPUState*>(this);
158 return reinterpret_cast<T>(cpu->pc());
159}
160
161template<typename T>
162T CPUState::fp() const
163{
164 CPUState* cpu = const_cast<CPUState*>(this);
165 return reinterpret_cast<T>(cpu->fp());
166}
167
168template<typename T>
169T CPUState::sp() const
170{
171 CPUState* cpu = const_cast<CPUState*>(this);
172 return reinterpret_cast<T>(cpu->sp());
173}
174
175struct State;
176typedef void (*StackInitializationFunction)(State*);
177
178struct State {
179 Probe::Function probeFunction;
180 void* arg;
181 StackInitializationFunction initializeStackFunction;
182 void* initializeStackArg;
183 CPUState cpu;
184};
185
186class Context {
187 WTF_MAKE_FAST_ALLOCATED;
188public:
189 using RegisterID = MacroAssembler::RegisterID;
190 using SPRegisterID = MacroAssembler::SPRegisterID;
191 using FPRegisterID = MacroAssembler::FPRegisterID;
192
193 Context(State* state)
194 : cpu(state->cpu)
195 , m_state(state)
196 { }
197
198 template<typename T>
199 T arg() { return reinterpret_cast<T>(m_state->arg); }
200
201 UCPURegister& gpr(RegisterID id) { return cpu.gpr(id); }
202 UCPURegister& spr(SPRegisterID id) { return cpu.spr(id); }
203 double& fpr(FPRegisterID id) { return cpu.fpr(id); }
204 const char* gprName(RegisterID id) { return cpu.gprName(id); }
205 const char* sprName(SPRegisterID id) { return cpu.sprName(id); }
206 const char* fprName(FPRegisterID id) { return cpu.fprName(id); }
207
208 template<typename T> T gpr(RegisterID id) const { return cpu.gpr<T>(id); }
209 template<typename T> T spr(SPRegisterID id) const { return cpu.spr<T>(id); }
210 template<typename T> T fpr(FPRegisterID id) const { return cpu.fpr<T>(id); }
211
212 void*& pc() { return cpu.pc(); }
213 void*& fp() { return cpu.fp(); }
214 void*& sp() { return cpu.sp(); }
215
216 template<typename T> T pc() { return cpu.pc<T>(); }
217 template<typename T> T fp() { return cpu.fp<T>(); }
218 template<typename T> T sp() { return cpu.sp<T>(); }
219
220 Stack& stack()
221 {
222 ASSERT(m_stack.isValid());
223 return m_stack;
224 };
225
226 bool hasWritesToFlush() { return m_stack.hasWritesToFlush(); }
227 Stack* releaseStack() { return new Stack(WTFMove(m_stack)); }
228
229 CPUState& cpu;
230
231private:
232 State* m_state;
233 Stack m_stack;
234
235 friend JS_EXPORT_PRIVATE void* probeStateForContext(Context&); // Not for general use. This should only be for writing tests.
236};
237
238void executeProbe(State*);
239
240} // namespace Probe
241} // namespace JSC
242
243#endif // ENABLE(MASM_PROBE)
244