CompactUnwindInfo.cpp revision 327952
1278332Semaste//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===//
2278332Semaste//
3278332Semaste//                     The LLVM Compiler Infrastructure
4278332Semaste//
5278332Semaste// This file is distributed under the University of Illinois Open Source
6278332Semaste// License. See LICENSE.TXT for details.
7278332Semaste//
8278332Semaste//===----------------------------------------------------------------------===//
9278332Semaste
10327952Sdim#include "lldb/Symbol/CompactUnwindInfo.h"
11278332Semaste#include "lldb/Core/Module.h"
12278332Semaste#include "lldb/Core/Section.h"
13278332Semaste#include "lldb/Symbol/ObjectFile.h"
14278332Semaste#include "lldb/Symbol/UnwindPlan.h"
15278332Semaste#include "lldb/Target/Process.h"
16278332Semaste#include "lldb/Target/Target.h"
17327952Sdim#include "lldb/Utility/ArchSpec.h"
18321369Sdim#include "lldb/Utility/DataBufferHeap.h"
19321369Sdim#include "lldb/Utility/Log.h"
20321369Sdim#include "lldb/Utility/StreamString.h"
21327952Sdim#include <algorithm>
22278332Semaste
23278332Semaste#include "llvm/Support/MathExtras.h"
24278332Semaste
25278332Semasteusing namespace lldb;
26278332Semasteusing namespace lldb_private;
27278332Semaste
28278332Semastenamespace lldb_private {
29278332Semaste
30314564Sdim// Constants from <mach-o/compact_unwind_encoding.h>
31278332Semaste
32314564SdimFLAGS_ANONYMOUS_ENUM(){
33314564Sdim    UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
34314564Sdim    UNWIND_PERSONALITY_MASK = 0x30000000,
35314564Sdim};
36278332Semaste
37314564SdimFLAGS_ANONYMOUS_ENUM(){
38314564Sdim    UNWIND_X86_MODE_MASK = 0x0F000000,
39314564Sdim    UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
40314564Sdim    UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
41314564Sdim    UNWIND_X86_MODE_STACK_IND = 0x03000000,
42314564Sdim    UNWIND_X86_MODE_DWARF = 0x04000000,
43278332Semaste
44314564Sdim    UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
45314564Sdim    UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
46278332Semaste
47314564Sdim    UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
48314564Sdim    UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
49314564Sdim    UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
50314564Sdim    UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
51278332Semaste
52314564Sdim    UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
53314564Sdim};
54278332Semaste
55314564Sdimenum {
56314564Sdim  UNWIND_X86_REG_NONE = 0,
57314564Sdim  UNWIND_X86_REG_EBX = 1,
58314564Sdim  UNWIND_X86_REG_ECX = 2,
59314564Sdim  UNWIND_X86_REG_EDX = 3,
60314564Sdim  UNWIND_X86_REG_EDI = 4,
61314564Sdim  UNWIND_X86_REG_ESI = 5,
62314564Sdim  UNWIND_X86_REG_EBP = 6,
63314564Sdim};
64288943Sdim
65314564SdimFLAGS_ANONYMOUS_ENUM(){
66314564Sdim    UNWIND_X86_64_MODE_MASK = 0x0F000000,
67314564Sdim    UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
68314564Sdim    UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
69314564Sdim    UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
70314564Sdim    UNWIND_X86_64_MODE_DWARF = 0x04000000,
71278332Semaste
72314564Sdim    UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
73314564Sdim    UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
74278332Semaste
75314564Sdim    UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
76314564Sdim    UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
77314564Sdim    UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
78314564Sdim    UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
79278332Semaste
80314564Sdim    UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
81314564Sdim};
82278332Semaste
83314564Sdimenum {
84314564Sdim  UNWIND_X86_64_REG_NONE = 0,
85314564Sdim  UNWIND_X86_64_REG_RBX = 1,
86314564Sdim  UNWIND_X86_64_REG_R12 = 2,
87314564Sdim  UNWIND_X86_64_REG_R13 = 3,
88314564Sdim  UNWIND_X86_64_REG_R14 = 4,
89314564Sdim  UNWIND_X86_64_REG_R15 = 5,
90314564Sdim  UNWIND_X86_64_REG_RBP = 6,
91314564Sdim};
92309124Sdim
93314564SdimFLAGS_ANONYMOUS_ENUM(){
94314564Sdim    UNWIND_ARM64_MODE_MASK = 0x0F000000,
95314564Sdim    UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
96314564Sdim    UNWIND_ARM64_MODE_DWARF = 0x03000000,
97314564Sdim    UNWIND_ARM64_MODE_FRAME = 0x04000000,
98309124Sdim
99314564Sdim    UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
100314564Sdim    UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
101314564Sdim    UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
102314564Sdim    UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
103314564Sdim    UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
104314564Sdim    UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
105314564Sdim    UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
106314564Sdim    UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
107314564Sdim    UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
108309124Sdim
109314564Sdim    UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
110314564Sdim    UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
111314564Sdim};
112309124Sdim
113314564SdimFLAGS_ANONYMOUS_ENUM(){
114314564Sdim    UNWIND_ARM_MODE_MASK = 0x0F000000,
115314564Sdim    UNWIND_ARM_MODE_FRAME = 0x01000000,
116314564Sdim    UNWIND_ARM_MODE_FRAME_D = 0x02000000,
117314564Sdim    UNWIND_ARM_MODE_DWARF = 0x04000000,
118309124Sdim
119314564Sdim    UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
120309124Sdim
121314564Sdim    UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
122314564Sdim    UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
123314564Sdim    UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
124309124Sdim
125314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
126314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
127314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
128314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
129314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
130309124Sdim
131314564Sdim    UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
132309124Sdim
133314564Sdim    UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
134314564Sdim};
135288943Sdim}
136278332Semaste
137278332Semaste#ifndef UNWIND_SECOND_LEVEL_REGULAR
138278332Semaste#define UNWIND_SECOND_LEVEL_REGULAR 2
139278332Semaste#endif
140278332Semaste
141278332Semaste#ifndef UNWIND_SECOND_LEVEL_COMPRESSED
142278332Semaste#define UNWIND_SECOND_LEVEL_COMPRESSED 3
143278332Semaste#endif
144278332Semaste
145278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
146314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
147278332Semaste#endif
148278332Semaste
149278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
150314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry)                     \
151314564Sdim  ((entry >> 24) & 0xFF)
152278332Semaste#endif
153278332Semaste
154314564Sdim#define EXTRACT_BITS(value, mask)                                              \
155314564Sdim  ((value >>                                                                   \
156314564Sdim    llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) &   \
157314564Sdim   (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1))
158278332Semaste
159278332Semaste//----------------------
160309124Sdim// constructor
161278332Semaste//----------------------
162278332Semaste
163309124SdimCompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP &section_sp)
164314564Sdim    : m_objfile(objfile), m_section_sp(section_sp),
165314564Sdim      m_section_contents_if_encrypted(), m_mutex(), m_indexes(),
166314564Sdim      m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(),
167314564Sdim      m_unwindinfo_data_computed(false), m_unwind_header() {}
168278332Semaste
169278332Semaste//----------------------
170278332Semaste// destructor
171278332Semaste//----------------------
172278332Semaste
173314564SdimCompactUnwindInfo::~CompactUnwindInfo() {}
174278332Semaste
175314564Sdimbool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
176314564Sdim                                      UnwindPlan &unwind_plan) {
177314564Sdim  if (!IsValid(target.GetProcessSP())) {
178314564Sdim    return false;
179314564Sdim  }
180314564Sdim  FunctionInfo function_info;
181314564Sdim  if (GetCompactUnwindInfoForFunction(target, addr, function_info)) {
182314564Sdim    // shortcut return for functions that have no compact unwind
183314564Sdim    if (function_info.encoding == 0)
184314564Sdim      return false;
185278332Semaste
186314564Sdim    ArchSpec arch;
187314564Sdim    if (m_objfile.GetArchitecture(arch)) {
188278332Semaste
189314564Sdim      Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
190314564Sdim      if (log && log->GetVerbose()) {
191314564Sdim        StreamString strm;
192314564Sdim        addr.Dump(
193314564Sdim            &strm, NULL,
194314564Sdim            Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments,
195314564Sdim            Address::DumpStyle::DumpStyleFileAddress,
196314564Sdim            arch.GetAddressByteSize());
197314564Sdim        log->Printf("Got compact unwind encoding 0x%x for function %s",
198314564Sdim                    function_info.encoding, strm.GetData());
199314564Sdim      }
200278332Semaste
201314564Sdim      if (function_info.valid_range_offset_start != 0 &&
202314564Sdim          function_info.valid_range_offset_end != 0) {
203314564Sdim        SectionList *sl = m_objfile.GetSectionList();
204314564Sdim        if (sl) {
205314564Sdim          addr_t func_range_start_file_addr =
206314564Sdim              function_info.valid_range_offset_start +
207314564Sdim              m_objfile.GetHeaderAddress().GetFileAddress();
208314564Sdim          AddressRange func_range(func_range_start_file_addr,
209314564Sdim                                  function_info.valid_range_offset_end -
210314564Sdim                                      function_info.valid_range_offset_start,
211314564Sdim                                  sl);
212314564Sdim          unwind_plan.SetPlanValidAddressRange(func_range);
213314564Sdim        }
214314564Sdim      }
215278332Semaste
216314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
217314564Sdim        return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
218314564Sdim                                       addr);
219314564Sdim      }
220314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::aarch64) {
221314564Sdim        return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
222314564Sdim      }
223314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::x86) {
224314564Sdim        return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
225314564Sdim      }
226314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::arm ||
227314564Sdim          arch.GetTriple().getArch() == llvm::Triple::thumb) {
228314564Sdim        return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);
229314564Sdim      }
230278332Semaste    }
231314564Sdim  }
232314564Sdim  return false;
233278332Semaste}
234278332Semaste
235314564Sdimbool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
236314564Sdim  if (m_section_sp.get() == nullptr)
237314564Sdim    return false;
238278332Semaste
239314564Sdim  if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
240314564Sdim    return true;
241278332Semaste
242314564Sdim  ScanIndex(process_sp);
243278332Semaste
244314564Sdim  return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
245278332Semaste}
246278332Semaste
247314564Sdimvoid CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
248314564Sdim  std::lock_guard<std::mutex> guard(m_mutex);
249314564Sdim  if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
250314564Sdim    return;
251278332Semaste
252314564Sdim  // We can't read the index for some reason.
253314564Sdim  if (m_indexes_computed == eLazyBoolNo) {
254314564Sdim    return;
255314564Sdim  }
256278332Semaste
257314564Sdim  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
258314564Sdim  if (log)
259314564Sdim    m_objfile.GetModule()->LogMessage(
260314564Sdim        log, "Reading compact unwind first-level indexes");
261278332Semaste
262314564Sdim  if (m_unwindinfo_data_computed == false) {
263314564Sdim    if (m_section_sp->IsEncrypted()) {
264314564Sdim      // Can't get section contents of a protected/encrypted section until we
265314564Sdim      // have a live
266314564Sdim      // process and can read them out of memory.
267314564Sdim      if (process_sp.get() == nullptr)
268314564Sdim        return;
269314564Sdim      m_section_contents_if_encrypted.reset(
270314564Sdim          new DataBufferHeap(m_section_sp->GetByteSize(), 0));
271321369Sdim      Status error;
272314564Sdim      if (process_sp->ReadMemory(
273314564Sdim              m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
274314564Sdim              m_section_contents_if_encrypted->GetBytes(),
275314564Sdim              m_section_sp->GetByteSize(),
276314564Sdim              error) == m_section_sp->GetByteSize() &&
277314564Sdim          error.Success()) {
278314564Sdim        m_unwindinfo_data.SetAddressByteSize(
279314564Sdim            process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
280314564Sdim        m_unwindinfo_data.SetByteOrder(
281314564Sdim            process_sp->GetTarget().GetArchitecture().GetByteOrder());
282314564Sdim        m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);
283314564Sdim      }
284314564Sdim    } else {
285314564Sdim      m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
286278332Semaste    }
287314564Sdim    if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
288314564Sdim      return;
289314564Sdim    m_unwindinfo_data_computed = true;
290314564Sdim  }
291278332Semaste
292314564Sdim  if (m_unwindinfo_data.GetByteSize() > 0) {
293314564Sdim    offset_t offset = 0;
294278332Semaste
295314564Sdim    // struct unwind_info_section_header
296314564Sdim    // {
297314564Sdim    // uint32_t    version;            // UNWIND_SECTION_VERSION
298314564Sdim    // uint32_t    commonEncodingsArraySectionOffset;
299314564Sdim    // uint32_t    commonEncodingsArrayCount;
300314564Sdim    // uint32_t    personalityArraySectionOffset;
301314564Sdim    // uint32_t    personalityArrayCount;
302314564Sdim    // uint32_t    indexSectionOffset;
303314564Sdim    // uint32_t    indexCount;
304309124Sdim
305314564Sdim    m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
306314564Sdim    m_unwind_header.common_encodings_array_offset =
307314564Sdim        m_unwindinfo_data.GetU32(&offset);
308314564Sdim    m_unwind_header.common_encodings_array_count =
309314564Sdim        m_unwindinfo_data.GetU32(&offset);
310314564Sdim    m_unwind_header.personality_array_offset =
311314564Sdim        m_unwindinfo_data.GetU32(&offset);
312314564Sdim    m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
313314564Sdim    uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
314278332Semaste
315314564Sdim    uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
316278332Semaste
317314564Sdim    if (m_unwind_header.common_encodings_array_offset >
318314564Sdim            m_unwindinfo_data.GetByteSize() ||
319314564Sdim        m_unwind_header.personality_array_offset >
320314564Sdim            m_unwindinfo_data.GetByteSize() ||
321314564Sdim        indexSectionOffset > m_unwindinfo_data.GetByteSize() ||
322314564Sdim        offset > m_unwindinfo_data.GetByteSize()) {
323314564Sdim      Host::SystemLog(Host::eSystemLogError, "error: Invalid offset "
324314564Sdim                                             "encountered in compact unwind "
325314564Sdim                                             "info, skipping\n");
326314564Sdim      // don't trust anything from this compact_unwind section if it looks
327314564Sdim      // blatantly invalid data in the header.
328314564Sdim      m_indexes_computed = eLazyBoolNo;
329314564Sdim      return;
330314564Sdim    }
331278332Semaste
332314564Sdim    // Parse the basic information from the indexes
333314564Sdim    // We wait to scan the second level page info until it's needed
334278332Semaste
335314564Sdim    // struct unwind_info_section_header_index_entry
336314564Sdim    // {
337314564Sdim    //     uint32_t        functionOffset;
338314564Sdim    //     uint32_t        secondLevelPagesSectionOffset;
339314564Sdim    //     uint32_t        lsdaIndexArraySectionOffset;
340314564Sdim    // };
341278332Semaste
342314564Sdim    bool clear_address_zeroth_bit = false;
343314564Sdim    ArchSpec arch;
344314564Sdim    if (m_objfile.GetArchitecture(arch)) {
345314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::arm ||
346314564Sdim          arch.GetTriple().getArch() == llvm::Triple::thumb)
347314564Sdim        clear_address_zeroth_bit = true;
348314564Sdim    }
349309124Sdim
350314564Sdim    offset = indexSectionOffset;
351314564Sdim    for (uint32_t idx = 0; idx < indexCount; idx++) {
352314564Sdim      uint32_t function_offset =
353314564Sdim          m_unwindinfo_data.GetU32(&offset); // functionOffset
354314564Sdim      uint32_t second_level_offset =
355314564Sdim          m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
356314564Sdim      uint32_t lsda_offset =
357314564Sdim          m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
358278332Semaste
359314564Sdim      if (second_level_offset > m_section_sp->GetByteSize() ||
360314564Sdim          lsda_offset > m_section_sp->GetByteSize()) {
361314564Sdim        m_indexes_computed = eLazyBoolNo;
362314564Sdim      }
363278332Semaste
364314564Sdim      if (clear_address_zeroth_bit)
365314564Sdim        function_offset &= ~1ull;
366309124Sdim
367314564Sdim      UnwindIndex this_index;
368314564Sdim      this_index.function_offset = function_offset;
369314564Sdim      this_index.second_level = second_level_offset;
370314564Sdim      this_index.lsda_array_start = lsda_offset;
371278332Semaste
372314564Sdim      if (m_indexes.size() > 0) {
373314564Sdim        m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
374314564Sdim      }
375278332Semaste
376314564Sdim      if (second_level_offset == 0) {
377314564Sdim        this_index.sentinal_entry = true;
378314564Sdim      }
379278332Semaste
380314564Sdim      m_indexes.push_back(this_index);
381278332Semaste    }
382314564Sdim    m_indexes_computed = eLazyBoolYes;
383314564Sdim  } else {
384314564Sdim    m_indexes_computed = eLazyBoolNo;
385314564Sdim  }
386278332Semaste}
387278332Semaste
388314564Sdimuint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
389314564Sdim                                                     uint32_t lsda_count,
390314564Sdim                                                     uint32_t function_offset) {
391314564Sdim  // struct unwind_info_section_header_lsda_index_entry
392314564Sdim  // {
393314564Sdim  //         uint32_t        functionOffset;
394314564Sdim  //         uint32_t        lsdaOffset;
395314564Sdim  // };
396278332Semaste
397314564Sdim  offset_t first_entry = lsda_offset;
398314564Sdim  uint32_t low = 0;
399314564Sdim  uint32_t high = lsda_count;
400314564Sdim  while (low < high) {
401314564Sdim    uint32_t mid = (low + high) / 2;
402314564Sdim    offset_t offset = first_entry + (mid * 8);
403314564Sdim    uint32_t mid_func_offset =
404314564Sdim        m_unwindinfo_data.GetU32(&offset); // functionOffset
405314564Sdim    uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
406314564Sdim    if (mid_func_offset == function_offset) {
407314564Sdim      return mid_lsda_offset;
408278332Semaste    }
409314564Sdim    if (mid_func_offset < function_offset) {
410314564Sdim      low = mid + 1;
411314564Sdim    } else {
412314564Sdim      high = mid;
413314564Sdim    }
414314564Sdim  }
415314564Sdim  return 0;
416278332Semaste}
417278332Semaste
418314564Sdimlldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(
419314564Sdim    uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,
420314564Sdim    uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
421314564Sdim  // typedef uint32_t compact_unwind_encoding_t;
422314564Sdim  // struct unwind_info_regular_second_level_entry
423314564Sdim  // {
424314564Sdim  //     uint32_t                    functionOffset;
425314564Sdim  //     compact_unwind_encoding_t    encoding;
426278332Semaste
427314564Sdim  offset_t first_entry = entry_page_offset;
428278332Semaste
429314564Sdim  uint32_t low = 0;
430314564Sdim  uint32_t high = entry_count;
431314564Sdim  uint32_t last = high - 1;
432314564Sdim  while (low < high) {
433314564Sdim    uint32_t mid = (low + high) / 2;
434314564Sdim    offset_t offset = first_entry + (mid * 8);
435314564Sdim    uint32_t mid_func_offset =
436314564Sdim        m_unwindinfo_data.GetU32(&offset); // functionOffset
437314564Sdim    uint32_t next_func_offset = 0;
438314564Sdim    if (mid < last) {
439314564Sdim      offset = first_entry + ((mid + 1) * 8);
440314564Sdim      next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
441278332Semaste    }
442314564Sdim    if (mid_func_offset <= function_offset) {
443314564Sdim      if (mid == last || (next_func_offset > function_offset)) {
444314564Sdim        if (entry_func_start_offset)
445314564Sdim          *entry_func_start_offset = mid_func_offset;
446314564Sdim        if (mid != last && entry_func_end_offset)
447314564Sdim          *entry_func_end_offset = next_func_offset;
448314564Sdim        return first_entry + (mid * 8);
449314564Sdim      } else {
450314564Sdim        low = mid + 1;
451314564Sdim      }
452314564Sdim    } else {
453314564Sdim      high = mid;
454314564Sdim    }
455314564Sdim  }
456314564Sdim  return LLDB_INVALID_OFFSET;
457278332Semaste}
458278332Semaste
459314564Sdimuint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(
460314564Sdim    uint32_t entry_page_offset, uint32_t entry_count,
461314564Sdim    uint32_t function_offset_to_find, uint32_t function_offset_base,
462314564Sdim    uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
463314564Sdim  offset_t first_entry = entry_page_offset;
464278332Semaste
465314564Sdim  uint32_t low = 0;
466314564Sdim  uint32_t high = entry_count;
467314564Sdim  uint32_t last = high - 1;
468314564Sdim  while (low < high) {
469314564Sdim    uint32_t mid = (low + high) / 2;
470314564Sdim    offset_t offset = first_entry + (mid * 4);
471314564Sdim    uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
472314564Sdim    uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
473314564Sdim    mid_func_offset += function_offset_base;
474314564Sdim    uint32_t next_func_offset = 0;
475314564Sdim    if (mid < last) {
476314564Sdim      offset = first_entry + ((mid + 1) * 4);
477314564Sdim      uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
478314564Sdim      next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);
479314564Sdim      next_func_offset += function_offset_base;
480278332Semaste    }
481314564Sdim    if (mid_func_offset <= function_offset_to_find) {
482314564Sdim      if (mid == last || (next_func_offset > function_offset_to_find)) {
483314564Sdim        if (entry_func_start_offset)
484314564Sdim          *entry_func_start_offset = mid_func_offset;
485314564Sdim        if (mid != last && entry_func_end_offset)
486314564Sdim          *entry_func_end_offset = next_func_offset;
487314564Sdim        return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
488314564Sdim      } else {
489314564Sdim        low = mid + 1;
490314564Sdim      }
491314564Sdim    } else {
492314564Sdim      high = mid;
493314564Sdim    }
494314564Sdim  }
495278332Semaste
496314564Sdim  return UINT32_MAX;
497278332Semaste}
498278332Semaste
499314564Sdimbool CompactUnwindInfo::GetCompactUnwindInfoForFunction(
500314564Sdim    Target &target, Address address, FunctionInfo &unwind_info) {
501314564Sdim  unwind_info.encoding = 0;
502314564Sdim  unwind_info.lsda_address.Clear();
503314564Sdim  unwind_info.personality_ptr_address.Clear();
504278332Semaste
505314564Sdim  if (!IsValid(target.GetProcessSP()))
506314564Sdim    return false;
507278332Semaste
508314564Sdim  addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
509314564Sdim  SectionList *sl = m_objfile.GetSectionList();
510314564Sdim  if (sl) {
511314564Sdim    SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
512314564Sdim    if (text_sect.get()) {
513314564Sdim      text_section_file_address = text_sect->GetFileAddress();
514278332Semaste    }
515314564Sdim  }
516314564Sdim  if (text_section_file_address == LLDB_INVALID_ADDRESS)
517314564Sdim    return false;
518278332Semaste
519314564Sdim  addr_t function_offset =
520314564Sdim      address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress();
521309124Sdim
522314564Sdim  UnwindIndex key;
523314564Sdim  key.function_offset = function_offset;
524309124Sdim
525314564Sdim  std::vector<UnwindIndex>::const_iterator it;
526314564Sdim  it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key);
527314564Sdim  if (it == m_indexes.end()) {
528314564Sdim    return false;
529314564Sdim  }
530278332Semaste
531314564Sdim  if (it->function_offset != key.function_offset) {
532314564Sdim    if (it != m_indexes.begin())
533314564Sdim      --it;
534314564Sdim  }
535278332Semaste
536314564Sdim  if (it->sentinal_entry == true) {
537314564Sdim    return false;
538314564Sdim  }
539278332Semaste
540314564Sdim  auto next_it = it + 1;
541314564Sdim  if (next_it != m_indexes.end()) {
542314564Sdim    // initialize the function offset end range to be the start of the
543314564Sdim    // next index offset.  If we find an entry which is at the end of
544314564Sdim    // the index table, this will establish the range end.
545314564Sdim    unwind_info.valid_range_offset_end = next_it->function_offset;
546314564Sdim  }
547278332Semaste
548314564Sdim  offset_t second_page_offset = it->second_level;
549314564Sdim  offset_t lsda_array_start = it->lsda_array_start;
550314564Sdim  offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
551278332Semaste
552314564Sdim  offset_t offset = second_page_offset;
553314564Sdim  uint32_t kind = m_unwindinfo_data.GetU32(
554314564Sdim      &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
555278332Semaste
556314564Sdim  if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
557314564Sdim    // struct unwind_info_regular_second_level_page_header
558314564Sdim    // {
559314564Sdim    //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_REGULAR
560314564Sdim    //     uint16_t    entryPageOffset;
561314564Sdim    //     uint16_t    entryCount;
562278332Semaste
563314564Sdim    // typedef uint32_t compact_unwind_encoding_t;
564314564Sdim    // struct unwind_info_regular_second_level_entry
565314564Sdim    // {
566314564Sdim    //     uint32_t                    functionOffset;
567314564Sdim    //     compact_unwind_encoding_t    encoding;
568278332Semaste
569314564Sdim    uint16_t entry_page_offset =
570314564Sdim        m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
571314564Sdim    uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
572278332Semaste
573314564Sdim    offset_t entry_offset = BinarySearchRegularSecondPage(
574314564Sdim        second_page_offset + entry_page_offset, entry_count, function_offset,
575314564Sdim        &unwind_info.valid_range_offset_start,
576314564Sdim        &unwind_info.valid_range_offset_end);
577314564Sdim    if (entry_offset == LLDB_INVALID_OFFSET) {
578314564Sdim      return false;
579314564Sdim    }
580314564Sdim    entry_offset += 4; // skip over functionOffset
581314564Sdim    unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
582314564Sdim    if (unwind_info.encoding & UNWIND_HAS_LSDA) {
583314564Sdim      SectionList *sl = m_objfile.GetSectionList();
584314564Sdim      if (sl) {
585314564Sdim        uint32_t lsda_offset = GetLSDAForFunctionOffset(
586314564Sdim            lsda_array_start, lsda_array_count, function_offset);
587314564Sdim        addr_t objfile_header_file_address =
588314564Sdim            m_objfile.GetHeaderAddress().GetFileAddress();
589314564Sdim        unwind_info.lsda_address.ResolveAddressUsingFileSections(
590314564Sdim            objfile_header_file_address + lsda_offset, sl);
591314564Sdim      }
592314564Sdim    }
593314564Sdim    if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
594314564Sdim      uint32_t personality_index =
595314564Sdim          EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
596278332Semaste
597314564Sdim      if (personality_index > 0) {
598314564Sdim        personality_index--;
599314564Sdim        if (personality_index < m_unwind_header.personality_array_count) {
600314564Sdim          offset_t offset = m_unwind_header.personality_array_offset;
601314564Sdim          offset += 4 * personality_index;
602314564Sdim          SectionList *sl = m_objfile.GetSectionList();
603314564Sdim          if (sl) {
604314564Sdim            uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
605314564Sdim            addr_t objfile_header_file_address =
606314564Sdim                m_objfile.GetHeaderAddress().GetFileAddress();
607314564Sdim            unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
608314564Sdim                objfile_header_file_address + personality_offset, sl);
609314564Sdim          }
610278332Semaste        }
611314564Sdim      }
612278332Semaste    }
613314564Sdim    return true;
614314564Sdim  } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
615314564Sdim    // struct unwind_info_compressed_second_level_page_header
616314564Sdim    // {
617314564Sdim    //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_COMPRESSED
618314564Sdim    //     uint16_t    entryPageOffset;         // offset from this 2nd lvl page
619314564Sdim    //     idx to array of entries
620314564Sdim    //                                          // (an entry has a function
621314564Sdim    //                                          offset and index into the
622314564Sdim    //                                          encodings)
623314564Sdim    //                                          // NB function offset from the
624314564Sdim    //                                          entry in the compressed page
625314564Sdim    //                                          // must be added to the index's
626314564Sdim    //                                          functionOffset value.
627314564Sdim    //     uint16_t    entryCount;
628314564Sdim    //     uint16_t    encodingsPageOffset;     // offset from this 2nd lvl page
629314564Sdim    //     idx to array of encodings
630314564Sdim    //     uint16_t    encodingsCount;
631278332Semaste
632314564Sdim    uint16_t entry_page_offset =
633314564Sdim        m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
634314564Sdim    uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
635314564Sdim    uint16_t encodings_page_offset =
636314564Sdim        m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
637314564Sdim    uint16_t encodings_count =
638314564Sdim        m_unwindinfo_data.GetU16(&offset); // encodingsCount
639278332Semaste
640314564Sdim    uint32_t encoding_index = BinarySearchCompressedSecondPage(
641314564Sdim        second_page_offset + entry_page_offset, entry_count, function_offset,
642314564Sdim        it->function_offset, &unwind_info.valid_range_offset_start,
643314564Sdim        &unwind_info.valid_range_offset_end);
644314564Sdim    if (encoding_index == UINT32_MAX ||
645314564Sdim        encoding_index >=
646314564Sdim            encodings_count + m_unwind_header.common_encodings_array_count) {
647314564Sdim      return false;
648314564Sdim    }
649314564Sdim    uint32_t encoding = 0;
650314564Sdim    if (encoding_index < m_unwind_header.common_encodings_array_count) {
651314564Sdim      offset = m_unwind_header.common_encodings_array_offset +
652314564Sdim               (encoding_index * sizeof(uint32_t));
653314564Sdim      encoding = m_unwindinfo_data.GetU32(
654314564Sdim          &offset); // encoding entry from the commonEncodingsArray
655314564Sdim    } else {
656314564Sdim      uint32_t page_specific_entry_index =
657314564Sdim          encoding_index - m_unwind_header.common_encodings_array_count;
658314564Sdim      offset = second_page_offset + encodings_page_offset +
659314564Sdim               (page_specific_entry_index * sizeof(uint32_t));
660314564Sdim      encoding = m_unwindinfo_data.GetU32(
661314564Sdim          &offset); // encoding entry from the page-specific encoding array
662314564Sdim    }
663314564Sdim    if (encoding == 0)
664314564Sdim      return false;
665278332Semaste
666314564Sdim    unwind_info.encoding = encoding;
667314564Sdim    if (unwind_info.encoding & UNWIND_HAS_LSDA) {
668314564Sdim      SectionList *sl = m_objfile.GetSectionList();
669314564Sdim      if (sl) {
670314564Sdim        uint32_t lsda_offset = GetLSDAForFunctionOffset(
671314564Sdim            lsda_array_start, lsda_array_count, function_offset);
672314564Sdim        addr_t objfile_header_file_address =
673314564Sdim            m_objfile.GetHeaderAddress().GetFileAddress();
674314564Sdim        unwind_info.lsda_address.ResolveAddressUsingFileSections(
675314564Sdim            objfile_header_file_address + lsda_offset, sl);
676314564Sdim      }
677314564Sdim    }
678314564Sdim    if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
679314564Sdim      uint32_t personality_index =
680314564Sdim          EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
681278332Semaste
682314564Sdim      if (personality_index > 0) {
683314564Sdim        personality_index--;
684314564Sdim        if (personality_index < m_unwind_header.personality_array_count) {
685314564Sdim          offset_t offset = m_unwind_header.personality_array_offset;
686314564Sdim          offset += 4 * personality_index;
687314564Sdim          SectionList *sl = m_objfile.GetSectionList();
688314564Sdim          if (sl) {
689314564Sdim            uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
690314564Sdim            addr_t objfile_header_file_address =
691314564Sdim                m_objfile.GetHeaderAddress().GetFileAddress();
692314564Sdim            unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
693314564Sdim                objfile_header_file_address + personality_offset, sl);
694314564Sdim          }
695278332Semaste        }
696314564Sdim      }
697278332Semaste    }
698314564Sdim    return true;
699314564Sdim  }
700314564Sdim  return false;
701278332Semaste}
702278332Semaste
703278332Semasteenum x86_64_eh_regnum {
704314564Sdim  rax = 0,
705314564Sdim  rdx = 1,
706314564Sdim  rcx = 2,
707314564Sdim  rbx = 3,
708314564Sdim  rsi = 4,
709314564Sdim  rdi = 5,
710314564Sdim  rbp = 6,
711314564Sdim  rsp = 7,
712314564Sdim  r8 = 8,
713314564Sdim  r9 = 9,
714314564Sdim  r10 = 10,
715314564Sdim  r11 = 11,
716314564Sdim  r12 = 12,
717314564Sdim  r13 = 13,
718314564Sdim  r14 = 14,
719314564Sdim  r15 = 15,
720314564Sdim  rip = 16 // this is officially the Return Address register number, but close
721314564Sdim           // enough
722278332Semaste};
723278332Semaste
724278332Semaste// Convert the compact_unwind_info.h register numbering scheme
725296417Sdim// to eRegisterKindEHFrame (eh_frame) register numbering scheme.
726314564Sdimuint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {
727314564Sdim  switch (unwind_regno) {
728314564Sdim  case UNWIND_X86_64_REG_RBX:
729314564Sdim    return x86_64_eh_regnum::rbx;
730314564Sdim  case UNWIND_X86_64_REG_R12:
731314564Sdim    return x86_64_eh_regnum::r12;
732314564Sdim  case UNWIND_X86_64_REG_R13:
733314564Sdim    return x86_64_eh_regnum::r13;
734314564Sdim  case UNWIND_X86_64_REG_R14:
735314564Sdim    return x86_64_eh_regnum::r14;
736314564Sdim  case UNWIND_X86_64_REG_R15:
737314564Sdim    return x86_64_eh_regnum::r15;
738314564Sdim  case UNWIND_X86_64_REG_RBP:
739314564Sdim    return x86_64_eh_regnum::rbp;
740314564Sdim  default:
741314564Sdim    return LLDB_INVALID_REGNUM;
742314564Sdim  }
743278332Semaste}
744278332Semaste
745314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
746314564Sdim                                                FunctionInfo &function_info,
747314564Sdim                                                UnwindPlan &unwind_plan,
748314564Sdim                                                Address pc_or_function_start) {
749314564Sdim  unwind_plan.SetSourceName("compact unwind info");
750314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
751314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
752314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
753278332Semaste
754314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
755314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
756278332Semaste
757314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
758278332Semaste
759314564Sdim  const int wordsize = 8;
760314564Sdim  int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
761314564Sdim  switch (mode) {
762314564Sdim  case UNWIND_X86_64_MODE_RBP_FRAME: {
763314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(
764314564Sdim        translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),
765314564Sdim        2 * wordsize);
766314564Sdim    row->SetOffset(0);
767314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,
768314564Sdim                                              wordsize * -2, true);
769314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
770314564Sdim                                              wordsize * -1, true);
771314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
772309124Sdim
773314564Sdim    uint32_t saved_registers_offset =
774314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
775278332Semaste
776314564Sdim    uint32_t saved_registers_locations =
777314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
778278332Semaste
779314564Sdim    saved_registers_offset += 2;
780278332Semaste
781314564Sdim    for (int i = 0; i < 5; i++) {
782314564Sdim      uint32_t regnum = saved_registers_locations & 0x7;
783314564Sdim      switch (regnum) {
784314564Sdim      case UNWIND_X86_64_REG_NONE:
785278332Semaste        break;
786314564Sdim      case UNWIND_X86_64_REG_RBX:
787314564Sdim      case UNWIND_X86_64_REG_R12:
788314564Sdim      case UNWIND_X86_64_REG_R13:
789314564Sdim      case UNWIND_X86_64_REG_R14:
790314564Sdim      case UNWIND_X86_64_REG_R15:
791314564Sdim        row->SetRegisterLocationToAtCFAPlusOffset(
792314564Sdim            translate_to_eh_frame_regnum_x86_64(regnum),
793314564Sdim            wordsize * -saved_registers_offset, true);
794278332Semaste        break;
795314564Sdim      }
796314564Sdim      saved_registers_offset--;
797314564Sdim      saved_registers_locations >>= 3;
798314564Sdim    }
799314564Sdim    unwind_plan.AppendRow(row);
800314564Sdim    return true;
801314564Sdim  } break;
802278332Semaste
803314564Sdim  case UNWIND_X86_64_MODE_STACK_IND: {
804314564Sdim    // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
805314564Sdim    // this
806314564Sdim    // style of unwind.  It was fixed in llvm r217020.
807314564Sdim    // The clang in Xcode 7 has this fixed.
808314564Sdim    return false;
809314564Sdim  } break;
810278332Semaste
811314564Sdim  case UNWIND_X86_64_MODE_STACK_IMMD: {
812314564Sdim    uint32_t stack_size = EXTRACT_BITS(function_info.encoding,
813314564Sdim                                       UNWIND_X86_64_FRAMELESS_STACK_SIZE);
814314564Sdim    uint32_t register_count = EXTRACT_BITS(
815314564Sdim        function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
816314564Sdim    uint32_t permutation = EXTRACT_BITS(
817314564Sdim        function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
818278332Semaste
819314564Sdim    if (mode == UNWIND_X86_64_MODE_STACK_IND &&
820314564Sdim        function_info.valid_range_offset_start != 0) {
821314564Sdim      uint32_t stack_adjust = EXTRACT_BITS(
822314564Sdim          function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
823278332Semaste
824314564Sdim      // offset into the function instructions; 0 == beginning of first
825314564Sdim      // instruction
826314564Sdim      uint32_t offset_to_subl_insn = EXTRACT_BITS(
827314564Sdim          function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
828278332Semaste
829314564Sdim      SectionList *sl = m_objfile.GetSectionList();
830314564Sdim      if (sl) {
831314564Sdim        ProcessSP process_sp = target.GetProcessSP();
832314564Sdim        if (process_sp) {
833314564Sdim          Address subl_payload_addr(function_info.valid_range_offset_start, sl);
834314564Sdim          subl_payload_addr.Slide(offset_to_subl_insn);
835321369Sdim          Status error;
836314564Sdim          uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
837314564Sdim              subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
838314564Sdim          if (large_stack_size != 0 && error.Success()) {
839314564Sdim            // Got the large stack frame size correctly - use it
840314564Sdim            stack_size = large_stack_size + (stack_adjust * wordsize);
841314564Sdim          } else {
842314564Sdim            return false;
843314564Sdim          }
844314564Sdim        } else {
845314564Sdim          return false;
846314564Sdim        }
847314564Sdim      } else {
848314564Sdim        return false;
849314564Sdim      }
850314564Sdim    }
851288943Sdim
852314564Sdim    int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
853314564Sdim                         ? stack_size
854314564Sdim                         : stack_size * wordsize;
855314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
856278332Semaste
857314564Sdim    row->SetOffset(0);
858314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
859314564Sdim                                              wordsize * -1, true);
860314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
861278332Semaste
862314564Sdim    if (register_count > 0) {
863278332Semaste
864314564Sdim      // We need to include (up to) 6 registers in 10 bits.
865314564Sdim      // That would be 18 bits if we just used 3 bits per reg to indicate
866314564Sdim      // the order they're saved on the stack.
867314564Sdim      //
868314564Sdim      // This is done with Lehmer code permutation, e.g. see
869314564Sdim      // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
870314564Sdim      int permunreg[6] = {0, 0, 0, 0, 0, 0};
871278332Semaste
872314564Sdim      // This decodes the variable-base number in the 10 bits
873314564Sdim      // and gives us the Lehmer code sequence which can then
874314564Sdim      // be decoded.
875309124Sdim
876314564Sdim      switch (register_count) {
877314564Sdim      case 6:
878314564Sdim        permunreg[0] = permutation / 120; // 120 == 5!
879314564Sdim        permutation -= (permunreg[0] * 120);
880314564Sdim        permunreg[1] = permutation / 24; // 24 == 4!
881314564Sdim        permutation -= (permunreg[1] * 24);
882314564Sdim        permunreg[2] = permutation / 6; // 6 == 3!
883314564Sdim        permutation -= (permunreg[2] * 6);
884314564Sdim        permunreg[3] = permutation / 2; // 2 == 2!
885314564Sdim        permutation -= (permunreg[3] * 2);
886314564Sdim        permunreg[4] = permutation; // 1 == 1!
887314564Sdim        permunreg[5] = 0;
888314564Sdim        break;
889314564Sdim      case 5:
890314564Sdim        permunreg[0] = permutation / 120;
891314564Sdim        permutation -= (permunreg[0] * 120);
892314564Sdim        permunreg[1] = permutation / 24;
893314564Sdim        permutation -= (permunreg[1] * 24);
894314564Sdim        permunreg[2] = permutation / 6;
895314564Sdim        permutation -= (permunreg[2] * 6);
896314564Sdim        permunreg[3] = permutation / 2;
897314564Sdim        permutation -= (permunreg[3] * 2);
898314564Sdim        permunreg[4] = permutation;
899314564Sdim        break;
900314564Sdim      case 4:
901314564Sdim        permunreg[0] = permutation / 60;
902314564Sdim        permutation -= (permunreg[0] * 60);
903314564Sdim        permunreg[1] = permutation / 12;
904314564Sdim        permutation -= (permunreg[1] * 12);
905314564Sdim        permunreg[2] = permutation / 3;
906314564Sdim        permutation -= (permunreg[2] * 3);
907314564Sdim        permunreg[3] = permutation;
908314564Sdim        break;
909314564Sdim      case 3:
910314564Sdim        permunreg[0] = permutation / 20;
911314564Sdim        permutation -= (permunreg[0] * 20);
912314564Sdim        permunreg[1] = permutation / 4;
913314564Sdim        permutation -= (permunreg[1] * 4);
914314564Sdim        permunreg[2] = permutation;
915314564Sdim        break;
916314564Sdim      case 2:
917314564Sdim        permunreg[0] = permutation / 5;
918314564Sdim        permutation -= (permunreg[0] * 5);
919314564Sdim        permunreg[1] = permutation;
920314564Sdim        break;
921314564Sdim      case 1:
922314564Sdim        permunreg[0] = permutation;
923314564Sdim        break;
924314564Sdim      }
925278332Semaste
926314564Sdim      // Decode the Lehmer code for this permutation of
927314564Sdim      // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
928278332Semaste
929314564Sdim      int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
930314564Sdim                          UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
931314564Sdim                          UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
932314564Sdim      bool used[7] = {false, false, false, false, false, false, false};
933314564Sdim      for (uint32_t i = 0; i < register_count; i++) {
934314564Sdim        int renum = 0;
935314564Sdim        for (int j = 1; j < 7; j++) {
936314564Sdim          if (used[j] == false) {
937314564Sdim            if (renum == permunreg[i]) {
938314564Sdim              registers[i] = j;
939314564Sdim              used[j] = true;
940314564Sdim              break;
941278332Semaste            }
942314564Sdim            renum++;
943314564Sdim          }
944278332Semaste        }
945314564Sdim      }
946278332Semaste
947314564Sdim      uint32_t saved_registers_offset = 1;
948314564Sdim      saved_registers_offset++;
949278332Semaste
950314564Sdim      for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
951314564Sdim        switch (registers[i]) {
952314564Sdim        case UNWIND_X86_64_REG_NONE:
953314564Sdim          break;
954314564Sdim        case UNWIND_X86_64_REG_RBX:
955314564Sdim        case UNWIND_X86_64_REG_R12:
956314564Sdim        case UNWIND_X86_64_REG_R13:
957314564Sdim        case UNWIND_X86_64_REG_R14:
958314564Sdim        case UNWIND_X86_64_REG_R15:
959314564Sdim        case UNWIND_X86_64_REG_RBP:
960314564Sdim          row->SetRegisterLocationToAtCFAPlusOffset(
961314564Sdim              translate_to_eh_frame_regnum_x86_64(registers[i]),
962314564Sdim              wordsize * -saved_registers_offset, true);
963314564Sdim          saved_registers_offset++;
964314564Sdim          break;
965278332Semaste        }
966314564Sdim      }
967278332Semaste    }
968314564Sdim    unwind_plan.AppendRow(row);
969314564Sdim    return true;
970314564Sdim  } break;
971314564Sdim
972314564Sdim  case UNWIND_X86_64_MODE_DWARF: {
973278332Semaste    return false;
974314564Sdim  } break;
975314564Sdim
976314564Sdim  case 0: {
977314564Sdim    return false;
978314564Sdim  } break;
979314564Sdim  }
980314564Sdim  return false;
981278332Semaste}
982278332Semaste
983278332Semasteenum i386_eh_regnum {
984314564Sdim  eax = 0,
985314564Sdim  ecx = 1,
986314564Sdim  edx = 2,
987314564Sdim  ebx = 3,
988314564Sdim  ebp = 4,
989314564Sdim  esp = 5,
990314564Sdim  esi = 6,
991314564Sdim  edi = 7,
992314564Sdim  eip = 8 // this is officially the Return Address register number, but close
993314564Sdim          // enough
994278332Semaste};
995278332Semaste
996278332Semaste// Convert the compact_unwind_info.h register numbering scheme
997296417Sdim// to eRegisterKindEHFrame (eh_frame) register numbering scheme.
998314564Sdimuint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {
999314564Sdim  switch (unwind_regno) {
1000314564Sdim  case UNWIND_X86_REG_EBX:
1001314564Sdim    return i386_eh_regnum::ebx;
1002314564Sdim  case UNWIND_X86_REG_ECX:
1003314564Sdim    return i386_eh_regnum::ecx;
1004314564Sdim  case UNWIND_X86_REG_EDX:
1005314564Sdim    return i386_eh_regnum::edx;
1006314564Sdim  case UNWIND_X86_REG_EDI:
1007314564Sdim    return i386_eh_regnum::edi;
1008314564Sdim  case UNWIND_X86_REG_ESI:
1009314564Sdim    return i386_eh_regnum::esi;
1010314564Sdim  case UNWIND_X86_REG_EBP:
1011314564Sdim    return i386_eh_regnum::ebp;
1012314564Sdim  default:
1013314564Sdim    return LLDB_INVALID_REGNUM;
1014314564Sdim  }
1015278332Semaste}
1016278332Semaste
1017314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
1018314564Sdim                                              FunctionInfo &function_info,
1019314564Sdim                                              UnwindPlan &unwind_plan,
1020314564Sdim                                              Address pc_or_function_start) {
1021314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1022314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1023314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1024314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1025278332Semaste
1026314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1027314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1028278332Semaste
1029314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1030278332Semaste
1031314564Sdim  const int wordsize = 4;
1032314564Sdim  int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1033314564Sdim  switch (mode) {
1034314564Sdim  case UNWIND_X86_MODE_EBP_FRAME: {
1035314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(
1036314564Sdim        translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
1037314564Sdim    row->SetOffset(0);
1038314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,
1039314564Sdim                                              wordsize * -2, true);
1040314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1041314564Sdim                                              wordsize * -1, true);
1042314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1043278332Semaste
1044314564Sdim    uint32_t saved_registers_offset =
1045314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1046309124Sdim
1047314564Sdim    uint32_t saved_registers_locations =
1048314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1049278332Semaste
1050314564Sdim    saved_registers_offset += 2;
1051278332Semaste
1052314564Sdim    for (int i = 0; i < 5; i++) {
1053314564Sdim      uint32_t regnum = saved_registers_locations & 0x7;
1054314564Sdim      switch (regnum) {
1055314564Sdim      case UNWIND_X86_REG_NONE:
1056278332Semaste        break;
1057314564Sdim      case UNWIND_X86_REG_EBX:
1058314564Sdim      case UNWIND_X86_REG_ECX:
1059314564Sdim      case UNWIND_X86_REG_EDX:
1060314564Sdim      case UNWIND_X86_REG_EDI:
1061314564Sdim      case UNWIND_X86_REG_ESI:
1062314564Sdim        row->SetRegisterLocationToAtCFAPlusOffset(
1063314564Sdim            translate_to_eh_frame_regnum_i386(regnum),
1064314564Sdim            wordsize * -saved_registers_offset, true);
1065314564Sdim        break;
1066314564Sdim      }
1067314564Sdim      saved_registers_offset--;
1068314564Sdim      saved_registers_locations >>= 3;
1069314564Sdim    }
1070314564Sdim    unwind_plan.AppendRow(row);
1071314564Sdim    return true;
1072314564Sdim  } break;
1073278332Semaste
1074314564Sdim  case UNWIND_X86_MODE_STACK_IND:
1075314564Sdim  case UNWIND_X86_MODE_STACK_IMMD: {
1076314564Sdim    uint32_t stack_size =
1077314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1078314564Sdim    uint32_t register_count = EXTRACT_BITS(
1079314564Sdim        function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1080314564Sdim    uint32_t permutation = EXTRACT_BITS(
1081314564Sdim        function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
1082278332Semaste
1083314564Sdim    if (mode == UNWIND_X86_MODE_STACK_IND &&
1084314564Sdim        function_info.valid_range_offset_start != 0) {
1085314564Sdim      uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,
1086314564Sdim                                           UNWIND_X86_FRAMELESS_STACK_ADJUST);
1087278332Semaste
1088314564Sdim      // offset into the function instructions; 0 == beginning of first
1089314564Sdim      // instruction
1090314564Sdim      uint32_t offset_to_subl_insn =
1091314564Sdim          EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1092278332Semaste
1093314564Sdim      SectionList *sl = m_objfile.GetSectionList();
1094314564Sdim      if (sl) {
1095314564Sdim        ProcessSP process_sp = target.GetProcessSP();
1096314564Sdim        if (process_sp) {
1097314564Sdim          Address subl_payload_addr(function_info.valid_range_offset_start, sl);
1098314564Sdim          subl_payload_addr.Slide(offset_to_subl_insn);
1099321369Sdim          Status error;
1100314564Sdim          uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
1101314564Sdim              subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
1102314564Sdim          if (large_stack_size != 0 && error.Success()) {
1103314564Sdim            // Got the large stack frame size correctly - use it
1104314564Sdim            stack_size = large_stack_size + (stack_adjust * wordsize);
1105314564Sdim          } else {
1106314564Sdim            return false;
1107314564Sdim          }
1108314564Sdim        } else {
1109314564Sdim          return false;
1110314564Sdim        }
1111314564Sdim      } else {
1112314564Sdim        return false;
1113314564Sdim      }
1114314564Sdim    }
1115278332Semaste
1116314564Sdim    int32_t offset =
1117314564Sdim        mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1118314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
1119314564Sdim    row->SetOffset(0);
1120314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1121314564Sdim                                              wordsize * -1, true);
1122314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1123309124Sdim
1124314564Sdim    if (register_count > 0) {
1125278332Semaste
1126314564Sdim      // We need to include (up to) 6 registers in 10 bits.
1127314564Sdim      // That would be 18 bits if we just used 3 bits per reg to indicate
1128314564Sdim      // the order they're saved on the stack.
1129314564Sdim      //
1130314564Sdim      // This is done with Lehmer code permutation, e.g. see
1131314564Sdim      // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
1132314564Sdim      int permunreg[6] = {0, 0, 0, 0, 0, 0};
1133278332Semaste
1134314564Sdim      // This decodes the variable-base number in the 10 bits
1135314564Sdim      // and gives us the Lehmer code sequence which can then
1136314564Sdim      // be decoded.
1137278332Semaste
1138314564Sdim      switch (register_count) {
1139314564Sdim      case 6:
1140314564Sdim        permunreg[0] = permutation / 120; // 120 == 5!
1141314564Sdim        permutation -= (permunreg[0] * 120);
1142314564Sdim        permunreg[1] = permutation / 24; // 24 == 4!
1143314564Sdim        permutation -= (permunreg[1] * 24);
1144314564Sdim        permunreg[2] = permutation / 6; // 6 == 3!
1145314564Sdim        permutation -= (permunreg[2] * 6);
1146314564Sdim        permunreg[3] = permutation / 2; // 2 == 2!
1147314564Sdim        permutation -= (permunreg[3] * 2);
1148314564Sdim        permunreg[4] = permutation; // 1 == 1!
1149314564Sdim        permunreg[5] = 0;
1150314564Sdim        break;
1151314564Sdim      case 5:
1152314564Sdim        permunreg[0] = permutation / 120;
1153314564Sdim        permutation -= (permunreg[0] * 120);
1154314564Sdim        permunreg[1] = permutation / 24;
1155314564Sdim        permutation -= (permunreg[1] * 24);
1156314564Sdim        permunreg[2] = permutation / 6;
1157314564Sdim        permutation -= (permunreg[2] * 6);
1158314564Sdim        permunreg[3] = permutation / 2;
1159314564Sdim        permutation -= (permunreg[3] * 2);
1160314564Sdim        permunreg[4] = permutation;
1161314564Sdim        break;
1162314564Sdim      case 4:
1163314564Sdim        permunreg[0] = permutation / 60;
1164314564Sdim        permutation -= (permunreg[0] * 60);
1165314564Sdim        permunreg[1] = permutation / 12;
1166314564Sdim        permutation -= (permunreg[1] * 12);
1167314564Sdim        permunreg[2] = permutation / 3;
1168314564Sdim        permutation -= (permunreg[2] * 3);
1169314564Sdim        permunreg[3] = permutation;
1170314564Sdim        break;
1171314564Sdim      case 3:
1172314564Sdim        permunreg[0] = permutation / 20;
1173314564Sdim        permutation -= (permunreg[0] * 20);
1174314564Sdim        permunreg[1] = permutation / 4;
1175314564Sdim        permutation -= (permunreg[1] * 4);
1176314564Sdim        permunreg[2] = permutation;
1177314564Sdim        break;
1178314564Sdim      case 2:
1179314564Sdim        permunreg[0] = permutation / 5;
1180314564Sdim        permutation -= (permunreg[0] * 5);
1181314564Sdim        permunreg[1] = permutation;
1182314564Sdim        break;
1183314564Sdim      case 1:
1184314564Sdim        permunreg[0] = permutation;
1185314564Sdim        break;
1186314564Sdim      }
1187309124Sdim
1188314564Sdim      // Decode the Lehmer code for this permutation of
1189314564Sdim      // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
1190278332Semaste
1191314564Sdim      int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1192314564Sdim                          UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1193314564Sdim                          UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};
1194314564Sdim      bool used[7] = {false, false, false, false, false, false, false};
1195314564Sdim      for (uint32_t i = 0; i < register_count; i++) {
1196314564Sdim        int renum = 0;
1197314564Sdim        for (int j = 1; j < 7; j++) {
1198314564Sdim          if (used[j] == false) {
1199314564Sdim            if (renum == permunreg[i]) {
1200314564Sdim              registers[i] = j;
1201314564Sdim              used[j] = true;
1202314564Sdim              break;
1203278332Semaste            }
1204314564Sdim            renum++;
1205314564Sdim          }
1206278332Semaste        }
1207314564Sdim      }
1208278332Semaste
1209314564Sdim      uint32_t saved_registers_offset = 1;
1210314564Sdim      saved_registers_offset++;
1211314564Sdim
1212314564Sdim      for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1213314564Sdim        switch (registers[i]) {
1214314564Sdim        case UNWIND_X86_REG_NONE:
1215314564Sdim          break;
1216314564Sdim        case UNWIND_X86_REG_EBX:
1217314564Sdim        case UNWIND_X86_REG_ECX:
1218314564Sdim        case UNWIND_X86_REG_EDX:
1219314564Sdim        case UNWIND_X86_REG_EDI:
1220314564Sdim        case UNWIND_X86_REG_ESI:
1221314564Sdim        case UNWIND_X86_REG_EBP:
1222314564Sdim          row->SetRegisterLocationToAtCFAPlusOffset(
1223314564Sdim              translate_to_eh_frame_regnum_i386(registers[i]),
1224314564Sdim              wordsize * -saved_registers_offset, true);
1225314564Sdim          saved_registers_offset++;
1226314564Sdim          break;
1227278332Semaste        }
1228314564Sdim      }
1229278332Semaste    }
1230314564Sdim
1231314564Sdim    unwind_plan.AppendRow(row);
1232314564Sdim    return true;
1233314564Sdim  } break;
1234314564Sdim
1235314564Sdim  case UNWIND_X86_MODE_DWARF: {
1236278332Semaste    return false;
1237314564Sdim  } break;
1238314564Sdim  }
1239314564Sdim  return false;
1240278332Semaste}
1241309124Sdim
1242314564Sdim// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1243314564Sdim// doc by ARM
1244309124Sdim
1245309124Sdimenum arm64_eh_regnum {
1246314564Sdim  x19 = 19,
1247314564Sdim  x20 = 20,
1248314564Sdim  x21 = 21,
1249314564Sdim  x22 = 22,
1250314564Sdim  x23 = 23,
1251314564Sdim  x24 = 24,
1252314564Sdim  x25 = 25,
1253314564Sdim  x26 = 26,
1254314564Sdim  x27 = 27,
1255314564Sdim  x28 = 28,
1256309124Sdim
1257314564Sdim  fp = 29,
1258314564Sdim  ra = 30,
1259314564Sdim  sp = 31,
1260314564Sdim  pc = 32,
1261309124Sdim
1262314564Sdim  // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
1263314564Sdim  // for the 64-bit
1264314564Sdim  // fp regs.  Normally in DWARF it's context sensitive - so it knows it is
1265314564Sdim  // fetching a
1266314564Sdim  // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder
1267314564Sdim  // is operating
1268314564Sdim  // at a lower level and we'd try to fetch 128 bits if we were told that v8
1269314564Sdim  // were stored on
1270314564Sdim  // the stack...
1271314564Sdim  v8 = 72,
1272314564Sdim  v9 = 73,
1273314564Sdim  v10 = 74,
1274314564Sdim  v11 = 75,
1275314564Sdim  v12 = 76,
1276314564Sdim  v13 = 77,
1277314564Sdim  v14 = 78,
1278314564Sdim  v15 = 79,
1279309124Sdim};
1280309124Sdim
1281309124Sdimenum arm_eh_regnum {
1282314564Sdim  arm_r0 = 0,
1283314564Sdim  arm_r1 = 1,
1284314564Sdim  arm_r2 = 2,
1285314564Sdim  arm_r3 = 3,
1286314564Sdim  arm_r4 = 4,
1287314564Sdim  arm_r5 = 5,
1288314564Sdim  arm_r6 = 6,
1289314564Sdim  arm_r7 = 7,
1290314564Sdim  arm_r8 = 8,
1291314564Sdim  arm_r9 = 9,
1292314564Sdim  arm_r10 = 10,
1293314564Sdim  arm_r11 = 11,
1294314564Sdim  arm_r12 = 12,
1295309124Sdim
1296314564Sdim  arm_sp = 13,
1297314564Sdim  arm_lr = 14,
1298314564Sdim  arm_pc = 15,
1299309124Sdim
1300314564Sdim  arm_d0 = 256,
1301314564Sdim  arm_d1 = 257,
1302314564Sdim  arm_d2 = 258,
1303314564Sdim  arm_d3 = 259,
1304314564Sdim  arm_d4 = 260,
1305314564Sdim  arm_d5 = 261,
1306314564Sdim  arm_d6 = 262,
1307314564Sdim  arm_d7 = 263,
1308314564Sdim  arm_d8 = 264,
1309314564Sdim  arm_d9 = 265,
1310314564Sdim  arm_d10 = 266,
1311314564Sdim  arm_d11 = 267,
1312314564Sdim  arm_d12 = 268,
1313314564Sdim  arm_d13 = 269,
1314314564Sdim  arm_d14 = 270,
1315309124Sdim};
1316309124Sdim
1317314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
1318314564Sdim                                               FunctionInfo &function_info,
1319314564Sdim                                               UnwindPlan &unwind_plan,
1320314564Sdim                                               Address pc_or_function_start) {
1321314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1322314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1323314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1324314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1325309124Sdim
1326314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1327314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1328309124Sdim
1329314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1330309124Sdim
1331314564Sdim  const int wordsize = 8;
1332314564Sdim  int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
1333309124Sdim
1334314564Sdim  if (mode == UNWIND_ARM64_MODE_DWARF)
1335314564Sdim    return false;
1336309124Sdim
1337314564Sdim  if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1338314564Sdim    row->SetOffset(0);
1339309124Sdim
1340314564Sdim    uint32_t stack_size =
1341314564Sdim        (EXTRACT_BITS(function_info.encoding,
1342314564Sdim                      UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1343314564Sdim        16;
1344309124Sdim
1345314564Sdim    // Our previous Call Frame Address is the stack pointer plus the stack size
1346314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
1347309124Sdim
1348314564Sdim    // Our previous PC is in the LR
1349314564Sdim    row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1350314564Sdim                                       true);
1351309124Sdim
1352314564Sdim    unwind_plan.AppendRow(row);
1353314564Sdim    return true;
1354314564Sdim  }
1355309124Sdim
1356314564Sdim  // Should not be possible
1357314564Sdim  if (mode != UNWIND_ARM64_MODE_FRAME)
1358314564Sdim    return false;
1359309124Sdim
1360314564Sdim  // mode == UNWIND_ARM64_MODE_FRAME
1361309124Sdim
1362314564Sdim  row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1363314564Sdim  row->SetOffset(0);
1364314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1365314564Sdim                                            true);
1366314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1367314564Sdim                                            true);
1368314564Sdim  row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1369309124Sdim
1370314564Sdim  int reg_pairs_saved_count = 1;
1371309124Sdim
1372314564Sdim  uint32_t saved_register_bits = function_info.encoding & 0xfff;
1373309124Sdim
1374314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
1375314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1376314564Sdim    cfa_offset -= wordsize;
1377314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,
1378314564Sdim                                              true);
1379314564Sdim    cfa_offset -= wordsize;
1380314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1381314564Sdim                                              true);
1382314564Sdim    reg_pairs_saved_count++;
1383314564Sdim  }
1384309124Sdim
1385314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
1386314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1387314564Sdim    cfa_offset -= wordsize;
1388314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,
1389314564Sdim                                              true);
1390314564Sdim    cfa_offset -= wordsize;
1391314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1392314564Sdim                                              true);
1393314564Sdim    reg_pairs_saved_count++;
1394314564Sdim  }
1395309124Sdim
1396314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
1397314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1398314564Sdim    cfa_offset -= wordsize;
1399314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,
1400314564Sdim                                              true);
1401314564Sdim    cfa_offset -= wordsize;
1402314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1403314564Sdim                                              true);
1404314564Sdim    reg_pairs_saved_count++;
1405314564Sdim  }
1406309124Sdim
1407314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
1408314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1409314564Sdim    cfa_offset -= wordsize;
1410314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,
1411314564Sdim                                              true);
1412314564Sdim    cfa_offset -= wordsize;
1413314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1414314564Sdim                                              true);
1415314564Sdim    reg_pairs_saved_count++;
1416314564Sdim  }
1417309124Sdim
1418314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
1419314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1420314564Sdim    cfa_offset -= wordsize;
1421314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,
1422314564Sdim                                              true);
1423314564Sdim    cfa_offset -= wordsize;
1424314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1425314564Sdim                                              true);
1426314564Sdim    reg_pairs_saved_count++;
1427314564Sdim  }
1428309124Sdim
1429314564Sdim  // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1430314564Sdim  // off the stack;
1431314564Sdim  // not sure if we have a good way to represent the 64-bitness of these saves.
1432309124Sdim
1433314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1434314564Sdim    reg_pairs_saved_count++;
1435314564Sdim  }
1436314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1437314564Sdim    reg_pairs_saved_count++;
1438314564Sdim  }
1439314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1440314564Sdim    reg_pairs_saved_count++;
1441314564Sdim  }
1442314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1443314564Sdim    reg_pairs_saved_count++;
1444314564Sdim  }
1445309124Sdim
1446314564Sdim  unwind_plan.AppendRow(row);
1447314564Sdim  return true;
1448309124Sdim}
1449309124Sdim
1450314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
1451314564Sdim                                               FunctionInfo &function_info,
1452314564Sdim                                               UnwindPlan &unwind_plan,
1453314564Sdim                                               Address pc_or_function_start) {
1454314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1455314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1456314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1457314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1458309124Sdim
1459314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1460314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1461309124Sdim
1462314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1463309124Sdim
1464314564Sdim  const int wordsize = 4;
1465314564Sdim  int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
1466309124Sdim
1467314564Sdim  if (mode == UNWIND_ARM_MODE_DWARF)
1468314564Sdim    return false;
1469309124Sdim
1470314564Sdim  uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1471314564Sdim                                        UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1472314564Sdim                          wordsize;
1473309124Sdim
1474314564Sdim  row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1475314564Sdim                                             (2 * wordsize) + stack_adjust);
1476314564Sdim  row->SetOffset(0);
1477314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(
1478314564Sdim      arm_r7, (wordsize * -2) - stack_adjust, true);
1479314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(
1480314564Sdim      arm_pc, (wordsize * -1) - stack_adjust, true);
1481314564Sdim  row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);
1482309124Sdim
1483314564Sdim  int cfa_offset = -stack_adjust - (2 * wordsize);
1484309124Sdim
1485314564Sdim  uint32_t saved_register_bits = function_info.encoding & 0xff;
1486309124Sdim
1487314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1488314564Sdim    cfa_offset -= wordsize;
1489314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1490314564Sdim  }
1491309124Sdim
1492314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1493314564Sdim    cfa_offset -= wordsize;
1494314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1495314564Sdim  }
1496309124Sdim
1497314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1498314564Sdim    cfa_offset -= wordsize;
1499314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1500314564Sdim  }
1501309124Sdim
1502314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1503314564Sdim    cfa_offset -= wordsize;
1504314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1505314564Sdim  }
1506309124Sdim
1507314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1508314564Sdim    cfa_offset -= wordsize;
1509314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1510314564Sdim  }
1511309124Sdim
1512314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1513314564Sdim    cfa_offset -= wordsize;
1514314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1515314564Sdim  }
1516309124Sdim
1517314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1518314564Sdim    cfa_offset -= wordsize;
1519314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1520314564Sdim  }
1521309124Sdim
1522314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1523314564Sdim    cfa_offset -= wordsize;
1524314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
1525314564Sdim  }
1526309124Sdim
1527314564Sdim  if (mode == UNWIND_ARM_MODE_FRAME_D) {
1528314564Sdim    uint32_t d_reg_bits =
1529314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1530314564Sdim    switch (d_reg_bits) {
1531314564Sdim    case 0:
1532314564Sdim      // vpush {d8}
1533314564Sdim      cfa_offset -= 8;
1534314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1535314564Sdim      break;
1536314564Sdim    case 1:
1537314564Sdim      // vpush {d10}
1538314564Sdim      // vpush {d8}
1539314564Sdim      cfa_offset -= 8;
1540314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1541314564Sdim      cfa_offset -= 8;
1542314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1543314564Sdim      break;
1544314564Sdim    case 2:
1545314564Sdim      // vpush {d12}
1546314564Sdim      // vpush {d10}
1547314564Sdim      // vpush {d8}
1548314564Sdim      cfa_offset -= 8;
1549314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1550314564Sdim      cfa_offset -= 8;
1551314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1552314564Sdim      cfa_offset -= 8;
1553314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1554314564Sdim      break;
1555314564Sdim    case 3:
1556314564Sdim      // vpush {d14}
1557314564Sdim      // vpush {d12}
1558314564Sdim      // vpush {d10}
1559314564Sdim      // vpush {d8}
1560314564Sdim      cfa_offset -= 8;
1561314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1562314564Sdim      cfa_offset -= 8;
1563314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1564314564Sdim      cfa_offset -= 8;
1565314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1566314564Sdim      cfa_offset -= 8;
1567314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1568314564Sdim      break;
1569314564Sdim    case 4:
1570314564Sdim      // vpush {d14}
1571314564Sdim      // vpush {d12}
1572314564Sdim      // sp = (sp - 24) & (-16);
1573314564Sdim      // vst   {d8, d9, d10}
1574314564Sdim      cfa_offset -= 8;
1575314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1576314564Sdim      cfa_offset -= 8;
1577314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1578309124Sdim
1579314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1580314564Sdim      // alignment short of
1581314564Sdim      // coming up with some DWARF location description.
1582309124Sdim
1583314564Sdim      break;
1584314564Sdim    case 5:
1585314564Sdim      // vpush {d14}
1586314564Sdim      // sp = (sp - 40) & (-16);
1587314564Sdim      // vst   {d8, d9, d10, d11}
1588314564Sdim      // vst   {d12}
1589309124Sdim
1590314564Sdim      cfa_offset -= 8;
1591314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1592309124Sdim
1593314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1594314564Sdim      // alignment short of
1595314564Sdim      // coming up with some DWARF location description.
1596309124Sdim
1597314564Sdim      break;
1598314564Sdim    case 6:
1599314564Sdim      // sp = (sp - 56) & (-16);
1600314564Sdim      // vst   {d8, d9, d10, d11}
1601314564Sdim      // vst   {d12, d13, d14}
1602309124Sdim
1603314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1604314564Sdim      // alignment short of
1605314564Sdim      // coming up with some DWARF location description.
1606309124Sdim
1607314564Sdim      break;
1608314564Sdim    case 7:
1609314564Sdim      // sp = (sp - 64) & (-16);
1610314564Sdim      // vst   {d8, d9, d10, d11}
1611314564Sdim      // vst   {d12, d13, d14, d15}
1612309124Sdim
1613314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1614314564Sdim      // alignment short of
1615314564Sdim      // coming up with some DWARF location description.
1616309124Sdim
1617314564Sdim      break;
1618309124Sdim    }
1619314564Sdim  }
1620309124Sdim
1621314564Sdim  unwind_plan.AppendRow(row);
1622314564Sdim  return true;
1623309124Sdim}
1624