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

source code of libunwind/src/UnwindRegistersSave.S