xref: /openbsd-src/gnu/llvm/libunwind/src/CompactUnwinder.hpp (revision 0faf1914bfa030ea6c1d961758e08514a79ff73a)
1*0faf1914Srobert //===----------------------------------------------------------------------===//
2f6c50668Spatrick //
3f6c50668Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f6c50668Spatrick // See https://llvm.org/LICENSE.txt for license information.
5f6c50668Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f6c50668Spatrick //
7f6c50668Spatrick //
8f6c50668Spatrick //  Does runtime stack unwinding using compact unwind encodings.
9f6c50668Spatrick //
10f6c50668Spatrick //===----------------------------------------------------------------------===//
11f6c50668Spatrick 
12f6c50668Spatrick #ifndef __COMPACT_UNWINDER_HPP__
13f6c50668Spatrick #define __COMPACT_UNWINDER_HPP__
14f6c50668Spatrick 
15f6c50668Spatrick #include <stdint.h>
16f6c50668Spatrick #include <stdlib.h>
17f6c50668Spatrick 
18f6c50668Spatrick #include <libunwind.h>
19f6c50668Spatrick #include <mach-o/compact_unwind_encoding.h>
20f6c50668Spatrick 
21f6c50668Spatrick #include "Registers.hpp"
22*0faf1914Srobert #include "libunwind_ext.h"
23f6c50668Spatrick 
24f6c50668Spatrick #define EXTRACT_BITS(value, mask)                                              \
25f6c50668Spatrick   ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
26f6c50668Spatrick 
27f6c50668Spatrick namespace libunwind {
28f6c50668Spatrick 
29f6c50668Spatrick #if defined(_LIBUNWIND_TARGET_I386)
30f6c50668Spatrick /// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
31f6c50668Spatrick /// unwind) by modifying a Registers_x86 register set
32f6c50668Spatrick template <typename A>
33f6c50668Spatrick class CompactUnwinder_x86 {
34f6c50668Spatrick public:
35f6c50668Spatrick 
36f6c50668Spatrick   static int stepWithCompactEncoding(compact_unwind_encoding_t info,
37f6c50668Spatrick                                      uint32_t functionStart, A &addressSpace,
38f6c50668Spatrick                                      Registers_x86 &registers);
39f6c50668Spatrick 
40f6c50668Spatrick private:
41f6c50668Spatrick   typename A::pint_t pint_t;
42f6c50668Spatrick 
43f6c50668Spatrick   static void frameUnwind(A &addressSpace, Registers_x86 &registers);
44f6c50668Spatrick   static void framelessUnwind(A &addressSpace,
45f6c50668Spatrick                               typename A::pint_t returnAddressLocation,
46f6c50668Spatrick                               Registers_x86 &registers);
47f6c50668Spatrick   static int
48f6c50668Spatrick       stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
49f6c50668Spatrick                                       uint32_t functionStart, A &addressSpace,
50f6c50668Spatrick                                       Registers_x86 &registers);
51f6c50668Spatrick   static int stepWithCompactEncodingFrameless(
52f6c50668Spatrick       compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
53f6c50668Spatrick       A &addressSpace, Registers_x86 &registers, bool indirectStackSize);
54f6c50668Spatrick };
55f6c50668Spatrick 
56f6c50668Spatrick template <typename A>
stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,uint32_t functionStart,A & addressSpace,Registers_x86 & registers)57f6c50668Spatrick int CompactUnwinder_x86<A>::stepWithCompactEncoding(
58f6c50668Spatrick     compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
59f6c50668Spatrick     A &addressSpace, Registers_x86 &registers) {
60f6c50668Spatrick   switch (compactEncoding & UNWIND_X86_MODE_MASK) {
61f6c50668Spatrick   case UNWIND_X86_MODE_EBP_FRAME:
62f6c50668Spatrick     return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
63f6c50668Spatrick                                            addressSpace, registers);
64f6c50668Spatrick   case UNWIND_X86_MODE_STACK_IMMD:
65f6c50668Spatrick     return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
66f6c50668Spatrick                                             addressSpace, registers, false);
67f6c50668Spatrick   case UNWIND_X86_MODE_STACK_IND:
68f6c50668Spatrick     return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
69f6c50668Spatrick                                             addressSpace, registers, true);
70f6c50668Spatrick   }
71f6c50668Spatrick   _LIBUNWIND_ABORT("invalid compact unwind encoding");
72f6c50668Spatrick }
73f6c50668Spatrick 
74f6c50668Spatrick template <typename A>
stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,uint32_t functionStart,A & addressSpace,Registers_x86 & registers)75f6c50668Spatrick int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
76f6c50668Spatrick     compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
77f6c50668Spatrick     A &addressSpace, Registers_x86 &registers) {
78f6c50668Spatrick   uint32_t savedRegistersOffset =
79f6c50668Spatrick       EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
80f6c50668Spatrick   uint32_t savedRegistersLocations =
81f6c50668Spatrick       EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
82f6c50668Spatrick 
83f6c50668Spatrick   uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
84f6c50668Spatrick   for (int i = 0; i < 5; ++i) {
85f6c50668Spatrick     switch (savedRegistersLocations & 0x7) {
86f6c50668Spatrick     case UNWIND_X86_REG_NONE:
87f6c50668Spatrick       // no register saved in this slot
88f6c50668Spatrick       break;
89f6c50668Spatrick     case UNWIND_X86_REG_EBX:
90f6c50668Spatrick       registers.setEBX(addressSpace.get32(savedRegisters));
91f6c50668Spatrick       break;
92f6c50668Spatrick     case UNWIND_X86_REG_ECX:
93f6c50668Spatrick       registers.setECX(addressSpace.get32(savedRegisters));
94f6c50668Spatrick       break;
95f6c50668Spatrick     case UNWIND_X86_REG_EDX:
96f6c50668Spatrick       registers.setEDX(addressSpace.get32(savedRegisters));
97f6c50668Spatrick       break;
98f6c50668Spatrick     case UNWIND_X86_REG_EDI:
99f6c50668Spatrick       registers.setEDI(addressSpace.get32(savedRegisters));
100f6c50668Spatrick       break;
101f6c50668Spatrick     case UNWIND_X86_REG_ESI:
102f6c50668Spatrick       registers.setESI(addressSpace.get32(savedRegisters));
103f6c50668Spatrick       break;
104f6c50668Spatrick     default:
105f6c50668Spatrick       (void)functionStart;
106f6c50668Spatrick       _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for  "
107f6c50668Spatrick                            "function starting at 0x%X",
108f6c50668Spatrick                             compactEncoding, functionStart);
109f6c50668Spatrick       _LIBUNWIND_ABORT("invalid compact unwind encoding");
110f6c50668Spatrick     }
111f6c50668Spatrick     savedRegisters += 4;
112f6c50668Spatrick     savedRegistersLocations = (savedRegistersLocations >> 3);
113f6c50668Spatrick   }
114f6c50668Spatrick   frameUnwind(addressSpace, registers);
115f6c50668Spatrick   return UNW_STEP_SUCCESS;
116f6c50668Spatrick }
117f6c50668Spatrick 
118f6c50668Spatrick template <typename A>
stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding,uint32_t functionStart,A & addressSpace,Registers_x86 & registers,bool indirectStackSize)119f6c50668Spatrick int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
120f6c50668Spatrick     compact_unwind_encoding_t encoding, uint32_t functionStart,
121f6c50668Spatrick     A &addressSpace, Registers_x86 &registers, bool indirectStackSize) {
122f6c50668Spatrick   uint32_t stackSizeEncoded =
123f6c50668Spatrick       EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
124f6c50668Spatrick   uint32_t stackAdjust =
125f6c50668Spatrick       EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
126f6c50668Spatrick   uint32_t regCount =
127f6c50668Spatrick       EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
128f6c50668Spatrick   uint32_t permutation =
129f6c50668Spatrick       EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
130f6c50668Spatrick   uint32_t stackSize = stackSizeEncoded * 4;
131f6c50668Spatrick   if (indirectStackSize) {
132f6c50668Spatrick     // stack size is encoded in subl $xxx,%esp instruction
133f6c50668Spatrick     uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
134f6c50668Spatrick     stackSize = subl + 4 * stackAdjust;
135f6c50668Spatrick   }
136f6c50668Spatrick   // decompress permutation
137f6c50668Spatrick   uint32_t permunreg[6];
138f6c50668Spatrick   switch (regCount) {
139f6c50668Spatrick   case 6:
140f6c50668Spatrick     permunreg[0] = permutation / 120;
141f6c50668Spatrick     permutation -= (permunreg[0] * 120);
142f6c50668Spatrick     permunreg[1] = permutation / 24;
143f6c50668Spatrick     permutation -= (permunreg[1] * 24);
144f6c50668Spatrick     permunreg[2] = permutation / 6;
145f6c50668Spatrick     permutation -= (permunreg[2] * 6);
146f6c50668Spatrick     permunreg[3] = permutation / 2;
147f6c50668Spatrick     permutation -= (permunreg[3] * 2);
148f6c50668Spatrick     permunreg[4] = permutation;
149f6c50668Spatrick     permunreg[5] = 0;
150f6c50668Spatrick     break;
151f6c50668Spatrick   case 5:
152f6c50668Spatrick     permunreg[0] = permutation / 120;
153f6c50668Spatrick     permutation -= (permunreg[0] * 120);
154f6c50668Spatrick     permunreg[1] = permutation / 24;
155f6c50668Spatrick     permutation -= (permunreg[1] * 24);
156f6c50668Spatrick     permunreg[2] = permutation / 6;
157f6c50668Spatrick     permutation -= (permunreg[2] * 6);
158f6c50668Spatrick     permunreg[3] = permutation / 2;
159f6c50668Spatrick     permutation -= (permunreg[3] * 2);
160f6c50668Spatrick     permunreg[4] = permutation;
161f6c50668Spatrick     break;
162f6c50668Spatrick   case 4:
163f6c50668Spatrick     permunreg[0] = permutation / 60;
164f6c50668Spatrick     permutation -= (permunreg[0] * 60);
165f6c50668Spatrick     permunreg[1] = permutation / 12;
166f6c50668Spatrick     permutation -= (permunreg[1] * 12);
167f6c50668Spatrick     permunreg[2] = permutation / 3;
168f6c50668Spatrick     permutation -= (permunreg[2] * 3);
169f6c50668Spatrick     permunreg[3] = permutation;
170f6c50668Spatrick     break;
171f6c50668Spatrick   case 3:
172f6c50668Spatrick     permunreg[0] = permutation / 20;
173f6c50668Spatrick     permutation -= (permunreg[0] * 20);
174f6c50668Spatrick     permunreg[1] = permutation / 4;
175f6c50668Spatrick     permutation -= (permunreg[1] * 4);
176f6c50668Spatrick     permunreg[2] = permutation;
177f6c50668Spatrick     break;
178f6c50668Spatrick   case 2:
179f6c50668Spatrick     permunreg[0] = permutation / 5;
180f6c50668Spatrick     permutation -= (permunreg[0] * 5);
181f6c50668Spatrick     permunreg[1] = permutation;
182f6c50668Spatrick     break;
183f6c50668Spatrick   case 1:
184f6c50668Spatrick     permunreg[0] = permutation;
185f6c50668Spatrick     break;
186f6c50668Spatrick   }
187f6c50668Spatrick   // re-number registers back to standard numbers
188f6c50668Spatrick   int registersSaved[6];
189f6c50668Spatrick   bool used[7] = { false, false, false, false, false, false, false };
190f6c50668Spatrick   for (uint32_t i = 0; i < regCount; ++i) {
191f6c50668Spatrick     uint32_t renum = 0;
192f6c50668Spatrick     for (int u = 1; u < 7; ++u) {
193f6c50668Spatrick       if (!used[u]) {
194f6c50668Spatrick         if (renum == permunreg[i]) {
195f6c50668Spatrick           registersSaved[i] = u;
196f6c50668Spatrick           used[u] = true;
197f6c50668Spatrick           break;
198f6c50668Spatrick         }
199f6c50668Spatrick         ++renum;
200f6c50668Spatrick       }
201f6c50668Spatrick     }
202f6c50668Spatrick   }
203f6c50668Spatrick   uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
204f6c50668Spatrick   for (uint32_t i = 0; i < regCount; ++i) {
205f6c50668Spatrick     switch (registersSaved[i]) {
206f6c50668Spatrick     case UNWIND_X86_REG_EBX:
207f6c50668Spatrick       registers.setEBX(addressSpace.get32(savedRegisters));
208f6c50668Spatrick       break;
209f6c50668Spatrick     case UNWIND_X86_REG_ECX:
210f6c50668Spatrick       registers.setECX(addressSpace.get32(savedRegisters));
211f6c50668Spatrick       break;
212f6c50668Spatrick     case UNWIND_X86_REG_EDX:
213f6c50668Spatrick       registers.setEDX(addressSpace.get32(savedRegisters));
214f6c50668Spatrick       break;
215f6c50668Spatrick     case UNWIND_X86_REG_EDI:
216f6c50668Spatrick       registers.setEDI(addressSpace.get32(savedRegisters));
217f6c50668Spatrick       break;
218f6c50668Spatrick     case UNWIND_X86_REG_ESI:
219f6c50668Spatrick       registers.setESI(addressSpace.get32(savedRegisters));
220f6c50668Spatrick       break;
221f6c50668Spatrick     case UNWIND_X86_REG_EBP:
222f6c50668Spatrick       registers.setEBP(addressSpace.get32(savedRegisters));
223f6c50668Spatrick       break;
224f6c50668Spatrick     default:
225f6c50668Spatrick       _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
226f6c50668Spatrick                            "function starting at 0x%X",
227f6c50668Spatrick                            encoding, functionStart);
228f6c50668Spatrick       _LIBUNWIND_ABORT("invalid compact unwind encoding");
229f6c50668Spatrick     }
230f6c50668Spatrick     savedRegisters += 4;
231f6c50668Spatrick   }
232f6c50668Spatrick   framelessUnwind(addressSpace, savedRegisters, registers);
233f6c50668Spatrick   return UNW_STEP_SUCCESS;
234f6c50668Spatrick }
235f6c50668Spatrick 
236f6c50668Spatrick 
237f6c50668Spatrick template <typename A>
frameUnwind(A & addressSpace,Registers_x86 & registers)238f6c50668Spatrick void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
239f6c50668Spatrick                                          Registers_x86 &registers) {
240f6c50668Spatrick   typename A::pint_t bp = registers.getEBP();
241f6c50668Spatrick   // ebp points to old ebp
242f6c50668Spatrick   registers.setEBP(addressSpace.get32(bp));
243f6c50668Spatrick   // old esp is ebp less saved ebp and return address
244f6c50668Spatrick   registers.setSP((uint32_t)bp + 8);
245f6c50668Spatrick   // pop return address into eip
246f6c50668Spatrick   registers.setIP(addressSpace.get32(bp + 4));
247f6c50668Spatrick }
248f6c50668Spatrick 
249f6c50668Spatrick template <typename A>
framelessUnwind(A & addressSpace,typename A::pint_t returnAddressLocation,Registers_x86 & registers)250f6c50668Spatrick void CompactUnwinder_x86<A>::framelessUnwind(
251f6c50668Spatrick     A &addressSpace, typename A::pint_t returnAddressLocation,
252f6c50668Spatrick     Registers_x86 &registers) {
253f6c50668Spatrick   // return address is on stack after last saved register
254f6c50668Spatrick   registers.setIP(addressSpace.get32(returnAddressLocation));
255f6c50668Spatrick   // old esp is before return address
256f6c50668Spatrick   registers.setSP((uint32_t)returnAddressLocation + 4);
257f6c50668Spatrick }
258f6c50668Spatrick #endif // _LIBUNWIND_TARGET_I386
259f6c50668Spatrick 
260f6c50668Spatrick 
261f6c50668Spatrick #if defined(_LIBUNWIND_TARGET_X86_64)
262f6c50668Spatrick /// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
263f6c50668Spatrick /// unwind) by modifying a Registers_x86_64 register set
264f6c50668Spatrick template <typename A>
265f6c50668Spatrick class CompactUnwinder_x86_64 {
266f6c50668Spatrick public:
267f6c50668Spatrick 
268f6c50668Spatrick   static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
269f6c50668Spatrick                                      uint64_t functionStart, A &addressSpace,
270f6c50668Spatrick                                      Registers_x86_64 &registers);
271f6c50668Spatrick 
272f6c50668Spatrick private:
273f6c50668Spatrick   typename A::pint_t pint_t;
274f6c50668Spatrick 
275f6c50668Spatrick   static void frameUnwind(A &addressSpace, Registers_x86_64 &registers);
276f6c50668Spatrick   static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
277f6c50668Spatrick                               Registers_x86_64 &registers);
278f6c50668Spatrick   static int
279f6c50668Spatrick       stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
280f6c50668Spatrick                                       uint64_t functionStart, A &addressSpace,
281f6c50668Spatrick                                       Registers_x86_64 &registers);
282f6c50668Spatrick   static int stepWithCompactEncodingFrameless(
283f6c50668Spatrick       compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
284f6c50668Spatrick       A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize);
285f6c50668Spatrick };
286f6c50668Spatrick 
287f6c50668Spatrick template <typename A>
stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,uint64_t functionStart,A & addressSpace,Registers_x86_64 & registers)288f6c50668Spatrick int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
289f6c50668Spatrick     compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
290f6c50668Spatrick     A &addressSpace, Registers_x86_64 &registers) {
291f6c50668Spatrick   switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
292f6c50668Spatrick   case UNWIND_X86_64_MODE_RBP_FRAME:
293f6c50668Spatrick     return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
294f6c50668Spatrick                                            addressSpace, registers);
295f6c50668Spatrick   case UNWIND_X86_64_MODE_STACK_IMMD:
296f6c50668Spatrick     return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
297f6c50668Spatrick                                             addressSpace, registers, false);
298f6c50668Spatrick   case UNWIND_X86_64_MODE_STACK_IND:
299f6c50668Spatrick     return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
300f6c50668Spatrick                                             addressSpace, registers, true);
301f6c50668Spatrick   }
302f6c50668Spatrick   _LIBUNWIND_ABORT("invalid compact unwind encoding");
303f6c50668Spatrick }
304f6c50668Spatrick 
305f6c50668Spatrick template <typename A>
stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,uint64_t functionStart,A & addressSpace,Registers_x86_64 & registers)306f6c50668Spatrick int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
307f6c50668Spatrick     compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
308f6c50668Spatrick     A &addressSpace, Registers_x86_64 &registers) {
309f6c50668Spatrick   uint32_t savedRegistersOffset =
310f6c50668Spatrick       EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
311f6c50668Spatrick   uint32_t savedRegistersLocations =
312f6c50668Spatrick       EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
313f6c50668Spatrick 
314f6c50668Spatrick   uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
315f6c50668Spatrick   for (int i = 0; i < 5; ++i) {
316f6c50668Spatrick     switch (savedRegistersLocations & 0x7) {
317f6c50668Spatrick     case UNWIND_X86_64_REG_NONE:
318f6c50668Spatrick       // no register saved in this slot
319f6c50668Spatrick       break;
320f6c50668Spatrick     case UNWIND_X86_64_REG_RBX:
321f6c50668Spatrick       registers.setRBX(addressSpace.get64(savedRegisters));
322f6c50668Spatrick       break;
323f6c50668Spatrick     case UNWIND_X86_64_REG_R12:
324f6c50668Spatrick       registers.setR12(addressSpace.get64(savedRegisters));
325f6c50668Spatrick       break;
326f6c50668Spatrick     case UNWIND_X86_64_REG_R13:
327f6c50668Spatrick       registers.setR13(addressSpace.get64(savedRegisters));
328f6c50668Spatrick       break;
329f6c50668Spatrick     case UNWIND_X86_64_REG_R14:
330f6c50668Spatrick       registers.setR14(addressSpace.get64(savedRegisters));
331f6c50668Spatrick       break;
332f6c50668Spatrick     case UNWIND_X86_64_REG_R15:
333f6c50668Spatrick       registers.setR15(addressSpace.get64(savedRegisters));
334f6c50668Spatrick       break;
335f6c50668Spatrick     default:
336f6c50668Spatrick       (void)functionStart;
337f6c50668Spatrick       _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
338f6c50668Spatrick                            "function starting at 0x%llX",
339f6c50668Spatrick                             compactEncoding, functionStart);
340f6c50668Spatrick       _LIBUNWIND_ABORT("invalid compact unwind encoding");
341f6c50668Spatrick     }
342f6c50668Spatrick     savedRegisters += 8;
343f6c50668Spatrick     savedRegistersLocations = (savedRegistersLocations >> 3);
344f6c50668Spatrick   }
345f6c50668Spatrick   frameUnwind(addressSpace, registers);
346f6c50668Spatrick   return UNW_STEP_SUCCESS;
347f6c50668Spatrick }
348f6c50668Spatrick 
349f6c50668Spatrick template <typename A>
stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding,uint64_t functionStart,A & addressSpace,Registers_x86_64 & registers,bool indirectStackSize)350f6c50668Spatrick int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
351f6c50668Spatrick     compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
352f6c50668Spatrick     Registers_x86_64 &registers, bool indirectStackSize) {
353f6c50668Spatrick   uint32_t stackSizeEncoded =
354f6c50668Spatrick       EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
355f6c50668Spatrick   uint32_t stackAdjust =
356f6c50668Spatrick       EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
357f6c50668Spatrick   uint32_t regCount =
358f6c50668Spatrick       EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
359f6c50668Spatrick   uint32_t permutation =
360f6c50668Spatrick       EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
361f6c50668Spatrick   uint32_t stackSize = stackSizeEncoded * 8;
362f6c50668Spatrick   if (indirectStackSize) {
363f6c50668Spatrick     // stack size is encoded in subl $xxx,%esp instruction
364f6c50668Spatrick     uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
365f6c50668Spatrick     stackSize = subl + 8 * stackAdjust;
366f6c50668Spatrick   }
367f6c50668Spatrick   // decompress permutation
368f6c50668Spatrick   uint32_t permunreg[6];
369f6c50668Spatrick   switch (regCount) {
370f6c50668Spatrick   case 6:
371f6c50668Spatrick     permunreg[0] = permutation / 120;
372f6c50668Spatrick     permutation -= (permunreg[0] * 120);
373f6c50668Spatrick     permunreg[1] = permutation / 24;
374f6c50668Spatrick     permutation -= (permunreg[1] * 24);
375f6c50668Spatrick     permunreg[2] = permutation / 6;
376f6c50668Spatrick     permutation -= (permunreg[2] * 6);
377f6c50668Spatrick     permunreg[3] = permutation / 2;
378f6c50668Spatrick     permutation -= (permunreg[3] * 2);
379f6c50668Spatrick     permunreg[4] = permutation;
380f6c50668Spatrick     permunreg[5] = 0;
381f6c50668Spatrick     break;
382f6c50668Spatrick   case 5:
383f6c50668Spatrick     permunreg[0] = permutation / 120;
384f6c50668Spatrick     permutation -= (permunreg[0] * 120);
385f6c50668Spatrick     permunreg[1] = permutation / 24;
386f6c50668Spatrick     permutation -= (permunreg[1] * 24);
387f6c50668Spatrick     permunreg[2] = permutation / 6;
388f6c50668Spatrick     permutation -= (permunreg[2] * 6);
389f6c50668Spatrick     permunreg[3] = permutation / 2;
390f6c50668Spatrick     permutation -= (permunreg[3] * 2);
391f6c50668Spatrick     permunreg[4] = permutation;
392f6c50668Spatrick     break;
393f6c50668Spatrick   case 4:
394f6c50668Spatrick     permunreg[0] = permutation / 60;
395f6c50668Spatrick     permutation -= (permunreg[0] * 60);
396f6c50668Spatrick     permunreg[1] = permutation / 12;
397f6c50668Spatrick     permutation -= (permunreg[1] * 12);
398f6c50668Spatrick     permunreg[2] = permutation / 3;
399f6c50668Spatrick     permutation -= (permunreg[2] * 3);
400f6c50668Spatrick     permunreg[3] = permutation;
401f6c50668Spatrick     break;
402f6c50668Spatrick   case 3:
403f6c50668Spatrick     permunreg[0] = permutation / 20;
404f6c50668Spatrick     permutation -= (permunreg[0] * 20);
405f6c50668Spatrick     permunreg[1] = permutation / 4;
406f6c50668Spatrick     permutation -= (permunreg[1] * 4);
407f6c50668Spatrick     permunreg[2] = permutation;
408f6c50668Spatrick     break;
409f6c50668Spatrick   case 2:
410f6c50668Spatrick     permunreg[0] = permutation / 5;
411f6c50668Spatrick     permutation -= (permunreg[0] * 5);
412f6c50668Spatrick     permunreg[1] = permutation;
413f6c50668Spatrick     break;
414f6c50668Spatrick   case 1:
415f6c50668Spatrick     permunreg[0] = permutation;
416f6c50668Spatrick     break;
417f6c50668Spatrick   }
418f6c50668Spatrick   // re-number registers back to standard numbers
419f6c50668Spatrick   int registersSaved[6];
420f6c50668Spatrick   bool used[7] = { false, false, false, false, false, false, false };
421f6c50668Spatrick   for (uint32_t i = 0; i < regCount; ++i) {
422f6c50668Spatrick     uint32_t renum = 0;
423f6c50668Spatrick     for (int u = 1; u < 7; ++u) {
424f6c50668Spatrick       if (!used[u]) {
425f6c50668Spatrick         if (renum == permunreg[i]) {
426f6c50668Spatrick           registersSaved[i] = u;
427f6c50668Spatrick           used[u] = true;
428f6c50668Spatrick           break;
429f6c50668Spatrick         }
430f6c50668Spatrick         ++renum;
431f6c50668Spatrick       }
432f6c50668Spatrick     }
433f6c50668Spatrick   }
434f6c50668Spatrick   uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
435f6c50668Spatrick   for (uint32_t i = 0; i < regCount; ++i) {
436f6c50668Spatrick     switch (registersSaved[i]) {
437f6c50668Spatrick     case UNWIND_X86_64_REG_RBX:
438f6c50668Spatrick       registers.setRBX(addressSpace.get64(savedRegisters));
439f6c50668Spatrick       break;
440f6c50668Spatrick     case UNWIND_X86_64_REG_R12:
441f6c50668Spatrick       registers.setR12(addressSpace.get64(savedRegisters));
442f6c50668Spatrick       break;
443f6c50668Spatrick     case UNWIND_X86_64_REG_R13:
444f6c50668Spatrick       registers.setR13(addressSpace.get64(savedRegisters));
445f6c50668Spatrick       break;
446f6c50668Spatrick     case UNWIND_X86_64_REG_R14:
447f6c50668Spatrick       registers.setR14(addressSpace.get64(savedRegisters));
448f6c50668Spatrick       break;
449f6c50668Spatrick     case UNWIND_X86_64_REG_R15:
450f6c50668Spatrick       registers.setR15(addressSpace.get64(savedRegisters));
451f6c50668Spatrick       break;
452f6c50668Spatrick     case UNWIND_X86_64_REG_RBP:
453f6c50668Spatrick       registers.setRBP(addressSpace.get64(savedRegisters));
454f6c50668Spatrick       break;
455f6c50668Spatrick     default:
456f6c50668Spatrick       _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
457f6c50668Spatrick                            "function starting at 0x%llX",
458f6c50668Spatrick                             encoding, functionStart);
459f6c50668Spatrick       _LIBUNWIND_ABORT("invalid compact unwind encoding");
460f6c50668Spatrick     }
461f6c50668Spatrick     savedRegisters += 8;
462f6c50668Spatrick   }
463f6c50668Spatrick   framelessUnwind(addressSpace, savedRegisters, registers);
464f6c50668Spatrick   return UNW_STEP_SUCCESS;
465f6c50668Spatrick }
466f6c50668Spatrick 
467f6c50668Spatrick 
468f6c50668Spatrick template <typename A>
frameUnwind(A & addressSpace,Registers_x86_64 & registers)469f6c50668Spatrick void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
470f6c50668Spatrick                                             Registers_x86_64 &registers) {
471f6c50668Spatrick   uint64_t rbp = registers.getRBP();
472f6c50668Spatrick   // ebp points to old ebp
473f6c50668Spatrick   registers.setRBP(addressSpace.get64(rbp));
474f6c50668Spatrick   // old esp is ebp less saved ebp and return address
475f6c50668Spatrick   registers.setSP(rbp + 16);
476f6c50668Spatrick   // pop return address into eip
477f6c50668Spatrick   registers.setIP(addressSpace.get64(rbp + 8));
478f6c50668Spatrick }
479f6c50668Spatrick 
480f6c50668Spatrick template <typename A>
framelessUnwind(A & addressSpace,uint64_t returnAddressLocation,Registers_x86_64 & registers)481f6c50668Spatrick void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
482f6c50668Spatrick                                                 uint64_t returnAddressLocation,
483f6c50668Spatrick                                                 Registers_x86_64 &registers) {
484f6c50668Spatrick   // return address is on stack after last saved register
485f6c50668Spatrick   registers.setIP(addressSpace.get64(returnAddressLocation));
486f6c50668Spatrick   // old esp is before return address
487f6c50668Spatrick   registers.setSP(returnAddressLocation + 8);
488f6c50668Spatrick }
489f6c50668Spatrick #endif // _LIBUNWIND_TARGET_X86_64
490f6c50668Spatrick 
491f6c50668Spatrick 
492f6c50668Spatrick 
493f6c50668Spatrick #if defined(_LIBUNWIND_TARGET_AARCH64)
494f6c50668Spatrick /// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
495f6c50668Spatrick /// unwind) by modifying a Registers_arm64 register set
496f6c50668Spatrick template <typename A>
497f6c50668Spatrick class CompactUnwinder_arm64 {
498f6c50668Spatrick public:
499f6c50668Spatrick 
500f6c50668Spatrick   static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
501f6c50668Spatrick                                      uint64_t functionStart, A &addressSpace,
502f6c50668Spatrick                                      Registers_arm64 &registers);
503f6c50668Spatrick 
504f6c50668Spatrick private:
505f6c50668Spatrick   typename A::pint_t pint_t;
506f6c50668Spatrick 
507f6c50668Spatrick   static int
508f6c50668Spatrick       stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
509f6c50668Spatrick                                    uint64_t functionStart, A &addressSpace,
510f6c50668Spatrick                                    Registers_arm64 &registers);
511f6c50668Spatrick   static int stepWithCompactEncodingFrameless(
512f6c50668Spatrick       compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
513f6c50668Spatrick       A &addressSpace, Registers_arm64 &registers);
514f6c50668Spatrick };
515f6c50668Spatrick 
516f6c50668Spatrick template <typename A>
stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,uint64_t functionStart,A & addressSpace,Registers_arm64 & registers)517f6c50668Spatrick int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
518f6c50668Spatrick     compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
519f6c50668Spatrick     A &addressSpace, Registers_arm64 &registers) {
520f6c50668Spatrick   switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
521f6c50668Spatrick   case UNWIND_ARM64_MODE_FRAME:
522f6c50668Spatrick     return stepWithCompactEncodingFrame(compactEncoding, functionStart,
523f6c50668Spatrick                                         addressSpace, registers);
524f6c50668Spatrick   case UNWIND_ARM64_MODE_FRAMELESS:
525f6c50668Spatrick     return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
526f6c50668Spatrick                                             addressSpace, registers);
527f6c50668Spatrick   }
528f6c50668Spatrick   _LIBUNWIND_ABORT("invalid compact unwind encoding");
529f6c50668Spatrick }
530f6c50668Spatrick 
531f6c50668Spatrick template <typename A>
stepWithCompactEncodingFrameless(compact_unwind_encoding_t encoding,uint64_t,A & addressSpace,Registers_arm64 & registers)532f6c50668Spatrick int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
533f6c50668Spatrick     compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
534f6c50668Spatrick     Registers_arm64 &registers) {
535f6c50668Spatrick   uint32_t stackSize =
536f6c50668Spatrick       16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
537f6c50668Spatrick 
538f6c50668Spatrick   uint64_t savedRegisterLoc = registers.getSP() + stackSize;
539f6c50668Spatrick 
540f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
541*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));
542f6c50668Spatrick     savedRegisterLoc -= 8;
543*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X20, addressSpace.get64(savedRegisterLoc));
544f6c50668Spatrick     savedRegisterLoc -= 8;
545f6c50668Spatrick   }
546f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
547*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X21, addressSpace.get64(savedRegisterLoc));
548f6c50668Spatrick     savedRegisterLoc -= 8;
549*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X22, addressSpace.get64(savedRegisterLoc));
550f6c50668Spatrick     savedRegisterLoc -= 8;
551f6c50668Spatrick   }
552f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
553*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X23, addressSpace.get64(savedRegisterLoc));
554f6c50668Spatrick     savedRegisterLoc -= 8;
555*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X24, addressSpace.get64(savedRegisterLoc));
556f6c50668Spatrick     savedRegisterLoc -= 8;
557f6c50668Spatrick   }
558f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
559*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X25, addressSpace.get64(savedRegisterLoc));
560f6c50668Spatrick     savedRegisterLoc -= 8;
561*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X26, addressSpace.get64(savedRegisterLoc));
562f6c50668Spatrick     savedRegisterLoc -= 8;
563f6c50668Spatrick   }
564f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
565*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X27, addressSpace.get64(savedRegisterLoc));
566f6c50668Spatrick     savedRegisterLoc -= 8;
567*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X28, addressSpace.get64(savedRegisterLoc));
568f6c50668Spatrick     savedRegisterLoc -= 8;
569f6c50668Spatrick   }
570f6c50668Spatrick 
571f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
572*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V8,
573f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
574f6c50668Spatrick     savedRegisterLoc -= 8;
575*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V9,
576f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
577f6c50668Spatrick     savedRegisterLoc -= 8;
578f6c50668Spatrick   }
579f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
580*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V10,
581f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
582f6c50668Spatrick     savedRegisterLoc -= 8;
583*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V11,
584f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
585f6c50668Spatrick     savedRegisterLoc -= 8;
586f6c50668Spatrick   }
587f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
588*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V12,
589f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
590f6c50668Spatrick     savedRegisterLoc -= 8;
591*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V13,
592f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
593f6c50668Spatrick     savedRegisterLoc -= 8;
594f6c50668Spatrick   }
595f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
596*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V14,
597f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
598f6c50668Spatrick     savedRegisterLoc -= 8;
599*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V15,
600f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
601f6c50668Spatrick     savedRegisterLoc -= 8;
602f6c50668Spatrick   }
603f6c50668Spatrick 
604f6c50668Spatrick   // subtract stack size off of sp
605f6c50668Spatrick   registers.setSP(savedRegisterLoc);
606f6c50668Spatrick 
607f6c50668Spatrick   // set pc to be value in lr
608*0faf1914Srobert   registers.setIP(registers.getRegister(UNW_AARCH64_LR));
609f6c50668Spatrick 
610f6c50668Spatrick   return UNW_STEP_SUCCESS;
611f6c50668Spatrick }
612f6c50668Spatrick 
613f6c50668Spatrick template <typename A>
stepWithCompactEncodingFrame(compact_unwind_encoding_t encoding,uint64_t,A & addressSpace,Registers_arm64 & registers)614f6c50668Spatrick int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
615f6c50668Spatrick     compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
616f6c50668Spatrick     Registers_arm64 &registers) {
617f6c50668Spatrick   uint64_t savedRegisterLoc = registers.getFP() - 8;
618f6c50668Spatrick 
619f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
620*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X19, addressSpace.get64(savedRegisterLoc));
621f6c50668Spatrick     savedRegisterLoc -= 8;
622*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X20, addressSpace.get64(savedRegisterLoc));
623f6c50668Spatrick     savedRegisterLoc -= 8;
624f6c50668Spatrick   }
625f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
626*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X21, addressSpace.get64(savedRegisterLoc));
627f6c50668Spatrick     savedRegisterLoc -= 8;
628*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X22, addressSpace.get64(savedRegisterLoc));
629f6c50668Spatrick     savedRegisterLoc -= 8;
630f6c50668Spatrick   }
631f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
632*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X23, addressSpace.get64(savedRegisterLoc));
633f6c50668Spatrick     savedRegisterLoc -= 8;
634*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X24, addressSpace.get64(savedRegisterLoc));
635f6c50668Spatrick     savedRegisterLoc -= 8;
636f6c50668Spatrick   }
637f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
638*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X25, addressSpace.get64(savedRegisterLoc));
639f6c50668Spatrick     savedRegisterLoc -= 8;
640*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X26, addressSpace.get64(savedRegisterLoc));
641f6c50668Spatrick     savedRegisterLoc -= 8;
642f6c50668Spatrick   }
643f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
644*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X27, addressSpace.get64(savedRegisterLoc));
645f6c50668Spatrick     savedRegisterLoc -= 8;
646*0faf1914Srobert     registers.setRegister(UNW_AARCH64_X28, addressSpace.get64(savedRegisterLoc));
647f6c50668Spatrick     savedRegisterLoc -= 8;
648f6c50668Spatrick   }
649f6c50668Spatrick 
650f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
651*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V8,
652f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
653f6c50668Spatrick     savedRegisterLoc -= 8;
654*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V9,
655f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
656f6c50668Spatrick     savedRegisterLoc -= 8;
657f6c50668Spatrick   }
658f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
659*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V10,
660f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
661f6c50668Spatrick     savedRegisterLoc -= 8;
662*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V11,
663f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
664f6c50668Spatrick     savedRegisterLoc -= 8;
665f6c50668Spatrick   }
666f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
667*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V12,
668f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
669f6c50668Spatrick     savedRegisterLoc -= 8;
670*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V13,
671f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
672f6c50668Spatrick     savedRegisterLoc -= 8;
673f6c50668Spatrick   }
674f6c50668Spatrick   if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
675*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V14,
676f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
677f6c50668Spatrick     savedRegisterLoc -= 8;
678*0faf1914Srobert     registers.setFloatRegister(UNW_AARCH64_V15,
679f6c50668Spatrick                                addressSpace.getDouble(savedRegisterLoc));
680f6c50668Spatrick     savedRegisterLoc -= 8;
681f6c50668Spatrick   }
682f6c50668Spatrick 
683f6c50668Spatrick   uint64_t fp = registers.getFP();
684f6c50668Spatrick   // fp points to old fp
685f6c50668Spatrick   registers.setFP(addressSpace.get64(fp));
686f6c50668Spatrick   // old sp is fp less saved fp and lr
687f6c50668Spatrick   registers.setSP(fp + 16);
688f6c50668Spatrick   // pop return address into pc
689f6c50668Spatrick   registers.setIP(addressSpace.get64(fp + 8));
690f6c50668Spatrick 
691f6c50668Spatrick   return UNW_STEP_SUCCESS;
692f6c50668Spatrick }
693f6c50668Spatrick #endif // _LIBUNWIND_TARGET_AARCH64
694f6c50668Spatrick 
695f6c50668Spatrick 
696f6c50668Spatrick } // namespace libunwind
697f6c50668Spatrick 
698f6c50668Spatrick #endif // __COMPACT_UNWINDER_HPP__
699