1 //===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lldb/Symbol/CompactUnwindInfo.h"
11 #include "lldb/Core/Module.h"
12 #include "lldb/Core/Section.h"
13 #include "lldb/Symbol/ObjectFile.h"
14 #include "lldb/Symbol/UnwindPlan.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/ArchSpec.h"
18 #include "lldb/Utility/DataBufferHeap.h"
19 #include "lldb/Utility/Log.h"
20 #include "lldb/Utility/StreamString.h"
23 #include "llvm/Support/MathExtras.h"
26 using namespace lldb_private;
28 namespace lldb_private {
30 // Constants from <mach-o/compact_unwind_encoding.h>
32 FLAGS_ANONYMOUS_ENUM(){
33 UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
34 UNWIND_PERSONALITY_MASK = 0x30000000,
37 FLAGS_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,
44 UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
45 UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
47 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,
52 UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
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,
65 FLAGS_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,
72 UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
73 UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
75 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,
80 UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
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,
93 FLAGS_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,
99 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,
109 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
110 UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
113 FLAGS_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,
119 UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
121 UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
122 UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
123 UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
125 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,
131 UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
133 UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
137 #ifndef UNWIND_SECOND_LEVEL_REGULAR
138 #define UNWIND_SECOND_LEVEL_REGULAR 2
141 #ifndef UNWIND_SECOND_LEVEL_COMPRESSED
142 #define UNWIND_SECOND_LEVEL_COMPRESSED 3
145 #ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
146 #define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
149 #ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
150 #define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \
151 ((entry >> 24) & 0xFF)
154 #define EXTRACT_BITS(value, mask) \
156 llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \
157 (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1))
159 //----------------------
161 //----------------------
163 CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp)
164 : 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() {}
169 //----------------------
171 //----------------------
173 CompactUnwindInfo::~CompactUnwindInfo() {}
175 bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
176 UnwindPlan &unwind_plan) {
177 if (!IsValid(target.GetProcessSP())) {
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)
187 if (m_objfile.GetArchitecture(arch)) {
189 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
190 if (log && log->GetVerbose()) {
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());
201 if (function_info.valid_range_offset_start != 0 &&
202 function_info.valid_range_offset_end != 0) {
203 SectionList *sl = m_objfile.GetSectionList();
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,
212 unwind_plan.SetPlanValidAddressRange(func_range);
216 if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
217 return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
220 if (arch.GetTriple().getArch() == llvm::Triple::aarch64) {
221 return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
223 if (arch.GetTriple().getArch() == llvm::Triple::x86) {
224 return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
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);
235 bool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
236 if (m_section_sp.get() == nullptr)
239 if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
242 ScanIndex(process_sp);
244 return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
247 void 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)
252 // We can't read the index for some reason.
253 if (m_indexes_computed == eLazyBoolNo) {
257 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
259 m_objfile.GetModule()->LogMessage(
260 log, "Reading compact unwind first-level indexes");
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
266 // process and can read them out of memory.
267 if (process_sp.get() == nullptr)
269 m_section_contents_if_encrypted.reset(
270 new DataBufferHeap(m_section_sp->GetByteSize(), 0));
272 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() &&
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);
285 m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
287 if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
289 m_unwindinfo_data_computed = true;
292 if (m_unwindinfo_data.GetByteSize() > 0) {
295 // struct unwind_info_section_header
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;
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);
315 uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
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 "
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;
332 // Parse the basic information from the indexes
333 // We wait to scan the second level page info until it's needed
335 // struct unwind_info_section_header_index_entry
337 // uint32_t functionOffset;
338 // uint32_t secondLevelPagesSectionOffset;
339 // uint32_t lsdaIndexArraySectionOffset;
342 bool clear_address_zeroth_bit = false;
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;
350 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
359 if (second_level_offset > m_section_sp->GetByteSize() ||
360 lsda_offset > m_section_sp->GetByteSize()) {
361 m_indexes_computed = eLazyBoolNo;
364 if (clear_address_zeroth_bit)
365 function_offset &= ~1ull;
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;
372 if (m_indexes.size() > 0) {
373 m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
376 if (second_level_offset == 0) {
377 this_index.sentinal_entry = true;
380 m_indexes.push_back(this_index);
382 m_indexes_computed = eLazyBoolYes;
384 m_indexes_computed = eLazyBoolNo;
388 uint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
390 uint32_t function_offset) {
391 // struct unwind_info_section_header_lsda_index_entry
393 // uint32_t functionOffset;
394 // uint32_t lsdaOffset;
397 offset_t first_entry = lsda_offset;
399 uint32_t high = lsda_count;
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;
409 if (mid_func_offset < function_offset) {
418 lldb::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
424 // uint32_t functionOffset;
425 // compact_unwind_encoding_t encoding;
427 offset_t first_entry = entry_page_offset;
430 uint32_t high = entry_count;
431 uint32_t last = high - 1;
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;
439 offset = first_entry + ((mid + 1) * 8);
440 next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
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);
456 return LLDB_INVALID_OFFSET;
459 uint32_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;
466 uint32_t high = entry_count;
467 uint32_t last = high - 1;
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;
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;
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);
499 bool 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();
505 if (!IsValid(target.GetProcessSP()))
508 addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
509 SectionList *sl = m_objfile.GetSectionList();
511 SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
512 if (text_sect.get()) {
513 text_section_file_address = text_sect->GetFileAddress();
516 if (text_section_file_address == LLDB_INVALID_ADDRESS)
519 addr_t function_offset =
520 address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress();
523 key.function_offset = function_offset;
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()) {
531 if (it->function_offset != key.function_offset) {
532 if (it != m_indexes.begin())
536 if (it->sentinal_entry == true) {
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;
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;
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
556 if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
557 // struct unwind_info_regular_second_level_page_header
559 // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
560 // uint16_t entryPageOffset;
561 // uint16_t entryCount;
563 // typedef uint32_t compact_unwind_encoding_t;
564 // struct unwind_info_regular_second_level_entry
566 // uint32_t functionOffset;
567 // compact_unwind_encoding_t encoding;
569 uint16_t entry_page_offset =
570 m_unwindinfo_data.GetU16(&offset); // entryPageOffset
571 uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
573 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) {
580 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();
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);
593 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
594 uint32_t personality_index =
595 EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
597 if (personality_index > 0) {
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();
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);
614 } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
615 // struct unwind_info_compressed_second_level_page_header
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
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;
632 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
640 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 ||
646 encodings_count + m_unwind_header.common_encodings_array_count) {
649 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
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
666 unwind_info.encoding = encoding;
667 if (unwind_info.encoding & UNWIND_HAS_LSDA) {
668 SectionList *sl = m_objfile.GetSectionList();
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);
678 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
679 uint32_t personality_index =
680 EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
682 if (personality_index > 0) {
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();
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);
703 enum x86_64_eh_regnum {
720 rip = 16 // this is officially the Return Address register number, but close
724 // Convert the compact_unwind_info.h register numbering scheme
725 // to eRegisterKindEHFrame (eh_frame) register numbering scheme.
726 uint32_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;
741 return LLDB_INVALID_REGNUM;
745 bool 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);
754 unwind_plan.SetLSDAAddress(function_info.lsda_address);
755 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
757 UnwindPlan::RowSP row(new UnwindPlan::Row);
759 const int wordsize = 8;
760 int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
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),
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);
773 uint32_t saved_registers_offset =
774 EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
776 uint32_t saved_registers_locations =
777 EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
779 saved_registers_offset += 2;
781 for (int i = 0; i < 5; i++) {
782 uint32_t regnum = saved_registers_locations & 0x7;
784 case UNWIND_X86_64_REG_NONE:
786 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);
796 saved_registers_offset--;
797 saved_registers_locations >>= 3;
799 unwind_plan.AppendRow(row);
803 case UNWIND_X86_64_MODE_STACK_IND: {
804 // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
806 // style of unwind. It was fixed in llvm r217020.
807 // The clang in Xcode 7 has this fixed.
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);
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);
824 // offset into the function instructions; 0 == beginning of first
826 uint32_t offset_to_subl_insn = EXTRACT_BITS(
827 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
829 SectionList *sl = m_objfile.GetSectionList();
831 ProcessSP process_sp = target.GetProcessSP();
833 Address subl_payload_addr(function_info.valid_range_offset_start, sl);
834 subl_payload_addr.Slide(offset_to_subl_insn);
836 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);
852 int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
854 : stack_size * wordsize;
855 row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
858 row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
859 wordsize * -1, true);
860 row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
862 if (register_count > 0) {
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.
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};
872 // This decodes the variable-base number in the 10 bits
873 // and gives us the Lehmer code sequence which can then
876 switch (register_count) {
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!
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;
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;
910 permunreg[0] = permutation / 20;
911 permutation -= (permunreg[0] * 20);
912 permunreg[1] = permutation / 4;
913 permutation -= (permunreg[1] * 4);
914 permunreg[2] = permutation;
917 permunreg[0] = permutation / 5;
918 permutation -= (permunreg[0] * 5);
919 permunreg[1] = permutation;
922 permunreg[0] = permutation;
926 // Decode the Lehmer code for this permutation of
927 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
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++) {
935 for (int j = 1; j < 7; j++) {
936 if (used[j] == false) {
937 if (renum == permunreg[i]) {
947 uint32_t saved_registers_offset = 1;
948 saved_registers_offset++;
950 for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
951 switch (registers[i]) {
952 case UNWIND_X86_64_REG_NONE:
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++;
968 unwind_plan.AppendRow(row);
972 case UNWIND_X86_64_MODE_DWARF: {
983 enum i386_eh_regnum {
992 eip = 8 // this is officially the Return Address register number, but close
996 // Convert the compact_unwind_info.h register numbering scheme
997 // to eRegisterKindEHFrame (eh_frame) register numbering scheme.
998 uint32_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;
1013 return LLDB_INVALID_REGNUM;
1017 bool 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);
1026 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1027 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1029 UnwindPlan::RowSP row(new UnwindPlan::Row);
1031 const int wordsize = 4;
1032 int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1034 case UNWIND_X86_MODE_EBP_FRAME: {
1035 row->GetCFAValue().SetIsRegisterPlusOffset(
1036 translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
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);
1044 uint32_t saved_registers_offset =
1045 EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1047 uint32_t saved_registers_locations =
1048 EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1050 saved_registers_offset += 2;
1052 for (int i = 0; i < 5; i++) {
1053 uint32_t regnum = saved_registers_locations & 0x7;
1055 case UNWIND_X86_REG_NONE:
1057 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);
1067 saved_registers_offset--;
1068 saved_registers_locations >>= 3;
1070 unwind_plan.AppendRow(row);
1074 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);
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);
1088 // offset into the function instructions; 0 == beginning of first
1090 uint32_t offset_to_subl_insn =
1091 EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1093 SectionList *sl = m_objfile.GetSectionList();
1095 ProcessSP process_sp = target.GetProcessSP();
1097 Address subl_payload_addr(function_info.valid_range_offset_start, sl);
1098 subl_payload_addr.Slide(offset_to_subl_insn);
1100 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);
1117 mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1118 row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
1120 row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1121 wordsize * -1, true);
1122 row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1124 if (register_count > 0) {
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.
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};
1134 // This decodes the variable-base number in the 10 bits
1135 // and gives us the Lehmer code sequence which can then
1138 switch (register_count) {
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!
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;
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;
1172 permunreg[0] = permutation / 20;
1173 permutation -= (permunreg[0] * 20);
1174 permunreg[1] = permutation / 4;
1175 permutation -= (permunreg[1] * 4);
1176 permunreg[2] = permutation;
1179 permunreg[0] = permutation / 5;
1180 permutation -= (permunreg[0] * 5);
1181 permunreg[1] = permutation;
1184 permunreg[0] = permutation;
1188 // Decode the Lehmer code for this permutation of
1189 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
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++) {
1197 for (int j = 1; j < 7; j++) {
1198 if (used[j] == false) {
1199 if (renum == permunreg[i]) {
1209 uint32_t saved_registers_offset = 1;
1210 saved_registers_offset++;
1212 for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1213 switch (registers[i]) {
1214 case UNWIND_X86_REG_NONE:
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++;
1231 unwind_plan.AppendRow(row);
1235 case UNWIND_X86_MODE_DWARF: {
1242 // DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1245 enum arm64_eh_regnum {
1262 // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
1264 // fp regs. Normally in DWARF it's context sensitive - so it knows it is
1266 // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder
1268 // at a lower level and we'd try to fetch 128 bits if we were told that v8
1281 enum arm_eh_regnum {
1317 bool 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);
1326 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1327 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1329 UnwindPlan::RowSP row(new UnwindPlan::Row);
1331 const int wordsize = 8;
1332 int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
1334 if (mode == UNWIND_ARM64_MODE_DWARF)
1337 if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1340 uint32_t stack_size =
1341 (EXTRACT_BITS(function_info.encoding,
1342 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1345 // Our previous Call Frame Address is the stack pointer plus the stack size
1346 row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
1348 // Our previous PC is in the LR
1349 row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1352 unwind_plan.AppendRow(row);
1356 // Should not be possible
1357 if (mode != UNWIND_ARM64_MODE_FRAME)
1360 // mode == UNWIND_ARM64_MODE_FRAME
1362 row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1364 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1366 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1368 row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1370 int reg_pairs_saved_count = 1;
1372 uint32_t saved_register_bits = function_info.encoding & 0xfff;
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,
1379 cfa_offset -= wordsize;
1380 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1382 reg_pairs_saved_count++;
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,
1390 cfa_offset -= wordsize;
1391 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1393 reg_pairs_saved_count++;
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,
1401 cfa_offset -= wordsize;
1402 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1404 reg_pairs_saved_count++;
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,
1412 cfa_offset -= wordsize;
1413 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1415 reg_pairs_saved_count++;
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,
1423 cfa_offset -= wordsize;
1424 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1426 reg_pairs_saved_count++;
1429 // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1431 // not sure if we have a good way to represent the 64-bitness of these saves.
1433 if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1434 reg_pairs_saved_count++;
1436 if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1437 reg_pairs_saved_count++;
1439 if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1440 reg_pairs_saved_count++;
1442 if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1443 reg_pairs_saved_count++;
1446 unwind_plan.AppendRow(row);
1450 bool 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);
1459 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1460 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1462 UnwindPlan::RowSP row(new UnwindPlan::Row);
1464 const int wordsize = 4;
1465 int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
1467 if (mode == UNWIND_ARM_MODE_DWARF)
1470 uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1471 UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1474 row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1475 (2 * wordsize) + stack_adjust);
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);
1483 int cfa_offset = -stack_adjust - (2 * wordsize);
1485 uint32_t saved_register_bits = function_info.encoding & 0xff;
1487 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1488 cfa_offset -= wordsize;
1489 row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1492 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1493 cfa_offset -= wordsize;
1494 row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1497 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1498 cfa_offset -= wordsize;
1499 row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1502 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1503 cfa_offset -= wordsize;
1504 row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1507 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1508 cfa_offset -= wordsize;
1509 row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1512 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1513 cfa_offset -= wordsize;
1514 row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1517 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1518 cfa_offset -= wordsize;
1519 row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1522 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1523 cfa_offset -= wordsize;
1524 row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
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) {
1534 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1540 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1542 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1549 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1551 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1553 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1561 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1563 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1565 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1567 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1572 // sp = (sp - 24) & (-16);
1573 // vst {d8, d9, d10}
1575 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1577 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
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.
1586 // sp = (sp - 40) & (-16);
1587 // vst {d8, d9, d10, d11}
1591 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
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.
1599 // sp = (sp - 56) & (-16);
1600 // vst {d8, d9, d10, d11}
1601 // vst {d12, d13, d14}
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.
1609 // sp = (sp - 64) & (-16);
1610 // vst {d8, d9, d10, d11}
1611 // vst {d12, d13, d14, d15}
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.
1621 unwind_plan.AppendRow(row);