blob: df71b17c09d0c3ea623e2b7defc4657235fdb60a [file] [log] [blame]
Jason Molendae589e7e2014-12-08 03:09:00 +00001//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Pavel Labath5f19b902017-11-13 16:16:33 +000010#include "lldb/Symbol/CompactUnwindInfo.h"
Jason Molendae589e7e2014-12-08 03:09:00 +000011#include "lldb/Core/Module.h"
12#include "lldb/Core/Section.h"
Jason Molendae589e7e2014-12-08 03:09:00 +000013#include "lldb/Symbol/ObjectFile.h"
14#include "lldb/Symbol/UnwindPlan.h"
Jason Molendab12a1362014-12-20 03:12:51 +000015#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
Pavel Labath5f19b902017-11-13 16:16:33 +000017#include "lldb/Utility/ArchSpec.h"
Zachary Turner666cc0b2017-03-04 01:30:05 +000018#include "lldb/Utility/DataBufferHeap.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000019#include "lldb/Utility/Log.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000020#include "lldb/Utility/StreamString.h"
Pavel Labath5f19b902017-11-13 16:16:33 +000021#include <algorithm>
Jason Molendae589e7e2014-12-08 03:09:00 +000022
Zachary Turner818a3672014-12-08 20:00:33 +000023#include "llvm/Support/MathExtras.h"
24
Jason Molendae589e7e2014-12-08 03:09:00 +000025using namespace lldb;
26using namespace lldb_private;
27
Jason Molendae589e7e2014-12-08 03:09:00 +000028namespace lldb_private {
29
Kate Stoneb9c1b512016-09-06 20:57:50 +000030// Constants from <mach-o/compact_unwind_encoding.h>
Jason Molendae589e7e2014-12-08 03:09:00 +000031
Kate Stoneb9c1b512016-09-06 20:57:50 +000032FLAGS_ANONYMOUS_ENUM(){
33 UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
34 UNWIND_PERSONALITY_MASK = 0x30000000,
35};
Jason Molendae589e7e2014-12-08 03:09:00 +000036
Kate Stoneb9c1b512016-09-06 20:57:50 +000037FLAGS_ANONYMOUS_ENUM(){
38 UNWIND_X86_MODE_MASK = 0x0F000000,
39 UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
40 UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
41 UNWIND_X86_MODE_STACK_IND = 0x03000000,
42 UNWIND_X86_MODE_DWARF = 0x04000000,
Jason Molendae589e7e2014-12-08 03:09:00 +000043
Kate Stoneb9c1b512016-09-06 20:57:50 +000044 UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
45 UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
Jason Molendae589e7e2014-12-08 03:09:00 +000046
Kate Stoneb9c1b512016-09-06 20:57:50 +000047 UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
48 UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
49 UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
50 UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
Jason Molendae589e7e2014-12-08 03:09:00 +000051
Kate Stoneb9c1b512016-09-06 20:57:50 +000052 UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
53};
Jason Molendae589e7e2014-12-08 03:09:00 +000054
Kate Stoneb9c1b512016-09-06 20:57:50 +000055enum {
56 UNWIND_X86_REG_NONE = 0,
57 UNWIND_X86_REG_EBX = 1,
58 UNWIND_X86_REG_ECX = 2,
59 UNWIND_X86_REG_EDX = 3,
60 UNWIND_X86_REG_EDI = 4,
61 UNWIND_X86_REG_ESI = 5,
62 UNWIND_X86_REG_EBP = 6,
63};
Zachary Turner48b475c2015-04-02 20:57:38 +000064
Kate Stoneb9c1b512016-09-06 20:57:50 +000065FLAGS_ANONYMOUS_ENUM(){
66 UNWIND_X86_64_MODE_MASK = 0x0F000000,
67 UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
68 UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
69 UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
70 UNWIND_X86_64_MODE_DWARF = 0x04000000,
Jason Molendae589e7e2014-12-08 03:09:00 +000071
Kate Stoneb9c1b512016-09-06 20:57:50 +000072 UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
73 UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
Jason Molendae589e7e2014-12-08 03:09:00 +000074
Kate Stoneb9c1b512016-09-06 20:57:50 +000075 UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
76 UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
77 UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
78 UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
Jason Molendae589e7e2014-12-08 03:09:00 +000079
Kate Stoneb9c1b512016-09-06 20:57:50 +000080 UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
81};
Jason Molendae589e7e2014-12-08 03:09:00 +000082
Kate Stoneb9c1b512016-09-06 20:57:50 +000083enum {
84 UNWIND_X86_64_REG_NONE = 0,
85 UNWIND_X86_64_REG_RBX = 1,
86 UNWIND_X86_64_REG_R12 = 2,
87 UNWIND_X86_64_REG_R13 = 3,
88 UNWIND_X86_64_REG_R14 = 4,
89 UNWIND_X86_64_REG_R15 = 5,
90 UNWIND_X86_64_REG_RBP = 6,
91};
Jason Molendab667c202016-05-25 04:20:28 +000092
Kate Stoneb9c1b512016-09-06 20:57:50 +000093FLAGS_ANONYMOUS_ENUM(){
94 UNWIND_ARM64_MODE_MASK = 0x0F000000,
95 UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
96 UNWIND_ARM64_MODE_DWARF = 0x03000000,
97 UNWIND_ARM64_MODE_FRAME = 0x04000000,
Jason Molendab667c202016-05-25 04:20:28 +000098
Kate Stoneb9c1b512016-09-06 20:57:50 +000099 UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
100 UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
101 UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
102 UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
103 UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
104 UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
105 UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
106 UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
107 UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
Jason Molendab667c202016-05-25 04:20:28 +0000108
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
110 UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
111};
Jason Molendac7afda52016-06-07 02:19:54 +0000112
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113FLAGS_ANONYMOUS_ENUM(){
114 UNWIND_ARM_MODE_MASK = 0x0F000000,
115 UNWIND_ARM_MODE_FRAME = 0x01000000,
116 UNWIND_ARM_MODE_FRAME_D = 0x02000000,
117 UNWIND_ARM_MODE_DWARF = 0x04000000,
Jason Molendac7afda52016-06-07 02:19:54 +0000118
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119 UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
Jason Molendac7afda52016-06-07 02:19:54 +0000120
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121 UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
122 UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
123 UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
Jason Molendac7afda52016-06-07 02:19:54 +0000124
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
126 UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
127 UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
128 UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
129 UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
Jason Molendac7afda52016-06-07 02:19:54 +0000130
Kate Stoneb9c1b512016-09-06 20:57:50 +0000131 UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
Jason Molendac7afda52016-06-07 02:19:54 +0000132
Kate Stoneb9c1b512016-09-06 20:57:50 +0000133 UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
134};
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000135}
Jason Molendae589e7e2014-12-08 03:09:00 +0000136
Jason Molendae589e7e2014-12-08 03:09:00 +0000137#ifndef UNWIND_SECOND_LEVEL_REGULAR
138#define UNWIND_SECOND_LEVEL_REGULAR 2
139#endif
140
141#ifndef UNWIND_SECOND_LEVEL_COMPRESSED
142#define UNWIND_SECOND_LEVEL_COMPRESSED 3
143#endif
144
145#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
Jason Molendae589e7e2014-12-08 03:09:00 +0000147#endif
148
149#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \
151 ((entry >> 24) & 0xFF)
Jason Molendae589e7e2014-12-08 03:09:00 +0000152#endif
153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154#define EXTRACT_BITS(value, mask) \
155 ((value >> \
156 llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \
157 (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1))
Jason Molendae589e7e2014-12-08 03:09:00 +0000158
159//----------------------
Jason Molendac7afda52016-06-07 02:19:54 +0000160// constructor
Jason Molendae589e7e2014-12-08 03:09:00 +0000161//----------------------
162
Saleem Abdulrasoolbb19a132016-05-19 05:13:57 +0000163CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP &section_sp)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000164 : m_objfile(objfile), m_section_sp(section_sp),
165 m_section_contents_if_encrypted(), m_mutex(), m_indexes(),
166 m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(),
167 m_unwindinfo_data_computed(false), m_unwind_header() {}
Jason Molendae589e7e2014-12-08 03:09:00 +0000168
169//----------------------
170// destructor
171//----------------------
172
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173CompactUnwindInfo::~CompactUnwindInfo() {}
Jason Molendae589e7e2014-12-08 03:09:00 +0000174
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
176 UnwindPlan &unwind_plan) {
177 if (!IsValid(target.GetProcessSP())) {
Jason Molendae589e7e2014-12-08 03:09:00 +0000178 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179 }
180 FunctionInfo function_info;
181 if (GetCompactUnwindInfoForFunction(target, addr, function_info)) {
182 // shortcut return for functions that have no compact unwind
183 if (function_info.encoding == 0)
184 return false;
185
186 ArchSpec arch;
187 if (m_objfile.GetArchitecture(arch)) {
188
189 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
190 if (log && log->GetVerbose()) {
191 StreamString strm;
192 addr.Dump(
193 &strm, NULL,
194 Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments,
195 Address::DumpStyle::DumpStyleFileAddress,
196 arch.GetAddressByteSize());
197 log->Printf("Got compact unwind encoding 0x%x for function %s",
198 function_info.encoding, strm.GetData());
199 }
200
201 if (function_info.valid_range_offset_start != 0 &&
202 function_info.valid_range_offset_end != 0) {
203 SectionList *sl = m_objfile.GetSectionList();
204 if (sl) {
205 addr_t func_range_start_file_addr =
206 function_info.valid_range_offset_start +
207 m_objfile.GetHeaderAddress().GetFileAddress();
208 AddressRange func_range(func_range_start_file_addr,
209 function_info.valid_range_offset_end -
210 function_info.valid_range_offset_start,
211 sl);
212 unwind_plan.SetPlanValidAddressRange(func_range);
213 }
214 }
215
216 if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
217 return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
218 addr);
219 }
220 if (arch.GetTriple().getArch() == llvm::Triple::aarch64) {
221 return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
222 }
223 if (arch.GetTriple().getArch() == llvm::Triple::x86) {
224 return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
225 }
226 if (arch.GetTriple().getArch() == llvm::Triple::arm ||
227 arch.GetTriple().getArch() == llvm::Triple::thumb) {
228 return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);
229 }
230 }
231 }
232 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000233}
234
Kate Stoneb9c1b512016-09-06 20:57:50 +0000235bool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
236 if (m_section_sp.get() == nullptr)
237 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
240 return true;
Jason Molendae589e7e2014-12-08 03:09:00 +0000241
Kate Stoneb9c1b512016-09-06 20:57:50 +0000242 ScanIndex(process_sp);
Jason Molendae589e7e2014-12-08 03:09:00 +0000243
Kate Stoneb9c1b512016-09-06 20:57:50 +0000244 return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
Jason Molendae589e7e2014-12-08 03:09:00 +0000245}
246
Kate Stoneb9c1b512016-09-06 20:57:50 +0000247void CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
248 std::lock_guard<std::mutex> guard(m_mutex);
249 if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
250 return;
251
252 // We can't read the index for some reason.
253 if (m_indexes_computed == eLazyBoolNo) {
254 return;
255 }
256
257 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
258 if (log)
259 m_objfile.GetModule()->LogMessage(
260 log, "Reading compact unwind first-level indexes");
261
262 if (m_unwindinfo_data_computed == false) {
263 if (m_section_sp->IsEncrypted()) {
264 // Can't get section contents of a protected/encrypted section until we
265 // have a live
266 // process and can read them out of memory.
267 if (process_sp.get() == nullptr)
Jason Molendae589e7e2014-12-08 03:09:00 +0000268 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000269 m_section_contents_if_encrypted.reset(
270 new DataBufferHeap(m_section_sp->GetByteSize(), 0));
Zachary Turner97206d52017-05-12 04:51:55 +0000271 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000272 if (process_sp->ReadMemory(
273 m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
274 m_section_contents_if_encrypted->GetBytes(),
275 m_section_sp->GetByteSize(),
276 error) == m_section_sp->GetByteSize() &&
277 error.Success()) {
278 m_unwindinfo_data.SetAddressByteSize(
279 process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
280 m_unwindinfo_data.SetByteOrder(
281 process_sp->GetTarget().GetArchitecture().GetByteOrder());
282 m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);
283 }
284 } else {
285 m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
286 }
287 if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
288 return;
289 m_unwindinfo_data_computed = true;
290 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000291
Kate Stoneb9c1b512016-09-06 20:57:50 +0000292 if (m_unwindinfo_data.GetByteSize() > 0) {
293 offset_t offset = 0;
294
295 // struct unwind_info_section_header
296 // {
297 // uint32_t version; // UNWIND_SECTION_VERSION
298 // uint32_t commonEncodingsArraySectionOffset;
299 // uint32_t commonEncodingsArrayCount;
300 // uint32_t personalityArraySectionOffset;
301 // uint32_t personalityArrayCount;
302 // uint32_t indexSectionOffset;
303 // uint32_t indexCount;
304
305 m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
306 m_unwind_header.common_encodings_array_offset =
307 m_unwindinfo_data.GetU32(&offset);
308 m_unwind_header.common_encodings_array_count =
309 m_unwindinfo_data.GetU32(&offset);
310 m_unwind_header.personality_array_offset =
311 m_unwindinfo_data.GetU32(&offset);
312 m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
313 uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
314
315 uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
316
317 if (m_unwind_header.common_encodings_array_offset >
318 m_unwindinfo_data.GetByteSize() ||
319 m_unwind_header.personality_array_offset >
320 m_unwindinfo_data.GetByteSize() ||
321 indexSectionOffset > m_unwindinfo_data.GetByteSize() ||
322 offset > m_unwindinfo_data.GetByteSize()) {
323 Host::SystemLog(Host::eSystemLogError, "error: Invalid offset "
324 "encountered in compact unwind "
325 "info, skipping\n");
326 // don't trust anything from this compact_unwind section if it looks
327 // blatantly invalid data in the header.
328 m_indexes_computed = eLazyBoolNo;
329 return;
Jason Molendae589e7e2014-12-08 03:09:00 +0000330 }
331
Kate Stoneb9c1b512016-09-06 20:57:50 +0000332 // Parse the basic information from the indexes
333 // We wait to scan the second level page info until it's needed
Jason Molenda5c45c542014-12-21 10:44:54 +0000334
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 // struct unwind_info_section_header_index_entry
336 // {
337 // uint32_t functionOffset;
338 // uint32_t secondLevelPagesSectionOffset;
339 // uint32_t lsdaIndexArraySectionOffset;
340 // };
341
342 bool clear_address_zeroth_bit = false;
343 ArchSpec arch;
344 if (m_objfile.GetArchitecture(arch)) {
345 if (arch.GetTriple().getArch() == llvm::Triple::arm ||
346 arch.GetTriple().getArch() == llvm::Triple::thumb)
347 clear_address_zeroth_bit = true;
Jason Molendae589e7e2014-12-08 03:09:00 +0000348 }
349
Kate Stoneb9c1b512016-09-06 20:57:50 +0000350 offset = indexSectionOffset;
351 for (uint32_t idx = 0; idx < indexCount; idx++) {
352 uint32_t function_offset =
353 m_unwindinfo_data.GetU32(&offset); // functionOffset
354 uint32_t second_level_offset =
355 m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
356 uint32_t lsda_offset =
357 m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
Jason Molendae589e7e2014-12-08 03:09:00 +0000358
Kate Stoneb9c1b512016-09-06 20:57:50 +0000359 if (second_level_offset > m_section_sp->GetByteSize() ||
360 lsda_offset > m_section_sp->GetByteSize()) {
Jason Molendae589e7e2014-12-08 03:09:00 +0000361 m_indexes_computed = eLazyBoolNo;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000362 }
363
364 if (clear_address_zeroth_bit)
365 function_offset &= ~1ull;
366
367 UnwindIndex this_index;
368 this_index.function_offset = function_offset;
369 this_index.second_level = second_level_offset;
370 this_index.lsda_array_start = lsda_offset;
371
372 if (m_indexes.size() > 0) {
373 m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
374 }
375
376 if (second_level_offset == 0) {
377 this_index.sentinal_entry = true;
378 }
379
380 m_indexes.push_back(this_index);
Jason Molendae589e7e2014-12-08 03:09:00 +0000381 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000382 m_indexes_computed = eLazyBoolYes;
383 } else {
384 m_indexes_computed = eLazyBoolNo;
385 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000386}
387
Kate Stoneb9c1b512016-09-06 20:57:50 +0000388uint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
389 uint32_t lsda_count,
390 uint32_t function_offset) {
391 // struct unwind_info_section_header_lsda_index_entry
392 // {
393 // uint32_t functionOffset;
394 // uint32_t lsdaOffset;
395 // };
Jason Molendae589e7e2014-12-08 03:09:00 +0000396
Kate Stoneb9c1b512016-09-06 20:57:50 +0000397 offset_t first_entry = lsda_offset;
398 uint32_t low = 0;
399 uint32_t high = lsda_count;
400 while (low < high) {
401 uint32_t mid = (low + high) / 2;
402 offset_t offset = first_entry + (mid * 8);
403 uint32_t mid_func_offset =
404 m_unwindinfo_data.GetU32(&offset); // functionOffset
405 uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
406 if (mid_func_offset == function_offset) {
407 return mid_lsda_offset;
Jason Molendae589e7e2014-12-08 03:09:00 +0000408 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000409 if (mid_func_offset < function_offset) {
410 low = mid + 1;
411 } else {
412 high = mid;
413 }
414 }
415 return 0;
Jason Molendae589e7e2014-12-08 03:09:00 +0000416}
417
Kate Stoneb9c1b512016-09-06 20:57:50 +0000418lldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(
419 uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,
420 uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
421 // typedef uint32_t compact_unwind_encoding_t;
422 // struct unwind_info_regular_second_level_entry
423 // {
424 // uint32_t functionOffset;
425 // compact_unwind_encoding_t encoding;
426
427 offset_t first_entry = entry_page_offset;
428
429 uint32_t low = 0;
430 uint32_t high = entry_count;
431 uint32_t last = high - 1;
432 while (low < high) {
433 uint32_t mid = (low + high) / 2;
434 offset_t offset = first_entry + (mid * 8);
435 uint32_t mid_func_offset =
436 m_unwindinfo_data.GetU32(&offset); // functionOffset
437 uint32_t next_func_offset = 0;
438 if (mid < last) {
439 offset = first_entry + ((mid + 1) * 8);
440 next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
441 }
442 if (mid_func_offset <= function_offset) {
443 if (mid == last || (next_func_offset > function_offset)) {
444 if (entry_func_start_offset)
445 *entry_func_start_offset = mid_func_offset;
446 if (mid != last && entry_func_end_offset)
447 *entry_func_end_offset = next_func_offset;
448 return first_entry + (mid * 8);
449 } else {
450 low = mid + 1;
451 }
452 } else {
453 high = mid;
454 }
455 }
456 return LLDB_INVALID_OFFSET;
457}
458
459uint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(
460 uint32_t entry_page_offset, uint32_t entry_count,
461 uint32_t function_offset_to_find, uint32_t function_offset_base,
462 uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
463 offset_t first_entry = entry_page_offset;
464
465 uint32_t low = 0;
466 uint32_t high = entry_count;
467 uint32_t last = high - 1;
468 while (low < high) {
469 uint32_t mid = (low + high) / 2;
470 offset_t offset = first_entry + (mid * 4);
471 uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
472 uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
473 mid_func_offset += function_offset_base;
474 uint32_t next_func_offset = 0;
475 if (mid < last) {
476 offset = first_entry + ((mid + 1) * 4);
477 uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
478 next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);
479 next_func_offset += function_offset_base;
480 }
481 if (mid_func_offset <= function_offset_to_find) {
482 if (mid == last || (next_func_offset > function_offset_to_find)) {
483 if (entry_func_start_offset)
484 *entry_func_start_offset = mid_func_offset;
485 if (mid != last && entry_func_end_offset)
486 *entry_func_end_offset = next_func_offset;
487 return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
488 } else {
489 low = mid + 1;
490 }
491 } else {
492 high = mid;
493 }
494 }
495
496 return UINT32_MAX;
497}
498
499bool CompactUnwindInfo::GetCompactUnwindInfoForFunction(
500 Target &target, Address address, FunctionInfo &unwind_info) {
501 unwind_info.encoding = 0;
502 unwind_info.lsda_address.Clear();
503 unwind_info.personality_ptr_address.Clear();
504
505 if (!IsValid(target.GetProcessSP()))
506 return false;
507
508 addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
509 SectionList *sl = m_objfile.GetSectionList();
510 if (sl) {
511 SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
512 if (text_sect.get()) {
513 text_section_file_address = text_sect->GetFileAddress();
514 }
515 }
516 if (text_section_file_address == LLDB_INVALID_ADDRESS)
517 return false;
518
519 addr_t function_offset =
520 address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress();
521
522 UnwindIndex key;
523 key.function_offset = function_offset;
524
525 std::vector<UnwindIndex>::const_iterator it;
526 it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key);
527 if (it == m_indexes.end()) {
528 return false;
529 }
530
531 if (it->function_offset != key.function_offset) {
532 if (it != m_indexes.begin())
533 --it;
534 }
535
536 if (it->sentinal_entry == true) {
537 return false;
538 }
539
540 auto next_it = it + 1;
541 if (next_it != m_indexes.end()) {
542 // initialize the function offset end range to be the start of the
543 // next index offset. If we find an entry which is at the end of
544 // the index table, this will establish the range end.
545 unwind_info.valid_range_offset_end = next_it->function_offset;
546 }
547
548 offset_t second_page_offset = it->second_level;
549 offset_t lsda_array_start = it->lsda_array_start;
550 offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
551
552 offset_t offset = second_page_offset;
553 uint32_t kind = m_unwindinfo_data.GetU32(
554 &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
555
556 if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
557 // struct unwind_info_regular_second_level_page_header
558 // {
559 // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
560 // uint16_t entryPageOffset;
561 // uint16_t entryCount;
562
Jason Molendae589e7e2014-12-08 03:09:00 +0000563 // typedef uint32_t compact_unwind_encoding_t;
Jason Molendac7afda52016-06-07 02:19:54 +0000564 // struct unwind_info_regular_second_level_entry
Jason Molendae589e7e2014-12-08 03:09:00 +0000565 // {
566 // uint32_t functionOffset;
567 // compact_unwind_encoding_t encoding;
568
Kate Stoneb9c1b512016-09-06 20:57:50 +0000569 uint16_t entry_page_offset =
570 m_unwindinfo_data.GetU16(&offset); // entryPageOffset
571 uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
Jason Molendae589e7e2014-12-08 03:09:00 +0000572
Kate Stoneb9c1b512016-09-06 20:57:50 +0000573 offset_t entry_offset = BinarySearchRegularSecondPage(
574 second_page_offset + entry_page_offset, entry_count, function_offset,
575 &unwind_info.valid_range_offset_start,
576 &unwind_info.valid_range_offset_end);
577 if (entry_offset == LLDB_INVALID_OFFSET) {
578 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000579 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000580 entry_offset += 4; // skip over functionOffset
581 unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
582 if (unwind_info.encoding & UNWIND_HAS_LSDA) {
583 SectionList *sl = m_objfile.GetSectionList();
584 if (sl) {
585 uint32_t lsda_offset = GetLSDAForFunctionOffset(
586 lsda_array_start, lsda_array_count, function_offset);
587 addr_t objfile_header_file_address =
588 m_objfile.GetHeaderAddress().GetFileAddress();
589 unwind_info.lsda_address.ResolveAddressUsingFileSections(
590 objfile_header_file_address + lsda_offset, sl);
591 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000592 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000593 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
594 uint32_t personality_index =
595 EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
Jason Molendae589e7e2014-12-08 03:09:00 +0000596
Kate Stoneb9c1b512016-09-06 20:57:50 +0000597 if (personality_index > 0) {
598 personality_index--;
599 if (personality_index < m_unwind_header.personality_array_count) {
600 offset_t offset = m_unwind_header.personality_array_offset;
601 offset += 4 * personality_index;
602 SectionList *sl = m_objfile.GetSectionList();
603 if (sl) {
604 uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
605 addr_t objfile_header_file_address =
606 m_objfile.GetHeaderAddress().GetFileAddress();
607 unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
608 objfile_header_file_address + personality_offset, sl);
609 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000610 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000611 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000612 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000613 return true;
614 } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
615 // struct unwind_info_compressed_second_level_page_header
616 // {
617 // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
618 // uint16_t entryPageOffset; // offset from this 2nd lvl page
619 // idx to array of entries
620 // // (an entry has a function
621 // offset and index into the
622 // encodings)
623 // // NB function offset from the
624 // entry in the compressed page
625 // // must be added to the index's
626 // functionOffset value.
627 // uint16_t entryCount;
628 // uint16_t encodingsPageOffset; // offset from this 2nd lvl page
629 // idx to array of encodings
630 // uint16_t encodingsCount;
Jason Molendae589e7e2014-12-08 03:09:00 +0000631
Kate Stoneb9c1b512016-09-06 20:57:50 +0000632 uint16_t entry_page_offset =
633 m_unwindinfo_data.GetU16(&offset); // entryPageOffset
634 uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
635 uint16_t encodings_page_offset =
636 m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
637 uint16_t encodings_count =
638 m_unwindinfo_data.GetU16(&offset); // encodingsCount
Jason Molendac7afda52016-06-07 02:19:54 +0000639
Kate Stoneb9c1b512016-09-06 20:57:50 +0000640 uint32_t encoding_index = BinarySearchCompressedSecondPage(
641 second_page_offset + entry_page_offset, entry_count, function_offset,
642 it->function_offset, &unwind_info.valid_range_offset_start,
643 &unwind_info.valid_range_offset_end);
644 if (encoding_index == UINT32_MAX ||
645 encoding_index >=
646 encodings_count + m_unwind_header.common_encodings_array_count) {
647 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000648 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000649 uint32_t encoding = 0;
650 if (encoding_index < m_unwind_header.common_encodings_array_count) {
651 offset = m_unwind_header.common_encodings_array_offset +
652 (encoding_index * sizeof(uint32_t));
653 encoding = m_unwindinfo_data.GetU32(
654 &offset); // encoding entry from the commonEncodingsArray
655 } else {
656 uint32_t page_specific_entry_index =
657 encoding_index - m_unwind_header.common_encodings_array_count;
658 offset = second_page_offset + encodings_page_offset +
659 (page_specific_entry_index * sizeof(uint32_t));
660 encoding = m_unwindinfo_data.GetU32(
661 &offset); // encoding entry from the page-specific encoding array
Jason Molendae589e7e2014-12-08 03:09:00 +0000662 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000663 if (encoding == 0)
664 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000665
Kate Stoneb9c1b512016-09-06 20:57:50 +0000666 unwind_info.encoding = encoding;
667 if (unwind_info.encoding & UNWIND_HAS_LSDA) {
668 SectionList *sl = m_objfile.GetSectionList();
669 if (sl) {
670 uint32_t lsda_offset = GetLSDAForFunctionOffset(
671 lsda_array_start, lsda_array_count, function_offset);
672 addr_t objfile_header_file_address =
673 m_objfile.GetHeaderAddress().GetFileAddress();
674 unwind_info.lsda_address.ResolveAddressUsingFileSections(
675 objfile_header_file_address + lsda_offset, sl);
676 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000677 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000678 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
679 uint32_t personality_index =
680 EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
Jason Molendae589e7e2014-12-08 03:09:00 +0000681
Kate Stoneb9c1b512016-09-06 20:57:50 +0000682 if (personality_index > 0) {
683 personality_index--;
684 if (personality_index < m_unwind_header.personality_array_count) {
685 offset_t offset = m_unwind_header.personality_array_offset;
686 offset += 4 * personality_index;
687 SectionList *sl = m_objfile.GetSectionList();
688 if (sl) {
689 uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
690 addr_t objfile_header_file_address =
691 m_objfile.GetHeaderAddress().GetFileAddress();
692 unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
693 objfile_header_file_address + personality_offset, sl);
694 }
695 }
696 }
Jason Molenda5c45c542014-12-21 10:44:54 +0000697 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000698 return true;
699 }
700 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000701}
702
703enum x86_64_eh_regnum {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000704 rax = 0,
705 rdx = 1,
706 rcx = 2,
707 rbx = 3,
708 rsi = 4,
709 rdi = 5,
710 rbp = 6,
711 rsp = 7,
712 r8 = 8,
713 r9 = 9,
714 r10 = 10,
715 r11 = 11,
716 r12 = 12,
717 r13 = 13,
718 r14 = 14,
719 r15 = 15,
720 rip = 16 // this is officially the Return Address register number, but close
721 // enough
Jason Molendae589e7e2014-12-08 03:09:00 +0000722};
723
724// Convert the compact_unwind_info.h register numbering scheme
Jason Molenda63bd0db2015-09-15 23:20:34 +0000725// to eRegisterKindEHFrame (eh_frame) register numbering scheme.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000726uint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {
727 switch (unwind_regno) {
728 case UNWIND_X86_64_REG_RBX:
729 return x86_64_eh_regnum::rbx;
730 case UNWIND_X86_64_REG_R12:
731 return x86_64_eh_regnum::r12;
732 case UNWIND_X86_64_REG_R13:
733 return x86_64_eh_regnum::r13;
734 case UNWIND_X86_64_REG_R14:
735 return x86_64_eh_regnum::r14;
736 case UNWIND_X86_64_REG_R15:
737 return x86_64_eh_regnum::r15;
738 case UNWIND_X86_64_REG_RBP:
739 return x86_64_eh_regnum::rbp;
740 default:
741 return LLDB_INVALID_REGNUM;
742 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000743}
744
Kate Stoneb9c1b512016-09-06 20:57:50 +0000745bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
746 FunctionInfo &function_info,
747 UnwindPlan &unwind_plan,
748 Address pc_or_function_start) {
749 unwind_plan.SetSourceName("compact unwind info");
750 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
751 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
752 unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
Jason Molendae589e7e2014-12-08 03:09:00 +0000753
Kate Stoneb9c1b512016-09-06 20:57:50 +0000754 unwind_plan.SetLSDAAddress(function_info.lsda_address);
755 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
Jason Molendae589e7e2014-12-08 03:09:00 +0000756
Kate Stoneb9c1b512016-09-06 20:57:50 +0000757 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendae589e7e2014-12-08 03:09:00 +0000758
Kate Stoneb9c1b512016-09-06 20:57:50 +0000759 const int wordsize = 8;
760 int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
761 switch (mode) {
762 case UNWIND_X86_64_MODE_RBP_FRAME: {
763 row->GetCFAValue().SetIsRegisterPlusOffset(
764 translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),
765 2 * wordsize);
766 row->SetOffset(0);
767 row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,
768 wordsize * -2, true);
769 row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
770 wordsize * -1, true);
771 row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
Jason Molendac7afda52016-06-07 02:19:54 +0000772
Kate Stoneb9c1b512016-09-06 20:57:50 +0000773 uint32_t saved_registers_offset =
774 EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
Jason Molendae589e7e2014-12-08 03:09:00 +0000775
Kate Stoneb9c1b512016-09-06 20:57:50 +0000776 uint32_t saved_registers_locations =
777 EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
Jason Molendae589e7e2014-12-08 03:09:00 +0000778
Kate Stoneb9c1b512016-09-06 20:57:50 +0000779 saved_registers_offset += 2;
Jason Molendae589e7e2014-12-08 03:09:00 +0000780
Kate Stoneb9c1b512016-09-06 20:57:50 +0000781 for (int i = 0; i < 5; i++) {
782 uint32_t regnum = saved_registers_locations & 0x7;
783 switch (regnum) {
784 case UNWIND_X86_64_REG_NONE:
Jason Molendae589e7e2014-12-08 03:09:00 +0000785 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000786 case UNWIND_X86_64_REG_RBX:
787 case UNWIND_X86_64_REG_R12:
788 case UNWIND_X86_64_REG_R13:
789 case UNWIND_X86_64_REG_R14:
790 case UNWIND_X86_64_REG_R15:
791 row->SetRegisterLocationToAtCFAPlusOffset(
792 translate_to_eh_frame_regnum_x86_64(regnum),
793 wordsize * -saved_registers_offset, true);
Jason Molendae589e7e2014-12-08 03:09:00 +0000794 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000795 }
796 saved_registers_offset--;
797 saved_registers_locations >>= 3;
Jason Molendae589e7e2014-12-08 03:09:00 +0000798 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000799 unwind_plan.AppendRow(row);
800 return true;
801 } break;
802
803 case UNWIND_X86_64_MODE_STACK_IND: {
804 // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
805 // this
806 // style of unwind. It was fixed in llvm r217020.
807 // The clang in Xcode 7 has this fixed.
Jason Molendae589e7e2014-12-08 03:09:00 +0000808 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000809 } break;
810
811 case UNWIND_X86_64_MODE_STACK_IMMD: {
812 uint32_t stack_size = EXTRACT_BITS(function_info.encoding,
813 UNWIND_X86_64_FRAMELESS_STACK_SIZE);
814 uint32_t register_count = EXTRACT_BITS(
815 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
816 uint32_t permutation = EXTRACT_BITS(
817 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
818
819 if (mode == UNWIND_X86_64_MODE_STACK_IND &&
820 function_info.valid_range_offset_start != 0) {
821 uint32_t stack_adjust = EXTRACT_BITS(
822 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
823
824 // offset into the function instructions; 0 == beginning of first
825 // instruction
826 uint32_t offset_to_subl_insn = EXTRACT_BITS(
827 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
828
829 SectionList *sl = m_objfile.GetSectionList();
830 if (sl) {
831 ProcessSP process_sp = target.GetProcessSP();
832 if (process_sp) {
833 Address subl_payload_addr(function_info.valid_range_offset_start, sl);
834 subl_payload_addr.Slide(offset_to_subl_insn);
Zachary Turner97206d52017-05-12 04:51:55 +0000835 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000836 uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
837 subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
838 if (large_stack_size != 0 && error.Success()) {
839 // Got the large stack frame size correctly - use it
840 stack_size = large_stack_size + (stack_adjust * wordsize);
841 } else {
842 return false;
843 }
844 } else {
845 return false;
846 }
847 } else {
848 return false;
849 }
850 }
851
852 int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
853 ? stack_size
854 : stack_size * wordsize;
855 row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
856
857 row->SetOffset(0);
858 row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
859 wordsize * -1, true);
860 row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
861
862 if (register_count > 0) {
863
864 // We need to include (up to) 6 registers in 10 bits.
865 // That would be 18 bits if we just used 3 bits per reg to indicate
866 // the order they're saved on the stack.
867 //
868 // This is done with Lehmer code permutation, e.g. see
869 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
870 int permunreg[6] = {0, 0, 0, 0, 0, 0};
871
872 // This decodes the variable-base number in the 10 bits
873 // and gives us the Lehmer code sequence which can then
874 // be decoded.
875
876 switch (register_count) {
877 case 6:
878 permunreg[0] = permutation / 120; // 120 == 5!
879 permutation -= (permunreg[0] * 120);
880 permunreg[1] = permutation / 24; // 24 == 4!
881 permutation -= (permunreg[1] * 24);
882 permunreg[2] = permutation / 6; // 6 == 3!
883 permutation -= (permunreg[2] * 6);
884 permunreg[3] = permutation / 2; // 2 == 2!
885 permutation -= (permunreg[3] * 2);
886 permunreg[4] = permutation; // 1 == 1!
887 permunreg[5] = 0;
888 break;
889 case 5:
890 permunreg[0] = permutation / 120;
891 permutation -= (permunreg[0] * 120);
892 permunreg[1] = permutation / 24;
893 permutation -= (permunreg[1] * 24);
894 permunreg[2] = permutation / 6;
895 permutation -= (permunreg[2] * 6);
896 permunreg[3] = permutation / 2;
897 permutation -= (permunreg[3] * 2);
898 permunreg[4] = permutation;
899 break;
900 case 4:
901 permunreg[0] = permutation / 60;
902 permutation -= (permunreg[0] * 60);
903 permunreg[1] = permutation / 12;
904 permutation -= (permunreg[1] * 12);
905 permunreg[2] = permutation / 3;
906 permutation -= (permunreg[2] * 3);
907 permunreg[3] = permutation;
908 break;
909 case 3:
910 permunreg[0] = permutation / 20;
911 permutation -= (permunreg[0] * 20);
912 permunreg[1] = permutation / 4;
913 permutation -= (permunreg[1] * 4);
914 permunreg[2] = permutation;
915 break;
916 case 2:
917 permunreg[0] = permutation / 5;
918 permutation -= (permunreg[0] * 5);
919 permunreg[1] = permutation;
920 break;
921 case 1:
922 permunreg[0] = permutation;
923 break;
924 }
925
926 // Decode the Lehmer code for this permutation of
927 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
928
929 int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
930 UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
931 UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
932 bool used[7] = {false, false, false, false, false, false, false};
933 for (uint32_t i = 0; i < register_count; i++) {
934 int renum = 0;
935 for (int j = 1; j < 7; j++) {
936 if (used[j] == false) {
937 if (renum == permunreg[i]) {
938 registers[i] = j;
939 used[j] = true;
940 break;
941 }
942 renum++;
943 }
944 }
945 }
946
947 uint32_t saved_registers_offset = 1;
948 saved_registers_offset++;
949
950 for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
951 switch (registers[i]) {
952 case UNWIND_X86_64_REG_NONE:
953 break;
954 case UNWIND_X86_64_REG_RBX:
955 case UNWIND_X86_64_REG_R12:
956 case UNWIND_X86_64_REG_R13:
957 case UNWIND_X86_64_REG_R14:
958 case UNWIND_X86_64_REG_R15:
959 case UNWIND_X86_64_REG_RBP:
960 row->SetRegisterLocationToAtCFAPlusOffset(
961 translate_to_eh_frame_regnum_x86_64(registers[i]),
962 wordsize * -saved_registers_offset, true);
963 saved_registers_offset++;
964 break;
965 }
966 }
967 }
968 unwind_plan.AppendRow(row);
969 return true;
970 } break;
971
972 case UNWIND_X86_64_MODE_DWARF: {
973 return false;
974 } break;
975
976 case 0: {
977 return false;
978 } break;
979 }
980 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000981}
982
983enum i386_eh_regnum {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000984 eax = 0,
985 ecx = 1,
986 edx = 2,
987 ebx = 3,
988 ebp = 4,
989 esp = 5,
990 esi = 6,
991 edi = 7,
992 eip = 8 // this is officially the Return Address register number, but close
993 // enough
Jason Molendae589e7e2014-12-08 03:09:00 +0000994};
995
996// Convert the compact_unwind_info.h register numbering scheme
Jason Molenda63bd0db2015-09-15 23:20:34 +0000997// to eRegisterKindEHFrame (eh_frame) register numbering scheme.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000998uint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {
999 switch (unwind_regno) {
1000 case UNWIND_X86_REG_EBX:
1001 return i386_eh_regnum::ebx;
1002 case UNWIND_X86_REG_ECX:
1003 return i386_eh_regnum::ecx;
1004 case UNWIND_X86_REG_EDX:
1005 return i386_eh_regnum::edx;
1006 case UNWIND_X86_REG_EDI:
1007 return i386_eh_regnum::edi;
1008 case UNWIND_X86_REG_ESI:
1009 return i386_eh_regnum::esi;
1010 case UNWIND_X86_REG_EBP:
1011 return i386_eh_regnum::ebp;
1012 default:
1013 return LLDB_INVALID_REGNUM;
1014 }
Jason Molendae589e7e2014-12-08 03:09:00 +00001015}
1016
Kate Stoneb9c1b512016-09-06 20:57:50 +00001017bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
1018 FunctionInfo &function_info,
1019 UnwindPlan &unwind_plan,
1020 Address pc_or_function_start) {
1021 unwind_plan.SetSourceName("compact unwind info");
1022 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1023 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1024 unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
Jason Molendae589e7e2014-12-08 03:09:00 +00001025
Kate Stoneb9c1b512016-09-06 20:57:50 +00001026 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1027 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
Jason Molendae589e7e2014-12-08 03:09:00 +00001028
Kate Stoneb9c1b512016-09-06 20:57:50 +00001029 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendae589e7e2014-12-08 03:09:00 +00001030
Kate Stoneb9c1b512016-09-06 20:57:50 +00001031 const int wordsize = 4;
1032 int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1033 switch (mode) {
1034 case UNWIND_X86_MODE_EBP_FRAME: {
1035 row->GetCFAValue().SetIsRegisterPlusOffset(
1036 translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
1037 row->SetOffset(0);
1038 row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,
1039 wordsize * -2, true);
1040 row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1041 wordsize * -1, true);
1042 row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
Jason Molendae589e7e2014-12-08 03:09:00 +00001043
Kate Stoneb9c1b512016-09-06 20:57:50 +00001044 uint32_t saved_registers_offset =
1045 EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
Jason Molendac7afda52016-06-07 02:19:54 +00001046
Kate Stoneb9c1b512016-09-06 20:57:50 +00001047 uint32_t saved_registers_locations =
1048 EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
Jason Molendae589e7e2014-12-08 03:09:00 +00001049
Kate Stoneb9c1b512016-09-06 20:57:50 +00001050 saved_registers_offset += 2;
Jason Molendae589e7e2014-12-08 03:09:00 +00001051
Kate Stoneb9c1b512016-09-06 20:57:50 +00001052 for (int i = 0; i < 5; i++) {
1053 uint32_t regnum = saved_registers_locations & 0x7;
1054 switch (regnum) {
1055 case UNWIND_X86_REG_NONE:
Jason Molendae589e7e2014-12-08 03:09:00 +00001056 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001057 case UNWIND_X86_REG_EBX:
1058 case UNWIND_X86_REG_ECX:
1059 case UNWIND_X86_REG_EDX:
1060 case UNWIND_X86_REG_EDI:
1061 case UNWIND_X86_REG_ESI:
1062 row->SetRegisterLocationToAtCFAPlusOffset(
1063 translate_to_eh_frame_regnum_i386(regnum),
1064 wordsize * -saved_registers_offset, true);
Jason Molenda19ba9fb2014-12-22 11:02:02 +00001065 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001066 }
1067 saved_registers_offset--;
1068 saved_registers_locations >>= 3;
1069 }
1070 unwind_plan.AppendRow(row);
1071 return true;
1072 } break;
Jason Molenda19ba9fb2014-12-22 11:02:02 +00001073
Kate Stoneb9c1b512016-09-06 20:57:50 +00001074 case UNWIND_X86_MODE_STACK_IND:
1075 case UNWIND_X86_MODE_STACK_IMMD: {
1076 uint32_t stack_size =
1077 EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1078 uint32_t register_count = EXTRACT_BITS(
1079 function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1080 uint32_t permutation = EXTRACT_BITS(
1081 function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
1082
1083 if (mode == UNWIND_X86_MODE_STACK_IND &&
1084 function_info.valid_range_offset_start != 0) {
1085 uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,
1086 UNWIND_X86_FRAMELESS_STACK_ADJUST);
1087
1088 // offset into the function instructions; 0 == beginning of first
1089 // instruction
1090 uint32_t offset_to_subl_insn =
1091 EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1092
1093 SectionList *sl = m_objfile.GetSectionList();
1094 if (sl) {
1095 ProcessSP process_sp = target.GetProcessSP();
1096 if (process_sp) {
1097 Address subl_payload_addr(function_info.valid_range_offset_start, sl);
1098 subl_payload_addr.Slide(offset_to_subl_insn);
Zachary Turner97206d52017-05-12 04:51:55 +00001099 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001100 uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
1101 subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
1102 if (large_stack_size != 0 && error.Success()) {
1103 // Got the large stack frame size correctly - use it
1104 stack_size = large_stack_size + (stack_adjust * wordsize);
1105 } else {
Jason Molendae589e7e2014-12-08 03:09:00 +00001106 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001107 }
1108 } else {
1109 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +00001110 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001111 } else {
1112 return false;
1113 }
Jason Molendae589e7e2014-12-08 03:09:00 +00001114 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001115
1116 int32_t offset =
1117 mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1118 row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
1119 row->SetOffset(0);
1120 row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1121 wordsize * -1, true);
1122 row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1123
1124 if (register_count > 0) {
1125
1126 // We need to include (up to) 6 registers in 10 bits.
1127 // That would be 18 bits if we just used 3 bits per reg to indicate
1128 // the order they're saved on the stack.
1129 //
1130 // This is done with Lehmer code permutation, e.g. see
1131 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
1132 int permunreg[6] = {0, 0, 0, 0, 0, 0};
1133
1134 // This decodes the variable-base number in the 10 bits
1135 // and gives us the Lehmer code sequence which can then
1136 // be decoded.
1137
1138 switch (register_count) {
1139 case 6:
1140 permunreg[0] = permutation / 120; // 120 == 5!
1141 permutation -= (permunreg[0] * 120);
1142 permunreg[1] = permutation / 24; // 24 == 4!
1143 permutation -= (permunreg[1] * 24);
1144 permunreg[2] = permutation / 6; // 6 == 3!
1145 permutation -= (permunreg[2] * 6);
1146 permunreg[3] = permutation / 2; // 2 == 2!
1147 permutation -= (permunreg[3] * 2);
1148 permunreg[4] = permutation; // 1 == 1!
1149 permunreg[5] = 0;
1150 break;
1151 case 5:
1152 permunreg[0] = permutation / 120;
1153 permutation -= (permunreg[0] * 120);
1154 permunreg[1] = permutation / 24;
1155 permutation -= (permunreg[1] * 24);
1156 permunreg[2] = permutation / 6;
1157 permutation -= (permunreg[2] * 6);
1158 permunreg[3] = permutation / 2;
1159 permutation -= (permunreg[3] * 2);
1160 permunreg[4] = permutation;
1161 break;
1162 case 4:
1163 permunreg[0] = permutation / 60;
1164 permutation -= (permunreg[0] * 60);
1165 permunreg[1] = permutation / 12;
1166 permutation -= (permunreg[1] * 12);
1167 permunreg[2] = permutation / 3;
1168 permutation -= (permunreg[2] * 3);
1169 permunreg[3] = permutation;
1170 break;
1171 case 3:
1172 permunreg[0] = permutation / 20;
1173 permutation -= (permunreg[0] * 20);
1174 permunreg[1] = permutation / 4;
1175 permutation -= (permunreg[1] * 4);
1176 permunreg[2] = permutation;
1177 break;
1178 case 2:
1179 permunreg[0] = permutation / 5;
1180 permutation -= (permunreg[0] * 5);
1181 permunreg[1] = permutation;
1182 break;
1183 case 1:
1184 permunreg[0] = permutation;
1185 break;
1186 }
1187
1188 // Decode the Lehmer code for this permutation of
1189 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
1190
1191 int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1192 UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1193 UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};
1194 bool used[7] = {false, false, false, false, false, false, false};
1195 for (uint32_t i = 0; i < register_count; i++) {
1196 int renum = 0;
1197 for (int j = 1; j < 7; j++) {
1198 if (used[j] == false) {
1199 if (renum == permunreg[i]) {
1200 registers[i] = j;
1201 used[j] = true;
1202 break;
1203 }
1204 renum++;
1205 }
1206 }
1207 }
1208
1209 uint32_t saved_registers_offset = 1;
1210 saved_registers_offset++;
1211
1212 for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1213 switch (registers[i]) {
1214 case UNWIND_X86_REG_NONE:
1215 break;
1216 case UNWIND_X86_REG_EBX:
1217 case UNWIND_X86_REG_ECX:
1218 case UNWIND_X86_REG_EDX:
1219 case UNWIND_X86_REG_EDI:
1220 case UNWIND_X86_REG_ESI:
1221 case UNWIND_X86_REG_EBP:
1222 row->SetRegisterLocationToAtCFAPlusOffset(
1223 translate_to_eh_frame_regnum_i386(registers[i]),
1224 wordsize * -saved_registers_offset, true);
1225 saved_registers_offset++;
1226 break;
1227 }
1228 }
1229 }
1230
1231 unwind_plan.AppendRow(row);
1232 return true;
1233 } break;
1234
1235 case UNWIND_X86_MODE_DWARF: {
Jason Molendae589e7e2014-12-08 03:09:00 +00001236 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001237 } break;
1238 }
1239 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +00001240}
Jason Molendab667c202016-05-25 04:20:28 +00001241
Kate Stoneb9c1b512016-09-06 20:57:50 +00001242// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1243// doc by ARM
Jason Molendab667c202016-05-25 04:20:28 +00001244
1245enum arm64_eh_regnum {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001246 x19 = 19,
1247 x20 = 20,
1248 x21 = 21,
1249 x22 = 22,
1250 x23 = 23,
1251 x24 = 24,
1252 x25 = 25,
1253 x26 = 26,
1254 x27 = 27,
1255 x28 = 28,
Jason Molendab667c202016-05-25 04:20:28 +00001256
Kate Stoneb9c1b512016-09-06 20:57:50 +00001257 fp = 29,
1258 ra = 30,
1259 sp = 31,
1260 pc = 32,
Jason Molendab667c202016-05-25 04:20:28 +00001261
Kate Stoneb9c1b512016-09-06 20:57:50 +00001262 // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
1263 // for the 64-bit
1264 // fp regs. Normally in DWARF it's context sensitive - so it knows it is
1265 // fetching a
1266 // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder
1267 // is operating
1268 // at a lower level and we'd try to fetch 128 bits if we were told that v8
1269 // were stored on
1270 // the stack...
1271 v8 = 72,
1272 v9 = 73,
1273 v10 = 74,
1274 v11 = 75,
1275 v12 = 76,
1276 v13 = 77,
1277 v14 = 78,
1278 v15 = 79,
Jason Molendab667c202016-05-25 04:20:28 +00001279};
1280
Jason Molendac7afda52016-06-07 02:19:54 +00001281enum arm_eh_regnum {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001282 arm_r0 = 0,
1283 arm_r1 = 1,
1284 arm_r2 = 2,
1285 arm_r3 = 3,
1286 arm_r4 = 4,
1287 arm_r5 = 5,
1288 arm_r6 = 6,
1289 arm_r7 = 7,
1290 arm_r8 = 8,
1291 arm_r9 = 9,
1292 arm_r10 = 10,
1293 arm_r11 = 11,
1294 arm_r12 = 12,
Jason Molendac7afda52016-06-07 02:19:54 +00001295
Kate Stoneb9c1b512016-09-06 20:57:50 +00001296 arm_sp = 13,
1297 arm_lr = 14,
1298 arm_pc = 15,
Jason Molendac7afda52016-06-07 02:19:54 +00001299
Kate Stoneb9c1b512016-09-06 20:57:50 +00001300 arm_d0 = 256,
1301 arm_d1 = 257,
1302 arm_d2 = 258,
1303 arm_d3 = 259,
1304 arm_d4 = 260,
1305 arm_d5 = 261,
1306 arm_d6 = 262,
1307 arm_d7 = 263,
1308 arm_d8 = 264,
1309 arm_d9 = 265,
1310 arm_d10 = 266,
1311 arm_d11 = 267,
1312 arm_d12 = 268,
1313 arm_d13 = 269,
1314 arm_d14 = 270,
Jason Molendac7afda52016-06-07 02:19:54 +00001315};
1316
Kate Stoneb9c1b512016-09-06 20:57:50 +00001317bool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
1318 FunctionInfo &function_info,
1319 UnwindPlan &unwind_plan,
1320 Address pc_or_function_start) {
1321 unwind_plan.SetSourceName("compact unwind info");
1322 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1323 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1324 unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
Jason Molendac7afda52016-06-07 02:19:54 +00001325
Kate Stoneb9c1b512016-09-06 20:57:50 +00001326 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1327 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
Jason Molendac7afda52016-06-07 02:19:54 +00001328
Kate Stoneb9c1b512016-09-06 20:57:50 +00001329 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendab667c202016-05-25 04:20:28 +00001330
Kate Stoneb9c1b512016-09-06 20:57:50 +00001331 const int wordsize = 8;
1332 int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
Jason Molendab667c202016-05-25 04:20:28 +00001333
Kate Stoneb9c1b512016-09-06 20:57:50 +00001334 if (mode == UNWIND_ARM64_MODE_DWARF)
1335 return false;
Jason Molendab667c202016-05-25 04:20:28 +00001336
Kate Stoneb9c1b512016-09-06 20:57:50 +00001337 if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1338 row->SetOffset(0);
Jason Molendab667c202016-05-25 04:20:28 +00001339
Kate Stoneb9c1b512016-09-06 20:57:50 +00001340 uint32_t stack_size =
1341 (EXTRACT_BITS(function_info.encoding,
1342 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1343 16;
Jason Molendab667c202016-05-25 04:20:28 +00001344
Kate Stoneb9c1b512016-09-06 20:57:50 +00001345 // Our previous Call Frame Address is the stack pointer plus the stack size
1346 row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
Jason Molendab667c202016-05-25 04:20:28 +00001347
Kate Stoneb9c1b512016-09-06 20:57:50 +00001348 // Our previous PC is in the LR
1349 row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1350 true);
Jason Molendab667c202016-05-25 04:20:28 +00001351
Kate Stoneb9c1b512016-09-06 20:57:50 +00001352 unwind_plan.AppendRow(row);
Jason Molendab667c202016-05-25 04:20:28 +00001353 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001354 }
1355
1356 // Should not be possible
1357 if (mode != UNWIND_ARM64_MODE_FRAME)
1358 return false;
1359
1360 // mode == UNWIND_ARM64_MODE_FRAME
1361
1362 row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1363 row->SetOffset(0);
1364 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1365 true);
1366 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1367 true);
1368 row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1369
1370 int reg_pairs_saved_count = 1;
1371
1372 uint32_t saved_register_bits = function_info.encoding & 0xfff;
1373
1374 if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
1375 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1376 cfa_offset -= wordsize;
1377 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,
1378 true);
1379 cfa_offset -= wordsize;
1380 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1381 true);
1382 reg_pairs_saved_count++;
1383 }
1384
1385 if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
1386 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1387 cfa_offset -= wordsize;
1388 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,
1389 true);
1390 cfa_offset -= wordsize;
1391 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1392 true);
1393 reg_pairs_saved_count++;
1394 }
1395
1396 if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
1397 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1398 cfa_offset -= wordsize;
1399 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,
1400 true);
1401 cfa_offset -= wordsize;
1402 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1403 true);
1404 reg_pairs_saved_count++;
1405 }
1406
1407 if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
1408 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1409 cfa_offset -= wordsize;
1410 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,
1411 true);
1412 cfa_offset -= wordsize;
1413 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1414 true);
1415 reg_pairs_saved_count++;
1416 }
1417
1418 if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
1419 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1420 cfa_offset -= wordsize;
1421 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,
1422 true);
1423 cfa_offset -= wordsize;
1424 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1425 true);
1426 reg_pairs_saved_count++;
1427 }
1428
1429 // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1430 // off the stack;
1431 // not sure if we have a good way to represent the 64-bitness of these saves.
1432
1433 if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1434 reg_pairs_saved_count++;
1435 }
1436 if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1437 reg_pairs_saved_count++;
1438 }
1439 if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1440 reg_pairs_saved_count++;
1441 }
1442 if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1443 reg_pairs_saved_count++;
1444 }
1445
1446 unwind_plan.AppendRow(row);
1447 return true;
Jason Molendab667c202016-05-25 04:20:28 +00001448}
1449
Kate Stoneb9c1b512016-09-06 20:57:50 +00001450bool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
1451 FunctionInfo &function_info,
1452 UnwindPlan &unwind_plan,
1453 Address pc_or_function_start) {
1454 unwind_plan.SetSourceName("compact unwind info");
1455 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1456 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1457 unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
Jason Molendac7afda52016-06-07 02:19:54 +00001458
Kate Stoneb9c1b512016-09-06 20:57:50 +00001459 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1460 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
Jason Molendac7afda52016-06-07 02:19:54 +00001461
Kate Stoneb9c1b512016-09-06 20:57:50 +00001462 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendac7afda52016-06-07 02:19:54 +00001463
Kate Stoneb9c1b512016-09-06 20:57:50 +00001464 const int wordsize = 4;
1465 int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
Jason Molendac7afda52016-06-07 02:19:54 +00001466
Kate Stoneb9c1b512016-09-06 20:57:50 +00001467 if (mode == UNWIND_ARM_MODE_DWARF)
1468 return false;
Jason Molendac7afda52016-06-07 02:19:54 +00001469
Kate Stoneb9c1b512016-09-06 20:57:50 +00001470 uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1471 UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1472 wordsize;
Jason Molendac7afda52016-06-07 02:19:54 +00001473
Kate Stoneb9c1b512016-09-06 20:57:50 +00001474 row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1475 (2 * wordsize) + stack_adjust);
1476 row->SetOffset(0);
1477 row->SetRegisterLocationToAtCFAPlusOffset(
1478 arm_r7, (wordsize * -2) - stack_adjust, true);
1479 row->SetRegisterLocationToAtCFAPlusOffset(
1480 arm_pc, (wordsize * -1) - stack_adjust, true);
1481 row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);
Jason Molendac7afda52016-06-07 02:19:54 +00001482
Kate Stoneb9c1b512016-09-06 20:57:50 +00001483 int cfa_offset = -stack_adjust - (2 * wordsize);
Jason Molendac7afda52016-06-07 02:19:54 +00001484
Kate Stoneb9c1b512016-09-06 20:57:50 +00001485 uint32_t saved_register_bits = function_info.encoding & 0xff;
Jason Molendac7afda52016-06-07 02:19:54 +00001486
Kate Stoneb9c1b512016-09-06 20:57:50 +00001487 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1488 cfa_offset -= wordsize;
1489 row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1490 }
1491
1492 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1493 cfa_offset -= wordsize;
1494 row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1495 }
1496
1497 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1498 cfa_offset -= wordsize;
1499 row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1500 }
1501
1502 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1503 cfa_offset -= wordsize;
1504 row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1505 }
1506
1507 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1508 cfa_offset -= wordsize;
1509 row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1510 }
1511
1512 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1513 cfa_offset -= wordsize;
1514 row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1515 }
1516
1517 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1518 cfa_offset -= wordsize;
1519 row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1520 }
1521
1522 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1523 cfa_offset -= wordsize;
1524 row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
1525 }
1526
1527 if (mode == UNWIND_ARM_MODE_FRAME_D) {
1528 uint32_t d_reg_bits =
1529 EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1530 switch (d_reg_bits) {
1531 case 0:
1532 // vpush {d8}
1533 cfa_offset -= 8;
1534 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1535 break;
1536 case 1:
1537 // vpush {d10}
1538 // vpush {d8}
1539 cfa_offset -= 8;
1540 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1541 cfa_offset -= 8;
1542 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1543 break;
1544 case 2:
1545 // vpush {d12}
1546 // vpush {d10}
1547 // vpush {d8}
1548 cfa_offset -= 8;
1549 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1550 cfa_offset -= 8;
1551 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1552 cfa_offset -= 8;
1553 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1554 break;
1555 case 3:
1556 // vpush {d14}
1557 // vpush {d12}
1558 // vpush {d10}
1559 // vpush {d8}
1560 cfa_offset -= 8;
1561 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1562 cfa_offset -= 8;
1563 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1564 cfa_offset -= 8;
1565 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1566 cfa_offset -= 8;
1567 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1568 break;
1569 case 4:
1570 // vpush {d14}
1571 // vpush {d12}
1572 // sp = (sp - 24) & (-16);
1573 // vst {d8, d9, d10}
1574 cfa_offset -= 8;
1575 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1576 cfa_offset -= 8;
1577 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1578
1579 // FIXME we don't have a way to represent reg saves at an specific
1580 // alignment short of
1581 // coming up with some DWARF location description.
1582
1583 break;
1584 case 5:
1585 // vpush {d14}
1586 // sp = (sp - 40) & (-16);
1587 // vst {d8, d9, d10, d11}
1588 // vst {d12}
1589
1590 cfa_offset -= 8;
1591 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1592
1593 // FIXME we don't have a way to represent reg saves at an specific
1594 // alignment short of
1595 // coming up with some DWARF location description.
1596
1597 break;
1598 case 6:
1599 // sp = (sp - 56) & (-16);
1600 // vst {d8, d9, d10, d11}
1601 // vst {d12, d13, d14}
1602
1603 // FIXME we don't have a way to represent reg saves at an specific
1604 // alignment short of
1605 // coming up with some DWARF location description.
1606
1607 break;
1608 case 7:
1609 // sp = (sp - 64) & (-16);
1610 // vst {d8, d9, d10, d11}
1611 // vst {d12, d13, d14, d15}
1612
1613 // FIXME we don't have a way to represent reg saves at an specific
1614 // alignment short of
1615 // coming up with some DWARF location description.
1616
1617 break;
Jason Molendac7afda52016-06-07 02:19:54 +00001618 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001619 }
Jason Molendac7afda52016-06-07 02:19:54 +00001620
Kate Stoneb9c1b512016-09-06 20:57:50 +00001621 unwind_plan.AppendRow(row);
1622 return true;
Jason Molendac7afda52016-06-07 02:19:54 +00001623}