1dda28197Spatrick //===-- CompactUnwindInfo.cpp ---------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Symbol/CompactUnwindInfo.h"
10*f6aab3d8Srobert #include "lldb/Core/Debugger.h"
11061da546Spatrick #include "lldb/Core/Module.h"
12061da546Spatrick #include "lldb/Core/Section.h"
13061da546Spatrick #include "lldb/Symbol/ObjectFile.h"
14061da546Spatrick #include "lldb/Symbol/UnwindPlan.h"
15061da546Spatrick #include "lldb/Target/Process.h"
16061da546Spatrick #include "lldb/Target/Target.h"
17061da546Spatrick #include "lldb/Utility/ArchSpec.h"
18061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
19*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
20061da546Spatrick #include "lldb/Utility/Log.h"
21061da546Spatrick #include "lldb/Utility/StreamString.h"
22061da546Spatrick
23061da546Spatrick #include "llvm/Support/MathExtras.h"
24061da546Spatrick
25061da546Spatrick #include <algorithm>
26061da546Spatrick #include <memory>
27061da546Spatrick
28061da546Spatrick using namespace lldb;
29061da546Spatrick using namespace lldb_private;
30061da546Spatrick
31061da546Spatrick namespace lldb_private {
32061da546Spatrick
33061da546Spatrick // Constants from <mach-o/compact_unwind_encoding.h>
34061da546Spatrick
FLAGS_ANONYMOUS_ENUM()35061da546Spatrick FLAGS_ANONYMOUS_ENUM(){
36061da546Spatrick UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
37061da546Spatrick UNWIND_PERSONALITY_MASK = 0x30000000,
38061da546Spatrick };
39061da546Spatrick
FLAGS_ANONYMOUS_ENUM()40061da546Spatrick FLAGS_ANONYMOUS_ENUM(){
41061da546Spatrick UNWIND_X86_MODE_MASK = 0x0F000000,
42061da546Spatrick UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
43061da546Spatrick UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
44061da546Spatrick UNWIND_X86_MODE_STACK_IND = 0x03000000,
45061da546Spatrick UNWIND_X86_MODE_DWARF = 0x04000000,
46061da546Spatrick
47061da546Spatrick UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
48061da546Spatrick UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
49061da546Spatrick
50061da546Spatrick UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
51061da546Spatrick UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
52061da546Spatrick UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
53061da546Spatrick UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
54061da546Spatrick
55061da546Spatrick UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
56061da546Spatrick };
57061da546Spatrick
58061da546Spatrick enum {
59061da546Spatrick UNWIND_X86_REG_NONE = 0,
60061da546Spatrick UNWIND_X86_REG_EBX = 1,
61061da546Spatrick UNWIND_X86_REG_ECX = 2,
62061da546Spatrick UNWIND_X86_REG_EDX = 3,
63061da546Spatrick UNWIND_X86_REG_EDI = 4,
64061da546Spatrick UNWIND_X86_REG_ESI = 5,
65061da546Spatrick UNWIND_X86_REG_EBP = 6,
66061da546Spatrick };
67061da546Spatrick
FLAGS_ANONYMOUS_ENUM()68061da546Spatrick FLAGS_ANONYMOUS_ENUM(){
69061da546Spatrick UNWIND_X86_64_MODE_MASK = 0x0F000000,
70061da546Spatrick UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
71061da546Spatrick UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
72061da546Spatrick UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
73061da546Spatrick UNWIND_X86_64_MODE_DWARF = 0x04000000,
74061da546Spatrick
75061da546Spatrick UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
76061da546Spatrick UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
77061da546Spatrick
78061da546Spatrick UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
79061da546Spatrick UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
80061da546Spatrick UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
81061da546Spatrick UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
82061da546Spatrick
83061da546Spatrick UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
84061da546Spatrick };
85061da546Spatrick
86061da546Spatrick enum {
87061da546Spatrick UNWIND_X86_64_REG_NONE = 0,
88061da546Spatrick UNWIND_X86_64_REG_RBX = 1,
89061da546Spatrick UNWIND_X86_64_REG_R12 = 2,
90061da546Spatrick UNWIND_X86_64_REG_R13 = 3,
91061da546Spatrick UNWIND_X86_64_REG_R14 = 4,
92061da546Spatrick UNWIND_X86_64_REG_R15 = 5,
93061da546Spatrick UNWIND_X86_64_REG_RBP = 6,
94061da546Spatrick };
95061da546Spatrick
FLAGS_ANONYMOUS_ENUM()96061da546Spatrick FLAGS_ANONYMOUS_ENUM(){
97061da546Spatrick UNWIND_ARM64_MODE_MASK = 0x0F000000,
98061da546Spatrick UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
99061da546Spatrick UNWIND_ARM64_MODE_DWARF = 0x03000000,
100061da546Spatrick UNWIND_ARM64_MODE_FRAME = 0x04000000,
101061da546Spatrick
102061da546Spatrick UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
103061da546Spatrick UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
104061da546Spatrick UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
105061da546Spatrick UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
106061da546Spatrick UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
107061da546Spatrick UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
108061da546Spatrick UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
109061da546Spatrick UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
110061da546Spatrick UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
111061da546Spatrick
112061da546Spatrick UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
113061da546Spatrick UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
114061da546Spatrick };
115061da546Spatrick
FLAGS_ANONYMOUS_ENUM()116061da546Spatrick FLAGS_ANONYMOUS_ENUM(){
117061da546Spatrick UNWIND_ARM_MODE_MASK = 0x0F000000,
118061da546Spatrick UNWIND_ARM_MODE_FRAME = 0x01000000,
119061da546Spatrick UNWIND_ARM_MODE_FRAME_D = 0x02000000,
120061da546Spatrick UNWIND_ARM_MODE_DWARF = 0x04000000,
121061da546Spatrick
122061da546Spatrick UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
123061da546Spatrick
124061da546Spatrick UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
125061da546Spatrick UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
126061da546Spatrick UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
127061da546Spatrick
128061da546Spatrick UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
129061da546Spatrick UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
130061da546Spatrick UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
131061da546Spatrick UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
132061da546Spatrick UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
133061da546Spatrick
134061da546Spatrick UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
135061da546Spatrick
136061da546Spatrick UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
137061da546Spatrick };
138061da546Spatrick }
139061da546Spatrick
140061da546Spatrick #ifndef UNWIND_SECOND_LEVEL_REGULAR
141061da546Spatrick #define UNWIND_SECOND_LEVEL_REGULAR 2
142061da546Spatrick #endif
143061da546Spatrick
144061da546Spatrick #ifndef UNWIND_SECOND_LEVEL_COMPRESSED
145061da546Spatrick #define UNWIND_SECOND_LEVEL_COMPRESSED 3
146061da546Spatrick #endif
147061da546Spatrick
148061da546Spatrick #ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
149061da546Spatrick #define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
150061da546Spatrick #endif
151061da546Spatrick
152061da546Spatrick #ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
153061da546Spatrick #define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \
154061da546Spatrick ((entry >> 24) & 0xFF)
155061da546Spatrick #endif
156061da546Spatrick
157061da546Spatrick #define EXTRACT_BITS(value, mask) \
158*f6aab3d8Srobert ((value >> llvm::countTrailingZeros(static_cast<uint32_t>(mask))) & \
159*f6aab3d8Srobert (((1 << llvm::popcount(static_cast<uint32_t>(mask)))) - 1))
160061da546Spatrick
161061da546Spatrick // constructor
162061da546Spatrick
CompactUnwindInfo(ObjectFile & objfile,SectionSP & section_sp)163061da546Spatrick CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp)
164061da546Spatrick : m_objfile(objfile), m_section_sp(section_sp),
165061da546Spatrick m_section_contents_if_encrypted(), m_mutex(), m_indexes(),
166061da546Spatrick m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(),
167061da546Spatrick m_unwindinfo_data_computed(false), m_unwind_header() {}
168061da546Spatrick
169061da546Spatrick // destructor
170061da546Spatrick
171be691f3bSpatrick CompactUnwindInfo::~CompactUnwindInfo() = default;
172061da546Spatrick
GetUnwindPlan(Target & target,Address addr,UnwindPlan & unwind_plan)173061da546Spatrick bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
174061da546Spatrick UnwindPlan &unwind_plan) {
175061da546Spatrick if (!IsValid(target.GetProcessSP())) {
176061da546Spatrick return false;
177061da546Spatrick }
178061da546Spatrick FunctionInfo function_info;
179061da546Spatrick if (GetCompactUnwindInfoForFunction(target, addr, function_info)) {
180061da546Spatrick // shortcut return for functions that have no compact unwind
181061da546Spatrick if (function_info.encoding == 0)
182061da546Spatrick return false;
183061da546Spatrick
184061da546Spatrick if (ArchSpec arch = m_objfile.GetArchitecture()) {
185061da546Spatrick
186*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Unwind);
187061da546Spatrick if (log && log->GetVerbose()) {
188061da546Spatrick StreamString strm;
189061da546Spatrick addr.Dump(
190061da546Spatrick &strm, nullptr,
191061da546Spatrick Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments,
192061da546Spatrick Address::DumpStyle::DumpStyleFileAddress,
193061da546Spatrick arch.GetAddressByteSize());
194061da546Spatrick LLDB_LOGF(log, "Got compact unwind encoding 0x%x for function %s",
195061da546Spatrick function_info.encoding, strm.GetData());
196061da546Spatrick }
197061da546Spatrick
198061da546Spatrick if (function_info.valid_range_offset_start != 0 &&
199061da546Spatrick function_info.valid_range_offset_end != 0) {
200061da546Spatrick SectionList *sl = m_objfile.GetSectionList();
201061da546Spatrick if (sl) {
202061da546Spatrick addr_t func_range_start_file_addr =
203061da546Spatrick function_info.valid_range_offset_start +
204061da546Spatrick m_objfile.GetBaseAddress().GetFileAddress();
205061da546Spatrick AddressRange func_range(func_range_start_file_addr,
206061da546Spatrick function_info.valid_range_offset_end -
207061da546Spatrick function_info.valid_range_offset_start,
208061da546Spatrick sl);
209061da546Spatrick unwind_plan.SetPlanValidAddressRange(func_range);
210061da546Spatrick }
211061da546Spatrick }
212061da546Spatrick
213061da546Spatrick if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
214061da546Spatrick return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
215061da546Spatrick addr);
216061da546Spatrick }
217061da546Spatrick if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||
218061da546Spatrick arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {
219061da546Spatrick return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
220061da546Spatrick }
221061da546Spatrick if (arch.GetTriple().getArch() == llvm::Triple::x86) {
222061da546Spatrick return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
223061da546Spatrick }
224061da546Spatrick if (arch.GetTriple().getArch() == llvm::Triple::arm ||
225061da546Spatrick arch.GetTriple().getArch() == llvm::Triple::thumb) {
226061da546Spatrick return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);
227061da546Spatrick }
228061da546Spatrick }
229061da546Spatrick }
230061da546Spatrick return false;
231061da546Spatrick }
232061da546Spatrick
IsValid(const ProcessSP & process_sp)233061da546Spatrick bool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
234061da546Spatrick if (m_section_sp.get() == nullptr)
235061da546Spatrick return false;
236061da546Spatrick
237061da546Spatrick if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
238061da546Spatrick return true;
239061da546Spatrick
240061da546Spatrick ScanIndex(process_sp);
241061da546Spatrick
242061da546Spatrick return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
243061da546Spatrick }
244061da546Spatrick
ScanIndex(const ProcessSP & process_sp)245061da546Spatrick void CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
246061da546Spatrick std::lock_guard<std::mutex> guard(m_mutex);
247061da546Spatrick if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
248061da546Spatrick return;
249061da546Spatrick
250061da546Spatrick // We can't read the index for some reason.
251061da546Spatrick if (m_indexes_computed == eLazyBoolNo) {
252061da546Spatrick return;
253061da546Spatrick }
254061da546Spatrick
255*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Unwind);
256061da546Spatrick if (log)
257061da546Spatrick m_objfile.GetModule()->LogMessage(
258061da546Spatrick log, "Reading compact unwind first-level indexes");
259061da546Spatrick
260061da546Spatrick if (!m_unwindinfo_data_computed) {
261061da546Spatrick if (m_section_sp->IsEncrypted()) {
262061da546Spatrick // Can't get section contents of a protected/encrypted section until we
263061da546Spatrick // have a live process and can read them out of memory.
264061da546Spatrick if (process_sp.get() == nullptr)
265061da546Spatrick return;
266061da546Spatrick m_section_contents_if_encrypted =
267061da546Spatrick std::make_shared<DataBufferHeap>(m_section_sp->GetByteSize(), 0);
268061da546Spatrick Status error;
269061da546Spatrick if (process_sp->ReadMemory(
270061da546Spatrick m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
271061da546Spatrick m_section_contents_if_encrypted->GetBytes(),
272061da546Spatrick m_section_sp->GetByteSize(),
273061da546Spatrick error) == m_section_sp->GetByteSize() &&
274061da546Spatrick error.Success()) {
275061da546Spatrick m_unwindinfo_data.SetAddressByteSize(
276061da546Spatrick process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
277061da546Spatrick m_unwindinfo_data.SetByteOrder(
278061da546Spatrick process_sp->GetTarget().GetArchitecture().GetByteOrder());
279061da546Spatrick m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);
280061da546Spatrick }
281061da546Spatrick } else {
282061da546Spatrick m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
283061da546Spatrick }
284061da546Spatrick if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
285061da546Spatrick return;
286061da546Spatrick m_unwindinfo_data_computed = true;
287061da546Spatrick }
288061da546Spatrick
289061da546Spatrick if (m_unwindinfo_data.GetByteSize() > 0) {
290061da546Spatrick offset_t offset = 0;
291061da546Spatrick
292061da546Spatrick // struct unwind_info_section_header
293061da546Spatrick // {
294061da546Spatrick // uint32_t version; // UNWIND_SECTION_VERSION
295061da546Spatrick // uint32_t commonEncodingsArraySectionOffset;
296061da546Spatrick // uint32_t commonEncodingsArrayCount;
297061da546Spatrick // uint32_t personalityArraySectionOffset;
298061da546Spatrick // uint32_t personalityArrayCount;
299061da546Spatrick // uint32_t indexSectionOffset;
300061da546Spatrick // uint32_t indexCount;
301061da546Spatrick
302061da546Spatrick m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
303061da546Spatrick m_unwind_header.common_encodings_array_offset =
304061da546Spatrick m_unwindinfo_data.GetU32(&offset);
305061da546Spatrick m_unwind_header.common_encodings_array_count =
306061da546Spatrick m_unwindinfo_data.GetU32(&offset);
307061da546Spatrick m_unwind_header.personality_array_offset =
308061da546Spatrick m_unwindinfo_data.GetU32(&offset);
309061da546Spatrick m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
310061da546Spatrick uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
311061da546Spatrick
312061da546Spatrick uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
313061da546Spatrick
314061da546Spatrick if (m_unwind_header.common_encodings_array_offset >
315061da546Spatrick m_unwindinfo_data.GetByteSize() ||
316061da546Spatrick m_unwind_header.personality_array_offset >
317061da546Spatrick m_unwindinfo_data.GetByteSize() ||
318061da546Spatrick indexSectionOffset > m_unwindinfo_data.GetByteSize() ||
319061da546Spatrick offset > m_unwindinfo_data.GetByteSize()) {
320*f6aab3d8Srobert Debugger::ReportError(
321*f6aab3d8Srobert "Invalid offset encountered in compact unwind info, skipping");
322061da546Spatrick // don't trust anything from this compact_unwind section if it looks
323061da546Spatrick // blatantly invalid data in the header.
324061da546Spatrick m_indexes_computed = eLazyBoolNo;
325061da546Spatrick return;
326061da546Spatrick }
327061da546Spatrick
328061da546Spatrick // Parse the basic information from the indexes We wait to scan the second
329061da546Spatrick // level page info until it's needed
330061da546Spatrick
331061da546Spatrick // struct unwind_info_section_header_index_entry {
332061da546Spatrick // uint32_t functionOffset;
333061da546Spatrick // uint32_t secondLevelPagesSectionOffset;
334061da546Spatrick // uint32_t lsdaIndexArraySectionOffset;
335061da546Spatrick // };
336061da546Spatrick
337061da546Spatrick bool clear_address_zeroth_bit = false;
338061da546Spatrick if (ArchSpec arch = m_objfile.GetArchitecture()) {
339061da546Spatrick if (arch.GetTriple().getArch() == llvm::Triple::arm ||
340061da546Spatrick arch.GetTriple().getArch() == llvm::Triple::thumb)
341061da546Spatrick clear_address_zeroth_bit = true;
342061da546Spatrick }
343061da546Spatrick
344061da546Spatrick offset = indexSectionOffset;
345061da546Spatrick for (uint32_t idx = 0; idx < indexCount; idx++) {
346061da546Spatrick uint32_t function_offset =
347061da546Spatrick m_unwindinfo_data.GetU32(&offset); // functionOffset
348061da546Spatrick uint32_t second_level_offset =
349061da546Spatrick m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
350061da546Spatrick uint32_t lsda_offset =
351061da546Spatrick m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
352061da546Spatrick
353061da546Spatrick if (second_level_offset > m_section_sp->GetByteSize() ||
354061da546Spatrick lsda_offset > m_section_sp->GetByteSize()) {
355061da546Spatrick m_indexes_computed = eLazyBoolNo;
356061da546Spatrick }
357061da546Spatrick
358061da546Spatrick if (clear_address_zeroth_bit)
359061da546Spatrick function_offset &= ~1ull;
360061da546Spatrick
361061da546Spatrick UnwindIndex this_index;
362061da546Spatrick this_index.function_offset = function_offset;
363061da546Spatrick this_index.second_level = second_level_offset;
364061da546Spatrick this_index.lsda_array_start = lsda_offset;
365061da546Spatrick
366061da546Spatrick if (m_indexes.size() > 0) {
367061da546Spatrick m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
368061da546Spatrick }
369061da546Spatrick
370061da546Spatrick if (second_level_offset == 0) {
371061da546Spatrick this_index.sentinal_entry = true;
372061da546Spatrick }
373061da546Spatrick
374061da546Spatrick m_indexes.push_back(this_index);
375061da546Spatrick }
376061da546Spatrick m_indexes_computed = eLazyBoolYes;
377061da546Spatrick } else {
378061da546Spatrick m_indexes_computed = eLazyBoolNo;
379061da546Spatrick }
380061da546Spatrick }
381061da546Spatrick
GetLSDAForFunctionOffset(uint32_t lsda_offset,uint32_t lsda_count,uint32_t function_offset)382061da546Spatrick uint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
383061da546Spatrick uint32_t lsda_count,
384061da546Spatrick uint32_t function_offset) {
385061da546Spatrick // struct unwind_info_section_header_lsda_index_entry {
386061da546Spatrick // uint32_t functionOffset;
387061da546Spatrick // uint32_t lsdaOffset;
388061da546Spatrick // };
389061da546Spatrick
390061da546Spatrick offset_t first_entry = lsda_offset;
391061da546Spatrick uint32_t low = 0;
392061da546Spatrick uint32_t high = lsda_count;
393061da546Spatrick while (low < high) {
394061da546Spatrick uint32_t mid = (low + high) / 2;
395061da546Spatrick offset_t offset = first_entry + (mid * 8);
396061da546Spatrick uint32_t mid_func_offset =
397061da546Spatrick m_unwindinfo_data.GetU32(&offset); // functionOffset
398061da546Spatrick uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
399061da546Spatrick if (mid_func_offset == function_offset) {
400061da546Spatrick return mid_lsda_offset;
401061da546Spatrick }
402061da546Spatrick if (mid_func_offset < function_offset) {
403061da546Spatrick low = mid + 1;
404061da546Spatrick } else {
405061da546Spatrick high = mid;
406061da546Spatrick }
407061da546Spatrick }
408061da546Spatrick return 0;
409061da546Spatrick }
410061da546Spatrick
BinarySearchRegularSecondPage(uint32_t entry_page_offset,uint32_t entry_count,uint32_t function_offset,uint32_t * entry_func_start_offset,uint32_t * entry_func_end_offset)411061da546Spatrick lldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(
412061da546Spatrick uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,
413061da546Spatrick uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
414061da546Spatrick // typedef uint32_t compact_unwind_encoding_t;
415061da546Spatrick // struct unwind_info_regular_second_level_entry {
416061da546Spatrick // uint32_t functionOffset;
417061da546Spatrick // compact_unwind_encoding_t encoding;
418061da546Spatrick
419061da546Spatrick offset_t first_entry = entry_page_offset;
420061da546Spatrick
421061da546Spatrick uint32_t low = 0;
422061da546Spatrick uint32_t high = entry_count;
423061da546Spatrick uint32_t last = high - 1;
424061da546Spatrick while (low < high) {
425061da546Spatrick uint32_t mid = (low + high) / 2;
426061da546Spatrick offset_t offset = first_entry + (mid * 8);
427061da546Spatrick uint32_t mid_func_offset =
428061da546Spatrick m_unwindinfo_data.GetU32(&offset); // functionOffset
429061da546Spatrick uint32_t next_func_offset = 0;
430061da546Spatrick if (mid < last) {
431061da546Spatrick offset = first_entry + ((mid + 1) * 8);
432061da546Spatrick next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
433061da546Spatrick }
434061da546Spatrick if (mid_func_offset <= function_offset) {
435061da546Spatrick if (mid == last || (next_func_offset > function_offset)) {
436061da546Spatrick if (entry_func_start_offset)
437061da546Spatrick *entry_func_start_offset = mid_func_offset;
438061da546Spatrick if (mid != last && entry_func_end_offset)
439061da546Spatrick *entry_func_end_offset = next_func_offset;
440061da546Spatrick return first_entry + (mid * 8);
441061da546Spatrick } else {
442061da546Spatrick low = mid + 1;
443061da546Spatrick }
444061da546Spatrick } else {
445061da546Spatrick high = mid;
446061da546Spatrick }
447061da546Spatrick }
448061da546Spatrick return LLDB_INVALID_OFFSET;
449061da546Spatrick }
450061da546Spatrick
BinarySearchCompressedSecondPage(uint32_t entry_page_offset,uint32_t entry_count,uint32_t function_offset_to_find,uint32_t function_offset_base,uint32_t * entry_func_start_offset,uint32_t * entry_func_end_offset)451061da546Spatrick uint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(
452061da546Spatrick uint32_t entry_page_offset, uint32_t entry_count,
453061da546Spatrick uint32_t function_offset_to_find, uint32_t function_offset_base,
454061da546Spatrick uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
455061da546Spatrick offset_t first_entry = entry_page_offset;
456061da546Spatrick
457061da546Spatrick uint32_t low = 0;
458061da546Spatrick uint32_t high = entry_count;
459061da546Spatrick uint32_t last = high - 1;
460061da546Spatrick while (low < high) {
461061da546Spatrick uint32_t mid = (low + high) / 2;
462061da546Spatrick offset_t offset = first_entry + (mid * 4);
463061da546Spatrick uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
464061da546Spatrick uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
465061da546Spatrick mid_func_offset += function_offset_base;
466061da546Spatrick uint32_t next_func_offset = 0;
467061da546Spatrick if (mid < last) {
468061da546Spatrick offset = first_entry + ((mid + 1) * 4);
469061da546Spatrick uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
470061da546Spatrick next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);
471061da546Spatrick next_func_offset += function_offset_base;
472061da546Spatrick }
473061da546Spatrick if (mid_func_offset <= function_offset_to_find) {
474061da546Spatrick if (mid == last || (next_func_offset > function_offset_to_find)) {
475061da546Spatrick if (entry_func_start_offset)
476061da546Spatrick *entry_func_start_offset = mid_func_offset;
477061da546Spatrick if (mid != last && entry_func_end_offset)
478061da546Spatrick *entry_func_end_offset = next_func_offset;
479061da546Spatrick return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
480061da546Spatrick } else {
481061da546Spatrick low = mid + 1;
482061da546Spatrick }
483061da546Spatrick } else {
484061da546Spatrick high = mid;
485061da546Spatrick }
486061da546Spatrick }
487061da546Spatrick
488061da546Spatrick return UINT32_MAX;
489061da546Spatrick }
490061da546Spatrick
GetCompactUnwindInfoForFunction(Target & target,Address address,FunctionInfo & unwind_info)491061da546Spatrick bool CompactUnwindInfo::GetCompactUnwindInfoForFunction(
492061da546Spatrick Target &target, Address address, FunctionInfo &unwind_info) {
493061da546Spatrick unwind_info.encoding = 0;
494061da546Spatrick unwind_info.lsda_address.Clear();
495061da546Spatrick unwind_info.personality_ptr_address.Clear();
496061da546Spatrick
497061da546Spatrick if (!IsValid(target.GetProcessSP()))
498061da546Spatrick return false;
499061da546Spatrick
500061da546Spatrick addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
501061da546Spatrick SectionList *sl = m_objfile.GetSectionList();
502061da546Spatrick if (sl) {
503061da546Spatrick SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
504061da546Spatrick if (text_sect.get()) {
505061da546Spatrick text_section_file_address = text_sect->GetFileAddress();
506061da546Spatrick }
507061da546Spatrick }
508061da546Spatrick if (text_section_file_address == LLDB_INVALID_ADDRESS)
509061da546Spatrick return false;
510061da546Spatrick
511061da546Spatrick addr_t function_offset =
512061da546Spatrick address.GetFileAddress() - m_objfile.GetBaseAddress().GetFileAddress();
513061da546Spatrick
514061da546Spatrick UnwindIndex key;
515061da546Spatrick key.function_offset = function_offset;
516061da546Spatrick
517061da546Spatrick std::vector<UnwindIndex>::const_iterator it;
518*f6aab3d8Srobert it = llvm::lower_bound(m_indexes, key);
519061da546Spatrick if (it == m_indexes.end()) {
520061da546Spatrick return false;
521061da546Spatrick }
522061da546Spatrick
523061da546Spatrick if (it->function_offset != key.function_offset) {
524061da546Spatrick if (it != m_indexes.begin())
525061da546Spatrick --it;
526061da546Spatrick }
527061da546Spatrick
528061da546Spatrick if (it->sentinal_entry) {
529061da546Spatrick return false;
530061da546Spatrick }
531061da546Spatrick
532061da546Spatrick auto next_it = it + 1;
533061da546Spatrick if (next_it != m_indexes.end()) {
534061da546Spatrick // initialize the function offset end range to be the start of the next
535061da546Spatrick // index offset. If we find an entry which is at the end of the index
536061da546Spatrick // table, this will establish the range end.
537061da546Spatrick unwind_info.valid_range_offset_end = next_it->function_offset;
538061da546Spatrick }
539061da546Spatrick
540061da546Spatrick offset_t second_page_offset = it->second_level;
541061da546Spatrick offset_t lsda_array_start = it->lsda_array_start;
542061da546Spatrick offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
543061da546Spatrick
544061da546Spatrick offset_t offset = second_page_offset;
545061da546Spatrick uint32_t kind = m_unwindinfo_data.GetU32(
546061da546Spatrick &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
547061da546Spatrick
548061da546Spatrick if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
549061da546Spatrick // struct unwind_info_regular_second_level_page_header {
550061da546Spatrick // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
551061da546Spatrick // uint16_t entryPageOffset;
552061da546Spatrick // uint16_t entryCount;
553061da546Spatrick
554061da546Spatrick // typedef uint32_t compact_unwind_encoding_t;
555061da546Spatrick // struct unwind_info_regular_second_level_entry {
556061da546Spatrick // uint32_t functionOffset;
557061da546Spatrick // compact_unwind_encoding_t encoding;
558061da546Spatrick
559061da546Spatrick uint16_t entry_page_offset =
560061da546Spatrick m_unwindinfo_data.GetU16(&offset); // entryPageOffset
561061da546Spatrick uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
562061da546Spatrick
563061da546Spatrick offset_t entry_offset = BinarySearchRegularSecondPage(
564061da546Spatrick second_page_offset + entry_page_offset, entry_count, function_offset,
565061da546Spatrick &unwind_info.valid_range_offset_start,
566061da546Spatrick &unwind_info.valid_range_offset_end);
567061da546Spatrick if (entry_offset == LLDB_INVALID_OFFSET) {
568061da546Spatrick return false;
569061da546Spatrick }
570061da546Spatrick entry_offset += 4; // skip over functionOffset
571061da546Spatrick unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
572061da546Spatrick if (unwind_info.encoding & UNWIND_HAS_LSDA) {
573061da546Spatrick SectionList *sl = m_objfile.GetSectionList();
574061da546Spatrick if (sl) {
575061da546Spatrick uint32_t lsda_offset = GetLSDAForFunctionOffset(
576061da546Spatrick lsda_array_start, lsda_array_count, function_offset);
577061da546Spatrick addr_t objfile_base_address =
578061da546Spatrick m_objfile.GetBaseAddress().GetFileAddress();
579061da546Spatrick unwind_info.lsda_address.ResolveAddressUsingFileSections(
580061da546Spatrick objfile_base_address + lsda_offset, sl);
581061da546Spatrick }
582061da546Spatrick }
583061da546Spatrick if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
584061da546Spatrick uint32_t personality_index =
585061da546Spatrick EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
586061da546Spatrick
587061da546Spatrick if (personality_index > 0) {
588061da546Spatrick personality_index--;
589061da546Spatrick if (personality_index < m_unwind_header.personality_array_count) {
590061da546Spatrick offset_t offset = m_unwind_header.personality_array_offset;
591061da546Spatrick offset += 4 * personality_index;
592061da546Spatrick SectionList *sl = m_objfile.GetSectionList();
593061da546Spatrick if (sl) {
594061da546Spatrick uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
595061da546Spatrick addr_t objfile_base_address =
596061da546Spatrick m_objfile.GetBaseAddress().GetFileAddress();
597061da546Spatrick unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
598061da546Spatrick objfile_base_address + personality_offset, sl);
599061da546Spatrick }
600061da546Spatrick }
601061da546Spatrick }
602061da546Spatrick }
603061da546Spatrick return true;
604061da546Spatrick } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
605061da546Spatrick // struct unwind_info_compressed_second_level_page_header {
606061da546Spatrick // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
607061da546Spatrick // uint16_t entryPageOffset; // offset from this 2nd lvl page
608061da546Spatrick // idx to array of entries
609061da546Spatrick // // (an entry has a function
610061da546Spatrick // offset and index into the
611061da546Spatrick // encodings)
612061da546Spatrick // // NB function offset from the
613061da546Spatrick // entry in the compressed page
614061da546Spatrick // // must be added to the index's
615061da546Spatrick // functionOffset value.
616061da546Spatrick // uint16_t entryCount;
617061da546Spatrick // uint16_t encodingsPageOffset; // offset from this 2nd lvl page
618061da546Spatrick // idx to array of encodings
619061da546Spatrick // uint16_t encodingsCount;
620061da546Spatrick
621061da546Spatrick uint16_t entry_page_offset =
622061da546Spatrick m_unwindinfo_data.GetU16(&offset); // entryPageOffset
623061da546Spatrick uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
624061da546Spatrick uint16_t encodings_page_offset =
625061da546Spatrick m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
626061da546Spatrick uint16_t encodings_count =
627061da546Spatrick m_unwindinfo_data.GetU16(&offset); // encodingsCount
628061da546Spatrick
629061da546Spatrick uint32_t encoding_index = BinarySearchCompressedSecondPage(
630061da546Spatrick second_page_offset + entry_page_offset, entry_count, function_offset,
631061da546Spatrick it->function_offset, &unwind_info.valid_range_offset_start,
632061da546Spatrick &unwind_info.valid_range_offset_end);
633061da546Spatrick if (encoding_index == UINT32_MAX ||
634061da546Spatrick encoding_index >=
635061da546Spatrick encodings_count + m_unwind_header.common_encodings_array_count) {
636061da546Spatrick return false;
637061da546Spatrick }
638061da546Spatrick uint32_t encoding = 0;
639061da546Spatrick if (encoding_index < m_unwind_header.common_encodings_array_count) {
640061da546Spatrick offset = m_unwind_header.common_encodings_array_offset +
641061da546Spatrick (encoding_index * sizeof(uint32_t));
642061da546Spatrick encoding = m_unwindinfo_data.GetU32(
643061da546Spatrick &offset); // encoding entry from the commonEncodingsArray
644061da546Spatrick } else {
645061da546Spatrick uint32_t page_specific_entry_index =
646061da546Spatrick encoding_index - m_unwind_header.common_encodings_array_count;
647061da546Spatrick offset = second_page_offset + encodings_page_offset +
648061da546Spatrick (page_specific_entry_index * sizeof(uint32_t));
649061da546Spatrick encoding = m_unwindinfo_data.GetU32(
650061da546Spatrick &offset); // encoding entry from the page-specific encoding array
651061da546Spatrick }
652061da546Spatrick if (encoding == 0)
653061da546Spatrick return false;
654061da546Spatrick
655061da546Spatrick unwind_info.encoding = encoding;
656061da546Spatrick if (unwind_info.encoding & UNWIND_HAS_LSDA) {
657061da546Spatrick SectionList *sl = m_objfile.GetSectionList();
658061da546Spatrick if (sl) {
659061da546Spatrick uint32_t lsda_offset = GetLSDAForFunctionOffset(
660061da546Spatrick lsda_array_start, lsda_array_count, function_offset);
661061da546Spatrick addr_t objfile_base_address =
662061da546Spatrick m_objfile.GetBaseAddress().GetFileAddress();
663061da546Spatrick unwind_info.lsda_address.ResolveAddressUsingFileSections(
664061da546Spatrick objfile_base_address + lsda_offset, sl);
665061da546Spatrick }
666061da546Spatrick }
667061da546Spatrick if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
668061da546Spatrick uint32_t personality_index =
669061da546Spatrick EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
670061da546Spatrick
671061da546Spatrick if (personality_index > 0) {
672061da546Spatrick personality_index--;
673061da546Spatrick if (personality_index < m_unwind_header.personality_array_count) {
674061da546Spatrick offset_t offset = m_unwind_header.personality_array_offset;
675061da546Spatrick offset += 4 * personality_index;
676061da546Spatrick SectionList *sl = m_objfile.GetSectionList();
677061da546Spatrick if (sl) {
678061da546Spatrick uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
679061da546Spatrick addr_t objfile_base_address =
680061da546Spatrick m_objfile.GetBaseAddress().GetFileAddress();
681061da546Spatrick unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
682061da546Spatrick objfile_base_address + personality_offset, sl);
683061da546Spatrick }
684061da546Spatrick }
685061da546Spatrick }
686061da546Spatrick }
687061da546Spatrick return true;
688061da546Spatrick }
689061da546Spatrick return false;
690061da546Spatrick }
691061da546Spatrick
692061da546Spatrick enum x86_64_eh_regnum {
693061da546Spatrick rax = 0,
694061da546Spatrick rdx = 1,
695061da546Spatrick rcx = 2,
696061da546Spatrick rbx = 3,
697061da546Spatrick rsi = 4,
698061da546Spatrick rdi = 5,
699061da546Spatrick rbp = 6,
700061da546Spatrick rsp = 7,
701061da546Spatrick r8 = 8,
702061da546Spatrick r9 = 9,
703061da546Spatrick r10 = 10,
704061da546Spatrick r11 = 11,
705061da546Spatrick r12 = 12,
706061da546Spatrick r13 = 13,
707061da546Spatrick r14 = 14,
708061da546Spatrick r15 = 15,
709061da546Spatrick rip = 16 // this is officially the Return Address register number, but close
710061da546Spatrick // enough
711061da546Spatrick };
712061da546Spatrick
713061da546Spatrick // Convert the compact_unwind_info.h register numbering scheme to
714061da546Spatrick // eRegisterKindEHFrame (eh_frame) register numbering scheme.
translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno)715061da546Spatrick uint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {
716061da546Spatrick switch (unwind_regno) {
717061da546Spatrick case UNWIND_X86_64_REG_RBX:
718061da546Spatrick return x86_64_eh_regnum::rbx;
719061da546Spatrick case UNWIND_X86_64_REG_R12:
720061da546Spatrick return x86_64_eh_regnum::r12;
721061da546Spatrick case UNWIND_X86_64_REG_R13:
722061da546Spatrick return x86_64_eh_regnum::r13;
723061da546Spatrick case UNWIND_X86_64_REG_R14:
724061da546Spatrick return x86_64_eh_regnum::r14;
725061da546Spatrick case UNWIND_X86_64_REG_R15:
726061da546Spatrick return x86_64_eh_regnum::r15;
727061da546Spatrick case UNWIND_X86_64_REG_RBP:
728061da546Spatrick return x86_64_eh_regnum::rbp;
729061da546Spatrick default:
730061da546Spatrick return LLDB_INVALID_REGNUM;
731061da546Spatrick }
732061da546Spatrick }
733061da546Spatrick
CreateUnwindPlan_x86_64(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)734061da546Spatrick bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
735061da546Spatrick FunctionInfo &function_info,
736061da546Spatrick UnwindPlan &unwind_plan,
737061da546Spatrick Address pc_or_function_start) {
738061da546Spatrick unwind_plan.SetSourceName("compact unwind info");
739061da546Spatrick unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
740061da546Spatrick unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
741061da546Spatrick unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
742061da546Spatrick unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
743061da546Spatrick
744061da546Spatrick unwind_plan.SetLSDAAddress(function_info.lsda_address);
745061da546Spatrick unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
746061da546Spatrick
747061da546Spatrick UnwindPlan::RowSP row(new UnwindPlan::Row);
748061da546Spatrick
749061da546Spatrick const int wordsize = 8;
750061da546Spatrick int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
751061da546Spatrick switch (mode) {
752061da546Spatrick case UNWIND_X86_64_MODE_RBP_FRAME: {
753061da546Spatrick row->GetCFAValue().SetIsRegisterPlusOffset(
754061da546Spatrick translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),
755061da546Spatrick 2 * wordsize);
756061da546Spatrick row->SetOffset(0);
757061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,
758061da546Spatrick wordsize * -2, true);
759061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
760061da546Spatrick wordsize * -1, true);
761061da546Spatrick row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
762061da546Spatrick
763061da546Spatrick uint32_t saved_registers_offset =
764061da546Spatrick EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
765061da546Spatrick
766061da546Spatrick uint32_t saved_registers_locations =
767061da546Spatrick EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
768061da546Spatrick
769061da546Spatrick saved_registers_offset += 2;
770061da546Spatrick
771061da546Spatrick for (int i = 0; i < 5; i++) {
772061da546Spatrick uint32_t regnum = saved_registers_locations & 0x7;
773061da546Spatrick switch (regnum) {
774061da546Spatrick case UNWIND_X86_64_REG_NONE:
775061da546Spatrick break;
776061da546Spatrick case UNWIND_X86_64_REG_RBX:
777061da546Spatrick case UNWIND_X86_64_REG_R12:
778061da546Spatrick case UNWIND_X86_64_REG_R13:
779061da546Spatrick case UNWIND_X86_64_REG_R14:
780061da546Spatrick case UNWIND_X86_64_REG_R15:
781061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(
782061da546Spatrick translate_to_eh_frame_regnum_x86_64(regnum),
783061da546Spatrick wordsize * -saved_registers_offset, true);
784061da546Spatrick break;
785061da546Spatrick }
786061da546Spatrick saved_registers_offset--;
787061da546Spatrick saved_registers_locations >>= 3;
788061da546Spatrick }
789061da546Spatrick unwind_plan.AppendRow(row);
790061da546Spatrick return true;
791061da546Spatrick } break;
792061da546Spatrick
793061da546Spatrick case UNWIND_X86_64_MODE_STACK_IND: {
794061da546Spatrick // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
795061da546Spatrick // this style of unwind. It was fixed in llvm r217020. The clang in Xcode
796061da546Spatrick // 7 has this fixed.
797061da546Spatrick return false;
798061da546Spatrick } break;
799061da546Spatrick
800061da546Spatrick case UNWIND_X86_64_MODE_STACK_IMMD: {
801061da546Spatrick uint32_t stack_size = EXTRACT_BITS(function_info.encoding,
802061da546Spatrick UNWIND_X86_64_FRAMELESS_STACK_SIZE);
803061da546Spatrick uint32_t register_count = EXTRACT_BITS(
804061da546Spatrick function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
805061da546Spatrick uint32_t permutation = EXTRACT_BITS(
806061da546Spatrick function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
807061da546Spatrick
808061da546Spatrick if (mode == UNWIND_X86_64_MODE_STACK_IND &&
809061da546Spatrick function_info.valid_range_offset_start != 0) {
810061da546Spatrick uint32_t stack_adjust = EXTRACT_BITS(
811061da546Spatrick function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
812061da546Spatrick
813061da546Spatrick // offset into the function instructions; 0 == beginning of first
814061da546Spatrick // instruction
815061da546Spatrick uint32_t offset_to_subl_insn = EXTRACT_BITS(
816061da546Spatrick function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
817061da546Spatrick
818061da546Spatrick SectionList *sl = m_objfile.GetSectionList();
819061da546Spatrick if (sl) {
820061da546Spatrick ProcessSP process_sp = target.GetProcessSP();
821061da546Spatrick if (process_sp) {
822061da546Spatrick Address subl_payload_addr(function_info.valid_range_offset_start, sl);
823061da546Spatrick subl_payload_addr.Slide(offset_to_subl_insn);
824061da546Spatrick Status error;
825061da546Spatrick uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
826061da546Spatrick subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
827061da546Spatrick if (large_stack_size != 0 && error.Success()) {
828061da546Spatrick // Got the large stack frame size correctly - use it
829061da546Spatrick stack_size = large_stack_size + (stack_adjust * wordsize);
830061da546Spatrick } else {
831061da546Spatrick return false;
832061da546Spatrick }
833061da546Spatrick } else {
834061da546Spatrick return false;
835061da546Spatrick }
836061da546Spatrick } else {
837061da546Spatrick return false;
838061da546Spatrick }
839061da546Spatrick }
840061da546Spatrick
841061da546Spatrick int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
842061da546Spatrick ? stack_size
843061da546Spatrick : stack_size * wordsize;
844061da546Spatrick row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
845061da546Spatrick
846061da546Spatrick row->SetOffset(0);
847061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
848061da546Spatrick wordsize * -1, true);
849061da546Spatrick row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
850061da546Spatrick
851061da546Spatrick if (register_count > 0) {
852061da546Spatrick
853061da546Spatrick // We need to include (up to) 6 registers in 10 bits. That would be 18
854061da546Spatrick // bits if we just used 3 bits per reg to indicate the order they're
855061da546Spatrick // saved on the stack.
856061da546Spatrick //
857061da546Spatrick // This is done with Lehmer code permutation, e.g. see
858061da546Spatrick // http://stackoverflow.com/questions/1506078/fast-permutation-number-
859061da546Spatrick // permutation-mapping-algorithms
860061da546Spatrick int permunreg[6] = {0, 0, 0, 0, 0, 0};
861061da546Spatrick
862061da546Spatrick // This decodes the variable-base number in the 10 bits and gives us the
863061da546Spatrick // Lehmer code sequence which can then be decoded.
864061da546Spatrick
865061da546Spatrick switch (register_count) {
866061da546Spatrick case 6:
867061da546Spatrick permunreg[0] = permutation / 120; // 120 == 5!
868061da546Spatrick permutation -= (permunreg[0] * 120);
869061da546Spatrick permunreg[1] = permutation / 24; // 24 == 4!
870061da546Spatrick permutation -= (permunreg[1] * 24);
871061da546Spatrick permunreg[2] = permutation / 6; // 6 == 3!
872061da546Spatrick permutation -= (permunreg[2] * 6);
873061da546Spatrick permunreg[3] = permutation / 2; // 2 == 2!
874061da546Spatrick permutation -= (permunreg[3] * 2);
875061da546Spatrick permunreg[4] = permutation; // 1 == 1!
876061da546Spatrick permunreg[5] = 0;
877061da546Spatrick break;
878061da546Spatrick case 5:
879061da546Spatrick permunreg[0] = permutation / 120;
880061da546Spatrick permutation -= (permunreg[0] * 120);
881061da546Spatrick permunreg[1] = permutation / 24;
882061da546Spatrick permutation -= (permunreg[1] * 24);
883061da546Spatrick permunreg[2] = permutation / 6;
884061da546Spatrick permutation -= (permunreg[2] * 6);
885061da546Spatrick permunreg[3] = permutation / 2;
886061da546Spatrick permutation -= (permunreg[3] * 2);
887061da546Spatrick permunreg[4] = permutation;
888061da546Spatrick break;
889061da546Spatrick case 4:
890061da546Spatrick permunreg[0] = permutation / 60;
891061da546Spatrick permutation -= (permunreg[0] * 60);
892061da546Spatrick permunreg[1] = permutation / 12;
893061da546Spatrick permutation -= (permunreg[1] * 12);
894061da546Spatrick permunreg[2] = permutation / 3;
895061da546Spatrick permutation -= (permunreg[2] * 3);
896061da546Spatrick permunreg[3] = permutation;
897061da546Spatrick break;
898061da546Spatrick case 3:
899061da546Spatrick permunreg[0] = permutation / 20;
900061da546Spatrick permutation -= (permunreg[0] * 20);
901061da546Spatrick permunreg[1] = permutation / 4;
902061da546Spatrick permutation -= (permunreg[1] * 4);
903061da546Spatrick permunreg[2] = permutation;
904061da546Spatrick break;
905061da546Spatrick case 2:
906061da546Spatrick permunreg[0] = permutation / 5;
907061da546Spatrick permutation -= (permunreg[0] * 5);
908061da546Spatrick permunreg[1] = permutation;
909061da546Spatrick break;
910061da546Spatrick case 1:
911061da546Spatrick permunreg[0] = permutation;
912061da546Spatrick break;
913061da546Spatrick }
914061da546Spatrick
915061da546Spatrick // Decode the Lehmer code for this permutation of the registers v.
916061da546Spatrick // http://en.wikipedia.org/wiki/Lehmer_code
917061da546Spatrick
918061da546Spatrick int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
919061da546Spatrick UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
920061da546Spatrick UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
921061da546Spatrick bool used[7] = {false, false, false, false, false, false, false};
922061da546Spatrick for (uint32_t i = 0; i < register_count; i++) {
923061da546Spatrick int renum = 0;
924061da546Spatrick for (int j = 1; j < 7; j++) {
925061da546Spatrick if (!used[j]) {
926061da546Spatrick if (renum == permunreg[i]) {
927061da546Spatrick registers[i] = j;
928061da546Spatrick used[j] = true;
929061da546Spatrick break;
930061da546Spatrick }
931061da546Spatrick renum++;
932061da546Spatrick }
933061da546Spatrick }
934061da546Spatrick }
935061da546Spatrick
936061da546Spatrick uint32_t saved_registers_offset = 1;
937061da546Spatrick saved_registers_offset++;
938061da546Spatrick
939061da546Spatrick for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
940061da546Spatrick switch (registers[i]) {
941061da546Spatrick case UNWIND_X86_64_REG_NONE:
942061da546Spatrick break;
943061da546Spatrick case UNWIND_X86_64_REG_RBX:
944061da546Spatrick case UNWIND_X86_64_REG_R12:
945061da546Spatrick case UNWIND_X86_64_REG_R13:
946061da546Spatrick case UNWIND_X86_64_REG_R14:
947061da546Spatrick case UNWIND_X86_64_REG_R15:
948061da546Spatrick case UNWIND_X86_64_REG_RBP:
949061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(
950061da546Spatrick translate_to_eh_frame_regnum_x86_64(registers[i]),
951061da546Spatrick wordsize * -saved_registers_offset, true);
952061da546Spatrick saved_registers_offset++;
953061da546Spatrick break;
954061da546Spatrick }
955061da546Spatrick }
956061da546Spatrick }
957061da546Spatrick unwind_plan.AppendRow(row);
958061da546Spatrick return true;
959061da546Spatrick } break;
960061da546Spatrick
961061da546Spatrick case UNWIND_X86_64_MODE_DWARF: {
962061da546Spatrick return false;
963061da546Spatrick } break;
964061da546Spatrick
965061da546Spatrick case 0: {
966061da546Spatrick return false;
967061da546Spatrick } break;
968061da546Spatrick }
969061da546Spatrick return false;
970061da546Spatrick }
971061da546Spatrick
972061da546Spatrick enum i386_eh_regnum {
973061da546Spatrick eax = 0,
974061da546Spatrick ecx = 1,
975061da546Spatrick edx = 2,
976061da546Spatrick ebx = 3,
977061da546Spatrick ebp = 4,
978061da546Spatrick esp = 5,
979061da546Spatrick esi = 6,
980061da546Spatrick edi = 7,
981061da546Spatrick eip = 8 // this is officially the Return Address register number, but close
982061da546Spatrick // enough
983061da546Spatrick };
984061da546Spatrick
985061da546Spatrick // Convert the compact_unwind_info.h register numbering scheme to
986061da546Spatrick // eRegisterKindEHFrame (eh_frame) register numbering scheme.
translate_to_eh_frame_regnum_i386(uint32_t unwind_regno)987061da546Spatrick uint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {
988061da546Spatrick switch (unwind_regno) {
989061da546Spatrick case UNWIND_X86_REG_EBX:
990061da546Spatrick return i386_eh_regnum::ebx;
991061da546Spatrick case UNWIND_X86_REG_ECX:
992061da546Spatrick return i386_eh_regnum::ecx;
993061da546Spatrick case UNWIND_X86_REG_EDX:
994061da546Spatrick return i386_eh_regnum::edx;
995061da546Spatrick case UNWIND_X86_REG_EDI:
996061da546Spatrick return i386_eh_regnum::edi;
997061da546Spatrick case UNWIND_X86_REG_ESI:
998061da546Spatrick return i386_eh_regnum::esi;
999061da546Spatrick case UNWIND_X86_REG_EBP:
1000061da546Spatrick return i386_eh_regnum::ebp;
1001061da546Spatrick default:
1002061da546Spatrick return LLDB_INVALID_REGNUM;
1003061da546Spatrick }
1004061da546Spatrick }
1005061da546Spatrick
CreateUnwindPlan_i386(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)1006061da546Spatrick bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
1007061da546Spatrick FunctionInfo &function_info,
1008061da546Spatrick UnwindPlan &unwind_plan,
1009061da546Spatrick Address pc_or_function_start) {
1010061da546Spatrick unwind_plan.SetSourceName("compact unwind info");
1011061da546Spatrick unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1012061da546Spatrick unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1013061da546Spatrick unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1014061da546Spatrick unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1015061da546Spatrick
1016061da546Spatrick unwind_plan.SetLSDAAddress(function_info.lsda_address);
1017061da546Spatrick unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1018061da546Spatrick
1019061da546Spatrick UnwindPlan::RowSP row(new UnwindPlan::Row);
1020061da546Spatrick
1021061da546Spatrick const int wordsize = 4;
1022061da546Spatrick int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1023061da546Spatrick switch (mode) {
1024061da546Spatrick case UNWIND_X86_MODE_EBP_FRAME: {
1025061da546Spatrick row->GetCFAValue().SetIsRegisterPlusOffset(
1026061da546Spatrick translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
1027061da546Spatrick row->SetOffset(0);
1028061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,
1029061da546Spatrick wordsize * -2, true);
1030061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1031061da546Spatrick wordsize * -1, true);
1032061da546Spatrick row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1033061da546Spatrick
1034061da546Spatrick uint32_t saved_registers_offset =
1035061da546Spatrick EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1036061da546Spatrick
1037061da546Spatrick uint32_t saved_registers_locations =
1038061da546Spatrick EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1039061da546Spatrick
1040061da546Spatrick saved_registers_offset += 2;
1041061da546Spatrick
1042061da546Spatrick for (int i = 0; i < 5; i++) {
1043061da546Spatrick uint32_t regnum = saved_registers_locations & 0x7;
1044061da546Spatrick switch (regnum) {
1045061da546Spatrick case UNWIND_X86_REG_NONE:
1046061da546Spatrick break;
1047061da546Spatrick case UNWIND_X86_REG_EBX:
1048061da546Spatrick case UNWIND_X86_REG_ECX:
1049061da546Spatrick case UNWIND_X86_REG_EDX:
1050061da546Spatrick case UNWIND_X86_REG_EDI:
1051061da546Spatrick case UNWIND_X86_REG_ESI:
1052061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(
1053061da546Spatrick translate_to_eh_frame_regnum_i386(regnum),
1054061da546Spatrick wordsize * -saved_registers_offset, true);
1055061da546Spatrick break;
1056061da546Spatrick }
1057061da546Spatrick saved_registers_offset--;
1058061da546Spatrick saved_registers_locations >>= 3;
1059061da546Spatrick }
1060061da546Spatrick unwind_plan.AppendRow(row);
1061061da546Spatrick return true;
1062061da546Spatrick } break;
1063061da546Spatrick
1064061da546Spatrick case UNWIND_X86_MODE_STACK_IND:
1065061da546Spatrick case UNWIND_X86_MODE_STACK_IMMD: {
1066061da546Spatrick uint32_t stack_size =
1067061da546Spatrick EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1068061da546Spatrick uint32_t register_count = EXTRACT_BITS(
1069061da546Spatrick function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1070061da546Spatrick uint32_t permutation = EXTRACT_BITS(
1071061da546Spatrick function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
1072061da546Spatrick
1073061da546Spatrick if (mode == UNWIND_X86_MODE_STACK_IND &&
1074061da546Spatrick function_info.valid_range_offset_start != 0) {
1075061da546Spatrick uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,
1076061da546Spatrick UNWIND_X86_FRAMELESS_STACK_ADJUST);
1077061da546Spatrick
1078061da546Spatrick // offset into the function instructions; 0 == beginning of first
1079061da546Spatrick // instruction
1080061da546Spatrick uint32_t offset_to_subl_insn =
1081061da546Spatrick EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1082061da546Spatrick
1083061da546Spatrick SectionList *sl = m_objfile.GetSectionList();
1084061da546Spatrick if (sl) {
1085061da546Spatrick ProcessSP process_sp = target.GetProcessSP();
1086061da546Spatrick if (process_sp) {
1087061da546Spatrick Address subl_payload_addr(function_info.valid_range_offset_start, sl);
1088061da546Spatrick subl_payload_addr.Slide(offset_to_subl_insn);
1089061da546Spatrick Status error;
1090061da546Spatrick uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
1091061da546Spatrick subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
1092061da546Spatrick if (large_stack_size != 0 && error.Success()) {
1093061da546Spatrick // Got the large stack frame size correctly - use it
1094061da546Spatrick stack_size = large_stack_size + (stack_adjust * wordsize);
1095061da546Spatrick } else {
1096061da546Spatrick return false;
1097061da546Spatrick }
1098061da546Spatrick } else {
1099061da546Spatrick return false;
1100061da546Spatrick }
1101061da546Spatrick } else {
1102061da546Spatrick return false;
1103061da546Spatrick }
1104061da546Spatrick }
1105061da546Spatrick
1106061da546Spatrick int32_t offset =
1107061da546Spatrick mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1108061da546Spatrick row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
1109061da546Spatrick row->SetOffset(0);
1110061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1111061da546Spatrick wordsize * -1, true);
1112061da546Spatrick row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1113061da546Spatrick
1114061da546Spatrick if (register_count > 0) {
1115061da546Spatrick
1116061da546Spatrick // We need to include (up to) 6 registers in 10 bits. That would be 18
1117061da546Spatrick // bits if we just used 3 bits per reg to indicate the order they're
1118061da546Spatrick // saved on the stack.
1119061da546Spatrick //
1120061da546Spatrick // This is done with Lehmer code permutation, e.g. see
1121061da546Spatrick // http://stackoverflow.com/questions/1506078/fast-permutation-number-
1122061da546Spatrick // permutation-mapping-algorithms
1123061da546Spatrick int permunreg[6] = {0, 0, 0, 0, 0, 0};
1124061da546Spatrick
1125061da546Spatrick // This decodes the variable-base number in the 10 bits and gives us the
1126061da546Spatrick // Lehmer code sequence which can then be decoded.
1127061da546Spatrick
1128061da546Spatrick switch (register_count) {
1129061da546Spatrick case 6:
1130061da546Spatrick permunreg[0] = permutation / 120; // 120 == 5!
1131061da546Spatrick permutation -= (permunreg[0] * 120);
1132061da546Spatrick permunreg[1] = permutation / 24; // 24 == 4!
1133061da546Spatrick permutation -= (permunreg[1] * 24);
1134061da546Spatrick permunreg[2] = permutation / 6; // 6 == 3!
1135061da546Spatrick permutation -= (permunreg[2] * 6);
1136061da546Spatrick permunreg[3] = permutation / 2; // 2 == 2!
1137061da546Spatrick permutation -= (permunreg[3] * 2);
1138061da546Spatrick permunreg[4] = permutation; // 1 == 1!
1139061da546Spatrick permunreg[5] = 0;
1140061da546Spatrick break;
1141061da546Spatrick case 5:
1142061da546Spatrick permunreg[0] = permutation / 120;
1143061da546Spatrick permutation -= (permunreg[0] * 120);
1144061da546Spatrick permunreg[1] = permutation / 24;
1145061da546Spatrick permutation -= (permunreg[1] * 24);
1146061da546Spatrick permunreg[2] = permutation / 6;
1147061da546Spatrick permutation -= (permunreg[2] * 6);
1148061da546Spatrick permunreg[3] = permutation / 2;
1149061da546Spatrick permutation -= (permunreg[3] * 2);
1150061da546Spatrick permunreg[4] = permutation;
1151061da546Spatrick break;
1152061da546Spatrick case 4:
1153061da546Spatrick permunreg[0] = permutation / 60;
1154061da546Spatrick permutation -= (permunreg[0] * 60);
1155061da546Spatrick permunreg[1] = permutation / 12;
1156061da546Spatrick permutation -= (permunreg[1] * 12);
1157061da546Spatrick permunreg[2] = permutation / 3;
1158061da546Spatrick permutation -= (permunreg[2] * 3);
1159061da546Spatrick permunreg[3] = permutation;
1160061da546Spatrick break;
1161061da546Spatrick case 3:
1162061da546Spatrick permunreg[0] = permutation / 20;
1163061da546Spatrick permutation -= (permunreg[0] * 20);
1164061da546Spatrick permunreg[1] = permutation / 4;
1165061da546Spatrick permutation -= (permunreg[1] * 4);
1166061da546Spatrick permunreg[2] = permutation;
1167061da546Spatrick break;
1168061da546Spatrick case 2:
1169061da546Spatrick permunreg[0] = permutation / 5;
1170061da546Spatrick permutation -= (permunreg[0] * 5);
1171061da546Spatrick permunreg[1] = permutation;
1172061da546Spatrick break;
1173061da546Spatrick case 1:
1174061da546Spatrick permunreg[0] = permutation;
1175061da546Spatrick break;
1176061da546Spatrick }
1177061da546Spatrick
1178061da546Spatrick // Decode the Lehmer code for this permutation of the registers v.
1179061da546Spatrick // http://en.wikipedia.org/wiki/Lehmer_code
1180061da546Spatrick
1181061da546Spatrick int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1182061da546Spatrick UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1183061da546Spatrick UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};
1184061da546Spatrick bool used[7] = {false, false, false, false, false, false, false};
1185061da546Spatrick for (uint32_t i = 0; i < register_count; i++) {
1186061da546Spatrick int renum = 0;
1187061da546Spatrick for (int j = 1; j < 7; j++) {
1188061da546Spatrick if (!used[j]) {
1189061da546Spatrick if (renum == permunreg[i]) {
1190061da546Spatrick registers[i] = j;
1191061da546Spatrick used[j] = true;
1192061da546Spatrick break;
1193061da546Spatrick }
1194061da546Spatrick renum++;
1195061da546Spatrick }
1196061da546Spatrick }
1197061da546Spatrick }
1198061da546Spatrick
1199061da546Spatrick uint32_t saved_registers_offset = 1;
1200061da546Spatrick saved_registers_offset++;
1201061da546Spatrick
1202061da546Spatrick for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1203061da546Spatrick switch (registers[i]) {
1204061da546Spatrick case UNWIND_X86_REG_NONE:
1205061da546Spatrick break;
1206061da546Spatrick case UNWIND_X86_REG_EBX:
1207061da546Spatrick case UNWIND_X86_REG_ECX:
1208061da546Spatrick case UNWIND_X86_REG_EDX:
1209061da546Spatrick case UNWIND_X86_REG_EDI:
1210061da546Spatrick case UNWIND_X86_REG_ESI:
1211061da546Spatrick case UNWIND_X86_REG_EBP:
1212061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(
1213061da546Spatrick translate_to_eh_frame_regnum_i386(registers[i]),
1214061da546Spatrick wordsize * -saved_registers_offset, true);
1215061da546Spatrick saved_registers_offset++;
1216061da546Spatrick break;
1217061da546Spatrick }
1218061da546Spatrick }
1219061da546Spatrick }
1220061da546Spatrick
1221061da546Spatrick unwind_plan.AppendRow(row);
1222061da546Spatrick return true;
1223061da546Spatrick } break;
1224061da546Spatrick
1225061da546Spatrick case UNWIND_X86_MODE_DWARF: {
1226061da546Spatrick return false;
1227061da546Spatrick } break;
1228061da546Spatrick }
1229061da546Spatrick return false;
1230061da546Spatrick }
1231061da546Spatrick
1232061da546Spatrick // DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1233061da546Spatrick // doc by ARM
1234061da546Spatrick
1235061da546Spatrick enum arm64_eh_regnum {
1236061da546Spatrick x19 = 19,
1237061da546Spatrick x20 = 20,
1238061da546Spatrick x21 = 21,
1239061da546Spatrick x22 = 22,
1240061da546Spatrick x23 = 23,
1241061da546Spatrick x24 = 24,
1242061da546Spatrick x25 = 25,
1243061da546Spatrick x26 = 26,
1244061da546Spatrick x27 = 27,
1245061da546Spatrick x28 = 28,
1246061da546Spatrick
1247061da546Spatrick fp = 29,
1248061da546Spatrick ra = 30,
1249061da546Spatrick sp = 31,
1250061da546Spatrick pc = 32,
1251061da546Spatrick
1252061da546Spatrick // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
1253061da546Spatrick // for the 64-bit fp regs. Normally in DWARF it's context sensitive - so it
1254061da546Spatrick // knows it is fetching a 32- or 64-bit quantity from reg v8 to indicate s0
1255061da546Spatrick // or d0 - but the unwinder is operating at a lower level and we'd try to
1256061da546Spatrick // fetch 128 bits if we were told that v8 were stored on the stack...
1257061da546Spatrick v8 = 72,
1258061da546Spatrick v9 = 73,
1259061da546Spatrick v10 = 74,
1260061da546Spatrick v11 = 75,
1261061da546Spatrick v12 = 76,
1262061da546Spatrick v13 = 77,
1263061da546Spatrick v14 = 78,
1264061da546Spatrick v15 = 79,
1265061da546Spatrick };
1266061da546Spatrick
1267061da546Spatrick enum arm_eh_regnum {
1268061da546Spatrick arm_r0 = 0,
1269061da546Spatrick arm_r1 = 1,
1270061da546Spatrick arm_r2 = 2,
1271061da546Spatrick arm_r3 = 3,
1272061da546Spatrick arm_r4 = 4,
1273061da546Spatrick arm_r5 = 5,
1274061da546Spatrick arm_r6 = 6,
1275061da546Spatrick arm_r7 = 7,
1276061da546Spatrick arm_r8 = 8,
1277061da546Spatrick arm_r9 = 9,
1278061da546Spatrick arm_r10 = 10,
1279061da546Spatrick arm_r11 = 11,
1280061da546Spatrick arm_r12 = 12,
1281061da546Spatrick
1282061da546Spatrick arm_sp = 13,
1283061da546Spatrick arm_lr = 14,
1284061da546Spatrick arm_pc = 15,
1285061da546Spatrick
1286061da546Spatrick arm_d0 = 256,
1287061da546Spatrick arm_d1 = 257,
1288061da546Spatrick arm_d2 = 258,
1289061da546Spatrick arm_d3 = 259,
1290061da546Spatrick arm_d4 = 260,
1291061da546Spatrick arm_d5 = 261,
1292061da546Spatrick arm_d6 = 262,
1293061da546Spatrick arm_d7 = 263,
1294061da546Spatrick arm_d8 = 264,
1295061da546Spatrick arm_d9 = 265,
1296061da546Spatrick arm_d10 = 266,
1297061da546Spatrick arm_d11 = 267,
1298061da546Spatrick arm_d12 = 268,
1299061da546Spatrick arm_d13 = 269,
1300061da546Spatrick arm_d14 = 270,
1301061da546Spatrick };
1302061da546Spatrick
CreateUnwindPlan_arm64(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)1303061da546Spatrick bool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
1304061da546Spatrick FunctionInfo &function_info,
1305061da546Spatrick UnwindPlan &unwind_plan,
1306061da546Spatrick Address pc_or_function_start) {
1307061da546Spatrick unwind_plan.SetSourceName("compact unwind info");
1308061da546Spatrick unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1309061da546Spatrick unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1310061da546Spatrick unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1311061da546Spatrick unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1312061da546Spatrick
1313061da546Spatrick unwind_plan.SetLSDAAddress(function_info.lsda_address);
1314061da546Spatrick unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1315061da546Spatrick
1316061da546Spatrick UnwindPlan::RowSP row(new UnwindPlan::Row);
1317061da546Spatrick
1318061da546Spatrick const int wordsize = 8;
1319061da546Spatrick int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
1320061da546Spatrick
1321061da546Spatrick if (mode == UNWIND_ARM64_MODE_DWARF)
1322061da546Spatrick return false;
1323061da546Spatrick
1324061da546Spatrick if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1325061da546Spatrick row->SetOffset(0);
1326061da546Spatrick
1327061da546Spatrick uint32_t stack_size =
1328061da546Spatrick (EXTRACT_BITS(function_info.encoding,
1329061da546Spatrick UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1330061da546Spatrick 16;
1331061da546Spatrick
1332061da546Spatrick // Our previous Call Frame Address is the stack pointer plus the stack size
1333061da546Spatrick row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
1334061da546Spatrick
1335061da546Spatrick // Our previous PC is in the LR
1336061da546Spatrick row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1337061da546Spatrick true);
1338061da546Spatrick
1339061da546Spatrick unwind_plan.AppendRow(row);
1340061da546Spatrick return true;
1341061da546Spatrick }
1342061da546Spatrick
1343061da546Spatrick // Should not be possible
1344061da546Spatrick if (mode != UNWIND_ARM64_MODE_FRAME)
1345061da546Spatrick return false;
1346061da546Spatrick
1347061da546Spatrick // mode == UNWIND_ARM64_MODE_FRAME
1348061da546Spatrick
1349061da546Spatrick row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1350061da546Spatrick row->SetOffset(0);
1351061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1352061da546Spatrick true);
1353061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1354061da546Spatrick true);
1355061da546Spatrick row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1356061da546Spatrick
1357061da546Spatrick int reg_pairs_saved_count = 1;
1358061da546Spatrick
1359061da546Spatrick uint32_t saved_register_bits = function_info.encoding & 0xfff;
1360061da546Spatrick
1361061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
1362061da546Spatrick int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1363061da546Spatrick cfa_offset -= wordsize;
1364061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,
1365061da546Spatrick true);
1366061da546Spatrick cfa_offset -= wordsize;
1367061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1368061da546Spatrick true);
1369061da546Spatrick reg_pairs_saved_count++;
1370061da546Spatrick }
1371061da546Spatrick
1372061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
1373061da546Spatrick int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1374061da546Spatrick cfa_offset -= wordsize;
1375061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,
1376061da546Spatrick true);
1377061da546Spatrick cfa_offset -= wordsize;
1378061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1379061da546Spatrick true);
1380061da546Spatrick reg_pairs_saved_count++;
1381061da546Spatrick }
1382061da546Spatrick
1383061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
1384061da546Spatrick int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1385061da546Spatrick cfa_offset -= wordsize;
1386061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,
1387061da546Spatrick true);
1388061da546Spatrick cfa_offset -= wordsize;
1389061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1390061da546Spatrick true);
1391061da546Spatrick reg_pairs_saved_count++;
1392061da546Spatrick }
1393061da546Spatrick
1394061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
1395061da546Spatrick int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1396061da546Spatrick cfa_offset -= wordsize;
1397061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,
1398061da546Spatrick true);
1399061da546Spatrick cfa_offset -= wordsize;
1400061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1401061da546Spatrick true);
1402061da546Spatrick reg_pairs_saved_count++;
1403061da546Spatrick }
1404061da546Spatrick
1405061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
1406061da546Spatrick int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1407061da546Spatrick cfa_offset -= wordsize;
1408061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,
1409061da546Spatrick true);
1410061da546Spatrick cfa_offset -= wordsize;
1411061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1412061da546Spatrick true);
1413061da546Spatrick reg_pairs_saved_count++;
1414061da546Spatrick }
1415061da546Spatrick
1416061da546Spatrick // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1417061da546Spatrick // off the stack;
1418061da546Spatrick // not sure if we have a good way to represent the 64-bitness of these saves.
1419061da546Spatrick
1420061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1421061da546Spatrick reg_pairs_saved_count++;
1422061da546Spatrick }
1423061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1424061da546Spatrick reg_pairs_saved_count++;
1425061da546Spatrick }
1426061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1427061da546Spatrick reg_pairs_saved_count++;
1428061da546Spatrick }
1429061da546Spatrick if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1430061da546Spatrick reg_pairs_saved_count++;
1431061da546Spatrick }
1432061da546Spatrick
1433061da546Spatrick unwind_plan.AppendRow(row);
1434061da546Spatrick return true;
1435061da546Spatrick }
1436061da546Spatrick
CreateUnwindPlan_armv7(Target & target,FunctionInfo & function_info,UnwindPlan & unwind_plan,Address pc_or_function_start)1437061da546Spatrick bool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
1438061da546Spatrick FunctionInfo &function_info,
1439061da546Spatrick UnwindPlan &unwind_plan,
1440061da546Spatrick Address pc_or_function_start) {
1441061da546Spatrick unwind_plan.SetSourceName("compact unwind info");
1442061da546Spatrick unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1443061da546Spatrick unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1444061da546Spatrick unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1445061da546Spatrick unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
1446061da546Spatrick
1447061da546Spatrick unwind_plan.SetLSDAAddress(function_info.lsda_address);
1448061da546Spatrick unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1449061da546Spatrick
1450061da546Spatrick UnwindPlan::RowSP row(new UnwindPlan::Row);
1451061da546Spatrick
1452061da546Spatrick const int wordsize = 4;
1453061da546Spatrick int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
1454061da546Spatrick
1455061da546Spatrick if (mode == UNWIND_ARM_MODE_DWARF)
1456061da546Spatrick return false;
1457061da546Spatrick
1458061da546Spatrick uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1459061da546Spatrick UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1460061da546Spatrick wordsize;
1461061da546Spatrick
1462061da546Spatrick row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1463061da546Spatrick (2 * wordsize) + stack_adjust);
1464061da546Spatrick row->SetOffset(0);
1465061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(
1466061da546Spatrick arm_r7, (wordsize * -2) - stack_adjust, true);
1467061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(
1468061da546Spatrick arm_pc, (wordsize * -1) - stack_adjust, true);
1469061da546Spatrick row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);
1470061da546Spatrick
1471061da546Spatrick int cfa_offset = -stack_adjust - (2 * wordsize);
1472061da546Spatrick
1473061da546Spatrick uint32_t saved_register_bits = function_info.encoding & 0xff;
1474061da546Spatrick
1475061da546Spatrick if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1476061da546Spatrick cfa_offset -= wordsize;
1477061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1478061da546Spatrick }
1479061da546Spatrick
1480061da546Spatrick if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1481061da546Spatrick cfa_offset -= wordsize;
1482061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1483061da546Spatrick }
1484061da546Spatrick
1485061da546Spatrick if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1486061da546Spatrick cfa_offset -= wordsize;
1487061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1488061da546Spatrick }
1489061da546Spatrick
1490061da546Spatrick if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1491061da546Spatrick cfa_offset -= wordsize;
1492061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1493061da546Spatrick }
1494061da546Spatrick
1495061da546Spatrick if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1496061da546Spatrick cfa_offset -= wordsize;
1497061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1498061da546Spatrick }
1499061da546Spatrick
1500061da546Spatrick if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1501061da546Spatrick cfa_offset -= wordsize;
1502061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1503061da546Spatrick }
1504061da546Spatrick
1505061da546Spatrick if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1506061da546Spatrick cfa_offset -= wordsize;
1507061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1508061da546Spatrick }
1509061da546Spatrick
1510061da546Spatrick if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1511061da546Spatrick cfa_offset -= wordsize;
1512061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
1513061da546Spatrick }
1514061da546Spatrick
1515061da546Spatrick if (mode == UNWIND_ARM_MODE_FRAME_D) {
1516061da546Spatrick uint32_t d_reg_bits =
1517061da546Spatrick EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1518061da546Spatrick switch (d_reg_bits) {
1519061da546Spatrick case 0:
1520061da546Spatrick // vpush {d8}
1521061da546Spatrick cfa_offset -= 8;
1522061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1523061da546Spatrick break;
1524061da546Spatrick case 1:
1525061da546Spatrick // vpush {d10}
1526061da546Spatrick // vpush {d8}
1527061da546Spatrick cfa_offset -= 8;
1528061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1529061da546Spatrick cfa_offset -= 8;
1530061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1531061da546Spatrick break;
1532061da546Spatrick case 2:
1533061da546Spatrick // vpush {d12}
1534061da546Spatrick // vpush {d10}
1535061da546Spatrick // vpush {d8}
1536061da546Spatrick cfa_offset -= 8;
1537061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1538061da546Spatrick cfa_offset -= 8;
1539061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1540061da546Spatrick cfa_offset -= 8;
1541061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1542061da546Spatrick break;
1543061da546Spatrick case 3:
1544061da546Spatrick // vpush {d14}
1545061da546Spatrick // vpush {d12}
1546061da546Spatrick // vpush {d10}
1547061da546Spatrick // vpush {d8}
1548061da546Spatrick cfa_offset -= 8;
1549061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1550061da546Spatrick cfa_offset -= 8;
1551061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1552061da546Spatrick cfa_offset -= 8;
1553061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1554061da546Spatrick cfa_offset -= 8;
1555061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1556061da546Spatrick break;
1557061da546Spatrick case 4:
1558061da546Spatrick // vpush {d14}
1559061da546Spatrick // vpush {d12}
1560061da546Spatrick // sp = (sp - 24) & (-16);
1561061da546Spatrick // vst {d8, d9, d10}
1562061da546Spatrick cfa_offset -= 8;
1563061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1564061da546Spatrick cfa_offset -= 8;
1565061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1566061da546Spatrick
1567061da546Spatrick // FIXME we don't have a way to represent reg saves at an specific
1568061da546Spatrick // alignment short of
1569061da546Spatrick // coming up with some DWARF location description.
1570061da546Spatrick
1571061da546Spatrick break;
1572061da546Spatrick case 5:
1573061da546Spatrick // vpush {d14}
1574061da546Spatrick // sp = (sp - 40) & (-16);
1575061da546Spatrick // vst {d8, d9, d10, d11}
1576061da546Spatrick // vst {d12}
1577061da546Spatrick
1578061da546Spatrick cfa_offset -= 8;
1579061da546Spatrick row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1580061da546Spatrick
1581061da546Spatrick // FIXME we don't have a way to represent reg saves at an specific
1582061da546Spatrick // alignment short of
1583061da546Spatrick // coming up with some DWARF location description.
1584061da546Spatrick
1585061da546Spatrick break;
1586061da546Spatrick case 6:
1587061da546Spatrick // sp = (sp - 56) & (-16);
1588061da546Spatrick // vst {d8, d9, d10, d11}
1589061da546Spatrick // vst {d12, d13, d14}
1590061da546Spatrick
1591061da546Spatrick // FIXME we don't have a way to represent reg saves at an specific
1592061da546Spatrick // alignment short of
1593061da546Spatrick // coming up with some DWARF location description.
1594061da546Spatrick
1595061da546Spatrick break;
1596061da546Spatrick case 7:
1597061da546Spatrick // sp = (sp - 64) & (-16);
1598061da546Spatrick // vst {d8, d9, d10, d11}
1599061da546Spatrick // vst {d12, d13, d14, d15}
1600061da546Spatrick
1601061da546Spatrick // FIXME we don't have a way to represent reg saves at an specific
1602061da546Spatrick // alignment short of
1603061da546Spatrick // coming up with some DWARF location description.
1604061da546Spatrick
1605061da546Spatrick break;
1606061da546Spatrick }
1607061da546Spatrick }
1608061da546Spatrick
1609061da546Spatrick unwind_plan.AppendRow(row);
1610061da546Spatrick return true;
1611061da546Spatrick }
1612