blob: 7af8b2b5dc7a0a1c958dea1431dbcfdd049391c9 [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
Jason Molendae589e7e2014-12-08 03:09:00 +000010// C Includes
11// C++ Includes
12#include <algorithm>
13
Jason Molendae589e7e2014-12-08 03:09:00 +000014#include "lldb/Core/ArchSpec.h"
Zachary Turneraf0f45f2015-03-03 21:05:17 +000015#include "lldb/Core/DataBufferHeap.h"
Jason Molendae589e7e2014-12-08 03:09:00 +000016#include "lldb/Core/Module.h"
17#include "lldb/Core/Section.h"
Jason Molendab12a1362014-12-20 03:12:51 +000018#include "lldb/Core/Section.h"
Jason Molendae589e7e2014-12-08 03:09:00 +000019#include "lldb/Symbol/CompactUnwindInfo.h"
20#include "lldb/Symbol/ObjectFile.h"
21#include "lldb/Symbol/UnwindPlan.h"
Jason Molendab12a1362014-12-20 03:12:51 +000022#include "lldb/Target/Process.h"
23#include "lldb/Target/Target.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000024#include "lldb/Utility/Log.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000025#include "lldb/Utility/StreamString.h"
Jason Molendae589e7e2014-12-08 03:09:00 +000026
Zachary Turner818a3672014-12-08 20:00:33 +000027#include "llvm/Support/MathExtras.h"
28
Jason Molendae589e7e2014-12-08 03:09:00 +000029using namespace lldb;
30using namespace lldb_private;
31
Jason Molendae589e7e2014-12-08 03:09:00 +000032namespace lldb_private {
33
Kate Stoneb9c1b512016-09-06 20:57:50 +000034// Constants from <mach-o/compact_unwind_encoding.h>
Jason Molendae589e7e2014-12-08 03:09:00 +000035
Kate Stoneb9c1b512016-09-06 20:57:50 +000036FLAGS_ANONYMOUS_ENUM(){
37 UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
38 UNWIND_PERSONALITY_MASK = 0x30000000,
39};
Jason Molendae589e7e2014-12-08 03:09:00 +000040
Kate Stoneb9c1b512016-09-06 20:57:50 +000041FLAGS_ANONYMOUS_ENUM(){
42 UNWIND_X86_MODE_MASK = 0x0F000000,
43 UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
44 UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
45 UNWIND_X86_MODE_STACK_IND = 0x03000000,
46 UNWIND_X86_MODE_DWARF = 0x04000000,
Jason Molendae589e7e2014-12-08 03:09:00 +000047
Kate Stoneb9c1b512016-09-06 20:57:50 +000048 UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
49 UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
Jason Molendae589e7e2014-12-08 03:09:00 +000050
Kate Stoneb9c1b512016-09-06 20:57:50 +000051 UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
52 UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
53 UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
54 UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
Jason Molendae589e7e2014-12-08 03:09:00 +000055
Kate Stoneb9c1b512016-09-06 20:57:50 +000056 UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
57};
Jason Molendae589e7e2014-12-08 03:09:00 +000058
Kate Stoneb9c1b512016-09-06 20:57:50 +000059enum {
60 UNWIND_X86_REG_NONE = 0,
61 UNWIND_X86_REG_EBX = 1,
62 UNWIND_X86_REG_ECX = 2,
63 UNWIND_X86_REG_EDX = 3,
64 UNWIND_X86_REG_EDI = 4,
65 UNWIND_X86_REG_ESI = 5,
66 UNWIND_X86_REG_EBP = 6,
67};
Zachary Turner48b475c2015-04-02 20:57:38 +000068
Kate Stoneb9c1b512016-09-06 20:57:50 +000069FLAGS_ANONYMOUS_ENUM(){
70 UNWIND_X86_64_MODE_MASK = 0x0F000000,
71 UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
72 UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
73 UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
74 UNWIND_X86_64_MODE_DWARF = 0x04000000,
Jason Molendae589e7e2014-12-08 03:09:00 +000075
Kate Stoneb9c1b512016-09-06 20:57:50 +000076 UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
77 UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
Jason Molendae589e7e2014-12-08 03:09:00 +000078
Kate Stoneb9c1b512016-09-06 20:57:50 +000079 UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
80 UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
81 UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
82 UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
Jason Molendae589e7e2014-12-08 03:09:00 +000083
Kate Stoneb9c1b512016-09-06 20:57:50 +000084 UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
85};
Jason Molendae589e7e2014-12-08 03:09:00 +000086
Kate Stoneb9c1b512016-09-06 20:57:50 +000087enum {
88 UNWIND_X86_64_REG_NONE = 0,
89 UNWIND_X86_64_REG_RBX = 1,
90 UNWIND_X86_64_REG_R12 = 2,
91 UNWIND_X86_64_REG_R13 = 3,
92 UNWIND_X86_64_REG_R14 = 4,
93 UNWIND_X86_64_REG_R15 = 5,
94 UNWIND_X86_64_REG_RBP = 6,
95};
Jason Molendab667c202016-05-25 04:20:28 +000096
Kate Stoneb9c1b512016-09-06 20:57:50 +000097FLAGS_ANONYMOUS_ENUM(){
98 UNWIND_ARM64_MODE_MASK = 0x0F000000,
99 UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
100 UNWIND_ARM64_MODE_DWARF = 0x03000000,
101 UNWIND_ARM64_MODE_FRAME = 0x04000000,
Jason Molendab667c202016-05-25 04:20:28 +0000102
Kate Stoneb9c1b512016-09-06 20:57:50 +0000103 UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
104 UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
105 UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
106 UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
107 UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
108 UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
109 UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
110 UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
111 UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
Jason Molendab667c202016-05-25 04:20:28 +0000112
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
114 UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
115};
Jason Molendac7afda52016-06-07 02:19:54 +0000116
Kate Stoneb9c1b512016-09-06 20:57:50 +0000117FLAGS_ANONYMOUS_ENUM(){
118 UNWIND_ARM_MODE_MASK = 0x0F000000,
119 UNWIND_ARM_MODE_FRAME = 0x01000000,
120 UNWIND_ARM_MODE_FRAME_D = 0x02000000,
121 UNWIND_ARM_MODE_DWARF = 0x04000000,
Jason Molendac7afda52016-06-07 02:19:54 +0000122
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123 UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
Jason Molendac7afda52016-06-07 02:19:54 +0000124
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
126 UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
127 UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
Jason Molendac7afda52016-06-07 02:19:54 +0000128
Kate Stoneb9c1b512016-09-06 20:57:50 +0000129 UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,
130 UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,
131 UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,
132 UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,
133 UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,
Jason Molendac7afda52016-06-07 02:19:54 +0000134
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
Jason Molendac7afda52016-06-07 02:19:54 +0000136
Kate Stoneb9c1b512016-09-06 20:57:50 +0000137 UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
138};
Vince Harrond7e6a4f2015-05-13 00:25:54 +0000139}
Jason Molendae589e7e2014-12-08 03:09:00 +0000140
Jason Molendae589e7e2014-12-08 03:09:00 +0000141#ifndef UNWIND_SECOND_LEVEL_REGULAR
142#define UNWIND_SECOND_LEVEL_REGULAR 2
143#endif
144
145#ifndef UNWIND_SECOND_LEVEL_COMPRESSED
146#define UNWIND_SECOND_LEVEL_COMPRESSED 3
147#endif
148
149#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
Jason Molendae589e7e2014-12-08 03:09:00 +0000151#endif
152
153#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \
155 ((entry >> 24) & 0xFF)
Jason Molendae589e7e2014-12-08 03:09:00 +0000156#endif
157
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158#define EXTRACT_BITS(value, mask) \
159 ((value >> \
160 llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \
161 (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1))
Jason Molendae589e7e2014-12-08 03:09:00 +0000162
163//----------------------
Jason Molendac7afda52016-06-07 02:19:54 +0000164// constructor
Jason Molendae589e7e2014-12-08 03:09:00 +0000165//----------------------
166
Saleem Abdulrasoolbb19a132016-05-19 05:13:57 +0000167CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP &section_sp)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000168 : m_objfile(objfile), m_section_sp(section_sp),
169 m_section_contents_if_encrypted(), m_mutex(), m_indexes(),
170 m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(),
171 m_unwindinfo_data_computed(false), m_unwind_header() {}
Jason Molendae589e7e2014-12-08 03:09:00 +0000172
173//----------------------
174// destructor
175//----------------------
176
Kate Stoneb9c1b512016-09-06 20:57:50 +0000177CompactUnwindInfo::~CompactUnwindInfo() {}
Jason Molendae589e7e2014-12-08 03:09:00 +0000178
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
180 UnwindPlan &unwind_plan) {
181 if (!IsValid(target.GetProcessSP())) {
Jason Molendae589e7e2014-12-08 03:09:00 +0000182 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000183 }
184 FunctionInfo function_info;
185 if (GetCompactUnwindInfoForFunction(target, addr, function_info)) {
186 // shortcut return for functions that have no compact unwind
187 if (function_info.encoding == 0)
188 return false;
189
190 ArchSpec arch;
191 if (m_objfile.GetArchitecture(arch)) {
192
193 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
194 if (log && log->GetVerbose()) {
195 StreamString strm;
196 addr.Dump(
197 &strm, NULL,
198 Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments,
199 Address::DumpStyle::DumpStyleFileAddress,
200 arch.GetAddressByteSize());
201 log->Printf("Got compact unwind encoding 0x%x for function %s",
202 function_info.encoding, strm.GetData());
203 }
204
205 if (function_info.valid_range_offset_start != 0 &&
206 function_info.valid_range_offset_end != 0) {
207 SectionList *sl = m_objfile.GetSectionList();
208 if (sl) {
209 addr_t func_range_start_file_addr =
210 function_info.valid_range_offset_start +
211 m_objfile.GetHeaderAddress().GetFileAddress();
212 AddressRange func_range(func_range_start_file_addr,
213 function_info.valid_range_offset_end -
214 function_info.valid_range_offset_start,
215 sl);
216 unwind_plan.SetPlanValidAddressRange(func_range);
217 }
218 }
219
220 if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
221 return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
222 addr);
223 }
224 if (arch.GetTriple().getArch() == llvm::Triple::aarch64) {
225 return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
226 }
227 if (arch.GetTriple().getArch() == llvm::Triple::x86) {
228 return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
229 }
230 if (arch.GetTriple().getArch() == llvm::Triple::arm ||
231 arch.GetTriple().getArch() == llvm::Triple::thumb) {
232 return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);
233 }
234 }
235 }
236 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000237}
238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239bool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
240 if (m_section_sp.get() == nullptr)
241 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000242
Kate Stoneb9c1b512016-09-06 20:57:50 +0000243 if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
244 return true;
Jason Molendae589e7e2014-12-08 03:09:00 +0000245
Kate Stoneb9c1b512016-09-06 20:57:50 +0000246 ScanIndex(process_sp);
Jason Molendae589e7e2014-12-08 03:09:00 +0000247
Kate Stoneb9c1b512016-09-06 20:57:50 +0000248 return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
Jason Molendae589e7e2014-12-08 03:09:00 +0000249}
250
Kate Stoneb9c1b512016-09-06 20:57:50 +0000251void CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {
252 std::lock_guard<std::mutex> guard(m_mutex);
253 if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
254 return;
255
256 // We can't read the index for some reason.
257 if (m_indexes_computed == eLazyBoolNo) {
258 return;
259 }
260
261 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
262 if (log)
263 m_objfile.GetModule()->LogMessage(
264 log, "Reading compact unwind first-level indexes");
265
266 if (m_unwindinfo_data_computed == false) {
267 if (m_section_sp->IsEncrypted()) {
268 // Can't get section contents of a protected/encrypted section until we
269 // have a live
270 // process and can read them out of memory.
271 if (process_sp.get() == nullptr)
Jason Molendae589e7e2014-12-08 03:09:00 +0000272 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000273 m_section_contents_if_encrypted.reset(
274 new DataBufferHeap(m_section_sp->GetByteSize(), 0));
275 Error error;
276 if (process_sp->ReadMemory(
277 m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),
278 m_section_contents_if_encrypted->GetBytes(),
279 m_section_sp->GetByteSize(),
280 error) == m_section_sp->GetByteSize() &&
281 error.Success()) {
282 m_unwindinfo_data.SetAddressByteSize(
283 process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
284 m_unwindinfo_data.SetByteOrder(
285 process_sp->GetTarget().GetArchitecture().GetByteOrder());
286 m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);
287 }
288 } else {
289 m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
290 }
291 if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
292 return;
293 m_unwindinfo_data_computed = true;
294 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000295
Kate Stoneb9c1b512016-09-06 20:57:50 +0000296 if (m_unwindinfo_data.GetByteSize() > 0) {
297 offset_t offset = 0;
298
299 // struct unwind_info_section_header
300 // {
301 // uint32_t version; // UNWIND_SECTION_VERSION
302 // uint32_t commonEncodingsArraySectionOffset;
303 // uint32_t commonEncodingsArrayCount;
304 // uint32_t personalityArraySectionOffset;
305 // uint32_t personalityArrayCount;
306 // uint32_t indexSectionOffset;
307 // uint32_t indexCount;
308
309 m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);
310 m_unwind_header.common_encodings_array_offset =
311 m_unwindinfo_data.GetU32(&offset);
312 m_unwind_header.common_encodings_array_count =
313 m_unwindinfo_data.GetU32(&offset);
314 m_unwind_header.personality_array_offset =
315 m_unwindinfo_data.GetU32(&offset);
316 m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);
317 uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);
318
319 uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
320
321 if (m_unwind_header.common_encodings_array_offset >
322 m_unwindinfo_data.GetByteSize() ||
323 m_unwind_header.personality_array_offset >
324 m_unwindinfo_data.GetByteSize() ||
325 indexSectionOffset > m_unwindinfo_data.GetByteSize() ||
326 offset > m_unwindinfo_data.GetByteSize()) {
327 Host::SystemLog(Host::eSystemLogError, "error: Invalid offset "
328 "encountered in compact unwind "
329 "info, skipping\n");
330 // don't trust anything from this compact_unwind section if it looks
331 // blatantly invalid data in the header.
332 m_indexes_computed = eLazyBoolNo;
333 return;
Jason Molendae589e7e2014-12-08 03:09:00 +0000334 }
335
Kate Stoneb9c1b512016-09-06 20:57:50 +0000336 // Parse the basic information from the indexes
337 // We wait to scan the second level page info until it's needed
Jason Molenda5c45c542014-12-21 10:44:54 +0000338
Kate Stoneb9c1b512016-09-06 20:57:50 +0000339 // struct unwind_info_section_header_index_entry
340 // {
341 // uint32_t functionOffset;
342 // uint32_t secondLevelPagesSectionOffset;
343 // uint32_t lsdaIndexArraySectionOffset;
344 // };
345
346 bool clear_address_zeroth_bit = false;
347 ArchSpec arch;
348 if (m_objfile.GetArchitecture(arch)) {
349 if (arch.GetTriple().getArch() == llvm::Triple::arm ||
350 arch.GetTriple().getArch() == llvm::Triple::thumb)
351 clear_address_zeroth_bit = true;
Jason Molendae589e7e2014-12-08 03:09:00 +0000352 }
353
Kate Stoneb9c1b512016-09-06 20:57:50 +0000354 offset = indexSectionOffset;
355 for (uint32_t idx = 0; idx < indexCount; idx++) {
356 uint32_t function_offset =
357 m_unwindinfo_data.GetU32(&offset); // functionOffset
358 uint32_t second_level_offset =
359 m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset
360 uint32_t lsda_offset =
361 m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset
Jason Molendae589e7e2014-12-08 03:09:00 +0000362
Kate Stoneb9c1b512016-09-06 20:57:50 +0000363 if (second_level_offset > m_section_sp->GetByteSize() ||
364 lsda_offset > m_section_sp->GetByteSize()) {
Jason Molendae589e7e2014-12-08 03:09:00 +0000365 m_indexes_computed = eLazyBoolNo;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000366 }
367
368 if (clear_address_zeroth_bit)
369 function_offset &= ~1ull;
370
371 UnwindIndex this_index;
372 this_index.function_offset = function_offset;
373 this_index.second_level = second_level_offset;
374 this_index.lsda_array_start = lsda_offset;
375
376 if (m_indexes.size() > 0) {
377 m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
378 }
379
380 if (second_level_offset == 0) {
381 this_index.sentinal_entry = true;
382 }
383
384 m_indexes.push_back(this_index);
Jason Molendae589e7e2014-12-08 03:09:00 +0000385 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000386 m_indexes_computed = eLazyBoolYes;
387 } else {
388 m_indexes_computed = eLazyBoolNo;
389 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000390}
391
Kate Stoneb9c1b512016-09-06 20:57:50 +0000392uint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
393 uint32_t lsda_count,
394 uint32_t function_offset) {
395 // struct unwind_info_section_header_lsda_index_entry
396 // {
397 // uint32_t functionOffset;
398 // uint32_t lsdaOffset;
399 // };
Jason Molendae589e7e2014-12-08 03:09:00 +0000400
Kate Stoneb9c1b512016-09-06 20:57:50 +0000401 offset_t first_entry = lsda_offset;
402 uint32_t low = 0;
403 uint32_t high = lsda_count;
404 while (low < high) {
405 uint32_t mid = (low + high) / 2;
406 offset_t offset = first_entry + (mid * 8);
407 uint32_t mid_func_offset =
408 m_unwindinfo_data.GetU32(&offset); // functionOffset
409 uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset
410 if (mid_func_offset == function_offset) {
411 return mid_lsda_offset;
Jason Molendae589e7e2014-12-08 03:09:00 +0000412 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000413 if (mid_func_offset < function_offset) {
414 low = mid + 1;
415 } else {
416 high = mid;
417 }
418 }
419 return 0;
Jason Molendae589e7e2014-12-08 03:09:00 +0000420}
421
Kate Stoneb9c1b512016-09-06 20:57:50 +0000422lldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(
423 uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,
424 uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
425 // typedef uint32_t compact_unwind_encoding_t;
426 // struct unwind_info_regular_second_level_entry
427 // {
428 // uint32_t functionOffset;
429 // compact_unwind_encoding_t encoding;
430
431 offset_t first_entry = entry_page_offset;
432
433 uint32_t low = 0;
434 uint32_t high = entry_count;
435 uint32_t last = high - 1;
436 while (low < high) {
437 uint32_t mid = (low + high) / 2;
438 offset_t offset = first_entry + (mid * 8);
439 uint32_t mid_func_offset =
440 m_unwindinfo_data.GetU32(&offset); // functionOffset
441 uint32_t next_func_offset = 0;
442 if (mid < last) {
443 offset = first_entry + ((mid + 1) * 8);
444 next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
445 }
446 if (mid_func_offset <= function_offset) {
447 if (mid == last || (next_func_offset > function_offset)) {
448 if (entry_func_start_offset)
449 *entry_func_start_offset = mid_func_offset;
450 if (mid != last && entry_func_end_offset)
451 *entry_func_end_offset = next_func_offset;
452 return first_entry + (mid * 8);
453 } else {
454 low = mid + 1;
455 }
456 } else {
457 high = mid;
458 }
459 }
460 return LLDB_INVALID_OFFSET;
461}
462
463uint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(
464 uint32_t entry_page_offset, uint32_t entry_count,
465 uint32_t function_offset_to_find, uint32_t function_offset_base,
466 uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {
467 offset_t first_entry = entry_page_offset;
468
469 uint32_t low = 0;
470 uint32_t high = entry_count;
471 uint32_t last = high - 1;
472 while (low < high) {
473 uint32_t mid = (low + high) / 2;
474 offset_t offset = first_entry + (mid * 4);
475 uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry
476 uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);
477 mid_func_offset += function_offset_base;
478 uint32_t next_func_offset = 0;
479 if (mid < last) {
480 offset = first_entry + ((mid + 1) * 4);
481 uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry
482 next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);
483 next_func_offset += function_offset_base;
484 }
485 if (mid_func_offset <= function_offset_to_find) {
486 if (mid == last || (next_func_offset > function_offset_to_find)) {
487 if (entry_func_start_offset)
488 *entry_func_start_offset = mid_func_offset;
489 if (mid != last && entry_func_end_offset)
490 *entry_func_end_offset = next_func_offset;
491 return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);
492 } else {
493 low = mid + 1;
494 }
495 } else {
496 high = mid;
497 }
498 }
499
500 return UINT32_MAX;
501}
502
503bool CompactUnwindInfo::GetCompactUnwindInfoForFunction(
504 Target &target, Address address, FunctionInfo &unwind_info) {
505 unwind_info.encoding = 0;
506 unwind_info.lsda_address.Clear();
507 unwind_info.personality_ptr_address.Clear();
508
509 if (!IsValid(target.GetProcessSP()))
510 return false;
511
512 addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
513 SectionList *sl = m_objfile.GetSectionList();
514 if (sl) {
515 SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
516 if (text_sect.get()) {
517 text_section_file_address = text_sect->GetFileAddress();
518 }
519 }
520 if (text_section_file_address == LLDB_INVALID_ADDRESS)
521 return false;
522
523 addr_t function_offset =
524 address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress();
525
526 UnwindIndex key;
527 key.function_offset = function_offset;
528
529 std::vector<UnwindIndex>::const_iterator it;
530 it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key);
531 if (it == m_indexes.end()) {
532 return false;
533 }
534
535 if (it->function_offset != key.function_offset) {
536 if (it != m_indexes.begin())
537 --it;
538 }
539
540 if (it->sentinal_entry == true) {
541 return false;
542 }
543
544 auto next_it = it + 1;
545 if (next_it != m_indexes.end()) {
546 // initialize the function offset end range to be the start of the
547 // next index offset. If we find an entry which is at the end of
548 // the index table, this will establish the range end.
549 unwind_info.valid_range_offset_end = next_it->function_offset;
550 }
551
552 offset_t second_page_offset = it->second_level;
553 offset_t lsda_array_start = it->lsda_array_start;
554 offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;
555
556 offset_t offset = second_page_offset;
557 uint32_t kind = m_unwindinfo_data.GetU32(
558 &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED
559
560 if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
561 // struct unwind_info_regular_second_level_page_header
562 // {
563 // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
564 // uint16_t entryPageOffset;
565 // uint16_t entryCount;
566
Jason Molendae589e7e2014-12-08 03:09:00 +0000567 // typedef uint32_t compact_unwind_encoding_t;
Jason Molendac7afda52016-06-07 02:19:54 +0000568 // struct unwind_info_regular_second_level_entry
Jason Molendae589e7e2014-12-08 03:09:00 +0000569 // {
570 // uint32_t functionOffset;
571 // compact_unwind_encoding_t encoding;
572
Kate Stoneb9c1b512016-09-06 20:57:50 +0000573 uint16_t entry_page_offset =
574 m_unwindinfo_data.GetU16(&offset); // entryPageOffset
575 uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
Jason Molendae589e7e2014-12-08 03:09:00 +0000576
Kate Stoneb9c1b512016-09-06 20:57:50 +0000577 offset_t entry_offset = BinarySearchRegularSecondPage(
578 second_page_offset + entry_page_offset, entry_count, function_offset,
579 &unwind_info.valid_range_offset_start,
580 &unwind_info.valid_range_offset_end);
581 if (entry_offset == LLDB_INVALID_OFFSET) {
582 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000583 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000584 entry_offset += 4; // skip over functionOffset
585 unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding
586 if (unwind_info.encoding & UNWIND_HAS_LSDA) {
587 SectionList *sl = m_objfile.GetSectionList();
588 if (sl) {
589 uint32_t lsda_offset = GetLSDAForFunctionOffset(
590 lsda_array_start, lsda_array_count, function_offset);
591 addr_t objfile_header_file_address =
592 m_objfile.GetHeaderAddress().GetFileAddress();
593 unwind_info.lsda_address.ResolveAddressUsingFileSections(
594 objfile_header_file_address + lsda_offset, sl);
595 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000596 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000597 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
598 uint32_t personality_index =
599 EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
Jason Molendae589e7e2014-12-08 03:09:00 +0000600
Kate Stoneb9c1b512016-09-06 20:57:50 +0000601 if (personality_index > 0) {
602 personality_index--;
603 if (personality_index < m_unwind_header.personality_array_count) {
604 offset_t offset = m_unwind_header.personality_array_offset;
605 offset += 4 * personality_index;
606 SectionList *sl = m_objfile.GetSectionList();
607 if (sl) {
608 uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
609 addr_t objfile_header_file_address =
610 m_objfile.GetHeaderAddress().GetFileAddress();
611 unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
612 objfile_header_file_address + personality_offset, sl);
613 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000614 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000615 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000616 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000617 return true;
618 } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
619 // struct unwind_info_compressed_second_level_page_header
620 // {
621 // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
622 // uint16_t entryPageOffset; // offset from this 2nd lvl page
623 // idx to array of entries
624 // // (an entry has a function
625 // offset and index into the
626 // encodings)
627 // // NB function offset from the
628 // entry in the compressed page
629 // // must be added to the index's
630 // functionOffset value.
631 // uint16_t entryCount;
632 // uint16_t encodingsPageOffset; // offset from this 2nd lvl page
633 // idx to array of encodings
634 // uint16_t encodingsCount;
Jason Molendae589e7e2014-12-08 03:09:00 +0000635
Kate Stoneb9c1b512016-09-06 20:57:50 +0000636 uint16_t entry_page_offset =
637 m_unwindinfo_data.GetU16(&offset); // entryPageOffset
638 uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
639 uint16_t encodings_page_offset =
640 m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset
641 uint16_t encodings_count =
642 m_unwindinfo_data.GetU16(&offset); // encodingsCount
Jason Molendac7afda52016-06-07 02:19:54 +0000643
Kate Stoneb9c1b512016-09-06 20:57:50 +0000644 uint32_t encoding_index = BinarySearchCompressedSecondPage(
645 second_page_offset + entry_page_offset, entry_count, function_offset,
646 it->function_offset, &unwind_info.valid_range_offset_start,
647 &unwind_info.valid_range_offset_end);
648 if (encoding_index == UINT32_MAX ||
649 encoding_index >=
650 encodings_count + m_unwind_header.common_encodings_array_count) {
651 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000652 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000653 uint32_t encoding = 0;
654 if (encoding_index < m_unwind_header.common_encodings_array_count) {
655 offset = m_unwind_header.common_encodings_array_offset +
656 (encoding_index * sizeof(uint32_t));
657 encoding = m_unwindinfo_data.GetU32(
658 &offset); // encoding entry from the commonEncodingsArray
659 } else {
660 uint32_t page_specific_entry_index =
661 encoding_index - m_unwind_header.common_encodings_array_count;
662 offset = second_page_offset + encodings_page_offset +
663 (page_specific_entry_index * sizeof(uint32_t));
664 encoding = m_unwindinfo_data.GetU32(
665 &offset); // encoding entry from the page-specific encoding array
Jason Molendae589e7e2014-12-08 03:09:00 +0000666 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000667 if (encoding == 0)
668 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000669
Kate Stoneb9c1b512016-09-06 20:57:50 +0000670 unwind_info.encoding = encoding;
671 if (unwind_info.encoding & UNWIND_HAS_LSDA) {
672 SectionList *sl = m_objfile.GetSectionList();
673 if (sl) {
674 uint32_t lsda_offset = GetLSDAForFunctionOffset(
675 lsda_array_start, lsda_array_count, function_offset);
676 addr_t objfile_header_file_address =
677 m_objfile.GetHeaderAddress().GetFileAddress();
678 unwind_info.lsda_address.ResolveAddressUsingFileSections(
679 objfile_header_file_address + lsda_offset, sl);
680 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000681 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000682 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
683 uint32_t personality_index =
684 EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
Jason Molendae589e7e2014-12-08 03:09:00 +0000685
Kate Stoneb9c1b512016-09-06 20:57:50 +0000686 if (personality_index > 0) {
687 personality_index--;
688 if (personality_index < m_unwind_header.personality_array_count) {
689 offset_t offset = m_unwind_header.personality_array_offset;
690 offset += 4 * personality_index;
691 SectionList *sl = m_objfile.GetSectionList();
692 if (sl) {
693 uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);
694 addr_t objfile_header_file_address =
695 m_objfile.GetHeaderAddress().GetFileAddress();
696 unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(
697 objfile_header_file_address + personality_offset, sl);
698 }
699 }
700 }
Jason Molenda5c45c542014-12-21 10:44:54 +0000701 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000702 return true;
703 }
704 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000705}
706
707enum x86_64_eh_regnum {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000708 rax = 0,
709 rdx = 1,
710 rcx = 2,
711 rbx = 3,
712 rsi = 4,
713 rdi = 5,
714 rbp = 6,
715 rsp = 7,
716 r8 = 8,
717 r9 = 9,
718 r10 = 10,
719 r11 = 11,
720 r12 = 12,
721 r13 = 13,
722 r14 = 14,
723 r15 = 15,
724 rip = 16 // this is officially the Return Address register number, but close
725 // enough
Jason Molendae589e7e2014-12-08 03:09:00 +0000726};
727
728// Convert the compact_unwind_info.h register numbering scheme
Jason Molenda63bd0db2015-09-15 23:20:34 +0000729// to eRegisterKindEHFrame (eh_frame) register numbering scheme.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000730uint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {
731 switch (unwind_regno) {
732 case UNWIND_X86_64_REG_RBX:
733 return x86_64_eh_regnum::rbx;
734 case UNWIND_X86_64_REG_R12:
735 return x86_64_eh_regnum::r12;
736 case UNWIND_X86_64_REG_R13:
737 return x86_64_eh_regnum::r13;
738 case UNWIND_X86_64_REG_R14:
739 return x86_64_eh_regnum::r14;
740 case UNWIND_X86_64_REG_R15:
741 return x86_64_eh_regnum::r15;
742 case UNWIND_X86_64_REG_RBP:
743 return x86_64_eh_regnum::rbp;
744 default:
745 return LLDB_INVALID_REGNUM;
746 }
Jason Molendae589e7e2014-12-08 03:09:00 +0000747}
748
Kate Stoneb9c1b512016-09-06 20:57:50 +0000749bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
750 FunctionInfo &function_info,
751 UnwindPlan &unwind_plan,
752 Address pc_or_function_start) {
753 unwind_plan.SetSourceName("compact unwind info");
754 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
755 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
756 unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
Jason Molendae589e7e2014-12-08 03:09:00 +0000757
Kate Stoneb9c1b512016-09-06 20:57:50 +0000758 unwind_plan.SetLSDAAddress(function_info.lsda_address);
759 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
Jason Molendae589e7e2014-12-08 03:09:00 +0000760
Kate Stoneb9c1b512016-09-06 20:57:50 +0000761 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendae589e7e2014-12-08 03:09:00 +0000762
Kate Stoneb9c1b512016-09-06 20:57:50 +0000763 const int wordsize = 8;
764 int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
765 switch (mode) {
766 case UNWIND_X86_64_MODE_RBP_FRAME: {
767 row->GetCFAValue().SetIsRegisterPlusOffset(
768 translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),
769 2 * wordsize);
770 row->SetOffset(0);
771 row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,
772 wordsize * -2, true);
773 row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
774 wordsize * -1, true);
775 row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
Jason Molendac7afda52016-06-07 02:19:54 +0000776
Kate Stoneb9c1b512016-09-06 20:57:50 +0000777 uint32_t saved_registers_offset =
778 EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
Jason Molendae589e7e2014-12-08 03:09:00 +0000779
Kate Stoneb9c1b512016-09-06 20:57:50 +0000780 uint32_t saved_registers_locations =
781 EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
Jason Molendae589e7e2014-12-08 03:09:00 +0000782
Kate Stoneb9c1b512016-09-06 20:57:50 +0000783 saved_registers_offset += 2;
Jason Molendae589e7e2014-12-08 03:09:00 +0000784
Kate Stoneb9c1b512016-09-06 20:57:50 +0000785 for (int i = 0; i < 5; i++) {
786 uint32_t regnum = saved_registers_locations & 0x7;
787 switch (regnum) {
788 case UNWIND_X86_64_REG_NONE:
Jason Molendae589e7e2014-12-08 03:09:00 +0000789 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000790 case UNWIND_X86_64_REG_RBX:
791 case UNWIND_X86_64_REG_R12:
792 case UNWIND_X86_64_REG_R13:
793 case UNWIND_X86_64_REG_R14:
794 case UNWIND_X86_64_REG_R15:
795 row->SetRegisterLocationToAtCFAPlusOffset(
796 translate_to_eh_frame_regnum_x86_64(regnum),
797 wordsize * -saved_registers_offset, true);
Jason Molendae589e7e2014-12-08 03:09:00 +0000798 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000799 }
800 saved_registers_offset--;
801 saved_registers_locations >>= 3;
Jason Molendae589e7e2014-12-08 03:09:00 +0000802 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000803 unwind_plan.AppendRow(row);
804 return true;
805 } break;
806
807 case UNWIND_X86_64_MODE_STACK_IND: {
808 // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
809 // this
810 // style of unwind. It was fixed in llvm r217020.
811 // The clang in Xcode 7 has this fixed.
Jason Molendae589e7e2014-12-08 03:09:00 +0000812 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000813 } break;
814
815 case UNWIND_X86_64_MODE_STACK_IMMD: {
816 uint32_t stack_size = EXTRACT_BITS(function_info.encoding,
817 UNWIND_X86_64_FRAMELESS_STACK_SIZE);
818 uint32_t register_count = EXTRACT_BITS(
819 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
820 uint32_t permutation = EXTRACT_BITS(
821 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
822
823 if (mode == UNWIND_X86_64_MODE_STACK_IND &&
824 function_info.valid_range_offset_start != 0) {
825 uint32_t stack_adjust = EXTRACT_BITS(
826 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
827
828 // offset into the function instructions; 0 == beginning of first
829 // instruction
830 uint32_t offset_to_subl_insn = EXTRACT_BITS(
831 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
832
833 SectionList *sl = m_objfile.GetSectionList();
834 if (sl) {
835 ProcessSP process_sp = target.GetProcessSP();
836 if (process_sp) {
837 Address subl_payload_addr(function_info.valid_range_offset_start, sl);
838 subl_payload_addr.Slide(offset_to_subl_insn);
839 Error error;
840 uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
841 subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
842 if (large_stack_size != 0 && error.Success()) {
843 // Got the large stack frame size correctly - use it
844 stack_size = large_stack_size + (stack_adjust * wordsize);
845 } else {
846 return false;
847 }
848 } else {
849 return false;
850 }
851 } else {
852 return false;
853 }
854 }
855
856 int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
857 ? stack_size
858 : stack_size * wordsize;
859 row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
860
861 row->SetOffset(0);
862 row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
863 wordsize * -1, true);
864 row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
865
866 if (register_count > 0) {
867
868 // We need to include (up to) 6 registers in 10 bits.
869 // That would be 18 bits if we just used 3 bits per reg to indicate
870 // the order they're saved on the stack.
871 //
872 // This is done with Lehmer code permutation, e.g. see
873 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
874 int permunreg[6] = {0, 0, 0, 0, 0, 0};
875
876 // This decodes the variable-base number in the 10 bits
877 // and gives us the Lehmer code sequence which can then
878 // be decoded.
879
880 switch (register_count) {
881 case 6:
882 permunreg[0] = permutation / 120; // 120 == 5!
883 permutation -= (permunreg[0] * 120);
884 permunreg[1] = permutation / 24; // 24 == 4!
885 permutation -= (permunreg[1] * 24);
886 permunreg[2] = permutation / 6; // 6 == 3!
887 permutation -= (permunreg[2] * 6);
888 permunreg[3] = permutation / 2; // 2 == 2!
889 permutation -= (permunreg[3] * 2);
890 permunreg[4] = permutation; // 1 == 1!
891 permunreg[5] = 0;
892 break;
893 case 5:
894 permunreg[0] = permutation / 120;
895 permutation -= (permunreg[0] * 120);
896 permunreg[1] = permutation / 24;
897 permutation -= (permunreg[1] * 24);
898 permunreg[2] = permutation / 6;
899 permutation -= (permunreg[2] * 6);
900 permunreg[3] = permutation / 2;
901 permutation -= (permunreg[3] * 2);
902 permunreg[4] = permutation;
903 break;
904 case 4:
905 permunreg[0] = permutation / 60;
906 permutation -= (permunreg[0] * 60);
907 permunreg[1] = permutation / 12;
908 permutation -= (permunreg[1] * 12);
909 permunreg[2] = permutation / 3;
910 permutation -= (permunreg[2] * 3);
911 permunreg[3] = permutation;
912 break;
913 case 3:
914 permunreg[0] = permutation / 20;
915 permutation -= (permunreg[0] * 20);
916 permunreg[1] = permutation / 4;
917 permutation -= (permunreg[1] * 4);
918 permunreg[2] = permutation;
919 break;
920 case 2:
921 permunreg[0] = permutation / 5;
922 permutation -= (permunreg[0] * 5);
923 permunreg[1] = permutation;
924 break;
925 case 1:
926 permunreg[0] = permutation;
927 break;
928 }
929
930 // Decode the Lehmer code for this permutation of
931 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
932
933 int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
934 UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,
935 UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};
936 bool used[7] = {false, false, false, false, false, false, false};
937 for (uint32_t i = 0; i < register_count; i++) {
938 int renum = 0;
939 for (int j = 1; j < 7; j++) {
940 if (used[j] == false) {
941 if (renum == permunreg[i]) {
942 registers[i] = j;
943 used[j] = true;
944 break;
945 }
946 renum++;
947 }
948 }
949 }
950
951 uint32_t saved_registers_offset = 1;
952 saved_registers_offset++;
953
954 for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
955 switch (registers[i]) {
956 case UNWIND_X86_64_REG_NONE:
957 break;
958 case UNWIND_X86_64_REG_RBX:
959 case UNWIND_X86_64_REG_R12:
960 case UNWIND_X86_64_REG_R13:
961 case UNWIND_X86_64_REG_R14:
962 case UNWIND_X86_64_REG_R15:
963 case UNWIND_X86_64_REG_RBP:
964 row->SetRegisterLocationToAtCFAPlusOffset(
965 translate_to_eh_frame_regnum_x86_64(registers[i]),
966 wordsize * -saved_registers_offset, true);
967 saved_registers_offset++;
968 break;
969 }
970 }
971 }
972 unwind_plan.AppendRow(row);
973 return true;
974 } break;
975
976 case UNWIND_X86_64_MODE_DWARF: {
977 return false;
978 } break;
979
980 case 0: {
981 return false;
982 } break;
983 }
984 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +0000985}
986
987enum i386_eh_regnum {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000988 eax = 0,
989 ecx = 1,
990 edx = 2,
991 ebx = 3,
992 ebp = 4,
993 esp = 5,
994 esi = 6,
995 edi = 7,
996 eip = 8 // this is officially the Return Address register number, but close
997 // enough
Jason Molendae589e7e2014-12-08 03:09:00 +0000998};
999
1000// Convert the compact_unwind_info.h register numbering scheme
Jason Molenda63bd0db2015-09-15 23:20:34 +00001001// to eRegisterKindEHFrame (eh_frame) register numbering scheme.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001002uint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {
1003 switch (unwind_regno) {
1004 case UNWIND_X86_REG_EBX:
1005 return i386_eh_regnum::ebx;
1006 case UNWIND_X86_REG_ECX:
1007 return i386_eh_regnum::ecx;
1008 case UNWIND_X86_REG_EDX:
1009 return i386_eh_regnum::edx;
1010 case UNWIND_X86_REG_EDI:
1011 return i386_eh_regnum::edi;
1012 case UNWIND_X86_REG_ESI:
1013 return i386_eh_regnum::esi;
1014 case UNWIND_X86_REG_EBP:
1015 return i386_eh_regnum::ebp;
1016 default:
1017 return LLDB_INVALID_REGNUM;
1018 }
Jason Molendae589e7e2014-12-08 03:09:00 +00001019}
1020
Kate Stoneb9c1b512016-09-06 20:57:50 +00001021bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
1022 FunctionInfo &function_info,
1023 UnwindPlan &unwind_plan,
1024 Address pc_or_function_start) {
1025 unwind_plan.SetSourceName("compact unwind info");
1026 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1027 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1028 unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
Jason Molendae589e7e2014-12-08 03:09:00 +00001029
Kate Stoneb9c1b512016-09-06 20:57:50 +00001030 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1031 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
Jason Molendae589e7e2014-12-08 03:09:00 +00001032
Kate Stoneb9c1b512016-09-06 20:57:50 +00001033 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendae589e7e2014-12-08 03:09:00 +00001034
Kate Stoneb9c1b512016-09-06 20:57:50 +00001035 const int wordsize = 4;
1036 int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1037 switch (mode) {
1038 case UNWIND_X86_MODE_EBP_FRAME: {
1039 row->GetCFAValue().SetIsRegisterPlusOffset(
1040 translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
1041 row->SetOffset(0);
1042 row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,
1043 wordsize * -2, true);
1044 row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1045 wordsize * -1, true);
1046 row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
Jason Molendae589e7e2014-12-08 03:09:00 +00001047
Kate Stoneb9c1b512016-09-06 20:57:50 +00001048 uint32_t saved_registers_offset =
1049 EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
Jason Molendac7afda52016-06-07 02:19:54 +00001050
Kate Stoneb9c1b512016-09-06 20:57:50 +00001051 uint32_t saved_registers_locations =
1052 EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
Jason Molendae589e7e2014-12-08 03:09:00 +00001053
Kate Stoneb9c1b512016-09-06 20:57:50 +00001054 saved_registers_offset += 2;
Jason Molendae589e7e2014-12-08 03:09:00 +00001055
Kate Stoneb9c1b512016-09-06 20:57:50 +00001056 for (int i = 0; i < 5; i++) {
1057 uint32_t regnum = saved_registers_locations & 0x7;
1058 switch (regnum) {
1059 case UNWIND_X86_REG_NONE:
Jason Molendae589e7e2014-12-08 03:09:00 +00001060 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001061 case UNWIND_X86_REG_EBX:
1062 case UNWIND_X86_REG_ECX:
1063 case UNWIND_X86_REG_EDX:
1064 case UNWIND_X86_REG_EDI:
1065 case UNWIND_X86_REG_ESI:
1066 row->SetRegisterLocationToAtCFAPlusOffset(
1067 translate_to_eh_frame_regnum_i386(regnum),
1068 wordsize * -saved_registers_offset, true);
Jason Molenda19ba9fb2014-12-22 11:02:02 +00001069 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001070 }
1071 saved_registers_offset--;
1072 saved_registers_locations >>= 3;
1073 }
1074 unwind_plan.AppendRow(row);
1075 return true;
1076 } break;
Jason Molenda19ba9fb2014-12-22 11:02:02 +00001077
Kate Stoneb9c1b512016-09-06 20:57:50 +00001078 case UNWIND_X86_MODE_STACK_IND:
1079 case UNWIND_X86_MODE_STACK_IMMD: {
1080 uint32_t stack_size =
1081 EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1082 uint32_t register_count = EXTRACT_BITS(
1083 function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
1084 uint32_t permutation = EXTRACT_BITS(
1085 function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
1086
1087 if (mode == UNWIND_X86_MODE_STACK_IND &&
1088 function_info.valid_range_offset_start != 0) {
1089 uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,
1090 UNWIND_X86_FRAMELESS_STACK_ADJUST);
1091
1092 // offset into the function instructions; 0 == beginning of first
1093 // instruction
1094 uint32_t offset_to_subl_insn =
1095 EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1096
1097 SectionList *sl = m_objfile.GetSectionList();
1098 if (sl) {
1099 ProcessSP process_sp = target.GetProcessSP();
1100 if (process_sp) {
1101 Address subl_payload_addr(function_info.valid_range_offset_start, sl);
1102 subl_payload_addr.Slide(offset_to_subl_insn);
1103 Error error;
1104 uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(
1105 subl_payload_addr.GetLoadAddress(&target), 4, 0, error);
1106 if (large_stack_size != 0 && error.Success()) {
1107 // Got the large stack frame size correctly - use it
1108 stack_size = large_stack_size + (stack_adjust * wordsize);
1109 } else {
Jason Molendae589e7e2014-12-08 03:09:00 +00001110 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001111 }
1112 } else {
1113 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +00001114 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001115 } else {
1116 return false;
1117 }
Jason Molendae589e7e2014-12-08 03:09:00 +00001118 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001119
1120 int32_t offset =
1121 mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1122 row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
1123 row->SetOffset(0);
1124 row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1125 wordsize * -1, true);
1126 row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1127
1128 if (register_count > 0) {
1129
1130 // We need to include (up to) 6 registers in 10 bits.
1131 // That would be 18 bits if we just used 3 bits per reg to indicate
1132 // the order they're saved on the stack.
1133 //
1134 // This is done with Lehmer code permutation, e.g. see
1135 // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms
1136 int permunreg[6] = {0, 0, 0, 0, 0, 0};
1137
1138 // This decodes the variable-base number in the 10 bits
1139 // and gives us the Lehmer code sequence which can then
1140 // be decoded.
1141
1142 switch (register_count) {
1143 case 6:
1144 permunreg[0] = permutation / 120; // 120 == 5!
1145 permutation -= (permunreg[0] * 120);
1146 permunreg[1] = permutation / 24; // 24 == 4!
1147 permutation -= (permunreg[1] * 24);
1148 permunreg[2] = permutation / 6; // 6 == 3!
1149 permutation -= (permunreg[2] * 6);
1150 permunreg[3] = permutation / 2; // 2 == 2!
1151 permutation -= (permunreg[3] * 2);
1152 permunreg[4] = permutation; // 1 == 1!
1153 permunreg[5] = 0;
1154 break;
1155 case 5:
1156 permunreg[0] = permutation / 120;
1157 permutation -= (permunreg[0] * 120);
1158 permunreg[1] = permutation / 24;
1159 permutation -= (permunreg[1] * 24);
1160 permunreg[2] = permutation / 6;
1161 permutation -= (permunreg[2] * 6);
1162 permunreg[3] = permutation / 2;
1163 permutation -= (permunreg[3] * 2);
1164 permunreg[4] = permutation;
1165 break;
1166 case 4:
1167 permunreg[0] = permutation / 60;
1168 permutation -= (permunreg[0] * 60);
1169 permunreg[1] = permutation / 12;
1170 permutation -= (permunreg[1] * 12);
1171 permunreg[2] = permutation / 3;
1172 permutation -= (permunreg[2] * 3);
1173 permunreg[3] = permutation;
1174 break;
1175 case 3:
1176 permunreg[0] = permutation / 20;
1177 permutation -= (permunreg[0] * 20);
1178 permunreg[1] = permutation / 4;
1179 permutation -= (permunreg[1] * 4);
1180 permunreg[2] = permutation;
1181 break;
1182 case 2:
1183 permunreg[0] = permutation / 5;
1184 permutation -= (permunreg[0] * 5);
1185 permunreg[1] = permutation;
1186 break;
1187 case 1:
1188 permunreg[0] = permutation;
1189 break;
1190 }
1191
1192 // Decode the Lehmer code for this permutation of
1193 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
1194
1195 int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1196 UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,
1197 UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};
1198 bool used[7] = {false, false, false, false, false, false, false};
1199 for (uint32_t i = 0; i < register_count; i++) {
1200 int renum = 0;
1201 for (int j = 1; j < 7; j++) {
1202 if (used[j] == false) {
1203 if (renum == permunreg[i]) {
1204 registers[i] = j;
1205 used[j] = true;
1206 break;
1207 }
1208 renum++;
1209 }
1210 }
1211 }
1212
1213 uint32_t saved_registers_offset = 1;
1214 saved_registers_offset++;
1215
1216 for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1217 switch (registers[i]) {
1218 case UNWIND_X86_REG_NONE:
1219 break;
1220 case UNWIND_X86_REG_EBX:
1221 case UNWIND_X86_REG_ECX:
1222 case UNWIND_X86_REG_EDX:
1223 case UNWIND_X86_REG_EDI:
1224 case UNWIND_X86_REG_ESI:
1225 case UNWIND_X86_REG_EBP:
1226 row->SetRegisterLocationToAtCFAPlusOffset(
1227 translate_to_eh_frame_regnum_i386(registers[i]),
1228 wordsize * -saved_registers_offset, true);
1229 saved_registers_offset++;
1230 break;
1231 }
1232 }
1233 }
1234
1235 unwind_plan.AppendRow(row);
1236 return true;
1237 } break;
1238
1239 case UNWIND_X86_MODE_DWARF: {
Jason Molendae589e7e2014-12-08 03:09:00 +00001240 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001241 } break;
1242 }
1243 return false;
Jason Molendae589e7e2014-12-08 03:09:00 +00001244}
Jason Molendab667c202016-05-25 04:20:28 +00001245
Kate Stoneb9c1b512016-09-06 20:57:50 +00001246// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1247// doc by ARM
Jason Molendab667c202016-05-25 04:20:28 +00001248
1249enum arm64_eh_regnum {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001250 x19 = 19,
1251 x20 = 20,
1252 x21 = 21,
1253 x22 = 22,
1254 x23 = 23,
1255 x24 = 24,
1256 x25 = 25,
1257 x26 = 26,
1258 x27 = 27,
1259 x28 = 28,
Jason Molendab667c202016-05-25 04:20:28 +00001260
Kate Stoneb9c1b512016-09-06 20:57:50 +00001261 fp = 29,
1262 ra = 30,
1263 sp = 31,
1264 pc = 32,
Jason Molendab667c202016-05-25 04:20:28 +00001265
Kate Stoneb9c1b512016-09-06 20:57:50 +00001266 // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
1267 // for the 64-bit
1268 // fp regs. Normally in DWARF it's context sensitive - so it knows it is
1269 // fetching a
1270 // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder
1271 // is operating
1272 // at a lower level and we'd try to fetch 128 bits if we were told that v8
1273 // were stored on
1274 // the stack...
1275 v8 = 72,
1276 v9 = 73,
1277 v10 = 74,
1278 v11 = 75,
1279 v12 = 76,
1280 v13 = 77,
1281 v14 = 78,
1282 v15 = 79,
Jason Molendab667c202016-05-25 04:20:28 +00001283};
1284
Jason Molendac7afda52016-06-07 02:19:54 +00001285enum arm_eh_regnum {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001286 arm_r0 = 0,
1287 arm_r1 = 1,
1288 arm_r2 = 2,
1289 arm_r3 = 3,
1290 arm_r4 = 4,
1291 arm_r5 = 5,
1292 arm_r6 = 6,
1293 arm_r7 = 7,
1294 arm_r8 = 8,
1295 arm_r9 = 9,
1296 arm_r10 = 10,
1297 arm_r11 = 11,
1298 arm_r12 = 12,
Jason Molendac7afda52016-06-07 02:19:54 +00001299
Kate Stoneb9c1b512016-09-06 20:57:50 +00001300 arm_sp = 13,
1301 arm_lr = 14,
1302 arm_pc = 15,
Jason Molendac7afda52016-06-07 02:19:54 +00001303
Kate Stoneb9c1b512016-09-06 20:57:50 +00001304 arm_d0 = 256,
1305 arm_d1 = 257,
1306 arm_d2 = 258,
1307 arm_d3 = 259,
1308 arm_d4 = 260,
1309 arm_d5 = 261,
1310 arm_d6 = 262,
1311 arm_d7 = 263,
1312 arm_d8 = 264,
1313 arm_d9 = 265,
1314 arm_d10 = 266,
1315 arm_d11 = 267,
1316 arm_d12 = 268,
1317 arm_d13 = 269,
1318 arm_d14 = 270,
Jason Molendac7afda52016-06-07 02:19:54 +00001319};
1320
Kate Stoneb9c1b512016-09-06 20:57:50 +00001321bool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
1322 FunctionInfo &function_info,
1323 UnwindPlan &unwind_plan,
1324 Address pc_or_function_start) {
1325 unwind_plan.SetSourceName("compact unwind info");
1326 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1327 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1328 unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
Jason Molendac7afda52016-06-07 02:19:54 +00001329
Kate Stoneb9c1b512016-09-06 20:57:50 +00001330 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1331 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
Jason Molendac7afda52016-06-07 02:19:54 +00001332
Kate Stoneb9c1b512016-09-06 20:57:50 +00001333 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendab667c202016-05-25 04:20:28 +00001334
Kate Stoneb9c1b512016-09-06 20:57:50 +00001335 const int wordsize = 8;
1336 int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
Jason Molendab667c202016-05-25 04:20:28 +00001337
Kate Stoneb9c1b512016-09-06 20:57:50 +00001338 if (mode == UNWIND_ARM64_MODE_DWARF)
1339 return false;
Jason Molendab667c202016-05-25 04:20:28 +00001340
Kate Stoneb9c1b512016-09-06 20:57:50 +00001341 if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1342 row->SetOffset(0);
Jason Molendab667c202016-05-25 04:20:28 +00001343
Kate Stoneb9c1b512016-09-06 20:57:50 +00001344 uint32_t stack_size =
1345 (EXTRACT_BITS(function_info.encoding,
1346 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1347 16;
Jason Molendab667c202016-05-25 04:20:28 +00001348
Kate Stoneb9c1b512016-09-06 20:57:50 +00001349 // Our previous Call Frame Address is the stack pointer plus the stack size
1350 row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
Jason Molendab667c202016-05-25 04:20:28 +00001351
Kate Stoneb9c1b512016-09-06 20:57:50 +00001352 // Our previous PC is in the LR
1353 row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1354 true);
Jason Molendab667c202016-05-25 04:20:28 +00001355
Kate Stoneb9c1b512016-09-06 20:57:50 +00001356 unwind_plan.AppendRow(row);
Jason Molendab667c202016-05-25 04:20:28 +00001357 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001358 }
1359
1360 // Should not be possible
1361 if (mode != UNWIND_ARM64_MODE_FRAME)
1362 return false;
1363
1364 // mode == UNWIND_ARM64_MODE_FRAME
1365
1366 row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1367 row->SetOffset(0);
1368 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1369 true);
1370 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1371 true);
1372 row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1373
1374 int reg_pairs_saved_count = 1;
1375
1376 uint32_t saved_register_bits = function_info.encoding & 0xfff;
1377
1378 if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
1379 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1380 cfa_offset -= wordsize;
1381 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,
1382 true);
1383 cfa_offset -= wordsize;
1384 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1385 true);
1386 reg_pairs_saved_count++;
1387 }
1388
1389 if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
1390 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1391 cfa_offset -= wordsize;
1392 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,
1393 true);
1394 cfa_offset -= wordsize;
1395 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1396 true);
1397 reg_pairs_saved_count++;
1398 }
1399
1400 if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
1401 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1402 cfa_offset -= wordsize;
1403 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,
1404 true);
1405 cfa_offset -= wordsize;
1406 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1407 true);
1408 reg_pairs_saved_count++;
1409 }
1410
1411 if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
1412 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1413 cfa_offset -= wordsize;
1414 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,
1415 true);
1416 cfa_offset -= wordsize;
1417 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1418 true);
1419 reg_pairs_saved_count++;
1420 }
1421
1422 if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
1423 int cfa_offset = reg_pairs_saved_count * -2 * wordsize;
1424 cfa_offset -= wordsize;
1425 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,
1426 true);
1427 cfa_offset -= wordsize;
1428 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1429 true);
1430 reg_pairs_saved_count++;
1431 }
1432
1433 // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1434 // off the stack;
1435 // not sure if we have a good way to represent the 64-bitness of these saves.
1436
1437 if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1438 reg_pairs_saved_count++;
1439 }
1440 if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1441 reg_pairs_saved_count++;
1442 }
1443 if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1444 reg_pairs_saved_count++;
1445 }
1446 if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1447 reg_pairs_saved_count++;
1448 }
1449
1450 unwind_plan.AppendRow(row);
1451 return true;
Jason Molendab667c202016-05-25 04:20:28 +00001452}
1453
Kate Stoneb9c1b512016-09-06 20:57:50 +00001454bool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
1455 FunctionInfo &function_info,
1456 UnwindPlan &unwind_plan,
1457 Address pc_or_function_start) {
1458 unwind_plan.SetSourceName("compact unwind info");
1459 unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
1460 unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
1461 unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
Jason Molendac7afda52016-06-07 02:19:54 +00001462
Kate Stoneb9c1b512016-09-06 20:57:50 +00001463 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1464 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
Jason Molendac7afda52016-06-07 02:19:54 +00001465
Kate Stoneb9c1b512016-09-06 20:57:50 +00001466 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendac7afda52016-06-07 02:19:54 +00001467
Kate Stoneb9c1b512016-09-06 20:57:50 +00001468 const int wordsize = 4;
1469 int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
Jason Molendac7afda52016-06-07 02:19:54 +00001470
Kate Stoneb9c1b512016-09-06 20:57:50 +00001471 if (mode == UNWIND_ARM_MODE_DWARF)
1472 return false;
Jason Molendac7afda52016-06-07 02:19:54 +00001473
Kate Stoneb9c1b512016-09-06 20:57:50 +00001474 uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1475 UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1476 wordsize;
Jason Molendac7afda52016-06-07 02:19:54 +00001477
Kate Stoneb9c1b512016-09-06 20:57:50 +00001478 row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1479 (2 * wordsize) + stack_adjust);
1480 row->SetOffset(0);
1481 row->SetRegisterLocationToAtCFAPlusOffset(
1482 arm_r7, (wordsize * -2) - stack_adjust, true);
1483 row->SetRegisterLocationToAtCFAPlusOffset(
1484 arm_pc, (wordsize * -1) - stack_adjust, true);
1485 row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);
Jason Molendac7afda52016-06-07 02:19:54 +00001486
Kate Stoneb9c1b512016-09-06 20:57:50 +00001487 int cfa_offset = -stack_adjust - (2 * wordsize);
Jason Molendac7afda52016-06-07 02:19:54 +00001488
Kate Stoneb9c1b512016-09-06 20:57:50 +00001489 uint32_t saved_register_bits = function_info.encoding & 0xff;
Jason Molendac7afda52016-06-07 02:19:54 +00001490
Kate Stoneb9c1b512016-09-06 20:57:50 +00001491 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1492 cfa_offset -= wordsize;
1493 row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1494 }
1495
1496 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1497 cfa_offset -= wordsize;
1498 row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1499 }
1500
1501 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1502 cfa_offset -= wordsize;
1503 row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1504 }
1505
1506 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1507 cfa_offset -= wordsize;
1508 row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1509 }
1510
1511 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1512 cfa_offset -= wordsize;
1513 row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1514 }
1515
1516 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1517 cfa_offset -= wordsize;
1518 row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1519 }
1520
1521 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1522 cfa_offset -= wordsize;
1523 row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1524 }
1525
1526 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1527 cfa_offset -= wordsize;
1528 row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
1529 }
1530
1531 if (mode == UNWIND_ARM_MODE_FRAME_D) {
1532 uint32_t d_reg_bits =
1533 EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);
1534 switch (d_reg_bits) {
1535 case 0:
1536 // vpush {d8}
1537 cfa_offset -= 8;
1538 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1539 break;
1540 case 1:
1541 // vpush {d10}
1542 // vpush {d8}
1543 cfa_offset -= 8;
1544 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1545 cfa_offset -= 8;
1546 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1547 break;
1548 case 2:
1549 // vpush {d12}
1550 // vpush {d10}
1551 // vpush {d8}
1552 cfa_offset -= 8;
1553 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1554 cfa_offset -= 8;
1555 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1556 cfa_offset -= 8;
1557 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1558 break;
1559 case 3:
1560 // vpush {d14}
1561 // vpush {d12}
1562 // vpush {d10}
1563 // vpush {d8}
1564 cfa_offset -= 8;
1565 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1566 cfa_offset -= 8;
1567 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1568 cfa_offset -= 8;
1569 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1570 cfa_offset -= 8;
1571 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1572 break;
1573 case 4:
1574 // vpush {d14}
1575 // vpush {d12}
1576 // sp = (sp - 24) & (-16);
1577 // vst {d8, d9, d10}
1578 cfa_offset -= 8;
1579 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1580 cfa_offset -= 8;
1581 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1582
1583 // FIXME we don't have a way to represent reg saves at an specific
1584 // alignment short of
1585 // coming up with some DWARF location description.
1586
1587 break;
1588 case 5:
1589 // vpush {d14}
1590 // sp = (sp - 40) & (-16);
1591 // vst {d8, d9, d10, d11}
1592 // vst {d12}
1593
1594 cfa_offset -= 8;
1595 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1596
1597 // FIXME we don't have a way to represent reg saves at an specific
1598 // alignment short of
1599 // coming up with some DWARF location description.
1600
1601 break;
1602 case 6:
1603 // sp = (sp - 56) & (-16);
1604 // vst {d8, d9, d10, d11}
1605 // vst {d12, d13, d14}
1606
1607 // FIXME we don't have a way to represent reg saves at an specific
1608 // alignment short of
1609 // coming up with some DWARF location description.
1610
1611 break;
1612 case 7:
1613 // sp = (sp - 64) & (-16);
1614 // vst {d8, d9, d10, d11}
1615 // vst {d12, d13, d14, d15}
1616
1617 // FIXME we don't have a way to represent reg saves at an specific
1618 // alignment short of
1619 // coming up with some DWARF location description.
1620
1621 break;
Jason Molendac7afda52016-06-07 02:19:54 +00001622 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001623 }
Jason Molendac7afda52016-06-07 02:19:54 +00001624
Kate Stoneb9c1b512016-09-06 20:57:50 +00001625 unwind_plan.AppendRow(row);
1626 return true;
Jason Molendac7afda52016-06-07 02:19:54 +00001627}