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 //===----------------------------------------------------------------------===//
14 #include "lldb/Core/ArchSpec.h"
15 #include "lldb/Core/DataBufferHeap.h"
16 #include "lldb/Core/Log.h"
17 #include "lldb/Core/Module.h"
18 #include "lldb/Core/Section.h"
19 #include "lldb/Core/Section.h"
20 #include "lldb/Core/StreamString.h"
21 #include "lldb/Symbol/CompactUnwindInfo.h"
22 #include "lldb/Symbol/ObjectFile.h"
23 #include "lldb/Symbol/UnwindPlan.h"
24 #include "lldb/Target/Process.h"
25 #include "lldb/Target/Target.h"
27 #include "llvm/Support/MathExtras.h"
30 using namespace lldb_private;
32 namespace lldb_private {
34 // Constants from <mach-o/compact_unwind_encoding.h>
36 FLAGS_ANONYMOUS_ENUM(){
37 UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,
38 UNWIND_PERSONALITY_MASK = 0x30000000,
41 FLAGS_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,
48 UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
49 UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
51 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,
56 UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
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,
69 FLAGS_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,
76 UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
77 UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
79 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,
84 UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
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,
97 FLAGS_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,
103 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,
113 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
114 UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
117 FLAGS_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,
123 UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,
125 UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,
126 UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,
127 UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,
129 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,
135 UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,
137 UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,
141 #ifndef UNWIND_SECOND_LEVEL_REGULAR
142 #define UNWIND_SECOND_LEVEL_REGULAR 2
145 #ifndef UNWIND_SECOND_LEVEL_COMPRESSED
146 #define UNWIND_SECOND_LEVEL_COMPRESSED 3
149 #ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET
150 #define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
153 #ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX
154 #define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \
155 ((entry >> 24) & 0xFF)
158 #define EXTRACT_BITS(value, mask) \
160 llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \
161 (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1))
163 //----------------------
165 //----------------------
167 CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp)
168 : 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() {}
173 //----------------------
175 //----------------------
177 CompactUnwindInfo::~CompactUnwindInfo() {}
179 bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,
180 UnwindPlan &unwind_plan) {
181 if (!IsValid(target.GetProcessSP())) {
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)
191 if (m_objfile.GetArchitecture(arch)) {
193 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
194 if (log && log->GetVerbose()) {
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());
205 if (function_info.valid_range_offset_start != 0 &&
206 function_info.valid_range_offset_end != 0) {
207 SectionList *sl = m_objfile.GetSectionList();
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,
216 unwind_plan.SetPlanValidAddressRange(func_range);
220 if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {
221 return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,
224 if (arch.GetTriple().getArch() == llvm::Triple::aarch64) {
225 return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);
227 if (arch.GetTriple().getArch() == llvm::Triple::x86) {
228 return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);
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);
239 bool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {
240 if (m_section_sp.get() == nullptr)
243 if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)
246 ScanIndex(process_sp);
248 return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;
251 void 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)
256 // We can't read the index for some reason.
257 if (m_indexes_computed == eLazyBoolNo) {
261 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND));
263 m_objfile.GetModule()->LogMessage(
264 log, "Reading compact unwind first-level indexes");
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
270 // process and can read them out of memory.
271 if (process_sp.get() == nullptr)
273 m_section_contents_if_encrypted.reset(
274 new DataBufferHeap(m_section_sp->GetByteSize(), 0));
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() &&
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);
289 m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);
291 if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())
293 m_unwindinfo_data_computed = true;
296 if (m_unwindinfo_data.GetByteSize() > 0) {
299 // struct unwind_info_section_header
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;
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);
319 uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);
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 "
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;
336 // Parse the basic information from the indexes
337 // We wait to scan the second level page info until it's needed
339 // struct unwind_info_section_header_index_entry
341 // uint32_t functionOffset;
342 // uint32_t secondLevelPagesSectionOffset;
343 // uint32_t lsdaIndexArraySectionOffset;
346 bool clear_address_zeroth_bit = false;
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;
354 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
363 if (second_level_offset > m_section_sp->GetByteSize() ||
364 lsda_offset > m_section_sp->GetByteSize()) {
365 m_indexes_computed = eLazyBoolNo;
368 if (clear_address_zeroth_bit)
369 function_offset &= ~1ull;
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;
376 if (m_indexes.size() > 0) {
377 m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;
380 if (second_level_offset == 0) {
381 this_index.sentinal_entry = true;
384 m_indexes.push_back(this_index);
386 m_indexes_computed = eLazyBoolYes;
388 m_indexes_computed = eLazyBoolNo;
392 uint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,
394 uint32_t function_offset) {
395 // struct unwind_info_section_header_lsda_index_entry
397 // uint32_t functionOffset;
398 // uint32_t lsdaOffset;
401 offset_t first_entry = lsda_offset;
403 uint32_t high = lsda_count;
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;
413 if (mid_func_offset < function_offset) {
422 lldb::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
428 // uint32_t functionOffset;
429 // compact_unwind_encoding_t encoding;
431 offset_t first_entry = entry_page_offset;
434 uint32_t high = entry_count;
435 uint32_t last = high - 1;
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;
443 offset = first_entry + ((mid + 1) * 8);
444 next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset
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);
460 return LLDB_INVALID_OFFSET;
463 uint32_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;
470 uint32_t high = entry_count;
471 uint32_t last = high - 1;
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;
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;
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);
503 bool 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();
509 if (!IsValid(target.GetProcessSP()))
512 addr_t text_section_file_address = LLDB_INVALID_ADDRESS;
513 SectionList *sl = m_objfile.GetSectionList();
515 SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);
516 if (text_sect.get()) {
517 text_section_file_address = text_sect->GetFileAddress();
520 if (text_section_file_address == LLDB_INVALID_ADDRESS)
523 addr_t function_offset =
524 address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress();
527 key.function_offset = function_offset;
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()) {
535 if (it->function_offset != key.function_offset) {
536 if (it != m_indexes.begin())
540 if (it->sentinal_entry == true) {
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;
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;
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
560 if (kind == UNWIND_SECOND_LEVEL_REGULAR) {
561 // struct unwind_info_regular_second_level_page_header
563 // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
564 // uint16_t entryPageOffset;
565 // uint16_t entryCount;
567 // typedef uint32_t compact_unwind_encoding_t;
568 // struct unwind_info_regular_second_level_entry
570 // uint32_t functionOffset;
571 // compact_unwind_encoding_t encoding;
573 uint16_t entry_page_offset =
574 m_unwindinfo_data.GetU16(&offset); // entryPageOffset
575 uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount
577 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) {
584 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();
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);
597 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
598 uint32_t personality_index =
599 EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
601 if (personality_index > 0) {
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();
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);
618 } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {
619 // struct unwind_info_compressed_second_level_page_header
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
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;
636 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
644 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 ||
650 encodings_count + m_unwind_header.common_encodings_array_count) {
653 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
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
670 unwind_info.encoding = encoding;
671 if (unwind_info.encoding & UNWIND_HAS_LSDA) {
672 SectionList *sl = m_objfile.GetSectionList();
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);
682 if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {
683 uint32_t personality_index =
684 EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);
686 if (personality_index > 0) {
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();
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);
707 enum x86_64_eh_regnum {
724 rip = 16 // this is officially the Return Address register number, but close
728 // Convert the compact_unwind_info.h register numbering scheme
729 // to eRegisterKindEHFrame (eh_frame) register numbering scheme.
730 uint32_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;
745 return LLDB_INVALID_REGNUM;
749 bool 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);
758 unwind_plan.SetLSDAAddress(function_info.lsda_address);
759 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
761 UnwindPlan::RowSP row(new UnwindPlan::Row);
763 const int wordsize = 8;
764 int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;
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),
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);
777 uint32_t saved_registers_offset =
778 EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
780 uint32_t saved_registers_locations =
781 EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
783 saved_registers_offset += 2;
785 for (int i = 0; i < 5; i++) {
786 uint32_t regnum = saved_registers_locations & 0x7;
788 case UNWIND_X86_64_REG_NONE:
790 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);
800 saved_registers_offset--;
801 saved_registers_locations >>= 3;
803 unwind_plan.AppendRow(row);
807 case UNWIND_X86_64_MODE_STACK_IND: {
808 // The clang in Xcode 6 is emitting incorrect compact unwind encodings for
810 // style of unwind. It was fixed in llvm r217020.
811 // The clang in Xcode 7 has this fixed.
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);
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);
828 // offset into the function instructions; 0 == beginning of first
830 uint32_t offset_to_subl_insn = EXTRACT_BITS(
831 function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
833 SectionList *sl = m_objfile.GetSectionList();
835 ProcessSP process_sp = target.GetProcessSP();
837 Address subl_payload_addr(function_info.valid_range_offset_start, sl);
838 subl_payload_addr.Slide(offset_to_subl_insn);
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);
856 int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND
858 : stack_size * wordsize;
859 row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);
862 row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,
863 wordsize * -1, true);
864 row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);
866 if (register_count > 0) {
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.
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};
876 // This decodes the variable-base number in the 10 bits
877 // and gives us the Lehmer code sequence which can then
880 switch (register_count) {
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!
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;
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;
914 permunreg[0] = permutation / 20;
915 permutation -= (permunreg[0] * 20);
916 permunreg[1] = permutation / 4;
917 permutation -= (permunreg[1] * 4);
918 permunreg[2] = permutation;
921 permunreg[0] = permutation / 5;
922 permutation -= (permunreg[0] * 5);
923 permunreg[1] = permutation;
926 permunreg[0] = permutation;
930 // Decode the Lehmer code for this permutation of
931 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
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++) {
939 for (int j = 1; j < 7; j++) {
940 if (used[j] == false) {
941 if (renum == permunreg[i]) {
951 uint32_t saved_registers_offset = 1;
952 saved_registers_offset++;
954 for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
955 switch (registers[i]) {
956 case UNWIND_X86_64_REG_NONE:
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++;
972 unwind_plan.AppendRow(row);
976 case UNWIND_X86_64_MODE_DWARF: {
987 enum i386_eh_regnum {
996 eip = 8 // this is officially the Return Address register number, but close
1000 // Convert the compact_unwind_info.h register numbering scheme
1001 // to eRegisterKindEHFrame (eh_frame) register numbering scheme.
1002 uint32_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;
1017 return LLDB_INVALID_REGNUM;
1021 bool 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);
1030 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1031 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1033 UnwindPlan::RowSP row(new UnwindPlan::Row);
1035 const int wordsize = 4;
1036 int mode = function_info.encoding & UNWIND_X86_MODE_MASK;
1038 case UNWIND_X86_MODE_EBP_FRAME: {
1039 row->GetCFAValue().SetIsRegisterPlusOffset(
1040 translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);
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);
1048 uint32_t saved_registers_offset =
1049 EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);
1051 uint32_t saved_registers_locations =
1052 EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);
1054 saved_registers_offset += 2;
1056 for (int i = 0; i < 5; i++) {
1057 uint32_t regnum = saved_registers_locations & 0x7;
1059 case UNWIND_X86_REG_NONE:
1061 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);
1071 saved_registers_offset--;
1072 saved_registers_locations >>= 3;
1074 unwind_plan.AppendRow(row);
1078 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);
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);
1092 // offset into the function instructions; 0 == beginning of first
1094 uint32_t offset_to_subl_insn =
1095 EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
1097 SectionList *sl = m_objfile.GetSectionList();
1099 ProcessSP process_sp = target.GetProcessSP();
1101 Address subl_payload_addr(function_info.valid_range_offset_start, sl);
1102 subl_payload_addr.Slide(offset_to_subl_insn);
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);
1121 mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;
1122 row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);
1124 row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,
1125 wordsize * -1, true);
1126 row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);
1128 if (register_count > 0) {
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.
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};
1138 // This decodes the variable-base number in the 10 bits
1139 // and gives us the Lehmer code sequence which can then
1142 switch (register_count) {
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!
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;
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;
1176 permunreg[0] = permutation / 20;
1177 permutation -= (permunreg[0] * 20);
1178 permunreg[1] = permutation / 4;
1179 permutation -= (permunreg[1] * 4);
1180 permunreg[2] = permutation;
1183 permunreg[0] = permutation / 5;
1184 permutation -= (permunreg[0] * 5);
1185 permunreg[1] = permutation;
1188 permunreg[0] = permutation;
1192 // Decode the Lehmer code for this permutation of
1193 // the registers v. http://en.wikipedia.org/wiki/Lehmer_code
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++) {
1201 for (int j = 1; j < 7; j++) {
1202 if (used[j] == false) {
1203 if (renum == permunreg[i]) {
1213 uint32_t saved_registers_offset = 1;
1214 saved_registers_offset++;
1216 for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {
1217 switch (registers[i]) {
1218 case UNWIND_X86_REG_NONE:
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++;
1235 unwind_plan.AppendRow(row);
1239 case UNWIND_X86_MODE_DWARF: {
1246 // DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"
1249 enum arm64_eh_regnum {
1266 // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s
1268 // fp regs. Normally in DWARF it's context sensitive - so it knows it is
1270 // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder
1272 // at a lower level and we'd try to fetch 128 bits if we were told that v8
1285 enum arm_eh_regnum {
1321 bool 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);
1330 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1331 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1333 UnwindPlan::RowSP row(new UnwindPlan::Row);
1335 const int wordsize = 8;
1336 int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;
1338 if (mode == UNWIND_ARM64_MODE_DWARF)
1341 if (mode == UNWIND_ARM64_MODE_FRAMELESS) {
1344 uint32_t stack_size =
1345 (EXTRACT_BITS(function_info.encoding,
1346 UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *
1349 // Our previous Call Frame Address is the stack pointer plus the stack size
1350 row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);
1352 // Our previous PC is in the LR
1353 row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,
1356 unwind_plan.AppendRow(row);
1360 // Should not be possible
1361 if (mode != UNWIND_ARM64_MODE_FRAME)
1364 // mode == UNWIND_ARM64_MODE_FRAME
1366 row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);
1368 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,
1370 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,
1372 row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);
1374 int reg_pairs_saved_count = 1;
1376 uint32_t saved_register_bits = function_info.encoding & 0xfff;
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,
1383 cfa_offset -= wordsize;
1384 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,
1386 reg_pairs_saved_count++;
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,
1394 cfa_offset -= wordsize;
1395 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,
1397 reg_pairs_saved_count++;
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,
1405 cfa_offset -= wordsize;
1406 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,
1408 reg_pairs_saved_count++;
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,
1416 cfa_offset -= wordsize;
1417 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,
1419 reg_pairs_saved_count++;
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,
1427 cfa_offset -= wordsize;
1428 row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,
1430 reg_pairs_saved_count++;
1433 // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits
1435 // not sure if we have a good way to represent the 64-bitness of these saves.
1437 if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
1438 reg_pairs_saved_count++;
1440 if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
1441 reg_pairs_saved_count++;
1443 if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
1444 reg_pairs_saved_count++;
1446 if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
1447 reg_pairs_saved_count++;
1450 unwind_plan.AppendRow(row);
1454 bool 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);
1463 unwind_plan.SetLSDAAddress(function_info.lsda_address);
1464 unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
1466 UnwindPlan::RowSP row(new UnwindPlan::Row);
1468 const int wordsize = 4;
1469 int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;
1471 if (mode == UNWIND_ARM_MODE_DWARF)
1474 uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,
1475 UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *
1478 row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,
1479 (2 * wordsize) + stack_adjust);
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);
1487 int cfa_offset = -stack_adjust - (2 * wordsize);
1489 uint32_t saved_register_bits = function_info.encoding & 0xff;
1491 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {
1492 cfa_offset -= wordsize;
1493 row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);
1496 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {
1497 cfa_offset -= wordsize;
1498 row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);
1501 if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {
1502 cfa_offset -= wordsize;
1503 row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);
1506 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {
1507 cfa_offset -= wordsize;
1508 row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);
1511 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {
1512 cfa_offset -= wordsize;
1513 row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);
1516 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {
1517 cfa_offset -= wordsize;
1518 row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);
1521 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {
1522 cfa_offset -= wordsize;
1523 row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);
1526 if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {
1527 cfa_offset -= wordsize;
1528 row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);
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) {
1538 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1544 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1546 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1553 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1555 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1557 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1565 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1567 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
1569 row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);
1571 row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);
1576 // sp = (sp - 24) & (-16);
1577 // vst {d8, d9, d10}
1579 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
1581 row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);
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.
1590 // sp = (sp - 40) & (-16);
1591 // vst {d8, d9, d10, d11}
1595 row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);
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.
1603 // sp = (sp - 56) & (-16);
1604 // vst {d8, d9, d10, d11}
1605 // vst {d12, d13, d14}
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.
1613 // sp = (sp - 64) & (-16);
1614 // vst {d8, d9, d10, d11}
1615 // vst {d12, d13, d14, d15}
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.
1625 unwind_plan.AppendRow(row);