libunwind: update to upstream snapshot r272680
[freebsd.git] / contrib / llvm / projects / libunwind / src / CompactUnwinder.hpp
1 //===-------------------------- CompactUnwinder.hpp -----------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //
9 //  Does runtime stack unwinding using compact unwind encodings.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef __COMPACT_UNWINDER_HPP__
14 #define __COMPACT_UNWINDER_HPP__
15
16 #include <stdint.h>
17 #include <stdlib.h>
18
19 #include <libunwind.h>
20 #include <mach-o/compact_unwind_encoding.h>
21
22 #include "AddressSpace.hpp"
23 #include "Registers.hpp"
24
25 #define EXTRACT_BITS(value, mask)                                              \
26   ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
27
28 namespace libunwind {
29
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
33 template <typename A>
34 class CompactUnwinder_x86 {
35 public:
36
37   static int stepWithCompactEncoding(compact_unwind_encoding_t info,
38                                      uint32_t functionStart, A &addressSpace,
39                                      Registers_x86 &registers);
40
41 private:
42   typename A::pint_t pint_t;
43
44   static void frameUnwind(A &addressSpace, Registers_x86 &registers);
45   static void framelessUnwind(A &addressSpace,
46                               typename A::pint_t returnAddressLocation,
47                               Registers_x86 &registers);
48   static int
49       stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
50                                       uint32_t functionStart, A &addressSpace,
51                                       Registers_x86 &registers);
52   static int stepWithCompactEncodingFrameless(
53       compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
54       A &addressSpace, Registers_x86 &registers, bool indirectStackSize);
55 };
56
57 template <typename A>
58 int CompactUnwinder_x86<A>::stepWithCompactEncoding(
59     compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
60     A &addressSpace, Registers_x86 &registers) {
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);
71   }
72   _LIBUNWIND_ABORT("invalid compact unwind encoding");
73 }
74
75 template <typename A>
76 int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
77     compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
78     A &addressSpace, Registers_x86 &registers) {
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);
83
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
89       break;
90     case UNWIND_X86_REG_EBX:
91       registers.setEBX(addressSpace.get32(savedRegisters));
92       break;
93     case UNWIND_X86_REG_ECX:
94       registers.setECX(addressSpace.get32(savedRegisters));
95       break;
96     case UNWIND_X86_REG_EDX:
97       registers.setEDX(addressSpace.get32(savedRegisters));
98       break;
99     case UNWIND_X86_REG_EDI:
100       registers.setEDI(addressSpace.get32(savedRegisters));
101       break;
102     case UNWIND_X86_REG_ESI:
103       registers.setESI(addressSpace.get32(savedRegisters));
104       break;
105     default:
106       (void)functionStart;
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");
111     }
112     savedRegisters += 4;
113     savedRegistersLocations = (savedRegistersLocations >> 3);
114   }
115   frameUnwind(addressSpace, registers);
116   return UNW_STEP_SUCCESS;
117 }
118
119 template <typename A>
120 int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
121     compact_unwind_encoding_t encoding, uint32_t functionStart,
122     A &addressSpace, Registers_x86 &registers, 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);
127   uint32_t regCount =
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;
136   }
137   // decompress permutation
138   uint32_t permunreg[6];
139   switch (regCount) {
140   case 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;
150     permunreg[5] = 0;
151     break;
152   case 5:
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;
162     break;
163   case 4:
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;
171     break;
172   case 3:
173     permunreg[0] = permutation / 20;
174     permutation -= (permunreg[0] * 20);
175     permunreg[1] = permutation / 4;
176     permutation -= (permunreg[1] * 4);
177     permunreg[2] = permutation;
178     break;
179   case 2:
180     permunreg[0] = permutation / 5;
181     permutation -= (permunreg[0] * 5);
182     permunreg[1] = permutation;
183     break;
184   case 1:
185     permunreg[0] = permutation;
186     break;
187   }
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) {
192     uint32_t renum = 0;
193     for (int u = 1; u < 7; ++u) {
194       if (!used[u]) {
195         if (renum == permunreg[i]) {
196           registersSaved[i] = u;
197           used[u] = true;
198           break;
199         }
200         ++renum;
201       }
202     }
203   }
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));
209       break;
210     case UNWIND_X86_REG_ECX:
211       registers.setECX(addressSpace.get32(savedRegisters));
212       break;
213     case UNWIND_X86_REG_EDX:
214       registers.setEDX(addressSpace.get32(savedRegisters));
215       break;
216     case UNWIND_X86_REG_EDI:
217       registers.setEDI(addressSpace.get32(savedRegisters));
218       break;
219     case UNWIND_X86_REG_ESI:
220       registers.setESI(addressSpace.get32(savedRegisters));
221       break;
222     case UNWIND_X86_REG_EBP:
223       registers.setEBP(addressSpace.get32(savedRegisters));
224       break;
225     default:
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");
230     }
231     savedRegisters += 4;
232   }
233   framelessUnwind(addressSpace, savedRegisters, registers);
234   return UNW_STEP_SUCCESS;
235 }
236
237
238 template <typename A>
239 void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
240                                          Registers_x86 &registers) {
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));
248 }
249
250 template <typename A>
251 void CompactUnwinder_x86<A>::framelessUnwind(
252     A &addressSpace, typename A::pint_t returnAddressLocation,
253     Registers_x86 &registers) {
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);
258 }
259 #endif // _LIBUNWIND_TARGET_I386
260
261
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 {
267 public:
268
269   static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
270                                      uint64_t functionStart, A &addressSpace,
271                                      Registers_x86_64 &registers);
272
273 private:
274   typename A::pint_t pint_t;
275
276   static void frameUnwind(A &addressSpace, Registers_x86_64 &registers);
277   static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
278                               Registers_x86_64 &registers);
279   static int
280       stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
281                                       uint64_t functionStart, A &addressSpace,
282                                       Registers_x86_64 &registers);
283   static int stepWithCompactEncodingFrameless(
284       compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
285       A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize);
286 };
287
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 &registers) {
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);
302   }
303   _LIBUNWIND_ABORT("invalid compact unwind encoding");
304 }
305
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 &registers) {
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);
314
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
320       break;
321     case UNWIND_X86_64_REG_RBX:
322       registers.setRBX(addressSpace.get64(savedRegisters));
323       break;
324     case UNWIND_X86_64_REG_R12:
325       registers.setR12(addressSpace.get64(savedRegisters));
326       break;
327     case UNWIND_X86_64_REG_R13:
328       registers.setR13(addressSpace.get64(savedRegisters));
329       break;
330     case UNWIND_X86_64_REG_R14:
331       registers.setR14(addressSpace.get64(savedRegisters));
332       break;
333     case UNWIND_X86_64_REG_R15:
334       registers.setR15(addressSpace.get64(savedRegisters));
335       break;
336     default:
337       (void)functionStart;
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");
342     }
343     savedRegisters += 8;
344     savedRegistersLocations = (savedRegistersLocations >> 3);
345   }
346   frameUnwind(addressSpace, registers);
347   return UNW_STEP_SUCCESS;
348 }
349
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 &registers, 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);
358   uint32_t regCount =
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;
367   }
368   // decompress permutation
369   uint32_t permunreg[6];
370   switch (regCount) {
371   case 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;
381     permunreg[5] = 0;
382     break;
383   case 5:
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;
393     break;
394   case 4:
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;
402     break;
403   case 3:
404     permunreg[0] = permutation / 20;
405     permutation -= (permunreg[0] * 20);
406     permunreg[1] = permutation / 4;
407     permutation -= (permunreg[1] * 4);
408     permunreg[2] = permutation;
409     break;
410   case 2:
411     permunreg[0] = permutation / 5;
412     permutation -= (permunreg[0] * 5);
413     permunreg[1] = permutation;
414     break;
415   case 1:
416     permunreg[0] = permutation;
417     break;
418   }
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) {
423     uint32_t renum = 0;
424     for (int u = 1; u < 7; ++u) {
425       if (!used[u]) {
426         if (renum == permunreg[i]) {
427           registersSaved[i] = u;
428           used[u] = true;
429           break;
430         }
431         ++renum;
432       }
433     }
434   }
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));
440       break;
441     case UNWIND_X86_64_REG_R12:
442       registers.setR12(addressSpace.get64(savedRegisters));
443       break;
444     case UNWIND_X86_64_REG_R13:
445       registers.setR13(addressSpace.get64(savedRegisters));
446       break;
447     case UNWIND_X86_64_REG_R14:
448       registers.setR14(addressSpace.get64(savedRegisters));
449       break;
450     case UNWIND_X86_64_REG_R15:
451       registers.setR15(addressSpace.get64(savedRegisters));
452       break;
453     case UNWIND_X86_64_REG_RBP:
454       registers.setRBP(addressSpace.get64(savedRegisters));
455       break;
456     default:
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");
461     }
462     savedRegisters += 8;
463   }
464   framelessUnwind(addressSpace, savedRegisters, registers);
465   return UNW_STEP_SUCCESS;
466 }
467
468
469 template <typename A>
470 void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
471                                             Registers_x86_64 &registers) {
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));
479 }
480
481 template <typename A>
482 void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
483                                                 uint64_t returnAddressLocation,
484                                                 Registers_x86_64 &registers) {
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);
489 }
490 #endif // _LIBUNWIND_TARGET_X86_64
491
492
493
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 {
499 public:
500
501   static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
502                                      uint64_t functionStart, A &addressSpace,
503                                      Registers_arm64 &registers);
504
505 private:
506   typename A::pint_t pint_t;
507
508   static int
509       stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
510                                    uint64_t functionStart, A &addressSpace,
511                                    Registers_arm64 &registers);
512   static int stepWithCompactEncodingFrameless(
513       compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
514       A &addressSpace, Registers_arm64 &registers);
515 };
516
517 template <typename A>
518 int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
519     compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
520     A &addressSpace, Registers_arm64 &registers) {
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);
528   }
529   _LIBUNWIND_ABORT("invalid compact unwind encoding");
530 }
531
532 template <typename A>
533 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
534     compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
535     Registers_arm64 &registers) {
536   uint32_t stackSize =
537       16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
538
539   uint64_t savedRegisterLoc = registers.getSP() + stackSize;
540
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;
546   }
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;
552   }
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;
558   }
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;
564   }
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;
570   }
571
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;
579   }
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;
587   }
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;
595   }
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;
603   }
604
605   // subtract stack size off of sp
606   registers.setSP(savedRegisterLoc);
607
608   // set pc to be value in lr
609   registers.setIP(registers.getRegister(UNW_ARM64_LR));
610
611   return UNW_STEP_SUCCESS;
612 }
613
614 template <typename A>
615 int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
616     compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
617     Registers_arm64 &registers) {
618   uint64_t savedRegisterLoc = registers.getFP() - 8;
619
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;
625   }
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;
631   }
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;
637   }
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;
643   }
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;
649   }
650
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;
658   }
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;
666   }
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;
674   }
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;
682   }
683
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));
691
692   return UNW_STEP_SUCCESS;
693 }
694 #endif // _LIBUNWIND_TARGET_AARCH64
695
696
697 } // namespace libunwind
698
699 #endif // __COMPACT_UNWINDER_HPP__