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