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 "AddressSpace.hpp"
23 #include "Registers.hpp"
25 #define EXTRACT_BITS(value, mask) \
26 ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
30 #if defined(_LIBUNWIND_TARGET_I386)
31 /// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
32 /// unwind) by modifying a Registers_x86 register set
34 class CompactUnwinder_x86 {
37 static int stepWithCompactEncoding(compact_unwind_encoding_t info,
38 uint32_t functionStart, A &addressSpace,
39 Registers_x86 ®isters);
42 typename A::pint_t pint_t;
44 static void frameUnwind(A &addressSpace, Registers_x86 ®isters);
45 static void framelessUnwind(A &addressSpace,
46 typename A::pint_t returnAddressLocation,
47 Registers_x86 ®isters);
49 stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
50 uint32_t functionStart, A &addressSpace,
51 Registers_x86 ®isters);
52 static int stepWithCompactEncodingFrameless(
53 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
54 A &addressSpace, Registers_x86 ®isters, bool indirectStackSize);
58 int CompactUnwinder_x86<A>::stepWithCompactEncoding(
59 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
60 A &addressSpace, Registers_x86 ®isters) {
61 switch (compactEncoding & UNWIND_X86_MODE_MASK) {
62 case UNWIND_X86_MODE_EBP_FRAME:
63 return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
64 addressSpace, registers);
65 case UNWIND_X86_MODE_STACK_IMMD:
66 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
67 addressSpace, registers, false);
68 case UNWIND_X86_MODE_STACK_IND:
69 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
70 addressSpace, registers, true);
72 _LIBUNWIND_ABORT("invalid compact unwind encoding");
76 int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
77 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
78 A &addressSpace, Registers_x86 ®isters) {
79 uint32_t savedRegistersOffset =
80 EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
81 uint32_t savedRegistersLocations =
82 EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
84 uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
85 for (int i = 0; i < 5; ++i) {
86 switch (savedRegistersLocations & 0x7) {
87 case UNWIND_X86_REG_NONE:
88 // no register saved in this slot
90 case UNWIND_X86_REG_EBX:
91 registers.setEBX(addressSpace.get32(savedRegisters));
93 case UNWIND_X86_REG_ECX:
94 registers.setECX(addressSpace.get32(savedRegisters));
96 case UNWIND_X86_REG_EDX:
97 registers.setEDX(addressSpace.get32(savedRegisters));
99 case UNWIND_X86_REG_EDI:
100 registers.setEDI(addressSpace.get32(savedRegisters));
102 case UNWIND_X86_REG_ESI:
103 registers.setESI(addressSpace.get32(savedRegisters));
107 _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
108 "function starting at 0x%X\n",
109 compactEncoding, functionStart);
110 _LIBUNWIND_ABORT("invalid compact unwind encoding");
113 savedRegistersLocations = (savedRegistersLocations >> 3);
115 frameUnwind(addressSpace, registers);
116 return UNW_STEP_SUCCESS;
119 template <typename A>
120 int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
121 compact_unwind_encoding_t encoding, uint32_t functionStart,
122 A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) {
123 uint32_t stackSizeEncoded =
124 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
125 uint32_t stackAdjust =
126 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
128 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
129 uint32_t permutation =
130 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
131 uint32_t stackSize = stackSizeEncoded * 4;
132 if (indirectStackSize) {
133 // stack size is encoded in subl $xxx,%esp instruction
134 uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
135 stackSize = subl + 4 * stackAdjust;
137 // decompress permutation
138 uint32_t permunreg[6];
141 permunreg[0] = permutation / 120;
142 permutation -= (permunreg[0] * 120);
143 permunreg[1] = permutation / 24;
144 permutation -= (permunreg[1] * 24);
145 permunreg[2] = permutation / 6;
146 permutation -= (permunreg[2] * 6);
147 permunreg[3] = permutation / 2;
148 permutation -= (permunreg[3] * 2);
149 permunreg[4] = permutation;
153 permunreg[0] = permutation / 120;
154 permutation -= (permunreg[0] * 120);
155 permunreg[1] = permutation / 24;
156 permutation -= (permunreg[1] * 24);
157 permunreg[2] = permutation / 6;
158 permutation -= (permunreg[2] * 6);
159 permunreg[3] = permutation / 2;
160 permutation -= (permunreg[3] * 2);
161 permunreg[4] = permutation;
164 permunreg[0] = permutation / 60;
165 permutation -= (permunreg[0] * 60);
166 permunreg[1] = permutation / 12;
167 permutation -= (permunreg[1] * 12);
168 permunreg[2] = permutation / 3;
169 permutation -= (permunreg[2] * 3);
170 permunreg[3] = permutation;
173 permunreg[0] = permutation / 20;
174 permutation -= (permunreg[0] * 20);
175 permunreg[1] = permutation / 4;
176 permutation -= (permunreg[1] * 4);
177 permunreg[2] = permutation;
180 permunreg[0] = permutation / 5;
181 permutation -= (permunreg[0] * 5);
182 permunreg[1] = permutation;
185 permunreg[0] = permutation;
188 // re-number registers back to standard numbers
189 int registersSaved[6];
190 bool used[7] = { false, false, false, false, false, false, false };
191 for (uint32_t i = 0; i < regCount; ++i) {
193 for (int u = 1; u < 7; ++u) {
195 if (renum == permunreg[i]) {
196 registersSaved[i] = u;
204 uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
205 for (uint32_t i = 0; i < regCount; ++i) {
206 switch (registersSaved[i]) {
207 case UNWIND_X86_REG_EBX:
208 registers.setEBX(addressSpace.get32(savedRegisters));
210 case UNWIND_X86_REG_ECX:
211 registers.setECX(addressSpace.get32(savedRegisters));
213 case UNWIND_X86_REG_EDX:
214 registers.setEDX(addressSpace.get32(savedRegisters));
216 case UNWIND_X86_REG_EDI:
217 registers.setEDI(addressSpace.get32(savedRegisters));
219 case UNWIND_X86_REG_ESI:
220 registers.setESI(addressSpace.get32(savedRegisters));
222 case UNWIND_X86_REG_EBP:
223 registers.setEBP(addressSpace.get32(savedRegisters));
226 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
227 "function starting at 0x%X\n",
228 encoding, functionStart);
229 _LIBUNWIND_ABORT("invalid compact unwind encoding");
233 framelessUnwind(addressSpace, savedRegisters, registers);
234 return UNW_STEP_SUCCESS;
238 template <typename A>
239 void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
240 Registers_x86 ®isters) {
241 typename A::pint_t bp = registers.getEBP();
242 // ebp points to old ebp
243 registers.setEBP(addressSpace.get32(bp));
244 // old esp is ebp less saved ebp and return address
245 registers.setSP((uint32_t)bp + 8);
246 // pop return address into eip
247 registers.setIP(addressSpace.get32(bp + 4));
250 template <typename A>
251 void CompactUnwinder_x86<A>::framelessUnwind(
252 A &addressSpace, typename A::pint_t returnAddressLocation,
253 Registers_x86 ®isters) {
254 // return address is on stack after last saved register
255 registers.setIP(addressSpace.get32(returnAddressLocation));
256 // old esp is before return address
257 registers.setSP((uint32_t)returnAddressLocation + 4);
259 #endif // _LIBUNWIND_TARGET_I386
262 #if defined(_LIBUNWIND_TARGET_X86_64)
263 /// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
264 /// unwind) by modifying a Registers_x86_64 register set
265 template <typename A>
266 class CompactUnwinder_x86_64 {
269 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
270 uint64_t functionStart, A &addressSpace,
271 Registers_x86_64 ®isters);
274 typename A::pint_t pint_t;
276 static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters);
277 static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
278 Registers_x86_64 ®isters);
280 stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
281 uint64_t functionStart, A &addressSpace,
282 Registers_x86_64 ®isters);
283 static int stepWithCompactEncodingFrameless(
284 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
285 A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize);
288 template <typename A>
289 int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
290 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
291 A &addressSpace, Registers_x86_64 ®isters) {
292 switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
293 case UNWIND_X86_64_MODE_RBP_FRAME:
294 return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
295 addressSpace, registers);
296 case UNWIND_X86_64_MODE_STACK_IMMD:
297 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
298 addressSpace, registers, false);
299 case UNWIND_X86_64_MODE_STACK_IND:
300 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
301 addressSpace, registers, true);
303 _LIBUNWIND_ABORT("invalid compact unwind encoding");
306 template <typename A>
307 int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
308 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
309 A &addressSpace, Registers_x86_64 ®isters) {
310 uint32_t savedRegistersOffset =
311 EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
312 uint32_t savedRegistersLocations =
313 EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
315 uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
316 for (int i = 0; i < 5; ++i) {
317 switch (savedRegistersLocations & 0x7) {
318 case UNWIND_X86_64_REG_NONE:
319 // no register saved in this slot
321 case UNWIND_X86_64_REG_RBX:
322 registers.setRBX(addressSpace.get64(savedRegisters));
324 case UNWIND_X86_64_REG_R12:
325 registers.setR12(addressSpace.get64(savedRegisters));
327 case UNWIND_X86_64_REG_R13:
328 registers.setR13(addressSpace.get64(savedRegisters));
330 case UNWIND_X86_64_REG_R14:
331 registers.setR14(addressSpace.get64(savedRegisters));
333 case UNWIND_X86_64_REG_R15:
334 registers.setR15(addressSpace.get64(savedRegisters));
338 _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
339 "function starting at 0x%llX\n",
340 compactEncoding, functionStart);
341 _LIBUNWIND_ABORT("invalid compact unwind encoding");
344 savedRegistersLocations = (savedRegistersLocations >> 3);
346 frameUnwind(addressSpace, registers);
347 return UNW_STEP_SUCCESS;
350 template <typename A>
351 int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
352 compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
353 Registers_x86_64 ®isters, bool indirectStackSize) {
354 uint32_t stackSizeEncoded =
355 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
356 uint32_t stackAdjust =
357 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
359 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
360 uint32_t permutation =
361 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
362 uint32_t stackSize = stackSizeEncoded * 8;
363 if (indirectStackSize) {
364 // stack size is encoded in subl $xxx,%esp instruction
365 uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
366 stackSize = subl + 8 * stackAdjust;
368 // decompress permutation
369 uint32_t permunreg[6];
372 permunreg[0] = permutation / 120;
373 permutation -= (permunreg[0] * 120);
374 permunreg[1] = permutation / 24;
375 permutation -= (permunreg[1] * 24);
376 permunreg[2] = permutation / 6;
377 permutation -= (permunreg[2] * 6);
378 permunreg[3] = permutation / 2;
379 permutation -= (permunreg[3] * 2);
380 permunreg[4] = permutation;
384 permunreg[0] = permutation / 120;
385 permutation -= (permunreg[0] * 120);
386 permunreg[1] = permutation / 24;
387 permutation -= (permunreg[1] * 24);
388 permunreg[2] = permutation / 6;
389 permutation -= (permunreg[2] * 6);
390 permunreg[3] = permutation / 2;
391 permutation -= (permunreg[3] * 2);
392 permunreg[4] = permutation;
395 permunreg[0] = permutation / 60;
396 permutation -= (permunreg[0] * 60);
397 permunreg[1] = permutation / 12;
398 permutation -= (permunreg[1] * 12);
399 permunreg[2] = permutation / 3;
400 permutation -= (permunreg[2] * 3);
401 permunreg[3] = permutation;
404 permunreg[0] = permutation / 20;
405 permutation -= (permunreg[0] * 20);
406 permunreg[1] = permutation / 4;
407 permutation -= (permunreg[1] * 4);
408 permunreg[2] = permutation;
411 permunreg[0] = permutation / 5;
412 permutation -= (permunreg[0] * 5);
413 permunreg[1] = permutation;
416 permunreg[0] = permutation;
419 // re-number registers back to standard numbers
420 int registersSaved[6];
421 bool used[7] = { false, false, false, false, false, false, false };
422 for (uint32_t i = 0; i < regCount; ++i) {
424 for (int u = 1; u < 7; ++u) {
426 if (renum == permunreg[i]) {
427 registersSaved[i] = u;
435 uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
436 for (uint32_t i = 0; i < regCount; ++i) {
437 switch (registersSaved[i]) {
438 case UNWIND_X86_64_REG_RBX:
439 registers.setRBX(addressSpace.get64(savedRegisters));
441 case UNWIND_X86_64_REG_R12:
442 registers.setR12(addressSpace.get64(savedRegisters));
444 case UNWIND_X86_64_REG_R13:
445 registers.setR13(addressSpace.get64(savedRegisters));
447 case UNWIND_X86_64_REG_R14:
448 registers.setR14(addressSpace.get64(savedRegisters));
450 case UNWIND_X86_64_REG_R15:
451 registers.setR15(addressSpace.get64(savedRegisters));
453 case UNWIND_X86_64_REG_RBP:
454 registers.setRBP(addressSpace.get64(savedRegisters));
457 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
458 "function starting at 0x%llX\n",
459 encoding, functionStart);
460 _LIBUNWIND_ABORT("invalid compact unwind encoding");
464 framelessUnwind(addressSpace, savedRegisters, registers);
465 return UNW_STEP_SUCCESS;
469 template <typename A>
470 void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
471 Registers_x86_64 ®isters) {
472 uint64_t rbp = registers.getRBP();
473 // ebp points to old ebp
474 registers.setRBP(addressSpace.get64(rbp));
475 // old esp is ebp less saved ebp and return address
476 registers.setSP(rbp + 16);
477 // pop return address into eip
478 registers.setIP(addressSpace.get64(rbp + 8));
481 template <typename A>
482 void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
483 uint64_t returnAddressLocation,
484 Registers_x86_64 ®isters) {
485 // return address is on stack after last saved register
486 registers.setIP(addressSpace.get64(returnAddressLocation));
487 // old esp is before return address
488 registers.setSP(returnAddressLocation + 8);
490 #endif // _LIBUNWIND_TARGET_X86_64
494 #if defined(_LIBUNWIND_TARGET_AARCH64)
495 /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
496 /// unwind) by modifying a Registers_arm64 register set
497 template <typename A>
498 class CompactUnwinder_arm64 {
501 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
502 uint64_t functionStart, A &addressSpace,
503 Registers_arm64 ®isters);
506 typename A::pint_t pint_t;
509 stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
510 uint64_t functionStart, A &addressSpace,
511 Registers_arm64 ®isters);
512 static int stepWithCompactEncodingFrameless(
513 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
514 A &addressSpace, Registers_arm64 ®isters);
517 template <typename A>
518 int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
519 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
520 A &addressSpace, Registers_arm64 ®isters) {
521 switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
522 case UNWIND_ARM64_MODE_FRAME:
523 return stepWithCompactEncodingFrame(compactEncoding, functionStart,
524 addressSpace, registers);
525 case UNWIND_ARM64_MODE_FRAMELESS:
526 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
527 addressSpace, registers);
529 _LIBUNWIND_ABORT("invalid compact unwind encoding");
532 template <typename A>
533 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
534 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
535 Registers_arm64 ®isters) {
537 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
539 uint64_t savedRegisterLoc = registers.getSP() + stackSize;
541 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
542 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
543 savedRegisterLoc -= 8;
544 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
545 savedRegisterLoc -= 8;
547 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
548 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
549 savedRegisterLoc -= 8;
550 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
551 savedRegisterLoc -= 8;
553 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
554 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
555 savedRegisterLoc -= 8;
556 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
557 savedRegisterLoc -= 8;
559 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
560 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
561 savedRegisterLoc -= 8;
562 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
563 savedRegisterLoc -= 8;
565 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
566 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
567 savedRegisterLoc -= 8;
568 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
569 savedRegisterLoc -= 8;
572 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
573 registers.setFloatRegister(UNW_ARM64_D8,
574 addressSpace.getDouble(savedRegisterLoc));
575 savedRegisterLoc -= 8;
576 registers.setFloatRegister(UNW_ARM64_D9,
577 addressSpace.getDouble(savedRegisterLoc));
578 savedRegisterLoc -= 8;
580 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
581 registers.setFloatRegister(UNW_ARM64_D10,
582 addressSpace.getDouble(savedRegisterLoc));
583 savedRegisterLoc -= 8;
584 registers.setFloatRegister(UNW_ARM64_D11,
585 addressSpace.getDouble(savedRegisterLoc));
586 savedRegisterLoc -= 8;
588 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
589 registers.setFloatRegister(UNW_ARM64_D12,
590 addressSpace.getDouble(savedRegisterLoc));
591 savedRegisterLoc -= 8;
592 registers.setFloatRegister(UNW_ARM64_D13,
593 addressSpace.getDouble(savedRegisterLoc));
594 savedRegisterLoc -= 8;
596 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
597 registers.setFloatRegister(UNW_ARM64_D14,
598 addressSpace.getDouble(savedRegisterLoc));
599 savedRegisterLoc -= 8;
600 registers.setFloatRegister(UNW_ARM64_D15,
601 addressSpace.getDouble(savedRegisterLoc));
602 savedRegisterLoc -= 8;
605 // subtract stack size off of sp
606 registers.setSP(savedRegisterLoc);
608 // set pc to be value in lr
609 registers.setIP(registers.getRegister(UNW_ARM64_LR));
611 return UNW_STEP_SUCCESS;
614 template <typename A>
615 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
616 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
617 Registers_arm64 ®isters) {
618 uint64_t savedRegisterLoc = registers.getFP() - 8;
620 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
621 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
622 savedRegisterLoc -= 8;
623 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
624 savedRegisterLoc -= 8;
626 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
627 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
628 savedRegisterLoc -= 8;
629 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
630 savedRegisterLoc -= 8;
632 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
633 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
634 savedRegisterLoc -= 8;
635 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
636 savedRegisterLoc -= 8;
638 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
639 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
640 savedRegisterLoc -= 8;
641 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
642 savedRegisterLoc -= 8;
644 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
645 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
646 savedRegisterLoc -= 8;
647 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
648 savedRegisterLoc -= 8;
651 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
652 registers.setFloatRegister(UNW_ARM64_D8,
653 addressSpace.getDouble(savedRegisterLoc));
654 savedRegisterLoc -= 8;
655 registers.setFloatRegister(UNW_ARM64_D9,
656 addressSpace.getDouble(savedRegisterLoc));
657 savedRegisterLoc -= 8;
659 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
660 registers.setFloatRegister(UNW_ARM64_D10,
661 addressSpace.getDouble(savedRegisterLoc));
662 savedRegisterLoc -= 8;
663 registers.setFloatRegister(UNW_ARM64_D11,
664 addressSpace.getDouble(savedRegisterLoc));
665 savedRegisterLoc -= 8;
667 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
668 registers.setFloatRegister(UNW_ARM64_D12,
669 addressSpace.getDouble(savedRegisterLoc));
670 savedRegisterLoc -= 8;
671 registers.setFloatRegister(UNW_ARM64_D13,
672 addressSpace.getDouble(savedRegisterLoc));
673 savedRegisterLoc -= 8;
675 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
676 registers.setFloatRegister(UNW_ARM64_D14,
677 addressSpace.getDouble(savedRegisterLoc));
678 savedRegisterLoc -= 8;
679 registers.setFloatRegister(UNW_ARM64_D15,
680 addressSpace.getDouble(savedRegisterLoc));
681 savedRegisterLoc -= 8;
684 uint64_t fp = registers.getFP();
685 // fp points to old fp
686 registers.setFP(addressSpace.get64(fp));
687 // old sp is fp less saved fp and lr
688 registers.setSP(fp + 16);
689 // pop return address into pc
690 registers.setIP(addressSpace.get64(fp + 8));
692 return UNW_STEP_SUCCESS;
694 #endif // _LIBUNWIND_TARGET_AARCH64
697 } // namespace libunwind
699 #endif // __COMPACT_UNWINDER_HPP__