1 //===-------------------------- CompactUnwinder.hpp -----------------------===//
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"
23 #define EXTRACT_BITS(value, mask) \
24 ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
28 #if defined(_LIBUNWIND_TARGET_I386)
29 /// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
30 /// unwind) by modifying a Registers_x86 register set
32 class CompactUnwinder_x86 {
35 static int stepWithCompactEncoding(compact_unwind_encoding_t info,
36 uint32_t functionStart, A &addressSpace,
37 Registers_x86 ®isters);
40 typename A::pint_t pint_t;
42 static void frameUnwind(A &addressSpace, Registers_x86 ®isters);
43 static void framelessUnwind(A &addressSpace,
44 typename A::pint_t returnAddressLocation,
45 Registers_x86 ®isters);
47 stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
48 uint32_t functionStart, A &addressSpace,
49 Registers_x86 ®isters);
50 static int stepWithCompactEncodingFrameless(
51 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
52 A &addressSpace, Registers_x86 ®isters, bool indirectStackSize);
56 int CompactUnwinder_x86<A>::stepWithCompactEncoding(
57 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
58 A &addressSpace, Registers_x86 ®isters) {
59 switch (compactEncoding & UNWIND_X86_MODE_MASK) {
60 case UNWIND_X86_MODE_EBP_FRAME:
61 return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
62 addressSpace, registers);
63 case UNWIND_X86_MODE_STACK_IMMD:
64 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
65 addressSpace, registers, false);
66 case UNWIND_X86_MODE_STACK_IND:
67 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
68 addressSpace, registers, true);
70 _LIBUNWIND_ABORT("invalid compact unwind encoding");
74 int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
75 compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
76 A &addressSpace, Registers_x86 ®isters) {
77 uint32_t savedRegistersOffset =
78 EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
79 uint32_t savedRegistersLocations =
80 EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
82 uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
83 for (int i = 0; i < 5; ++i) {
84 switch (savedRegistersLocations & 0x7) {
85 case UNWIND_X86_REG_NONE:
86 // no register saved in this slot
88 case UNWIND_X86_REG_EBX:
89 registers.setEBX(addressSpace.get32(savedRegisters));
91 case UNWIND_X86_REG_ECX:
92 registers.setECX(addressSpace.get32(savedRegisters));
94 case UNWIND_X86_REG_EDX:
95 registers.setEDX(addressSpace.get32(savedRegisters));
97 case UNWIND_X86_REG_EDI:
98 registers.setEDI(addressSpace.get32(savedRegisters));
100 case UNWIND_X86_REG_ESI:
101 registers.setESI(addressSpace.get32(savedRegisters));
105 _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
106 "function starting at 0x%X",
107 compactEncoding, functionStart);
108 _LIBUNWIND_ABORT("invalid compact unwind encoding");
111 savedRegistersLocations = (savedRegistersLocations >> 3);
113 frameUnwind(addressSpace, registers);
114 return UNW_STEP_SUCCESS;
117 template <typename A>
118 int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
119 compact_unwind_encoding_t encoding, uint32_t functionStart,
120 A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) {
121 uint32_t stackSizeEncoded =
122 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
123 uint32_t stackAdjust =
124 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
126 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
127 uint32_t permutation =
128 EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
129 uint32_t stackSize = stackSizeEncoded * 4;
130 if (indirectStackSize) {
131 // stack size is encoded in subl $xxx,%esp instruction
132 uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
133 stackSize = subl + 4 * stackAdjust;
135 // decompress permutation
136 uint32_t permunreg[6];
139 permunreg[0] = permutation / 120;
140 permutation -= (permunreg[0] * 120);
141 permunreg[1] = permutation / 24;
142 permutation -= (permunreg[1] * 24);
143 permunreg[2] = permutation / 6;
144 permutation -= (permunreg[2] * 6);
145 permunreg[3] = permutation / 2;
146 permutation -= (permunreg[3] * 2);
147 permunreg[4] = permutation;
151 permunreg[0] = permutation / 120;
152 permutation -= (permunreg[0] * 120);
153 permunreg[1] = permutation / 24;
154 permutation -= (permunreg[1] * 24);
155 permunreg[2] = permutation / 6;
156 permutation -= (permunreg[2] * 6);
157 permunreg[3] = permutation / 2;
158 permutation -= (permunreg[3] * 2);
159 permunreg[4] = permutation;
162 permunreg[0] = permutation / 60;
163 permutation -= (permunreg[0] * 60);
164 permunreg[1] = permutation / 12;
165 permutation -= (permunreg[1] * 12);
166 permunreg[2] = permutation / 3;
167 permutation -= (permunreg[2] * 3);
168 permunreg[3] = permutation;
171 permunreg[0] = permutation / 20;
172 permutation -= (permunreg[0] * 20);
173 permunreg[1] = permutation / 4;
174 permutation -= (permunreg[1] * 4);
175 permunreg[2] = permutation;
178 permunreg[0] = permutation / 5;
179 permutation -= (permunreg[0] * 5);
180 permunreg[1] = permutation;
183 permunreg[0] = permutation;
186 // re-number registers back to standard numbers
187 int registersSaved[6];
188 bool used[7] = { false, false, false, false, false, false, false };
189 for (uint32_t i = 0; i < regCount; ++i) {
191 for (int u = 1; u < 7; ++u) {
193 if (renum == permunreg[i]) {
194 registersSaved[i] = u;
202 uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
203 for (uint32_t i = 0; i < regCount; ++i) {
204 switch (registersSaved[i]) {
205 case UNWIND_X86_REG_EBX:
206 registers.setEBX(addressSpace.get32(savedRegisters));
208 case UNWIND_X86_REG_ECX:
209 registers.setECX(addressSpace.get32(savedRegisters));
211 case UNWIND_X86_REG_EDX:
212 registers.setEDX(addressSpace.get32(savedRegisters));
214 case UNWIND_X86_REG_EDI:
215 registers.setEDI(addressSpace.get32(savedRegisters));
217 case UNWIND_X86_REG_ESI:
218 registers.setESI(addressSpace.get32(savedRegisters));
220 case UNWIND_X86_REG_EBP:
221 registers.setEBP(addressSpace.get32(savedRegisters));
224 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
225 "function starting at 0x%X",
226 encoding, functionStart);
227 _LIBUNWIND_ABORT("invalid compact unwind encoding");
231 framelessUnwind(addressSpace, savedRegisters, registers);
232 return UNW_STEP_SUCCESS;
236 template <typename A>
237 void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
238 Registers_x86 ®isters) {
239 typename A::pint_t bp = registers.getEBP();
240 // ebp points to old ebp
241 registers.setEBP(addressSpace.get32(bp));
242 // old esp is ebp less saved ebp and return address
243 registers.setSP((uint32_t)bp + 8);
244 // pop return address into eip
245 registers.setIP(addressSpace.get32(bp + 4));
248 template <typename A>
249 void CompactUnwinder_x86<A>::framelessUnwind(
250 A &addressSpace, typename A::pint_t returnAddressLocation,
251 Registers_x86 ®isters) {
252 // return address is on stack after last saved register
253 registers.setIP(addressSpace.get32(returnAddressLocation));
254 // old esp is before return address
255 registers.setSP((uint32_t)returnAddressLocation + 4);
257 #endif // _LIBUNWIND_TARGET_I386
260 #if defined(_LIBUNWIND_TARGET_X86_64)
261 /// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
262 /// unwind) by modifying a Registers_x86_64 register set
263 template <typename A>
264 class CompactUnwinder_x86_64 {
267 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
268 uint64_t functionStart, A &addressSpace,
269 Registers_x86_64 ®isters);
272 typename A::pint_t pint_t;
274 static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters);
275 static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
276 Registers_x86_64 ®isters);
278 stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
279 uint64_t functionStart, A &addressSpace,
280 Registers_x86_64 ®isters);
281 static int stepWithCompactEncodingFrameless(
282 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
283 A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize);
286 template <typename A>
287 int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
288 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
289 A &addressSpace, Registers_x86_64 ®isters) {
290 switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
291 case UNWIND_X86_64_MODE_RBP_FRAME:
292 return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
293 addressSpace, registers);
294 case UNWIND_X86_64_MODE_STACK_IMMD:
295 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
296 addressSpace, registers, false);
297 case UNWIND_X86_64_MODE_STACK_IND:
298 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
299 addressSpace, registers, true);
301 _LIBUNWIND_ABORT("invalid compact unwind encoding");
304 template <typename A>
305 int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
306 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
307 A &addressSpace, Registers_x86_64 ®isters) {
308 uint32_t savedRegistersOffset =
309 EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
310 uint32_t savedRegistersLocations =
311 EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
313 uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
314 for (int i = 0; i < 5; ++i) {
315 switch (savedRegistersLocations & 0x7) {
316 case UNWIND_X86_64_REG_NONE:
317 // no register saved in this slot
319 case UNWIND_X86_64_REG_RBX:
320 registers.setRBX(addressSpace.get64(savedRegisters));
322 case UNWIND_X86_64_REG_R12:
323 registers.setR12(addressSpace.get64(savedRegisters));
325 case UNWIND_X86_64_REG_R13:
326 registers.setR13(addressSpace.get64(savedRegisters));
328 case UNWIND_X86_64_REG_R14:
329 registers.setR14(addressSpace.get64(savedRegisters));
331 case UNWIND_X86_64_REG_R15:
332 registers.setR15(addressSpace.get64(savedRegisters));
336 _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
337 "function starting at 0x%llX",
338 compactEncoding, functionStart);
339 _LIBUNWIND_ABORT("invalid compact unwind encoding");
342 savedRegistersLocations = (savedRegistersLocations >> 3);
344 frameUnwind(addressSpace, registers);
345 return UNW_STEP_SUCCESS;
348 template <typename A>
349 int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
350 compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
351 Registers_x86_64 ®isters, bool indirectStackSize) {
352 uint32_t stackSizeEncoded =
353 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
354 uint32_t stackAdjust =
355 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
357 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
358 uint32_t permutation =
359 EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
360 uint32_t stackSize = stackSizeEncoded * 8;
361 if (indirectStackSize) {
362 // stack size is encoded in subl $xxx,%esp instruction
363 uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
364 stackSize = subl + 8 * stackAdjust;
366 // decompress permutation
367 uint32_t permunreg[6];
370 permunreg[0] = permutation / 120;
371 permutation -= (permunreg[0] * 120);
372 permunreg[1] = permutation / 24;
373 permutation -= (permunreg[1] * 24);
374 permunreg[2] = permutation / 6;
375 permutation -= (permunreg[2] * 6);
376 permunreg[3] = permutation / 2;
377 permutation -= (permunreg[3] * 2);
378 permunreg[4] = permutation;
382 permunreg[0] = permutation / 120;
383 permutation -= (permunreg[0] * 120);
384 permunreg[1] = permutation / 24;
385 permutation -= (permunreg[1] * 24);
386 permunreg[2] = permutation / 6;
387 permutation -= (permunreg[2] * 6);
388 permunreg[3] = permutation / 2;
389 permutation -= (permunreg[3] * 2);
390 permunreg[4] = permutation;
393 permunreg[0] = permutation / 60;
394 permutation -= (permunreg[0] * 60);
395 permunreg[1] = permutation / 12;
396 permutation -= (permunreg[1] * 12);
397 permunreg[2] = permutation / 3;
398 permutation -= (permunreg[2] * 3);
399 permunreg[3] = permutation;
402 permunreg[0] = permutation / 20;
403 permutation -= (permunreg[0] * 20);
404 permunreg[1] = permutation / 4;
405 permutation -= (permunreg[1] * 4);
406 permunreg[2] = permutation;
409 permunreg[0] = permutation / 5;
410 permutation -= (permunreg[0] * 5);
411 permunreg[1] = permutation;
414 permunreg[0] = permutation;
417 // re-number registers back to standard numbers
418 int registersSaved[6];
419 bool used[7] = { false, false, false, false, false, false, false };
420 for (uint32_t i = 0; i < regCount; ++i) {
422 for (int u = 1; u < 7; ++u) {
424 if (renum == permunreg[i]) {
425 registersSaved[i] = u;
433 uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
434 for (uint32_t i = 0; i < regCount; ++i) {
435 switch (registersSaved[i]) {
436 case UNWIND_X86_64_REG_RBX:
437 registers.setRBX(addressSpace.get64(savedRegisters));
439 case UNWIND_X86_64_REG_R12:
440 registers.setR12(addressSpace.get64(savedRegisters));
442 case UNWIND_X86_64_REG_R13:
443 registers.setR13(addressSpace.get64(savedRegisters));
445 case UNWIND_X86_64_REG_R14:
446 registers.setR14(addressSpace.get64(savedRegisters));
448 case UNWIND_X86_64_REG_R15:
449 registers.setR15(addressSpace.get64(savedRegisters));
451 case UNWIND_X86_64_REG_RBP:
452 registers.setRBP(addressSpace.get64(savedRegisters));
455 _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
456 "function starting at 0x%llX",
457 encoding, functionStart);
458 _LIBUNWIND_ABORT("invalid compact unwind encoding");
462 framelessUnwind(addressSpace, savedRegisters, registers);
463 return UNW_STEP_SUCCESS;
467 template <typename A>
468 void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
469 Registers_x86_64 ®isters) {
470 uint64_t rbp = registers.getRBP();
471 // ebp points to old ebp
472 registers.setRBP(addressSpace.get64(rbp));
473 // old esp is ebp less saved ebp and return address
474 registers.setSP(rbp + 16);
475 // pop return address into eip
476 registers.setIP(addressSpace.get64(rbp + 8));
479 template <typename A>
480 void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
481 uint64_t returnAddressLocation,
482 Registers_x86_64 ®isters) {
483 // return address is on stack after last saved register
484 registers.setIP(addressSpace.get64(returnAddressLocation));
485 // old esp is before return address
486 registers.setSP(returnAddressLocation + 8);
488 #endif // _LIBUNWIND_TARGET_X86_64
492 #if defined(_LIBUNWIND_TARGET_AARCH64)
493 /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
494 /// unwind) by modifying a Registers_arm64 register set
495 template <typename A>
496 class CompactUnwinder_arm64 {
499 static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
500 uint64_t functionStart, A &addressSpace,
501 Registers_arm64 ®isters);
504 typename A::pint_t pint_t;
507 stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
508 uint64_t functionStart, A &addressSpace,
509 Registers_arm64 ®isters);
510 static int stepWithCompactEncodingFrameless(
511 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
512 A &addressSpace, Registers_arm64 ®isters);
515 template <typename A>
516 int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
517 compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
518 A &addressSpace, Registers_arm64 ®isters) {
519 switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
520 case UNWIND_ARM64_MODE_FRAME:
521 return stepWithCompactEncodingFrame(compactEncoding, functionStart,
522 addressSpace, registers);
523 case UNWIND_ARM64_MODE_FRAMELESS:
524 return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
525 addressSpace, registers);
527 _LIBUNWIND_ABORT("invalid compact unwind encoding");
530 template <typename A>
531 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
532 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
533 Registers_arm64 ®isters) {
535 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
537 uint64_t savedRegisterLoc = registers.getSP() + stackSize;
539 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
540 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
541 savedRegisterLoc -= 8;
542 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
543 savedRegisterLoc -= 8;
545 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
546 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
547 savedRegisterLoc -= 8;
548 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
549 savedRegisterLoc -= 8;
551 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
552 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
553 savedRegisterLoc -= 8;
554 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
555 savedRegisterLoc -= 8;
557 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
558 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
559 savedRegisterLoc -= 8;
560 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
561 savedRegisterLoc -= 8;
563 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
564 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
565 savedRegisterLoc -= 8;
566 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
567 savedRegisterLoc -= 8;
570 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
571 registers.setFloatRegister(UNW_ARM64_D8,
572 addressSpace.getDouble(savedRegisterLoc));
573 savedRegisterLoc -= 8;
574 registers.setFloatRegister(UNW_ARM64_D9,
575 addressSpace.getDouble(savedRegisterLoc));
576 savedRegisterLoc -= 8;
578 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
579 registers.setFloatRegister(UNW_ARM64_D10,
580 addressSpace.getDouble(savedRegisterLoc));
581 savedRegisterLoc -= 8;
582 registers.setFloatRegister(UNW_ARM64_D11,
583 addressSpace.getDouble(savedRegisterLoc));
584 savedRegisterLoc -= 8;
586 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
587 registers.setFloatRegister(UNW_ARM64_D12,
588 addressSpace.getDouble(savedRegisterLoc));
589 savedRegisterLoc -= 8;
590 registers.setFloatRegister(UNW_ARM64_D13,
591 addressSpace.getDouble(savedRegisterLoc));
592 savedRegisterLoc -= 8;
594 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
595 registers.setFloatRegister(UNW_ARM64_D14,
596 addressSpace.getDouble(savedRegisterLoc));
597 savedRegisterLoc -= 8;
598 registers.setFloatRegister(UNW_ARM64_D15,
599 addressSpace.getDouble(savedRegisterLoc));
600 savedRegisterLoc -= 8;
603 // subtract stack size off of sp
604 registers.setSP(savedRegisterLoc);
606 // set pc to be value in lr
607 registers.setIP(registers.getRegister(UNW_ARM64_LR));
609 return UNW_STEP_SUCCESS;
612 template <typename A>
613 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
614 compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
615 Registers_arm64 ®isters) {
616 uint64_t savedRegisterLoc = registers.getFP() - 8;
618 if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
619 registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
620 savedRegisterLoc -= 8;
621 registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
622 savedRegisterLoc -= 8;
624 if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
625 registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
626 savedRegisterLoc -= 8;
627 registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
628 savedRegisterLoc -= 8;
630 if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
631 registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
632 savedRegisterLoc -= 8;
633 registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
634 savedRegisterLoc -= 8;
636 if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
637 registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
638 savedRegisterLoc -= 8;
639 registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
640 savedRegisterLoc -= 8;
642 if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
643 registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
644 savedRegisterLoc -= 8;
645 registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
646 savedRegisterLoc -= 8;
649 if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
650 registers.setFloatRegister(UNW_ARM64_D8,
651 addressSpace.getDouble(savedRegisterLoc));
652 savedRegisterLoc -= 8;
653 registers.setFloatRegister(UNW_ARM64_D9,
654 addressSpace.getDouble(savedRegisterLoc));
655 savedRegisterLoc -= 8;
657 if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
658 registers.setFloatRegister(UNW_ARM64_D10,
659 addressSpace.getDouble(savedRegisterLoc));
660 savedRegisterLoc -= 8;
661 registers.setFloatRegister(UNW_ARM64_D11,
662 addressSpace.getDouble(savedRegisterLoc));
663 savedRegisterLoc -= 8;
665 if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
666 registers.setFloatRegister(UNW_ARM64_D12,
667 addressSpace.getDouble(savedRegisterLoc));
668 savedRegisterLoc -= 8;
669 registers.setFloatRegister(UNW_ARM64_D13,
670 addressSpace.getDouble(savedRegisterLoc));
671 savedRegisterLoc -= 8;
673 if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
674 registers.setFloatRegister(UNW_ARM64_D14,
675 addressSpace.getDouble(savedRegisterLoc));
676 savedRegisterLoc -= 8;
677 registers.setFloatRegister(UNW_ARM64_D15,
678 addressSpace.getDouble(savedRegisterLoc));
679 savedRegisterLoc -= 8;
682 uint64_t fp = registers.getFP();
683 // fp points to old fp
684 registers.setFP(addressSpace.get64(fp));
685 // old sp is fp less saved fp and lr
686 registers.setSP(fp + 16);
687 // pop return address into pc
688 registers.setIP(addressSpace.get64(fp + 8));
690 return UNW_STEP_SUCCESS;
692 #endif // _LIBUNWIND_TARGET_AARCH64
695 } // namespace libunwind
697 #endif // __COMPACT_UNWINDER_HPP__