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