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