1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#if !defined(__wasm__)
10
11#include "assembly.h"
12
13#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
14#define FROM_16_TO_31 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
15
16#define FROM_0_TO_31 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
17#define FROM_32_TO_63 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
18
19#if defined(_AIX)
20 .toc
21#elif defined(__aarch64__) && defined(__ELF__) && defined(_LIBUNWIND_EXECUTE_ONLY_CODE)
22 .section .text,"axy",@progbits,unique,0
23#else
24 .text
25#endif
26
27#if !defined(__USING_SJLJ_EXCEPTIONS__)
28
29#if defined(__i386__)
30.att_syntax
31
32#
33# extern int __unw_getcontext(unw_context_t* thread_state)
34#
35# On entry:
36# + +
37# +-----------------------+
38# + thread_state pointer +
39# +-----------------------+
40# + return address +
41# +-----------------------+ <-- SP
42# + +
43#
44DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
45
46 _LIBUNWIND_CET_ENDBR
47 push %eax
48 movl 8(%esp), %eax
49 movl %ebx, 4(%eax)
50 movl %ecx, 8(%eax)
51 movl %edx, 12(%eax)
52 movl %edi, 16(%eax)
53 movl %esi, 20(%eax)
54 movl %ebp, 24(%eax)
55 movl %esp, %edx
56 addl $8, %edx
57 movl %edx, 28(%eax) # store what sp was at call site as esp
58 # skip ss
59 # skip eflags
60 movl 4(%esp), %edx
61 movl %edx, 40(%eax) # store return address as eip
62 # skip cs
63 # skip ds
64 # skip es
65 # skip fs
66 # skip gs
67 movl (%esp), %edx
68 movl %edx, (%eax) # store original eax
69 popl %eax
70 xorl %eax, %eax # return UNW_ESUCCESS
71 ret
72
73#elif defined(__arm64ec__)
74
75//
76// extern int __unw_getcontext(unw_context_t* thread_state)
77//
78// On entry:
79// thread_state pointer is in x0
80//
81 .section .text,"xr",discard,"#__unw_getcontext"
82 .p2align 2
83DEFINE_LIBUNWIND_FUNCTION("#__unw_getcontext")
84 stp x8, x27, [x0, #0x000] // rax, rbx
85 stp x0, x1, [x0, #0x010] // rcx, rdx
86 stp x26,x25, [x0, #0x020] // rdi, rsi
87 mov x1, sp
88 stp fp, x1, [x0, #0x030] // rbp, rsp
89 stp x2, x3, [x0, #0x040] // r8, r9
90 stp x4, x5, [x0, #0x050] // r10, r11
91 stp x19,x20, [x0, #0x060] // r12, r13
92 stp x21,x22, [x0, #0x070] // r14, r15
93 str x30, [x0, #0x080] // store return address as pc
94 stp q0, q1, [x0, #0x0b0] // xmm0, xmm1
95 stp q2, q3, [x0, #0x0d0] // xmm2, xmm3
96 stp q4, q5, [x0, #0x0f0] // xmm4, xmm5
97 stp q6, q7, [x0, #0x110] // xmm6, xmm7
98 stp q8, q9, [x0, #0x130] // xmm8, xmm9
99 stp q10,q11, [x0, #0x150] // xmm10,xmm11
100 stp q12,q13, [x0, #0x170] // xmm12,xmm13
101 stp q14,q15, [x0, #0x190] // xmm14,xmm15
102 mov x0, #0 // return UNW_ESUCCESS
103 ret
104
105 .weak_anti_dep __unw_getcontext
106 .set __unw_getcontext, "#__unw_getcontext"
107
108 .section .hybmp$x,"yi"
109 .symidx "#__unw_getcontext"
110 .symidx $ientry_thunk$cdecl$i8$i8
111 .word 1
112 .text
113
114#elif defined(__x86_64__)
115.att_syntax
116
117#
118# extern int __unw_getcontext(unw_context_t* thread_state)
119#
120# On entry:
121# thread_state pointer is in rdi
122#
123DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
124#if defined(_WIN64)
125#define PTR %rcx
126#define TMP %rdx
127#else
128#define PTR %rdi
129#define TMP %rsi
130#endif
131
132 _LIBUNWIND_CET_ENDBR
133 movq %rax, (PTR)
134 movq %rbx, 8(PTR)
135 movq %rcx, 16(PTR)
136 movq %rdx, 24(PTR)
137 movq %rdi, 32(PTR)
138 movq %rsi, 40(PTR)
139 movq %rbp, 48(PTR)
140 movq %rsp, 56(PTR)
141 addq $8, 56(PTR)
142 movq %r8, 64(PTR)
143 movq %r9, 72(PTR)
144 movq %r10, 80(PTR)
145 movq %r11, 88(PTR)
146 movq %r12, 96(PTR)
147 movq %r13,104(PTR)
148 movq %r14,112(PTR)
149 movq %r15,120(PTR)
150 movq (%rsp),TMP
151 movq TMP,128(PTR) # store return address as rip
152 # skip rflags
153 # skip cs
154 # skip fs
155 # skip gs
156
157#if defined(_WIN64)
158 movdqu %xmm0,176(PTR)
159 movdqu %xmm1,192(PTR)
160 movdqu %xmm2,208(PTR)
161 movdqu %xmm3,224(PTR)
162 movdqu %xmm4,240(PTR)
163 movdqu %xmm5,256(PTR)
164 movdqu %xmm6,272(PTR)
165 movdqu %xmm7,288(PTR)
166 movdqu %xmm8,304(PTR)
167 movdqu %xmm9,320(PTR)
168 movdqu %xmm10,336(PTR)
169 movdqu %xmm11,352(PTR)
170 movdqu %xmm12,368(PTR)
171 movdqu %xmm13,384(PTR)
172 movdqu %xmm14,400(PTR)
173 movdqu %xmm15,416(PTR)
174#endif
175 xorl %eax, %eax # return UNW_ESUCCESS
176 ret
177
178#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
179
180#
181# extern int __unw_getcontext(unw_context_t* thread_state)
182#
183# On entry:
184# thread_state pointer is in a0 ($4)
185#
186DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
187 .set push
188 .set noat
189 .set noreorder
190 .set nomacro
191 sw $1, (4 * 1)($4)
192 sw $2, (4 * 2)($4)
193 sw $3, (4 * 3)($4)
194 sw $4, (4 * 4)($4)
195 sw $5, (4 * 5)($4)
196 sw $6, (4 * 6)($4)
197 sw $7, (4 * 7)($4)
198 sw $8, (4 * 8)($4)
199 sw $9, (4 * 9)($4)
200 sw $10, (4 * 10)($4)
201 sw $11, (4 * 11)($4)
202 sw $12, (4 * 12)($4)
203 sw $13, (4 * 13)($4)
204 sw $14, (4 * 14)($4)
205 sw $15, (4 * 15)($4)
206 sw $16, (4 * 16)($4)
207 sw $17, (4 * 17)($4)
208 sw $18, (4 * 18)($4)
209 sw $19, (4 * 19)($4)
210 sw $20, (4 * 20)($4)
211 sw $21, (4 * 21)($4)
212 sw $22, (4 * 22)($4)
213 sw $23, (4 * 23)($4)
214 sw $24, (4 * 24)($4)
215 sw $25, (4 * 25)($4)
216 sw $26, (4 * 26)($4)
217 sw $27, (4 * 27)($4)
218 sw $28, (4 * 28)($4)
219 sw $29, (4 * 29)($4)
220 sw $30, (4 * 30)($4)
221 sw $31, (4 * 31)($4)
222 # Store return address to pc
223 sw $31, (4 * 32)($4)
224#if __mips_isa_rev < 6
225 # hi and lo
226 mfhi $8
227 sw $8, (4 * 33)($4)
228 mflo $8
229 sw $8, (4 * 34)($4)
230#endif
231#ifdef __mips_hard_float
232#if defined(__mips_single_float)
233 // A single-precision-only FPU has no sdc1. Each register still occupies
234 // an 8-byte slot so that the context layout matches the other o32 FPU
235 // configurations; only the low half of each slot is used.
236 swc1 $f0, (4 * 36 + 8 * 0)($4)
237 swc1 $f1, (4 * 36 + 8 * 1)($4)
238 swc1 $f2, (4 * 36 + 8 * 2)($4)
239 swc1 $f3, (4 * 36 + 8 * 3)($4)
240 swc1 $f4, (4 * 36 + 8 * 4)($4)
241 swc1 $f5, (4 * 36 + 8 * 5)($4)
242 swc1 $f6, (4 * 36 + 8 * 6)($4)
243 swc1 $f7, (4 * 36 + 8 * 7)($4)
244 swc1 $f8, (4 * 36 + 8 * 8)($4)
245 swc1 $f9, (4 * 36 + 8 * 9)($4)
246 swc1 $f10, (4 * 36 + 8 * 10)($4)
247 swc1 $f11, (4 * 36 + 8 * 11)($4)
248 swc1 $f12, (4 * 36 + 8 * 12)($4)
249 swc1 $f13, (4 * 36 + 8 * 13)($4)
250 swc1 $f14, (4 * 36 + 8 * 14)($4)
251 swc1 $f15, (4 * 36 + 8 * 15)($4)
252 swc1 $f16, (4 * 36 + 8 * 16)($4)
253 swc1 $f17, (4 * 36 + 8 * 17)($4)
254 swc1 $f18, (4 * 36 + 8 * 18)($4)
255 swc1 $f19, (4 * 36 + 8 * 19)($4)
256 swc1 $f20, (4 * 36 + 8 * 20)($4)
257 swc1 $f21, (4 * 36 + 8 * 21)($4)
258 swc1 $f22, (4 * 36 + 8 * 22)($4)
259 swc1 $f23, (4 * 36 + 8 * 23)($4)
260 swc1 $f24, (4 * 36 + 8 * 24)($4)
261 swc1 $f25, (4 * 36 + 8 * 25)($4)
262 swc1 $f26, (4 * 36 + 8 * 26)($4)
263 swc1 $f27, (4 * 36 + 8 * 27)($4)
264 swc1 $f28, (4 * 36 + 8 * 28)($4)
265 swc1 $f29, (4 * 36 + 8 * 29)($4)
266 swc1 $f30, (4 * 36 + 8 * 30)($4)
267 swc1 $f31, (4 * 36 + 8 * 31)($4)
268#elif __mips_fpr != 64
269 sdc1 $f0, (4 * 36 + 8 * 0)($4)
270 sdc1 $f2, (4 * 36 + 8 * 2)($4)
271 sdc1 $f4, (4 * 36 + 8 * 4)($4)
272 sdc1 $f6, (4 * 36 + 8 * 6)($4)
273 sdc1 $f8, (4 * 36 + 8 * 8)($4)
274 sdc1 $f10, (4 * 36 + 8 * 10)($4)
275 sdc1 $f12, (4 * 36 + 8 * 12)($4)
276 sdc1 $f14, (4 * 36 + 8 * 14)($4)
277 sdc1 $f16, (4 * 36 + 8 * 16)($4)
278 sdc1 $f18, (4 * 36 + 8 * 18)($4)
279 sdc1 $f20, (4 * 36 + 8 * 20)($4)
280 sdc1 $f22, (4 * 36 + 8 * 22)($4)
281 sdc1 $f24, (4 * 36 + 8 * 24)($4)
282 sdc1 $f26, (4 * 36 + 8 * 26)($4)
283 sdc1 $f28, (4 * 36 + 8 * 28)($4)
284 sdc1 $f30, (4 * 36 + 8 * 30)($4)
285#else
286 sdc1 $f0, (4 * 36 + 8 * 0)($4)
287 sdc1 $f1, (4 * 36 + 8 * 1)($4)
288 sdc1 $f2, (4 * 36 + 8 * 2)($4)
289 sdc1 $f3, (4 * 36 + 8 * 3)($4)
290 sdc1 $f4, (4 * 36 + 8 * 4)($4)
291 sdc1 $f5, (4 * 36 + 8 * 5)($4)
292 sdc1 $f6, (4 * 36 + 8 * 6)($4)
293 sdc1 $f7, (4 * 36 + 8 * 7)($4)
294 sdc1 $f8, (4 * 36 + 8 * 8)($4)
295 sdc1 $f9, (4 * 36 + 8 * 9)($4)
296 sdc1 $f10, (4 * 36 + 8 * 10)($4)
297 sdc1 $f11, (4 * 36 + 8 * 11)($4)
298 sdc1 $f12, (4 * 36 + 8 * 12)($4)
299 sdc1 $f13, (4 * 36 + 8 * 13)($4)
300 sdc1 $f14, (4 * 36 + 8 * 14)($4)
301 sdc1 $f15, (4 * 36 + 8 * 15)($4)
302 sdc1 $f16, (4 * 36 + 8 * 16)($4)
303 sdc1 $f17, (4 * 36 + 8 * 17)($4)
304 sdc1 $f18, (4 * 36 + 8 * 18)($4)
305 sdc1 $f19, (4 * 36 + 8 * 19)($4)
306 sdc1 $f20, (4 * 36 + 8 * 20)($4)
307 sdc1 $f21, (4 * 36 + 8 * 21)($4)
308 sdc1 $f22, (4 * 36 + 8 * 22)($4)
309 sdc1 $f23, (4 * 36 + 8 * 23)($4)
310 sdc1 $f24, (4 * 36 + 8 * 24)($4)
311 sdc1 $f25, (4 * 36 + 8 * 25)($4)
312 sdc1 $f26, (4 * 36 + 8 * 26)($4)
313 sdc1 $f27, (4 * 36 + 8 * 27)($4)
314 sdc1 $f28, (4 * 36 + 8 * 28)($4)
315 sdc1 $f29, (4 * 36 + 8 * 29)($4)
316 sdc1 $f30, (4 * 36 + 8 * 30)($4)
317 sdc1 $f31, (4 * 36 + 8 * 31)($4)
318#endif
319#endif
320 jr $31
321 # return UNW_ESUCCESS
322 or $2, $0, $0
323 .set pop
324
325#elif defined(__mips64)
326
327#
328# extern int __unw_getcontext(unw_context_t* thread_state)
329#
330# On entry:
331# thread_state pointer is in a0 ($4)
332#
333DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
334 .set push
335 .set noat
336 .set noreorder
337 .set nomacro
338 .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
339 sd $\i, (8 * \i)($4)
340 .endr
341 # Store return address to pc
342 sd $31, (8 * 32)($4)
343#if __mips_isa_rev < 6
344 # hi and lo
345 mfhi $8
346 sd $8, (8 * 33)($4)
347 mflo $8
348 sd $8, (8 * 34)($4)
349#endif
350#ifdef __mips_hard_float
351 .irp i,FROM_0_TO_31
352 sdc1 $f\i, (280+8*\i)($4)
353 .endr
354#endif
355 jr $31
356 # return UNW_ESUCCESS
357 or $2, $0, $0
358 .set pop
359
360# elif defined(__mips__)
361
362#
363# extern int __unw_getcontext(unw_context_t* thread_state)
364#
365# Just trap for the time being.
366DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
367 teq $0, $0
368
369#elif defined(__powerpc64__)
370
371//
372// extern int __unw_getcontext(unw_context_t* thread_state)
373//
374// On entry:
375// thread_state pointer is in r3
376//
377#if defined(_AIX)
378DEFINE_LIBUNWIND_FUNCTION_AND_WEAK_ALIAS(__unw_getcontext, unw_getcontext)
379#else
380DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
381#endif
382// store register (GPR)
383#define PPC64_STR(n) \
384 std n, (8 * (n + 2))(3)
385
386 // save GPRs
387 PPC64_STR(0)
388 mflr 0
389 std 0, PPC64_OFFS_SRR0(3) // store lr as ssr0
390 PPC64_STR(1)
391 PPC64_STR(4) // Save r4 first since it will be used for fixing r2.
392#if defined(_AIX)
393 // The TOC register (r2) was changed by the glue code if unw_getcontext
394 // is called from a different module. Save the original TOC register
395 // in the context if this is the case.
396 mflr 4
397 lwz 4, 0(4) // Get the first instruction at the return address.
398 xoris 0, 4, 0xe841 // Is it reloading the TOC register "ld 2,40(1)"?
399 cmplwi 0, 0x28
400 bne 0, LnoR2Fix // No need to fix up r2 if it is not.
401 ld 2, 40(1) // Use the saved TOC register in the stack.
402LnoR2Fix:
403#endif
404 PPC64_STR(2)
405 PPC64_STR(3)
406 PPC64_STR(5)
407 PPC64_STR(6)
408 PPC64_STR(7)
409 PPC64_STR(8)
410 PPC64_STR(9)
411 PPC64_STR(10)
412 PPC64_STR(11)
413 PPC64_STR(12)
414 PPC64_STR(13)
415 PPC64_STR(14)
416 PPC64_STR(15)
417 PPC64_STR(16)
418 PPC64_STR(17)
419 PPC64_STR(18)
420 PPC64_STR(19)
421 PPC64_STR(20)
422 PPC64_STR(21)
423 PPC64_STR(22)
424 PPC64_STR(23)
425 PPC64_STR(24)
426 PPC64_STR(25)
427 PPC64_STR(26)
428 PPC64_STR(27)
429 PPC64_STR(28)
430 PPC64_STR(29)
431 PPC64_STR(30)
432 PPC64_STR(31)
433
434 mfcr 0
435 std 0, PPC64_OFFS_CR(3)
436 mfxer 0
437 std 0, PPC64_OFFS_XER(3)
438#if defined(_AIX)
439 // LR value saved from the register is not used, initialize it to 0.
440 li 0, 0
441#else
442 mflr 0
443#endif
444 std 0, PPC64_OFFS_LR(3)
445 mfctr 0
446 std 0, PPC64_OFFS_CTR(3)
447 mfvrsave 0
448 std 0, PPC64_OFFS_VRSAVE(3)
449
450#if defined(__VSX__)
451 // save VS registers
452 // (note that this also saves floating point registers and V registers,
453 // because part of VS is mapped to these registers)
454
455 addi 4, 3, PPC64_OFFS_FP
456
457// store VS register
458#ifdef __LITTLE_ENDIAN__
459// For little-endian targets, we need a swap since stxvd2x will store the
460// register in the incorrect doubleword order.
461// FIXME: when supporting targets older than Power9 on LE is no longer required
462// this can be changed to simply `stxv n, 16 * n(4)`.
463// Restore the register after storing: xxswapd is its own inverse, so a second
464// xxswapd undoes the in-place corruption of callee-saved VSRs (f14-f31,
465// VR20-VR31) that would otherwise persist after unw_getcontext returns.
466#define PPC64_STVS(n) \
467 xxswapd n, n ;\
468 stxvd2x n, 0, 4 ;\
469 xxswapd n, n ;\
470 addi 4, 4, 16
471#else
472#define PPC64_STVS(n) \
473 stxvd2x n, 0, 4 ;\
474 addi 4, 4, 16
475#endif
476
477 PPC64_STVS(0)
478 PPC64_STVS(1)
479 PPC64_STVS(2)
480 PPC64_STVS(3)
481 PPC64_STVS(4)
482 PPC64_STVS(5)
483 PPC64_STVS(6)
484 PPC64_STVS(7)
485 PPC64_STVS(8)
486 PPC64_STVS(9)
487 PPC64_STVS(10)
488 PPC64_STVS(11)
489 PPC64_STVS(12)
490 PPC64_STVS(13)
491 PPC64_STVS(14)
492 PPC64_STVS(15)
493 PPC64_STVS(16)
494 PPC64_STVS(17)
495 PPC64_STVS(18)
496 PPC64_STVS(19)
497 PPC64_STVS(20)
498 PPC64_STVS(21)
499 PPC64_STVS(22)
500 PPC64_STVS(23)
501 PPC64_STVS(24)
502 PPC64_STVS(25)
503 PPC64_STVS(26)
504 PPC64_STVS(27)
505 PPC64_STVS(28)
506 PPC64_STVS(29)
507 PPC64_STVS(30)
508 PPC64_STVS(31)
509 PPC64_STVS(32)
510 PPC64_STVS(33)
511 PPC64_STVS(34)
512 PPC64_STVS(35)
513 PPC64_STVS(36)
514 PPC64_STVS(37)
515 PPC64_STVS(38)
516 PPC64_STVS(39)
517 PPC64_STVS(40)
518 PPC64_STVS(41)
519 PPC64_STVS(42)
520 PPC64_STVS(43)
521 PPC64_STVS(44)
522 PPC64_STVS(45)
523 PPC64_STVS(46)
524 PPC64_STVS(47)
525 PPC64_STVS(48)
526 PPC64_STVS(49)
527 PPC64_STVS(50)
528 PPC64_STVS(51)
529 PPC64_STVS(52)
530 PPC64_STVS(53)
531 PPC64_STVS(54)
532 PPC64_STVS(55)
533 PPC64_STVS(56)
534 PPC64_STVS(57)
535 PPC64_STVS(58)
536 PPC64_STVS(59)
537 PPC64_STVS(60)
538 PPC64_STVS(61)
539 PPC64_STVS(62)
540 PPC64_STVS(63)
541
542#else
543
544// store FP register
545#define PPC64_STF(n) \
546 stfd n, (PPC64_OFFS_FP + n * 16)(3)
547
548 // save float registers
549 PPC64_STF(0)
550 PPC64_STF(1)
551 PPC64_STF(2)
552 PPC64_STF(3)
553 PPC64_STF(4)
554 PPC64_STF(5)
555 PPC64_STF(6)
556 PPC64_STF(7)
557 PPC64_STF(8)
558 PPC64_STF(9)
559 PPC64_STF(10)
560 PPC64_STF(11)
561 PPC64_STF(12)
562 PPC64_STF(13)
563 PPC64_STF(14)
564 PPC64_STF(15)
565 PPC64_STF(16)
566 PPC64_STF(17)
567 PPC64_STF(18)
568 PPC64_STF(19)
569 PPC64_STF(20)
570 PPC64_STF(21)
571 PPC64_STF(22)
572 PPC64_STF(23)
573 PPC64_STF(24)
574 PPC64_STF(25)
575 PPC64_STF(26)
576 PPC64_STF(27)
577 PPC64_STF(28)
578 PPC64_STF(29)
579 PPC64_STF(30)
580 PPC64_STF(31)
581
582#if defined(__ALTIVEC__)
583 // save vector registers
584
585 // Use 16-bytes below the stack pointer as an
586 // aligned buffer to save each vector register.
587 // Note that the stack pointer is always 16-byte aligned.
588 subi 4, 1, 16
589
590#define PPC64_STV_UNALIGNED(n) \
591 stvx n, 0, 4 ;\
592 ld 5, 0(4) ;\
593 std 5, (PPC64_OFFS_V + n * 16)(3) ;\
594 ld 5, 8(4) ;\
595 std 5, (PPC64_OFFS_V + n * 16 + 8)(3)
596
597 PPC64_STV_UNALIGNED(0)
598 PPC64_STV_UNALIGNED(1)
599 PPC64_STV_UNALIGNED(2)
600 PPC64_STV_UNALIGNED(3)
601 PPC64_STV_UNALIGNED(4)
602 PPC64_STV_UNALIGNED(5)
603 PPC64_STV_UNALIGNED(6)
604 PPC64_STV_UNALIGNED(7)
605 PPC64_STV_UNALIGNED(8)
606 PPC64_STV_UNALIGNED(9)
607 PPC64_STV_UNALIGNED(10)
608 PPC64_STV_UNALIGNED(11)
609 PPC64_STV_UNALIGNED(12)
610 PPC64_STV_UNALIGNED(13)
611 PPC64_STV_UNALIGNED(14)
612 PPC64_STV_UNALIGNED(15)
613 PPC64_STV_UNALIGNED(16)
614 PPC64_STV_UNALIGNED(17)
615 PPC64_STV_UNALIGNED(18)
616 PPC64_STV_UNALIGNED(19)
617 PPC64_STV_UNALIGNED(20)
618 PPC64_STV_UNALIGNED(21)
619 PPC64_STV_UNALIGNED(22)
620 PPC64_STV_UNALIGNED(23)
621 PPC64_STV_UNALIGNED(24)
622 PPC64_STV_UNALIGNED(25)
623 PPC64_STV_UNALIGNED(26)
624 PPC64_STV_UNALIGNED(27)
625 PPC64_STV_UNALIGNED(28)
626 PPC64_STV_UNALIGNED(29)
627 PPC64_STV_UNALIGNED(30)
628 PPC64_STV_UNALIGNED(31)
629
630#endif
631#endif
632
633 li 3, 0 // return UNW_ESUCCESS
634 blr
635
636
637#elif defined(__powerpc__)
638
639//
640// extern int unw_getcontext(unw_context_t* thread_state)
641//
642// On entry:
643// thread_state pointer is in r3
644//
645#if defined(_AIX)
646DEFINE_LIBUNWIND_FUNCTION_AND_WEAK_ALIAS(__unw_getcontext, unw_getcontext)
647#else
648DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
649#endif
650 stw 0, 8(3)
651 mflr 0
652 stw 0, 0(3) // store lr as ssr0
653 stw 1, 12(3)
654 stw 4, 24(3) // Save r4 first since it will be used for fixing r2.
655#if defined(_AIX)
656 // The TOC register (r2) was changed by the glue code if unw_getcontext
657 // is called from a different module. Save the original TOC register
658 // in the context if this is the case.
659 mflr 4
660 lwz 4, 0(4) // Get the instruction at the return address.
661 xoris 0, 4, 0x8041 // Is it reloading the TOC register "lwz 2,20(1)"?
662 cmplwi 0, 0x14
663 bne 0, LnoR2Fix // No need to fix up r2 if it is not.
664 lwz 2, 20(1) // Use the saved TOC register in the stack.
665LnoR2Fix:
666#endif
667 stw 2, 16(3)
668 stw 3, 20(3)
669 stw 5, 28(3)
670 stw 6, 32(3)
671 stw 7, 36(3)
672 stw 8, 40(3)
673 stw 9, 44(3)
674 stw 10, 48(3)
675 stw 11, 52(3)
676 stw 12, 56(3)
677 stw 13, 60(3)
678 stw 14, 64(3)
679 stw 15, 68(3)
680 stw 16, 72(3)
681 stw 17, 76(3)
682 stw 18, 80(3)
683 stw 19, 84(3)
684 stw 20, 88(3)
685 stw 21, 92(3)
686 stw 22, 96(3)
687 stw 23,100(3)
688 stw 24,104(3)
689 stw 25,108(3)
690 stw 26,112(3)
691 stw 27,116(3)
692 stw 28,120(3)
693 stw 29,124(3)
694 stw 30,128(3)
695 stw 31,132(3)
696
697#if defined(__ALTIVEC__)
698 // save VRSave register
699 mfspr 0, 256
700 stw 0, 156(3)
701#endif
702 // save CR registers
703 mfcr 0
704 stw 0, 136(3)
705#if defined(_AIX)
706 // LR value from the register is not used, initialize it to 0.
707 li 0, 0
708 stw 0, 144(3)
709#endif
710 // save CTR register
711 mfctr 0
712 stw 0, 148(3)
713
714#if !defined(__NO_FPRS__)
715 // save float registers
716 stfd 0, 160(3)
717 stfd 1, 168(3)
718 stfd 2, 176(3)
719 stfd 3, 184(3)
720 stfd 4, 192(3)
721 stfd 5, 200(3)
722 stfd 6, 208(3)
723 stfd 7, 216(3)
724 stfd 8, 224(3)
725 stfd 9, 232(3)
726 stfd 10,240(3)
727 stfd 11,248(3)
728 stfd 12,256(3)
729 stfd 13,264(3)
730 stfd 14,272(3)
731 stfd 15,280(3)
732 stfd 16,288(3)
733 stfd 17,296(3)
734 stfd 18,304(3)
735 stfd 19,312(3)
736 stfd 20,320(3)
737 stfd 21,328(3)
738 stfd 22,336(3)
739 stfd 23,344(3)
740 stfd 24,352(3)
741 stfd 25,360(3)
742 stfd 26,368(3)
743 stfd 27,376(3)
744 stfd 28,384(3)
745 stfd 29,392(3)
746 stfd 30,400(3)
747 stfd 31,408(3)
748#endif
749
750#if defined(__ALTIVEC__)
751 // save vector registers
752
753 subi 4, 1, 16
754 rlwinm 4, 4, 0, 0, 27 // mask low 4-bits
755 // r4 is now a 16-byte aligned pointer into the red zone
756
757#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
758 stvx _vec, 0, 4 SEPARATOR \
759 lwz 5, 0(4) SEPARATOR \
760 stw 5, _offset(3) SEPARATOR \
761 lwz 5, 4(4) SEPARATOR \
762 stw 5, _offset+4(3) SEPARATOR \
763 lwz 5, 8(4) SEPARATOR \
764 stw 5, _offset+8(3) SEPARATOR \
765 lwz 5, 12(4) SEPARATOR \
766 stw 5, _offset+12(3)
767
768 SAVE_VECTOR_UNALIGNED( 0, 424+0x000)
769 SAVE_VECTOR_UNALIGNED( 1, 424+0x010)
770 SAVE_VECTOR_UNALIGNED( 2, 424+0x020)
771 SAVE_VECTOR_UNALIGNED( 3, 424+0x030)
772 SAVE_VECTOR_UNALIGNED( 4, 424+0x040)
773 SAVE_VECTOR_UNALIGNED( 5, 424+0x050)
774 SAVE_VECTOR_UNALIGNED( 6, 424+0x060)
775 SAVE_VECTOR_UNALIGNED( 7, 424+0x070)
776 SAVE_VECTOR_UNALIGNED( 8, 424+0x080)
777 SAVE_VECTOR_UNALIGNED( 9, 424+0x090)
778 SAVE_VECTOR_UNALIGNED(10, 424+0x0A0)
779 SAVE_VECTOR_UNALIGNED(11, 424+0x0B0)
780 SAVE_VECTOR_UNALIGNED(12, 424+0x0C0)
781 SAVE_VECTOR_UNALIGNED(13, 424+0x0D0)
782 SAVE_VECTOR_UNALIGNED(14, 424+0x0E0)
783 SAVE_VECTOR_UNALIGNED(15, 424+0x0F0)
784 SAVE_VECTOR_UNALIGNED(16, 424+0x100)
785 SAVE_VECTOR_UNALIGNED(17, 424+0x110)
786 SAVE_VECTOR_UNALIGNED(18, 424+0x120)
787 SAVE_VECTOR_UNALIGNED(19, 424+0x130)
788 SAVE_VECTOR_UNALIGNED(20, 424+0x140)
789 SAVE_VECTOR_UNALIGNED(21, 424+0x150)
790 SAVE_VECTOR_UNALIGNED(22, 424+0x160)
791 SAVE_VECTOR_UNALIGNED(23, 424+0x170)
792 SAVE_VECTOR_UNALIGNED(24, 424+0x180)
793 SAVE_VECTOR_UNALIGNED(25, 424+0x190)
794 SAVE_VECTOR_UNALIGNED(26, 424+0x1A0)
795 SAVE_VECTOR_UNALIGNED(27, 424+0x1B0)
796 SAVE_VECTOR_UNALIGNED(28, 424+0x1C0)
797 SAVE_VECTOR_UNALIGNED(29, 424+0x1D0)
798 SAVE_VECTOR_UNALIGNED(30, 424+0x1E0)
799 SAVE_VECTOR_UNALIGNED(31, 424+0x1F0)
800#endif
801
802 li 3, 0 // return UNW_ESUCCESS
803 blr
804
805
806#elif defined(__aarch64__)
807
808#ifndef __has_feature
809#define __has_feature(__feature) 0
810#endif
811
812//
813// extern int __unw_getcontext(unw_context_t* thread_state)
814//
815// On entry:
816// thread_state pointer is in x0
817//
818 .p2align 2
819DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
820
821#if __has_feature(ptrauth_calls)
822 pacibsp
823#endif
824
825 stp x0, x1, [x0, #0x000]
826 stp x2, x3, [x0, #0x010]
827 stp x4, x5, [x0, #0x020]
828 stp x6, x7, [x0, #0x030]
829 stp x8, x9, [x0, #0x040]
830 stp x10,x11, [x0, #0x050]
831 stp x12,x13, [x0, #0x060]
832 stp x14,x15, [x0, #0x070]
833 stp x16,x17, [x0, #0x080]
834 stp x18,x19, [x0, #0x090]
835 stp x20,x21, [x0, #0x0A0]
836 stp x22,x23, [x0, #0x0B0]
837#if defined(__LFI__)
838 str x24, [x0, #0x0C0]
839 // Skip spilling x25-x28; reserved by LFI ABI.
840 str x29, [x0, #0x0E8]
841#else
842 stp x24,x25, [x0, #0x0C0]
843 stp x26,x27, [x0, #0x0D0]
844 stp x28,x29, [x0, #0x0E0]
845#endif
846 str x30, [x0, #0x0F0]
847 mov x1,sp
848 str x1, [x0, #0x0F8]
849 str x30, [x0, #0x100] // store return address as pc
850 str xzr, [x0, #0x108] // zero __ra_sign_state
851 // skip cpsr
852#if defined(__ARM_FP) && __ARM_FP != 0
853 stp d0, d1, [x0, #0x110]
854 stp d2, d3, [x0, #0x120]
855 stp d4, d5, [x0, #0x130]
856 stp d6, d7, [x0, #0x140]
857 stp d8, d9, [x0, #0x150]
858 stp d10,d11, [x0, #0x160]
859 stp d12,d13, [x0, #0x170]
860 stp d14,d15, [x0, #0x180]
861 stp d16,d17, [x0, #0x190]
862 stp d18,d19, [x0, #0x1A0]
863 stp d20,d21, [x0, #0x1B0]
864 stp d22,d23, [x0, #0x1C0]
865 stp d24,d25, [x0, #0x1D0]
866 stp d26,d27, [x0, #0x1E0]
867 stp d28,d29, [x0, #0x1F0]
868 str d30, [x0, #0x200]
869 str d31, [x0, #0x208]
870#endif
871 mov x0, #0 // return UNW_ESUCCESS
872
873#if __has_feature(ptrauth_calls)
874 retab
875#else
876 ret
877#endif
878
879//
880// extern "C" int64_t __libunwind_Registers_arm64_za_disable()
881//
882// This function implements the requirements of the __arm_za_disable ABI
883// routine, except that it will not abort; it will return a non-zero value
884// to signify the routine failed.
885//
886// Note: This function uses SME instructions. It must only be called if SME
887// has been confirmed to be available.
888//
889// On return:
890//
891// A status is placed in x0. A zero value indicates success; any non-zero
892// value indicates failure.
893//
894 .p2align 2
895DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_za_disable)
896 .variant_pcs __libunwind_Registers_arm64_za_disable
897#if defined(__LFI__)
898 mov x0, #1
899 ret
900#else
901#if __has_feature(ptrauth_calls)
902 pacibsp
903#endif
904 // If TPIDR2_EL0 is null, the subroutine just disables ZA.
905 .inst 0xd53bd0b0 // mrs x16, TPIDR2_EL0
906 cbz x16, 1f
907
908 // If any of the reserved bytes in the first 16 bytes of the TPIDR2 block are
909 // nonzero, return a non-zero value (libunwind will then abort).
910 ldrh w0, [x16, #10]
911 cbnz w0, 2f
912 ldr w0, [x16, #12]
913 cbnz w0, 2f
914
915 // If num_za_save_slices is zero, the subroutine just disables ZA.
916 ldrh w0, [x16, #8]
917 cbz x0, 1f
918
919 // If za_save_buffer is NULL, the subroutine just disables ZA.
920 ldr x16, [x16]
921 cbz x16, 1f
922
923 // Store ZA to za_save_buffer.
924 mov x15, xzr
9250:
926 .inst 0xe1206200 // str za[w15,0], [x16]
927 .inst 0x04305830 // addsvl x16, x16, #1
928 add x15, x15, #1
929 cmp x0, x15
930 b.ne 0b
9311:
932 // * Set TPIDR2_EL0 to null.
933 .inst 0xd51bd0bf // msr TPIDR2_EL0, xzr
934 // * Set PSTATE.ZA to 0.
935 .inst 0xd503447f // smstop za
936 // * Return zero (success)
937 mov x0, xzr
9382:
939#if __has_feature(ptrauth_calls)
940 retab
941#else
942 ret
943#endif
944#endif
945
946#elif defined(__arm__) && !defined(__APPLE__)
947
948#if !defined(__ARM_ARCH_ISA_ARM)
949#if (__ARM_ARCH_ISA_THUMB == 2)
950 .syntax unified
951#endif
952 .thumb
953#endif
954
955@
956@ extern int __unw_getcontext(unw_context_t* thread_state)
957@
958@ On entry:
959@ thread_state pointer is in r0
960@
961@ Per EHABI #4.7 this only saves the core integer registers.
962@ EHABI #7.4.5 notes that in general all VRS registers should be restored
963@ however this is very hard to do for VFP registers because it is unknown
964@ to the library how many registers are implemented by the architecture.
965@ Instead, VFP registers are demand saved by logic external to __unw_getcontext.
966@
967 .p2align 2
968DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
969#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
970 stm r0!, {r0-r7}
971 mov r1, r8
972 mov r2, r9
973 mov r3, r10
974 stm r0!, {r1-r3}
975 mov r1, r11
976 mov r2, sp
977 mov r3, lr
978 str r1, [r0, #0] @ r11
979 @ r12 does not need storing, it it the intra-procedure-call scratch register
980 str r2, [r0, #8] @ sp
981 str r3, [r0, #12] @ lr
982 str r3, [r0, #16] @ store return address as pc
983 @ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
984 @ It is safe to use here though because we are about to return, and cpsr is
985 @ not expected to be preserved.
986 movs r0, #0 @ return UNW_ESUCCESS
987#else
988 @ 32bit thumb-2 restrictions for stm:
989 @ . the sp (r13) cannot be in the list
990 @ . the pc (r15) cannot be in the list in an STM instruction
991 stm r0, {r0-r12}
992 str sp, [r0, #52]
993 str lr, [r0, #56]
994 str lr, [r0, #60] @ store return address as pc
995 mov r0, #0 @ return UNW_ESUCCESS
996#endif
997 JMP(lr)
998
999@
1000@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values)
1001@
1002@ On entry:
1003@ values pointer is in r0
1004@
1005 .p2align 2
1006#if defined(__ELF__)
1007 .fpu vfpv3-d16
1008#endif
1009DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPv)
1010 vstmia r0, {d0-d15}
1011 JMP(lr)
1012
1013@
1014@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values)
1015@
1016@ On entry:
1017@ values pointer is in r0
1018@
1019 .p2align 2
1020#if defined(__ELF__)
1021 .fpu vfpv3-d16
1022#endif
1023DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPv)
1024 vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
1025 JMP(lr)
1026
1027@
1028@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values)
1029@
1030@ On entry:
1031@ values pointer is in r0
1032@
1033 .p2align 2
1034#if defined(__ELF__)
1035 .fpu vfpv3
1036#endif
1037DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPv)
1038 @ VFP and iwMMX instructions are only available when compiling with the flags
1039 @ that enable them. We do not want to do that in the library (because we do not
1040 @ want the compiler to generate instructions that access those) but this is
1041 @ only accessed if the personality routine needs these registers. Use of
1042 @ these registers implies they are, actually, available on the target, so
1043 @ it's ok to execute.
1044 @ So, generate the instructions using the corresponding coprocessor mnemonic.
1045 vstmia r0, {d16-d31}
1046 JMP(lr)
1047
1048#if defined(_LIBUNWIND_ARM_WMMX)
1049
1050@
1051@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
1052@
1053@ On entry:
1054@ values pointer is in r0
1055@
1056 .p2align 2
1057#if defined(__ELF__)
1058 .arch armv5te
1059#endif
1060DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPv)
1061 stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8
1062 stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8
1063 stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8
1064 stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8
1065 stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8
1066 stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8
1067 stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8
1068 stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8
1069 stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8
1070 stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8
1071 stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8
1072 stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8
1073 stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8
1074 stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8
1075 stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8
1076 stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8
1077 JMP(lr)
1078
1079@
1080@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values)
1081@
1082@ On entry:
1083@ values pointer is in r0
1084@
1085 .p2align 2
1086#if defined(__ELF__)
1087 .arch armv5te
1088#endif
1089DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
1090 stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4
1091 stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4
1092 stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4
1093 stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4
1094 JMP(lr)
1095
1096#endif
1097
1098#elif defined(__or1k__)
1099
1100#
1101# extern int __unw_getcontext(unw_context_t* thread_state)
1102#
1103# On entry:
1104# thread_state pointer is in r3
1105#
1106DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
1107 l.sw 0(r3), r0
1108 l.sw 4(r3), r1
1109 l.sw 8(r3), r2
1110 l.sw 12(r3), r3
1111 l.sw 16(r3), r4
1112 l.sw 20(r3), r5
1113 l.sw 24(r3), r6
1114 l.sw 28(r3), r7
1115 l.sw 32(r3), r8
1116 l.sw 36(r3), r9
1117 l.sw 40(r3), r10
1118 l.sw 44(r3), r11
1119 l.sw 48(r3), r12
1120 l.sw 52(r3), r13
1121 l.sw 56(r3), r14
1122 l.sw 60(r3), r15
1123 l.sw 64(r3), r16
1124 l.sw 68(r3), r17
1125 l.sw 72(r3), r18
1126 l.sw 76(r3), r19
1127 l.sw 80(r3), r20
1128 l.sw 84(r3), r21
1129 l.sw 88(r3), r22
1130 l.sw 92(r3), r23
1131 l.sw 96(r3), r24
1132 l.sw 100(r3), r25
1133 l.sw 104(r3), r26
1134 l.sw 108(r3), r27
1135 l.sw 112(r3), r28
1136 l.sw 116(r3), r29
1137 l.sw 120(r3), r30
1138 l.sw 124(r3), r31
1139 # store ra to pc
1140 l.sw 128(r3), r9
1141 # zero epcr
1142 l.sw 132(r3), r0
1143
1144#elif defined(__hexagon__)
1145#
1146# extern int unw_getcontext(unw_context_t* thread_state)
1147#
1148# On entry:
1149# thread_state pointer is in r0
1150#
1151# The context layout is hexagon_thread_state_t: unsigned int __r[35]
1152# __r[0..31] = r0..r31, __r[32] = predicates, __r[33] = PC, __r[34] = unused
1153# Offsets: __r[n] is at byte offset n*4.
1154#
1155#define OFFSET(offset) (offset/4)
1156DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
1157 // Save r1-r7 first (r0 is the context pointer, saved last)
1158 memw(r0+#4) = r1
1159 memw(r0+#8) = r2
1160 memw(r0+#12) = r3
1161 memw(r0+#16) = r4
1162 memw(r0+#20) = r5
1163 memw(r0+#24) = r6
1164 memw(r0+#28) = r7
1165
1166 memw(r0+#32) = r8
1167 memw(r0+#36) = r9
1168 memw(r0+#40) = r10
1169 memw(r0+#44) = r11
1170
1171 memw(r0+#48) = r12
1172 memw(r0+#52) = r13
1173 memw(r0+#56) = r14
1174 memw(r0+#60) = r15
1175
1176 memw(r0+#64) = r16
1177 memw(r0+#68) = r17
1178 memw(r0+#72) = r18
1179 memw(r0+#76) = r19
1180
1181 memw(r0+#80) = r20
1182 memw(r0+#84) = r21
1183 memw(r0+#88) = r22
1184 memw(r0+#92) = r23
1185
1186 memw(r0+#96) = r24
1187 memw(r0+#100) = r25
1188 memw(r0+#104) = r26
1189 memw(r0+#108) = r27
1190
1191 memw(r0+#112) = r28
1192 memw(r0+#116) = r29
1193 memw(r0+#120) = r30
1194 memw(r0+#124) = r31
1195
1196 r1 = c4 // Predicate register
1197 memw(r0+#128) = r1
1198
1199 r1 = r31 // Store return address as PC
1200 memw(r0+#132) = r1
1201
1202 // Save r0 (the context pointer itself) last
1203 memw(r0+#0) = r0
1204
1205 r0 = #0 // return UNW_ESUCCESS
1206 jumpr r31
1207
1208#elif defined(__sparc__) && defined(__arch64__)
1209
1210#
1211# extern int __unw_getcontext(unw_context_t* thread_state)
1212#
1213# On entry:
1214# thread_state pointer is in %o0
1215#
1216DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
1217 .register %g2, #scratch
1218 .register %g3, #scratch
1219 .register %g6, #scratch
1220 .register %g7, #scratch
1221 stx %g1, [%o0 + 0x08]
1222 stx %g2, [%o0 + 0x10]
1223 stx %g3, [%o0 + 0x18]
1224 stx %g4, [%o0 + 0x20]
1225 stx %g5, [%o0 + 0x28]
1226 stx %g6, [%o0 + 0x30]
1227 stx %g7, [%o0 + 0x38]
1228 stx %o0, [%o0 + 0x40]
1229 stx %o1, [%o0 + 0x48]
1230 stx %o2, [%o0 + 0x50]
1231 stx %o3, [%o0 + 0x58]
1232 stx %o4, [%o0 + 0x60]
1233 stx %o5, [%o0 + 0x68]
1234 stx %o6, [%o0 + 0x70]
1235 stx %o7, [%o0 + 0x78]
1236 stx %l0, [%o0 + 0x80]
1237 stx %l1, [%o0 + 0x88]
1238 stx %l2, [%o0 + 0x90]
1239 stx %l3, [%o0 + 0x98]
1240 stx %l4, [%o0 + 0xa0]
1241 stx %l5, [%o0 + 0xa8]
1242 stx %l6, [%o0 + 0xb0]
1243 stx %l7, [%o0 + 0xb8]
1244 stx %i0, [%o0 + 0xc0]
1245 stx %i1, [%o0 + 0xc8]
1246 stx %i2, [%o0 + 0xd0]
1247 stx %i3, [%o0 + 0xd8]
1248 stx %i4, [%o0 + 0xe0]
1249 stx %i5, [%o0 + 0xe8]
1250 stx %i6, [%o0 + 0xf0]
1251 stx %i7, [%o0 + 0xf8]
1252
1253 # save StackGhost cookie
1254 mov %i7, %g4
1255 save %sp, -176, %sp
1256 # register window flush necessary even without StackGhost
1257 flushw
1258 restore
1259 ldx [%sp + 2047 + 0x78], %g5
1260 xor %g4, %g5, %g4
1261 stx %g4, [%o0 + 0x100]
1262 retl
1263 # return UNW_ESUCCESS
1264 clr %o0
1265
1266#elif defined(__sparc__)
1267
1268#
1269# extern int __unw_getcontext(unw_context_t* thread_state)
1270#
1271# On entry:
1272# thread_state pointer is in o0
1273#
1274DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
1275 ta 3
1276 add %o7, 8, %o7
1277 std %g0, [%o0 + 0]
1278 std %g2, [%o0 + 8]
1279 std %g4, [%o0 + 16]
1280 std %g6, [%o0 + 24]
1281 std %o0, [%o0 + 32]
1282 std %o2, [%o0 + 40]
1283 std %o4, [%o0 + 48]
1284 std %o6, [%o0 + 56]
1285 std %l0, [%o0 + 64]
1286 std %l2, [%o0 + 72]
1287 std %l4, [%o0 + 80]
1288 std %l6, [%o0 + 88]
1289 std %i0, [%o0 + 96]
1290 std %i2, [%o0 + 104]
1291 std %i4, [%o0 + 112]
1292 std %i6, [%o0 + 120]
1293 jmp %o7
1294 clr %o0 // return UNW_ESUCCESS
1295
1296#elif defined(__riscv)
1297
1298#
1299# extern int __unw_getcontext(unw_context_t* thread_state)
1300#
1301# On entry:
1302# thread_state pointer is in a0
1303#
1304DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
1305 ISTORE x1, (RISCV_ISIZE * 0)(a0) // store ra as pc
1306#if defined(__riscv_32e)
1307 .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
1308#else
1309 .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
1310#endif
1311 ISTORE x\i, (RISCV_ISIZE * \i)(a0)
1312 .endr
1313
1314# if defined(__riscv_flen)
1315 .irp i,FROM_0_TO_31
1316 FSTORE f\i, (RISCV_FOFFSET + RISCV_FSIZE * \i)(a0)
1317 .endr
1318# endif
1319
1320 li a0, 0 // return UNW_ESUCCESS
1321 ret // jump to ra
1322
1323#elif defined(__s390x__)
1324
1325//
1326// extern int __unw_getcontext(unw_context_t* thread_state)
1327//
1328// On entry:
1329// thread_state pointer is in r2
1330//
1331DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
1332
1333 // Save GPRs
1334 stmg %r0, %r15, 16(%r2)
1335
1336 // Save PSWM
1337 epsw %r0, %r1
1338 stm %r0, %r1, 0(%r2)
1339
1340 // Store return address as PSWA
1341 stg %r14, 8(%r2)
1342
1343 // Save FPRs
1344 .irp i,FROM_0_TO_15
1345 std %f\i, (144+8*\i)(%r2)
1346 .endr
1347
1348 // Return UNW_ESUCCESS
1349 lghi %r2, 0
1350 br %r14
1351
1352#elif defined(__loongarch__) && __loongarch_grlen == 64
1353
1354#
1355# extern int __unw_getcontext(unw_context_t* thread_state)
1356#
1357# On entry:
1358# thread_state pointer is in $a0($r4)
1359#
1360DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
1361 .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
1362 st.d $r\i, $a0, (8*\i)
1363 .endr
1364 st.d $r1, $a0, (8 * 32) // store $ra to pc
1365
1366# if __loongarch_frlen == 64
1367 .irp i,FROM_0_TO_31
1368 fst.d $f\i, $a0, (8 * 33 + 8 * \i)
1369 .endr
1370# endif
1371
1372 move $a0, $zero // UNW_ESUCCESS
1373 jr $ra
1374
1375#endif
1376
1377#ifdef __arm64ec__
1378 .globl "#unw_getcontext"
1379 .set "#unw_getcontext", "#__unw_getcontext"
1380 .weak_anti_dep unw_getcontext
1381 .set unw_getcontext, "#unw_getcontext"
1382 EXPORT_SYMBOL(unw_getcontext)
1383#else
1384 WEAK_ALIAS(__unw_getcontext, unw_getcontext)
1385#endif
1386
1387#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
1388
1389NO_EXEC_STACK_DIRECTIVE
1390
1391#endif /* !defined(__wasm__) */
1392