1 //===----------------------------------------------------------------------===//
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
8 // Does runtime stack unwinding using compact unwind encodings.
10 //===----------------------------------------------------------------------===//
12 #ifndef __COMPACT_UNWINDER_HPP__
13 #define __COMPACT_UNWINDER_HPP__
18 #include <libunwind.h>
19 #include <mach-o/compact_unwind_encoding.h>
21 #include "Registers.hpp"
22 #include "libunwind_ext.h"
24 #define EXTRACT_BITS(value, mask) \
25 ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
29 #if defined(_LIBUNWIND_TARGET_I386)
30 /// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
31 /// unwind) by modifying a Registers_x86 register set
33 class CompactUnwinder_x86
{
36 static int stepWithCompactEncoding(compact_unwind_encoding_t info
,
37 uint32_t functionStart
, A
&addressSpace
,
38 Registers_x86
®isters
);
41 typename
A::pint_t pint_t
;
43 static void frameUnwind(A
&addressSpace
, Registers_x86
®isters
);
44 static void framelessUnwind(A
&addressSpace
,
45 typename
A::pint_t returnAddressLocation
,
46 Registers_x86
®isters
);
48 stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding
,
49 uint32_t functionStart
, A
&addressSpace
,
50 Registers_x86
®isters
);
51 static int stepWithCompactEncodingFrameless(
52 compact_unwind_encoding_t compactEncoding
, uint32_t functionStart
,
53 A
&addressSpace
, Registers_x86
®isters
, bool indirectStackSize
);
57 int CompactUnwinder_x86
<A
>::stepWithCompactEncoding(
58 compact_unwind_encoding_t compactEncoding
, uint32_t functionStart
,
59 A
&addressSpace
, Registers_x86
®isters
) {
60 switch (compactEncoding
& UNWIND_X86_MODE_MASK
) {
61 case UNWIND_X86_MODE_EBP_FRAME
:
62 return stepWithCompactEncodingEBPFrame(compactEncoding
, functionStart
,
63 addressSpace
, registers
);
64 case UNWIND_X86_MODE_STACK_IMMD
:
65 return stepWithCompactEncodingFrameless(compactEncoding
, functionStart
,
66 addressSpace
, registers
, false);
67 case UNWIND_X86_MODE_STACK_IND
:
68 return stepWithCompactEncodingFrameless(compactEncoding
, functionStart
,
69 addressSpace
, registers
, true);
71 _LIBUNWIND_ABORT("invalid compact unwind encoding");
75 int CompactUnwinder_x86
<A
>::stepWithCompactEncodingEBPFrame(
76 compact_unwind_encoding_t compactEncoding
, uint32_t functionStart
,
77 A
&addressSpace
, Registers_x86
®isters
) {
78 uint32_t savedRegistersOffset
=
79 EXTRACT_BITS(compactEncoding
, UNWIND_X86_EBP_FRAME_OFFSET
);
80 uint32_t savedRegistersLocations
=
81 EXTRACT_BITS(compactEncoding
, UNWIND_X86_EBP_FRAME_REGISTERS
);
83 uint32_t savedRegisters
= registers
.getEBP() - 4 * savedRegistersOffset
;
84 for (int i
= 0; i
< 5; ++i
) {
85 switch (savedRegistersLocations
& 0x7) {
86 case UNWIND_X86_REG_NONE
:
87 // no register saved in this slot
89 case UNWIND_X86_REG_EBX
:
90 registers
.setEBX(addressSpace
.get32(savedRegisters
));
92 case UNWIND_X86_REG_ECX
:
93 registers
.setECX(addressSpace
.get32(savedRegisters
));
95 case UNWIND_X86_REG_EDX
:
96 registers
.setEDX(addressSpace
.get32(savedRegisters
));
98 case UNWIND_X86_REG_EDI
:
99 registers
.setEDI(addressSpace
.get32(savedRegisters
));
101 case UNWIND_X86_REG_ESI
:
102 registers
.setESI(addressSpace
.get32(savedRegisters
));
106 _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
107 "function starting at 0x%X",
108 compactEncoding
, functionStart
);
109 _LIBUNWIND_ABORT("invalid compact unwind encoding");
112 savedRegistersLocations
= (savedRegistersLocations
>> 3);
114 frameUnwind(addressSpace
, registers
);
115 return UNW_STEP_SUCCESS
;
118 template <typename A
>
119 int CompactUnwinder_x86
<A
>::stepWithCompactEncodingFrameless(
120 compact_unwind_encoding_t encoding
, uint32_t functionStart
,
121 A
&addressSpace
, Registers_x86
®isters
, bool indirectStackSize
) {
122 uint32_t stackSizeEncoded
=
123 EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_SIZE
);
124 uint32_t stackAdjust
=
125 EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_ADJUST
);
127 EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_REG_COUNT
);
128 uint32_t permutation
=
129 EXTRACT_BITS(encoding
, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION
);
130 uint32_t stackSize
= stackSizeEncoded
* 4;
131 if (indirectStackSize
) {
132 // stack size is encoded in subl $xxx,%esp instruction
133 uint32_t subl
= addressSpace
.get32(functionStart
+ stackSizeEncoded
);
134 stackSize
= subl
+ 4 * stackAdjust
;
136 // decompress permutation
137 uint32_t permunreg
[6];
140 permunreg
[0] = permutation
/ 120;
141 permutation
-= (permunreg
[0] * 120);
142 permunreg
[1] = permutation
/ 24;
143 permutation
-= (permunreg
[1] * 24);
144 permunreg
[2] = permutation
/ 6;
145 permutation
-= (permunreg
[2] * 6);
146 permunreg
[3] = permutation
/ 2;
147 permutation
-= (permunreg
[3] * 2);
148 permunreg
[4] = permutation
;
152 permunreg
[0] = permutation
/ 120;
153 permutation
-= (permunreg
[0] * 120);
154 permunreg
[1] = permutation
/ 24;
155 permutation
-= (permunreg
[1] * 24);
156 permunreg
[2] = permutation
/ 6;
157 permutation
-= (permunreg
[2] * 6);
158 permunreg
[3] = permutation
/ 2;
159 permutation
-= (permunreg
[3] * 2);
160 permunreg
[4] = permutation
;
163 permunreg
[0] = permutation
/ 60;
164 permutation
-= (permunreg
[0] * 60);
165 permunreg
[1] = permutation
/ 12;
166 permutation
-= (permunreg
[1] * 12);
167 permunreg
[2] = permutation
/ 3;
168 permutation
-= (permunreg
[2] * 3);
169 permunreg
[3] = permutation
;
172 permunreg
[0] = permutation
/ 20;
173 permutation
-= (permunreg
[0] * 20);
174 permunreg
[1] = permutation
/ 4;
175 permutation
-= (permunreg
[1] * 4);
176 permunreg
[2] = permutation
;
179 permunreg
[0] = permutation
/ 5;
180 permutation
-= (permunreg
[0] * 5);
181 permunreg
[1] = permutation
;
184 permunreg
[0] = permutation
;
187 // re-number registers back to standard numbers
188 int registersSaved
[6];
189 bool used
[7] = { false, false, false, false, false, false, false };
190 for (uint32_t i
= 0; i
< regCount
; ++i
) {
192 for (int u
= 1; u
< 7; ++u
) {
194 if (renum
== permunreg
[i
]) {
195 registersSaved
[i
] = u
;
203 uint32_t savedRegisters
= registers
.getSP() + stackSize
- 4 - 4 * regCount
;
204 for (uint32_t i
= 0; i
< regCount
; ++i
) {
205 switch (registersSaved
[i
]) {
206 case UNWIND_X86_REG_EBX
:
207 registers
.setEBX(addressSpace
.get32(savedRegisters
));
209 case UNWIND_X86_REG_ECX
:
210 registers
.setECX(addressSpace
.get32(savedRegisters
));
212 case UNWIND_X86_REG_EDX
:
213 registers
.setEDX(addressSpace
.get32(savedRegisters
));
215 case UNWIND_X86_REG_EDI
:
216 registers
.setEDI(addressSpace
.get32(savedRegisters
));
218 case UNWIND_X86_REG_ESI
:
219 registers
.setESI(addressSpace
.get32(savedRegisters
));
221 case UNWIND_X86_REG_EBP
:
222 registers
.setEBP(addressSpace
.get32(savedRegisters
));
225 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
226 "function starting at 0x%X",
227 encoding
, functionStart
);
228 _LIBUNWIND_ABORT("invalid compact unwind encoding");
232 framelessUnwind(addressSpace
, savedRegisters
, registers
);
233 return UNW_STEP_SUCCESS
;
237 template <typename A
>
238 void CompactUnwinder_x86
<A
>::frameUnwind(A
&addressSpace
,
239 Registers_x86
®isters
) {
240 typename
A::pint_t bp
= registers
.getEBP();
241 // ebp points to old ebp
242 registers
.setEBP(addressSpace
.get32(bp
));
243 // old esp is ebp less saved ebp and return address
244 registers
.setSP((uint32_t)bp
+ 8);
245 // pop return address into eip
246 registers
.setIP(addressSpace
.get32(bp
+ 4));
249 template <typename A
>
250 void CompactUnwinder_x86
<A
>::framelessUnwind(
251 A
&addressSpace
, typename
A::pint_t returnAddressLocation
,
252 Registers_x86
®isters
) {
253 // return address is on stack after last saved register
254 registers
.setIP(addressSpace
.get32(returnAddressLocation
));
255 // old esp is before return address
256 registers
.setSP((uint32_t)returnAddressLocation
+ 4);
258 #endif // _LIBUNWIND_TARGET_I386
261 #if defined(_LIBUNWIND_TARGET_X86_64)
262 /// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
263 /// unwind) by modifying a Registers_x86_64 register set
264 template <typename A
>
265 class CompactUnwinder_x86_64
{
268 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding
,
269 uint64_t functionStart
, A
&addressSpace
,
270 Registers_x86_64
®isters
);
273 typename
A::pint_t pint_t
;
275 static void frameUnwind(A
&addressSpace
, Registers_x86_64
®isters
);
276 static void framelessUnwind(A
&addressSpace
, uint64_t returnAddressLocation
,
277 Registers_x86_64
®isters
);
279 stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding
,
280 uint64_t functionStart
, A
&addressSpace
,
281 Registers_x86_64
®isters
);
282 static int stepWithCompactEncodingFrameless(
283 compact_unwind_encoding_t compactEncoding
, uint64_t functionStart
,
284 A
&addressSpace
, Registers_x86_64
®isters
, bool indirectStackSize
);
287 template <typename A
>
288 int CompactUnwinder_x86_64
<A
>::stepWithCompactEncoding(
289 compact_unwind_encoding_t compactEncoding
, uint64_t functionStart
,
290 A
&addressSpace
, Registers_x86_64
®isters
) {
291 switch (compactEncoding
& UNWIND_X86_64_MODE_MASK
) {
292 case UNWIND_X86_64_MODE_RBP_FRAME
:
293 return stepWithCompactEncodingRBPFrame(compactEncoding
, functionStart
,
294 addressSpace
, registers
);
295 case UNWIND_X86_64_MODE_STACK_IMMD
:
296 return stepWithCompactEncodingFrameless(compactEncoding
, functionStart
,
297 addressSpace
, registers
, false);
298 case UNWIND_X86_64_MODE_STACK_IND
:
299 return stepWithCompactEncodingFrameless(compactEncoding
, functionStart
,
300 addressSpace
, registers
, true);
302 _LIBUNWIND_ABORT("invalid compact unwind encoding");
305 template <typename A
>
306 int CompactUnwinder_x86_64
<A
>::stepWithCompactEncodingRBPFrame(
307 compact_unwind_encoding_t compactEncoding
, uint64_t functionStart
,
308 A
&addressSpace
, Registers_x86_64
®isters
) {
309 uint32_t savedRegistersOffset
=
310 EXTRACT_BITS(compactEncoding
, UNWIND_X86_64_RBP_FRAME_OFFSET
);
311 uint32_t savedRegistersLocations
=
312 EXTRACT_BITS(compactEncoding
, UNWIND_X86_64_RBP_FRAME_REGISTERS
);
314 uint64_t savedRegisters
= registers
.getRBP() - 8 * savedRegistersOffset
;
315 for (int i
= 0; i
< 5; ++i
) {
316 switch (savedRegistersLocations
& 0x7) {
317 case UNWIND_X86_64_REG_NONE
:
318 // no register saved in this slot
320 case UNWIND_X86_64_REG_RBX
:
321 registers
.setRBX(addressSpace
.get64(savedRegisters
));
323 case UNWIND_X86_64_REG_R12
:
324 registers
.setR12(addressSpace
.get64(savedRegisters
));
326 case UNWIND_X86_64_REG_R13
:
327 registers
.setR13(addressSpace
.get64(savedRegisters
));
329 case UNWIND_X86_64_REG_R14
:
330 registers
.setR14(addressSpace
.get64(savedRegisters
));
332 case UNWIND_X86_64_REG_R15
:
333 registers
.setR15(addressSpace
.get64(savedRegisters
));
337 _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
338 "function starting at 0x%llX",
339 compactEncoding
, functionStart
);
340 _LIBUNWIND_ABORT("invalid compact unwind encoding");
343 savedRegistersLocations
= (savedRegistersLocations
>> 3);
345 frameUnwind(addressSpace
, registers
);
346 return UNW_STEP_SUCCESS
;
349 template <typename A
>
350 int CompactUnwinder_x86_64
<A
>::stepWithCompactEncodingFrameless(
351 compact_unwind_encoding_t encoding
, uint64_t functionStart
, A
&addressSpace
,
352 Registers_x86_64
®isters
, bool indirectStackSize
) {
353 uint32_t stackSizeEncoded
=
354 EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_SIZE
);
355 uint32_t stackAdjust
=
356 EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_ADJUST
);
358 EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT
);
359 uint32_t permutation
=
360 EXTRACT_BITS(encoding
, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION
);
361 uint32_t stackSize
= stackSizeEncoded
* 8;
362 if (indirectStackSize
) {
363 // stack size is encoded in subl $xxx,%esp instruction
364 uint32_t subl
= addressSpace
.get32(functionStart
+ stackSizeEncoded
);
365 stackSize
= subl
+ 8 * stackAdjust
;
367 // decompress permutation
368 uint32_t permunreg
[6];
371 permunreg
[0] = permutation
/ 120;
372 permutation
-= (permunreg
[0] * 120);
373 permunreg
[1] = permutation
/ 24;
374 permutation
-= (permunreg
[1] * 24);
375 permunreg
[2] = permutation
/ 6;
376 permutation
-= (permunreg
[2] * 6);
377 permunreg
[3] = permutation
/ 2;
378 permutation
-= (permunreg
[3] * 2);
379 permunreg
[4] = permutation
;
383 permunreg
[0] = permutation
/ 120;
384 permutation
-= (permunreg
[0] * 120);
385 permunreg
[1] = permutation
/ 24;
386 permutation
-= (permunreg
[1] * 24);
387 permunreg
[2] = permutation
/ 6;
388 permutation
-= (permunreg
[2] * 6);
389 permunreg
[3] = permutation
/ 2;
390 permutation
-= (permunreg
[3] * 2);
391 permunreg
[4] = permutation
;
394 permunreg
[0] = permutation
/ 60;
395 permutation
-= (permunreg
[0] * 60);
396 permunreg
[1] = permutation
/ 12;
397 permutation
-= (permunreg
[1] * 12);
398 permunreg
[2] = permutation
/ 3;
399 permutation
-= (permunreg
[2] * 3);
400 permunreg
[3] = permutation
;
403 permunreg
[0] = permutation
/ 20;
404 permutation
-= (permunreg
[0] * 20);
405 permunreg
[1] = permutation
/ 4;
406 permutation
-= (permunreg
[1] * 4);
407 permunreg
[2] = permutation
;
410 permunreg
[0] = permutation
/ 5;
411 permutation
-= (permunreg
[0] * 5);
412 permunreg
[1] = permutation
;
415 permunreg
[0] = permutation
;
418 // re-number registers back to standard numbers
419 int registersSaved
[6];
420 bool used
[7] = { false, false, false, false, false, false, false };
421 for (uint32_t i
= 0; i
< regCount
; ++i
) {
423 for (int u
= 1; u
< 7; ++u
) {
425 if (renum
== permunreg
[i
]) {
426 registersSaved
[i
] = u
;
434 uint64_t savedRegisters
= registers
.getSP() + stackSize
- 8 - 8 * regCount
;
435 for (uint32_t i
= 0; i
< regCount
; ++i
) {
436 switch (registersSaved
[i
]) {
437 case UNWIND_X86_64_REG_RBX
:
438 registers
.setRBX(addressSpace
.get64(savedRegisters
));
440 case UNWIND_X86_64_REG_R12
:
441 registers
.setR12(addressSpace
.get64(savedRegisters
));
443 case UNWIND_X86_64_REG_R13
:
444 registers
.setR13(addressSpace
.get64(savedRegisters
));
446 case UNWIND_X86_64_REG_R14
:
447 registers
.setR14(addressSpace
.get64(savedRegisters
));
449 case UNWIND_X86_64_REG_R15
:
450 registers
.setR15(addressSpace
.get64(savedRegisters
));
452 case UNWIND_X86_64_REG_RBP
:
453 registers
.setRBP(addressSpace
.get64(savedRegisters
));
456 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
457 "function starting at 0x%llX",
458 encoding
, functionStart
);
459 _LIBUNWIND_ABORT("invalid compact unwind encoding");
463 framelessUnwind(addressSpace
, savedRegisters
, registers
);
464 return UNW_STEP_SUCCESS
;
468 template <typename A
>
469 void CompactUnwinder_x86_64
<A
>::frameUnwind(A
&addressSpace
,
470 Registers_x86_64
®isters
) {
471 uint64_t rbp
= registers
.getRBP();
472 // ebp points to old ebp
473 registers
.setRBP(addressSpace
.get64(rbp
));
474 // old esp is ebp less saved ebp and return address
475 registers
.setSP(rbp
+ 16);
476 // pop return address into eip
477 registers
.setIP(addressSpace
.get64(rbp
+ 8));
480 template <typename A
>
481 void CompactUnwinder_x86_64
<A
>::framelessUnwind(A
&addressSpace
,
482 uint64_t returnAddressLocation
,
483 Registers_x86_64
®isters
) {
484 // return address is on stack after last saved register
485 registers
.setIP(addressSpace
.get64(returnAddressLocation
));
486 // old esp is before return address
487 registers
.setSP(returnAddressLocation
+ 8);
489 #endif // _LIBUNWIND_TARGET_X86_64
493 #if defined(_LIBUNWIND_TARGET_AARCH64)
494 /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
495 /// unwind) by modifying a Registers_arm64 register set
496 template <typename A
>
497 class CompactUnwinder_arm64
{
500 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding
,
501 uint64_t functionStart
, A
&addressSpace
,
502 Registers_arm64
®isters
);
505 typename
A::pint_t pint_t
;
508 stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding
,
509 uint64_t functionStart
, A
&addressSpace
,
510 Registers_arm64
®isters
);
511 static int stepWithCompactEncodingFrameless(
512 compact_unwind_encoding_t compactEncoding
, uint64_t functionStart
,
513 A
&addressSpace
, Registers_arm64
®isters
);
516 template <typename A
>
517 int CompactUnwinder_arm64
<A
>::stepWithCompactEncoding(
518 compact_unwind_encoding_t compactEncoding
, uint64_t functionStart
,
519 A
&addressSpace
, Registers_arm64
®isters
) {
520 switch (compactEncoding
& UNWIND_ARM64_MODE_MASK
) {
521 case UNWIND_ARM64_MODE_FRAME
:
522 return stepWithCompactEncodingFrame(compactEncoding
, functionStart
,
523 addressSpace
, registers
);
524 case UNWIND_ARM64_MODE_FRAMELESS
:
525 return stepWithCompactEncodingFrameless(compactEncoding
, functionStart
,
526 addressSpace
, registers
);
528 _LIBUNWIND_ABORT("invalid compact unwind encoding");
531 template <typename A
>
532 int CompactUnwinder_arm64
<A
>::stepWithCompactEncodingFrameless(
533 compact_unwind_encoding_t encoding
, uint64_t, A
&addressSpace
,
534 Registers_arm64
®isters
) {
536 16 * EXTRACT_BITS(encoding
, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK
);
538 uint64_t savedRegisterLoc
= registers
.getSP() + stackSize
;
540 if (encoding
& UNWIND_ARM64_FRAME_X19_X20_PAIR
) {
541 registers
.setRegister(UNW_AARCH64_X19
, addressSpace
.get64(savedRegisterLoc
));
542 savedRegisterLoc
-= 8;
543 registers
.setRegister(UNW_AARCH64_X20
, addressSpace
.get64(savedRegisterLoc
));
544 savedRegisterLoc
-= 8;
546 if (encoding
& UNWIND_ARM64_FRAME_X21_X22_PAIR
) {
547 registers
.setRegister(UNW_AARCH64_X21
, addressSpace
.get64(savedRegisterLoc
));
548 savedRegisterLoc
-= 8;
549 registers
.setRegister(UNW_AARCH64_X22
, addressSpace
.get64(savedRegisterLoc
));
550 savedRegisterLoc
-= 8;
552 if (encoding
& UNWIND_ARM64_FRAME_X23_X24_PAIR
) {
553 registers
.setRegister(UNW_AARCH64_X23
, addressSpace
.get64(savedRegisterLoc
));
554 savedRegisterLoc
-= 8;
555 registers
.setRegister(UNW_AARCH64_X24
, addressSpace
.get64(savedRegisterLoc
));
556 savedRegisterLoc
-= 8;
558 if (encoding
& UNWIND_ARM64_FRAME_X25_X26_PAIR
) {
559 registers
.setRegister(UNW_AARCH64_X25
, addressSpace
.get64(savedRegisterLoc
));
560 savedRegisterLoc
-= 8;
561 registers
.setRegister(UNW_AARCH64_X26
, addressSpace
.get64(savedRegisterLoc
));
562 savedRegisterLoc
-= 8;
564 if (encoding
& UNWIND_ARM64_FRAME_X27_X28_PAIR
) {
565 registers
.setRegister(UNW_AARCH64_X27
, addressSpace
.get64(savedRegisterLoc
));
566 savedRegisterLoc
-= 8;
567 registers
.setRegister(UNW_AARCH64_X28
, addressSpace
.get64(savedRegisterLoc
));
568 savedRegisterLoc
-= 8;
571 if (encoding
& UNWIND_ARM64_FRAME_D8_D9_PAIR
) {
572 registers
.setFloatRegister(UNW_AARCH64_V8
,
573 addressSpace
.getDouble(savedRegisterLoc
));
574 savedRegisterLoc
-= 8;
575 registers
.setFloatRegister(UNW_AARCH64_V9
,
576 addressSpace
.getDouble(savedRegisterLoc
));
577 savedRegisterLoc
-= 8;
579 if (encoding
& UNWIND_ARM64_FRAME_D10_D11_PAIR
) {
580 registers
.setFloatRegister(UNW_AARCH64_V10
,
581 addressSpace
.getDouble(savedRegisterLoc
));
582 savedRegisterLoc
-= 8;
583 registers
.setFloatRegister(UNW_AARCH64_V11
,
584 addressSpace
.getDouble(savedRegisterLoc
));
585 savedRegisterLoc
-= 8;
587 if (encoding
& UNWIND_ARM64_FRAME_D12_D13_PAIR
) {
588 registers
.setFloatRegister(UNW_AARCH64_V12
,
589 addressSpace
.getDouble(savedRegisterLoc
));
590 savedRegisterLoc
-= 8;
591 registers
.setFloatRegister(UNW_AARCH64_V13
,
592 addressSpace
.getDouble(savedRegisterLoc
));
593 savedRegisterLoc
-= 8;
595 if (encoding
& UNWIND_ARM64_FRAME_D14_D15_PAIR
) {
596 registers
.setFloatRegister(UNW_AARCH64_V14
,
597 addressSpace
.getDouble(savedRegisterLoc
));
598 savedRegisterLoc
-= 8;
599 registers
.setFloatRegister(UNW_AARCH64_V15
,
600 addressSpace
.getDouble(savedRegisterLoc
));
601 savedRegisterLoc
-= 8;
604 // subtract stack size off of sp
605 registers
.setSP(savedRegisterLoc
);
607 // set pc to be value in lr
608 registers
.setIP(registers
.getRegister(UNW_AARCH64_LR
));
610 return UNW_STEP_SUCCESS
;
613 template <typename A
>
614 int CompactUnwinder_arm64
<A
>::stepWithCompactEncodingFrame(
615 compact_unwind_encoding_t encoding
, uint64_t, A
&addressSpace
,
616 Registers_arm64
®isters
) {
617 uint64_t savedRegisterLoc
= registers
.getFP() - 8;
619 if (encoding
& UNWIND_ARM64_FRAME_X19_X20_PAIR
) {
620 registers
.setRegister(UNW_AARCH64_X19
, addressSpace
.get64(savedRegisterLoc
));
621 savedRegisterLoc
-= 8;
622 registers
.setRegister(UNW_AARCH64_X20
, addressSpace
.get64(savedRegisterLoc
));
623 savedRegisterLoc
-= 8;
625 if (encoding
& UNWIND_ARM64_FRAME_X21_X22_PAIR
) {
626 registers
.setRegister(UNW_AARCH64_X21
, addressSpace
.get64(savedRegisterLoc
));
627 savedRegisterLoc
-= 8;
628 registers
.setRegister(UNW_AARCH64_X22
, addressSpace
.get64(savedRegisterLoc
));
629 savedRegisterLoc
-= 8;
631 if (encoding
& UNWIND_ARM64_FRAME_X23_X24_PAIR
) {
632 registers
.setRegister(UNW_AARCH64_X23
, addressSpace
.get64(savedRegisterLoc
));
633 savedRegisterLoc
-= 8;
634 registers
.setRegister(UNW_AARCH64_X24
, addressSpace
.get64(savedRegisterLoc
));
635 savedRegisterLoc
-= 8;
637 if (encoding
& UNWIND_ARM64_FRAME_X25_X26_PAIR
) {
638 registers
.setRegister(UNW_AARCH64_X25
, addressSpace
.get64(savedRegisterLoc
));
639 savedRegisterLoc
-= 8;
640 registers
.setRegister(UNW_AARCH64_X26
, addressSpace
.get64(savedRegisterLoc
));
641 savedRegisterLoc
-= 8;
643 if (encoding
& UNWIND_ARM64_FRAME_X27_X28_PAIR
) {
644 registers
.setRegister(UNW_AARCH64_X27
, addressSpace
.get64(savedRegisterLoc
));
645 savedRegisterLoc
-= 8;
646 registers
.setRegister(UNW_AARCH64_X28
, addressSpace
.get64(savedRegisterLoc
));
647 savedRegisterLoc
-= 8;
650 if (encoding
& UNWIND_ARM64_FRAME_D8_D9_PAIR
) {
651 registers
.setFloatRegister(UNW_AARCH64_V8
,
652 addressSpace
.getDouble(savedRegisterLoc
));
653 savedRegisterLoc
-= 8;
654 registers
.setFloatRegister(UNW_AARCH64_V9
,
655 addressSpace
.getDouble(savedRegisterLoc
));
656 savedRegisterLoc
-= 8;
658 if (encoding
& UNWIND_ARM64_FRAME_D10_D11_PAIR
) {
659 registers
.setFloatRegister(UNW_AARCH64_V10
,
660 addressSpace
.getDouble(savedRegisterLoc
));
661 savedRegisterLoc
-= 8;
662 registers
.setFloatRegister(UNW_AARCH64_V11
,
663 addressSpace
.getDouble(savedRegisterLoc
));
664 savedRegisterLoc
-= 8;
666 if (encoding
& UNWIND_ARM64_FRAME_D12_D13_PAIR
) {
667 registers
.setFloatRegister(UNW_AARCH64_V12
,
668 addressSpace
.getDouble(savedRegisterLoc
));
669 savedRegisterLoc
-= 8;
670 registers
.setFloatRegister(UNW_AARCH64_V13
,
671 addressSpace
.getDouble(savedRegisterLoc
));
672 savedRegisterLoc
-= 8;
674 if (encoding
& UNWIND_ARM64_FRAME_D14_D15_PAIR
) {
675 registers
.setFloatRegister(UNW_AARCH64_V14
,
676 addressSpace
.getDouble(savedRegisterLoc
));
677 savedRegisterLoc
-= 8;
678 registers
.setFloatRegister(UNW_AARCH64_V15
,
679 addressSpace
.getDouble(savedRegisterLoc
));
680 savedRegisterLoc
-= 8;
683 uint64_t fp
= registers
.getFP();
684 // fp points to old fp
685 registers
.setFP(addressSpace
.get64(fp
));
686 // old sp is fp less saved fp and lr
687 registers
.setSP(fp
+ 16);
688 // pop return address into pc
689 registers
.setIP(addressSpace
.get64(fp
+ 8));
691 return UNW_STEP_SUCCESS
;
693 #endif // _LIBUNWIND_TARGET_AARCH64
696 } // namespace libunwind
698 #endif // __COMPACT_UNWINDER_HPP__