1/*
2 * Copyright (C) 2017 Yusuke Suzuki <utatane.tea@gmail.com>.
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. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "GPRInfo.h"
29#include "LLIntPCRanges.h"
30#include <wtf/StdLibExtras.h>
31
32#if OS(DARWIN) || OS(FREEBSD) || defined(__GLIBC__)
33#include <signal.h>
34// Using signal.h didn't make mcontext_t and ucontext_t available on FreeBSD.
35// This bug has been fixed in FreeBSD 11.0-CURRENT, so this workaround can be
36// removed after FreeBSD 10.x goes EOL.
37// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=207079
38#if OS(FREEBSD)
39#include <ucontext.h>
40#endif
41#endif
42
43namespace JSC {
44namespace MachineContext {
45#if OS(DARWIN) || OS(WINDOWS)
46
47#if OS(DARWIN)
48#if CPU(X86)
49typedef i386_thread_state_t PlatformRegisters;
50#elif CPU(X86_64)
51typedef x86_thread_state64_t PlatformRegisters;
52#elif CPU(PPC)
53typedef ppc_thread_state_t PlatformRegisters;
54#elif CPU(PPC64)
55typedef ppc_thread_state64_t PlatformRegisters;
56#elif CPU(ARM)
57typedef arm_thread_state_t PlatformRegisters;
58#elif CPU(ARM64)
59typedef arm_thread_state64_t PlatformRegisters;
60#else
61#error Unknown Architecture
62#endif
63
64inline void*& stackPointer(PlatformRegisters& regs)
65{
66#if __DARWIN_UNIX03
67
68#if CPU(X86)
69 return reinterpret_cast<void*&>(regs.__esp);
70#elif CPU(X86_64)
71 return reinterpret_cast<void*&>(regs.__rsp);
72#elif CPU(PPC) || CPU(PPC64)
73 return reinterpret_cast<void*&>(regs.__r1);
74#elif CPU(ARM_THUMB2) || CPU(ARM) || CPU(ARM64)
75 return reinterpret_cast<void*&>(regs.__sp);
76#else
77#error Unknown Architecture
78#endif
79
80#else // !__DARWIN_UNIX03
81
82#if CPU(X86)
83 return reinterpret_cast<void*&>(regs.esp);
84#elif CPU(X86_64)
85 return reinterpret_cast<void*&>(regs.rsp);
86#elif CPU(PPC) || CPU(PPC64)
87 return reinterpret_cast<void*&>(regs.r1);
88#else
89#error Unknown Architecture
90#endif
91
92#endif // __DARWIN_UNIX03
93}
94
95inline void*& framePointer(PlatformRegisters& regs)
96{
97#if __DARWIN_UNIX03
98
99#if CPU(X86)
100 return reinterpret_cast<void*&>(regs.__ebp);
101#elif CPU(X86_64)
102 return reinterpret_cast<void*&>(regs.__rbp);
103#elif CPU(ARM_THUMB2)
104 return reinterpret_cast<void*&>(regs.__r[7]);
105#elif CPU(ARM)
106 return reinterpret_cast<void*&>(regs.__r[11]);
107#elif CPU(ARM64)
108 return reinterpret_cast<void*&>(regs.__x[29]);
109#else
110#error Unknown Architecture
111#endif
112
113#else // !__DARWIN_UNIX03
114
115#if CPU(X86)
116 return reinterpret_cast<void*&>(regs.esp);
117#elif CPU(X86_64)
118 return reinterpret_cast<void*&>(regs.rsp);
119#else
120#error Unknown Architecture
121#endif
122
123#endif // __DARWIN_UNIX03
124}
125
126inline void*& instructionPointer(PlatformRegisters& regs)
127{
128#if __DARWIN_UNIX03
129
130#if CPU(X86)
131 return reinterpret_cast<void*&>(regs.__eip);
132#elif CPU(X86_64)
133 return reinterpret_cast<void*&>(regs.__rip);
134#elif CPU(ARM_THUMB2) || CPU(ARM) || CPU(ARM64)
135 return reinterpret_cast<void*&>(regs.__pc);
136#else
137#error Unknown Architecture
138#endif
139
140#else // !__DARWIN_UNIX03
141#if CPU(X86)
142 return reinterpret_cast<void*&>(regs.eip);
143#elif CPU(X86_64)
144 return reinterpret_cast<void*&>(regs.rip);
145#else
146#error Unknown Architecture
147#endif
148
149#endif // __DARWIN_UNIX03
150}
151
152template<size_t N>
153void*& argumentPointer(PlatformRegisters&);
154
155template<>
156inline void*& argumentPointer<1>(PlatformRegisters& regs)
157{
158#if __DARWIN_UNIX03
159
160#if CPU(X86)
161 return reinterpret_cast<void*&>(regs.__edx);
162#elif CPU(X86_64)
163 return reinterpret_cast<void*&>(regs.__rsi);
164#elif CPU(ARM_THUMB2) || CPU(ARM)
165 return reinterpret_cast<void*&>(regs.__r[1]);
166#elif CPU(ARM64)
167 return reinterpret_cast<void*&>(regs.__x[1]);
168#else
169#error Unknown Architecture
170#endif
171
172#else // !__DARWIN_UNIX03
173
174#if CPU(X86)
175 return reinterpret_cast<void*&>(regs.edx);
176#elif CPU(X86_64)
177 return reinterpret_cast<void*&>(regs.rsi);
178#else
179#error Unknown Architecture
180#endif
181
182#endif // __DARWIN_UNIX03
183}
184
185#if ENABLE(JIT)
186inline void*& llintInstructionPointer(PlatformRegisters& regs)
187{
188 // LLInt uses regT4 as PC.
189#if __DARWIN_UNIX03
190
191#if CPU(X86)
192 static_assert(LLInt::LLIntPC == X86Registers::esi, "Wrong LLInt PC.");
193 return reinterpret_cast<void*&>(regs.__esi);
194#elif CPU(X86_64)
195 static_assert(LLInt::LLIntPC == X86Registers::r8, "Wrong LLInt PC.");
196 return reinterpret_cast<void*&>(regs.__r8);
197#elif CPU(ARM)
198 static_assert(LLInt::LLIntPC == ARMRegisters::r8, "Wrong LLInt PC.");
199 return reinterpret_cast<void*&>(regs.__r[8]);
200#elif CPU(ARM64)
201 static_assert(LLInt::LLIntPC == ARM64Registers::x4, "Wrong LLInt PC.");
202 return reinterpret_cast<void*&>(regs.__x[4]);
203#else
204#error Unknown Architecture
205#endif
206
207#else // !__DARWIN_UNIX03
208#if CPU(X86)
209 static_assert(LLInt::LLIntPC == X86Registers::esi, "Wrong LLInt PC.");
210 return reinterpret_cast<void*&>(regs.esi);
211#elif CPU(X86_64)
212 static_assert(LLInt::LLIntPC == X86Registers::r8, "Wrong LLInt PC.");
213 return reinterpret_cast<void*&>(regs.r8);
214#else
215#error Unknown Architecture
216#endif
217
218#endif // __DARWIN_UNIX03
219}
220#endif
221
222#elif OS(WINDOWS)
223
224typedef CONTEXT PlatformRegisters;
225
226inline void*& stackPointer(PlatformRegisters& regs)
227{
228#if CPU(ARM)
229 return reinterpret_cast<void*&>((uintptr_t&) regs.Sp);
230#elif CPU(MIPS)
231 return reinterpret_cast<void*&>((uintptr_t&) regs.IntSp);
232#elif CPU(X86)
233 return reinterpret_cast<void*&>((uintptr_t&) regs.Esp);
234#elif CPU(X86_64)
235 return reinterpret_cast<void*&>((uintptr_t&) regs.Rsp);
236#else
237#error Unknown Architecture
238#endif
239}
240
241inline void*& framePointer(PlatformRegisters& regs)
242{
243#if CPU(ARM)
244 return reinterpret_cast<void*&>((uintptr_t&) regs.R11);
245#elif CPU(MIPS)
246#error Dont know what to do with mips. Do we even need this?
247#elif CPU(X86)
248 return reinterpret_cast<void*&>((uintptr_t&) regs.Ebp);
249#elif CPU(X86_64)
250 return reinterpret_cast<void*&>((uintptr_t&) regs.Rbp);
251#else
252#error Unknown Architecture
253#endif
254}
255
256inline void*& instructionPointer(PlatformRegisters& regs)
257{
258#if CPU(ARM)
259 return reinterpret_cast<void*&>((uintptr_t&) regs.Pc);
260#elif CPU(MIPS)
261#error Dont know what to do with mips. Do we even need this?
262#elif CPU(X86)
263 return reinterpret_cast<void*&>((uintptr_t&) regs.Eip);
264#elif CPU(X86_64)
265 return reinterpret_cast<void*&>((uintptr_t&) regs.Rip);
266#else
267#error Unknown Architecture
268#endif
269}
270
271template<size_t N>
272void*& argumentPointer(PlatformRegisters&);
273
274template<>
275inline void*& argumentPointer<1>(PlatformRegisters& regs);
276{
277#if CPU(ARM)
278 return reinterpret_cast<void*&>((uintptr_t&) regs.R1);
279#elif CPU(MIPS)
280#error Dont know what to do with mips. Do we even need this?
281#elif CPU(X86)
282 return reinterpret_cast<void*&>((uintptr_t&) regs.Edx);
283#elif CPU(X86_64)
284 return reinterpret_cast<void*&>((uintptr_t&) regs.Rdx);
285#else
286#error Unknown Architecture
287#endif
288}
289
290#if ENABLE(JIT)
291inline void*& llintInstructionPointer(PlatformRegisters& regs)
292{
293 // LLInt uses regT4 as PC.
294#if CPU(ARM)
295 static_assert(LLInt::LLIntPC == ARMRegisters::r8, "Wrong LLInt PC.");
296 return reinterpret_cast<void*&>((uintptr_t&) regs.R8);
297#elif CPU(MIPS)
298#error Dont know what to do with mips. Do we even need this?
299#elif CPU(X86)
300 static_assert(LLInt::LLIntPC == X86Registers::esi, "Wrong LLInt PC.");
301 return reinterpret_cast<void*&>((uintptr_t&) regs.Esi);
302#elif CPU(X86_64)
303 static_assert(LLInt::LLIntPC == X86Registers::r10, "Wrong LLInt PC.");
304 return reinterpret_cast<void*&>((uintptr_t&) regs.R10);
305#else
306#error Unknown Architecture
307#endif
308}
309#endif
310
311#endif
312
313inline void* stackPointer(const PlatformRegisters& regs)
314{
315 return stackPointer(const_cast<PlatformRegisters&>(regs));
316}
317
318inline void* framePointer(const PlatformRegisters& regs)
319{
320 return framePointer(const_cast<PlatformRegisters&>(regs));
321}
322
323inline void* instructionPointer(const PlatformRegisters& regs)
324{
325 return instructionPointer(const_cast<PlatformRegisters&>(regs));
326}
327
328template<size_t N>
329inline void* argumentPointer(const PlatformRegisters& regs)
330{
331 return argumentPointer<N>(const_cast<PlatformRegisters&>(regs));
332}
333
334#if ENABLE(JIT)
335inline void* llintInstructionPointer(const PlatformRegisters& regs)
336{
337 return llintInstructionPointer(const_cast<PlatformRegisters&>(regs));
338}
339#endif
340
341#endif
342
343#if OS(DARWIN) || ((OS(FREEBSD) || defined(__GLIBC__)) && (CPU(X86) || CPU(X86_64) || CPU(ARM) || CPU(ARM64) || CPU(MIPS)))
344
345inline void*& stackPointer(mcontext_t& machineContext)
346{
347#if OS(DARWIN)
348 return stackPointer(machineContext->__ss);
349#elif OS(FREEBSD)
350
351#if CPU(X86)
352 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_esp);
353#elif CPU(X86_64)
354 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_rsp);
355#elif CPU(ARM)
356 return reinterpret_cast<void*&>((uintptr_t&) machineContext.__gregs[_REG_SP]);
357#elif CPU(ARM64)
358 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_gpregs.gp_sp);
359#elif CPU(MIPS)
360 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_regs[29]);
361#else
362#error Unknown Architecture
363#endif
364
365#elif defined(__GLIBC__)
366
367#if CPU(X86)
368 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_ESP]);
369#elif CPU(X86_64)
370 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_RSP]);
371#elif CPU(ARM)
372 return reinterpret_cast<void*&>((uintptr_t&) machineContext.arm_sp);
373#elif CPU(ARM64)
374 return reinterpret_cast<void*&>((uintptr_t&) machineContext.sp);
375#elif CPU(MIPS)
376 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[29]);
377#else
378#error Unknown Architecture
379#endif
380#endif
381}
382
383inline void* stackPointer(const mcontext_t& machineContext)
384{
385 return stackPointer(const_cast<mcontext_t&>(machineContext));
386}
387
388inline void*& framePointer(mcontext_t& machineContext)
389{
390#if OS(DARWIN)
391 return framePointer(machineContext->__ss);
392#elif OS(FREEBSD)
393
394#if CPU(X86)
395 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_ebp);
396#elif CPU(X86_64)
397 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_rbp);
398#elif CPU(ARM)
399 return reinterpret_cast<void*&>((uintptr_t&) machineContext.__gregs[_REG_FP]);
400#elif CPU(ARM64)
401 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_gpregs.gp_x[29]);
402#elif CPU(MIPS)
403 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_regs[30]);
404#else
405#error Unknown Architecture
406#endif
407
408#elif defined(__GLIBC__)
409
410// The following sequence depends on glibc's sys/ucontext.h.
411#if CPU(X86)
412 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_EBP]);
413#elif CPU(X86_64)
414 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_RBP]);
415#elif CPU(ARM)
416 return reinterpret_cast<void*&>((uintptr_t&) machineContext.arm_fp);
417#elif CPU(ARM64)
418 return reinterpret_cast<void*&>((uintptr_t&) machineContext.regs[29]);
419#elif CPU(MIPS)
420 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[30]);
421#else
422#error Unknown Architecture
423#endif
424
425#else
426#error Need a way to get the frame pointer for another thread on this platform
427#endif
428}
429
430inline void* framePointer(const mcontext_t& machineContext)
431{
432 return framePointer(const_cast<mcontext_t&>(machineContext));
433}
434
435inline void*& instructionPointer(mcontext_t& machineContext)
436{
437#if OS(DARWIN)
438 return instructionPointer(machineContext->__ss);
439#elif OS(FREEBSD)
440
441#if CPU(X86)
442 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_eip);
443#elif CPU(X86_64)
444 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_rip);
445#elif CPU(ARM)
446 return reinterpret_cast<void*&>((uintptr_t&) machineContext.__gregs[_REG_PC]);
447#elif CPU(ARM64)
448 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_gpregs.gp_elr);
449#elif CPU(MIPS)
450 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_pc);
451#else
452#error Unknown Architecture
453#endif
454
455#elif defined(__GLIBC__)
456
457// The following sequence depends on glibc's sys/ucontext.h.
458#if CPU(X86)
459 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_EIP]);
460#elif CPU(X86_64)
461 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_RIP]);
462#elif CPU(ARM)
463 return reinterpret_cast<void*&>((uintptr_t&) machineContext.arm_pc);
464#elif CPU(ARM64)
465 return reinterpret_cast<void*&>((uintptr_t&) machineContext.pc);
466#elif CPU(MIPS)
467 return reinterpret_cast<void*&>((uintptr_t&) machineContext.pc);
468#else
469#error Unknown Architecture
470#endif
471
472#else
473#error Need a way to get the instruction pointer for another thread on this platform
474#endif
475}
476
477inline void* instructionPointer(const mcontext_t& machineContext)
478{
479 return instructionPointer(const_cast<mcontext_t&>(machineContext));
480}
481
482template<unsigned N>
483void*& argumentPointer(mcontext_t&);
484
485template<>
486inline void*& argumentPointer<1>(mcontext_t& machineContext)
487{
488#if OS(DARWIN)
489 return argumentPointer<1>(machineContext->__ss);
490#elif OS(FREEBSD)
491
492#if CPU(X86)
493 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_edx);
494#elif CPU(X86_64)
495 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_rsi);
496#elif CPU(ARM)
497 return reinterpret_cast<void*&>((uintptr_t&) machineContext.__gregs[_REG_R1]);
498#elif CPU(ARM64)
499 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_gpregs.gp_x[1]);
500#elif CPU(MIPS)
501 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_regs[5]);
502#else
503#error Unknown Architecture
504#endif
505
506#elif defined(__GLIBC__)
507
508// The following sequence depends on glibc's sys/ucontext.h.
509#if CPU(X86)
510 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_EDX]);
511#elif CPU(X86_64)
512 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_RSI]);
513#elif CPU(ARM)
514 return reinterpret_cast<void*&>((uintptr_t&) machineContext.arm_r1);
515#elif CPU(ARM64)
516 return reinterpret_cast<void*&>((uintptr_t&) machineContext.regs[1]);
517#elif CPU(MIPS)
518 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[5]);
519#else
520#error Unknown Architecture
521#endif
522
523#else
524#error Need a way to get the frame pointer for another thread on this platform
525#endif
526}
527
528template<unsigned N>
529inline void* argumentPointer(const mcontext_t& machineContext)
530{
531 return argumentPointer<N>(const_cast<mcontext_t&>(machineContext));
532}
533
534#if ENABLE(JIT)
535inline void*& llintInstructionPointer(mcontext_t& machineContext)
536{
537 // LLInt uses regT4 as PC.
538#if OS(DARWIN)
539 return llintInstructionPointer(machineContext->__ss);
540#elif OS(FREEBSD)
541
542#if CPU(X86)
543 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_esi);
544#elif CPU(X86_64)
545 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_r8);
546#elif CPU(ARM)
547 return reinterpret_cast<void*&>((uintptr_t&) machineContext.__gregs[_REG_R8]);
548#elif CPU(ARM64)
549 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_gpregs.gp_x[4]);
550#elif CPU(MIPS)
551 return reinterpret_cast<void*&>((uintptr_t&) machineContext.mc_regs[12]);
552#else
553#error Unknown Architecture
554#endif
555
556#elif defined(__GLIBC__)
557
558// The following sequence depends on glibc's sys/ucontext.h.
559#if CPU(X86)
560 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_ESI]);
561#elif CPU(X86_64)
562 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[REG_R8]);
563#elif CPU(ARM)
564 return reinterpret_cast<void*&>((uintptr_t&) machineContext.arm_r8);
565#elif CPU(ARM64)
566 return reinterpret_cast<void*&>((uintptr_t&) machineContext.regs[4]);
567#elif CPU(MIPS)
568 return reinterpret_cast<void*&>((uintptr_t&) machineContext.gregs[12]);
569#else
570#error Unknown Architecture
571#endif
572
573#else
574#error Need a way to get the LLIntPC for another thread on this platform
575#endif
576}
577
578inline void* llintInstructionPointer(const mcontext_t& machineContext)
579{
580 return llintInstructionPointer(const_cast<mcontext_t&>(machineContext));
581}
582#endif
583
584#endif
585
586}
587}