15ffd83dbSDimitry Andric //===-- CompactUnwindInfo.cpp ---------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Symbol/CompactUnwindInfo.h"
1081ad6265SDimitry Andric #include "lldb/Core/Debugger.h"
110b57cec5SDimitry Andric #include "lldb/Core/Module.h"
120b57cec5SDimitry Andric #include "lldb/Core/Section.h"
130b57cec5SDimitry Andric #include "lldb/Symbol/ObjectFile.h"
140b57cec5SDimitry Andric #include "lldb/Symbol/UnwindPlan.h"
150b57cec5SDimitry Andric #include "lldb/Target/Process.h"
160b57cec5SDimitry Andric #include "lldb/Target/Target.h"
170b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h"
180b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
1981ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
200b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
210b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric #include <algorithm>
260b57cec5SDimitry Andric #include <memory>
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric using namespace lldb;
290b57cec5SDimitry Andric using namespace lldb_private;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace lldb_private {
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric // Constants from <mach-o/compact_unwind_encoding.h>
340b57cec5SDimitry Andric 
FLAGS_ANONYMOUS_ENUM()350b57cec5SDimitry Andric FLAGS_ANONYMOUS_ENUM(){
360b57cec5SDimitry Andric     UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
370b57cec5SDimitry Andric     UNWIND_PERSONALITY_MASK = 0x30000000,
380b57cec5SDimitry Andric };
390b57cec5SDimitry Andric 
FLAGS_ANONYMOUS_ENUM()400b57cec5SDimitry Andric FLAGS_ANONYMOUS_ENUM(){
410b57cec5SDimitry Andric     UNWIND_X86_MODE_MASK = 0x0F000000,
420b57cec5SDimitry Andric     UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
430b57cec5SDimitry Andric     UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
440b57cec5SDimitry Andric     UNWIND_X86_MODE_STACK_IND = 0x03000000,
450b57cec5SDimitry Andric     UNWIND_X86_MODE_DWARF = 0x04000000,
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric     UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
480b57cec5SDimitry Andric     UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric     UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
510b57cec5SDimitry Andric     UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
520b57cec5SDimitry Andric     UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
530b57cec5SDimitry Andric     UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric     UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
560b57cec5SDimitry Andric };
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric enum {
590b57cec5SDimitry Andric   UNWIND_X86_REG_NONE = 0,
600b57cec5SDimitry Andric   UNWIND_X86_REG_EBX = 1,
610b57cec5SDimitry Andric   UNWIND_X86_REG_ECX = 2,
620b57cec5SDimitry Andric   UNWIND_X86_REG_EDX = 3,
630b57cec5SDimitry Andric   UNWIND_X86_REG_EDI = 4,
640b57cec5SDimitry Andric   UNWIND_X86_REG_ESI = 5,
650b57cec5SDimitry Andric   UNWIND_X86_REG_EBP = 6,
660b57cec5SDimitry Andric };
670b57cec5SDimitry Andric 
FLAGS_ANONYMOUS_ENUM()680b57cec5SDimitry Andric FLAGS_ANONYMOUS_ENUM(){
690b57cec5SDimitry Andric     UNWIND_X86_64_MODE_MASK = 0x0F000000,
700b57cec5SDimitry Andric     UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
710b57cec5SDimitry Andric     UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
720b57cec5SDimitry Andric     UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
730b57cec5SDimitry Andric     UNWIND_X86_64_MODE_DWARF = 0x04000000,
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric     UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
760b57cec5SDimitry Andric     UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
770b57cec5SDimitry Andric 
780b57cec5SDimitry Andric     UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
790b57cec5SDimitry Andric     UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
800b57cec5SDimitry Andric     UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
810b57cec5SDimitry Andric     UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric     UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
840b57cec5SDimitry Andric };
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric enum {
870b57cec5SDimitry Andric   UNWIND_X86_64_REG_NONE = 0,
880b57cec5SDimitry Andric   UNWIND_X86_64_REG_RBX = 1,
890b57cec5SDimitry Andric   UNWIND_X86_64_REG_R12 = 2,
900b57cec5SDimitry Andric   UNWIND_X86_64_REG_R13 = 3,
910b57cec5SDimitry Andric   UNWIND_X86_64_REG_R14 = 4,
920b57cec5SDimitry Andric   UNWIND_X86_64_REG_R15 = 5,
930b57cec5SDimitry Andric   UNWIND_X86_64_REG_RBP = 6,
940b57cec5SDimitry Andric };
950b57cec5SDimitry Andric 
FLAGS_ANONYMOUS_ENUM()960b57cec5SDimitry Andric FLAGS_ANONYMOUS_ENUM(){
970b57cec5SDimitry Andric     UNWIND_ARM64_MODE_MASK = 0x0F000000,
980b57cec5SDimitry Andric     UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
990b57cec5SDimitry Andric     UNWIND_ARM64_MODE_DWARF = 0x03000000,
1000b57cec5SDimitry Andric     UNWIND_ARM64_MODE_FRAME = 0x04000000,
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
1030b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
1040b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
1050b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
1060b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
1070b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
1080b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
1090b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
1100b57cec5SDimitry Andric     UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric     UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
1130b57cec5SDimitry Andric     UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
1140b57cec5SDimitry Andric };
1150b57cec5SDimitry Andric 
FLAGS_ANONYMOUS_ENUM()1160b57cec5SDimitry Andric FLAGS_ANONYMOUS_ENUM(){
1170b57cec5SDimitry Andric     UNWIND_ARM_MODE_MASK = 0x0F000000,
1180b57cec5SDimitry Andric     UNWIND_ARM_MODE_FRAME = 0x01000000,
1190b57cec5SDimitry Andric     UNWIND_ARM_MODE_FRAME_D = 0x02000000,
1200b57cec5SDimitry Andric     UNWIND_ARM_MODE_DWARF = 0x04000000,
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric     UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
1250b57cec5SDimitry Andric     UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
1260b57cec5SDimitry Andric     UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric     UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
1290b57cec5SDimitry Andric     UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
1300b57cec5SDimitry Andric     UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
1310b57cec5SDimitry Andric     UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
1320b57cec5SDimitry Andric     UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric     UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric     UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
1370b57cec5SDimitry Andric };
1380b57cec5SDimitry Andric }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric #ifndef UNWIND_SECOND_LEVEL_REGULAR
1410b57cec5SDimitry Andric #define UNWIND_SECOND_LEVEL_REGULAR 2
1420b57cec5SDimitry Andric #endif
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric #ifndef UNWIND_SECOND_LEVEL_COMPRESSED
1450b57cec5SDimitry Andric #define UNWIND_SECOND_LEVEL_COMPRESSED 3
1460b57cec5SDimitry Andric #endif
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric #ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
1490b57cec5SDimitry Andric #define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
1500b57cec5SDimitry Andric #endif
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric #ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
1530b57cec5SDimitry Andric #define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry)                     \
1540b57cec5SDimitry Andric   ((entry >> 24) & 0xFF)
1550b57cec5SDimitry Andric #endif
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric #define EXTRACT_BITS(value, mask)                                              \
15806c3fb27SDimitry Andric   ((value >> llvm::countr_zero(static_cast<uint32_t>(mask))) &                 \
159bdd1243dSDimitry Andric    (((1 << llvm::popcount(static_cast<uint32_t>(mask)))) - 1))
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric // constructor
1620b57cec5SDimitry Andric 
CompactUnwindInfo(ObjectFile & objfile,SectionSP & section_sp)1630b57cec5SDimitry Andric CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP &section_sp)
1640b57cec5SDimitry Andric     : m_objfile(objfile), m_section_sp(section_sp),
1650b57cec5SDimitry Andric       m_section_contents_if_encrypted(), m_mutex(), m_indexes(),
1660b57cec5SDimitry Andric       m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(),
1670b57cec5SDimitry Andric       m_unwindinfo_data_computed(false), m_unwind_header() {}
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric // destructor
1700b57cec5SDimitry Andric 
171fe6060f1SDimitry Andric CompactUnwindInfo::~CompactUnwindInfo() = default;
1720b57cec5SDimitry Andric 
GetUnwindPlan(Target & target,Address addr,UnwindPlan & unwind_plan)1730b57cec5SDimitry Andric bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
1740b57cec5SDimitry Andric                                       UnwindPlan &unwind_plan) {
1750b57cec5SDimitry Andric   if (!IsValid(target.GetProcessSP())) {
1760b57cec5SDimitry Andric     return false;
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric   FunctionInfo function_info;
1790b57cec5SDimitry Andric   if (GetCompactUnwindInfoForFunction(target, addr, function_info)) {
1800b57cec5SDimitry Andric     // shortcut return for functions that have no compact unwind
1810b57cec5SDimitry Andric     if (function_info.encoding == 0)
1820b57cec5SDimitry Andric       return false;
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric     if (ArchSpec arch = m_objfile.GetArchitecture()) {
1850b57cec5SDimitry Andric 
18681ad6265SDimitry Andric       Log *log = GetLog(LLDBLog::Unwind);
1870b57cec5SDimitry Andric       if (log && log->GetVerbose()) {
1880b57cec5SDimitry Andric         StreamString strm;
1890b57cec5SDimitry Andric         addr.Dump(
1900b57cec5SDimitry Andric             &strm, nullptr,
1910b57cec5SDimitry Andric             Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments,
1920b57cec5SDimitry Andric             Address::DumpStyle::DumpStyleFileAddress,
1930b57cec5SDimitry Andric             arch.GetAddressByteSize());
1949dba64beSDimitry Andric         LLDB_LOGF(log, "Got compact unwind encoding 0x%x for function %s",
1950b57cec5SDimitry Andric                   function_info.encoding, strm.GetData());
1960b57cec5SDimitry Andric       }
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric       if (function_info.valid_range_offset_start != 0 &&
1990b57cec5SDimitry Andric           function_info.valid_range_offset_end != 0) {
2000b57cec5SDimitry Andric         SectionList *sl = m_objfile.GetSectionList();
2010b57cec5SDimitry Andric         if (sl) {
2020b57cec5SDimitry Andric           addr_t func_range_start_file_addr =
2030b57cec5SDimitry Andric               function_info.valid_range_offset_start +
2040b57cec5SDimitry Andric               m_objfile.GetBaseAddress().GetFileAddress();
2050b57cec5SDimitry Andric           AddressRange func_range(func_range_start_file_addr,
2060b57cec5SDimitry Andric                                   function_info.valid_range_offset_end -
2070b57cec5SDimitry Andric                                       function_info.valid_range_offset_start,
2080b57cec5SDimitry Andric                                   sl);
2090b57cec5SDimitry Andric           unwind_plan.SetPlanValidAddressRange(func_range);
2100b57cec5SDimitry Andric         }
2110b57cec5SDimitry Andric       }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric       if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
2140b57cec5SDimitry Andric         return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
2150b57cec5SDimitry Andric                                        addr);
2160b57cec5SDimitry Andric       }
2179dba64beSDimitry Andric       if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
2189dba64beSDimitry Andric           arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {
2190b57cec5SDimitry Andric         return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
2200b57cec5SDimitry Andric       }
2210b57cec5SDimitry Andric       if (arch.GetTriple().getArch() == llvm::Triple::x86) {
2220b57cec5SDimitry Andric         return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
2230b57cec5SDimitry Andric       }
2240b57cec5SDimitry Andric       if (arch.GetTriple().getArch() == llvm::Triple::arm ||
2250b57cec5SDimitry Andric           arch.GetTriple().getArch() == llvm::Triple::thumb) {
2260b57cec5SDimitry Andric         return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);
2270b57cec5SDimitry Andric       }
2280b57cec5SDimitry Andric     }
2290b57cec5SDimitry Andric   }
2300b57cec5SDimitry Andric   return false;
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
IsValid(const ProcessSP & process_sp)2330b57cec5SDimitry Andric bool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
2340b57cec5SDimitry Andric   if (m_section_sp.get() == nullptr)
2350b57cec5SDimitry Andric     return false;
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric   if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
2380b57cec5SDimitry Andric     return true;
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   ScanIndex(process_sp);
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric 
ScanIndex(const ProcessSP & process_sp)2450b57cec5SDimitry Andric void CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
2460b57cec5SDimitry Andric   std::lock_guard<std::mutex> guard(m_mutex);
2470b57cec5SDimitry Andric   if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
2480b57cec5SDimitry Andric     return;
2490b57cec5SDimitry Andric 
2500b57cec5SDimitry Andric   // We can't read the index for some reason.
2510b57cec5SDimitry Andric   if (m_indexes_computed == eLazyBoolNo) {
2520b57cec5SDimitry Andric     return;
2530b57cec5SDimitry Andric   }
2540b57cec5SDimitry Andric 
25581ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Unwind);
2560b57cec5SDimitry Andric   if (log)
2570b57cec5SDimitry Andric     m_objfile.GetModule()->LogMessage(
2580b57cec5SDimitry Andric         log, "Reading compact unwind first-level indexes");
2590b57cec5SDimitry Andric 
2600b57cec5SDimitry Andric   if (!m_unwindinfo_data_computed) {
2610b57cec5SDimitry Andric     if (m_section_sp->IsEncrypted()) {
2620b57cec5SDimitry Andric       // Can't get section contents of a protected/encrypted section until we
2630b57cec5SDimitry Andric       // have a live process and can read them out of memory.
2640b57cec5SDimitry Andric       if (process_sp.get() == nullptr)
2650b57cec5SDimitry Andric         return;
2660b57cec5SDimitry Andric       m_section_contents_if_encrypted =
2670b57cec5SDimitry Andric           std::make_shared<DataBufferHeap>(m_section_sp->GetByteSize(), 0);
2680b57cec5SDimitry Andric       Status error;
2690b57cec5SDimitry Andric       if (process_sp->ReadMemory(
2700b57cec5SDimitry Andric               m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
2710b57cec5SDimitry Andric               m_section_contents_if_encrypted->GetBytes(),
2720b57cec5SDimitry Andric               m_section_sp->GetByteSize(),
2730b57cec5SDimitry Andric               error) == m_section_sp->GetByteSize() &&
2740b57cec5SDimitry Andric           error.Success()) {
2750b57cec5SDimitry Andric         m_unwindinfo_data.SetAddressByteSize(
2760b57cec5SDimitry Andric             process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
2770b57cec5SDimitry Andric         m_unwindinfo_data.SetByteOrder(
2780b57cec5SDimitry Andric             process_sp->GetTarget().GetArchitecture().GetByteOrder());
2790b57cec5SDimitry Andric         m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);
2800b57cec5SDimitry Andric       }
2810b57cec5SDimitry Andric     } else {
2820b57cec5SDimitry Andric       m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
2830b57cec5SDimitry Andric     }
2840b57cec5SDimitry Andric     if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
2850b57cec5SDimitry Andric       return;
2860b57cec5SDimitry Andric     m_unwindinfo_data_computed = true;
2870b57cec5SDimitry Andric   }
2880b57cec5SDimitry Andric 
2890b57cec5SDimitry Andric   if (m_unwindinfo_data.GetByteSize() > 0) {
2900b57cec5SDimitry Andric     offset_t offset = 0;
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric     // struct unwind_info_section_header
2930b57cec5SDimitry Andric     // {
2940b57cec5SDimitry Andric     // uint32_t    version;            // UNWIND_SECTION_VERSION
2950b57cec5SDimitry Andric     // uint32_t    commonEncodingsArraySectionOffset;
2960b57cec5SDimitry Andric     // uint32_t    commonEncodingsArrayCount;
2970b57cec5SDimitry Andric     // uint32_t    personalityArraySectionOffset;
2980b57cec5SDimitry Andric     // uint32_t    personalityArrayCount;
2990b57cec5SDimitry Andric     // uint32_t    indexSectionOffset;
3000b57cec5SDimitry Andric     // uint32_t    indexCount;
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric     m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
3030b57cec5SDimitry Andric     m_unwind_header.common_encodings_array_offset =
3040b57cec5SDimitry Andric         m_unwindinfo_data.GetU32(&offset);
3050b57cec5SDimitry Andric     m_unwind_header.common_encodings_array_count =
3060b57cec5SDimitry Andric         m_unwindinfo_data.GetU32(&offset);
3070b57cec5SDimitry Andric     m_unwind_header.personality_array_offset =
3080b57cec5SDimitry Andric         m_unwindinfo_data.GetU32(&offset);
3090b57cec5SDimitry Andric     m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
3100b57cec5SDimitry Andric     uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric     uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric     if (m_unwind_header.common_encodings_array_offset >
3150b57cec5SDimitry Andric             m_unwindinfo_data.GetByteSize() ||
3160b57cec5SDimitry Andric         m_unwind_header.personality_array_offset >
3170b57cec5SDimitry Andric             m_unwindinfo_data.GetByteSize() ||
3180b57cec5SDimitry Andric         indexSectionOffset > m_unwindinfo_data.GetByteSize() ||
3190b57cec5SDimitry Andric         offset > m_unwindinfo_data.GetByteSize()) {
32081ad6265SDimitry Andric       Debugger::ReportError(
32181ad6265SDimitry Andric           "Invalid offset encountered in compact unwind info, skipping");
3220b57cec5SDimitry Andric       // don't trust anything from this compact_unwind section if it looks
3230b57cec5SDimitry Andric       // blatantly invalid data in the header.
3240b57cec5SDimitry Andric       m_indexes_computed = eLazyBoolNo;
3250b57cec5SDimitry Andric       return;
3260b57cec5SDimitry Andric     }
3270b57cec5SDimitry Andric 
3280b57cec5SDimitry Andric     // Parse the basic information from the indexes We wait to scan the second
3290b57cec5SDimitry Andric     // level page info until it's needed
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric     // struct unwind_info_section_header_index_entry {
3320b57cec5SDimitry Andric     //     uint32_t        functionOffset;
3330b57cec5SDimitry Andric     //     uint32_t        secondLevelPagesSectionOffset;
3340b57cec5SDimitry Andric     //     uint32_t        lsdaIndexArraySectionOffset;
3350b57cec5SDimitry Andric     // };
3360b57cec5SDimitry Andric 
3370b57cec5SDimitry Andric     bool clear_address_zeroth_bit = false;
3380b57cec5SDimitry Andric     if (ArchSpec arch = m_objfile.GetArchitecture()) {
3390b57cec5SDimitry Andric       if (arch.GetTriple().getArch() == llvm::Triple::arm ||
3400b57cec5SDimitry Andric           arch.GetTriple().getArch() == llvm::Triple::thumb)
3410b57cec5SDimitry Andric         clear_address_zeroth_bit = true;
3420b57cec5SDimitry Andric     }
3430b57cec5SDimitry Andric 
3440b57cec5SDimitry Andric     offset = indexSectionOffset;
3450b57cec5SDimitry Andric     for (uint32_t idx = 0; idx < indexCount; idx++) {
3460b57cec5SDimitry Andric       uint32_t function_offset =
3470b57cec5SDimitry Andric           m_unwindinfo_data.GetU32(&offset); // functionOffset
3480b57cec5SDimitry Andric       uint32_t second_level_offset =
3490b57cec5SDimitry Andric           m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
3500b57cec5SDimitry Andric       uint32_t lsda_offset =
3510b57cec5SDimitry Andric           m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric       if (second_level_offset > m_section_sp->GetByteSize() ||
3540b57cec5SDimitry Andric           lsda_offset > m_section_sp->GetByteSize()) {
3550b57cec5SDimitry Andric         m_indexes_computed = eLazyBoolNo;
3560b57cec5SDimitry Andric       }
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric       if (clear_address_zeroth_bit)
3590b57cec5SDimitry Andric         function_offset &= ~1ull;
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric       UnwindIndex this_index;
3620b57cec5SDimitry Andric       this_index.function_offset = function_offset;
3630b57cec5SDimitry Andric       this_index.second_level = second_level_offset;
3640b57cec5SDimitry Andric       this_index.lsda_array_start = lsda_offset;
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric       if (m_indexes.size() > 0) {
3670b57cec5SDimitry Andric         m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
3680b57cec5SDimitry Andric       }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric       if (second_level_offset == 0) {
3710b57cec5SDimitry Andric         this_index.sentinal_entry = true;
3720b57cec5SDimitry Andric       }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric       m_indexes.push_back(this_index);
3750b57cec5SDimitry Andric     }
3760b57cec5SDimitry Andric     m_indexes_computed = eLazyBoolYes;
3770b57cec5SDimitry Andric   } else {
3780b57cec5SDimitry Andric     m_indexes_computed = eLazyBoolNo;
3790b57cec5SDimitry Andric   }
3800b57cec5SDimitry Andric }
3810b57cec5SDimitry Andric 
GetLSDAForFunctionOffset(uint32_t lsda_offset,uint32_t lsda_count,uint32_t function_offset)3820b57cec5SDimitry Andric uint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
3830b57cec5SDimitry Andric                                                      uint32_t lsda_count,
3840b57cec5SDimitry Andric                                                      uint32_t function_offset) {
3850b57cec5SDimitry Andric   // struct unwind_info_section_header_lsda_index_entry {
3860b57cec5SDimitry Andric   //         uint32_t        functionOffset;
3870b57cec5SDimitry Andric   //         uint32_t        lsdaOffset;
3880b57cec5SDimitry Andric   // };
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric   offset_t first_entry = lsda_offset;
3910b57cec5SDimitry Andric   uint32_t low = 0;
3920b57cec5SDimitry Andric   uint32_t high = lsda_count;
3930b57cec5SDimitry Andric   while (low < high) {
3940b57cec5SDimitry Andric     uint32_t mid = (low + high) / 2;
3950b57cec5SDimitry Andric     offset_t offset = first_entry + (mid * 8);
3960b57cec5SDimitry Andric     uint32_t mid_func_offset =
3970b57cec5SDimitry Andric         m_unwindinfo_data.GetU32(&offset); // functionOffset
3980b57cec5SDimitry Andric     uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
3990b57cec5SDimitry Andric     if (mid_func_offset == function_offset) {
4000b57cec5SDimitry Andric       return mid_lsda_offset;
4010b57cec5SDimitry Andric     }
4020b57cec5SDimitry Andric     if (mid_func_offset < function_offset) {
4030b57cec5SDimitry Andric       low = mid + 1;
4040b57cec5SDimitry Andric     } else {
4050b57cec5SDimitry Andric       high = mid;
4060b57cec5SDimitry Andric     }
4070b57cec5SDimitry Andric   }
4080b57cec5SDimitry Andric   return 0;
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric 
BinarySearchRegularSecondPage(uint32_t entry_page_offset,uint32_t entry_count,uint32_t function_offset,uint32_t * entry_func_start_offset,uint32_t * entry_func_end_offset)4110b57cec5SDimitry Andric lldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(
4120b57cec5SDimitry Andric     uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,
4130b57cec5SDimitry Andric     uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
4140b57cec5SDimitry Andric   // typedef uint32_t compact_unwind_encoding_t;
4150b57cec5SDimitry Andric   // struct unwind_info_regular_second_level_entry {
4160b57cec5SDimitry Andric   //     uint32_t                    functionOffset;
4170b57cec5SDimitry Andric   //     compact_unwind_encoding_t    encoding;
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric   offset_t first_entry = entry_page_offset;
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric   uint32_t low = 0;
4220b57cec5SDimitry Andric   uint32_t high = entry_count;
4230b57cec5SDimitry Andric   uint32_t last = high - 1;
4240b57cec5SDimitry Andric   while (low < high) {
4250b57cec5SDimitry Andric     uint32_t mid = (low + high) / 2;
4260b57cec5SDimitry Andric     offset_t offset = first_entry + (mid * 8);
4270b57cec5SDimitry Andric     uint32_t mid_func_offset =
4280b57cec5SDimitry Andric         m_unwindinfo_data.GetU32(&offset); // functionOffset
4290b57cec5SDimitry Andric     uint32_t next_func_offset = 0;
4300b57cec5SDimitry Andric     if (mid < last) {
4310b57cec5SDimitry Andric       offset = first_entry + ((mid + 1) * 8);
4320b57cec5SDimitry Andric       next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
4330b57cec5SDimitry Andric     }
4340b57cec5SDimitry Andric     if (mid_func_offset <= function_offset) {
4350b57cec5SDimitry Andric       if (mid == last || (next_func_offset > function_offset)) {
4360b57cec5SDimitry Andric         if (entry_func_start_offset)
4370b57cec5SDimitry Andric           *entry_func_start_offset = mid_func_offset;
4380b57cec5SDimitry Andric         if (mid != last && entry_func_end_offset)
4390b57cec5SDimitry Andric           *entry_func_end_offset = next_func_offset;
4400b57cec5SDimitry Andric         return first_entry + (mid * 8);
4410b57cec5SDimitry Andric       } else {
4420b57cec5SDimitry Andric         low = mid + 1;
4430b57cec5SDimitry Andric       }
4440b57cec5SDimitry Andric     } else {
4450b57cec5SDimitry Andric       high = mid;
4460b57cec5SDimitry Andric     }
4470b57cec5SDimitry Andric   }
4480b57cec5SDimitry Andric   return LLDB_INVALID_OFFSET;
4490b57cec5SDimitry Andric }
4500b57cec5SDimitry Andric 
BinarySearchCompressedSecondPage(uint32_t entry_page_offset,uint32_t entry_count,uint32_t function_offset_to_find,uint32_t function_offset_base,uint32_t * entry_func_start_offset,uint32_t * entry_func_end_offset)4510b57cec5SDimitry Andric uint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(
4520b57cec5SDimitry Andric     uint32_t entry_page_offset, uint32_t entry_count,
4530b57cec5SDimitry Andric     uint32_t function_offset_to_find, uint32_t function_offset_base,
4540b57cec5SDimitry Andric     uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
4550b57cec5SDimitry Andric   offset_t first_entry = entry_page_offset;
4560b57cec5SDimitry Andric 
4570b57cec5SDimitry Andric   uint32_t low = 0;
4580b57cec5SDimitry Andric   uint32_t high = entry_count;
4590b57cec5SDimitry Andric   uint32_t last = high - 1;
4600b57cec5SDimitry Andric   while (low < high) {
4610b57cec5SDimitry Andric     uint32_t mid = (low + high) / 2;
4620b57cec5SDimitry Andric     offset_t offset = first_entry + (mid * 4);
4630b57cec5SDimitry Andric     uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
4640b57cec5SDimitry Andric     uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
4650b57cec5SDimitry Andric     mid_func_offset += function_offset_base;
4660b57cec5SDimitry Andric     uint32_t next_func_offset = 0;
4670b57cec5SDimitry Andric     if (mid < last) {
4680b57cec5SDimitry Andric       offset = first_entry + ((mid + 1) * 4);
4690b57cec5SDimitry Andric       uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
4700b57cec5SDimitry Andric       next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);
4710b57cec5SDimitry Andric       next_func_offset += function_offset_base;
4720b57cec5SDimitry Andric     }
4730b57cec5SDimitry Andric     if (mid_func_offset <= function_offset_to_find) {
4740b57cec5SDimitry Andric       if (mid == last || (next_func_offset > function_offset_to_find)) {
4750b57cec5SDimitry Andric         if (entry_func_start_offset)
4760b57cec5SDimitry Andric           *entry_func_start_offset = mid_func_offset;
4770b57cec5SDimitry Andric         if (mid != last && entry_func_end_offset)
4780b57cec5SDimitry Andric           *entry_func_end_offset = next_func_offset;
4790b57cec5SDimitry Andric         return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
4800b57cec5SDimitry Andric       } else {
4810b57cec5SDimitry Andric         low = mid + 1;
4820b57cec5SDimitry Andric       }
4830b57cec5SDimitry Andric     } else {
4840b57cec5SDimitry Andric       high = mid;
4850b57cec5SDimitry Andric     }
4860b57cec5SDimitry Andric   }
4870b57cec5SDimitry Andric 
4880b57cec5SDimitry Andric   return UINT32_MAX;
4890b57cec5SDimitry Andric }
4900b57cec5SDimitry Andric 
GetCompactUnwindInfoForFunction(Target & target,Address address,FunctionInfo & unwind_info)4910b57cec5SDimitry Andric bool CompactUnwindInfo::GetCompactUnwindInfoForFunction(
4920b57cec5SDimitry Andric     Target &target, Address address, FunctionInfo &unwind_info) {
4930b57cec5SDimitry Andric   unwind_info.encoding = 0;
4940b57cec5SDimitry Andric   unwind_info.lsda_address.Clear();
4950b57cec5SDimitry Andric   unwind_info.personality_ptr_address.Clear();
4960b57cec5SDimitry Andric 
4970b57cec5SDimitry Andric   if (!IsValid(target.GetProcessSP()))
4980b57cec5SDimitry Andric     return false;
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
5010b57cec5SDimitry Andric   SectionList *sl = m_objfile.GetSectionList();
5020b57cec5SDimitry Andric   if (sl) {
5030b57cec5SDimitry Andric     SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
5040b57cec5SDimitry Andric     if (text_sect.get()) {
5050b57cec5SDimitry Andric       text_section_file_address = text_sect->GetFileAddress();
5060b57cec5SDimitry Andric     }
5070b57cec5SDimitry Andric   }
5080b57cec5SDimitry Andric   if (text_section_file_address == LLDB_INVALID_ADDRESS)
5090b57cec5SDimitry Andric     return false;
5100b57cec5SDimitry Andric 
5110b57cec5SDimitry Andric   addr_t function_offset =
5120b57cec5SDimitry Andric       address.GetFileAddress() - m_objfile.GetBaseAddress().GetFileAddress();
5130b57cec5SDimitry Andric 
5140b57cec5SDimitry Andric   UnwindIndex key;
5150b57cec5SDimitry Andric   key.function_offset = function_offset;
5160b57cec5SDimitry Andric 
5170b57cec5SDimitry Andric   std::vector<UnwindIndex>::const_iterator it;
518bdd1243dSDimitry Andric   it = llvm::lower_bound(m_indexes, key);
5190b57cec5SDimitry Andric   if (it == m_indexes.end()) {
5200b57cec5SDimitry Andric     return false;
5210b57cec5SDimitry Andric   }
5220b57cec5SDimitry Andric 
5230b57cec5SDimitry Andric   if (it->function_offset != key.function_offset) {
5240b57cec5SDimitry Andric     if (it != m_indexes.begin())
5250b57cec5SDimitry Andric       --it;
5260b57cec5SDimitry Andric   }
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric   if (it->sentinal_entry) {
5290b57cec5SDimitry Andric     return false;
5300b57cec5SDimitry Andric   }
5310b57cec5SDimitry Andric 
5320b57cec5SDimitry Andric   auto next_it = it + 1;
5330b57cec5SDimitry Andric   if (next_it != m_indexes.end()) {
5340b57cec5SDimitry Andric     // initialize the function offset end range to be the start of the next
5350b57cec5SDimitry Andric     // index offset.  If we find an entry which is at the end of the index
5360b57cec5SDimitry Andric     // table, this will establish the range end.
5370b57cec5SDimitry Andric     unwind_info.valid_range_offset_end = next_it->function_offset;
5380b57cec5SDimitry Andric   }
5390b57cec5SDimitry Andric 
5400b57cec5SDimitry Andric   offset_t second_page_offset = it->second_level;
5410b57cec5SDimitry Andric   offset_t lsda_array_start = it->lsda_array_start;
5420b57cec5SDimitry Andric   offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
5430b57cec5SDimitry Andric 
5440b57cec5SDimitry Andric   offset_t offset = second_page_offset;
5450b57cec5SDimitry Andric   uint32_t kind = m_unwindinfo_data.GetU32(
5460b57cec5SDimitry Andric       &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric   if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
5490b57cec5SDimitry Andric     // struct unwind_info_regular_second_level_page_header {
5500b57cec5SDimitry Andric     //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_REGULAR
5510b57cec5SDimitry Andric     //     uint16_t    entryPageOffset;
5520b57cec5SDimitry Andric     //     uint16_t    entryCount;
5530b57cec5SDimitry Andric 
5540b57cec5SDimitry Andric     // typedef uint32_t compact_unwind_encoding_t;
5550b57cec5SDimitry Andric     // struct unwind_info_regular_second_level_entry {
5560b57cec5SDimitry Andric     //     uint32_t                    functionOffset;
5570b57cec5SDimitry Andric     //     compact_unwind_encoding_t    encoding;
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric     uint16_t entry_page_offset =
5600b57cec5SDimitry Andric         m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
5610b57cec5SDimitry Andric     uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
5620b57cec5SDimitry Andric 
5630b57cec5SDimitry Andric     offset_t entry_offset = BinarySearchRegularSecondPage(
5640b57cec5SDimitry Andric         second_page_offset + entry_page_offset, entry_count, function_offset,
5650b57cec5SDimitry Andric         &unwind_info.valid_range_offset_start,
5660b57cec5SDimitry Andric         &unwind_info.valid_range_offset_end);
5670b57cec5SDimitry Andric     if (entry_offset == LLDB_INVALID_OFFSET) {
5680b57cec5SDimitry Andric       return false;
5690b57cec5SDimitry Andric     }
5700b57cec5SDimitry Andric     entry_offset += 4; // skip over functionOffset
5710b57cec5SDimitry Andric     unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
5720b57cec5SDimitry Andric     if (unwind_info.encoding & UNWIND_HAS_LSDA) {
5730b57cec5SDimitry Andric       SectionList *sl = m_objfile.GetSectionList();
5740b57cec5SDimitry Andric       if (sl) {
5750b57cec5SDimitry Andric         uint32_t lsda_offset = GetLSDAForFunctionOffset(
5760b57cec5SDimitry Andric             lsda_array_start, lsda_array_count, function_offset);
5770b57cec5SDimitry Andric         addr_t objfile_base_address =
5780b57cec5SDimitry Andric             m_objfile.GetBaseAddress().GetFileAddress();
5790b57cec5SDimitry Andric         unwind_info.lsda_address.ResolveAddressUsingFileSections(
5800b57cec5SDimitry Andric             objfile_base_address + lsda_offset, sl);
5810b57cec5SDimitry Andric       }
5820b57cec5SDimitry Andric     }
5830b57cec5SDimitry Andric     if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
5840b57cec5SDimitry Andric       uint32_t personality_index =
5850b57cec5SDimitry Andric           EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric       if (personality_index > 0) {
5880b57cec5SDimitry Andric         personality_index--;
5890b57cec5SDimitry Andric         if (personality_index < m_unwind_header.personality_array_count) {
5900b57cec5SDimitry Andric           offset_t offset = m_unwind_header.personality_array_offset;
5910b57cec5SDimitry Andric           offset += 4 * personality_index;
5920b57cec5SDimitry Andric           SectionList *sl = m_objfile.GetSectionList();
5930b57cec5SDimitry Andric           if (sl) {
5940b57cec5SDimitry Andric             uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
5950b57cec5SDimitry Andric             addr_t objfile_base_address =
5960b57cec5SDimitry Andric                 m_objfile.GetBaseAddress().GetFileAddress();
5970b57cec5SDimitry Andric             unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
5980b57cec5SDimitry Andric                 objfile_base_address + personality_offset, sl);
5990b57cec5SDimitry Andric           }
6000b57cec5SDimitry Andric         }
6010b57cec5SDimitry Andric       }
6020b57cec5SDimitry Andric     }
6030b57cec5SDimitry Andric     return true;
6040b57cec5SDimitry Andric   } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
6050b57cec5SDimitry Andric     // struct unwind_info_compressed_second_level_page_header {
6060b57cec5SDimitry Andric     //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_COMPRESSED
6070b57cec5SDimitry Andric     //     uint16_t    entryPageOffset;         // offset from this 2nd lvl page
6080b57cec5SDimitry Andric     //     idx to array of entries
6090b57cec5SDimitry Andric     //                                          // (an entry has a function
6100b57cec5SDimitry Andric     //                                          offset and index into the
6110b57cec5SDimitry Andric     //                                          encodings)
6120b57cec5SDimitry Andric     //                                          // NB function offset from the
6130b57cec5SDimitry Andric     //                                          entry in the compressed page
6140b57cec5SDimitry Andric     //                                          // must be added to the index's
6150b57cec5SDimitry Andric     //                                          functionOffset value.
6160b57cec5SDimitry Andric     //     uint16_t    entryCount;
6170b57cec5SDimitry Andric     //     uint16_t    encodingsPageOffset;     // offset from this 2nd lvl page
6180b57cec5SDimitry Andric     //     idx to array of encodings
6190b57cec5SDimitry Andric     //     uint16_t    encodingsCount;
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric     uint16_t entry_page_offset =
6220b57cec5SDimitry Andric         m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
6230b57cec5SDimitry Andric     uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
6240b57cec5SDimitry Andric     uint16_t encodings_page_offset =
6250b57cec5SDimitry Andric         m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
6260b57cec5SDimitry Andric     uint16_t encodings_count =
6270b57cec5SDimitry Andric         m_unwindinfo_data.GetU16(&offset); // encodingsCount
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric     uint32_t encoding_index = BinarySearchCompressedSecondPage(
6300b57cec5SDimitry Andric         second_page_offset + entry_page_offset, entry_count, function_offset,
6310b57cec5SDimitry Andric         it->function_offset, &unwind_info.valid_range_offset_start,
6320b57cec5SDimitry Andric         &unwind_info.valid_range_offset_end);
6330b57cec5SDimitry Andric     if (encoding_index == UINT32_MAX ||
6340b57cec5SDimitry Andric         encoding_index >=
6350b57cec5SDimitry Andric             encodings_count + m_unwind_header.common_encodings_array_count) {
6360b57cec5SDimitry Andric       return false;
6370b57cec5SDimitry Andric     }
6380b57cec5SDimitry Andric     uint32_t encoding = 0;
6390b57cec5SDimitry Andric     if (encoding_index < m_unwind_header.common_encodings_array_count) {
6400b57cec5SDimitry Andric       offset = m_unwind_header.common_encodings_array_offset +
6410b57cec5SDimitry Andric                (encoding_index * sizeof(uint32_t));
6420b57cec5SDimitry Andric       encoding = m_unwindinfo_data.GetU32(
6430b57cec5SDimitry Andric           &offset); // encoding entry from the commonEncodingsArray
6440b57cec5SDimitry Andric     } else {
6450b57cec5SDimitry Andric       uint32_t page_specific_entry_index =
6460b57cec5SDimitry Andric           encoding_index - m_unwind_header.common_encodings_array_count;
6470b57cec5SDimitry Andric       offset = second_page_offset + encodings_page_offset +
6480b57cec5SDimitry Andric                (page_specific_entry_index * sizeof(uint32_t));
6490b57cec5SDimitry Andric       encoding = m_unwindinfo_data.GetU32(
6500b57cec5SDimitry Andric           &offset); // encoding entry from the page-specific encoding array
6510b57cec5SDimitry Andric     }
6520b57cec5SDimitry Andric     if (encoding == 0)
6530b57cec5SDimitry Andric       return false;
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric     unwind_info.encoding = encoding;
6560b57cec5SDimitry Andric     if (unwind_info.encoding & UNWIND_HAS_LSDA) {
6570b57cec5SDimitry Andric       SectionList *sl = m_objfile.GetSectionList();
6580b57cec5SDimitry Andric       if (sl) {
6590b57cec5SDimitry Andric         uint32_t lsda_offset = GetLSDAForFunctionOffset(
6600b57cec5SDimitry Andric             lsda_array_start, lsda_array_count, function_offset);
6610b57cec5SDimitry Andric         addr_t objfile_base_address =
6620b57cec5SDimitry Andric             m_objfile.GetBaseAddress().GetFileAddress();
6630b57cec5SDimitry Andric         unwind_info.lsda_address.ResolveAddressUsingFileSections(
6640b57cec5SDimitry Andric             objfile_base_address + lsda_offset, sl);
6650b57cec5SDimitry Andric       }
6660b57cec5SDimitry Andric     }
6670b57cec5SDimitry Andric     if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
6680b57cec5SDimitry Andric       uint32_t personality_index =
6690b57cec5SDimitry Andric           EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric       if (personality_index > 0) {
6720b57cec5SDimitry Andric         personality_index--;
6730b57cec5SDimitry Andric         if (personality_index < m_unwind_header.personality_array_count) {
6740b57cec5SDimitry Andric           offset_t offset = m_unwind_header.personality_array_offset;
6750b57cec5SDimitry Andric           offset += 4 * personality_index;
6760b57cec5SDimitry Andric           SectionList *sl = m_objfile.GetSectionList();
6770b57cec5SDimitry Andric           if (sl) {
6780b57cec5SDimitry Andric             uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
6790b57cec5SDimitry Andric             addr_t objfile_base_address =
6800b57cec5SDimitry Andric                 m_objfile.GetBaseAddress().GetFileAddress();
6810b57cec5SDimitry Andric             unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
6820b57cec5SDimitry Andric                 objfile_base_address + personality_offset, sl);
6830b57cec5SDimitry Andric           }
6840b57cec5SDimitry Andric         }
6850b57cec5SDimitry Andric       }
6860b57cec5SDimitry Andric     }
6870b57cec5SDimitry Andric     return true;
6880b57cec5SDimitry Andric   }
6890b57cec5SDimitry Andric   return false;
6900b57cec5SDimitry Andric }
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric enum x86_64_eh_regnum {
6930b57cec5SDimitry Andric   rax = 0,
6940b57cec5SDimitry Andric   rdx = 1,
6950b57cec5SDimitry Andric   rcx = 2,
6960b57cec5SDimitry Andric   rbx = 3,
6970b57cec5SDimitry Andric   rsi = 4,
6980b57cec5SDimitry Andric   rdi = 5,
6990b57cec5SDimitry Andric   rbp = 6,
7000b57cec5SDimitry Andric   rsp = 7,
7010b57cec5SDimitry Andric   r8 = 8,
7020b57cec5SDimitry Andric   r9 = 9,
7030b57cec5SDimitry Andric   r10 = 10,
7040b57cec5SDimitry Andric   r11 = 11,
7050b57cec5SDimitry Andric   r12 = 12,
7060b57cec5SDimitry Andric   r13 = 13,
7070b57cec5SDimitry Andric   r14 = 14,
7080b57cec5SDimitry Andric   r15 = 15,
7090b57cec5SDimitry Andric   rip = 16 // this is officially the Return Address register number, but close
7100b57cec5SDimitry Andric            // enough
7110b57cec5SDimitry Andric };
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric // Convert the compact_unwind_info.h register numbering scheme to
7140b57cec5SDimitry Andric // eRegisterKindEHFrame (eh_frame) register numbering scheme.
translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno)7150b57cec5SDimitry Andric uint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {
7160b57cec5SDimitry Andric   switch (unwind_regno) {
7170b57cec5SDimitry Andric   case UNWIND_X86_64_REG_RBX:
7180b57cec5SDimitry Andric     return x86_64_eh_regnum::rbx;
7190b57cec5SDimitry Andric   case UNWIND_X86_64_REG_R12:
7200b57cec5SDimitry Andric     return x86_64_eh_regnum::r12;
7210b57cec5SDimitry Andric   case UNWIND_X86_64_REG_R13:
7220b57cec5SDimitry Andric     return x86_64_eh_regnum::r13;
7230b57cec5SDimitry Andric   case UNWIND_X86_64_REG_R14:
7240b57cec5SDimitry Andric     return x86_64_eh_regnum::r14;
7250b57cec5SDimitry Andric   case UNWIND_X86_64_REG_R15:
7260b57cec5SDimitry Andric     return x86_64_eh_regnum::r15;
7270b57cec5SDimitry Andric   case UNWIND_X86_64_REG_RBP:
7280b57cec5SDimitry Andric     return x86_64_eh_regnum::rbp;
7290b57cec5SDimitry Andric   default:
7300b57cec5SDimitry Andric     return LLDB_INVALID_REGNUM;
7310b57cec5SDimitry Andric   }
7320b57cec5SDimitry Andric }
7330b57cec5SDimitry Andric 
CreateUnwindPlan_x86_64(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)7340b57cec5SDimitry Andric bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
7350b57cec5SDimitry Andric                                                 FunctionInfo &function_info,
7360b57cec5SDimitry Andric                                                 UnwindPlan &unwind_plan,
7370b57cec5SDimitry Andric                                                 Address pc_or_function_start) {
7380b57cec5SDimitry Andric   unwind_plan.SetSourceName("compact unwind info");
7390b57cec5SDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
7400b57cec5SDimitry Andric   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
7419dba64beSDimitry Andric   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
7420b57cec5SDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric   unwind_plan.SetLSDAAddress(function_info.lsda_address);
7450b57cec5SDimitry Andric   unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
7460b57cec5SDimitry Andric 
7470b57cec5SDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric   const int wordsize = 8;
7500b57cec5SDimitry Andric   int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
7510b57cec5SDimitry Andric   switch (mode) {
7520b57cec5SDimitry Andric   case UNWIND_X86_64_MODE_RBP_FRAME: {
7530b57cec5SDimitry Andric     row->GetCFAValue().SetIsRegisterPlusOffset(
7540b57cec5SDimitry Andric         translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),
7550b57cec5SDimitry Andric         2 * wordsize);
7560b57cec5SDimitry Andric     row->SetOffset(0);
7570b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,
7580b57cec5SDimitry Andric                                               wordsize * -2, true);
7590b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
7600b57cec5SDimitry Andric                                               wordsize * -1, true);
7610b57cec5SDimitry Andric     row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric     uint32_t saved_registers_offset =
7640b57cec5SDimitry Andric         EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
7650b57cec5SDimitry Andric 
7660b57cec5SDimitry Andric     uint32_t saved_registers_locations =
7670b57cec5SDimitry Andric         EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric     saved_registers_offset += 2;
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric     for (int i = 0; i < 5; i++) {
7720b57cec5SDimitry Andric       uint32_t regnum = saved_registers_locations & 0x7;
7730b57cec5SDimitry Andric       switch (regnum) {
7740b57cec5SDimitry Andric       case UNWIND_X86_64_REG_NONE:
7750b57cec5SDimitry Andric         break;
7760b57cec5SDimitry Andric       case UNWIND_X86_64_REG_RBX:
7770b57cec5SDimitry Andric       case UNWIND_X86_64_REG_R12:
7780b57cec5SDimitry Andric       case UNWIND_X86_64_REG_R13:
7790b57cec5SDimitry Andric       case UNWIND_X86_64_REG_R14:
7800b57cec5SDimitry Andric       case UNWIND_X86_64_REG_R15:
7810b57cec5SDimitry Andric         row->SetRegisterLocationToAtCFAPlusOffset(
7820b57cec5SDimitry Andric             translate_to_eh_frame_regnum_x86_64(regnum),
7830b57cec5SDimitry Andric             wordsize * -saved_registers_offset, true);
7840b57cec5SDimitry Andric         break;
7850b57cec5SDimitry Andric       }
7860b57cec5SDimitry Andric       saved_registers_offset--;
7870b57cec5SDimitry Andric       saved_registers_locations >>= 3;
7880b57cec5SDimitry Andric     }
7890b57cec5SDimitry Andric     unwind_plan.AppendRow(row);
7900b57cec5SDimitry Andric     return true;
7910b57cec5SDimitry Andric   } break;
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric   case UNWIND_X86_64_MODE_STACK_IND: {
7940b57cec5SDimitry Andric     // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
7950b57cec5SDimitry Andric     // this style of unwind.  It was fixed in llvm r217020. The clang in Xcode
7960b57cec5SDimitry Andric     // 7 has this fixed.
7970b57cec5SDimitry Andric     return false;
7980b57cec5SDimitry Andric   } break;
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric   case UNWIND_X86_64_MODE_STACK_IMMD: {
8010b57cec5SDimitry Andric     uint32_t stack_size = EXTRACT_BITS(function_info.encoding,
8020b57cec5SDimitry Andric                                        UNWIND_X86_64_FRAMELESS_STACK_SIZE);
8030b57cec5SDimitry Andric     uint32_t register_count = EXTRACT_BITS(
8040b57cec5SDimitry Andric         function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
8050b57cec5SDimitry Andric     uint32_t permutation = EXTRACT_BITS(
8060b57cec5SDimitry Andric         function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric     if (mode == UNWIND_X86_64_MODE_STACK_IND &&
8090b57cec5SDimitry Andric         function_info.valid_range_offset_start != 0) {
8100b57cec5SDimitry Andric       uint32_t stack_adjust = EXTRACT_BITS(
8110b57cec5SDimitry Andric           function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric       // offset into the function instructions; 0 == beginning of first
8140b57cec5SDimitry Andric       // instruction
8150b57cec5SDimitry Andric       uint32_t offset_to_subl_insn = EXTRACT_BITS(
8160b57cec5SDimitry Andric           function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
8170b57cec5SDimitry Andric 
8180b57cec5SDimitry Andric       SectionList *sl = m_objfile.GetSectionList();
8190b57cec5SDimitry Andric       if (sl) {
8200b57cec5SDimitry Andric         ProcessSP process_sp = target.GetProcessSP();
8210b57cec5SDimitry Andric         if (process_sp) {
8220b57cec5SDimitry Andric           Address subl_payload_addr(function_info.valid_range_offset_start, sl);
8230b57cec5SDimitry Andric           subl_payload_addr.Slide(offset_to_subl_insn);
8240b57cec5SDimitry Andric           Status error;
8250b57cec5SDimitry Andric           uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
8260b57cec5SDimitry Andric               subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
8270b57cec5SDimitry Andric           if (large_stack_size != 0 && error.Success()) {
8280b57cec5SDimitry Andric             // Got the large stack frame size correctly - use it
8290b57cec5SDimitry Andric             stack_size = large_stack_size + (stack_adjust * wordsize);
8300b57cec5SDimitry Andric           } else {
8310b57cec5SDimitry Andric             return false;
8320b57cec5SDimitry Andric           }
8330b57cec5SDimitry Andric         } else {
8340b57cec5SDimitry Andric           return false;
8350b57cec5SDimitry Andric         }
8360b57cec5SDimitry Andric       } else {
8370b57cec5SDimitry Andric         return false;
8380b57cec5SDimitry Andric       }
8390b57cec5SDimitry Andric     }
8400b57cec5SDimitry Andric 
8410b57cec5SDimitry Andric     int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
8420b57cec5SDimitry Andric                          ? stack_size
8430b57cec5SDimitry Andric                          : stack_size * wordsize;
8440b57cec5SDimitry Andric     row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric     row->SetOffset(0);
8470b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
8480b57cec5SDimitry Andric                                               wordsize * -1, true);
8490b57cec5SDimitry Andric     row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
8500b57cec5SDimitry Andric 
8510b57cec5SDimitry Andric     if (register_count > 0) {
8520b57cec5SDimitry Andric 
8530b57cec5SDimitry Andric       // We need to include (up to) 6 registers in 10 bits. That would be 18
8540b57cec5SDimitry Andric       // bits if we just used 3 bits per reg to indicate the order they're
8550b57cec5SDimitry Andric       // saved on the stack.
8560b57cec5SDimitry Andric       //
8570b57cec5SDimitry Andric       // This is done with Lehmer code permutation, e.g. see
8580b57cec5SDimitry Andric       // http://stackoverflow.com/questions/1506078/fast-permutation-number-
8590b57cec5SDimitry Andric       // permutation-mapping-algorithms
8600b57cec5SDimitry Andric       int permunreg[6] = {0, 0, 0, 0, 0, 0};
8610b57cec5SDimitry Andric 
8620b57cec5SDimitry Andric       // This decodes the variable-base number in the 10 bits and gives us the
8630b57cec5SDimitry Andric       // Lehmer code sequence which can then be decoded.
8640b57cec5SDimitry Andric 
8650b57cec5SDimitry Andric       switch (register_count) {
8660b57cec5SDimitry Andric       case 6:
8670b57cec5SDimitry Andric         permunreg[0] = permutation / 120; // 120 == 5!
8680b57cec5SDimitry Andric         permutation -= (permunreg[0] * 120);
8690b57cec5SDimitry Andric         permunreg[1] = permutation / 24; // 24 == 4!
8700b57cec5SDimitry Andric         permutation -= (permunreg[1] * 24);
8710b57cec5SDimitry Andric         permunreg[2] = permutation / 6; // 6 == 3!
8720b57cec5SDimitry Andric         permutation -= (permunreg[2] * 6);
8730b57cec5SDimitry Andric         permunreg[3] = permutation / 2; // 2 == 2!
8740b57cec5SDimitry Andric         permutation -= (permunreg[3] * 2);
8750b57cec5SDimitry Andric         permunreg[4] = permutation; // 1 == 1!
8760b57cec5SDimitry Andric         permunreg[5] = 0;
8770b57cec5SDimitry Andric         break;
8780b57cec5SDimitry Andric       case 5:
8790b57cec5SDimitry Andric         permunreg[0] = permutation / 120;
8800b57cec5SDimitry Andric         permutation -= (permunreg[0] * 120);
8810b57cec5SDimitry Andric         permunreg[1] = permutation / 24;
8820b57cec5SDimitry Andric         permutation -= (permunreg[1] * 24);
8830b57cec5SDimitry Andric         permunreg[2] = permutation / 6;
8840b57cec5SDimitry Andric         permutation -= (permunreg[2] * 6);
8850b57cec5SDimitry Andric         permunreg[3] = permutation / 2;
8860b57cec5SDimitry Andric         permutation -= (permunreg[3] * 2);
8870b57cec5SDimitry Andric         permunreg[4] = permutation;
8880b57cec5SDimitry Andric         break;
8890b57cec5SDimitry Andric       case 4:
8900b57cec5SDimitry Andric         permunreg[0] = permutation / 60;
8910b57cec5SDimitry Andric         permutation -= (permunreg[0] * 60);
8920b57cec5SDimitry Andric         permunreg[1] = permutation / 12;
8930b57cec5SDimitry Andric         permutation -= (permunreg[1] * 12);
8940b57cec5SDimitry Andric         permunreg[2] = permutation / 3;
8950b57cec5SDimitry Andric         permutation -= (permunreg[2] * 3);
8960b57cec5SDimitry Andric         permunreg[3] = permutation;
8970b57cec5SDimitry Andric         break;
8980b57cec5SDimitry Andric       case 3:
8990b57cec5SDimitry Andric         permunreg[0] = permutation / 20;
9000b57cec5SDimitry Andric         permutation -= (permunreg[0] * 20);
9010b57cec5SDimitry Andric         permunreg[1] = permutation / 4;
9020b57cec5SDimitry Andric         permutation -= (permunreg[1] * 4);
9030b57cec5SDimitry Andric         permunreg[2] = permutation;
9040b57cec5SDimitry Andric         break;
9050b57cec5SDimitry Andric       case 2:
9060b57cec5SDimitry Andric         permunreg[0] = permutation / 5;
9070b57cec5SDimitry Andric         permutation -= (permunreg[0] * 5);
9080b57cec5SDimitry Andric         permunreg[1] = permutation;
9090b57cec5SDimitry Andric         break;
9100b57cec5SDimitry Andric       case 1:
9110b57cec5SDimitry Andric         permunreg[0] = permutation;
9120b57cec5SDimitry Andric         break;
9130b57cec5SDimitry Andric       }
9140b57cec5SDimitry Andric 
9150b57cec5SDimitry Andric       // Decode the Lehmer code for this permutation of the registers v.
9160b57cec5SDimitry Andric       // http://en.wikipedia.org/wiki/Lehmer_code
9170b57cec5SDimitry Andric 
9180b57cec5SDimitry Andric       int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
9190b57cec5SDimitry Andric                           UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
9200b57cec5SDimitry Andric                           UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
9210b57cec5SDimitry Andric       bool used[7] = {false, false, false, false, false, false, false};
9220b57cec5SDimitry Andric       for (uint32_t i = 0; i < register_count; i++) {
9230b57cec5SDimitry Andric         int renum = 0;
9240b57cec5SDimitry Andric         for (int j = 1; j < 7; j++) {
9250b57cec5SDimitry Andric           if (!used[j]) {
9260b57cec5SDimitry Andric             if (renum == permunreg[i]) {
9270b57cec5SDimitry Andric               registers[i] = j;
9280b57cec5SDimitry Andric               used[j] = true;
9290b57cec5SDimitry Andric               break;
9300b57cec5SDimitry Andric             }
9310b57cec5SDimitry Andric             renum++;
9320b57cec5SDimitry Andric           }
9330b57cec5SDimitry Andric         }
9340b57cec5SDimitry Andric       }
9350b57cec5SDimitry Andric 
9360b57cec5SDimitry Andric       uint32_t saved_registers_offset = 1;
9370b57cec5SDimitry Andric       saved_registers_offset++;
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric       for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
9400b57cec5SDimitry Andric         switch (registers[i]) {
9410b57cec5SDimitry Andric         case UNWIND_X86_64_REG_NONE:
9420b57cec5SDimitry Andric           break;
9430b57cec5SDimitry Andric         case UNWIND_X86_64_REG_RBX:
9440b57cec5SDimitry Andric         case UNWIND_X86_64_REG_R12:
9450b57cec5SDimitry Andric         case UNWIND_X86_64_REG_R13:
9460b57cec5SDimitry Andric         case UNWIND_X86_64_REG_R14:
9470b57cec5SDimitry Andric         case UNWIND_X86_64_REG_R15:
9480b57cec5SDimitry Andric         case UNWIND_X86_64_REG_RBP:
9490b57cec5SDimitry Andric           row->SetRegisterLocationToAtCFAPlusOffset(
9500b57cec5SDimitry Andric               translate_to_eh_frame_regnum_x86_64(registers[i]),
9510b57cec5SDimitry Andric               wordsize * -saved_registers_offset, true);
9520b57cec5SDimitry Andric           saved_registers_offset++;
9530b57cec5SDimitry Andric           break;
9540b57cec5SDimitry Andric         }
9550b57cec5SDimitry Andric       }
9560b57cec5SDimitry Andric     }
9570b57cec5SDimitry Andric     unwind_plan.AppendRow(row);
9580b57cec5SDimitry Andric     return true;
9590b57cec5SDimitry Andric   } break;
9600b57cec5SDimitry Andric 
9610b57cec5SDimitry Andric   case UNWIND_X86_64_MODE_DWARF: {
9620b57cec5SDimitry Andric     return false;
9630b57cec5SDimitry Andric   } break;
9640b57cec5SDimitry Andric 
9650b57cec5SDimitry Andric   case 0: {
9660b57cec5SDimitry Andric     return false;
9670b57cec5SDimitry Andric   } break;
9680b57cec5SDimitry Andric   }
9690b57cec5SDimitry Andric   return false;
9700b57cec5SDimitry Andric }
9710b57cec5SDimitry Andric 
9720b57cec5SDimitry Andric enum i386_eh_regnum {
9730b57cec5SDimitry Andric   eax = 0,
9740b57cec5SDimitry Andric   ecx = 1,
9750b57cec5SDimitry Andric   edx = 2,
9760b57cec5SDimitry Andric   ebx = 3,
9770b57cec5SDimitry Andric   ebp = 4,
9780b57cec5SDimitry Andric   esp = 5,
9790b57cec5SDimitry Andric   esi = 6,
9800b57cec5SDimitry Andric   edi = 7,
9810b57cec5SDimitry Andric   eip = 8 // this is officially the Return Address register number, but close
9820b57cec5SDimitry Andric           // enough
9830b57cec5SDimitry Andric };
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric // Convert the compact_unwind_info.h register numbering scheme to
9860b57cec5SDimitry Andric // eRegisterKindEHFrame (eh_frame) register numbering scheme.
translate_to_eh_frame_regnum_i386(uint32_t unwind_regno)9870b57cec5SDimitry Andric uint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {
9880b57cec5SDimitry Andric   switch (unwind_regno) {
9890b57cec5SDimitry Andric   case UNWIND_X86_REG_EBX:
9900b57cec5SDimitry Andric     return i386_eh_regnum::ebx;
9910b57cec5SDimitry Andric   case UNWIND_X86_REG_ECX:
9920b57cec5SDimitry Andric     return i386_eh_regnum::ecx;
9930b57cec5SDimitry Andric   case UNWIND_X86_REG_EDX:
9940b57cec5SDimitry Andric     return i386_eh_regnum::edx;
9950b57cec5SDimitry Andric   case UNWIND_X86_REG_EDI:
9960b57cec5SDimitry Andric     return i386_eh_regnum::edi;
9970b57cec5SDimitry Andric   case UNWIND_X86_REG_ESI:
9980b57cec5SDimitry Andric     return i386_eh_regnum::esi;
9990b57cec5SDimitry Andric   case UNWIND_X86_REG_EBP:
10000b57cec5SDimitry Andric     return i386_eh_regnum::ebp;
10010b57cec5SDimitry Andric   default:
10020b57cec5SDimitry Andric     return LLDB_INVALID_REGNUM;
10030b57cec5SDimitry Andric   }
10040b57cec5SDimitry Andric }
10050b57cec5SDimitry Andric 
CreateUnwindPlan_i386(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)10060b57cec5SDimitry Andric bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
10070b57cec5SDimitry Andric                                               FunctionInfo &function_info,
10080b57cec5SDimitry Andric                                               UnwindPlan &unwind_plan,
10090b57cec5SDimitry Andric                                               Address pc_or_function_start) {
10100b57cec5SDimitry Andric   unwind_plan.SetSourceName("compact unwind info");
10110b57cec5SDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
10120b57cec5SDimitry Andric   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
10139dba64beSDimitry Andric   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
10140b57cec5SDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
10150b57cec5SDimitry Andric 
10160b57cec5SDimitry Andric   unwind_plan.SetLSDAAddress(function_info.lsda_address);
10170b57cec5SDimitry Andric   unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
10180b57cec5SDimitry Andric 
10190b57cec5SDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
10200b57cec5SDimitry Andric 
10210b57cec5SDimitry Andric   const int wordsize = 4;
10220b57cec5SDimitry Andric   int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
10230b57cec5SDimitry Andric   switch (mode) {
10240b57cec5SDimitry Andric   case UNWIND_X86_MODE_EBP_FRAME: {
10250b57cec5SDimitry Andric     row->GetCFAValue().SetIsRegisterPlusOffset(
10260b57cec5SDimitry Andric         translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
10270b57cec5SDimitry Andric     row->SetOffset(0);
10280b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,
10290b57cec5SDimitry Andric                                               wordsize * -2, true);
10300b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
10310b57cec5SDimitry Andric                                               wordsize * -1, true);
10320b57cec5SDimitry Andric     row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
10330b57cec5SDimitry Andric 
10340b57cec5SDimitry Andric     uint32_t saved_registers_offset =
10350b57cec5SDimitry Andric         EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric     uint32_t saved_registers_locations =
10380b57cec5SDimitry Andric         EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric     saved_registers_offset += 2;
10410b57cec5SDimitry Andric 
10420b57cec5SDimitry Andric     for (int i = 0; i < 5; i++) {
10430b57cec5SDimitry Andric       uint32_t regnum = saved_registers_locations & 0x7;
10440b57cec5SDimitry Andric       switch (regnum) {
10450b57cec5SDimitry Andric       case UNWIND_X86_REG_NONE:
10460b57cec5SDimitry Andric         break;
10470b57cec5SDimitry Andric       case UNWIND_X86_REG_EBX:
10480b57cec5SDimitry Andric       case UNWIND_X86_REG_ECX:
10490b57cec5SDimitry Andric       case UNWIND_X86_REG_EDX:
10500b57cec5SDimitry Andric       case UNWIND_X86_REG_EDI:
10510b57cec5SDimitry Andric       case UNWIND_X86_REG_ESI:
10520b57cec5SDimitry Andric         row->SetRegisterLocationToAtCFAPlusOffset(
10530b57cec5SDimitry Andric             translate_to_eh_frame_regnum_i386(regnum),
10540b57cec5SDimitry Andric             wordsize * -saved_registers_offset, true);
10550b57cec5SDimitry Andric         break;
10560b57cec5SDimitry Andric       }
10570b57cec5SDimitry Andric       saved_registers_offset--;
10580b57cec5SDimitry Andric       saved_registers_locations >>= 3;
10590b57cec5SDimitry Andric     }
10600b57cec5SDimitry Andric     unwind_plan.AppendRow(row);
10610b57cec5SDimitry Andric     return true;
10620b57cec5SDimitry Andric   } break;
10630b57cec5SDimitry Andric 
10640b57cec5SDimitry Andric   case UNWIND_X86_MODE_STACK_IND:
10650b57cec5SDimitry Andric   case UNWIND_X86_MODE_STACK_IMMD: {
10660b57cec5SDimitry Andric     uint32_t stack_size =
10670b57cec5SDimitry Andric         EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
10680b57cec5SDimitry Andric     uint32_t register_count = EXTRACT_BITS(
10690b57cec5SDimitry Andric         function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
10700b57cec5SDimitry Andric     uint32_t permutation = EXTRACT_BITS(
10710b57cec5SDimitry Andric         function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
10720b57cec5SDimitry Andric 
10730b57cec5SDimitry Andric     if (mode == UNWIND_X86_MODE_STACK_IND &&
10740b57cec5SDimitry Andric         function_info.valid_range_offset_start != 0) {
10750b57cec5SDimitry Andric       uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,
10760b57cec5SDimitry Andric                                            UNWIND_X86_FRAMELESS_STACK_ADJUST);
10770b57cec5SDimitry Andric 
10780b57cec5SDimitry Andric       // offset into the function instructions; 0 == beginning of first
10790b57cec5SDimitry Andric       // instruction
10800b57cec5SDimitry Andric       uint32_t offset_to_subl_insn =
10810b57cec5SDimitry Andric           EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
10820b57cec5SDimitry Andric 
10830b57cec5SDimitry Andric       SectionList *sl = m_objfile.GetSectionList();
10840b57cec5SDimitry Andric       if (sl) {
10850b57cec5SDimitry Andric         ProcessSP process_sp = target.GetProcessSP();
10860b57cec5SDimitry Andric         if (process_sp) {
10870b57cec5SDimitry Andric           Address subl_payload_addr(function_info.valid_range_offset_start, sl);
10880b57cec5SDimitry Andric           subl_payload_addr.Slide(offset_to_subl_insn);
10890b57cec5SDimitry Andric           Status error;
10900b57cec5SDimitry Andric           uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
10910b57cec5SDimitry Andric               subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
10920b57cec5SDimitry Andric           if (large_stack_size != 0 && error.Success()) {
10930b57cec5SDimitry Andric             // Got the large stack frame size correctly - use it
10940b57cec5SDimitry Andric             stack_size = large_stack_size + (stack_adjust * wordsize);
10950b57cec5SDimitry Andric           } else {
10960b57cec5SDimitry Andric             return false;
10970b57cec5SDimitry Andric           }
10980b57cec5SDimitry Andric         } else {
10990b57cec5SDimitry Andric           return false;
11000b57cec5SDimitry Andric         }
11010b57cec5SDimitry Andric       } else {
11020b57cec5SDimitry Andric         return false;
11030b57cec5SDimitry Andric       }
11040b57cec5SDimitry Andric     }
11050b57cec5SDimitry Andric 
11060b57cec5SDimitry Andric     int32_t offset =
11070b57cec5SDimitry Andric         mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
11080b57cec5SDimitry Andric     row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
11090b57cec5SDimitry Andric     row->SetOffset(0);
11100b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
11110b57cec5SDimitry Andric                                               wordsize * -1, true);
11120b57cec5SDimitry Andric     row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric     if (register_count > 0) {
11150b57cec5SDimitry Andric 
11160b57cec5SDimitry Andric       // We need to include (up to) 6 registers in 10 bits. That would be 18
11170b57cec5SDimitry Andric       // bits if we just used 3 bits per reg to indicate the order they're
11180b57cec5SDimitry Andric       // saved on the stack.
11190b57cec5SDimitry Andric       //
11200b57cec5SDimitry Andric       // This is done with Lehmer code permutation, e.g. see
11210b57cec5SDimitry Andric       // http://stackoverflow.com/questions/1506078/fast-permutation-number-
11220b57cec5SDimitry Andric       // permutation-mapping-algorithms
11230b57cec5SDimitry Andric       int permunreg[6] = {0, 0, 0, 0, 0, 0};
11240b57cec5SDimitry Andric 
11250b57cec5SDimitry Andric       // This decodes the variable-base number in the 10 bits and gives us the
11260b57cec5SDimitry Andric       // Lehmer code sequence which can then be decoded.
11270b57cec5SDimitry Andric 
11280b57cec5SDimitry Andric       switch (register_count) {
11290b57cec5SDimitry Andric       case 6:
11300b57cec5SDimitry Andric         permunreg[0] = permutation / 120; // 120 == 5!
11310b57cec5SDimitry Andric         permutation -= (permunreg[0] * 120);
11320b57cec5SDimitry Andric         permunreg[1] = permutation / 24; // 24 == 4!
11330b57cec5SDimitry Andric         permutation -= (permunreg[1] * 24);
11340b57cec5SDimitry Andric         permunreg[2] = permutation / 6; // 6 == 3!
11350b57cec5SDimitry Andric         permutation -= (permunreg[2] * 6);
11360b57cec5SDimitry Andric         permunreg[3] = permutation / 2; // 2 == 2!
11370b57cec5SDimitry Andric         permutation -= (permunreg[3] * 2);
11380b57cec5SDimitry Andric         permunreg[4] = permutation; // 1 == 1!
11390b57cec5SDimitry Andric         permunreg[5] = 0;
11400b57cec5SDimitry Andric         break;
11410b57cec5SDimitry Andric       case 5:
11420b57cec5SDimitry Andric         permunreg[0] = permutation / 120;
11430b57cec5SDimitry Andric         permutation -= (permunreg[0] * 120);
11440b57cec5SDimitry Andric         permunreg[1] = permutation / 24;
11450b57cec5SDimitry Andric         permutation -= (permunreg[1] * 24);
11460b57cec5SDimitry Andric         permunreg[2] = permutation / 6;
11470b57cec5SDimitry Andric         permutation -= (permunreg[2] * 6);
11480b57cec5SDimitry Andric         permunreg[3] = permutation / 2;
11490b57cec5SDimitry Andric         permutation -= (permunreg[3] * 2);
11500b57cec5SDimitry Andric         permunreg[4] = permutation;
11510b57cec5SDimitry Andric         break;
11520b57cec5SDimitry Andric       case 4:
11530b57cec5SDimitry Andric         permunreg[0] = permutation / 60;
11540b57cec5SDimitry Andric         permutation -= (permunreg[0] * 60);
11550b57cec5SDimitry Andric         permunreg[1] = permutation / 12;
11560b57cec5SDimitry Andric         permutation -= (permunreg[1] * 12);
11570b57cec5SDimitry Andric         permunreg[2] = permutation / 3;
11580b57cec5SDimitry Andric         permutation -= (permunreg[2] * 3);
11590b57cec5SDimitry Andric         permunreg[3] = permutation;
11600b57cec5SDimitry Andric         break;
11610b57cec5SDimitry Andric       case 3:
11620b57cec5SDimitry Andric         permunreg[0] = permutation / 20;
11630b57cec5SDimitry Andric         permutation -= (permunreg[0] * 20);
11640b57cec5SDimitry Andric         permunreg[1] = permutation / 4;
11650b57cec5SDimitry Andric         permutation -= (permunreg[1] * 4);
11660b57cec5SDimitry Andric         permunreg[2] = permutation;
11670b57cec5SDimitry Andric         break;
11680b57cec5SDimitry Andric       case 2:
11690b57cec5SDimitry Andric         permunreg[0] = permutation / 5;
11700b57cec5SDimitry Andric         permutation -= (permunreg[0] * 5);
11710b57cec5SDimitry Andric         permunreg[1] = permutation;
11720b57cec5SDimitry Andric         break;
11730b57cec5SDimitry Andric       case 1:
11740b57cec5SDimitry Andric         permunreg[0] = permutation;
11750b57cec5SDimitry Andric         break;
11760b57cec5SDimitry Andric       }
11770b57cec5SDimitry Andric 
11780b57cec5SDimitry Andric       // Decode the Lehmer code for this permutation of the registers v.
11790b57cec5SDimitry Andric       // http://en.wikipedia.org/wiki/Lehmer_code
11800b57cec5SDimitry Andric 
11810b57cec5SDimitry Andric       int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
11820b57cec5SDimitry Andric                           UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
11830b57cec5SDimitry Andric                           UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};
11840b57cec5SDimitry Andric       bool used[7] = {false, false, false, false, false, false, false};
11850b57cec5SDimitry Andric       for (uint32_t i = 0; i < register_count; i++) {
11860b57cec5SDimitry Andric         int renum = 0;
11870b57cec5SDimitry Andric         for (int j = 1; j < 7; j++) {
11880b57cec5SDimitry Andric           if (!used[j]) {
11890b57cec5SDimitry Andric             if (renum == permunreg[i]) {
11900b57cec5SDimitry Andric               registers[i] = j;
11910b57cec5SDimitry Andric               used[j] = true;
11920b57cec5SDimitry Andric               break;
11930b57cec5SDimitry Andric             }
11940b57cec5SDimitry Andric             renum++;
11950b57cec5SDimitry Andric           }
11960b57cec5SDimitry Andric         }
11970b57cec5SDimitry Andric       }
11980b57cec5SDimitry Andric 
11990b57cec5SDimitry Andric       uint32_t saved_registers_offset = 1;
12000b57cec5SDimitry Andric       saved_registers_offset++;
12010b57cec5SDimitry Andric 
12020b57cec5SDimitry Andric       for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
12030b57cec5SDimitry Andric         switch (registers[i]) {
12040b57cec5SDimitry Andric         case UNWIND_X86_REG_NONE:
12050b57cec5SDimitry Andric           break;
12060b57cec5SDimitry Andric         case UNWIND_X86_REG_EBX:
12070b57cec5SDimitry Andric         case UNWIND_X86_REG_ECX:
12080b57cec5SDimitry Andric         case UNWIND_X86_REG_EDX:
12090b57cec5SDimitry Andric         case UNWIND_X86_REG_EDI:
12100b57cec5SDimitry Andric         case UNWIND_X86_REG_ESI:
12110b57cec5SDimitry Andric         case UNWIND_X86_REG_EBP:
12120b57cec5SDimitry Andric           row->SetRegisterLocationToAtCFAPlusOffset(
12130b57cec5SDimitry Andric               translate_to_eh_frame_regnum_i386(registers[i]),
12140b57cec5SDimitry Andric               wordsize * -saved_registers_offset, true);
12150b57cec5SDimitry Andric           saved_registers_offset++;
12160b57cec5SDimitry Andric           break;
12170b57cec5SDimitry Andric         }
12180b57cec5SDimitry Andric       }
12190b57cec5SDimitry Andric     }
12200b57cec5SDimitry Andric 
12210b57cec5SDimitry Andric     unwind_plan.AppendRow(row);
12220b57cec5SDimitry Andric     return true;
12230b57cec5SDimitry Andric   } break;
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric   case UNWIND_X86_MODE_DWARF: {
12260b57cec5SDimitry Andric     return false;
12270b57cec5SDimitry Andric   } break;
12280b57cec5SDimitry Andric   }
12290b57cec5SDimitry Andric   return false;
12300b57cec5SDimitry Andric }
12310b57cec5SDimitry Andric 
12320b57cec5SDimitry Andric // DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
12330b57cec5SDimitry Andric // doc by ARM
12340b57cec5SDimitry Andric 
12350b57cec5SDimitry Andric enum arm64_eh_regnum {
12360b57cec5SDimitry Andric   x19 = 19,
12370b57cec5SDimitry Andric   x20 = 20,
12380b57cec5SDimitry Andric   x21 = 21,
12390b57cec5SDimitry Andric   x22 = 22,
12400b57cec5SDimitry Andric   x23 = 23,
12410b57cec5SDimitry Andric   x24 = 24,
12420b57cec5SDimitry Andric   x25 = 25,
12430b57cec5SDimitry Andric   x26 = 26,
12440b57cec5SDimitry Andric   x27 = 27,
12450b57cec5SDimitry Andric   x28 = 28,
12460b57cec5SDimitry Andric 
12470b57cec5SDimitry Andric   fp = 29,
12480b57cec5SDimitry Andric   ra = 30,
12490b57cec5SDimitry Andric   sp = 31,
12500b57cec5SDimitry Andric   pc = 32,
12510b57cec5SDimitry Andric 
12520b57cec5SDimitry Andric   // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
12530b57cec5SDimitry Andric   // for the 64-bit fp regs.  Normally in DWARF it's context sensitive - so it
12540b57cec5SDimitry Andric   // knows it is fetching a 32- or 64-bit quantity from reg v8 to indicate s0
12550b57cec5SDimitry Andric   // or d0 - but the unwinder is operating at a lower level and we'd try to
12560b57cec5SDimitry Andric   // fetch 128 bits if we were told that v8 were stored on the stack...
12570b57cec5SDimitry Andric   v8 = 72,
12580b57cec5SDimitry Andric   v9 = 73,
12590b57cec5SDimitry Andric   v10 = 74,
12600b57cec5SDimitry Andric   v11 = 75,
12610b57cec5SDimitry Andric   v12 = 76,
12620b57cec5SDimitry Andric   v13 = 77,
12630b57cec5SDimitry Andric   v14 = 78,
12640b57cec5SDimitry Andric   v15 = 79,
12650b57cec5SDimitry Andric };
12660b57cec5SDimitry Andric 
12670b57cec5SDimitry Andric enum arm_eh_regnum {
12680b57cec5SDimitry Andric   arm_r0 = 0,
12690b57cec5SDimitry Andric   arm_r1 = 1,
12700b57cec5SDimitry Andric   arm_r2 = 2,
12710b57cec5SDimitry Andric   arm_r3 = 3,
12720b57cec5SDimitry Andric   arm_r4 = 4,
12730b57cec5SDimitry Andric   arm_r5 = 5,
12740b57cec5SDimitry Andric   arm_r6 = 6,
12750b57cec5SDimitry Andric   arm_r7 = 7,
12760b57cec5SDimitry Andric   arm_r8 = 8,
12770b57cec5SDimitry Andric   arm_r9 = 9,
12780b57cec5SDimitry Andric   arm_r10 = 10,
12790b57cec5SDimitry Andric   arm_r11 = 11,
12800b57cec5SDimitry Andric   arm_r12 = 12,
12810b57cec5SDimitry Andric 
12820b57cec5SDimitry Andric   arm_sp = 13,
12830b57cec5SDimitry Andric   arm_lr = 14,
12840b57cec5SDimitry Andric   arm_pc = 15,
12850b57cec5SDimitry Andric 
12860b57cec5SDimitry Andric   arm_d0 = 256,
12870b57cec5SDimitry Andric   arm_d1 = 257,
12880b57cec5SDimitry Andric   arm_d2 = 258,
12890b57cec5SDimitry Andric   arm_d3 = 259,
12900b57cec5SDimitry Andric   arm_d4 = 260,
12910b57cec5SDimitry Andric   arm_d5 = 261,
12920b57cec5SDimitry Andric   arm_d6 = 262,
12930b57cec5SDimitry Andric   arm_d7 = 263,
12940b57cec5SDimitry Andric   arm_d8 = 264,
12950b57cec5SDimitry Andric   arm_d9 = 265,
12960b57cec5SDimitry Andric   arm_d10 = 266,
12970b57cec5SDimitry Andric   arm_d11 = 267,
12980b57cec5SDimitry Andric   arm_d12 = 268,
12990b57cec5SDimitry Andric   arm_d13 = 269,
13000b57cec5SDimitry Andric   arm_d14 = 270,
13010b57cec5SDimitry Andric };
13020b57cec5SDimitry Andric 
CreateUnwindPlan_arm64(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)13030b57cec5SDimitry Andric bool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
13040b57cec5SDimitry Andric                                                FunctionInfo &function_info,
13050b57cec5SDimitry Andric                                                UnwindPlan &unwind_plan,
13060b57cec5SDimitry Andric                                                Address pc_or_function_start) {
13070b57cec5SDimitry Andric   unwind_plan.SetSourceName("compact unwind info");
13080b57cec5SDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
13090b57cec5SDimitry Andric   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
13109dba64beSDimitry Andric   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
13110b57cec5SDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
13120b57cec5SDimitry Andric 
13130b57cec5SDimitry Andric   unwind_plan.SetLSDAAddress(function_info.lsda_address);
13140b57cec5SDimitry Andric   unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
13150b57cec5SDimitry Andric 
13160b57cec5SDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
13170b57cec5SDimitry Andric 
13180b57cec5SDimitry Andric   const int wordsize = 8;
13190b57cec5SDimitry Andric   int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
13200b57cec5SDimitry Andric 
13210b57cec5SDimitry Andric   if (mode == UNWIND_ARM64_MODE_DWARF)
13220b57cec5SDimitry Andric     return false;
13230b57cec5SDimitry Andric 
13240b57cec5SDimitry Andric   if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
13250b57cec5SDimitry Andric     row->SetOffset(0);
13260b57cec5SDimitry Andric 
13270b57cec5SDimitry Andric     uint32_t stack_size =
13280b57cec5SDimitry Andric         (EXTRACT_BITS(function_info.encoding,
13290b57cec5SDimitry Andric                       UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
13300b57cec5SDimitry Andric         16;
13310b57cec5SDimitry Andric 
13320b57cec5SDimitry Andric     // Our previous Call Frame Address is the stack pointer plus the stack size
13330b57cec5SDimitry Andric     row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
13340b57cec5SDimitry Andric 
13350b57cec5SDimitry Andric     // Our previous PC is in the LR
13360b57cec5SDimitry Andric     row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
13370b57cec5SDimitry Andric                                        true);
13380b57cec5SDimitry Andric 
13390b57cec5SDimitry Andric     unwind_plan.AppendRow(row);
13400b57cec5SDimitry Andric     return true;
13410b57cec5SDimitry Andric   }
13420b57cec5SDimitry Andric 
13430b57cec5SDimitry Andric   // Should not be possible
13440b57cec5SDimitry Andric   if (mode != UNWIND_ARM64_MODE_FRAME)
13450b57cec5SDimitry Andric     return false;
13460b57cec5SDimitry Andric 
13470b57cec5SDimitry Andric   // mode == UNWIND_ARM64_MODE_FRAME
13480b57cec5SDimitry Andric 
13490b57cec5SDimitry Andric   row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
13500b57cec5SDimitry Andric   row->SetOffset(0);
13510b57cec5SDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
13520b57cec5SDimitry Andric                                             true);
13530b57cec5SDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
13540b57cec5SDimitry Andric                                             true);
13550b57cec5SDimitry Andric   row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
13560b57cec5SDimitry Andric 
13570b57cec5SDimitry Andric   int reg_pairs_saved_count = 1;
13580b57cec5SDimitry Andric 
13590b57cec5SDimitry Andric   uint32_t saved_register_bits = function_info.encoding & 0xfff;
13600b57cec5SDimitry Andric 
13610b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
13620b57cec5SDimitry Andric     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
13630b57cec5SDimitry Andric     cfa_offset -= wordsize;
13640b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,
13650b57cec5SDimitry Andric                                               true);
13660b57cec5SDimitry Andric     cfa_offset -= wordsize;
13670b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
13680b57cec5SDimitry Andric                                               true);
13690b57cec5SDimitry Andric     reg_pairs_saved_count++;
13700b57cec5SDimitry Andric   }
13710b57cec5SDimitry Andric 
13720b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
13730b57cec5SDimitry Andric     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
13740b57cec5SDimitry Andric     cfa_offset -= wordsize;
13750b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,
13760b57cec5SDimitry Andric                                               true);
13770b57cec5SDimitry Andric     cfa_offset -= wordsize;
13780b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
13790b57cec5SDimitry Andric                                               true);
13800b57cec5SDimitry Andric     reg_pairs_saved_count++;
13810b57cec5SDimitry Andric   }
13820b57cec5SDimitry Andric 
13830b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
13840b57cec5SDimitry Andric     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
13850b57cec5SDimitry Andric     cfa_offset -= wordsize;
13860b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,
13870b57cec5SDimitry Andric                                               true);
13880b57cec5SDimitry Andric     cfa_offset -= wordsize;
13890b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
13900b57cec5SDimitry Andric                                               true);
13910b57cec5SDimitry Andric     reg_pairs_saved_count++;
13920b57cec5SDimitry Andric   }
13930b57cec5SDimitry Andric 
13940b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
13950b57cec5SDimitry Andric     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
13960b57cec5SDimitry Andric     cfa_offset -= wordsize;
13970b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,
13980b57cec5SDimitry Andric                                               true);
13990b57cec5SDimitry Andric     cfa_offset -= wordsize;
14000b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
14010b57cec5SDimitry Andric                                               true);
14020b57cec5SDimitry Andric     reg_pairs_saved_count++;
14030b57cec5SDimitry Andric   }
14040b57cec5SDimitry Andric 
14050b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
14060b57cec5SDimitry Andric     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
14070b57cec5SDimitry Andric     cfa_offset -= wordsize;
14080b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,
14090b57cec5SDimitry Andric                                               true);
14100b57cec5SDimitry Andric     cfa_offset -= wordsize;
14110b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
14120b57cec5SDimitry Andric                                               true);
14130b57cec5SDimitry Andric     reg_pairs_saved_count++;
14140b57cec5SDimitry Andric   }
14150b57cec5SDimitry Andric 
14160b57cec5SDimitry Andric   // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
14170b57cec5SDimitry Andric   // off the stack;
14180b57cec5SDimitry Andric   // not sure if we have a good way to represent the 64-bitness of these saves.
14190b57cec5SDimitry Andric 
14200b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
14210b57cec5SDimitry Andric     reg_pairs_saved_count++;
14220b57cec5SDimitry Andric   }
14230b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
14240b57cec5SDimitry Andric     reg_pairs_saved_count++;
14250b57cec5SDimitry Andric   }
14260b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
14270b57cec5SDimitry Andric     reg_pairs_saved_count++;
14280b57cec5SDimitry Andric   }
14290b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
14300b57cec5SDimitry Andric     reg_pairs_saved_count++;
14310b57cec5SDimitry Andric   }
14320b57cec5SDimitry Andric 
14330b57cec5SDimitry Andric   unwind_plan.AppendRow(row);
14340b57cec5SDimitry Andric   return true;
14350b57cec5SDimitry Andric }
14360b57cec5SDimitry Andric 
CreateUnwindPlan_armv7(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)14370b57cec5SDimitry Andric bool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
14380b57cec5SDimitry Andric                                                FunctionInfo &function_info,
14390b57cec5SDimitry Andric                                                UnwindPlan &unwind_plan,
14400b57cec5SDimitry Andric                                                Address pc_or_function_start) {
14410b57cec5SDimitry Andric   unwind_plan.SetSourceName("compact unwind info");
14420b57cec5SDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
14430b57cec5SDimitry Andric   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
14449dba64beSDimitry Andric   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
14450b57cec5SDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
14460b57cec5SDimitry Andric 
14470b57cec5SDimitry Andric   unwind_plan.SetLSDAAddress(function_info.lsda_address);
14480b57cec5SDimitry Andric   unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
14490b57cec5SDimitry Andric 
14500b57cec5SDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
14510b57cec5SDimitry Andric 
14520b57cec5SDimitry Andric   const int wordsize = 4;
14530b57cec5SDimitry Andric   int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric   if (mode == UNWIND_ARM_MODE_DWARF)
14560b57cec5SDimitry Andric     return false;
14570b57cec5SDimitry Andric 
14580b57cec5SDimitry Andric   uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
14590b57cec5SDimitry Andric                                         UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
14600b57cec5SDimitry Andric                           wordsize;
14610b57cec5SDimitry Andric 
14620b57cec5SDimitry Andric   row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
14630b57cec5SDimitry Andric                                              (2 * wordsize) + stack_adjust);
14640b57cec5SDimitry Andric   row->SetOffset(0);
14650b57cec5SDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(
14660b57cec5SDimitry Andric       arm_r7, (wordsize * -2) - stack_adjust, true);
14670b57cec5SDimitry Andric   row->SetRegisterLocationToAtCFAPlusOffset(
14680b57cec5SDimitry Andric       arm_pc, (wordsize * -1) - stack_adjust, true);
14690b57cec5SDimitry Andric   row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);
14700b57cec5SDimitry Andric 
14710b57cec5SDimitry Andric   int cfa_offset = -stack_adjust - (2 * wordsize);
14720b57cec5SDimitry Andric 
14730b57cec5SDimitry Andric   uint32_t saved_register_bits = function_info.encoding & 0xff;
14740b57cec5SDimitry Andric 
14750b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
14760b57cec5SDimitry Andric     cfa_offset -= wordsize;
14770b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
14780b57cec5SDimitry Andric   }
14790b57cec5SDimitry Andric 
14800b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
14810b57cec5SDimitry Andric     cfa_offset -= wordsize;
14820b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
14830b57cec5SDimitry Andric   }
14840b57cec5SDimitry Andric 
14850b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
14860b57cec5SDimitry Andric     cfa_offset -= wordsize;
14870b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
14880b57cec5SDimitry Andric   }
14890b57cec5SDimitry Andric 
14900b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
14910b57cec5SDimitry Andric     cfa_offset -= wordsize;
14920b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
14930b57cec5SDimitry Andric   }
14940b57cec5SDimitry Andric 
14950b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
14960b57cec5SDimitry Andric     cfa_offset -= wordsize;
14970b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
14980b57cec5SDimitry Andric   }
14990b57cec5SDimitry Andric 
15000b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
15010b57cec5SDimitry Andric     cfa_offset -= wordsize;
15020b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
15030b57cec5SDimitry Andric   }
15040b57cec5SDimitry Andric 
15050b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
15060b57cec5SDimitry Andric     cfa_offset -= wordsize;
15070b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
15080b57cec5SDimitry Andric   }
15090b57cec5SDimitry Andric 
15100b57cec5SDimitry Andric   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
15110b57cec5SDimitry Andric     cfa_offset -= wordsize;
15120b57cec5SDimitry Andric     row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
15130b57cec5SDimitry Andric   }
15140b57cec5SDimitry Andric 
15150b57cec5SDimitry Andric   if (mode == UNWIND_ARM_MODE_FRAME_D) {
15160b57cec5SDimitry Andric     uint32_t d_reg_bits =
15170b57cec5SDimitry Andric         EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
15180b57cec5SDimitry Andric     switch (d_reg_bits) {
15190b57cec5SDimitry Andric     case 0:
15200b57cec5SDimitry Andric       // vpush {d8}
15210b57cec5SDimitry Andric       cfa_offset -= 8;
15220b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
15230b57cec5SDimitry Andric       break;
15240b57cec5SDimitry Andric     case 1:
15250b57cec5SDimitry Andric       // vpush {d10}
15260b57cec5SDimitry Andric       // vpush {d8}
15270b57cec5SDimitry Andric       cfa_offset -= 8;
15280b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
15290b57cec5SDimitry Andric       cfa_offset -= 8;
15300b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
15310b57cec5SDimitry Andric       break;
15320b57cec5SDimitry Andric     case 2:
15330b57cec5SDimitry Andric       // vpush {d12}
15340b57cec5SDimitry Andric       // vpush {d10}
15350b57cec5SDimitry Andric       // vpush {d8}
15360b57cec5SDimitry Andric       cfa_offset -= 8;
15370b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
15380b57cec5SDimitry Andric       cfa_offset -= 8;
15390b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
15400b57cec5SDimitry Andric       cfa_offset -= 8;
15410b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
15420b57cec5SDimitry Andric       break;
15430b57cec5SDimitry Andric     case 3:
15440b57cec5SDimitry Andric       // vpush {d14}
15450b57cec5SDimitry Andric       // vpush {d12}
15460b57cec5SDimitry Andric       // vpush {d10}
15470b57cec5SDimitry Andric       // vpush {d8}
15480b57cec5SDimitry Andric       cfa_offset -= 8;
15490b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
15500b57cec5SDimitry Andric       cfa_offset -= 8;
15510b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
15520b57cec5SDimitry Andric       cfa_offset -= 8;
15530b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
15540b57cec5SDimitry Andric       cfa_offset -= 8;
15550b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
15560b57cec5SDimitry Andric       break;
15570b57cec5SDimitry Andric     case 4:
15580b57cec5SDimitry Andric       // vpush {d14}
15590b57cec5SDimitry Andric       // vpush {d12}
15600b57cec5SDimitry Andric       // sp = (sp - 24) & (-16);
15610b57cec5SDimitry Andric       // vst   {d8, d9, d10}
15620b57cec5SDimitry Andric       cfa_offset -= 8;
15630b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
15640b57cec5SDimitry Andric       cfa_offset -= 8;
15650b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
15660b57cec5SDimitry Andric 
15670b57cec5SDimitry Andric       // FIXME we don't have a way to represent reg saves at an specific
15680b57cec5SDimitry Andric       // alignment short of
15690b57cec5SDimitry Andric       // coming up with some DWARF location description.
15700b57cec5SDimitry Andric 
15710b57cec5SDimitry Andric       break;
15720b57cec5SDimitry Andric     case 5:
15730b57cec5SDimitry Andric       // vpush {d14}
15740b57cec5SDimitry Andric       // sp = (sp - 40) & (-16);
15750b57cec5SDimitry Andric       // vst   {d8, d9, d10, d11}
15760b57cec5SDimitry Andric       // vst   {d12}
15770b57cec5SDimitry Andric 
15780b57cec5SDimitry Andric       cfa_offset -= 8;
15790b57cec5SDimitry Andric       row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
15800b57cec5SDimitry Andric 
15810b57cec5SDimitry Andric       // FIXME we don't have a way to represent reg saves at an specific
15820b57cec5SDimitry Andric       // alignment short of
15830b57cec5SDimitry Andric       // coming up with some DWARF location description.
15840b57cec5SDimitry Andric 
15850b57cec5SDimitry Andric       break;
15860b57cec5SDimitry Andric     case 6:
15870b57cec5SDimitry Andric       // sp = (sp - 56) & (-16);
15880b57cec5SDimitry Andric       // vst   {d8, d9, d10, d11}
15890b57cec5SDimitry Andric       // vst   {d12, d13, d14}
15900b57cec5SDimitry Andric 
15910b57cec5SDimitry Andric       // FIXME we don't have a way to represent reg saves at an specific
15920b57cec5SDimitry Andric       // alignment short of
15930b57cec5SDimitry Andric       // coming up with some DWARF location description.
15940b57cec5SDimitry Andric 
15950b57cec5SDimitry Andric       break;
15960b57cec5SDimitry Andric     case 7:
15970b57cec5SDimitry Andric       // sp = (sp - 64) & (-16);
15980b57cec5SDimitry Andric       // vst   {d8, d9, d10, d11}
15990b57cec5SDimitry Andric       // vst   {d12, d13, d14, d15}
16000b57cec5SDimitry Andric 
16010b57cec5SDimitry Andric       // FIXME we don't have a way to represent reg saves at an specific
16020b57cec5SDimitry Andric       // alignment short of
16030b57cec5SDimitry Andric       // coming up with some DWARF location description.
16040b57cec5SDimitry Andric 
16050b57cec5SDimitry Andric       break;
16060b57cec5SDimitry Andric     }
16070b57cec5SDimitry Andric   }
16080b57cec5SDimitry Andric 
16090b57cec5SDimitry Andric   unwind_plan.AppendRow(row);
16100b57cec5SDimitry Andric   return true;
16110b57cec5SDimitry Andric }
1612