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