CompactUnwindInfo.cpp revision 353358
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());
193314564Sdim        log->Printf("Got compact unwind encoding 0x%x for function %s",
194314564Sdim                    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      }
216314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::aarch64) {
217314564Sdim        return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
218314564Sdim      }
219314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::x86) {
220314564Sdim        return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
221314564Sdim      }
222314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::arm ||
223314564Sdim          arch.GetTriple().getArch() == llvm::Triple::thumb) {
224314564Sdim        return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);
225314564Sdim      }
226278332Semaste    }
227314564Sdim  }
228314564Sdim  return false;
229278332Semaste}
230278332Semaste
231314564Sdimbool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
232314564Sdim  if (m_section_sp.get() == nullptr)
233314564Sdim    return false;
234278332Semaste
235314564Sdim  if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
236314564Sdim    return true;
237278332Semaste
238314564Sdim  ScanIndex(process_sp);
239278332Semaste
240314564Sdim  return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
241278332Semaste}
242278332Semaste
243314564Sdimvoid CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
244314564Sdim  std::lock_guard<std::mutex> guard(m_mutex);
245314564Sdim  if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
246314564Sdim    return;
247278332Semaste
248314564Sdim  // We can't read the index for some reason.
249314564Sdim  if (m_indexes_computed == eLazyBoolNo) {
250314564Sdim    return;
251314564Sdim  }
252278332Semaste
253314564Sdim  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
254314564Sdim  if (log)
255314564Sdim    m_objfile.GetModule()->LogMessage(
256314564Sdim        log, "Reading compact unwind first-level indexes");
257278332Semaste
258344779Sdim  if (!m_unwindinfo_data_computed) {
259314564Sdim    if (m_section_sp->IsEncrypted()) {
260314564Sdim      // Can't get section contents of a protected/encrypted section until we
261341825Sdim      // have a live process and can read them out of memory.
262314564Sdim      if (process_sp.get() == nullptr)
263314564Sdim        return;
264353358Sdim      m_section_contents_if_encrypted =
265353358Sdim          std::make_shared<DataBufferHeap>(m_section_sp->GetByteSize(), 0);
266321369Sdim      Status error;
267314564Sdim      if (process_sp->ReadMemory(
268314564Sdim              m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
269314564Sdim              m_section_contents_if_encrypted->GetBytes(),
270314564Sdim              m_section_sp->GetByteSize(),
271314564Sdim              error) == m_section_sp->GetByteSize() &&
272314564Sdim          error.Success()) {
273314564Sdim        m_unwindinfo_data.SetAddressByteSize(
274314564Sdim            process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
275314564Sdim        m_unwindinfo_data.SetByteOrder(
276314564Sdim            process_sp->GetTarget().GetArchitecture().GetByteOrder());
277314564Sdim        m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);
278314564Sdim      }
279314564Sdim    } else {
280314564Sdim      m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
281278332Semaste    }
282314564Sdim    if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
283314564Sdim      return;
284314564Sdim    m_unwindinfo_data_computed = true;
285314564Sdim  }
286278332Semaste
287314564Sdim  if (m_unwindinfo_data.GetByteSize() > 0) {
288314564Sdim    offset_t offset = 0;
289278332Semaste
290314564Sdim    // struct unwind_info_section_header
291314564Sdim    // {
292314564Sdim    // uint32_t    version;            // UNWIND_SECTION_VERSION
293314564Sdim    // uint32_t    commonEncodingsArraySectionOffset;
294314564Sdim    // uint32_t    commonEncodingsArrayCount;
295314564Sdim    // uint32_t    personalityArraySectionOffset;
296314564Sdim    // uint32_t    personalityArrayCount;
297314564Sdim    // uint32_t    indexSectionOffset;
298314564Sdim    // uint32_t    indexCount;
299309124Sdim
300314564Sdim    m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
301314564Sdim    m_unwind_header.common_encodings_array_offset =
302314564Sdim        m_unwindinfo_data.GetU32(&offset);
303314564Sdim    m_unwind_header.common_encodings_array_count =
304314564Sdim        m_unwindinfo_data.GetU32(&offset);
305314564Sdim    m_unwind_header.personality_array_offset =
306314564Sdim        m_unwindinfo_data.GetU32(&offset);
307314564Sdim    m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
308314564Sdim    uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
309278332Semaste
310314564Sdim    uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
311278332Semaste
312314564Sdim    if (m_unwind_header.common_encodings_array_offset >
313314564Sdim            m_unwindinfo_data.GetByteSize() ||
314314564Sdim        m_unwind_header.personality_array_offset >
315314564Sdim            m_unwindinfo_data.GetByteSize() ||
316314564Sdim        indexSectionOffset > m_unwindinfo_data.GetByteSize() ||
317314564Sdim        offset > m_unwindinfo_data.GetByteSize()) {
318314564Sdim      Host::SystemLog(Host::eSystemLogError, "error: Invalid offset "
319314564Sdim                                             "encountered in compact unwind "
320314564Sdim                                             "info, skipping\n");
321314564Sdim      // don't trust anything from this compact_unwind section if it looks
322314564Sdim      // blatantly invalid data in the header.
323314564Sdim      m_indexes_computed = eLazyBoolNo;
324314564Sdim      return;
325314564Sdim    }
326278332Semaste
327341825Sdim    // Parse the basic information from the indexes We wait to scan the second
328341825Sdim    // level page info until it's needed
329278332Semaste
330341825Sdim    // struct unwind_info_section_header_index_entry {
331314564Sdim    //     uint32_t        functionOffset;
332314564Sdim    //     uint32_t        secondLevelPagesSectionOffset;
333314564Sdim    //     uint32_t        lsdaIndexArraySectionOffset;
334314564Sdim    // };
335278332Semaste
336314564Sdim    bool clear_address_zeroth_bit = false;
337344779Sdim    if (ArchSpec arch = m_objfile.GetArchitecture()) {
338314564Sdim      if (arch.GetTriple().getArch() == llvm::Triple::arm ||
339314564Sdim          arch.GetTriple().getArch() == llvm::Triple::thumb)
340314564Sdim        clear_address_zeroth_bit = true;
341314564Sdim    }
342309124Sdim
343314564Sdim    offset = indexSectionOffset;
344314564Sdim    for (uint32_t idx = 0; idx < indexCount; idx++) {
345314564Sdim      uint32_t function_offset =
346314564Sdim          m_unwindinfo_data.GetU32(&offset); // functionOffset
347314564Sdim      uint32_t second_level_offset =
348314564Sdim          m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
349314564Sdim      uint32_t lsda_offset =
350314564Sdim          m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
351278332Semaste
352314564Sdim      if (second_level_offset > m_section_sp->GetByteSize() ||
353314564Sdim          lsda_offset > m_section_sp->GetByteSize()) {
354314564Sdim        m_indexes_computed = eLazyBoolNo;
355314564Sdim      }
356278332Semaste
357314564Sdim      if (clear_address_zeroth_bit)
358314564Sdim        function_offset &= ~1ull;
359309124Sdim
360314564Sdim      UnwindIndex this_index;
361314564Sdim      this_index.function_offset = function_offset;
362314564Sdim      this_index.second_level = second_level_offset;
363314564Sdim      this_index.lsda_array_start = lsda_offset;
364278332Semaste
365314564Sdim      if (m_indexes.size() > 0) {
366314564Sdim        m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
367314564Sdim      }
368278332Semaste
369314564Sdim      if (second_level_offset == 0) {
370314564Sdim        this_index.sentinal_entry = true;
371314564Sdim      }
372278332Semaste
373314564Sdim      m_indexes.push_back(this_index);
374278332Semaste    }
375314564Sdim    m_indexes_computed = eLazyBoolYes;
376314564Sdim  } else {
377314564Sdim    m_indexes_computed = eLazyBoolNo;
378314564Sdim  }
379278332Semaste}
380278332Semaste
381314564Sdimuint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
382314564Sdim                                                     uint32_t lsda_count,
383314564Sdim                                                     uint32_t function_offset) {
384341825Sdim  // struct unwind_info_section_header_lsda_index_entry {
385314564Sdim  //         uint32_t        functionOffset;
386314564Sdim  //         uint32_t        lsdaOffset;
387314564Sdim  // };
388278332Semaste
389314564Sdim  offset_t first_entry = lsda_offset;
390314564Sdim  uint32_t low = 0;
391314564Sdim  uint32_t high = lsda_count;
392314564Sdim  while (low < high) {
393314564Sdim    uint32_t mid = (low + high) / 2;
394314564Sdim    offset_t offset = first_entry + (mid * 8);
395314564Sdim    uint32_t mid_func_offset =
396314564Sdim        m_unwindinfo_data.GetU32(&offset); // functionOffset
397314564Sdim    uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
398314564Sdim    if (mid_func_offset == function_offset) {
399314564Sdim      return mid_lsda_offset;
400278332Semaste    }
401314564Sdim    if (mid_func_offset < function_offset) {
402314564Sdim      low = mid + 1;
403314564Sdim    } else {
404314564Sdim      high = mid;
405314564Sdim    }
406314564Sdim  }
407314564Sdim  return 0;
408278332Semaste}
409278332Semaste
410314564Sdimlldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(
411314564Sdim    uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,
412314564Sdim    uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
413314564Sdim  // typedef uint32_t compact_unwind_encoding_t;
414341825Sdim  // struct unwind_info_regular_second_level_entry {
415314564Sdim  //     uint32_t                    functionOffset;
416314564Sdim  //     compact_unwind_encoding_t    encoding;
417278332Semaste
418314564Sdim  offset_t first_entry = entry_page_offset;
419278332Semaste
420314564Sdim  uint32_t low = 0;
421314564Sdim  uint32_t high = entry_count;
422314564Sdim  uint32_t last = high - 1;
423314564Sdim  while (low < high) {
424314564Sdim    uint32_t mid = (low + high) / 2;
425314564Sdim    offset_t offset = first_entry + (mid * 8);
426314564Sdim    uint32_t mid_func_offset =
427314564Sdim        m_unwindinfo_data.GetU32(&offset); // functionOffset
428314564Sdim    uint32_t next_func_offset = 0;
429314564Sdim    if (mid < last) {
430314564Sdim      offset = first_entry + ((mid + 1) * 8);
431314564Sdim      next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
432278332Semaste    }
433314564Sdim    if (mid_func_offset <= function_offset) {
434314564Sdim      if (mid == last || (next_func_offset > function_offset)) {
435314564Sdim        if (entry_func_start_offset)
436314564Sdim          *entry_func_start_offset = mid_func_offset;
437314564Sdim        if (mid != last && entry_func_end_offset)
438314564Sdim          *entry_func_end_offset = next_func_offset;
439314564Sdim        return first_entry + (mid * 8);
440314564Sdim      } else {
441314564Sdim        low = mid + 1;
442314564Sdim      }
443314564Sdim    } else {
444314564Sdim      high = mid;
445314564Sdim    }
446314564Sdim  }
447314564Sdim  return LLDB_INVALID_OFFSET;
448278332Semaste}
449278332Semaste
450314564Sdimuint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(
451314564Sdim    uint32_t entry_page_offset, uint32_t entry_count,
452314564Sdim    uint32_t function_offset_to_find, uint32_t function_offset_base,
453314564Sdim    uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
454314564Sdim  offset_t first_entry = entry_page_offset;
455278332Semaste
456314564Sdim  uint32_t low = 0;
457314564Sdim  uint32_t high = entry_count;
458314564Sdim  uint32_t last = high - 1;
459314564Sdim  while (low < high) {
460314564Sdim    uint32_t mid = (low + high) / 2;
461314564Sdim    offset_t offset = first_entry + (mid * 4);
462314564Sdim    uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
463314564Sdim    uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
464314564Sdim    mid_func_offset += function_offset_base;
465314564Sdim    uint32_t next_func_offset = 0;
466314564Sdim    if (mid < last) {
467314564Sdim      offset = first_entry + ((mid + 1) * 4);
468314564Sdim      uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
469314564Sdim      next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);
470314564Sdim      next_func_offset += function_offset_base;
471278332Semaste    }
472314564Sdim    if (mid_func_offset <= function_offset_to_find) {
473314564Sdim      if (mid == last || (next_func_offset > function_offset_to_find)) {
474314564Sdim        if (entry_func_start_offset)
475314564Sdim          *entry_func_start_offset = mid_func_offset;
476314564Sdim        if (mid != last && entry_func_end_offset)
477314564Sdim          *entry_func_end_offset = next_func_offset;
478314564Sdim        return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
479314564Sdim      } else {
480314564Sdim        low = mid + 1;
481314564Sdim      }
482314564Sdim    } else {
483314564Sdim      high = mid;
484314564Sdim    }
485314564Sdim  }
486278332Semaste
487314564Sdim  return UINT32_MAX;
488278332Semaste}
489278332Semaste
490314564Sdimbool CompactUnwindInfo::GetCompactUnwindInfoForFunction(
491314564Sdim    Target &target, Address address, FunctionInfo &unwind_info) {
492314564Sdim  unwind_info.encoding = 0;
493314564Sdim  unwind_info.lsda_address.Clear();
494314564Sdim  unwind_info.personality_ptr_address.Clear();
495278332Semaste
496314564Sdim  if (!IsValid(target.GetProcessSP()))
497314564Sdim    return false;
498278332Semaste
499314564Sdim  addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
500314564Sdim  SectionList *sl = m_objfile.GetSectionList();
501314564Sdim  if (sl) {
502314564Sdim    SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
503314564Sdim    if (text_sect.get()) {
504314564Sdim      text_section_file_address = text_sect->GetFileAddress();
505278332Semaste    }
506314564Sdim  }
507314564Sdim  if (text_section_file_address == LLDB_INVALID_ADDRESS)
508314564Sdim    return false;
509278332Semaste
510314564Sdim  addr_t function_offset =
511344779Sdim      address.GetFileAddress() - m_objfile.GetBaseAddress().GetFileAddress();
512309124Sdim
513314564Sdim  UnwindIndex key;
514314564Sdim  key.function_offset = function_offset;
515309124Sdim
516314564Sdim  std::vector<UnwindIndex>::const_iterator it;
517314564Sdim  it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key);
518314564Sdim  if (it == m_indexes.end()) {
519314564Sdim    return false;
520314564Sdim  }
521278332Semaste
522314564Sdim  if (it->function_offset != key.function_offset) {
523314564Sdim    if (it != m_indexes.begin())
524314564Sdim      --it;
525314564Sdim  }
526278332Semaste
527344779Sdim  if (it->sentinal_entry) {
528314564Sdim    return false;
529314564Sdim  }
530278332Semaste
531314564Sdim  auto next_it = it + 1;
532314564Sdim  if (next_it != m_indexes.end()) {
533341825Sdim    // initialize the function offset end range to be the start of the next
534341825Sdim    // index offset.  If we find an entry which is at the end of the index
535341825Sdim    // table, this will establish the range end.
536314564Sdim    unwind_info.valid_range_offset_end = next_it->function_offset;
537314564Sdim  }
538278332Semaste
539314564Sdim  offset_t second_page_offset = it->second_level;
540314564Sdim  offset_t lsda_array_start = it->lsda_array_start;
541314564Sdim  offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
542278332Semaste
543314564Sdim  offset_t offset = second_page_offset;
544314564Sdim  uint32_t kind = m_unwindinfo_data.GetU32(
545314564Sdim      &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
546278332Semaste
547314564Sdim  if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
548341825Sdim    // struct unwind_info_regular_second_level_page_header {
549314564Sdim    //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_REGULAR
550314564Sdim    //     uint16_t    entryPageOffset;
551314564Sdim    //     uint16_t    entryCount;
552278332Semaste
553314564Sdim    // typedef uint32_t compact_unwind_encoding_t;
554341825Sdim    // struct unwind_info_regular_second_level_entry {
555314564Sdim    //     uint32_t                    functionOffset;
556314564Sdim    //     compact_unwind_encoding_t    encoding;
557278332Semaste
558314564Sdim    uint16_t entry_page_offset =
559314564Sdim        m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
560314564Sdim    uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
561278332Semaste
562314564Sdim    offset_t entry_offset = BinarySearchRegularSecondPage(
563314564Sdim        second_page_offset + entry_page_offset, entry_count, function_offset,
564314564Sdim        &unwind_info.valid_range_offset_start,
565314564Sdim        &unwind_info.valid_range_offset_end);
566314564Sdim    if (entry_offset == LLDB_INVALID_OFFSET) {
567314564Sdim      return false;
568314564Sdim    }
569314564Sdim    entry_offset += 4; // skip over functionOffset
570314564Sdim    unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
571314564Sdim    if (unwind_info.encoding & UNWIND_HAS_LSDA) {
572314564Sdim      SectionList *sl = m_objfile.GetSectionList();
573314564Sdim      if (sl) {
574314564Sdim        uint32_t lsda_offset = GetLSDAForFunctionOffset(
575314564Sdim            lsda_array_start, lsda_array_count, function_offset);
576344779Sdim        addr_t objfile_base_address =
577344779Sdim            m_objfile.GetBaseAddress().GetFileAddress();
578314564Sdim        unwind_info.lsda_address.ResolveAddressUsingFileSections(
579344779Sdim            objfile_base_address + lsda_offset, sl);
580314564Sdim      }
581314564Sdim    }
582314564Sdim    if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
583314564Sdim      uint32_t personality_index =
584314564Sdim          EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
585278332Semaste
586314564Sdim      if (personality_index > 0) {
587314564Sdim        personality_index--;
588314564Sdim        if (personality_index < m_unwind_header.personality_array_count) {
589314564Sdim          offset_t offset = m_unwind_header.personality_array_offset;
590314564Sdim          offset += 4 * personality_index;
591314564Sdim          SectionList *sl = m_objfile.GetSectionList();
592314564Sdim          if (sl) {
593314564Sdim            uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
594344779Sdim            addr_t objfile_base_address =
595344779Sdim                m_objfile.GetBaseAddress().GetFileAddress();
596314564Sdim            unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
597344779Sdim                objfile_base_address + personality_offset, sl);
598314564Sdim          }
599278332Semaste        }
600314564Sdim      }
601278332Semaste    }
602314564Sdim    return true;
603314564Sdim  } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
604341825Sdim    // struct unwind_info_compressed_second_level_page_header {
605314564Sdim    //     uint32_t    kind;    // UNWIND_SECOND_LEVEL_COMPRESSED
606314564Sdim    //     uint16_t    entryPageOffset;         // offset from this 2nd lvl page
607314564Sdim    //     idx to array of entries
608314564Sdim    //                                          // (an entry has a function
609314564Sdim    //                                          offset and index into the
610314564Sdim    //                                          encodings)
611314564Sdim    //                                          // NB function offset from the
612314564Sdim    //                                          entry in the compressed page
613314564Sdim    //                                          // must be added to the index's
614314564Sdim    //                                          functionOffset value.
615314564Sdim    //     uint16_t    entryCount;
616314564Sdim    //     uint16_t    encodingsPageOffset;     // offset from this 2nd lvl page
617314564Sdim    //     idx to array of encodings
618314564Sdim    //     uint16_t    encodingsCount;
619278332Semaste
620314564Sdim    uint16_t entry_page_offset =
621314564Sdim        m_unwindinfo_data.GetU16(&offset);                    // entryPageOffset
622314564Sdim    uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
623314564Sdim    uint16_t encodings_page_offset =
624314564Sdim        m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
625314564Sdim    uint16_t encodings_count =
626314564Sdim        m_unwindinfo_data.GetU16(&offset); // encodingsCount
627278332Semaste
628314564Sdim    uint32_t encoding_index = BinarySearchCompressedSecondPage(
629314564Sdim        second_page_offset + entry_page_offset, entry_count, function_offset,
630314564Sdim        it->function_offset, &unwind_info.valid_range_offset_start,
631314564Sdim        &unwind_info.valid_range_offset_end);
632314564Sdim    if (encoding_index == UINT32_MAX ||
633314564Sdim        encoding_index >=
634314564Sdim            encodings_count + m_unwind_header.common_encodings_array_count) {
635314564Sdim      return false;
636314564Sdim    }
637314564Sdim    uint32_t encoding = 0;
638314564Sdim    if (encoding_index < m_unwind_header.common_encodings_array_count) {
639314564Sdim      offset = m_unwind_header.common_encodings_array_offset +
640314564Sdim               (encoding_index * sizeof(uint32_t));
641314564Sdim      encoding = m_unwindinfo_data.GetU32(
642314564Sdim          &offset); // encoding entry from the commonEncodingsArray
643314564Sdim    } else {
644314564Sdim      uint32_t page_specific_entry_index =
645314564Sdim          encoding_index - m_unwind_header.common_encodings_array_count;
646314564Sdim      offset = second_page_offset + encodings_page_offset +
647314564Sdim               (page_specific_entry_index * sizeof(uint32_t));
648314564Sdim      encoding = m_unwindinfo_data.GetU32(
649314564Sdim          &offset); // encoding entry from the page-specific encoding array
650314564Sdim    }
651314564Sdim    if (encoding == 0)
652314564Sdim      return false;
653278332Semaste
654314564Sdim    unwind_info.encoding = encoding;
655314564Sdim    if (unwind_info.encoding & UNWIND_HAS_LSDA) {
656314564Sdim      SectionList *sl = m_objfile.GetSectionList();
657314564Sdim      if (sl) {
658314564Sdim        uint32_t lsda_offset = GetLSDAForFunctionOffset(
659314564Sdim            lsda_array_start, lsda_array_count, function_offset);
660344779Sdim        addr_t objfile_base_address =
661344779Sdim            m_objfile.GetBaseAddress().GetFileAddress();
662314564Sdim        unwind_info.lsda_address.ResolveAddressUsingFileSections(
663344779Sdim            objfile_base_address + lsda_offset, sl);
664314564Sdim      }
665314564Sdim    }
666314564Sdim    if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
667314564Sdim      uint32_t personality_index =
668314564Sdim          EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
669278332Semaste
670314564Sdim      if (personality_index > 0) {
671314564Sdim        personality_index--;
672314564Sdim        if (personality_index < m_unwind_header.personality_array_count) {
673314564Sdim          offset_t offset = m_unwind_header.personality_array_offset;
674314564Sdim          offset += 4 * personality_index;
675314564Sdim          SectionList *sl = m_objfile.GetSectionList();
676314564Sdim          if (sl) {
677314564Sdim            uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
678344779Sdim            addr_t objfile_base_address =
679344779Sdim                m_objfile.GetBaseAddress().GetFileAddress();
680314564Sdim            unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
681344779Sdim                objfile_base_address + personality_offset, sl);
682314564Sdim          }
683278332Semaste        }
684314564Sdim      }
685278332Semaste    }
686314564Sdim    return true;
687314564Sdim  }
688314564Sdim  return false;
689278332Semaste}
690278332Semaste
691278332Semasteenum x86_64_eh_regnum {
692314564Sdim  rax = 0,
693314564Sdim  rdx = 1,
694314564Sdim  rcx = 2,
695314564Sdim  rbx = 3,
696314564Sdim  rsi = 4,
697314564Sdim  rdi = 5,
698314564Sdim  rbp = 6,
699314564Sdim  rsp = 7,
700314564Sdim  r8 = 8,
701314564Sdim  r9 = 9,
702314564Sdim  r10 = 10,
703314564Sdim  r11 = 11,
704314564Sdim  r12 = 12,
705314564Sdim  r13 = 13,
706314564Sdim  r14 = 14,
707314564Sdim  r15 = 15,
708314564Sdim  rip = 16 // this is officially the Return Address register number, but close
709314564Sdim           // enough
710278332Semaste};
711278332Semaste
712341825Sdim// Convert the compact_unwind_info.h register numbering scheme to
713341825Sdim// eRegisterKindEHFrame (eh_frame) register numbering scheme.
714314564Sdimuint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {
715314564Sdim  switch (unwind_regno) {
716314564Sdim  case UNWIND_X86_64_REG_RBX:
717314564Sdim    return x86_64_eh_regnum::rbx;
718314564Sdim  case UNWIND_X86_64_REG_R12:
719314564Sdim    return x86_64_eh_regnum::r12;
720314564Sdim  case UNWIND_X86_64_REG_R13:
721314564Sdim    return x86_64_eh_regnum::r13;
722314564Sdim  case UNWIND_X86_64_REG_R14:
723314564Sdim    return x86_64_eh_regnum::r14;
724314564Sdim  case UNWIND_X86_64_REG_R15:
725314564Sdim    return x86_64_eh_regnum::r15;
726314564Sdim  case UNWIND_X86_64_REG_RBP:
727314564Sdim    return x86_64_eh_regnum::rbp;
728314564Sdim  default:
729314564Sdim    return LLDB_INVALID_REGNUM;
730314564Sdim  }
731278332Semaste}
732278332Semaste
733314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
734314564Sdim                                                FunctionInfo &function_info,
735314564Sdim                                                UnwindPlan &unwind_plan,
736314564Sdim                                                Address pc_or_function_start) {
737314564Sdim  unwind_plan.SetSourceName("compact unwind info");
738314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
739314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
740314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
741278332Semaste
742314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
743314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
744278332Semaste
745314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
746278332Semaste
747314564Sdim  const int wordsize = 8;
748314564Sdim  int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
749314564Sdim  switch (mode) {
750314564Sdim  case UNWIND_X86_64_MODE_RBP_FRAME: {
751314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(
752314564Sdim        translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),
753314564Sdim        2 * wordsize);
754314564Sdim    row->SetOffset(0);
755314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,
756314564Sdim                                              wordsize * -2, true);
757314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
758314564Sdim                                              wordsize * -1, true);
759314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
760309124Sdim
761314564Sdim    uint32_t saved_registers_offset =
762314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
763278332Semaste
764314564Sdim    uint32_t saved_registers_locations =
765314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
766278332Semaste
767314564Sdim    saved_registers_offset += 2;
768278332Semaste
769314564Sdim    for (int i = 0; i < 5; i++) {
770314564Sdim      uint32_t regnum = saved_registers_locations & 0x7;
771314564Sdim      switch (regnum) {
772314564Sdim      case UNWIND_X86_64_REG_NONE:
773278332Semaste        break;
774314564Sdim      case UNWIND_X86_64_REG_RBX:
775314564Sdim      case UNWIND_X86_64_REG_R12:
776314564Sdim      case UNWIND_X86_64_REG_R13:
777314564Sdim      case UNWIND_X86_64_REG_R14:
778314564Sdim      case UNWIND_X86_64_REG_R15:
779314564Sdim        row->SetRegisterLocationToAtCFAPlusOffset(
780314564Sdim            translate_to_eh_frame_regnum_x86_64(regnum),
781314564Sdim            wordsize * -saved_registers_offset, true);
782278332Semaste        break;
783314564Sdim      }
784314564Sdim      saved_registers_offset--;
785314564Sdim      saved_registers_locations >>= 3;
786314564Sdim    }
787314564Sdim    unwind_plan.AppendRow(row);
788314564Sdim    return true;
789314564Sdim  } break;
790278332Semaste
791314564Sdim  case UNWIND_X86_64_MODE_STACK_IND: {
792314564Sdim    // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
793341825Sdim    // this style of unwind.  It was fixed in llvm r217020. The clang in Xcode
794341825Sdim    // 7 has this fixed.
795314564Sdim    return false;
796314564Sdim  } break;
797278332Semaste
798314564Sdim  case UNWIND_X86_64_MODE_STACK_IMMD: {
799314564Sdim    uint32_t stack_size = EXTRACT_BITS(function_info.encoding,
800314564Sdim                                       UNWIND_X86_64_FRAMELESS_STACK_SIZE);
801314564Sdim    uint32_t register_count = EXTRACT_BITS(
802314564Sdim        function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
803314564Sdim    uint32_t permutation = EXTRACT_BITS(
804314564Sdim        function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
805278332Semaste
806314564Sdim    if (mode == UNWIND_X86_64_MODE_STACK_IND &&
807314564Sdim        function_info.valid_range_offset_start != 0) {
808314564Sdim      uint32_t stack_adjust = EXTRACT_BITS(
809314564Sdim          function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
810278332Semaste
811314564Sdim      // offset into the function instructions; 0 == beginning of first
812314564Sdim      // instruction
813314564Sdim      uint32_t offset_to_subl_insn = EXTRACT_BITS(
814314564Sdim          function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
815278332Semaste
816314564Sdim      SectionList *sl = m_objfile.GetSectionList();
817314564Sdim      if (sl) {
818314564Sdim        ProcessSP process_sp = target.GetProcessSP();
819314564Sdim        if (process_sp) {
820314564Sdim          Address subl_payload_addr(function_info.valid_range_offset_start, sl);
821314564Sdim          subl_payload_addr.Slide(offset_to_subl_insn);
822321369Sdim          Status error;
823314564Sdim          uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
824314564Sdim              subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
825314564Sdim          if (large_stack_size != 0 && error.Success()) {
826314564Sdim            // Got the large stack frame size correctly - use it
827314564Sdim            stack_size = large_stack_size + (stack_adjust * wordsize);
828314564Sdim          } else {
829314564Sdim            return false;
830314564Sdim          }
831314564Sdim        } else {
832314564Sdim          return false;
833314564Sdim        }
834314564Sdim      } else {
835314564Sdim        return false;
836314564Sdim      }
837314564Sdim    }
838288943Sdim
839314564Sdim    int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
840314564Sdim                         ? stack_size
841314564Sdim                         : stack_size * wordsize;
842314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
843278332Semaste
844314564Sdim    row->SetOffset(0);
845314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
846314564Sdim                                              wordsize * -1, true);
847314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
848278332Semaste
849314564Sdim    if (register_count > 0) {
850278332Semaste
851341825Sdim      // We need to include (up to) 6 registers in 10 bits. That would be 18
852341825Sdim      // bits if we just used 3 bits per reg to indicate the order they're
853341825Sdim      // saved on the stack.
854314564Sdim      //
855314564Sdim      // This is done with Lehmer code permutation, e.g. see
856341825Sdim      // http://stackoverflow.com/questions/1506078/fast-permutation-number-
857341825Sdim      // permutation-mapping-algorithms
858314564Sdim      int permunreg[6] = {0, 0, 0, 0, 0, 0};
859278332Semaste
860341825Sdim      // This decodes the variable-base number in the 10 bits and gives us the
861341825Sdim      // Lehmer code sequence which can then be decoded.
862309124Sdim
863314564Sdim      switch (register_count) {
864314564Sdim      case 6:
865314564Sdim        permunreg[0] = permutation / 120; // 120 == 5!
866314564Sdim        permutation -= (permunreg[0] * 120);
867314564Sdim        permunreg[1] = permutation / 24; // 24 == 4!
868314564Sdim        permutation -= (permunreg[1] * 24);
869314564Sdim        permunreg[2] = permutation / 6; // 6 == 3!
870314564Sdim        permutation -= (permunreg[2] * 6);
871314564Sdim        permunreg[3] = permutation / 2; // 2 == 2!
872314564Sdim        permutation -= (permunreg[3] * 2);
873314564Sdim        permunreg[4] = permutation; // 1 == 1!
874314564Sdim        permunreg[5] = 0;
875314564Sdim        break;
876314564Sdim      case 5:
877314564Sdim        permunreg[0] = permutation / 120;
878314564Sdim        permutation -= (permunreg[0] * 120);
879314564Sdim        permunreg[1] = permutation / 24;
880314564Sdim        permutation -= (permunreg[1] * 24);
881314564Sdim        permunreg[2] = permutation / 6;
882314564Sdim        permutation -= (permunreg[2] * 6);
883314564Sdim        permunreg[3] = permutation / 2;
884314564Sdim        permutation -= (permunreg[3] * 2);
885314564Sdim        permunreg[4] = permutation;
886314564Sdim        break;
887314564Sdim      case 4:
888314564Sdim        permunreg[0] = permutation / 60;
889314564Sdim        permutation -= (permunreg[0] * 60);
890314564Sdim        permunreg[1] = permutation / 12;
891314564Sdim        permutation -= (permunreg[1] * 12);
892314564Sdim        permunreg[2] = permutation / 3;
893314564Sdim        permutation -= (permunreg[2] * 3);
894314564Sdim        permunreg[3] = permutation;
895314564Sdim        break;
896314564Sdim      case 3:
897314564Sdim        permunreg[0] = permutation / 20;
898314564Sdim        permutation -= (permunreg[0] * 20);
899314564Sdim        permunreg[1] = permutation / 4;
900314564Sdim        permutation -= (permunreg[1] * 4);
901314564Sdim        permunreg[2] = permutation;
902314564Sdim        break;
903314564Sdim      case 2:
904314564Sdim        permunreg[0] = permutation / 5;
905314564Sdim        permutation -= (permunreg[0] * 5);
906314564Sdim        permunreg[1] = permutation;
907314564Sdim        break;
908314564Sdim      case 1:
909314564Sdim        permunreg[0] = permutation;
910314564Sdim        break;
911314564Sdim      }
912278332Semaste
913341825Sdim      // Decode the Lehmer code for this permutation of the registers v.
914341825Sdim      // http://en.wikipedia.org/wiki/Lehmer_code
915278332Semaste
916314564Sdim      int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
917314564Sdim                          UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
918314564Sdim                          UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
919314564Sdim      bool used[7] = {false, false, false, false, false, false, false};
920314564Sdim      for (uint32_t i = 0; i < register_count; i++) {
921314564Sdim        int renum = 0;
922314564Sdim        for (int j = 1; j < 7; j++) {
923344779Sdim          if (!used[j]) {
924314564Sdim            if (renum == permunreg[i]) {
925314564Sdim              registers[i] = j;
926314564Sdim              used[j] = true;
927314564Sdim              break;
928278332Semaste            }
929314564Sdim            renum++;
930314564Sdim          }
931278332Semaste        }
932314564Sdim      }
933278332Semaste
934314564Sdim      uint32_t saved_registers_offset = 1;
935314564Sdim      saved_registers_offset++;
936278332Semaste
937314564Sdim      for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
938314564Sdim        switch (registers[i]) {
939314564Sdim        case UNWIND_X86_64_REG_NONE:
940314564Sdim          break;
941314564Sdim        case UNWIND_X86_64_REG_RBX:
942314564Sdim        case UNWIND_X86_64_REG_R12:
943314564Sdim        case UNWIND_X86_64_REG_R13:
944314564Sdim        case UNWIND_X86_64_REG_R14:
945314564Sdim        case UNWIND_X86_64_REG_R15:
946314564Sdim        case UNWIND_X86_64_REG_RBP:
947314564Sdim          row->SetRegisterLocationToAtCFAPlusOffset(
948314564Sdim              translate_to_eh_frame_regnum_x86_64(registers[i]),
949314564Sdim              wordsize * -saved_registers_offset, true);
950314564Sdim          saved_registers_offset++;
951314564Sdim          break;
952278332Semaste        }
953314564Sdim      }
954278332Semaste    }
955314564Sdim    unwind_plan.AppendRow(row);
956314564Sdim    return true;
957314564Sdim  } break;
958314564Sdim
959314564Sdim  case UNWIND_X86_64_MODE_DWARF: {
960278332Semaste    return false;
961314564Sdim  } break;
962314564Sdim
963314564Sdim  case 0: {
964314564Sdim    return false;
965314564Sdim  } break;
966314564Sdim  }
967314564Sdim  return false;
968278332Semaste}
969278332Semaste
970278332Semasteenum i386_eh_regnum {
971314564Sdim  eax = 0,
972314564Sdim  ecx = 1,
973314564Sdim  edx = 2,
974314564Sdim  ebx = 3,
975314564Sdim  ebp = 4,
976314564Sdim  esp = 5,
977314564Sdim  esi = 6,
978314564Sdim  edi = 7,
979314564Sdim  eip = 8 // this is officially the Return Address register number, but close
980314564Sdim          // enough
981278332Semaste};
982278332Semaste
983341825Sdim// Convert the compact_unwind_info.h register numbering scheme to
984341825Sdim// eRegisterKindEHFrame (eh_frame) register numbering scheme.
985314564Sdimuint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {
986314564Sdim  switch (unwind_regno) {
987314564Sdim  case UNWIND_X86_REG_EBX:
988314564Sdim    return i386_eh_regnum::ebx;
989314564Sdim  case UNWIND_X86_REG_ECX:
990314564Sdim    return i386_eh_regnum::ecx;
991314564Sdim  case UNWIND_X86_REG_EDX:
992314564Sdim    return i386_eh_regnum::edx;
993314564Sdim  case UNWIND_X86_REG_EDI:
994314564Sdim    return i386_eh_regnum::edi;
995314564Sdim  case UNWIND_X86_REG_ESI:
996314564Sdim    return i386_eh_regnum::esi;
997314564Sdim  case UNWIND_X86_REG_EBP:
998314564Sdim    return i386_eh_regnum::ebp;
999314564Sdim  default:
1000314564Sdim    return LLDB_INVALID_REGNUM;
1001314564Sdim  }
1002278332Semaste}
1003278332Semaste
1004314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
1005314564Sdim                                              FunctionInfo &function_info,
1006314564Sdim                                              UnwindPlan &unwind_plan,
1007314564Sdim                                              Address pc_or_function_start) {
1008314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1009314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1010314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1011314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1012278332Semaste
1013314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1014314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1015278332Semaste
1016314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1017278332Semaste
1018314564Sdim  const int wordsize = 4;
1019314564Sdim  int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1020314564Sdim  switch (mode) {
1021314564Sdim  case UNWIND_X86_MODE_EBP_FRAME: {
1022314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(
1023314564Sdim        translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
1024314564Sdim    row->SetOffset(0);
1025314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,
1026314564Sdim                                              wordsize * -2, true);
1027314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1028314564Sdim                                              wordsize * -1, true);
1029314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1030278332Semaste
1031314564Sdim    uint32_t saved_registers_offset =
1032314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1033309124Sdim
1034314564Sdim    uint32_t saved_registers_locations =
1035314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1036278332Semaste
1037314564Sdim    saved_registers_offset += 2;
1038278332Semaste
1039314564Sdim    for (int i = 0; i < 5; i++) {
1040314564Sdim      uint32_t regnum = saved_registers_locations & 0x7;
1041314564Sdim      switch (regnum) {
1042314564Sdim      case UNWIND_X86_REG_NONE:
1043278332Semaste        break;
1044314564Sdim      case UNWIND_X86_REG_EBX:
1045314564Sdim      case UNWIND_X86_REG_ECX:
1046314564Sdim      case UNWIND_X86_REG_EDX:
1047314564Sdim      case UNWIND_X86_REG_EDI:
1048314564Sdim      case UNWIND_X86_REG_ESI:
1049314564Sdim        row->SetRegisterLocationToAtCFAPlusOffset(
1050314564Sdim            translate_to_eh_frame_regnum_i386(regnum),
1051314564Sdim            wordsize * -saved_registers_offset, true);
1052314564Sdim        break;
1053314564Sdim      }
1054314564Sdim      saved_registers_offset--;
1055314564Sdim      saved_registers_locations >>= 3;
1056314564Sdim    }
1057314564Sdim    unwind_plan.AppendRow(row);
1058314564Sdim    return true;
1059314564Sdim  } break;
1060278332Semaste
1061314564Sdim  case UNWIND_X86_MODE_STACK_IND:
1062314564Sdim  case UNWIND_X86_MODE_STACK_IMMD: {
1063314564Sdim    uint32_t stack_size =
1064314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1065314564Sdim    uint32_t register_count = EXTRACT_BITS(
1066314564Sdim        function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1067314564Sdim    uint32_t permutation = EXTRACT_BITS(
1068314564Sdim        function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
1069278332Semaste
1070314564Sdim    if (mode == UNWIND_X86_MODE_STACK_IND &&
1071314564Sdim        function_info.valid_range_offset_start != 0) {
1072314564Sdim      uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,
1073314564Sdim                                           UNWIND_X86_FRAMELESS_STACK_ADJUST);
1074278332Semaste
1075314564Sdim      // offset into the function instructions; 0 == beginning of first
1076314564Sdim      // instruction
1077314564Sdim      uint32_t offset_to_subl_insn =
1078314564Sdim          EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1079278332Semaste
1080314564Sdim      SectionList *sl = m_objfile.GetSectionList();
1081314564Sdim      if (sl) {
1082314564Sdim        ProcessSP process_sp = target.GetProcessSP();
1083314564Sdim        if (process_sp) {
1084314564Sdim          Address subl_payload_addr(function_info.valid_range_offset_start, sl);
1085314564Sdim          subl_payload_addr.Slide(offset_to_subl_insn);
1086321369Sdim          Status error;
1087314564Sdim          uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
1088314564Sdim              subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
1089314564Sdim          if (large_stack_size != 0 && error.Success()) {
1090314564Sdim            // Got the large stack frame size correctly - use it
1091314564Sdim            stack_size = large_stack_size + (stack_adjust * wordsize);
1092314564Sdim          } else {
1093314564Sdim            return false;
1094314564Sdim          }
1095314564Sdim        } else {
1096314564Sdim          return false;
1097314564Sdim        }
1098314564Sdim      } else {
1099314564Sdim        return false;
1100314564Sdim      }
1101314564Sdim    }
1102278332Semaste
1103314564Sdim    int32_t offset =
1104314564Sdim        mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1105314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
1106314564Sdim    row->SetOffset(0);
1107314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1108314564Sdim                                              wordsize * -1, true);
1109314564Sdim    row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1110309124Sdim
1111314564Sdim    if (register_count > 0) {
1112278332Semaste
1113341825Sdim      // We need to include (up to) 6 registers in 10 bits. That would be 18
1114341825Sdim      // bits if we just used 3 bits per reg to indicate the order they're
1115341825Sdim      // saved on the stack.
1116314564Sdim      //
1117314564Sdim      // This is done with Lehmer code permutation, e.g. see
1118341825Sdim      // http://stackoverflow.com/questions/1506078/fast-permutation-number-
1119341825Sdim      // permutation-mapping-algorithms
1120314564Sdim      int permunreg[6] = {0, 0, 0, 0, 0, 0};
1121278332Semaste
1122341825Sdim      // This decodes the variable-base number in the 10 bits and gives us the
1123341825Sdim      // Lehmer code sequence which can then be decoded.
1124278332Semaste
1125314564Sdim      switch (register_count) {
1126314564Sdim      case 6:
1127314564Sdim        permunreg[0] = permutation / 120; // 120 == 5!
1128314564Sdim        permutation -= (permunreg[0] * 120);
1129314564Sdim        permunreg[1] = permutation / 24; // 24 == 4!
1130314564Sdim        permutation -= (permunreg[1] * 24);
1131314564Sdim        permunreg[2] = permutation / 6; // 6 == 3!
1132314564Sdim        permutation -= (permunreg[2] * 6);
1133314564Sdim        permunreg[3] = permutation / 2; // 2 == 2!
1134314564Sdim        permutation -= (permunreg[3] * 2);
1135314564Sdim        permunreg[4] = permutation; // 1 == 1!
1136314564Sdim        permunreg[5] = 0;
1137314564Sdim        break;
1138314564Sdim      case 5:
1139314564Sdim        permunreg[0] = permutation / 120;
1140314564Sdim        permutation -= (permunreg[0] * 120);
1141314564Sdim        permunreg[1] = permutation / 24;
1142314564Sdim        permutation -= (permunreg[1] * 24);
1143314564Sdim        permunreg[2] = permutation / 6;
1144314564Sdim        permutation -= (permunreg[2] * 6);
1145314564Sdim        permunreg[3] = permutation / 2;
1146314564Sdim        permutation -= (permunreg[3] * 2);
1147314564Sdim        permunreg[4] = permutation;
1148314564Sdim        break;
1149314564Sdim      case 4:
1150314564Sdim        permunreg[0] = permutation / 60;
1151314564Sdim        permutation -= (permunreg[0] * 60);
1152314564Sdim        permunreg[1] = permutation / 12;
1153314564Sdim        permutation -= (permunreg[1] * 12);
1154314564Sdim        permunreg[2] = permutation / 3;
1155314564Sdim        permutation -= (permunreg[2] * 3);
1156314564Sdim        permunreg[3] = permutation;
1157314564Sdim        break;
1158314564Sdim      case 3:
1159314564Sdim        permunreg[0] = permutation / 20;
1160314564Sdim        permutation -= (permunreg[0] * 20);
1161314564Sdim        permunreg[1] = permutation / 4;
1162314564Sdim        permutation -= (permunreg[1] * 4);
1163314564Sdim        permunreg[2] = permutation;
1164314564Sdim        break;
1165314564Sdim      case 2:
1166314564Sdim        permunreg[0] = permutation / 5;
1167314564Sdim        permutation -= (permunreg[0] * 5);
1168314564Sdim        permunreg[1] = permutation;
1169314564Sdim        break;
1170314564Sdim      case 1:
1171314564Sdim        permunreg[0] = permutation;
1172314564Sdim        break;
1173314564Sdim      }
1174309124Sdim
1175341825Sdim      // Decode the Lehmer code for this permutation of the registers v.
1176341825Sdim      // http://en.wikipedia.org/wiki/Lehmer_code
1177278332Semaste
1178314564Sdim      int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1179314564Sdim                          UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1180314564Sdim                          UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};
1181314564Sdim      bool used[7] = {false, false, false, false, false, false, false};
1182314564Sdim      for (uint32_t i = 0; i < register_count; i++) {
1183314564Sdim        int renum = 0;
1184314564Sdim        for (int j = 1; j < 7; j++) {
1185344779Sdim          if (!used[j]) {
1186314564Sdim            if (renum == permunreg[i]) {
1187314564Sdim              registers[i] = j;
1188314564Sdim              used[j] = true;
1189314564Sdim              break;
1190278332Semaste            }
1191314564Sdim            renum++;
1192314564Sdim          }
1193278332Semaste        }
1194314564Sdim      }
1195278332Semaste
1196314564Sdim      uint32_t saved_registers_offset = 1;
1197314564Sdim      saved_registers_offset++;
1198314564Sdim
1199314564Sdim      for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1200314564Sdim        switch (registers[i]) {
1201314564Sdim        case UNWIND_X86_REG_NONE:
1202314564Sdim          break;
1203314564Sdim        case UNWIND_X86_REG_EBX:
1204314564Sdim        case UNWIND_X86_REG_ECX:
1205314564Sdim        case UNWIND_X86_REG_EDX:
1206314564Sdim        case UNWIND_X86_REG_EDI:
1207314564Sdim        case UNWIND_X86_REG_ESI:
1208314564Sdim        case UNWIND_X86_REG_EBP:
1209314564Sdim          row->SetRegisterLocationToAtCFAPlusOffset(
1210314564Sdim              translate_to_eh_frame_regnum_i386(registers[i]),
1211314564Sdim              wordsize * -saved_registers_offset, true);
1212314564Sdim          saved_registers_offset++;
1213314564Sdim          break;
1214278332Semaste        }
1215314564Sdim      }
1216278332Semaste    }
1217314564Sdim
1218314564Sdim    unwind_plan.AppendRow(row);
1219314564Sdim    return true;
1220314564Sdim  } break;
1221314564Sdim
1222314564Sdim  case UNWIND_X86_MODE_DWARF: {
1223278332Semaste    return false;
1224314564Sdim  } break;
1225314564Sdim  }
1226314564Sdim  return false;
1227278332Semaste}
1228309124Sdim
1229314564Sdim// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1230314564Sdim// doc by ARM
1231309124Sdim
1232309124Sdimenum arm64_eh_regnum {
1233314564Sdim  x19 = 19,
1234314564Sdim  x20 = 20,
1235314564Sdim  x21 = 21,
1236314564Sdim  x22 = 22,
1237314564Sdim  x23 = 23,
1238314564Sdim  x24 = 24,
1239314564Sdim  x25 = 25,
1240314564Sdim  x26 = 26,
1241314564Sdim  x27 = 27,
1242314564Sdim  x28 = 28,
1243309124Sdim
1244314564Sdim  fp = 29,
1245314564Sdim  ra = 30,
1246314564Sdim  sp = 31,
1247314564Sdim  pc = 32,
1248309124Sdim
1249314564Sdim  // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
1250341825Sdim  // for the 64-bit fp regs.  Normally in DWARF it's context sensitive - so it
1251341825Sdim  // knows it is fetching a 32- or 64-bit quantity from reg v8 to indicate s0
1252341825Sdim  // or d0 - but the unwinder is operating at a lower level and we'd try to
1253341825Sdim  // fetch 128 bits if we were told that v8 were stored on the stack...
1254314564Sdim  v8 = 72,
1255314564Sdim  v9 = 73,
1256314564Sdim  v10 = 74,
1257314564Sdim  v11 = 75,
1258314564Sdim  v12 = 76,
1259314564Sdim  v13 = 77,
1260314564Sdim  v14 = 78,
1261314564Sdim  v15 = 79,
1262309124Sdim};
1263309124Sdim
1264309124Sdimenum arm_eh_regnum {
1265314564Sdim  arm_r0 = 0,
1266314564Sdim  arm_r1 = 1,
1267314564Sdim  arm_r2 = 2,
1268314564Sdim  arm_r3 = 3,
1269314564Sdim  arm_r4 = 4,
1270314564Sdim  arm_r5 = 5,
1271314564Sdim  arm_r6 = 6,
1272314564Sdim  arm_r7 = 7,
1273314564Sdim  arm_r8 = 8,
1274314564Sdim  arm_r9 = 9,
1275314564Sdim  arm_r10 = 10,
1276314564Sdim  arm_r11 = 11,
1277314564Sdim  arm_r12 = 12,
1278309124Sdim
1279314564Sdim  arm_sp = 13,
1280314564Sdim  arm_lr = 14,
1281314564Sdim  arm_pc = 15,
1282309124Sdim
1283314564Sdim  arm_d0 = 256,
1284314564Sdim  arm_d1 = 257,
1285314564Sdim  arm_d2 = 258,
1286314564Sdim  arm_d3 = 259,
1287314564Sdim  arm_d4 = 260,
1288314564Sdim  arm_d5 = 261,
1289314564Sdim  arm_d6 = 262,
1290314564Sdim  arm_d7 = 263,
1291314564Sdim  arm_d8 = 264,
1292314564Sdim  arm_d9 = 265,
1293314564Sdim  arm_d10 = 266,
1294314564Sdim  arm_d11 = 267,
1295314564Sdim  arm_d12 = 268,
1296314564Sdim  arm_d13 = 269,
1297314564Sdim  arm_d14 = 270,
1298309124Sdim};
1299309124Sdim
1300314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
1301314564Sdim                                               FunctionInfo &function_info,
1302314564Sdim                                               UnwindPlan &unwind_plan,
1303314564Sdim                                               Address pc_or_function_start) {
1304314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1305314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1306314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1307314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1308309124Sdim
1309314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1310314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1311309124Sdim
1312314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1313309124Sdim
1314314564Sdim  const int wordsize = 8;
1315314564Sdim  int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
1316309124Sdim
1317314564Sdim  if (mode == UNWIND_ARM64_MODE_DWARF)
1318314564Sdim    return false;
1319309124Sdim
1320314564Sdim  if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1321314564Sdim    row->SetOffset(0);
1322309124Sdim
1323314564Sdim    uint32_t stack_size =
1324314564Sdim        (EXTRACT_BITS(function_info.encoding,
1325314564Sdim                      UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1326314564Sdim        16;
1327309124Sdim
1328314564Sdim    // Our previous Call Frame Address is the stack pointer plus the stack size
1329314564Sdim    row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
1330309124Sdim
1331314564Sdim    // Our previous PC is in the LR
1332314564Sdim    row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1333314564Sdim                                       true);
1334309124Sdim
1335314564Sdim    unwind_plan.AppendRow(row);
1336314564Sdim    return true;
1337314564Sdim  }
1338309124Sdim
1339314564Sdim  // Should not be possible
1340314564Sdim  if (mode != UNWIND_ARM64_MODE_FRAME)
1341314564Sdim    return false;
1342309124Sdim
1343314564Sdim  // mode == UNWIND_ARM64_MODE_FRAME
1344309124Sdim
1345314564Sdim  row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1346314564Sdim  row->SetOffset(0);
1347314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1348314564Sdim                                            true);
1349314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1350314564Sdim                                            true);
1351314564Sdim  row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1352309124Sdim
1353314564Sdim  int reg_pairs_saved_count = 1;
1354309124Sdim
1355314564Sdim  uint32_t saved_register_bits = function_info.encoding & 0xfff;
1356309124Sdim
1357314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
1358314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1359314564Sdim    cfa_offset -= wordsize;
1360314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,
1361314564Sdim                                              true);
1362314564Sdim    cfa_offset -= wordsize;
1363314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1364314564Sdim                                              true);
1365314564Sdim    reg_pairs_saved_count++;
1366314564Sdim  }
1367309124Sdim
1368314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
1369314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1370314564Sdim    cfa_offset -= wordsize;
1371314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,
1372314564Sdim                                              true);
1373314564Sdim    cfa_offset -= wordsize;
1374314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1375314564Sdim                                              true);
1376314564Sdim    reg_pairs_saved_count++;
1377314564Sdim  }
1378309124Sdim
1379314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
1380314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1381314564Sdim    cfa_offset -= wordsize;
1382314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,
1383314564Sdim                                              true);
1384314564Sdim    cfa_offset -= wordsize;
1385314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1386314564Sdim                                              true);
1387314564Sdim    reg_pairs_saved_count++;
1388314564Sdim  }
1389309124Sdim
1390314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
1391314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1392314564Sdim    cfa_offset -= wordsize;
1393314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,
1394314564Sdim                                              true);
1395314564Sdim    cfa_offset -= wordsize;
1396314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1397314564Sdim                                              true);
1398314564Sdim    reg_pairs_saved_count++;
1399314564Sdim  }
1400309124Sdim
1401314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
1402314564Sdim    int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1403314564Sdim    cfa_offset -= wordsize;
1404314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,
1405314564Sdim                                              true);
1406314564Sdim    cfa_offset -= wordsize;
1407314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1408314564Sdim                                              true);
1409314564Sdim    reg_pairs_saved_count++;
1410314564Sdim  }
1411309124Sdim
1412314564Sdim  // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1413314564Sdim  // off the stack;
1414314564Sdim  // not sure if we have a good way to represent the 64-bitness of these saves.
1415309124Sdim
1416314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1417314564Sdim    reg_pairs_saved_count++;
1418314564Sdim  }
1419314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1420314564Sdim    reg_pairs_saved_count++;
1421314564Sdim  }
1422314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1423314564Sdim    reg_pairs_saved_count++;
1424314564Sdim  }
1425314564Sdim  if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1426314564Sdim    reg_pairs_saved_count++;
1427314564Sdim  }
1428309124Sdim
1429314564Sdim  unwind_plan.AppendRow(row);
1430314564Sdim  return true;
1431309124Sdim}
1432309124Sdim
1433314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
1434314564Sdim                                               FunctionInfo &function_info,
1435314564Sdim                                               UnwindPlan &unwind_plan,
1436314564Sdim                                               Address pc_or_function_start) {
1437314564Sdim  unwind_plan.SetSourceName("compact unwind info");
1438314564Sdim  unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1439314564Sdim  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1440314564Sdim  unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1441309124Sdim
1442314564Sdim  unwind_plan.SetLSDAAddress(function_info.lsda_address);
1443314564Sdim  unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1444309124Sdim
1445314564Sdim  UnwindPlan::RowSP row(new UnwindPlan::Row);
1446309124Sdim
1447314564Sdim  const int wordsize = 4;
1448314564Sdim  int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
1449309124Sdim
1450314564Sdim  if (mode == UNWIND_ARM_MODE_DWARF)
1451314564Sdim    return false;
1452309124Sdim
1453314564Sdim  uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1454314564Sdim                                        UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1455314564Sdim                          wordsize;
1456309124Sdim
1457314564Sdim  row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1458314564Sdim                                             (2 * wordsize) + stack_adjust);
1459314564Sdim  row->SetOffset(0);
1460314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(
1461314564Sdim      arm_r7, (wordsize * -2) - stack_adjust, true);
1462314564Sdim  row->SetRegisterLocationToAtCFAPlusOffset(
1463314564Sdim      arm_pc, (wordsize * -1) - stack_adjust, true);
1464314564Sdim  row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);
1465309124Sdim
1466314564Sdim  int cfa_offset = -stack_adjust - (2 * wordsize);
1467309124Sdim
1468314564Sdim  uint32_t saved_register_bits = function_info.encoding & 0xff;
1469309124Sdim
1470314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1471314564Sdim    cfa_offset -= wordsize;
1472314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1473314564Sdim  }
1474309124Sdim
1475314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1476314564Sdim    cfa_offset -= wordsize;
1477314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1478314564Sdim  }
1479309124Sdim
1480314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1481314564Sdim    cfa_offset -= wordsize;
1482314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1483314564Sdim  }
1484309124Sdim
1485314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1486314564Sdim    cfa_offset -= wordsize;
1487314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1488314564Sdim  }
1489309124Sdim
1490314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1491314564Sdim    cfa_offset -= wordsize;
1492314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1493314564Sdim  }
1494309124Sdim
1495314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1496314564Sdim    cfa_offset -= wordsize;
1497314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1498314564Sdim  }
1499309124Sdim
1500314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1501314564Sdim    cfa_offset -= wordsize;
1502314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1503314564Sdim  }
1504309124Sdim
1505314564Sdim  if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1506314564Sdim    cfa_offset -= wordsize;
1507314564Sdim    row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
1508314564Sdim  }
1509309124Sdim
1510314564Sdim  if (mode == UNWIND_ARM_MODE_FRAME_D) {
1511314564Sdim    uint32_t d_reg_bits =
1512314564Sdim        EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1513314564Sdim    switch (d_reg_bits) {
1514314564Sdim    case 0:
1515314564Sdim      // vpush {d8}
1516314564Sdim      cfa_offset -= 8;
1517314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1518314564Sdim      break;
1519314564Sdim    case 1:
1520314564Sdim      // vpush {d10}
1521314564Sdim      // vpush {d8}
1522314564Sdim      cfa_offset -= 8;
1523314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1524314564Sdim      cfa_offset -= 8;
1525314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1526314564Sdim      break;
1527314564Sdim    case 2:
1528314564Sdim      // vpush {d12}
1529314564Sdim      // vpush {d10}
1530314564Sdim      // vpush {d8}
1531314564Sdim      cfa_offset -= 8;
1532314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1533314564Sdim      cfa_offset -= 8;
1534314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1535314564Sdim      cfa_offset -= 8;
1536314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1537314564Sdim      break;
1538314564Sdim    case 3:
1539314564Sdim      // vpush {d14}
1540314564Sdim      // vpush {d12}
1541314564Sdim      // vpush {d10}
1542314564Sdim      // vpush {d8}
1543314564Sdim      cfa_offset -= 8;
1544314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1545314564Sdim      cfa_offset -= 8;
1546314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1547314564Sdim      cfa_offset -= 8;
1548314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1549314564Sdim      cfa_offset -= 8;
1550314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1551314564Sdim      break;
1552314564Sdim    case 4:
1553314564Sdim      // vpush {d14}
1554314564Sdim      // vpush {d12}
1555314564Sdim      // sp = (sp - 24) & (-16);
1556314564Sdim      // vst   {d8, d9, d10}
1557314564Sdim      cfa_offset -= 8;
1558314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1559314564Sdim      cfa_offset -= 8;
1560314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1561309124Sdim
1562314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1563314564Sdim      // alignment short of
1564314564Sdim      // coming up with some DWARF location description.
1565309124Sdim
1566314564Sdim      break;
1567314564Sdim    case 5:
1568314564Sdim      // vpush {d14}
1569314564Sdim      // sp = (sp - 40) & (-16);
1570314564Sdim      // vst   {d8, d9, d10, d11}
1571314564Sdim      // vst   {d12}
1572309124Sdim
1573314564Sdim      cfa_offset -= 8;
1574314564Sdim      row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1575309124Sdim
1576314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1577314564Sdim      // alignment short of
1578314564Sdim      // coming up with some DWARF location description.
1579309124Sdim
1580314564Sdim      break;
1581314564Sdim    case 6:
1582314564Sdim      // sp = (sp - 56) & (-16);
1583314564Sdim      // vst   {d8, d9, d10, d11}
1584314564Sdim      // vst   {d12, d13, d14}
1585309124Sdim
1586314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1587314564Sdim      // alignment short of
1588314564Sdim      // coming up with some DWARF location description.
1589309124Sdim
1590314564Sdim      break;
1591314564Sdim    case 7:
1592314564Sdim      // sp = (sp - 64) & (-16);
1593314564Sdim      // vst   {d8, d9, d10, d11}
1594314564Sdim      // vst   {d12, d13, d14, d15}
1595309124Sdim
1596314564Sdim      // FIXME we don't have a way to represent reg saves at an specific
1597314564Sdim      // alignment short of
1598314564Sdim      // coming up with some DWARF location description.
1599309124Sdim
1600314564Sdim      break;
1601309124Sdim    }
1602314564Sdim  }
1603309124Sdim
1604314564Sdim  unwind_plan.AppendRow(row);
1605314564Sdim  return true;
1606309124Sdim}
1607