1 //===-------------------------- CompactUnwinder.hpp -----------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
9 // Does runtime stack unwinding using compact unwind encodings.
11 //===----------------------------------------------------------------------===//
13 #ifndef __COMPACT_UNWINDER_HPP__
14 #define __COMPACT_UNWINDER_HPP__
19 #include <libunwind.h>
20 #include <mach-o/compact_unwind_encoding.h>
22 #include "Registers.hpp"
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_ARM64_X19, addressSpace.get64(savedRegisterLoc));
542 savedRegisterLoc -= 8;
543 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
544 savedRegisterLoc -= 8;
546 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
547 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
548 savedRegisterLoc -= 8;
549 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
550 savedRegisterLoc -= 8;
552 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
553 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
554 savedRegisterLoc -= 8;
555 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
556 savedRegisterLoc -= 8;
558 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
559 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
560 savedRegisterLoc -= 8;
561 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
562 savedRegisterLoc -= 8;
564 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
565 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
566 savedRegisterLoc -= 8;
567 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
568 savedRegisterLoc -= 8;
571 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
572 registers.setFloatRegister(UNW_ARM64_D8,
573 addressSpace.getDouble(savedRegisterLoc));
574 savedRegisterLoc -= 8;
575 registers.setFloatRegister(UNW_ARM64_D9,
576 addressSpace.getDouble(savedRegisterLoc));
577 savedRegisterLoc -= 8;
579 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
580 registers.setFloatRegister(UNW_ARM64_D10,
581 addressSpace.getDouble(savedRegisterLoc));
582 savedRegisterLoc -= 8;
583 registers.setFloatRegister(UNW_ARM64_D11,
584 addressSpace.getDouble(savedRegisterLoc));
585 savedRegisterLoc -= 8;
587 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
588 registers.setFloatRegister(UNW_ARM64_D12,
589 addressSpace.getDouble(savedRegisterLoc));
590 savedRegisterLoc -= 8;
591 registers.setFloatRegister(UNW_ARM64_D13,
592 addressSpace.getDouble(savedRegisterLoc));
593 savedRegisterLoc -= 8;
595 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
596 registers.setFloatRegister(UNW_ARM64_D14,
597 addressSpace.getDouble(savedRegisterLoc));
598 savedRegisterLoc -= 8;
599 registers.setFloatRegister(UNW_ARM64_D15,
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_ARM64_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_ARM64_X19, addressSpace.get64(savedRegisterLoc));
621 savedRegisterLoc -= 8;
622 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
623 savedRegisterLoc -= 8;
625 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
626 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
627 savedRegisterLoc -= 8;
628 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
629 savedRegisterLoc -= 8;
631 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
632 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
633 savedRegisterLoc -= 8;
634 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
635 savedRegisterLoc -= 8;
637 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
638 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
639 savedRegisterLoc -= 8;
640 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
641 savedRegisterLoc -= 8;
643 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
644 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
645 savedRegisterLoc -= 8;
646 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
647 savedRegisterLoc -= 8;
650 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
651 registers.setFloatRegister(UNW_ARM64_D8,
652 addressSpace.getDouble(savedRegisterLoc));
653 savedRegisterLoc -= 8;
654 registers.setFloatRegister(UNW_ARM64_D9,
655 addressSpace.getDouble(savedRegisterLoc));
656 savedRegisterLoc -= 8;
658 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
659 registers.setFloatRegister(UNW_ARM64_D10,
660 addressSpace.getDouble(savedRegisterLoc));
661 savedRegisterLoc -= 8;
662 registers.setFloatRegister(UNW_ARM64_D11,
663 addressSpace.getDouble(savedRegisterLoc));
664 savedRegisterLoc -= 8;
666 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
667 registers.setFloatRegister(UNW_ARM64_D12,
668 addressSpace.getDouble(savedRegisterLoc));
669 savedRegisterLoc -= 8;
670 registers.setFloatRegister(UNW_ARM64_D13,
671 addressSpace.getDouble(savedRegisterLoc));
672 savedRegisterLoc -= 8;
674 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
675 registers.setFloatRegister(UNW_ARM64_D14,
676 addressSpace.getDouble(savedRegisterLoc));
677 savedRegisterLoc -= 8;
678 registers.setFloatRegister(UNW_ARM64_D15,
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__