1278332Semaste//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===//
2278332Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6278332Semaste//
7278332Semaste//===----------------------------------------------------------------------===//
8278332Semaste
9327952Sdim#include "lldb/Symbol/CompactUnwindInfo.h"
10278332Semaste#include "lldb/Core/Module.h"
11278332Semaste#include "lldb/Core/Section.h"
12278332Semaste#include "lldb/Symbol/ObjectFile.h"
13278332Semaste#include "lldb/Symbol/UnwindPlan.h"
14278332Semaste#include "lldb/Target/Process.h"
15278332Semaste#include "lldb/Target/Target.h"
16327952Sdim#include "lldb/Utility/ArchSpec.h"
17321369Sdim#include "lldb/Utility/DataBufferHeap.h"
18321369Sdim#include "lldb/Utility/Log.h"
19321369Sdim#include "lldb/Utility/StreamString.h"
20278332Semaste
21278332Semaste#include "llvm/Support/MathExtras.h"
22278332Semaste
23353358Sdim#include <algorithm>
24353358Sdim#include <memory>
25353358Sdim
26278332Semasteusing namespace lldb;
27278332Semasteusing namespace lldb_private;
28278332Semaste
29278332Semastenamespace lldb_private {
30278332Semaste
31314564Sdim// Constants from <mach-o/compact_unwind_encoding.h>
32278332Semaste
33314564SdimFLAGS_ANONYMOUS_ENUM(){
34314564Sdim    UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
35314564Sdim    UNWIND_PERSONALITY_MASK = 0x30000000,
36314564Sdim};
37278332Semaste
38314564SdimFLAGS_ANONYMOUS_ENUM(){
39314564Sdim    UNWIND_X86_MODE_MASK = 0x0F000000,
40314564Sdim    UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
41314564Sdim    UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
42314564Sdim    UNWIND_X86_MODE_STACK_IND = 0x03000000,
43314564Sdim    UNWIND_X86_MODE_DWARF = 0x04000000,
44278332Semaste
45314564Sdim    UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
46314564Sdim    UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
47278332Semaste
48314564Sdim    UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
49314564Sdim    UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
50314564Sdim    UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
51314564Sdim    UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
52278332Semaste
53314564Sdim    UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
54314564Sdim};
55278332Semaste
56314564Sdimenum {
57314564Sdim  UNWIND_X86_REG_NONE = 0,
58314564Sdim  UNWIND_X86_REG_EBX = 1,
59314564Sdim  UNWIND_X86_REG_ECX = 2,
60314564Sdim  UNWIND_X86_REG_EDX = 3,
61314564Sdim  UNWIND_X86_REG_EDI = 4,
62314564Sdim  UNWIND_X86_REG_ESI = 5,
63314564Sdim  UNWIND_X86_REG_EBP = 6,
64314564Sdim};
65288943Sdim
66314564SdimFLAGS_ANONYMOUS_ENUM(){
67314564Sdim    UNWIND_X86_64_MODE_MASK = 0x0F000000,
68314564Sdim    UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
69314564Sdim    UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
70314564Sdim    UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
71314564Sdim    UNWIND_X86_64_MODE_DWARF = 0x04000000,
72278332Semaste
73314564Sdim    UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
74314564Sdim    UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
75278332Semaste
76314564Sdim    UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
77314564Sdim    UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
78314564Sdim    UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
79314564Sdim    UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
80278332Semaste
81314564Sdim    UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
82314564Sdim};
83278332Semaste
84314564Sdimenum {
85314564Sdim  UNWIND_X86_64_REG_NONE = 0,
86314564Sdim  UNWIND_X86_64_REG_RBX = 1,
87314564Sdim  UNWIND_X86_64_REG_R12 = 2,
88314564Sdim  UNWIND_X86_64_REG_R13 = 3,
89314564Sdim  UNWIND_X86_64_REG_R14 = 4,
90314564Sdim  UNWIND_X86_64_REG_R15 = 5,
91314564Sdim  UNWIND_X86_64_REG_RBP = 6,
92314564Sdim};
93309124Sdim
94314564SdimFLAGS_ANONYMOUS_ENUM(){
95314564Sdim    UNWIND_ARM64_MODE_MASK = 0x0F000000,
96314564Sdim    UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
97314564Sdim    UNWIND_ARM64_MODE_DWARF = 0x03000000,
98314564Sdim    UNWIND_ARM64_MODE_FRAME = 0x04000000,
99309124Sdim
100314564Sdim    UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
101314564Sdim    UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
102314564Sdim    UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
103314564Sdim    UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
104314564Sdim    UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
105314564Sdim    UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
106314564Sdim    UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
107314564Sdim    UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
108314564Sdim    UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
109309124Sdim
110314564Sdim    UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
111314564Sdim    UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
112314564Sdim};
113309124Sdim
114314564SdimFLAGS_ANONYMOUS_ENUM(){
115314564Sdim    UNWIND_ARM_MODE_MASK = 0x0F000000,
116314564Sdim    UNWIND_ARM_MODE_FRAME = 0x01000000,
117314564Sdim    UNWIND_ARM_MODE_FRAME_D = 0x02000000,
118314564Sdim    UNWIND_ARM_MODE_DWARF = 0x04000000,
119309124Sdim
120314564Sdim    UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
121309124Sdim
122314564Sdim    UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
123314564Sdim    UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
124314564Sdim    UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
125309124Sdim
126314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
127314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
128314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
129314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
130314564Sdim    UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
131309124Sdim
132314564Sdim    UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
133309124Sdim
134314564Sdim    UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
135314564Sdim};
136288943Sdim}
137278332Semaste
138278332Semaste#ifndef UNWIND_SECOND_LEVEL_REGULAR
139278332Semaste#define UNWIND_SECOND_LEVEL_REGULAR 2
140278332Semaste#endif
141278332Semaste
142278332Semaste#ifndef UNWIND_SECOND_LEVEL_COMPRESSED
143278332Semaste#define UNWIND_SECOND_LEVEL_COMPRESSED 3
144278332Semaste#endif
145278332Semaste
146278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
147314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
148278332Semaste#endif
149278332Semaste
150278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
151314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry)                     \
152314564Sdim  ((entry >> 24) & 0xFF)
153278332Semaste#endif
154278332Semaste
155314564Sdim#define EXTRACT_BITS(value, mask)                                              \
156314564Sdim  ((value >>                                                                   \
157314564Sdim    llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) &   \
158314564Sdim   (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1))
159278332Semaste
160309124Sdim// constructor
161278332Semaste
162309124SdimCompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP &section_sp)
163314564Sdim    : m_objfile(objfile), m_section_sp(section_sp),
164314564Sdim      m_section_contents_if_encrypted(), m_mutex(), m_indexes(),
165314564Sdim      m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(),
166314564Sdim      m_unwindinfo_data_computed(false), m_unwind_header() {}
167278332Semaste
168278332Semaste// destructor
169278332Semaste
170314564SdimCompactUnwindInfo::~CompactUnwindInfo() {}
171278332Semaste
172314564Sdimbool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
173314564Sdim                                      UnwindPlan &unwind_plan) {
174314564Sdim  if (!IsValid(target.GetProcessSP())) {
175314564Sdim    return false;
176314564Sdim  }
177314564Sdim  FunctionInfo function_info;
178314564Sdim  if (GetCompactUnwindInfoForFunction(target, addr, function_info)) {
179314564Sdim    // shortcut return for functions that have no compact unwind
180314564Sdim    if (function_info.encoding == 0)
181314564Sdim      return false;
182278332Semaste
183344779Sdim    if (ArchSpec arch = m_objfile.GetArchitecture()) {
184278332Semaste
185314564Sdim      Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
186314564Sdim      if (log && log->GetVerbose()) {
187314564Sdim        StreamString strm;
188314564Sdim        addr.Dump(
189353358Sdim            &strm, nullptr,
190314564Sdim            Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments,
191314564Sdim            Address::DumpStyle::DumpStyleFileAddress,
192314564Sdim            arch.GetAddressByteSize());
193360784Sdim        LLDB_LOGF(log, "Got compact unwind encoding 0x%x for function %s",
194360784Sdim                  function_info.encoding, strm.GetData());
195314564Sdim      }
196278332Semaste
197314564Sdim      if (function_info.valid_range_offset_start != 0 &&
198314564Sdim          function_info.valid_range_offset_end != 0) {
199314564Sdim        SectionList *sl = m_objfile.GetSectionList();
200314564Sdim        if (sl) {
201314564Sdim          addr_t func_range_start_file_addr =
202314564Sdim              function_info.valid_range_offset_start +
203344779Sdim              m_objfile.GetBaseAddress().GetFileAddress();
204314564Sdim          AddressRange func_range(func_range_start_file_addr,
205314564Sdim                                  function_info.valid_range_offset_end -
206314564Sdim                                      function_info.valid_range_offset_start,
207314564Sdim                                  sl);
208314564Sdim          unwind_plan.SetPlanValidAddressRange(func_range);
209314564Sdim        }
210314564Sdim      }
211278332Semaste
212314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
213314564Sdim        return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
214314564Sdim                                       addr);
215314564Sdim      }
216360784Sdim      if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
217360784Sdim          arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {
218314564Sdim        return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
219314564Sdim      }
220314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::x86) {
221314564Sdim        return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
222314564Sdim      }
223314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::arm ||
224314564Sdim          arch.GetTriple().getArch() == llvm::Triple::thumb) {
225314564Sdim        return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);
226314564Sdim      }
227278332Semaste    }
228314564Sdim  }
229314564Sdim  return false;
230278332Semaste}
231278332Semaste
232314564Sdimbool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
233314564Sdim  if (m_section_sp.get() == nullptr)
234314564Sdim    return false;
235278332Semaste
236314564Sdim  if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
237314564Sdim    return true;
238278332Semaste
239314564Sdim  ScanIndex(process_sp);
240278332Semaste
241314564Sdim  return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
242278332Semaste}
243278332Semaste
244314564Sdimvoid CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
245314564Sdim  std::lock_guard<std::mutex> guard(m_mutex);
246314564Sdim  if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
247314564Sdim    return;
248278332Semaste
249314564Sdim  // We can't read the index for some reason.
250314564Sdim  if (m_indexes_computed == eLazyBoolNo) {
251314564Sdim    return;
252314564Sdim  }
253278332Semaste
254314564Sdim  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
255314564Sdim  if (log)
256314564Sdim    m_objfile.GetModule()->LogMessage(
257314564Sdim        log, "Reading compact unwind first-level indexes");
258278332Semaste
259344779Sdim  if (!m_unwindinfo_data_computed) {
260314564Sdim    if (m_section_sp->IsEncrypted()) {
261314564Sdim      // Can't get section contents of a protected/encrypted section until we
262341825Sdim      // have a live process and can read them out of memory.
263314564Sdim      if (process_sp.get() == nullptr)
264314564Sdim        return;
265353358Sdim      m_section_contents_if_encrypted =
266353358Sdim          std::make_shared<DataBufferHeap>(m_section_sp->GetByteSize(), 0);
267321369Sdim      Status error;
268314564Sdim      if (process_sp->ReadMemory(
269314564Sdim              m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
270314564Sdim              m_section_contents_if_encrypted->GetBytes(),
271314564Sdim              m_section_sp->GetByteSize(),
272314564Sdim              error) == m_section_sp->GetByteSize() &&
273314564Sdim          error.Success()) {
274314564Sdim        m_unwindinfo_data.SetAddressByteSize(
275314564Sdim            process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
276314564Sdim        m_unwindinfo_data.SetByteOrder(
277314564Sdim            process_sp->GetTarget().GetArchitecture().GetByteOrder());
278314564Sdim        m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);
279314564Sdim      }
280314564Sdim    } else {
281314564Sdim      m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
282278332Semaste    }
283314564Sdim    if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
284314564Sdim      return;
285314564Sdim    m_unwindinfo_data_computed = true;
286314564Sdim  }
287278332Semaste
288314564Sdim  if (m_unwindinfo_data.GetByteSize() > 0) {
289314564Sdim    offset_t offset = 0;
290278332Semaste
291314564Sdim    // struct unwind_info_section_header
292314564Sdim    // {
293314564Sdim    // uint32_t    version;            // UNWIND_SECTION_VERSION
294314564Sdim    // uint32_t    commonEncodingsArraySectionOffset;
295314564Sdim    // uint32_t    commonEncodingsArrayCount;
296314564Sdim    // uint32_t    personalityArraySectionOffset;
297314564Sdim    // uint32_t    personalityArrayCount;
298314564Sdim    // uint32_t    indexSectionOffset;
299314564Sdim    // uint32_t    indexCount;
300309124Sdim
301314564Sdim    m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
302314564Sdim    m_unwind_header.common_encodings_array_offset =
303314564Sdim        m_unwindinfo_data.GetU32(&offset);
304314564Sdim    m_unwind_header.common_encodings_array_count =
305314564Sdim        m_unwindinfo_data.GetU32(&offset);
306314564Sdim    m_unwind_header.personality_array_offset =
307314564Sdim        m_unwindinfo_data.GetU32(&offset);
308314564Sdim    m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
309314564Sdim    uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
310278332Semaste
311314564Sdim    uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
312278332Semaste
313314564Sdim    if (m_unwind_header.common_encodings_array_offset >
314314564Sdim            m_unwindinfo_data.GetByteSize() ||
315314564Sdim        m_unwind_header.personality_array_offset >
316314564Sdim            m_unwindinfo_data.GetByteSize() ||
317314564Sdim        indexSectionOffset > m_unwindinfo_data.GetByteSize() ||
318314564Sdim        offset > m_unwindinfo_data.GetByteSize()) {
319314564Sdim      Host::SystemLog(Host::eSystemLogError, "error: Invalid offset "
320314564Sdim                                             "encountered in compact unwind "
321314564Sdim                                             "info, skipping\n");
322314564Sdim      // don't trust anything from this compact_unwind section if it looks
323314564Sdim      // blatantly invalid data in the header.
324314564Sdim      m_indexes_computed = eLazyBoolNo;
325314564Sdim      return;
326314564Sdim    }
327278332Semaste
328341825Sdim    // Parse the basic information from the indexes We wait to scan the second
329341825Sdim    // level page info until it's needed
330278332Semaste
331341825Sdim    // struct unwind_info_section_header_index_entry {
332314564Sdim    //     uint32_t        functionOffset;
333314564Sdim    //     uint32_t        secondLevelPagesSectionOffset;
334314564Sdim    //     uint32_t        lsdaIndexArraySectionOffset;
335314564Sdim    // };
336278332Semaste
337314564Sdim    bool clear_address_zeroth_bit = false;
338344779Sdim    if (ArchSpec arch = m_objfile.GetArchitecture()) {
339314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::arm ||
340314564Sdim          arch.GetTriple().getArch() == llvm::Triple::thumb)
341314564Sdim        clear_address_zeroth_bit = true;
342314564Sdim    }
343309124Sdim
344314564Sdim    offset = indexSectionOffset;
345314564Sdim    for (uint32_t idx = 0; idx < indexCount; idx++) {
346314564Sdim      uint32_t function_offset =
347314564Sdim          m_unwindinfo_data.GetU32(&offset); // functionOffset
348314564Sdim      uint32_t second_level_offset =
349314564Sdim          m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
350314564Sdim      uint32_t lsda_offset =
351314564Sdim          m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
352278332Semaste
353314564Sdim      if (second_level_offset > m_section_sp->GetByteSize() ||
354314564Sdim          lsda_offset > m_section_sp->GetByteSize()) {
355314564Sdim        m_indexes_computed = eLazyBoolNo;
356314564Sdim      }
357278332Semaste
358314564Sdim      if (clear_address_zeroth_bit)
359314564Sdim        function_offset &= ~1ull;
360309124Sdim
361314564Sdim      UnwindIndex this_index;
362314564Sdim      this_index.function_offset = function_offset;
363314564Sdim      this_index.second_level = second_level_offset;
364314564Sdim      this_index.lsda_array_start = lsda_offset;
365278332Semaste
366314564Sdim      if (m_indexes.size() > 0) {
367314564Sdim        m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
368314564Sdim      }
369278332Semaste
370314564Sdim      if (second_level_offset == 0) {
371314564Sdim        this_index.sentinal_entry = true;
372314564Sdim      }
373278332Semaste
374314564Sdim      m_indexes.push_back(this_index);
375278332Semaste    }
376314564Sdim    m_indexes_computed = eLazyBoolYes;
377314564Sdim  } else {
378314564Sdim    m_indexes_computed = eLazyBoolNo;
379314564Sdim  }
380278332Semaste}
381278332Semaste
382314564Sdimuint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
383314564Sdim                                                     uint32_t lsda_count,
384314564Sdim                                                     uint32_t function_offset) {
385341825Sdim  // struct unwind_info_section_header_lsda_index_entry {
386314564Sdim  //         uint32_t        functionOffset;
387314564Sdim  //         uint32_t        lsdaOffset;
388314564Sdim  // };
389278332Semaste
390314564Sdim  offset_t first_entry = lsda_offset;
391314564Sdim  uint32_t low = 0;
392314564Sdim  uint32_t high = lsda_count;
393314564Sdim  while (low < high) {
394314564Sdim    uint32_t mid = (low + high) / 2;
395314564Sdim    offset_t offset = first_entry + (mid * 8);
396314564Sdim    uint32_t mid_func_offset =
397314564Sdim        m_unwindinfo_data.GetU32(&offset); // functionOffset
398314564Sdim    uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
399314564Sdim    if (mid_func_offset == function_offset) {
400314564Sdim      return mid_lsda_offset;
401278332Semaste    }
402314564Sdim    if (mid_func_offset < function_offset) {
403314564Sdim      low = mid + 1;
404314564Sdim    } else {
405314564Sdim      high = mid;
406314564Sdim    }
407314564Sdim  }
408314564Sdim  return 0;
409278332Semaste}
410278332Semaste
411314564Sdimlldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(
412314564Sdim    uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,
413314564Sdim    uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
414314564Sdim  // typedef uint32_t compact_unwind_encoding_t;
415341825Sdim  // struct unwind_info_regular_second_level_entry {
416314564Sdim  //     uint32_t                    functionOffset;
417314564Sdim  //     compact_unwind_encoding_t    encoding;
418278332Semaste
419314564Sdim  offset_t first_entry = entry_page_offset;
420278332Semaste
421314564Sdim  uint32_t low = 0;
422314564Sdim  uint32_t high = entry_count;
423314564Sdim  uint32_t last = high - 1;
424314564Sdim  while (low < high) {
425314564Sdim    uint32_t mid = (low + high) / 2;
426314564Sdim    offset_t offset = first_entry + (mid * 8);
427314564Sdim    uint32_t mid_func_offset =
428314564Sdim        m_unwindinfo_data.GetU32(&offset); // functionOffset
429314564Sdim    uint32_t next_func_offset = 0;
430314564Sdim    if (mid < last) {
431314564Sdim      offset = first_entry + ((mid + 1) * 8);
432314564Sdim      next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
433278332Semaste    }
434314564Sdim    if (mid_func_offset <= function_offset) {
435314564Sdim      if (mid == last || (next_func_offset > function_offset)) {
436314564Sdim        if (entry_func_start_offset)
437314564Sdim          *entry_func_start_offset = mid_func_offset;
438314564Sdim        if (mid != last && entry_func_end_offset)
439314564Sdim          *entry_func_end_offset = next_func_offset;
440314564Sdim        return first_entry + (mid * 8);
441314564Sdim      } else {
442314564Sdim        low = mid + 1;
443314564Sdim      }
444314564Sdim    } else {
445314564Sdim      high = mid;
446314564Sdim    }
447314564Sdim  }
448314564Sdim  return LLDB_INVALID_OFFSET;
449278332Semaste}
450278332Semaste
451314564Sdimuint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(
452314564Sdim    uint32_t entry_page_offset, uint32_t entry_count,
453314564Sdim    uint32_t function_offset_to_find, uint32_t function_offset_base,
454314564Sdim    uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
455314564Sdim  offset_t first_entry = entry_page_offset;
456278332Semaste
457314564Sdim  uint32_t low = 0;
458314564Sdim  uint32_t high = entry_count;
459314564Sdim  uint32_t last = high - 1;
460314564Sdim  while (low < high) {
461314564Sdim    uint32_t mid = (low + high) / 2;
462314564Sdim    offset_t offset = first_entry + (mid * 4);
463314564Sdim    uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
464314564Sdim    uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
465314564Sdim    mid_func_offset += function_offset_base;
466314564Sdim    uint32_t next_func_offset = 0;
467314564Sdim    if (mid < last) {
468314564Sdim      offset = first_entry + ((mid + 1) * 4);
469314564Sdim      uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
470314564Sdim      next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);
471314564Sdim      next_func_offset += function_offset_base;
472278332Semaste    }
473314564Sdim    if (mid_func_offset <= function_offset_to_find) {
474314564Sdim      if (mid == last || (next_func_offset > function_offset_to_find)) {
475314564Sdim        if (entry_func_start_offset)
476314564Sdim          *entry_func_start_offset = mid_func_offset;
477314564Sdim        if (mid != last && entry_func_end_offset)
478314564Sdim          *entry_func_end_offset = next_func_offset;
479314564Sdim        return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
480314564Sdim      } else {
481314564Sdim        low = mid + 1;
482314564Sdim      }
483314564Sdim    } else {
484314564Sdim      high = mid;
485314564Sdim    }
486314564Sdim  }
487278332Semaste
488314564Sdim  return UINT32_MAX;
489278332Semaste}
490278332Semaste
491314564Sdimbool CompactUnwindInfo::GetCompactUnwindInfoForFunction(
492314564Sdim    Target &target, Address address, FunctionInfo &unwind_info) {
493314564Sdim  unwind_info.encoding = 0;
494314564Sdim  unwind_info.lsda_address.Clear();
495314564Sdim  unwind_info.personality_ptr_address.Clear();
496278332Semaste
497314564Sdim  if (!IsValid(target.GetProcessSP()))
498314564Sdim    return false;
499278332Semaste
500314564Sdim  addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
501314564Sdim  SectionList *sl = m_objfile.GetSectionList();
502314564Sdim  if (sl) {
503314564Sdim    SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
504314564Sdim    if (text_sect.get()) {
505314564Sdim      text_section_file_address = text_sect->GetFileAddress();
506278332Semaste    }
507314564Sdim  }
508314564Sdim  if (text_section_file_address == LLDB_INVALID_ADDRESS)
509314564Sdim    return false;
510278332Semaste
511314564Sdim  addr_t function_offset =
512344779Sdim      address.GetFileAddress() - m_objfile.GetBaseAddress().GetFileAddress();
513309124Sdim
514314564Sdim  UnwindIndex key;
515314564Sdim  key.function_offset = function_offset;
516309124Sdim
517314564Sdim  std::vector<UnwindIndex>::const_iterator it;
518314564Sdim  it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key);
519314564Sdim  if (it == m_indexes.end()) {
520314564Sdim    return false;
521314564Sdim  }
522278332Semaste
523314564Sdim  if (it->function_offset != key.function_offset) {
524314564Sdim    if (it != m_indexes.begin())
525314564Sdim      --it;
526314564Sdim  }
527278332Semaste
528344779Sdim  if (it->sentinal_entry) {
529314564Sdim    return false;
530314564Sdim  }
531278332Semaste
532314564Sdim  auto next_it = it + 1;
533314564Sdim  if (next_it != m_indexes.end()) {
534341825Sdim    // initialize the function offset end range to be the start of the next
535341825Sdim    // index offset.  If we find an entry which is at the end of the index
536341825Sdim    // table, this will establish the range end.
537314564Sdim    unwind_info.valid_range_offset_end = next_it->function_offset;
538314564Sdim  }
539278332Semaste
540314564Sdim  offset_t second_page_offset = it->second_level;
541314564Sdim  offset_t lsda_array_start = it->lsda_array_start;
542314564Sdim  offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
543278332Semaste
544314564Sdim  offset_t offset = second_page_offset;
545314564Sdim  uint32_t kind = m_unwindinfo_data.GetU32(
546314564Sdim      &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
547278332Semaste
548314564Sdim  if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
549341825Sdim    // struct unwind_info_regular_second_level_page_header {
550314564Sdim    //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_REGULAR
551314564Sdim    //     uint16_t    entryPageOffset;
552314564Sdim    //     uint16_t    entryCount;
553278332Semaste
554314564Sdim    // typedef uint32_t compact_unwind_encoding_t;
555341825Sdim    // struct unwind_info_regular_second_level_entry {
556314564Sdim    //     uint32_t                    functionOffset;
557314564Sdim    //     compact_unwind_encoding_t    encoding;
558278332Semaste
559314564Sdim    uint16_t entry_page_offset =
560314564Sdim        m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
561314564Sdim    uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
562278332Semaste
563314564Sdim    offset_t entry_offset = BinarySearchRegularSecondPage(
564314564Sdim        second_page_offset + entry_page_offset, entry_count, function_offset,
565314564Sdim        &unwind_info.valid_range_offset_start,
566314564Sdim        &unwind_info.valid_range_offset_end);
567314564Sdim    if (entry_offset == LLDB_INVALID_OFFSET) {
568314564Sdim      return false;
569314564Sdim    }
570314564Sdim    entry_offset += 4; // skip over functionOffset
571314564Sdim    unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
572314564Sdim    if (unwind_info.encoding & UNWIND_HAS_LSDA) {
573314564Sdim      SectionList *sl = m_objfile.GetSectionList();
574314564Sdim      if (sl) {
575314564Sdim        uint32_t lsda_offset = GetLSDAForFunctionOffset(
576314564Sdim            lsda_array_start, lsda_array_count, function_offset);
577344779Sdim        addr_t objfile_base_address =
578344779Sdim            m_objfile.GetBaseAddress().GetFileAddress();
579314564Sdim        unwind_info.lsda_address.ResolveAddressUsingFileSections(
580344779Sdim            objfile_base_address + lsda_offset, sl);
581314564Sdim      }
582314564Sdim    }
583314564Sdim    if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
584314564Sdim      uint32_t personality_index =
585314564Sdim          EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
586278332Semaste
587314564Sdim      if (personality_index > 0) {
588314564Sdim        personality_index--;
589314564Sdim        if (personality_index < m_unwind_header.personality_array_count) {
590314564Sdim          offset_t offset = m_unwind_header.personality_array_offset;
591314564Sdim          offset += 4 * personality_index;
592314564Sdim          SectionList *sl = m_objfile.GetSectionList();
593314564Sdim          if (sl) {
594314564Sdim            uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
595344779Sdim            addr_t objfile_base_address =
596344779Sdim                m_objfile.GetBaseAddress().GetFileAddress();
597314564Sdim            unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
598344779Sdim                objfile_base_address + personality_offset, sl);
599314564Sdim          }
600278332Semaste        }
601314564Sdim      }
602278332Semaste    }
603314564Sdim    return true;
604314564Sdim  } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
605341825Sdim    // struct unwind_info_compressed_second_level_page_header {
606314564Sdim    //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_COMPRESSED
607314564Sdim    //     uint16_t    entryPageOffset;         // offset from this 2nd lvl page
608314564Sdim    //     idx to array of entries
609314564Sdim    //                                          // (an entry has a function
610314564Sdim    //                                          offset and index into the
611314564Sdim    //                                          encodings)
612314564Sdim    //                                          // NB function offset from the
613314564Sdim    //                                          entry in the compressed page
614314564Sdim    //                                          // must be added to the index's
615314564Sdim    //                                          functionOffset value.
616314564Sdim    //     uint16_t    entryCount;
617314564Sdim    //     uint16_t    encodingsPageOffset;     // offset from this 2nd lvl page
618314564Sdim    //     idx to array of encodings
619314564Sdim    //     uint16_t    encodingsCount;
620278332Semaste
621314564Sdim    uint16_t entry_page_offset =
622314564Sdim        m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
623314564Sdim    uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
624314564Sdim    uint16_t encodings_page_offset =
625314564Sdim        m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
626314564Sdim    uint16_t encodings_count =
627314564Sdim        m_unwindinfo_data.GetU16(&offset); // encodingsCount
628278332Semaste
629314564Sdim    uint32_t encoding_index = BinarySearchCompressedSecondPage(
630314564Sdim        second_page_offset + entry_page_offset, entry_count, function_offset,
631314564Sdim        it->function_offset, &unwind_info.valid_range_offset_start,
632314564Sdim        &unwind_info.valid_range_offset_end);
633314564Sdim    if (encoding_index == UINT32_MAX ||
634314564Sdim        encoding_index >=
635314564Sdim            encodings_count + m_unwind_header.common_encodings_array_count) {
636314564Sdim      return false;
637314564Sdim    }
638314564Sdim    uint32_t encoding = 0;
639314564Sdim    if (encoding_index < m_unwind_header.common_encodings_array_count) {
640314564Sdim      offset = m_unwind_header.common_encodings_array_offset +
641314564Sdim               (encoding_index * sizeof(uint32_t));
642314564Sdim      encoding = m_unwindinfo_data.GetU32(
643314564Sdim          &offset); // encoding entry from the commonEncodingsArray
644314564Sdim    } else {
645314564Sdim      uint32_t page_specific_entry_index =
646314564Sdim          encoding_index - m_unwind_header.common_encodings_array_count;
647314564Sdim      offset = second_page_offset + encodings_page_offset +
648314564Sdim               (page_specific_entry_index * sizeof(uint32_t));
649314564Sdim      encoding = m_unwindinfo_data.GetU32(
650314564Sdim          &offset); // encoding entry from the page-specific encoding array
651314564Sdim    }
652314564Sdim    if (encoding == 0)
653314564Sdim      return false;
654278332Semaste
655314564Sdim    unwind_info.encoding = encoding;
656314564Sdim    if (unwind_info.encoding & UNWIND_HAS_LSDA) {
657314564Sdim      SectionList *sl = m_objfile.GetSectionList();
658314564Sdim      if (sl) {
659314564Sdim        uint32_t lsda_offset = GetLSDAForFunctionOffset(
660314564Sdim            lsda_array_start, lsda_array_count, function_offset);
661344779Sdim        addr_t objfile_base_address =
662344779Sdim            m_objfile.GetBaseAddress().GetFileAddress();
663314564Sdim        unwind_info.lsda_address.ResolveAddressUsingFileSections(
664344779Sdim            objfile_base_address + lsda_offset, sl);
665314564Sdim      }
666314564Sdim    }
667314564Sdim    if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
668314564Sdim      uint32_t personality_index =
669314564Sdim          EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
670278332Semaste
671314564Sdim      if (personality_index > 0) {
672314564Sdim        personality_index--;
673314564Sdim        if (personality_index < m_unwind_header.personality_array_count) {
674314564Sdim          offset_t offset = m_unwind_header.personality_array_offset;
675314564Sdim          offset += 4 * personality_index;
676314564Sdim          SectionList *sl = m_objfile.GetSectionList();
677314564Sdim          if (sl) {
678314564Sdim            uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
679344779Sdim            addr_t objfile_base_address =
680344779Sdim                m_objfile.GetBaseAddress().GetFileAddress();
681314564Sdim            unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
682344779Sdim                objfile_base_address + personality_offset, sl);
683314564Sdim          }
684278332Semaste        }
685314564Sdim      }
686278332Semaste    }
687314564Sdim    return true;
688314564Sdim  }
689314564Sdim  return false;
690278332Semaste}
691278332Semaste
692278332Semasteenum x86_64_eh_regnum {
693314564Sdim  rax = 0,
694314564Sdim  rdx = 1,
695314564Sdim  rcx = 2,
696314564Sdim  rbx = 3,
697314564Sdim  rsi = 4,
698314564Sdim  rdi = 5,
699314564Sdim  rbp = 6,
700314564Sdim  rsp = 7,
701314564Sdim  r8 = 8,
702314564Sdim  r9 = 9,
703314564Sdim  r10 = 10,
704314564Sdim  r11 = 11,
705314564Sdim  r12 = 12,
706314564Sdim  r13 = 13,
707314564Sdim  r14 = 14,
708314564Sdim  r15 = 15,
709314564Sdim  rip = 16 // this is officially the Return Address register number, but close
710314564Sdim           // enough
711278332Semaste};
712278332Semaste
713341825Sdim// Convert the compact_unwind_info.h register numbering scheme to
714341825Sdim// eRegisterKindEHFrame (eh_frame) register numbering scheme.
715314564Sdimuint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {
716314564Sdim  switch (unwind_regno) {
717314564Sdim  case UNWIND_X86_64_REG_RBX:
718314564Sdim    return x86_64_eh_regnum::rbx;
719314564Sdim  case UNWIND_X86_64_REG_R12:
720314564Sdim    return x86_64_eh_regnum::r12;
721314564Sdim  case UNWIND_X86_64_REG_R13:
722314564Sdim    return x86_64_eh_regnum::r13;
723314564Sdim  case UNWIND_X86_64_REG_R14:
724314564Sdim    return x86_64_eh_regnum::r14;
725314564Sdim  case UNWIND_X86_64_REG_R15:
726314564Sdim    return x86_64_eh_regnum::r15;
727314564Sdim  case UNWIND_X86_64_REG_RBP:
728314564Sdim    return x86_64_eh_regnum::rbp;
729314564Sdim  default:
730314564Sdim    return LLDB_INVALID_REGNUM;
731314564Sdim  }
732278332Semaste}
733278332Semaste
734314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
735314564Sdim                                                FunctionInfo &function_info,
736314564Sdim                                                UnwindPlan &unwind_plan,
737314564Sdim                                                Address pc_or_function_start) {
738314564Sdim  unwind_plan.SetSourceName("compact unwind info");
739314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
740314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
741360784Sdim  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
742314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
743278332Semaste
744314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
745314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
746278332Semaste
747314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
748278332Semaste
749314564Sdim  const int wordsize = 8;
750314564Sdim  int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
751314564Sdim  switch (mode) {
752314564Sdim  case UNWIND_X86_64_MODE_RBP_FRAME: {
753314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(
754314564Sdim        translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),
755314564Sdim        2 * wordsize);
756314564Sdim    row->SetOffset(0);
757314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,
758314564Sdim                                              wordsize * -2, true);
759314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
760314564Sdim                                              wordsize * -1, true);
761314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
762309124Sdim
763314564Sdim    uint32_t saved_registers_offset =
764314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
765278332Semaste
766314564Sdim    uint32_t saved_registers_locations =
767314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
768278332Semaste
769314564Sdim    saved_registers_offset += 2;
770278332Semaste
771314564Sdim    for (int i = 0; i < 5; i++) {
772314564Sdim      uint32_t regnum = saved_registers_locations & 0x7;
773314564Sdim      switch (regnum) {
774314564Sdim      case UNWIND_X86_64_REG_NONE:
775278332Semaste        break;
776314564Sdim      case UNWIND_X86_64_REG_RBX:
777314564Sdim      case UNWIND_X86_64_REG_R12:
778314564Sdim      case UNWIND_X86_64_REG_R13:
779314564Sdim      case UNWIND_X86_64_REG_R14:
780314564Sdim      case UNWIND_X86_64_REG_R15:
781314564Sdim        row->SetRegisterLocationToAtCFAPlusOffset(
782314564Sdim            translate_to_eh_frame_regnum_x86_64(regnum),
783314564Sdim            wordsize * -saved_registers_offset, true);
784278332Semaste        break;
785314564Sdim      }
786314564Sdim      saved_registers_offset--;
787314564Sdim      saved_registers_locations >>= 3;
788314564Sdim    }
789314564Sdim    unwind_plan.AppendRow(row);
790314564Sdim    return true;
791314564Sdim  } break;
792278332Semaste
793314564Sdim  case UNWIND_X86_64_MODE_STACK_IND: {
794314564Sdim    // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
795341825Sdim    // this style of unwind.  It was fixed in llvm r217020. The clang in Xcode
796341825Sdim    // 7 has this fixed.
797314564Sdim    return false;
798314564Sdim  } break;
799278332Semaste
800314564Sdim  case UNWIND_X86_64_MODE_STACK_IMMD: {
801314564Sdim    uint32_t stack_size = EXTRACT_BITS(function_info.encoding,
802314564Sdim                                       UNWIND_X86_64_FRAMELESS_STACK_SIZE);
803314564Sdim    uint32_t register_count = EXTRACT_BITS(
804314564Sdim        function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
805314564Sdim    uint32_t permutation = EXTRACT_BITS(
806314564Sdim        function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
807278332Semaste
808314564Sdim    if (mode == UNWIND_X86_64_MODE_STACK_IND &&
809314564Sdim        function_info.valid_range_offset_start != 0) {
810314564Sdim      uint32_t stack_adjust = EXTRACT_BITS(
811314564Sdim          function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
812278332Semaste
813314564Sdim      // offset into the function instructions; 0 == beginning of first
814314564Sdim      // instruction
815314564Sdim      uint32_t offset_to_subl_insn = EXTRACT_BITS(
816314564Sdim          function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
817278332Semaste
818314564Sdim      SectionList *sl = m_objfile.GetSectionList();
819314564Sdim      if (sl) {
820314564Sdim        ProcessSP process_sp = target.GetProcessSP();
821314564Sdim        if (process_sp) {
822314564Sdim          Address subl_payload_addr(function_info.valid_range_offset_start, sl);
823314564Sdim          subl_payload_addr.Slide(offset_to_subl_insn);
824321369Sdim          Status error;
825314564Sdim          uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
826314564Sdim              subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
827314564Sdim          if (large_stack_size != 0 && error.Success()) {
828314564Sdim            // Got the large stack frame size correctly - use it
829314564Sdim            stack_size = large_stack_size + (stack_adjust * wordsize);
830314564Sdim          } else {
831314564Sdim            return false;
832314564Sdim          }
833314564Sdim        } else {
834314564Sdim          return false;
835314564Sdim        }
836314564Sdim      } else {
837314564Sdim        return false;
838314564Sdim      }
839314564Sdim    }
840288943Sdim
841314564Sdim    int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
842314564Sdim                         ? stack_size
843314564Sdim                         : stack_size * wordsize;
844314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
845278332Semaste
846314564Sdim    row->SetOffset(0);
847314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
848314564Sdim                                              wordsize * -1, true);
849314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
850278332Semaste
851314564Sdim    if (register_count > 0) {
852278332Semaste
853341825Sdim      // We need to include (up to) 6 registers in 10 bits. That would be 18
854341825Sdim      // bits if we just used 3 bits per reg to indicate the order they're
855341825Sdim      // saved on the stack.
856314564Sdim      //
857314564Sdim      // This is done with Lehmer code permutation, e.g. see
858341825Sdim      // http://stackoverflow.com/questions/1506078/fast-permutation-number-
859341825Sdim      // permutation-mapping-algorithms
860314564Sdim      int permunreg[6] = {0, 0, 0, 0, 0, 0};
861278332Semaste
862341825Sdim      // This decodes the variable-base number in the 10 bits and gives us the
863341825Sdim      // Lehmer code sequence which can then be decoded.
864309124Sdim
865314564Sdim      switch (register_count) {
866314564Sdim      case 6:
867314564Sdim        permunreg[0] = permutation / 120; // 120 == 5!
868314564Sdim        permutation -= (permunreg[0] * 120);
869314564Sdim        permunreg[1] = permutation / 24; // 24 == 4!
870314564Sdim        permutation -= (permunreg[1] * 24);
871314564Sdim        permunreg[2] = permutation / 6; // 6 == 3!
872314564Sdim        permutation -= (permunreg[2] * 6);
873314564Sdim        permunreg[3] = permutation / 2; // 2 == 2!
874314564Sdim        permutation -= (permunreg[3] * 2);
875314564Sdim        permunreg[4] = permutation; // 1 == 1!
876314564Sdim        permunreg[5] = 0;
877314564Sdim        break;
878314564Sdim      case 5:
879314564Sdim        permunreg[0] = permutation / 120;
880314564Sdim        permutation -= (permunreg[0] * 120);
881314564Sdim        permunreg[1] = permutation / 24;
882314564Sdim        permutation -= (permunreg[1] * 24);
883314564Sdim        permunreg[2] = permutation / 6;
884314564Sdim        permutation -= (permunreg[2] * 6);
885314564Sdim        permunreg[3] = permutation / 2;
886314564Sdim        permutation -= (permunreg[3] * 2);
887314564Sdim        permunreg[4] = permutation;
888314564Sdim        break;
889314564Sdim      case 4:
890314564Sdim        permunreg[0] = permutation / 60;
891314564Sdim        permutation -= (permunreg[0] * 60);
892314564Sdim        permunreg[1] = permutation / 12;
893314564Sdim        permutation -= (permunreg[1] * 12);
894314564Sdim        permunreg[2] = permutation / 3;
895314564Sdim        permutation -= (permunreg[2] * 3);
896314564Sdim        permunreg[3] = permutation;
897314564Sdim        break;
898314564Sdim      case 3:
899314564Sdim        permunreg[0] = permutation / 20;
900314564Sdim        permutation -= (permunreg[0] * 20);
901314564Sdim        permunreg[1] = permutation / 4;
902314564Sdim        permutation -= (permunreg[1] * 4);
903314564Sdim        permunreg[2] = permutation;
904314564Sdim        break;
905314564Sdim      case 2:
906314564Sdim        permunreg[0] = permutation / 5;
907314564Sdim        permutation -= (permunreg[0] * 5);
908314564Sdim        permunreg[1] = permutation;
909314564Sdim        break;
910314564Sdim      case 1:
911314564Sdim        permunreg[0] = permutation;
912314564Sdim        break;
913314564Sdim      }
914278332Semaste
915341825Sdim      // Decode the Lehmer code for this permutation of the registers v.
916341825Sdim      // http://en.wikipedia.org/wiki/Lehmer_code
917278332Semaste
918314564Sdim      int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
919314564Sdim                          UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
920314564Sdim                          UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
921314564Sdim      bool used[7] = {false, false, false, false, false, false, false};
922314564Sdim      for (uint32_t i = 0; i < register_count; i++) {
923314564Sdim        int renum = 0;
924314564Sdim        for (int j = 1; j < 7; j++) {
925344779Sdim          if (!used[j]) {
926314564Sdim            if (renum == permunreg[i]) {
927314564Sdim              registers[i] = j;
928314564Sdim              used[j] = true;
929314564Sdim              break;
930278332Semaste            }
931314564Sdim            renum++;
932314564Sdim          }
933278332Semaste        }
934314564Sdim      }
935278332Semaste
936314564Sdim      uint32_t saved_registers_offset = 1;
937314564Sdim      saved_registers_offset++;
938278332Semaste
939314564Sdim      for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
940314564Sdim        switch (registers[i]) {
941314564Sdim        case UNWIND_X86_64_REG_NONE:
942314564Sdim          break;
943314564Sdim        case UNWIND_X86_64_REG_RBX:
944314564Sdim        case UNWIND_X86_64_REG_R12:
945314564Sdim        case UNWIND_X86_64_REG_R13:
946314564Sdim        case UNWIND_X86_64_REG_R14:
947314564Sdim        case UNWIND_X86_64_REG_R15:
948314564Sdim        case UNWIND_X86_64_REG_RBP:
949314564Sdim          row->SetRegisterLocationToAtCFAPlusOffset(
950314564Sdim              translate_to_eh_frame_regnum_x86_64(registers[i]),
951314564Sdim              wordsize * -saved_registers_offset, true);
952314564Sdim          saved_registers_offset++;
953314564Sdim          break;
954278332Semaste        }
955314564Sdim      }
956278332Semaste    }
957314564Sdim    unwind_plan.AppendRow(row);
958314564Sdim    return true;
959314564Sdim  } break;
960314564Sdim
961314564Sdim  case UNWIND_X86_64_MODE_DWARF: {
962278332Semaste    return false;
963314564Sdim  } break;
964314564Sdim
965314564Sdim  case 0: {
966314564Sdim    return false;
967314564Sdim  } break;
968314564Sdim  }
969314564Sdim  return false;
970278332Semaste}
971278332Semaste
972278332Semasteenum i386_eh_regnum {
973314564Sdim  eax = 0,
974314564Sdim  ecx = 1,
975314564Sdim  edx = 2,
976314564Sdim  ebx = 3,
977314564Sdim  ebp = 4,
978314564Sdim  esp = 5,
979314564Sdim  esi = 6,
980314564Sdim  edi = 7,
981314564Sdim  eip = 8 // this is officially the Return Address register number, but close
982314564Sdim          // enough
983278332Semaste};
984278332Semaste
985341825Sdim// Convert the compact_unwind_info.h register numbering scheme to
986341825Sdim// eRegisterKindEHFrame (eh_frame) register numbering scheme.
987314564Sdimuint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {
988314564Sdim  switch (unwind_regno) {
989314564Sdim  case UNWIND_X86_REG_EBX:
990314564Sdim    return i386_eh_regnum::ebx;
991314564Sdim  case UNWIND_X86_REG_ECX:
992314564Sdim    return i386_eh_regnum::ecx;
993314564Sdim  case UNWIND_X86_REG_EDX:
994314564Sdim    return i386_eh_regnum::edx;
995314564Sdim  case UNWIND_X86_REG_EDI:
996314564Sdim    return i386_eh_regnum::edi;
997314564Sdim  case UNWIND_X86_REG_ESI:
998314564Sdim    return i386_eh_regnum::esi;
999314564Sdim  case UNWIND_X86_REG_EBP:
1000314564Sdim    return i386_eh_regnum::ebp;
1001314564Sdim  default:
1002314564Sdim    return LLDB_INVALID_REGNUM;
1003314564Sdim  }
1004278332Semaste}
1005278332Semaste
1006314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
1007314564Sdim                                              FunctionInfo &function_info,
1008314564Sdim                                              UnwindPlan &unwind_plan,
1009314564Sdim                                              Address pc_or_function_start) {
1010314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1011314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1012314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1013360784Sdim  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1014314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1015278332Semaste
1016314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1017314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1018278332Semaste
1019314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1020278332Semaste
1021314564Sdim  const int wordsize = 4;
1022314564Sdim  int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1023314564Sdim  switch (mode) {
1024314564Sdim  case UNWIND_X86_MODE_EBP_FRAME: {
1025314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(
1026314564Sdim        translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
1027314564Sdim    row->SetOffset(0);
1028314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,
1029314564Sdim                                              wordsize * -2, true);
1030314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1031314564Sdim                                              wordsize * -1, true);
1032314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1033278332Semaste
1034314564Sdim    uint32_t saved_registers_offset =
1035314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1036309124Sdim
1037314564Sdim    uint32_t saved_registers_locations =
1038314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1039278332Semaste
1040314564Sdim    saved_registers_offset += 2;
1041278332Semaste
1042314564Sdim    for (int i = 0; i < 5; i++) {
1043314564Sdim      uint32_t regnum = saved_registers_locations & 0x7;
1044314564Sdim      switch (regnum) {
1045314564Sdim      case UNWIND_X86_REG_NONE:
1046278332Semaste        break;
1047314564Sdim      case UNWIND_X86_REG_EBX:
1048314564Sdim      case UNWIND_X86_REG_ECX:
1049314564Sdim      case UNWIND_X86_REG_EDX:
1050314564Sdim      case UNWIND_X86_REG_EDI:
1051314564Sdim      case UNWIND_X86_REG_ESI:
1052314564Sdim        row->SetRegisterLocationToAtCFAPlusOffset(
1053314564Sdim            translate_to_eh_frame_regnum_i386(regnum),
1054314564Sdim            wordsize * -saved_registers_offset, true);
1055314564Sdim        break;
1056314564Sdim      }
1057314564Sdim      saved_registers_offset--;
1058314564Sdim      saved_registers_locations >>= 3;
1059314564Sdim    }
1060314564Sdim    unwind_plan.AppendRow(row);
1061314564Sdim    return true;
1062314564Sdim  } break;
1063278332Semaste
1064314564Sdim  case UNWIND_X86_MODE_STACK_IND:
1065314564Sdim  case UNWIND_X86_MODE_STACK_IMMD: {
1066314564Sdim    uint32_t stack_size =
1067314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1068314564Sdim    uint32_t register_count = EXTRACT_BITS(
1069314564Sdim        function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1070314564Sdim    uint32_t permutation = EXTRACT_BITS(
1071314564Sdim        function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
1072278332Semaste
1073314564Sdim    if (mode == UNWIND_X86_MODE_STACK_IND &&
1074314564Sdim        function_info.valid_range_offset_start != 0) {
1075314564Sdim      uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,
1076314564Sdim                                           UNWIND_X86_FRAMELESS_STACK_ADJUST);
1077278332Semaste
1078314564Sdim      // offset into the function instructions; 0 == beginning of first
1079314564Sdim      // instruction
1080314564Sdim      uint32_t offset_to_subl_insn =
1081314564Sdim          EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1082278332Semaste
1083314564Sdim      SectionList *sl = m_objfile.GetSectionList();
1084314564Sdim      if (sl) {
1085314564Sdim        ProcessSP process_sp = target.GetProcessSP();
1086314564Sdim        if (process_sp) {
1087314564Sdim          Address subl_payload_addr(function_info.valid_range_offset_start, sl);
1088314564Sdim          subl_payload_addr.Slide(offset_to_subl_insn);
1089321369Sdim          Status error;
1090314564Sdim          uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
1091314564Sdim              subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
1092314564Sdim          if (large_stack_size != 0 && error.Success()) {
1093314564Sdim            // Got the large stack frame size correctly - use it
1094314564Sdim            stack_size = large_stack_size + (stack_adjust * wordsize);
1095314564Sdim          } else {
1096314564Sdim            return false;
1097314564Sdim          }
1098314564Sdim        } else {
1099314564Sdim          return false;
1100314564Sdim        }
1101314564Sdim      } else {
1102314564Sdim        return false;
1103314564Sdim      }
1104314564Sdim    }
1105278332Semaste
1106314564Sdim    int32_t offset =
1107314564Sdim        mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1108314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
1109314564Sdim    row->SetOffset(0);
1110314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1111314564Sdim                                              wordsize * -1, true);
1112314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1113309124Sdim
1114314564Sdim    if (register_count > 0) {
1115278332Semaste
1116341825Sdim      // We need to include (up to) 6 registers in 10 bits. That would be 18
1117341825Sdim      // bits if we just used 3 bits per reg to indicate the order they're
1118341825Sdim      // saved on the stack.
1119314564Sdim      //
1120314564Sdim      // This is done with Lehmer code permutation, e.g. see
1121341825Sdim      // http://stackoverflow.com/questions/1506078/fast-permutation-number-
1122341825Sdim      // permutation-mapping-algorithms
1123314564Sdim      int permunreg[6] = {0, 0, 0, 0, 0, 0};
1124278332Semaste
1125341825Sdim      // This decodes the variable-base number in the 10 bits and gives us the
1126341825Sdim      // Lehmer code sequence which can then be decoded.
1127278332Semaste
1128314564Sdim      switch (register_count) {
1129314564Sdim      case 6:
1130314564Sdim        permunreg[0] = permutation / 120; // 120 == 5!
1131314564Sdim        permutation -= (permunreg[0] * 120);
1132314564Sdim        permunreg[1] = permutation / 24; // 24 == 4!
1133314564Sdim        permutation -= (permunreg[1] * 24);
1134314564Sdim        permunreg[2] = permutation / 6; // 6 == 3!
1135314564Sdim        permutation -= (permunreg[2] * 6);
1136314564Sdim        permunreg[3] = permutation / 2; // 2 == 2!
1137314564Sdim        permutation -= (permunreg[3] * 2);
1138314564Sdim        permunreg[4] = permutation; // 1 == 1!
1139314564Sdim        permunreg[5] = 0;
1140314564Sdim        break;
1141314564Sdim      case 5:
1142314564Sdim        permunreg[0] = permutation / 120;
1143314564Sdim        permutation -= (permunreg[0] * 120);
1144314564Sdim        permunreg[1] = permutation / 24;
1145314564Sdim        permutation -= (permunreg[1] * 24);
1146314564Sdim        permunreg[2] = permutation / 6;
1147314564Sdim        permutation -= (permunreg[2] * 6);
1148314564Sdim        permunreg[3] = permutation / 2;
1149314564Sdim        permutation -= (permunreg[3] * 2);
1150314564Sdim        permunreg[4] = permutation;
1151314564Sdim        break;
1152314564Sdim      case 4:
1153314564Sdim        permunreg[0] = permutation / 60;
1154314564Sdim        permutation -= (permunreg[0] * 60);
1155314564Sdim        permunreg[1] = permutation / 12;
1156314564Sdim        permutation -= (permunreg[1] * 12);
1157314564Sdim        permunreg[2] = permutation / 3;
1158314564Sdim        permutation -= (permunreg[2] * 3);
1159314564Sdim        permunreg[3] = permutation;
1160314564Sdim        break;
1161314564Sdim      case 3:
1162314564Sdim        permunreg[0] = permutation / 20;
1163314564Sdim        permutation -= (permunreg[0] * 20);
1164314564Sdim        permunreg[1] = permutation / 4;
1165314564Sdim        permutation -= (permunreg[1] * 4);
1166314564Sdim        permunreg[2] = permutation;
1167314564Sdim        break;
1168314564Sdim      case 2:
1169314564Sdim        permunreg[0] = permutation / 5;
1170314564Sdim        permutation -= (permunreg[0] * 5);
1171314564Sdim        permunreg[1] = permutation;
1172314564Sdim        break;
1173314564Sdim      case 1:
1174314564Sdim        permunreg[0] = permutation;
1175314564Sdim        break;
1176314564Sdim      }
1177309124Sdim
1178341825Sdim      // Decode the Lehmer code for this permutation of the registers v.
1179341825Sdim      // http://en.wikipedia.org/wiki/Lehmer_code
1180278332Semaste
1181314564Sdim      int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1182314564Sdim                          UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1183314564Sdim                          UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};
1184314564Sdim      bool used[7] = {false, false, false, false, false, false, false};
1185314564Sdim      for (uint32_t i = 0; i < register_count; i++) {
1186314564Sdim        int renum = 0;
1187314564Sdim        for (int j = 1; j < 7; j++) {
1188344779Sdim          if (!used[j]) {
1189314564Sdim            if (renum == permunreg[i]) {
1190314564Sdim              registers[i] = j;
1191314564Sdim              used[j] = true;
1192314564Sdim              break;
1193278332Semaste            }
1194314564Sdim            renum++;
1195314564Sdim          }
1196278332Semaste        }
1197314564Sdim      }
1198278332Semaste
1199314564Sdim      uint32_t saved_registers_offset = 1;
1200314564Sdim      saved_registers_offset++;
1201314564Sdim
1202314564Sdim      for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1203314564Sdim        switch (registers[i]) {
1204314564Sdim        case UNWIND_X86_REG_NONE:
1205314564Sdim          break;
1206314564Sdim        case UNWIND_X86_REG_EBX:
1207314564Sdim        case UNWIND_X86_REG_ECX:
1208314564Sdim        case UNWIND_X86_REG_EDX:
1209314564Sdim        case UNWIND_X86_REG_EDI:
1210314564Sdim        case UNWIND_X86_REG_ESI:
1211314564Sdim        case UNWIND_X86_REG_EBP:
1212314564Sdim          row->SetRegisterLocationToAtCFAPlusOffset(
1213314564Sdim              translate_to_eh_frame_regnum_i386(registers[i]),
1214314564Sdim              wordsize * -saved_registers_offset, true);
1215314564Sdim          saved_registers_offset++;
1216314564Sdim          break;
1217278332Semaste        }
1218314564Sdim      }
1219278332Semaste    }
1220314564Sdim
1221314564Sdim    unwind_plan.AppendRow(row);
1222314564Sdim    return true;
1223314564Sdim  } break;
1224314564Sdim
1225314564Sdim  case UNWIND_X86_MODE_DWARF: {
1226278332Semaste    return false;
1227314564Sdim  } break;
1228314564Sdim  }
1229314564Sdim  return false;
1230278332Semaste}
1231309124Sdim
1232314564Sdim// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1233314564Sdim// doc by ARM
1234309124Sdim
1235309124Sdimenum arm64_eh_regnum {
1236314564Sdim  x19 = 19,
1237314564Sdim  x20 = 20,
1238314564Sdim  x21 = 21,
1239314564Sdim  x22 = 22,
1240314564Sdim  x23 = 23,
1241314564Sdim  x24 = 24,
1242314564Sdim  x25 = 25,
1243314564Sdim  x26 = 26,
1244314564Sdim  x27 = 27,
1245314564Sdim  x28 = 28,
1246309124Sdim
1247314564Sdim  fp = 29,
1248314564Sdim  ra = 30,
1249314564Sdim  sp = 31,
1250314564Sdim  pc = 32,
1251309124Sdim
1252314564Sdim  // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
1253341825Sdim  // for the 64-bit fp regs.  Normally in DWARF it's context sensitive - so it
1254341825Sdim  // knows it is fetching a 32- or 64-bit quantity from reg v8 to indicate s0
1255341825Sdim  // or d0 - but the unwinder is operating at a lower level and we'd try to
1256341825Sdim  // fetch 128 bits if we were told that v8 were stored on the stack...
1257314564Sdim  v8 = 72,
1258314564Sdim  v9 = 73,
1259314564Sdim  v10 = 74,
1260314564Sdim  v11 = 75,
1261314564Sdim  v12 = 76,
1262314564Sdim  v13 = 77,
1263314564Sdim  v14 = 78,
1264314564Sdim  v15 = 79,
1265309124Sdim};
1266309124Sdim
1267309124Sdimenum arm_eh_regnum {
1268314564Sdim  arm_r0 = 0,
1269314564Sdim  arm_r1 = 1,
1270314564Sdim  arm_r2 = 2,
1271314564Sdim  arm_r3 = 3,
1272314564Sdim  arm_r4 = 4,
1273314564Sdim  arm_r5 = 5,
1274314564Sdim  arm_r6 = 6,
1275314564Sdim  arm_r7 = 7,
1276314564Sdim  arm_r8 = 8,
1277314564Sdim  arm_r9 = 9,
1278314564Sdim  arm_r10 = 10,
1279314564Sdim  arm_r11 = 11,
1280314564Sdim  arm_r12 = 12,
1281309124Sdim
1282314564Sdim  arm_sp = 13,
1283314564Sdim  arm_lr = 14,
1284314564Sdim  arm_pc = 15,
1285309124Sdim
1286314564Sdim  arm_d0 = 256,
1287314564Sdim  arm_d1 = 257,
1288314564Sdim  arm_d2 = 258,
1289314564Sdim  arm_d3 = 259,
1290314564Sdim  arm_d4 = 260,
1291314564Sdim  arm_d5 = 261,
1292314564Sdim  arm_d6 = 262,
1293314564Sdim  arm_d7 = 263,
1294314564Sdim  arm_d8 = 264,
1295314564Sdim  arm_d9 = 265,
1296314564Sdim  arm_d10 = 266,
1297314564Sdim  arm_d11 = 267,
1298314564Sdim  arm_d12 = 268,
1299314564Sdim  arm_d13 = 269,
1300314564Sdim  arm_d14 = 270,
1301309124Sdim};
1302309124Sdim
1303314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
1304314564Sdim                                               FunctionInfo &function_info,
1305314564Sdim                                               UnwindPlan &unwind_plan,
1306314564Sdim                                               Address pc_or_function_start) {
1307314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1308314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1309314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1310360784Sdim  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1311314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1312309124Sdim
1313314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1314314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1315309124Sdim
1316314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1317309124Sdim
1318314564Sdim  const int wordsize = 8;
1319314564Sdim  int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
1320309124Sdim
1321314564Sdim  if (mode == UNWIND_ARM64_MODE_DWARF)
1322314564Sdim    return false;
1323309124Sdim
1324314564Sdim  if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1325314564Sdim    row->SetOffset(0);
1326309124Sdim
1327314564Sdim    uint32_t stack_size =
1328314564Sdim        (EXTRACT_BITS(function_info.encoding,
1329314564Sdim                      UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1330314564Sdim        16;
1331309124Sdim
1332314564Sdim    // Our previous Call Frame Address is the stack pointer plus the stack size
1333314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
1334309124Sdim
1335314564Sdim    // Our previous PC is in the LR
1336314564Sdim    row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1337314564Sdim                                       true);
1338309124Sdim
1339314564Sdim    unwind_plan.AppendRow(row);
1340314564Sdim    return true;
1341314564Sdim  }
1342309124Sdim
1343314564Sdim  // Should not be possible
1344314564Sdim  if (mode != UNWIND_ARM64_MODE_FRAME)
1345314564Sdim    return false;
1346309124Sdim
1347314564Sdim  // mode == UNWIND_ARM64_MODE_FRAME
1348309124Sdim
1349314564Sdim  row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1350314564Sdim  row->SetOffset(0);
1351314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1352314564Sdim                                            true);
1353314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1354314564Sdim                                            true);
1355314564Sdim  row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1356309124Sdim
1357314564Sdim  int reg_pairs_saved_count = 1;
1358309124Sdim
1359314564Sdim  uint32_t saved_register_bits = function_info.encoding & 0xfff;
1360309124Sdim
1361314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
1362314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1363314564Sdim    cfa_offset -= wordsize;
1364314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,
1365314564Sdim                                              true);
1366314564Sdim    cfa_offset -= wordsize;
1367314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1368314564Sdim                                              true);
1369314564Sdim    reg_pairs_saved_count++;
1370314564Sdim  }
1371309124Sdim
1372314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
1373314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1374314564Sdim    cfa_offset -= wordsize;
1375314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,
1376314564Sdim                                              true);
1377314564Sdim    cfa_offset -= wordsize;
1378314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1379314564Sdim                                              true);
1380314564Sdim    reg_pairs_saved_count++;
1381314564Sdim  }
1382309124Sdim
1383314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
1384314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1385314564Sdim    cfa_offset -= wordsize;
1386314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,
1387314564Sdim                                              true);
1388314564Sdim    cfa_offset -= wordsize;
1389314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1390314564Sdim                                              true);
1391314564Sdim    reg_pairs_saved_count++;
1392314564Sdim  }
1393309124Sdim
1394314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
1395314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1396314564Sdim    cfa_offset -= wordsize;
1397314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,
1398314564Sdim                                              true);
1399314564Sdim    cfa_offset -= wordsize;
1400314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1401314564Sdim                                              true);
1402314564Sdim    reg_pairs_saved_count++;
1403314564Sdim  }
1404309124Sdim
1405314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
1406314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1407314564Sdim    cfa_offset -= wordsize;
1408314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,
1409314564Sdim                                              true);
1410314564Sdim    cfa_offset -= wordsize;
1411314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1412314564Sdim                                              true);
1413314564Sdim    reg_pairs_saved_count++;
1414314564Sdim  }
1415309124Sdim
1416314564Sdim  // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1417314564Sdim  // off the stack;
1418314564Sdim  // not sure if we have a good way to represent the 64-bitness of these saves.
1419309124Sdim
1420314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1421314564Sdim    reg_pairs_saved_count++;
1422314564Sdim  }
1423314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1424314564Sdim    reg_pairs_saved_count++;
1425314564Sdim  }
1426314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1427314564Sdim    reg_pairs_saved_count++;
1428314564Sdim  }
1429314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1430314564Sdim    reg_pairs_saved_count++;
1431314564Sdim  }
1432309124Sdim
1433314564Sdim  unwind_plan.AppendRow(row);
1434314564Sdim  return true;
1435309124Sdim}
1436309124Sdim
1437314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
1438314564Sdim                                               FunctionInfo &function_info,
1439314564Sdim                                               UnwindPlan &unwind_plan,
1440314564Sdim                                               Address pc_or_function_start) {
1441314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1442314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1443314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1444360784Sdim  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1445314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1446309124Sdim
1447314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1448314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1449309124Sdim
1450314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1451309124Sdim
1452314564Sdim  const int wordsize = 4;
1453314564Sdim  int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
1454309124Sdim
1455314564Sdim  if (mode == UNWIND_ARM_MODE_DWARF)
1456314564Sdim    return false;
1457309124Sdim
1458314564Sdim  uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1459314564Sdim                                        UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1460314564Sdim                          wordsize;
1461309124Sdim
1462314564Sdim  row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1463314564Sdim                                             (2 * wordsize) + stack_adjust);
1464314564Sdim  row->SetOffset(0);
1465314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(
1466314564Sdim      arm_r7, (wordsize * -2) - stack_adjust, true);
1467314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(
1468314564Sdim      arm_pc, (wordsize * -1) - stack_adjust, true);
1469314564Sdim  row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);
1470309124Sdim
1471314564Sdim  int cfa_offset = -stack_adjust - (2 * wordsize);
1472309124Sdim
1473314564Sdim  uint32_t saved_register_bits = function_info.encoding & 0xff;
1474309124Sdim
1475314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1476314564Sdim    cfa_offset -= wordsize;
1477314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1478314564Sdim  }
1479309124Sdim
1480314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1481314564Sdim    cfa_offset -= wordsize;
1482314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1483314564Sdim  }
1484309124Sdim
1485314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1486314564Sdim    cfa_offset -= wordsize;
1487314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1488314564Sdim  }
1489309124Sdim
1490314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1491314564Sdim    cfa_offset -= wordsize;
1492314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1493314564Sdim  }
1494309124Sdim
1495314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1496314564Sdim    cfa_offset -= wordsize;
1497314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1498314564Sdim  }
1499309124Sdim
1500314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1501314564Sdim    cfa_offset -= wordsize;
1502314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1503314564Sdim  }
1504309124Sdim
1505314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1506314564Sdim    cfa_offset -= wordsize;
1507314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1508314564Sdim  }
1509309124Sdim
1510314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1511314564Sdim    cfa_offset -= wordsize;
1512314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
1513314564Sdim  }
1514309124Sdim
1515314564Sdim  if (mode == UNWIND_ARM_MODE_FRAME_D) {
1516314564Sdim    uint32_t d_reg_bits =
1517314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1518314564Sdim    switch (d_reg_bits) {
1519314564Sdim    case 0:
1520314564Sdim      // vpush {d8}
1521314564Sdim      cfa_offset -= 8;
1522314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1523314564Sdim      break;
1524314564Sdim    case 1:
1525314564Sdim      // vpush {d10}
1526314564Sdim      // vpush {d8}
1527314564Sdim      cfa_offset -= 8;
1528314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1529314564Sdim      cfa_offset -= 8;
1530314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1531314564Sdim      break;
1532314564Sdim    case 2:
1533314564Sdim      // vpush {d12}
1534314564Sdim      // vpush {d10}
1535314564Sdim      // vpush {d8}
1536314564Sdim      cfa_offset -= 8;
1537314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1538314564Sdim      cfa_offset -= 8;
1539314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1540314564Sdim      cfa_offset -= 8;
1541314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1542314564Sdim      break;
1543314564Sdim    case 3:
1544314564Sdim      // vpush {d14}
1545314564Sdim      // vpush {d12}
1546314564Sdim      // vpush {d10}
1547314564Sdim      // vpush {d8}
1548314564Sdim      cfa_offset -= 8;
1549314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1550314564Sdim      cfa_offset -= 8;
1551314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1552314564Sdim      cfa_offset -= 8;
1553314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1554314564Sdim      cfa_offset -= 8;
1555314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1556314564Sdim      break;
1557314564Sdim    case 4:
1558314564Sdim      // vpush {d14}
1559314564Sdim      // vpush {d12}
1560314564Sdim      // sp = (sp - 24) & (-16);
1561314564Sdim      // vst   {d8, d9, d10}
1562314564Sdim      cfa_offset -= 8;
1563314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1564314564Sdim      cfa_offset -= 8;
1565314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1566309124Sdim
1567314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1568314564Sdim      // alignment short of
1569314564Sdim      // coming up with some DWARF location description.
1570309124Sdim
1571314564Sdim      break;
1572314564Sdim    case 5:
1573314564Sdim      // vpush {d14}
1574314564Sdim      // sp = (sp - 40) & (-16);
1575314564Sdim      // vst   {d8, d9, d10, d11}
1576314564Sdim      // vst   {d12}
1577309124Sdim
1578314564Sdim      cfa_offset -= 8;
1579314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1580309124Sdim
1581314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1582314564Sdim      // alignment short of
1583314564Sdim      // coming up with some DWARF location description.
1584309124Sdim
1585314564Sdim      break;
1586314564Sdim    case 6:
1587314564Sdim      // sp = (sp - 56) & (-16);
1588314564Sdim      // vst   {d8, d9, d10, d11}
1589314564Sdim      // vst   {d12, d13, d14}
1590309124Sdim
1591314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1592314564Sdim      // alignment short of
1593314564Sdim      // coming up with some DWARF location description.
1594309124Sdim
1595314564Sdim      break;
1596314564Sdim    case 7:
1597314564Sdim      // sp = (sp - 64) & (-16);
1598314564Sdim      // vst   {d8, d9, d10, d11}
1599314564Sdim      // vst   {d12, d13, d14, d15}
1600309124Sdim
1601314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1602314564Sdim      // alignment short of
1603314564Sdim      // coming up with some DWARF location description.
1604309124Sdim
1605314564Sdim      break;
1606309124Sdim    }
1607314564Sdim  }
1608309124Sdim
1609314564Sdim  unwind_plan.AppendRow(row);
1610314564Sdim  return true;
1611309124Sdim}
1612