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