180814287SRaphael Isemann //===-- CompactUnwindInfo.cpp ---------------------------------------------===//
2e589e7e3SJason Molenda //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e589e7e3SJason Molenda //
7e589e7e3SJason Molenda //===----------------------------------------------------------------------===//
8e589e7e3SJason Molenda 
95f19b907SPavel Labath #include "lldb/Symbol/CompactUnwindInfo.h"
10*68793919SJonas Devlieghere #include "lldb/Core/Debugger.h"
11e589e7e3SJason Molenda #include "lldb/Core/Module.h"
12e589e7e3SJason Molenda #include "lldb/Core/Section.h"
13e589e7e3SJason Molenda #include "lldb/Symbol/ObjectFile.h"
14e589e7e3SJason Molenda #include "lldb/Symbol/UnwindPlan.h"
15b12a136cSJason Molenda #include "lldb/Target/Process.h"
16b12a136cSJason Molenda #include "lldb/Target/Target.h"
175f19b907SPavel Labath #include "lldb/Utility/ArchSpec.h"
18666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
19c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
206f9e6901SZachary Turner #include "lldb/Utility/Log.h"
21bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
22e589e7e3SJason Molenda 
23818a3676SZachary Turner #include "llvm/Support/MathExtras.h"
24818a3676SZachary Turner 
25796ac80bSJonas Devlieghere #include <algorithm>
26796ac80bSJonas Devlieghere #include <memory>
27796ac80bSJonas Devlieghere 
28e589e7e3SJason Molenda using namespace lldb;
29e589e7e3SJason Molenda using namespace lldb_private;
30e589e7e3SJason Molenda 
31e589e7e3SJason Molenda namespace lldb_private {
32e589e7e3SJason Molenda 
33e589e7e3SJason Molenda // Constants from <mach-o/compact_unwind_encoding.h>
34e589e7e3SJason Molenda 
FLAGS_ANONYMOUS_ENUM()35b9c1b51eSKate Stone FLAGS_ANONYMOUS_ENUM(){
36b9c1b51eSKate Stone     UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
37e589e7e3SJason Molenda     UNWIND_PERSONALITY_MASK = 0x30000000,
38e589e7e3SJason Molenda };
39e589e7e3SJason Molenda 
FLAGS_ANONYMOUS_ENUM()40b9c1b51eSKate Stone FLAGS_ANONYMOUS_ENUM(){
41e589e7e3SJason Molenda     UNWIND_X86_MODE_MASK = 0x0F000000,
42e589e7e3SJason Molenda     UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
43e589e7e3SJason Molenda     UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
44e589e7e3SJason Molenda     UNWIND_X86_MODE_STACK_IND = 0x03000000,
45e589e7e3SJason Molenda     UNWIND_X86_MODE_DWARF = 0x04000000,
46e589e7e3SJason Molenda 
47e589e7e3SJason Molenda     UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
48e589e7e3SJason Molenda     UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
49e589e7e3SJason Molenda 
50e589e7e3SJason Molenda     UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
51e589e7e3SJason Molenda     UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
52e589e7e3SJason Molenda     UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
53e589e7e3SJason Molenda     UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
54e589e7e3SJason Molenda 
55e589e7e3SJason Molenda     UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
56e589e7e3SJason Molenda };
57e589e7e3SJason Molenda 
58b9c1b51eSKate Stone enum {
59e589e7e3SJason Molenda   UNWIND_X86_REG_NONE = 0,
60e589e7e3SJason Molenda   UNWIND_X86_REG_EBX = 1,
61e589e7e3SJason Molenda   UNWIND_X86_REG_ECX = 2,
62e589e7e3SJason Molenda   UNWIND_X86_REG_EDX = 3,
63e589e7e3SJason Molenda   UNWIND_X86_REG_EDI = 4,
64e589e7e3SJason Molenda   UNWIND_X86_REG_ESI = 5,
65e589e7e3SJason Molenda   UNWIND_X86_REG_EBP = 6,
66e589e7e3SJason Molenda };
6748b475cbSZachary Turner 
FLAGS_ANONYMOUS_ENUM()68b9c1b51eSKate Stone FLAGS_ANONYMOUS_ENUM(){
69e589e7e3SJason Molenda     UNWIND_X86_64_MODE_MASK = 0x0F000000,
70e589e7e3SJason Molenda     UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
71e589e7e3SJason Molenda     UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
72e589e7e3SJason Molenda     UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
73e589e7e3SJason Molenda     UNWIND_X86_64_MODE_DWARF = 0x04000000,
74e589e7e3SJason Molenda 
75e589e7e3SJason Molenda     UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
76e589e7e3SJason Molenda     UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
77e589e7e3SJason Molenda 
78e589e7e3SJason Molenda     UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
79e589e7e3SJason Molenda     UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
80e589e7e3SJason Molenda     UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
81e589e7e3SJason Molenda     UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
82e589e7e3SJason Molenda 
83e589e7e3SJason Molenda     UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
84e589e7e3SJason Molenda };
85e589e7e3SJason Molenda 
86b9c1b51eSKate Stone enum {
87e589e7e3SJason Molenda   UNWIND_X86_64_REG_NONE = 0,
88e589e7e3SJason Molenda   UNWIND_X86_64_REG_RBX = 1,
89e589e7e3SJason Molenda   UNWIND_X86_64_REG_R12 = 2,
90e589e7e3SJason Molenda   UNWIND_X86_64_REG_R13 = 3,
91e589e7e3SJason Molenda   UNWIND_X86_64_REG_R14 = 4,
92e589e7e3SJason Molenda   UNWIND_X86_64_REG_R15 = 5,
93e589e7e3SJason Molenda   UNWIND_X86_64_REG_RBP = 6,
94e589e7e3SJason Molenda };
95b667c202SJason Molenda 
FLAGS_ANONYMOUS_ENUM()96b9c1b51eSKate Stone FLAGS_ANONYMOUS_ENUM(){
97b667c202SJason Molenda     UNWIND_ARM64_MODE_MASK = 0x0F000000,
98b667c202SJason Molenda     UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
99b667c202SJason Molenda     UNWIND_ARM64_MODE_DWARF = 0x03000000,
100b667c202SJason Molenda     UNWIND_ARM64_MODE_FRAME = 0x04000000,
101b667c202SJason Molenda 
102b667c202SJason Molenda     UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
103b667c202SJason Molenda     UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
104b667c202SJason Molenda     UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
105b667c202SJason Molenda     UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
106b667c202SJason Molenda     UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
107b667c202SJason Molenda     UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
108b667c202SJason Molenda     UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
109b667c202SJason Molenda     UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
110b667c202SJason Molenda     UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
111b667c202SJason Molenda 
112b667c202SJason Molenda     UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
113b667c202SJason Molenda     UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
114b667c202SJason Molenda };
115c7afda5aSJason Molenda 
FLAGS_ANONYMOUS_ENUM()116b9c1b51eSKate Stone FLAGS_ANONYMOUS_ENUM(){
117c7afda5aSJason Molenda     UNWIND_ARM_MODE_MASK = 0x0F000000,
118c7afda5aSJason Molenda     UNWIND_ARM_MODE_FRAME = 0x01000000,
119c7afda5aSJason Molenda     UNWIND_ARM_MODE_FRAME_D = 0x02000000,
120c7afda5aSJason Molenda     UNWIND_ARM_MODE_DWARF = 0x04000000,
121c7afda5aSJason Molenda 
122c7afda5aSJason Molenda     UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
123c7afda5aSJason Molenda 
124c7afda5aSJason Molenda     UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
125c7afda5aSJason Molenda     UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
126c7afda5aSJason Molenda     UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
127c7afda5aSJason Molenda 
128c7afda5aSJason Molenda     UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
129c7afda5aSJason Molenda     UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
130c7afda5aSJason Molenda     UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
131c7afda5aSJason Molenda     UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
132c7afda5aSJason Molenda     UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
133c7afda5aSJason Molenda 
134c7afda5aSJason Molenda     UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
135c7afda5aSJason Molenda 
136c7afda5aSJason Molenda     UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
137c7afda5aSJason Molenda };
138d7e6a4f2SVince Harron }
139e589e7e3SJason Molenda 
140e589e7e3SJason Molenda #ifndef UNWIND_SECOND_LEVEL_REGULAR
141e589e7e3SJason Molenda #define UNWIND_SECOND_LEVEL_REGULAR 2
142e589e7e3SJason Molenda #endif
143e589e7e3SJason Molenda 
144e589e7e3SJason Molenda #ifndef UNWIND_SECOND_LEVEL_COMPRESSED
145e589e7e3SJason Molenda #define UNWIND_SECOND_LEVEL_COMPRESSED 3
146e589e7e3SJason Molenda #endif
147e589e7e3SJason Molenda 
148e589e7e3SJason Molenda #ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
149e589e7e3SJason Molenda #define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
150e589e7e3SJason Molenda #endif
151e589e7e3SJason Molenda 
152e589e7e3SJason Molenda #ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
153b9c1b51eSKate Stone #define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry)                     \
154b9c1b51eSKate Stone   ((entry >> 24) & 0xFF)
155e589e7e3SJason Molenda #endif
156e589e7e3SJason Molenda 
157e589e7e3SJason Molenda #define EXTRACT_BITS(value, mask)                                              \
158b9c1b51eSKate Stone   ((value >>                                                                   \
159b9c1b51eSKate Stone     llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) &   \
1602ea19616SBenjamin Kramer    (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1))
161e589e7e3SJason Molenda 
162e589e7e3SJason Molenda // constructor
163e589e7e3SJason Molenda 
CompactUnwindInfo(ObjectFile & objfile,SectionSP & section_sp)164bb19a13cSSaleem Abdulrasool CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP &section_sp)
165b9c1b51eSKate Stone     : m_objfile(objfile), m_section_sp(section_sp),
166b9c1b51eSKate Stone       m_section_contents_if_encrypted(), m_mutex(), m_indexes(),
167b9c1b51eSKate Stone       m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(),
168b9c1b51eSKate Stone       m_unwindinfo_data_computed(false), m_unwind_header() {}
169e589e7e3SJason Molenda 
170e589e7e3SJason Molenda // destructor
171e589e7e3SJason Molenda 
172fd2433e1SJonas Devlieghere CompactUnwindInfo::~CompactUnwindInfo() = default;
173e589e7e3SJason Molenda 
GetUnwindPlan(Target & target,Address addr,UnwindPlan & unwind_plan)174b9c1b51eSKate Stone bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
175b9c1b51eSKate Stone                                       UnwindPlan &unwind_plan) {
176b9c1b51eSKate Stone   if (!IsValid(target.GetProcessSP())) {
177e589e7e3SJason Molenda     return false;
178e589e7e3SJason Molenda   }
179e589e7e3SJason Molenda   FunctionInfo function_info;
180b9c1b51eSKate Stone   if (GetCompactUnwindInfoForFunction(target, addr, function_info)) {
181e589e7e3SJason Molenda     // shortcut return for functions that have no compact unwind
182e589e7e3SJason Molenda     if (function_info.encoding == 0)
183e589e7e3SJason Molenda       return false;
184e589e7e3SJason Molenda 
185f760f5aeSPavel Labath     if (ArchSpec arch = m_objfile.GetArchitecture()) {
1865c45c541SJason Molenda 
187a007a6d8SPavel Labath       Log *log = GetLog(LLDBLog::Unwind);
188b9c1b51eSKate Stone       if (log && log->GetVerbose()) {
1895c45c541SJason Molenda         StreamString strm;
190b9c1b51eSKate Stone         addr.Dump(
191248a1305SKonrad Kleine             &strm, nullptr,
192b9c1b51eSKate Stone             Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments,
193b9c1b51eSKate Stone             Address::DumpStyle::DumpStyleFileAddress,
194b9c1b51eSKate Stone             arch.GetAddressByteSize());
19563e5fb76SJonas Devlieghere         LLDB_LOGF(log, "Got compact unwind encoding 0x%x for function %s",
196b9c1b51eSKate Stone                   function_info.encoding, strm.GetData());
1975c45c541SJason Molenda       }
1985c45c541SJason Molenda 
199b9c1b51eSKate Stone       if (function_info.valid_range_offset_start != 0 &&
200b9c1b51eSKate Stone           function_info.valid_range_offset_end != 0) {
2015c45c541SJason Molenda         SectionList *sl = m_objfile.GetSectionList();
202b9c1b51eSKate Stone         if (sl) {
2035c45c541SJason Molenda           addr_t func_range_start_file_addr =
204b9c1b51eSKate Stone               function_info.valid_range_offset_start +
205d1e3fe21SPavel Labath               m_objfile.GetBaseAddress().GetFileAddress();
2065c45c541SJason Molenda           AddressRange func_range(func_range_start_file_addr,
207b9c1b51eSKate Stone                                   function_info.valid_range_offset_end -
208b9c1b51eSKate Stone                                       function_info.valid_range_offset_start,
2095c45c541SJason Molenda                                   sl);
2105c45c541SJason Molenda           unwind_plan.SetPlanValidAddressRange(func_range);
2115c45c541SJason Molenda         }
2125c45c541SJason Molenda       }
2135c45c541SJason Molenda 
214b9c1b51eSKate Stone       if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
215b9c1b51eSKate Stone         return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
216b9c1b51eSKate Stone                                        addr);
217e589e7e3SJason Molenda       }
2187dd7a360SJason Molenda       if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
2197dd7a360SJason Molenda           arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {
220b667c202SJason Molenda         return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
221b667c202SJason Molenda       }
222b9c1b51eSKate Stone       if (arch.GetTriple().getArch() == llvm::Triple::x86) {
223e589e7e3SJason Molenda         return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
224e589e7e3SJason Molenda       }
225b9c1b51eSKate Stone       if (arch.GetTriple().getArch() == llvm::Triple::arm ||
226b9c1b51eSKate Stone           arch.GetTriple().getArch() == llvm::Triple::thumb) {
227c7afda5aSJason Molenda         return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);
228c7afda5aSJason Molenda       }
229e589e7e3SJason Molenda     }
230e589e7e3SJason Molenda   }
231e589e7e3SJason Molenda   return false;
232e589e7e3SJason Molenda }
233e589e7e3SJason Molenda 
IsValid(const ProcessSP & process_sp)234b9c1b51eSKate Stone bool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
235b12a136cSJason Molenda   if (m_section_sp.get() == nullptr)
236e589e7e3SJason Molenda     return false;
237e589e7e3SJason Molenda 
238e589e7e3SJason Molenda   if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
239e589e7e3SJason Molenda     return true;
240e589e7e3SJason Molenda 
241b12a136cSJason Molenda   ScanIndex(process_sp);
242e589e7e3SJason Molenda 
243e589e7e3SJason Molenda   return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
244e589e7e3SJason Molenda }
245e589e7e3SJason Molenda 
ScanIndex(const ProcessSP & process_sp)246b9c1b51eSKate Stone void CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
247bb19a13cSSaleem Abdulrasool   std::lock_guard<std::mutex> guard(m_mutex);
248e589e7e3SJason Molenda   if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
249e589e7e3SJason Molenda     return;
250e589e7e3SJason Molenda 
251e589e7e3SJason Molenda   // We can't read the index for some reason.
252b9c1b51eSKate Stone   if (m_indexes_computed == eLazyBoolNo) {
253e589e7e3SJason Molenda     return;
254e589e7e3SJason Molenda   }
255e589e7e3SJason Molenda 
256a007a6d8SPavel Labath   Log *log = GetLog(LLDBLog::Unwind);
2575c45c541SJason Molenda   if (log)
258b9c1b51eSKate Stone     m_objfile.GetModule()->LogMessage(
259b9c1b51eSKate Stone         log, "Reading compact unwind first-level indexes");
2605c45c541SJason Molenda 
261a6682a41SJonas Devlieghere   if (!m_unwindinfo_data_computed) {
262b9c1b51eSKate Stone     if (m_section_sp->IsEncrypted()) {
263b9c1b51eSKate Stone       // Can't get section contents of a protected/encrypted section until we
26405097246SAdrian Prantl       // have a live process and can read them out of memory.
265b12a136cSJason Molenda       if (process_sp.get() == nullptr)
266b12a136cSJason Molenda         return;
267796ac80bSJonas Devlieghere       m_section_contents_if_encrypted =
268796ac80bSJonas Devlieghere           std::make_shared<DataBufferHeap>(m_section_sp->GetByteSize(), 0);
26997206d57SZachary Turner       Status error;
270b12a136cSJason Molenda       if (process_sp->ReadMemory(
271b12a136cSJason Molenda               m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
272b12a136cSJason Molenda               m_section_contents_if_encrypted->GetBytes(),
273b9c1b51eSKate Stone               m_section_sp->GetByteSize(),
274b9c1b51eSKate Stone               error) == m_section_sp->GetByteSize() &&
275b9c1b51eSKate Stone           error.Success()) {
276b9c1b51eSKate Stone         m_unwindinfo_data.SetAddressByteSize(
277b9c1b51eSKate Stone             process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
278b9c1b51eSKate Stone         m_unwindinfo_data.SetByteOrder(
279b9c1b51eSKate Stone             process_sp->GetTarget().GetArchitecture().GetByteOrder());
280b12a136cSJason Molenda         m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);
281b12a136cSJason Molenda       }
282b9c1b51eSKate Stone     } else {
283e589e7e3SJason Molenda       m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
284b12a136cSJason Molenda     }
285b12a136cSJason Molenda     if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
286b12a136cSJason Molenda       return;
287e589e7e3SJason Molenda     m_unwindinfo_data_computed = true;
288e589e7e3SJason Molenda   }
289e589e7e3SJason Molenda 
290b9c1b51eSKate Stone   if (m_unwindinfo_data.GetByteSize() > 0) {
291e589e7e3SJason Molenda     offset_t offset = 0;
292e589e7e3SJason Molenda 
293e589e7e3SJason Molenda     // struct unwind_info_section_header
294e589e7e3SJason Molenda     // {
295e589e7e3SJason Molenda     // uint32_t    version;            // UNWIND_SECTION_VERSION
296e589e7e3SJason Molenda     // uint32_t    commonEncodingsArraySectionOffset;
297e589e7e3SJason Molenda     // uint32_t    commonEncodingsArrayCount;
298e589e7e3SJason Molenda     // uint32_t    personalityArraySectionOffset;
299e589e7e3SJason Molenda     // uint32_t    personalityArrayCount;
300e589e7e3SJason Molenda     // uint32_t    indexSectionOffset;
301e589e7e3SJason Molenda     // uint32_t    indexCount;
302e589e7e3SJason Molenda 
303e589e7e3SJason Molenda     m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
304b9c1b51eSKate Stone     m_unwind_header.common_encodings_array_offset =
305b9c1b51eSKate Stone         m_unwindinfo_data.GetU32(&offset);
306b9c1b51eSKate Stone     m_unwind_header.common_encodings_array_count =
307b9c1b51eSKate Stone         m_unwindinfo_data.GetU32(&offset);
308b9c1b51eSKate Stone     m_unwind_header.personality_array_offset =
309b9c1b51eSKate Stone         m_unwindinfo_data.GetU32(&offset);
310e589e7e3SJason Molenda     m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
311e589e7e3SJason Molenda     uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
312e589e7e3SJason Molenda 
313e589e7e3SJason Molenda     uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
314e589e7e3SJason Molenda 
315b9c1b51eSKate Stone     if (m_unwind_header.common_encodings_array_offset >
316b9c1b51eSKate Stone             m_unwindinfo_data.GetByteSize() ||
317b9c1b51eSKate Stone         m_unwind_header.personality_array_offset >
318b9c1b51eSKate Stone             m_unwindinfo_data.GetByteSize() ||
319b9c1b51eSKate Stone         indexSectionOffset > m_unwindinfo_data.GetByteSize() ||
320b9c1b51eSKate Stone         offset > m_unwindinfo_data.GetByteSize()) {
321*68793919SJonas Devlieghere       Debugger::ReportError(
322*68793919SJonas Devlieghere           "Invalid offset encountered in compact unwind info, skipping");
323c48ef341SJason Molenda       // don't trust anything from this compact_unwind section if it looks
324e171da5cSBruce Mitchener       // blatantly invalid data in the header.
325e589e7e3SJason Molenda       m_indexes_computed = eLazyBoolNo;
326c48ef341SJason Molenda       return;
327e589e7e3SJason Molenda     }
328e589e7e3SJason Molenda 
32905097246SAdrian Prantl     // Parse the basic information from the indexes We wait to scan the second
33005097246SAdrian Prantl     // level page info until it's needed
331e589e7e3SJason Molenda 
33205097246SAdrian Prantl     // struct unwind_info_section_header_index_entry {
333e589e7e3SJason Molenda     //     uint32_t        functionOffset;
334e589e7e3SJason Molenda     //     uint32_t        secondLevelPagesSectionOffset;
335e589e7e3SJason Molenda     //     uint32_t        lsdaIndexArraySectionOffset;
336e589e7e3SJason Molenda     // };
337e589e7e3SJason Molenda 
338c7afda5aSJason Molenda     bool clear_address_zeroth_bit = false;
339f760f5aeSPavel Labath     if (ArchSpec arch = m_objfile.GetArchitecture()) {
340b9c1b51eSKate Stone       if (arch.GetTriple().getArch() == llvm::Triple::arm ||
341b9c1b51eSKate Stone           arch.GetTriple().getArch() == llvm::Triple::thumb)
342c7afda5aSJason Molenda         clear_address_zeroth_bit = true;
343c7afda5aSJason Molenda     }
344c7afda5aSJason Molenda 
345e589e7e3SJason Molenda     offset = indexSectionOffset;
346b9c1b51eSKate Stone     for (uint32_t idx = 0; idx < indexCount; idx++) {
347b9c1b51eSKate Stone       uint32_t function_offset =
348b9c1b51eSKate Stone           m_unwindinfo_data.GetU32(&offset); // functionOffset
349b9c1b51eSKate Stone       uint32_t second_level_offset =
350b9c1b51eSKate Stone           m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
351b9c1b51eSKate Stone       uint32_t lsda_offset =
352b9c1b51eSKate Stone           m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
353e589e7e3SJason Molenda 
354b9c1b51eSKate Stone       if (second_level_offset > m_section_sp->GetByteSize() ||
355b9c1b51eSKate Stone           lsda_offset > m_section_sp->GetByteSize()) {
356e589e7e3SJason Molenda         m_indexes_computed = eLazyBoolNo;
357e589e7e3SJason Molenda       }
358e589e7e3SJason Molenda 
359c7afda5aSJason Molenda       if (clear_address_zeroth_bit)
360c7afda5aSJason Molenda         function_offset &= ~1ull;
361c7afda5aSJason Molenda 
362e589e7e3SJason Molenda       UnwindIndex this_index;
363c7afda5aSJason Molenda       this_index.function_offset = function_offset;
364e589e7e3SJason Molenda       this_index.second_level = second_level_offset;
365e589e7e3SJason Molenda       this_index.lsda_array_start = lsda_offset;
366e589e7e3SJason Molenda 
367b9c1b51eSKate Stone       if (m_indexes.size() > 0) {
368e589e7e3SJason Molenda         m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
369e589e7e3SJason Molenda       }
370e589e7e3SJason Molenda 
371b9c1b51eSKate Stone       if (second_level_offset == 0) {
372e589e7e3SJason Molenda         this_index.sentinal_entry = true;
373e589e7e3SJason Molenda       }
374e589e7e3SJason Molenda 
375e589e7e3SJason Molenda       m_indexes.push_back(this_index);
376e589e7e3SJason Molenda     }
377e589e7e3SJason Molenda     m_indexes_computed = eLazyBoolYes;
378b9c1b51eSKate Stone   } else {
379e589e7e3SJason Molenda     m_indexes_computed = eLazyBoolNo;
380e589e7e3SJason Molenda   }
381e589e7e3SJason Molenda }
382e589e7e3SJason Molenda 
GetLSDAForFunctionOffset(uint32_t lsda_offset,uint32_t lsda_count,uint32_t function_offset)383b9c1b51eSKate Stone uint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
384b9c1b51eSKate Stone                                                      uint32_t lsda_count,
385b9c1b51eSKate Stone                                                      uint32_t function_offset) {
38605097246SAdrian Prantl   // struct unwind_info_section_header_lsda_index_entry {
387e589e7e3SJason Molenda   //         uint32_t        functionOffset;
388e589e7e3SJason Molenda   //         uint32_t        lsdaOffset;
389e589e7e3SJason Molenda   // };
390e589e7e3SJason Molenda 
391e589e7e3SJason Molenda   offset_t first_entry = lsda_offset;
392e589e7e3SJason Molenda   uint32_t low = 0;
393e589e7e3SJason Molenda   uint32_t high = lsda_count;
394b9c1b51eSKate Stone   while (low < high) {
395e589e7e3SJason Molenda     uint32_t mid = (low + high) / 2;
396e589e7e3SJason Molenda     offset_t offset = first_entry + (mid * 8);
397b9c1b51eSKate Stone     uint32_t mid_func_offset =
398b9c1b51eSKate Stone         m_unwindinfo_data.GetU32(&offset); // functionOffset
399e589e7e3SJason Molenda     uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
400b9c1b51eSKate Stone     if (mid_func_offset == function_offset) {
401e589e7e3SJason Molenda       return mid_lsda_offset;
402e589e7e3SJason Molenda     }
403b9c1b51eSKate Stone     if (mid_func_offset < function_offset) {
404e589e7e3SJason Molenda       low = mid + 1;
405b9c1b51eSKate Stone     } else {
406e589e7e3SJason Molenda       high = mid;
407e589e7e3SJason Molenda     }
408e589e7e3SJason Molenda   }
409e589e7e3SJason Molenda   return 0;
410e589e7e3SJason Molenda }
411e589e7e3SJason Molenda 
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)412b9c1b51eSKate Stone lldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(
413b9c1b51eSKate Stone     uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,
414b9c1b51eSKate Stone     uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
415e589e7e3SJason Molenda   // typedef uint32_t compact_unwind_encoding_t;
41605097246SAdrian Prantl   // struct unwind_info_regular_second_level_entry {
417e589e7e3SJason Molenda   //     uint32_t                    functionOffset;
418e589e7e3SJason Molenda   //     compact_unwind_encoding_t    encoding;
419e589e7e3SJason Molenda 
420e589e7e3SJason Molenda   offset_t first_entry = entry_page_offset;
421e589e7e3SJason Molenda 
422e589e7e3SJason Molenda   uint32_t low = 0;
423e589e7e3SJason Molenda   uint32_t high = entry_count;
424e589e7e3SJason Molenda   uint32_t last = high - 1;
425b9c1b51eSKate Stone   while (low < high) {
426e589e7e3SJason Molenda     uint32_t mid = (low + high) / 2;
427e589e7e3SJason Molenda     offset_t offset = first_entry + (mid * 8);
428b9c1b51eSKate Stone     uint32_t mid_func_offset =
429b9c1b51eSKate Stone         m_unwindinfo_data.GetU32(&offset); // functionOffset
430e589e7e3SJason Molenda     uint32_t next_func_offset = 0;
431b9c1b51eSKate Stone     if (mid < last) {
432e589e7e3SJason Molenda       offset = first_entry + ((mid + 1) * 8);
433e589e7e3SJason Molenda       next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
434e589e7e3SJason Molenda     }
435b9c1b51eSKate Stone     if (mid_func_offset <= function_offset) {
436b9c1b51eSKate Stone       if (mid == last || (next_func_offset > function_offset)) {
4375c45c541SJason Molenda         if (entry_func_start_offset)
4385c45c541SJason Molenda           *entry_func_start_offset = mid_func_offset;
4395c45c541SJason Molenda         if (mid != last && entry_func_end_offset)
4405c45c541SJason Molenda           *entry_func_end_offset = next_func_offset;
441e589e7e3SJason Molenda         return first_entry + (mid * 8);
442b9c1b51eSKate Stone       } else {
443e589e7e3SJason Molenda         low = mid + 1;
444e589e7e3SJason Molenda       }
445b9c1b51eSKate Stone     } else {
446e589e7e3SJason Molenda       high = mid;
447e589e7e3SJason Molenda     }
448e589e7e3SJason Molenda   }
449e589e7e3SJason Molenda   return LLDB_INVALID_OFFSET;
450e589e7e3SJason Molenda }
451e589e7e3SJason Molenda 
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)452b9c1b51eSKate Stone uint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(
453b9c1b51eSKate Stone     uint32_t entry_page_offset, uint32_t entry_count,
454b9c1b51eSKate Stone     uint32_t function_offset_to_find, uint32_t function_offset_base,
455b9c1b51eSKate Stone     uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
456e589e7e3SJason Molenda   offset_t first_entry = entry_page_offset;
457e589e7e3SJason Molenda 
458e589e7e3SJason Molenda   uint32_t low = 0;
459e589e7e3SJason Molenda   uint32_t high = entry_count;
460e589e7e3SJason Molenda   uint32_t last = high - 1;
461b9c1b51eSKate Stone   while (low < high) {
462e589e7e3SJason Molenda     uint32_t mid = (low + high) / 2;
463e589e7e3SJason Molenda     offset_t offset = first_entry + (mid * 4);
464e589e7e3SJason Molenda     uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
465e589e7e3SJason Molenda     uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
466e589e7e3SJason Molenda     mid_func_offset += function_offset_base;
467e589e7e3SJason Molenda     uint32_t next_func_offset = 0;
468b9c1b51eSKate Stone     if (mid < last) {
469e589e7e3SJason Molenda       offset = first_entry + ((mid + 1) * 4);
470e589e7e3SJason Molenda       uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
471e589e7e3SJason Molenda       next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);
472e589e7e3SJason Molenda       next_func_offset += function_offset_base;
473e589e7e3SJason Molenda     }
474b9c1b51eSKate Stone     if (mid_func_offset <= function_offset_to_find) {
475b9c1b51eSKate Stone       if (mid == last || (next_func_offset > function_offset_to_find)) {
4765c45c541SJason Molenda         if (entry_func_start_offset)
4775c45c541SJason Molenda           *entry_func_start_offset = mid_func_offset;
4785c45c541SJason Molenda         if (mid != last && entry_func_end_offset)
4795c45c541SJason Molenda           *entry_func_end_offset = next_func_offset;
480e589e7e3SJason Molenda         return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
481b9c1b51eSKate Stone       } else {
482e589e7e3SJason Molenda         low = mid + 1;
483e589e7e3SJason Molenda       }
484b9c1b51eSKate Stone     } else {
485e589e7e3SJason Molenda       high = mid;
486e589e7e3SJason Molenda     }
487e589e7e3SJason Molenda   }
488e589e7e3SJason Molenda 
489e589e7e3SJason Molenda   return UINT32_MAX;
490e589e7e3SJason Molenda }
491e589e7e3SJason Molenda 
GetCompactUnwindInfoForFunction(Target & target,Address address,FunctionInfo & unwind_info)492b9c1b51eSKate Stone bool CompactUnwindInfo::GetCompactUnwindInfoForFunction(
493b9c1b51eSKate Stone     Target &target, Address address, FunctionInfo &unwind_info) {
494e589e7e3SJason Molenda   unwind_info.encoding = 0;
495e589e7e3SJason Molenda   unwind_info.lsda_address.Clear();
496e589e7e3SJason Molenda   unwind_info.personality_ptr_address.Clear();
497e589e7e3SJason Molenda 
498b12a136cSJason Molenda   if (!IsValid(target.GetProcessSP()))
4990f479da7SJason Molenda     return false;
5000f479da7SJason Molenda 
501e589e7e3SJason Molenda   addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
502e589e7e3SJason Molenda   SectionList *sl = m_objfile.GetSectionList();
503b9c1b51eSKate Stone   if (sl) {
504e589e7e3SJason Molenda     SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
505b9c1b51eSKate Stone     if (text_sect.get()) {
506e589e7e3SJason Molenda       text_section_file_address = text_sect->GetFileAddress();
507e589e7e3SJason Molenda     }
508e589e7e3SJason Molenda   }
509e589e7e3SJason Molenda   if (text_section_file_address == LLDB_INVALID_ADDRESS)
510e589e7e3SJason Molenda     return false;
511e589e7e3SJason Molenda 
512b9c1b51eSKate Stone   addr_t function_offset =
513d1e3fe21SPavel Labath       address.GetFileAddress() - m_objfile.GetBaseAddress().GetFileAddress();
514e589e7e3SJason Molenda 
515e589e7e3SJason Molenda   UnwindIndex key;
516e589e7e3SJason Molenda   key.function_offset = function_offset;
517e589e7e3SJason Molenda 
518e589e7e3SJason Molenda   std::vector<UnwindIndex>::const_iterator it;
519e589e7e3SJason Molenda   it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key);
520b9c1b51eSKate Stone   if (it == m_indexes.end()) {
521e589e7e3SJason Molenda     return false;
522e589e7e3SJason Molenda   }
523e589e7e3SJason Molenda 
524b9c1b51eSKate Stone   if (it->function_offset != key.function_offset) {
525e589e7e3SJason Molenda     if (it != m_indexes.begin())
526e589e7e3SJason Molenda       --it;
527e589e7e3SJason Molenda   }
528e589e7e3SJason Molenda 
529a6682a41SJonas Devlieghere   if (it->sentinal_entry) {
530e589e7e3SJason Molenda     return false;
531e589e7e3SJason Molenda   }
532e589e7e3SJason Molenda 
5335c45c541SJason Molenda   auto next_it = it + 1;
534b9c1b51eSKate Stone   if (next_it != m_indexes.end()) {
53505097246SAdrian Prantl     // initialize the function offset end range to be the start of the next
53605097246SAdrian Prantl     // index offset.  If we find an entry which is at the end of the index
53705097246SAdrian Prantl     // table, this will establish the range end.
5385c45c541SJason Molenda     unwind_info.valid_range_offset_end = next_it->function_offset;
5395c45c541SJason Molenda   }
5405c45c541SJason Molenda 
541e589e7e3SJason Molenda   offset_t second_page_offset = it->second_level;
542e589e7e3SJason Molenda   offset_t lsda_array_start = it->lsda_array_start;
543e589e7e3SJason Molenda   offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
544e589e7e3SJason Molenda 
545e589e7e3SJason Molenda   offset_t offset = second_page_offset;
546b9c1b51eSKate Stone   uint32_t kind = m_unwindinfo_data.GetU32(
547b9c1b51eSKate Stone       &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
548e589e7e3SJason Molenda 
549b9c1b51eSKate Stone   if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
55005097246SAdrian Prantl     // struct unwind_info_regular_second_level_page_header {
551e589e7e3SJason Molenda     //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_REGULAR
552e589e7e3SJason Molenda     //     uint16_t    entryPageOffset;
553e589e7e3SJason Molenda     //     uint16_t    entryCount;
554e589e7e3SJason Molenda 
555e589e7e3SJason Molenda     // typedef uint32_t compact_unwind_encoding_t;
55605097246SAdrian Prantl     // struct unwind_info_regular_second_level_entry {
557e589e7e3SJason Molenda     //     uint32_t                    functionOffset;
558e589e7e3SJason Molenda     //     compact_unwind_encoding_t    encoding;
559e589e7e3SJason Molenda 
560b9c1b51eSKate Stone     uint16_t entry_page_offset =
561b9c1b51eSKate Stone         m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
562e589e7e3SJason Molenda     uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
563e589e7e3SJason Molenda 
564b9c1b51eSKate Stone     offset_t entry_offset = BinarySearchRegularSecondPage(
565b9c1b51eSKate Stone         second_page_offset + entry_page_offset, entry_count, function_offset,
566b9c1b51eSKate Stone         &unwind_info.valid_range_offset_start,
567b9c1b51eSKate Stone         &unwind_info.valid_range_offset_end);
568b9c1b51eSKate Stone     if (entry_offset == LLDB_INVALID_OFFSET) {
569e589e7e3SJason Molenda       return false;
570e589e7e3SJason Molenda     }
571e589e7e3SJason Molenda     entry_offset += 4; // skip over functionOffset
572e589e7e3SJason Molenda     unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
573b9c1b51eSKate Stone     if (unwind_info.encoding & UNWIND_HAS_LSDA) {
574e589e7e3SJason Molenda       SectionList *sl = m_objfile.GetSectionList();
575b9c1b51eSKate Stone       if (sl) {
576b9c1b51eSKate Stone         uint32_t lsda_offset = GetLSDAForFunctionOffset(
577b9c1b51eSKate Stone             lsda_array_start, lsda_array_count, function_offset);
578d1e3fe21SPavel Labath         addr_t objfile_base_address =
579d1e3fe21SPavel Labath             m_objfile.GetBaseAddress().GetFileAddress();
580b9c1b51eSKate Stone         unwind_info.lsda_address.ResolveAddressUsingFileSections(
581d1e3fe21SPavel Labath             objfile_base_address + lsda_offset, sl);
582e589e7e3SJason Molenda       }
583e589e7e3SJason Molenda     }
584b9c1b51eSKate Stone     if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
585b9c1b51eSKate Stone       uint32_t personality_index =
586b9c1b51eSKate Stone           EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
587e589e7e3SJason Molenda 
588b9c1b51eSKate Stone       if (personality_index > 0) {
589e589e7e3SJason Molenda         personality_index--;
590b9c1b51eSKate Stone         if (personality_index < m_unwind_header.personality_array_count) {
591e589e7e3SJason Molenda           offset_t offset = m_unwind_header.personality_array_offset;
592e589e7e3SJason Molenda           offset += 4 * personality_index;
593e589e7e3SJason Molenda           SectionList *sl = m_objfile.GetSectionList();
594b9c1b51eSKate Stone           if (sl) {
595e589e7e3SJason Molenda             uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
596d1e3fe21SPavel Labath             addr_t objfile_base_address =
597d1e3fe21SPavel Labath                 m_objfile.GetBaseAddress().GetFileAddress();
598b9c1b51eSKate Stone             unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
599d1e3fe21SPavel Labath                 objfile_base_address + personality_offset, sl);
600e589e7e3SJason Molenda           }
601e589e7e3SJason Molenda         }
602e589e7e3SJason Molenda       }
603e589e7e3SJason Molenda     }
604e589e7e3SJason Molenda     return true;
605b9c1b51eSKate Stone   } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
60605097246SAdrian Prantl     // struct unwind_info_compressed_second_level_page_header {
607e589e7e3SJason Molenda     //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_COMPRESSED
608b9c1b51eSKate Stone     //     uint16_t    entryPageOffset;         // offset from this 2nd lvl page
609b9c1b51eSKate Stone     //     idx to array of entries
610b9c1b51eSKate Stone     //                                          // (an entry has a function
611b9c1b51eSKate Stone     //                                          offset and index into the
612b9c1b51eSKate Stone     //                                          encodings)
613b9c1b51eSKate Stone     //                                          // NB function offset from the
614b9c1b51eSKate Stone     //                                          entry in the compressed page
615b9c1b51eSKate Stone     //                                          // must be added to the index's
616b9c1b51eSKate Stone     //                                          functionOffset value.
617e589e7e3SJason Molenda     //     uint16_t    entryCount;
618b9c1b51eSKate Stone     //     uint16_t    encodingsPageOffset;     // offset from this 2nd lvl page
619b9c1b51eSKate Stone     //     idx to array of encodings
620e589e7e3SJason Molenda     //     uint16_t    encodingsCount;
621e589e7e3SJason Molenda 
622b9c1b51eSKate Stone     uint16_t entry_page_offset =
623b9c1b51eSKate Stone         m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
624e589e7e3SJason Molenda     uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
625b9c1b51eSKate Stone     uint16_t encodings_page_offset =
626b9c1b51eSKate Stone         m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
627b9c1b51eSKate Stone     uint16_t encodings_count =
628b9c1b51eSKate Stone         m_unwindinfo_data.GetU16(&offset); // encodingsCount
629e589e7e3SJason Molenda 
630b9c1b51eSKate Stone     uint32_t encoding_index = BinarySearchCompressedSecondPage(
631b9c1b51eSKate Stone         second_page_offset + entry_page_offset, entry_count, function_offset,
632b9c1b51eSKate Stone         it->function_offset, &unwind_info.valid_range_offset_start,
633b9c1b51eSKate Stone         &unwind_info.valid_range_offset_end);
634b9c1b51eSKate Stone     if (encoding_index == UINT32_MAX ||
635b9c1b51eSKate Stone         encoding_index >=
636b9c1b51eSKate Stone             encodings_count + m_unwind_header.common_encodings_array_count) {
637e589e7e3SJason Molenda       return false;
638e589e7e3SJason Molenda     }
639e589e7e3SJason Molenda     uint32_t encoding = 0;
640b9c1b51eSKate Stone     if (encoding_index < m_unwind_header.common_encodings_array_count) {
641b9c1b51eSKate Stone       offset = m_unwind_header.common_encodings_array_offset +
642b9c1b51eSKate Stone                (encoding_index * sizeof(uint32_t));
643b9c1b51eSKate Stone       encoding = m_unwindinfo_data.GetU32(
644b9c1b51eSKate Stone           &offset); // encoding entry from the commonEncodingsArray
645b9c1b51eSKate Stone     } else {
646b9c1b51eSKate Stone       uint32_t page_specific_entry_index =
647b9c1b51eSKate Stone           encoding_index - m_unwind_header.common_encodings_array_count;
648b9c1b51eSKate Stone       offset = second_page_offset + encodings_page_offset +
649b9c1b51eSKate Stone                (page_specific_entry_index * sizeof(uint32_t));
650b9c1b51eSKate Stone       encoding = m_unwindinfo_data.GetU32(
651b9c1b51eSKate Stone           &offset); // encoding entry from the page-specific encoding array
652e589e7e3SJason Molenda     }
653e589e7e3SJason Molenda     if (encoding == 0)
654e589e7e3SJason Molenda       return false;
655e589e7e3SJason Molenda 
656e589e7e3SJason Molenda     unwind_info.encoding = encoding;
657b9c1b51eSKate Stone     if (unwind_info.encoding & UNWIND_HAS_LSDA) {
658e589e7e3SJason Molenda       SectionList *sl = m_objfile.GetSectionList();
659b9c1b51eSKate Stone       if (sl) {
660b9c1b51eSKate Stone         uint32_t lsda_offset = GetLSDAForFunctionOffset(
661b9c1b51eSKate Stone             lsda_array_start, lsda_array_count, function_offset);
662d1e3fe21SPavel Labath         addr_t objfile_base_address =
663d1e3fe21SPavel Labath             m_objfile.GetBaseAddress().GetFileAddress();
664b9c1b51eSKate Stone         unwind_info.lsda_address.ResolveAddressUsingFileSections(
665d1e3fe21SPavel Labath             objfile_base_address + lsda_offset, sl);
666e589e7e3SJason Molenda       }
667e589e7e3SJason Molenda     }
668b9c1b51eSKate Stone     if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
669b9c1b51eSKate Stone       uint32_t personality_index =
670b9c1b51eSKate Stone           EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
671e589e7e3SJason Molenda 
672b9c1b51eSKate Stone       if (personality_index > 0) {
673e589e7e3SJason Molenda         personality_index--;
674b9c1b51eSKate Stone         if (personality_index < m_unwind_header.personality_array_count) {
675e589e7e3SJason Molenda           offset_t offset = m_unwind_header.personality_array_offset;
676e589e7e3SJason Molenda           offset += 4 * personality_index;
677e589e7e3SJason Molenda           SectionList *sl = m_objfile.GetSectionList();
678b9c1b51eSKate Stone           if (sl) {
679e589e7e3SJason Molenda             uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
680d1e3fe21SPavel Labath             addr_t objfile_base_address =
681d1e3fe21SPavel Labath                 m_objfile.GetBaseAddress().GetFileAddress();
682b9c1b51eSKate Stone             unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
683d1e3fe21SPavel Labath                 objfile_base_address + personality_offset, sl);
684e589e7e3SJason Molenda           }
685e589e7e3SJason Molenda         }
686e589e7e3SJason Molenda       }
687e589e7e3SJason Molenda     }
688e589e7e3SJason Molenda     return true;
689e589e7e3SJason Molenda   }
690e589e7e3SJason Molenda   return false;
691e589e7e3SJason Molenda }
692e589e7e3SJason Molenda 
693e589e7e3SJason Molenda enum x86_64_eh_regnum {
694e589e7e3SJason Molenda   rax = 0,
695e589e7e3SJason Molenda   rdx = 1,
696e589e7e3SJason Molenda   rcx = 2,
697e589e7e3SJason Molenda   rbx = 3,
698e589e7e3SJason Molenda   rsi = 4,
699e589e7e3SJason Molenda   rdi = 5,
700e589e7e3SJason Molenda   rbp = 6,
701e589e7e3SJason Molenda   rsp = 7,
702e589e7e3SJason Molenda   r8 = 8,
703e589e7e3SJason Molenda   r9 = 9,
704e589e7e3SJason Molenda   r10 = 10,
705e589e7e3SJason Molenda   r11 = 11,
706e589e7e3SJason Molenda   r12 = 12,
707e589e7e3SJason Molenda   r13 = 13,
708e589e7e3SJason Molenda   r14 = 14,
709e589e7e3SJason Molenda   r15 = 15,
710b9c1b51eSKate Stone   rip = 16 // this is officially the Return Address register number, but close
711b9c1b51eSKate Stone            // enough
712e589e7e3SJason Molenda };
713e589e7e3SJason Molenda 
71405097246SAdrian Prantl // Convert the compact_unwind_info.h register numbering scheme to
71505097246SAdrian Prantl // eRegisterKindEHFrame (eh_frame) register numbering scheme.
translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno)716b9c1b51eSKate Stone uint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {
717b9c1b51eSKate Stone   switch (unwind_regno) {
718e589e7e3SJason Molenda   case UNWIND_X86_64_REG_RBX:
719e589e7e3SJason Molenda     return x86_64_eh_regnum::rbx;
720e589e7e3SJason Molenda   case UNWIND_X86_64_REG_R12:
721e589e7e3SJason Molenda     return x86_64_eh_regnum::r12;
722e589e7e3SJason Molenda   case UNWIND_X86_64_REG_R13:
723e589e7e3SJason Molenda     return x86_64_eh_regnum::r13;
724e589e7e3SJason Molenda   case UNWIND_X86_64_REG_R14:
725e589e7e3SJason Molenda     return x86_64_eh_regnum::r14;
726e589e7e3SJason Molenda   case UNWIND_X86_64_REG_R15:
727e589e7e3SJason Molenda     return x86_64_eh_regnum::r15;
728e589e7e3SJason Molenda   case UNWIND_X86_64_REG_RBP:
729e589e7e3SJason Molenda     return x86_64_eh_regnum::rbp;
730e589e7e3SJason Molenda   default:
731e589e7e3SJason Molenda     return LLDB_INVALID_REGNUM;
732e589e7e3SJason Molenda   }
733e589e7e3SJason Molenda }
734e589e7e3SJason Molenda 
CreateUnwindPlan_x86_64(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)735b9c1b51eSKate Stone bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
736b9c1b51eSKate Stone                                                 FunctionInfo &function_info,
737b9c1b51eSKate Stone                                                 UnwindPlan &unwind_plan,
738b9c1b51eSKate Stone                                                 Address pc_or_function_start) {
739e589e7e3SJason Molenda   unwind_plan.SetSourceName("compact unwind info");
740e589e7e3SJason Molenda   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
741e589e7e3SJason Molenda   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
7423fd917d8SJoseph Tremoulet   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
743a18f7071SJason Molenda   unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
744e589e7e3SJason Molenda 
745e589e7e3SJason Molenda   unwind_plan.SetLSDAAddress(function_info.lsda_address);
746e589e7e3SJason Molenda   unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
747e589e7e3SJason Molenda 
748e589e7e3SJason Molenda   UnwindPlan::RowSP row(new UnwindPlan::Row);
749e589e7e3SJason Molenda 
750e589e7e3SJason Molenda   const int wordsize = 8;
751e589e7e3SJason Molenda   int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
752b9c1b51eSKate Stone   switch (mode) {
753b9c1b51eSKate Stone   case UNWIND_X86_64_MODE_RBP_FRAME: {
754ab970f5eSPavel Labath     row->GetCFAValue().SetIsRegisterPlusOffset(
755ab970f5eSPavel Labath         translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),
756ab970f5eSPavel Labath         2 * wordsize);
757e589e7e3SJason Molenda     row->SetOffset(0);
758b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,
759b9c1b51eSKate Stone                                               wordsize * -2, true);
760b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
761b9c1b51eSKate Stone                                               wordsize * -1, true);
762e589e7e3SJason Molenda     row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
763e589e7e3SJason Molenda 
764b9c1b51eSKate Stone     uint32_t saved_registers_offset =
765b9c1b51eSKate Stone         EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
766e589e7e3SJason Molenda 
767b9c1b51eSKate Stone     uint32_t saved_registers_locations =
768b9c1b51eSKate Stone         EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
769e589e7e3SJason Molenda 
770e589e7e3SJason Molenda     saved_registers_offset += 2;
771e589e7e3SJason Molenda 
772b9c1b51eSKate Stone     for (int i = 0; i < 5; i++) {
773e589e7e3SJason Molenda       uint32_t regnum = saved_registers_locations & 0x7;
774b9c1b51eSKate Stone       switch (regnum) {
775e589e7e3SJason Molenda       case UNWIND_X86_64_REG_NONE:
776e589e7e3SJason Molenda         break;
777e589e7e3SJason Molenda       case UNWIND_X86_64_REG_RBX:
778e589e7e3SJason Molenda       case UNWIND_X86_64_REG_R12:
779e589e7e3SJason Molenda       case UNWIND_X86_64_REG_R13:
780e589e7e3SJason Molenda       case UNWIND_X86_64_REG_R14:
781e589e7e3SJason Molenda       case UNWIND_X86_64_REG_R15:
782b9c1b51eSKate Stone         row->SetRegisterLocationToAtCFAPlusOffset(
783b9c1b51eSKate Stone             translate_to_eh_frame_regnum_x86_64(regnum),
784b9c1b51eSKate Stone             wordsize * -saved_registers_offset, true);
785e589e7e3SJason Molenda         break;
786e589e7e3SJason Molenda       }
787e589e7e3SJason Molenda       saved_registers_offset--;
788e589e7e3SJason Molenda       saved_registers_locations >>= 3;
789e589e7e3SJason Molenda     }
790e589e7e3SJason Molenda     unwind_plan.AppendRow(row);
791e589e7e3SJason Molenda     return true;
792b9c1b51eSKate Stone   } break;
793e589e7e3SJason Molenda 
794b9c1b51eSKate Stone   case UNWIND_X86_64_MODE_STACK_IND: {
795b9c1b51eSKate Stone     // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
79605097246SAdrian Prantl     // this style of unwind.  It was fixed in llvm r217020. The clang in Xcode
79705097246SAdrian Prantl     // 7 has this fixed.
798e589e7e3SJason Molenda     return false;
799b9c1b51eSKate Stone   } break;
800e589e7e3SJason Molenda 
801b9c1b51eSKate Stone   case UNWIND_X86_64_MODE_STACK_IMMD: {
802b9c1b51eSKate Stone     uint32_t stack_size = EXTRACT_BITS(function_info.encoding,
803b9c1b51eSKate Stone                                        UNWIND_X86_64_FRAMELESS_STACK_SIZE);
804b9c1b51eSKate Stone     uint32_t register_count = EXTRACT_BITS(
805b9c1b51eSKate Stone         function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
806b9c1b51eSKate Stone     uint32_t permutation = EXTRACT_BITS(
807b9c1b51eSKate Stone         function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
808e589e7e3SJason Molenda 
809b9c1b51eSKate Stone     if (mode == UNWIND_X86_64_MODE_STACK_IND &&
810b9c1b51eSKate Stone         function_info.valid_range_offset_start != 0) {
811b9c1b51eSKate Stone       uint32_t stack_adjust = EXTRACT_BITS(
812b9c1b51eSKate Stone           function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
813e589e7e3SJason Molenda 
814b9c1b51eSKate Stone       // offset into the function instructions; 0 == beginning of first
815b9c1b51eSKate Stone       // instruction
816b9c1b51eSKate Stone       uint32_t offset_to_subl_insn = EXTRACT_BITS(
817b9c1b51eSKate Stone           function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
818e589e7e3SJason Molenda 
81919ba9fbfSJason Molenda       SectionList *sl = m_objfile.GetSectionList();
820b9c1b51eSKate Stone       if (sl) {
82119ba9fbfSJason Molenda         ProcessSP process_sp = target.GetProcessSP();
822b9c1b51eSKate Stone         if (process_sp) {
82319ba9fbfSJason Molenda           Address subl_payload_addr(function_info.valid_range_offset_start, sl);
82419ba9fbfSJason Molenda           subl_payload_addr.Slide(offset_to_subl_insn);
82597206d57SZachary Turner           Status error;
826b9c1b51eSKate Stone           uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
827b9c1b51eSKate Stone               subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
828b9c1b51eSKate Stone           if (large_stack_size != 0 && error.Success()) {
82919ba9fbfSJason Molenda             // Got the large stack frame size correctly - use it
83019ba9fbfSJason Molenda             stack_size = large_stack_size + (stack_adjust * wordsize);
831b9c1b51eSKate Stone           } else {
83219ba9fbfSJason Molenda             return false;
83319ba9fbfSJason Molenda           }
834b9c1b51eSKate Stone         } else {
83519ba9fbfSJason Molenda           return false;
83619ba9fbfSJason Molenda         }
837b9c1b51eSKate Stone       } else {
83819ba9fbfSJason Molenda         return false;
83919ba9fbfSJason Molenda       }
84019ba9fbfSJason Molenda     }
84119ba9fbfSJason Molenda 
842b9c1b51eSKate Stone     int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
843b9c1b51eSKate Stone                          ? stack_size
844b9c1b51eSKate Stone                          : stack_size * wordsize;
845ab970f5eSPavel Labath     row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
8468122bb0eSJason Molenda 
84719ba9fbfSJason Molenda     row->SetOffset(0);
848b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
849b9c1b51eSKate Stone                                               wordsize * -1, true);
85019ba9fbfSJason Molenda     row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
85119ba9fbfSJason Molenda 
852b9c1b51eSKate Stone     if (register_count > 0) {
853e589e7e3SJason Molenda 
85405097246SAdrian Prantl       // We need to include (up to) 6 registers in 10 bits. That would be 18
85505097246SAdrian Prantl       // bits if we just used 3 bits per reg to indicate the order they're
85605097246SAdrian Prantl       // saved on the stack.
857e589e7e3SJason Molenda       //
858e589e7e3SJason Molenda       // This is done with Lehmer code permutation, e.g. see
85905097246SAdrian Prantl       // http://stackoverflow.com/questions/1506078/fast-permutation-number-
86005097246SAdrian Prantl       // permutation-mapping-algorithms
8619060e987SJason Molenda       int permunreg[6] = {0, 0, 0, 0, 0, 0};
862e589e7e3SJason Molenda 
86305097246SAdrian Prantl       // This decodes the variable-base number in the 10 bits and gives us the
86405097246SAdrian Prantl       // Lehmer code sequence which can then be decoded.
865e589e7e3SJason Molenda 
866b9c1b51eSKate Stone       switch (register_count) {
867e589e7e3SJason Molenda       case 6:
868e589e7e3SJason Molenda         permunreg[0] = permutation / 120; // 120 == 5!
869e589e7e3SJason Molenda         permutation -= (permunreg[0] * 120);
870e589e7e3SJason Molenda         permunreg[1] = permutation / 24; // 24 == 4!
871e589e7e3SJason Molenda         permutation -= (permunreg[1] * 24);
872e589e7e3SJason Molenda         permunreg[2] = permutation / 6; // 6 == 3!
873e589e7e3SJason Molenda         permutation -= (permunreg[2] * 6);
874e589e7e3SJason Molenda         permunreg[3] = permutation / 2; // 2 == 2!
875e589e7e3SJason Molenda         permutation -= (permunreg[3] * 2);
876e589e7e3SJason Molenda         permunreg[4] = permutation; // 1 == 1!
877e589e7e3SJason Molenda         permunreg[5] = 0;
878e589e7e3SJason Molenda         break;
879e589e7e3SJason Molenda       case 5:
880e589e7e3SJason Molenda         permunreg[0] = permutation / 120;
881e589e7e3SJason Molenda         permutation -= (permunreg[0] * 120);
882e589e7e3SJason Molenda         permunreg[1] = permutation / 24;
883e589e7e3SJason Molenda         permutation -= (permunreg[1] * 24);
884e589e7e3SJason Molenda         permunreg[2] = permutation / 6;
885e589e7e3SJason Molenda         permutation -= (permunreg[2] * 6);
886e589e7e3SJason Molenda         permunreg[3] = permutation / 2;
887e589e7e3SJason Molenda         permutation -= (permunreg[3] * 2);
888e589e7e3SJason Molenda         permunreg[4] = permutation;
889e589e7e3SJason Molenda         break;
890e589e7e3SJason Molenda       case 4:
891e589e7e3SJason Molenda         permunreg[0] = permutation / 60;
892e589e7e3SJason Molenda         permutation -= (permunreg[0] * 60);
893e589e7e3SJason Molenda         permunreg[1] = permutation / 12;
894e589e7e3SJason Molenda         permutation -= (permunreg[1] * 12);
895e589e7e3SJason Molenda         permunreg[2] = permutation / 3;
896e589e7e3SJason Molenda         permutation -= (permunreg[2] * 3);
897e589e7e3SJason Molenda         permunreg[3] = permutation;
898e589e7e3SJason Molenda         break;
899e589e7e3SJason Molenda       case 3:
900e589e7e3SJason Molenda         permunreg[0] = permutation / 20;
901e589e7e3SJason Molenda         permutation -= (permunreg[0] * 20);
902e589e7e3SJason Molenda         permunreg[1] = permutation / 4;
903e589e7e3SJason Molenda         permutation -= (permunreg[1] * 4);
904e589e7e3SJason Molenda         permunreg[2] = permutation;
905e589e7e3SJason Molenda         break;
906e589e7e3SJason Molenda       case 2:
907e589e7e3SJason Molenda         permunreg[0] = permutation / 5;
908e589e7e3SJason Molenda         permutation -= (permunreg[0] * 5);
909e589e7e3SJason Molenda         permunreg[1] = permutation;
910e589e7e3SJason Molenda         break;
911e589e7e3SJason Molenda       case 1:
912e589e7e3SJason Molenda         permunreg[0] = permutation;
913e589e7e3SJason Molenda         break;
914e589e7e3SJason Molenda       }
915e589e7e3SJason Molenda 
91605097246SAdrian Prantl       // Decode the Lehmer code for this permutation of the registers v.
91705097246SAdrian Prantl       // http://en.wikipedia.org/wiki/Lehmer_code
918e589e7e3SJason Molenda 
919b9c1b51eSKate Stone       int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
920b9c1b51eSKate Stone                           UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
921b9c1b51eSKate Stone                           UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
922e589e7e3SJason Molenda       bool used[7] = {false, false, false, false, false, false, false};
923b9c1b51eSKate Stone       for (uint32_t i = 0; i < register_count; i++) {
924e589e7e3SJason Molenda         int renum = 0;
925b9c1b51eSKate Stone         for (int j = 1; j < 7; j++) {
926a6682a41SJonas Devlieghere           if (!used[j]) {
927b9c1b51eSKate Stone             if (renum == permunreg[i]) {
928e589e7e3SJason Molenda               registers[i] = j;
929e589e7e3SJason Molenda               used[j] = true;
930e589e7e3SJason Molenda               break;
931e589e7e3SJason Molenda             }
932e589e7e3SJason Molenda             renum++;
933e589e7e3SJason Molenda           }
934e589e7e3SJason Molenda         }
935e589e7e3SJason Molenda       }
936e589e7e3SJason Molenda 
937e589e7e3SJason Molenda       uint32_t saved_registers_offset = 1;
938e589e7e3SJason Molenda       saved_registers_offset++;
939e589e7e3SJason Molenda 
940b9c1b51eSKate Stone       for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
941b9c1b51eSKate Stone         switch (registers[i]) {
942e589e7e3SJason Molenda         case UNWIND_X86_64_REG_NONE:
943e589e7e3SJason Molenda           break;
944e589e7e3SJason Molenda         case UNWIND_X86_64_REG_RBX:
945e589e7e3SJason Molenda         case UNWIND_X86_64_REG_R12:
946e589e7e3SJason Molenda         case UNWIND_X86_64_REG_R13:
947e589e7e3SJason Molenda         case UNWIND_X86_64_REG_R14:
948e589e7e3SJason Molenda         case UNWIND_X86_64_REG_R15:
949e589e7e3SJason Molenda         case UNWIND_X86_64_REG_RBP:
950b9c1b51eSKate Stone           row->SetRegisterLocationToAtCFAPlusOffset(
951b9c1b51eSKate Stone               translate_to_eh_frame_regnum_x86_64(registers[i]),
952b9c1b51eSKate Stone               wordsize * -saved_registers_offset, true);
9538122bb0eSJason Molenda           saved_registers_offset++;
954e589e7e3SJason Molenda           break;
955e589e7e3SJason Molenda         }
956e589e7e3SJason Molenda       }
957e589e7e3SJason Molenda     }
95819ba9fbfSJason Molenda     unwind_plan.AppendRow(row);
95919ba9fbfSJason Molenda     return true;
960b9c1b51eSKate Stone   } break;
961e589e7e3SJason Molenda 
962b9c1b51eSKate Stone   case UNWIND_X86_64_MODE_DWARF: {
963e589e7e3SJason Molenda     return false;
964b9c1b51eSKate Stone   } break;
965e589e7e3SJason Molenda 
966b9c1b51eSKate Stone   case 0: {
967e589e7e3SJason Molenda     return false;
968b9c1b51eSKate Stone   } break;
969e589e7e3SJason Molenda   }
970e589e7e3SJason Molenda   return false;
971e589e7e3SJason Molenda }
972e589e7e3SJason Molenda 
973e589e7e3SJason Molenda enum i386_eh_regnum {
974e589e7e3SJason Molenda   eax = 0,
975e589e7e3SJason Molenda   ecx = 1,
976e589e7e3SJason Molenda   edx = 2,
977e589e7e3SJason Molenda   ebx = 3,
978e589e7e3SJason Molenda   ebp = 4,
979e589e7e3SJason Molenda   esp = 5,
980e589e7e3SJason Molenda   esi = 6,
981e589e7e3SJason Molenda   edi = 7,
982b9c1b51eSKate Stone   eip = 8 // this is officially the Return Address register number, but close
983b9c1b51eSKate Stone           // enough
984e589e7e3SJason Molenda };
985e589e7e3SJason Molenda 
98605097246SAdrian Prantl // Convert the compact_unwind_info.h register numbering scheme to
98705097246SAdrian Prantl // eRegisterKindEHFrame (eh_frame) register numbering scheme.
translate_to_eh_frame_regnum_i386(uint32_t unwind_regno)988b9c1b51eSKate Stone uint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {
989b9c1b51eSKate Stone   switch (unwind_regno) {
990e589e7e3SJason Molenda   case UNWIND_X86_REG_EBX:
991e589e7e3SJason Molenda     return i386_eh_regnum::ebx;
992e589e7e3SJason Molenda   case UNWIND_X86_REG_ECX:
993e589e7e3SJason Molenda     return i386_eh_regnum::ecx;
994e589e7e3SJason Molenda   case UNWIND_X86_REG_EDX:
995e589e7e3SJason Molenda     return i386_eh_regnum::edx;
996e589e7e3SJason Molenda   case UNWIND_X86_REG_EDI:
997e589e7e3SJason Molenda     return i386_eh_regnum::edi;
998e589e7e3SJason Molenda   case UNWIND_X86_REG_ESI:
999e589e7e3SJason Molenda     return i386_eh_regnum::esi;
1000e589e7e3SJason Molenda   case UNWIND_X86_REG_EBP:
1001e589e7e3SJason Molenda     return i386_eh_regnum::ebp;
1002e589e7e3SJason Molenda   default:
1003e589e7e3SJason Molenda     return LLDB_INVALID_REGNUM;
1004e589e7e3SJason Molenda   }
1005e589e7e3SJason Molenda }
1006e589e7e3SJason Molenda 
CreateUnwindPlan_i386(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)1007b9c1b51eSKate Stone bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
1008b9c1b51eSKate Stone                                               FunctionInfo &function_info,
1009b9c1b51eSKate Stone                                               UnwindPlan &unwind_plan,
1010b9c1b51eSKate Stone                                               Address pc_or_function_start) {
1011e589e7e3SJason Molenda   unwind_plan.SetSourceName("compact unwind info");
1012e589e7e3SJason Molenda   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1013e589e7e3SJason Molenda   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
10143fd917d8SJoseph Tremoulet   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1015a18f7071SJason Molenda   unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1016e589e7e3SJason Molenda 
1017e589e7e3SJason Molenda   unwind_plan.SetLSDAAddress(function_info.lsda_address);
1018e589e7e3SJason Molenda   unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1019e589e7e3SJason Molenda 
1020e589e7e3SJason Molenda   UnwindPlan::RowSP row(new UnwindPlan::Row);
1021e589e7e3SJason Molenda 
1022e589e7e3SJason Molenda   const int wordsize = 4;
1023e589e7e3SJason Molenda   int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1024b9c1b51eSKate Stone   switch (mode) {
1025b9c1b51eSKate Stone   case UNWIND_X86_MODE_EBP_FRAME: {
1026ab970f5eSPavel Labath     row->GetCFAValue().SetIsRegisterPlusOffset(
1027ab970f5eSPavel Labath         translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
1028e589e7e3SJason Molenda     row->SetOffset(0);
1029b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,
1030b9c1b51eSKate Stone                                               wordsize * -2, true);
1031b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1032b9c1b51eSKate Stone                                               wordsize * -1, true);
1033e589e7e3SJason Molenda     row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1034e589e7e3SJason Molenda 
1035b9c1b51eSKate Stone     uint32_t saved_registers_offset =
1036b9c1b51eSKate Stone         EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1037e589e7e3SJason Molenda 
1038b9c1b51eSKate Stone     uint32_t saved_registers_locations =
1039b9c1b51eSKate Stone         EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1040e589e7e3SJason Molenda 
1041e589e7e3SJason Molenda     saved_registers_offset += 2;
1042e589e7e3SJason Molenda 
1043b9c1b51eSKate Stone     for (int i = 0; i < 5; i++) {
1044e589e7e3SJason Molenda       uint32_t regnum = saved_registers_locations & 0x7;
1045b9c1b51eSKate Stone       switch (regnum) {
1046e589e7e3SJason Molenda       case UNWIND_X86_REG_NONE:
1047e589e7e3SJason Molenda         break;
1048e589e7e3SJason Molenda       case UNWIND_X86_REG_EBX:
1049e589e7e3SJason Molenda       case UNWIND_X86_REG_ECX:
1050e589e7e3SJason Molenda       case UNWIND_X86_REG_EDX:
1051e589e7e3SJason Molenda       case UNWIND_X86_REG_EDI:
1052e589e7e3SJason Molenda       case UNWIND_X86_REG_ESI:
1053b9c1b51eSKate Stone         row->SetRegisterLocationToAtCFAPlusOffset(
1054b9c1b51eSKate Stone             translate_to_eh_frame_regnum_i386(regnum),
1055b9c1b51eSKate Stone             wordsize * -saved_registers_offset, true);
1056e589e7e3SJason Molenda         break;
1057e589e7e3SJason Molenda       }
1058e589e7e3SJason Molenda       saved_registers_offset--;
1059e589e7e3SJason Molenda       saved_registers_locations >>= 3;
1060e589e7e3SJason Molenda     }
1061e589e7e3SJason Molenda     unwind_plan.AppendRow(row);
1062e589e7e3SJason Molenda     return true;
1063b9c1b51eSKate Stone   } break;
1064e589e7e3SJason Molenda 
1065e589e7e3SJason Molenda   case UNWIND_X86_MODE_STACK_IND:
1066b9c1b51eSKate Stone   case UNWIND_X86_MODE_STACK_IMMD: {
1067b9c1b51eSKate Stone     uint32_t stack_size =
1068b9c1b51eSKate Stone         EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1069b9c1b51eSKate Stone     uint32_t register_count = EXTRACT_BITS(
1070b9c1b51eSKate Stone         function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1071b9c1b51eSKate Stone     uint32_t permutation = EXTRACT_BITS(
1072b9c1b51eSKate Stone         function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
107319ba9fbfSJason Molenda 
1074b9c1b51eSKate Stone     if (mode == UNWIND_X86_MODE_STACK_IND &&
1075b9c1b51eSKate Stone         function_info.valid_range_offset_start != 0) {
1076b9c1b51eSKate Stone       uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,
1077b9c1b51eSKate Stone                                            UNWIND_X86_FRAMELESS_STACK_ADJUST);
107819ba9fbfSJason Molenda 
1079b9c1b51eSKate Stone       // offset into the function instructions; 0 == beginning of first
1080b9c1b51eSKate Stone       // instruction
1081b9c1b51eSKate Stone       uint32_t offset_to_subl_insn =
1082b9c1b51eSKate Stone           EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
108319ba9fbfSJason Molenda 
108419ba9fbfSJason Molenda       SectionList *sl = m_objfile.GetSectionList();
1085b9c1b51eSKate Stone       if (sl) {
108619ba9fbfSJason Molenda         ProcessSP process_sp = target.GetProcessSP();
1087b9c1b51eSKate Stone         if (process_sp) {
108819ba9fbfSJason Molenda           Address subl_payload_addr(function_info.valid_range_offset_start, sl);
108919ba9fbfSJason Molenda           subl_payload_addr.Slide(offset_to_subl_insn);
109097206d57SZachary Turner           Status error;
1091b9c1b51eSKate Stone           uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
1092b9c1b51eSKate Stone               subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
1093b9c1b51eSKate Stone           if (large_stack_size != 0 && error.Success()) {
109419ba9fbfSJason Molenda             // Got the large stack frame size correctly - use it
109519ba9fbfSJason Molenda             stack_size = large_stack_size + (stack_adjust * wordsize);
1096b9c1b51eSKate Stone           } else {
109719ba9fbfSJason Molenda             return false;
109819ba9fbfSJason Molenda           }
1099b9c1b51eSKate Stone         } else {
110019ba9fbfSJason Molenda           return false;
110119ba9fbfSJason Molenda         }
1102b9c1b51eSKate Stone       } else {
110319ba9fbfSJason Molenda         return false;
110419ba9fbfSJason Molenda       }
110519ba9fbfSJason Molenda     }
110619ba9fbfSJason Molenda 
1107b9c1b51eSKate Stone     int32_t offset =
1108b9c1b51eSKate Stone         mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1109ab970f5eSPavel Labath     row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
111019ba9fbfSJason Molenda     row->SetOffset(0);
1111b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1112b9c1b51eSKate Stone                                               wordsize * -1, true);
111319ba9fbfSJason Molenda     row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
111419ba9fbfSJason Molenda 
1115b9c1b51eSKate Stone     if (register_count > 0) {
111619ba9fbfSJason Molenda 
111705097246SAdrian Prantl       // We need to include (up to) 6 registers in 10 bits. That would be 18
111805097246SAdrian Prantl       // bits if we just used 3 bits per reg to indicate the order they're
111905097246SAdrian Prantl       // saved on the stack.
112019ba9fbfSJason Molenda       //
112119ba9fbfSJason Molenda       // This is done with Lehmer code permutation, e.g. see
112205097246SAdrian Prantl       // http://stackoverflow.com/questions/1506078/fast-permutation-number-
112305097246SAdrian Prantl       // permutation-mapping-algorithms
11249060e987SJason Molenda       int permunreg[6] = {0, 0, 0, 0, 0, 0};
112519ba9fbfSJason Molenda 
112605097246SAdrian Prantl       // This decodes the variable-base number in the 10 bits and gives us the
112705097246SAdrian Prantl       // Lehmer code sequence which can then be decoded.
112819ba9fbfSJason Molenda 
1129b9c1b51eSKate Stone       switch (register_count) {
113019ba9fbfSJason Molenda       case 6:
113119ba9fbfSJason Molenda         permunreg[0] = permutation / 120; // 120 == 5!
113219ba9fbfSJason Molenda         permutation -= (permunreg[0] * 120);
113319ba9fbfSJason Molenda         permunreg[1] = permutation / 24; // 24 == 4!
113419ba9fbfSJason Molenda         permutation -= (permunreg[1] * 24);
113519ba9fbfSJason Molenda         permunreg[2] = permutation / 6; // 6 == 3!
113619ba9fbfSJason Molenda         permutation -= (permunreg[2] * 6);
113719ba9fbfSJason Molenda         permunreg[3] = permutation / 2; // 2 == 2!
113819ba9fbfSJason Molenda         permutation -= (permunreg[3] * 2);
113919ba9fbfSJason Molenda         permunreg[4] = permutation; // 1 == 1!
114019ba9fbfSJason Molenda         permunreg[5] = 0;
114119ba9fbfSJason Molenda         break;
114219ba9fbfSJason Molenda       case 5:
114319ba9fbfSJason Molenda         permunreg[0] = permutation / 120;
114419ba9fbfSJason Molenda         permutation -= (permunreg[0] * 120);
114519ba9fbfSJason Molenda         permunreg[1] = permutation / 24;
114619ba9fbfSJason Molenda         permutation -= (permunreg[1] * 24);
114719ba9fbfSJason Molenda         permunreg[2] = permutation / 6;
114819ba9fbfSJason Molenda         permutation -= (permunreg[2] * 6);
114919ba9fbfSJason Molenda         permunreg[3] = permutation / 2;
115019ba9fbfSJason Molenda         permutation -= (permunreg[3] * 2);
115119ba9fbfSJason Molenda         permunreg[4] = permutation;
115219ba9fbfSJason Molenda         break;
115319ba9fbfSJason Molenda       case 4:
115419ba9fbfSJason Molenda         permunreg[0] = permutation / 60;
115519ba9fbfSJason Molenda         permutation -= (permunreg[0] * 60);
115619ba9fbfSJason Molenda         permunreg[1] = permutation / 12;
115719ba9fbfSJason Molenda         permutation -= (permunreg[1] * 12);
115819ba9fbfSJason Molenda         permunreg[2] = permutation / 3;
115919ba9fbfSJason Molenda         permutation -= (permunreg[2] * 3);
116019ba9fbfSJason Molenda         permunreg[3] = permutation;
116119ba9fbfSJason Molenda         break;
116219ba9fbfSJason Molenda       case 3:
116319ba9fbfSJason Molenda         permunreg[0] = permutation / 20;
116419ba9fbfSJason Molenda         permutation -= (permunreg[0] * 20);
116519ba9fbfSJason Molenda         permunreg[1] = permutation / 4;
116619ba9fbfSJason Molenda         permutation -= (permunreg[1] * 4);
116719ba9fbfSJason Molenda         permunreg[2] = permutation;
116819ba9fbfSJason Molenda         break;
116919ba9fbfSJason Molenda       case 2:
117019ba9fbfSJason Molenda         permunreg[0] = permutation / 5;
117119ba9fbfSJason Molenda         permutation -= (permunreg[0] * 5);
117219ba9fbfSJason Molenda         permunreg[1] = permutation;
117319ba9fbfSJason Molenda         break;
117419ba9fbfSJason Molenda       case 1:
117519ba9fbfSJason Molenda         permunreg[0] = permutation;
117619ba9fbfSJason Molenda         break;
117719ba9fbfSJason Molenda       }
117819ba9fbfSJason Molenda 
117905097246SAdrian Prantl       // Decode the Lehmer code for this permutation of the registers v.
118005097246SAdrian Prantl       // http://en.wikipedia.org/wiki/Lehmer_code
118119ba9fbfSJason Molenda 
1182b9c1b51eSKate Stone       int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1183b9c1b51eSKate Stone                           UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1184b9c1b51eSKate Stone                           UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};
118519ba9fbfSJason Molenda       bool used[7] = {false, false, false, false, false, false, false};
1186b9c1b51eSKate Stone       for (uint32_t i = 0; i < register_count; i++) {
118719ba9fbfSJason Molenda         int renum = 0;
1188b9c1b51eSKate Stone         for (int j = 1; j < 7; j++) {
1189a6682a41SJonas Devlieghere           if (!used[j]) {
1190b9c1b51eSKate Stone             if (renum == permunreg[i]) {
119119ba9fbfSJason Molenda               registers[i] = j;
119219ba9fbfSJason Molenda               used[j] = true;
119319ba9fbfSJason Molenda               break;
119419ba9fbfSJason Molenda             }
119519ba9fbfSJason Molenda             renum++;
119619ba9fbfSJason Molenda           }
119719ba9fbfSJason Molenda         }
119819ba9fbfSJason Molenda       }
119919ba9fbfSJason Molenda 
120019ba9fbfSJason Molenda       uint32_t saved_registers_offset = 1;
120119ba9fbfSJason Molenda       saved_registers_offset++;
120219ba9fbfSJason Molenda 
1203b9c1b51eSKate Stone       for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1204b9c1b51eSKate Stone         switch (registers[i]) {
120519ba9fbfSJason Molenda         case UNWIND_X86_REG_NONE:
120619ba9fbfSJason Molenda           break;
120719ba9fbfSJason Molenda         case UNWIND_X86_REG_EBX:
120819ba9fbfSJason Molenda         case UNWIND_X86_REG_ECX:
120919ba9fbfSJason Molenda         case UNWIND_X86_REG_EDX:
121019ba9fbfSJason Molenda         case UNWIND_X86_REG_EDI:
121119ba9fbfSJason Molenda         case UNWIND_X86_REG_ESI:
121219ba9fbfSJason Molenda         case UNWIND_X86_REG_EBP:
1213b9c1b51eSKate Stone           row->SetRegisterLocationToAtCFAPlusOffset(
1214b9c1b51eSKate Stone               translate_to_eh_frame_regnum_i386(registers[i]),
1215b9c1b51eSKate Stone               wordsize * -saved_registers_offset, true);
12168122bb0eSJason Molenda           saved_registers_offset++;
121719ba9fbfSJason Molenda           break;
121819ba9fbfSJason Molenda         }
121919ba9fbfSJason Molenda       }
122019ba9fbfSJason Molenda     }
122119ba9fbfSJason Molenda 
122219ba9fbfSJason Molenda     unwind_plan.AppendRow(row);
122319ba9fbfSJason Molenda     return true;
1224b9c1b51eSKate Stone   } break;
122519ba9fbfSJason Molenda 
1226b9c1b51eSKate Stone   case UNWIND_X86_MODE_DWARF: {
1227e589e7e3SJason Molenda     return false;
1228b9c1b51eSKate Stone   } break;
1229e589e7e3SJason Molenda   }
1230e589e7e3SJason Molenda   return false;
1231e589e7e3SJason Molenda }
1232b667c202SJason Molenda 
1233b9c1b51eSKate Stone // DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1234b9c1b51eSKate Stone // doc by ARM
1235b667c202SJason Molenda 
1236b667c202SJason Molenda enum arm64_eh_regnum {
1237b667c202SJason Molenda   x19 = 19,
1238b667c202SJason Molenda   x20 = 20,
1239b667c202SJason Molenda   x21 = 21,
1240b667c202SJason Molenda   x22 = 22,
1241b667c202SJason Molenda   x23 = 23,
1242b667c202SJason Molenda   x24 = 24,
1243b667c202SJason Molenda   x25 = 25,
1244b667c202SJason Molenda   x26 = 26,
1245b667c202SJason Molenda   x27 = 27,
1246b667c202SJason Molenda   x28 = 28,
1247b667c202SJason Molenda 
1248b667c202SJason Molenda   fp = 29,
1249b667c202SJason Molenda   ra = 30,
1250b667c202SJason Molenda   sp = 31,
1251b667c202SJason Molenda   pc = 32,
1252b667c202SJason Molenda 
1253b9c1b51eSKate Stone   // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
125405097246SAdrian Prantl   // for the 64-bit fp regs.  Normally in DWARF it's context sensitive - so it
125505097246SAdrian Prantl   // knows it is fetching a 32- or 64-bit quantity from reg v8 to indicate s0
125605097246SAdrian Prantl   // or d0 - but the unwinder is operating at a lower level and we'd try to
125705097246SAdrian Prantl   // fetch 128 bits if we were told that v8 were stored on the stack...
1258b667c202SJason Molenda   v8 = 72,
1259b667c202SJason Molenda   v9 = 73,
1260b667c202SJason Molenda   v10 = 74,
1261b667c202SJason Molenda   v11 = 75,
1262b667c202SJason Molenda   v12 = 76,
1263b667c202SJason Molenda   v13 = 77,
1264b667c202SJason Molenda   v14 = 78,
1265b667c202SJason Molenda   v15 = 79,
1266b667c202SJason Molenda };
1267b667c202SJason Molenda 
1268c7afda5aSJason Molenda enum arm_eh_regnum {
1269c7afda5aSJason Molenda   arm_r0 = 0,
1270c7afda5aSJason Molenda   arm_r1 = 1,
1271c7afda5aSJason Molenda   arm_r2 = 2,
1272c7afda5aSJason Molenda   arm_r3 = 3,
1273c7afda5aSJason Molenda   arm_r4 = 4,
1274c7afda5aSJason Molenda   arm_r5 = 5,
1275c7afda5aSJason Molenda   arm_r6 = 6,
1276c7afda5aSJason Molenda   arm_r7 = 7,
1277c7afda5aSJason Molenda   arm_r8 = 8,
1278c7afda5aSJason Molenda   arm_r9 = 9,
1279c7afda5aSJason Molenda   arm_r10 = 10,
1280c7afda5aSJason Molenda   arm_r11 = 11,
1281c7afda5aSJason Molenda   arm_r12 = 12,
1282c7afda5aSJason Molenda 
1283c7afda5aSJason Molenda   arm_sp = 13,
1284c7afda5aSJason Molenda   arm_lr = 14,
1285c7afda5aSJason Molenda   arm_pc = 15,
1286c7afda5aSJason Molenda 
1287c7afda5aSJason Molenda   arm_d0 = 256,
1288c7afda5aSJason Molenda   arm_d1 = 257,
1289c7afda5aSJason Molenda   arm_d2 = 258,
1290c7afda5aSJason Molenda   arm_d3 = 259,
1291c7afda5aSJason Molenda   arm_d4 = 260,
1292c7afda5aSJason Molenda   arm_d5 = 261,
1293c7afda5aSJason Molenda   arm_d6 = 262,
1294c7afda5aSJason Molenda   arm_d7 = 263,
1295c7afda5aSJason Molenda   arm_d8 = 264,
1296c7afda5aSJason Molenda   arm_d9 = 265,
1297c7afda5aSJason Molenda   arm_d10 = 266,
1298c7afda5aSJason Molenda   arm_d11 = 267,
1299c7afda5aSJason Molenda   arm_d12 = 268,
1300c7afda5aSJason Molenda   arm_d13 = 269,
1301c7afda5aSJason Molenda   arm_d14 = 270,
1302c7afda5aSJason Molenda };
1303c7afda5aSJason Molenda 
CreateUnwindPlan_arm64(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)1304b9c1b51eSKate Stone bool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
1305b9c1b51eSKate Stone                                                FunctionInfo &function_info,
1306b9c1b51eSKate Stone                                                UnwindPlan &unwind_plan,
1307b9c1b51eSKate Stone                                                Address pc_or_function_start) {
1308b667c202SJason Molenda   unwind_plan.SetSourceName("compact unwind info");
1309b667c202SJason Molenda   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1310b667c202SJason Molenda   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
13113fd917d8SJoseph Tremoulet   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1312b667c202SJason Molenda   unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1313b667c202SJason Molenda 
1314b667c202SJason Molenda   unwind_plan.SetLSDAAddress(function_info.lsda_address);
1315b667c202SJason Molenda   unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1316b667c202SJason Molenda 
1317b667c202SJason Molenda   UnwindPlan::RowSP row(new UnwindPlan::Row);
1318b667c202SJason Molenda 
1319b667c202SJason Molenda   const int wordsize = 8;
1320b667c202SJason Molenda   int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
1321b667c202SJason Molenda 
1322b667c202SJason Molenda   if (mode == UNWIND_ARM64_MODE_DWARF)
1323b667c202SJason Molenda     return false;
1324b667c202SJason Molenda 
1325b9c1b51eSKate Stone   if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1326b667c202SJason Molenda     row->SetOffset(0);
1327b667c202SJason Molenda 
1328b9c1b51eSKate Stone     uint32_t stack_size =
1329b9c1b51eSKate Stone         (EXTRACT_BITS(function_info.encoding,
1330b9c1b51eSKate Stone                       UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1331b9c1b51eSKate Stone         16;
1332b667c202SJason Molenda 
1333b667c202SJason Molenda     // Our previous Call Frame Address is the stack pointer plus the stack size
1334b667c202SJason Molenda     row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
1335b667c202SJason Molenda 
1336b667c202SJason Molenda     // Our previous PC is in the LR
1337b9c1b51eSKate Stone     row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1338b9c1b51eSKate Stone                                        true);
1339b667c202SJason Molenda 
1340b667c202SJason Molenda     unwind_plan.AppendRow(row);
1341b667c202SJason Molenda     return true;
1342b667c202SJason Molenda   }
1343b667c202SJason Molenda 
1344b667c202SJason Molenda   // Should not be possible
1345b667c202SJason Molenda   if (mode != UNWIND_ARM64_MODE_FRAME)
1346b667c202SJason Molenda     return false;
1347b667c202SJason Molenda 
1348b667c202SJason Molenda   // mode == UNWIND_ARM64_MODE_FRAME
1349b667c202SJason Molenda 
1350b667c202SJason Molenda   row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1351b667c202SJason Molenda   row->SetOffset(0);
1352b9c1b51eSKate Stone   row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1353b9c1b51eSKate Stone                                             true);
1354b9c1b51eSKate Stone   row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1355b9c1b51eSKate Stone                                             true);
1356b667c202SJason Molenda   row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1357b667c202SJason Molenda 
1358b667c202SJason Molenda   int reg_pairs_saved_count = 1;
1359b667c202SJason Molenda 
1360b667c202SJason Molenda   uint32_t saved_register_bits = function_info.encoding & 0xfff;
1361b667c202SJason Molenda 
1362b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
1363b667c202SJason Molenda     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1364b667c202SJason Molenda     cfa_offset -= wordsize;
1365b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,
1366b9c1b51eSKate Stone                                               true);
1367b667c202SJason Molenda     cfa_offset -= wordsize;
1368b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1369b9c1b51eSKate Stone                                               true);
1370b667c202SJason Molenda     reg_pairs_saved_count++;
1371b667c202SJason Molenda   }
1372b667c202SJason Molenda 
1373b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
1374b667c202SJason Molenda     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1375b667c202SJason Molenda     cfa_offset -= wordsize;
1376b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,
1377b9c1b51eSKate Stone                                               true);
1378b667c202SJason Molenda     cfa_offset -= wordsize;
1379b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1380b9c1b51eSKate Stone                                               true);
1381b667c202SJason Molenda     reg_pairs_saved_count++;
1382b667c202SJason Molenda   }
1383b667c202SJason Molenda 
1384b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
1385b667c202SJason Molenda     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1386b667c202SJason Molenda     cfa_offset -= wordsize;
1387b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,
1388b9c1b51eSKate Stone                                               true);
1389b667c202SJason Molenda     cfa_offset -= wordsize;
1390b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1391b9c1b51eSKate Stone                                               true);
1392b667c202SJason Molenda     reg_pairs_saved_count++;
1393b667c202SJason Molenda   }
1394b667c202SJason Molenda 
1395b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
1396b667c202SJason Molenda     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1397b667c202SJason Molenda     cfa_offset -= wordsize;
1398b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,
1399b9c1b51eSKate Stone                                               true);
1400b667c202SJason Molenda     cfa_offset -= wordsize;
1401b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1402b9c1b51eSKate Stone                                               true);
1403b667c202SJason Molenda     reg_pairs_saved_count++;
1404b667c202SJason Molenda   }
1405b667c202SJason Molenda 
1406b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
1407b667c202SJason Molenda     int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1408b667c202SJason Molenda     cfa_offset -= wordsize;
1409b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,
1410b9c1b51eSKate Stone                                               true);
1411b667c202SJason Molenda     cfa_offset -= wordsize;
1412b9c1b51eSKate Stone     row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1413b9c1b51eSKate Stone                                               true);
1414b667c202SJason Molenda     reg_pairs_saved_count++;
1415b667c202SJason Molenda   }
1416b667c202SJason Molenda 
1417b9c1b51eSKate Stone   // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1418b9c1b51eSKate Stone   // off the stack;
1419b667c202SJason Molenda   // not sure if we have a good way to represent the 64-bitness of these saves.
1420b667c202SJason Molenda 
1421b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1422b667c202SJason Molenda     reg_pairs_saved_count++;
1423b667c202SJason Molenda   }
1424b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1425b667c202SJason Molenda     reg_pairs_saved_count++;
1426b667c202SJason Molenda   }
1427b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1428b667c202SJason Molenda     reg_pairs_saved_count++;
1429b667c202SJason Molenda   }
1430b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1431b667c202SJason Molenda     reg_pairs_saved_count++;
1432b667c202SJason Molenda   }
1433b667c202SJason Molenda 
1434b667c202SJason Molenda   unwind_plan.AppendRow(row);
1435b667c202SJason Molenda   return true;
1436b667c202SJason Molenda }
1437b667c202SJason Molenda 
CreateUnwindPlan_armv7(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)1438b9c1b51eSKate Stone bool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
1439b9c1b51eSKate Stone                                                FunctionInfo &function_info,
1440b9c1b51eSKate Stone                                                UnwindPlan &unwind_plan,
1441b9c1b51eSKate Stone                                                Address pc_or_function_start) {
1442c7afda5aSJason Molenda   unwind_plan.SetSourceName("compact unwind info");
1443c7afda5aSJason Molenda   unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1444c7afda5aSJason Molenda   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
14453fd917d8SJoseph Tremoulet   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1446c7afda5aSJason Molenda   unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1447c7afda5aSJason Molenda 
1448c7afda5aSJason Molenda   unwind_plan.SetLSDAAddress(function_info.lsda_address);
1449c7afda5aSJason Molenda   unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1450c7afda5aSJason Molenda 
1451c7afda5aSJason Molenda   UnwindPlan::RowSP row(new UnwindPlan::Row);
1452c7afda5aSJason Molenda 
1453c7afda5aSJason Molenda   const int wordsize = 4;
1454c7afda5aSJason Molenda   int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
1455c7afda5aSJason Molenda 
1456c7afda5aSJason Molenda   if (mode == UNWIND_ARM_MODE_DWARF)
1457c7afda5aSJason Molenda     return false;
1458c7afda5aSJason Molenda 
1459b9c1b51eSKate Stone   uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1460b9c1b51eSKate Stone                                         UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1461b9c1b51eSKate Stone                           wordsize;
1462c7afda5aSJason Molenda 
1463b9c1b51eSKate Stone   row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1464b9c1b51eSKate Stone                                              (2 * wordsize) + stack_adjust);
1465c7afda5aSJason Molenda   row->SetOffset(0);
1466b9c1b51eSKate Stone   row->SetRegisterLocationToAtCFAPlusOffset(
1467b9c1b51eSKate Stone       arm_r7, (wordsize * -2) - stack_adjust, true);
1468b9c1b51eSKate Stone   row->SetRegisterLocationToAtCFAPlusOffset(
1469b9c1b51eSKate Stone       arm_pc, (wordsize * -1) - stack_adjust, true);
1470c7afda5aSJason Molenda   row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);
1471c7afda5aSJason Molenda 
1472c7afda5aSJason Molenda   int cfa_offset = -stack_adjust - (2 * wordsize);
1473c7afda5aSJason Molenda 
1474c7afda5aSJason Molenda   uint32_t saved_register_bits = function_info.encoding & 0xff;
1475c7afda5aSJason Molenda 
1476b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1477c7afda5aSJason Molenda     cfa_offset -= wordsize;
1478c7afda5aSJason Molenda     row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1479c7afda5aSJason Molenda   }
1480c7afda5aSJason Molenda 
1481b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1482c7afda5aSJason Molenda     cfa_offset -= wordsize;
1483c7afda5aSJason Molenda     row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1484c7afda5aSJason Molenda   }
1485c7afda5aSJason Molenda 
1486b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1487c7afda5aSJason Molenda     cfa_offset -= wordsize;
1488c7afda5aSJason Molenda     row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1489c7afda5aSJason Molenda   }
1490c7afda5aSJason Molenda 
1491b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1492c7afda5aSJason Molenda     cfa_offset -= wordsize;
1493c7afda5aSJason Molenda     row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1494c7afda5aSJason Molenda   }
1495c7afda5aSJason Molenda 
1496b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1497c7afda5aSJason Molenda     cfa_offset -= wordsize;
1498c7afda5aSJason Molenda     row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1499c7afda5aSJason Molenda   }
1500c7afda5aSJason Molenda 
1501b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1502c7afda5aSJason Molenda     cfa_offset -= wordsize;
1503c7afda5aSJason Molenda     row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1504c7afda5aSJason Molenda   }
1505c7afda5aSJason Molenda 
1506b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1507c7afda5aSJason Molenda     cfa_offset -= wordsize;
1508c7afda5aSJason Molenda     row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1509c7afda5aSJason Molenda   }
1510c7afda5aSJason Molenda 
1511b9c1b51eSKate Stone   if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1512c7afda5aSJason Molenda     cfa_offset -= wordsize;
1513c7afda5aSJason Molenda     row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
1514c7afda5aSJason Molenda   }
1515c7afda5aSJason Molenda 
1516b9c1b51eSKate Stone   if (mode == UNWIND_ARM_MODE_FRAME_D) {
1517b9c1b51eSKate Stone     uint32_t d_reg_bits =
1518b9c1b51eSKate Stone         EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1519b9c1b51eSKate Stone     switch (d_reg_bits) {
1520c7afda5aSJason Molenda     case 0:
1521c7afda5aSJason Molenda       // vpush {d8}
1522c7afda5aSJason Molenda       cfa_offset -= 8;
1523c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1524c7afda5aSJason Molenda       break;
1525c7afda5aSJason Molenda     case 1:
1526c7afda5aSJason Molenda       // vpush {d10}
1527c7afda5aSJason Molenda       // vpush {d8}
1528c7afda5aSJason Molenda       cfa_offset -= 8;
1529c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1530c7afda5aSJason Molenda       cfa_offset -= 8;
1531c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1532c7afda5aSJason Molenda       break;
1533c7afda5aSJason Molenda     case 2:
1534c7afda5aSJason Molenda       // vpush {d12}
1535c7afda5aSJason Molenda       // vpush {d10}
1536c7afda5aSJason Molenda       // vpush {d8}
1537c7afda5aSJason Molenda       cfa_offset -= 8;
1538c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1539c7afda5aSJason Molenda       cfa_offset -= 8;
1540c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1541c7afda5aSJason Molenda       cfa_offset -= 8;
1542c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1543c7afda5aSJason Molenda       break;
1544c7afda5aSJason Molenda     case 3:
1545c7afda5aSJason Molenda       // vpush {d14}
1546c7afda5aSJason Molenda       // vpush {d12}
1547c7afda5aSJason Molenda       // vpush {d10}
1548c7afda5aSJason Molenda       // vpush {d8}
1549c7afda5aSJason Molenda       cfa_offset -= 8;
1550c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1551c7afda5aSJason Molenda       cfa_offset -= 8;
1552c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1553c7afda5aSJason Molenda       cfa_offset -= 8;
1554c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1555c7afda5aSJason Molenda       cfa_offset -= 8;
1556c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1557c7afda5aSJason Molenda       break;
1558c7afda5aSJason Molenda     case 4:
1559c7afda5aSJason Molenda       // vpush {d14}
1560c7afda5aSJason Molenda       // vpush {d12}
1561c7afda5aSJason Molenda       // sp = (sp - 24) & (-16);
1562c7afda5aSJason Molenda       // vst   {d8, d9, d10}
1563c7afda5aSJason Molenda       cfa_offset -= 8;
1564c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1565c7afda5aSJason Molenda       cfa_offset -= 8;
1566c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1567c7afda5aSJason Molenda 
1568b9c1b51eSKate Stone       // FIXME we don't have a way to represent reg saves at an specific
1569b9c1b51eSKate Stone       // alignment short of
1570c7afda5aSJason Molenda       // coming up with some DWARF location description.
1571c7afda5aSJason Molenda 
1572c7afda5aSJason Molenda       break;
1573c7afda5aSJason Molenda     case 5:
1574c7afda5aSJason Molenda       // vpush {d14}
1575c7afda5aSJason Molenda       // sp = (sp - 40) & (-16);
1576c7afda5aSJason Molenda       // vst   {d8, d9, d10, d11}
1577c7afda5aSJason Molenda       // vst   {d12}
1578c7afda5aSJason Molenda 
1579c7afda5aSJason Molenda       cfa_offset -= 8;
1580c7afda5aSJason Molenda       row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1581c7afda5aSJason Molenda 
1582b9c1b51eSKate Stone       // FIXME we don't have a way to represent reg saves at an specific
1583b9c1b51eSKate Stone       // alignment short of
1584c7afda5aSJason Molenda       // coming up with some DWARF location description.
1585c7afda5aSJason Molenda 
1586c7afda5aSJason Molenda       break;
1587c7afda5aSJason Molenda     case 6:
1588c7afda5aSJason Molenda       // sp = (sp - 56) & (-16);
1589c7afda5aSJason Molenda       // vst   {d8, d9, d10, d11}
1590c7afda5aSJason Molenda       // vst   {d12, d13, d14}
1591c7afda5aSJason Molenda 
1592b9c1b51eSKate Stone       // FIXME we don't have a way to represent reg saves at an specific
1593b9c1b51eSKate Stone       // alignment short of
1594c7afda5aSJason Molenda       // coming up with some DWARF location description.
1595c7afda5aSJason Molenda 
1596c7afda5aSJason Molenda       break;
1597c7afda5aSJason Molenda     case 7:
1598c7afda5aSJason Molenda       // sp = (sp - 64) & (-16);
1599c7afda5aSJason Molenda       // vst   {d8, d9, d10, d11}
1600c7afda5aSJason Molenda       // vst   {d12, d13, d14, d15}
1601c7afda5aSJason Molenda 
1602b9c1b51eSKate Stone       // FIXME we don't have a way to represent reg saves at an specific
1603b9c1b51eSKate Stone       // alignment short of
1604c7afda5aSJason Molenda       // coming up with some DWARF location description.
1605c7afda5aSJason Molenda 
1606c7afda5aSJason Molenda       break;
1607c7afda5aSJason Molenda     }
1608c7afda5aSJason Molenda   }
1609c7afda5aSJason Molenda 
1610c7afda5aSJason Molenda   unwind_plan.AppendRow(row);
1611c7afda5aSJason Molenda   return true;
1612c7afda5aSJason Molenda }
1613