Path: blob/main/contrib/llvm-project/lldb/source/Symbol/CompactUnwindInfo.cpp
39587 views
//===-- CompactUnwindInfo.cpp ---------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Symbol/CompactUnwindInfo.h"9#include "lldb/Core/Debugger.h"10#include "lldb/Core/Module.h"11#include "lldb/Core/Section.h"12#include "lldb/Symbol/ObjectFile.h"13#include "lldb/Symbol/UnwindPlan.h"14#include "lldb/Target/Process.h"15#include "lldb/Target/Target.h"16#include "lldb/Utility/ArchSpec.h"17#include "lldb/Utility/DataBufferHeap.h"18#include "lldb/Utility/LLDBLog.h"19#include "lldb/Utility/Log.h"20#include "lldb/Utility/StreamString.h"2122#include "llvm/Support/MathExtras.h"2324#include <algorithm>25#include <memory>2627using namespace lldb;28using namespace lldb_private;2930namespace lldb_private {3132// Constants from <mach-o/compact_unwind_encoding.h>3334FLAGS_ANONYMOUS_ENUM(){35UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000,36UNWIND_PERSONALITY_MASK = 0x30000000,37};3839FLAGS_ANONYMOUS_ENUM(){40UNWIND_X86_MODE_MASK = 0x0F000000,41UNWIND_X86_MODE_EBP_FRAME = 0x01000000,42UNWIND_X86_MODE_STACK_IMMD = 0x02000000,43UNWIND_X86_MODE_STACK_IND = 0x03000000,44UNWIND_X86_MODE_DWARF = 0x04000000,4546UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,47UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,4849UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,50UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,51UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,52UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,5354UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,55};5657enum {58UNWIND_X86_REG_NONE = 0,59UNWIND_X86_REG_EBX = 1,60UNWIND_X86_REG_ECX = 2,61UNWIND_X86_REG_EDX = 3,62UNWIND_X86_REG_EDI = 4,63UNWIND_X86_REG_ESI = 5,64UNWIND_X86_REG_EBP = 6,65};6667FLAGS_ANONYMOUS_ENUM(){68UNWIND_X86_64_MODE_MASK = 0x0F000000,69UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,70UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,71UNWIND_X86_64_MODE_STACK_IND = 0x03000000,72UNWIND_X86_64_MODE_DWARF = 0x04000000,7374UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,75UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,7677UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,78UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,79UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,80UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,8182UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,83};8485enum {86UNWIND_X86_64_REG_NONE = 0,87UNWIND_X86_64_REG_RBX = 1,88UNWIND_X86_64_REG_R12 = 2,89UNWIND_X86_64_REG_R13 = 3,90UNWIND_X86_64_REG_R14 = 4,91UNWIND_X86_64_REG_R15 = 5,92UNWIND_X86_64_REG_RBP = 6,93};9495FLAGS_ANONYMOUS_ENUM(){96UNWIND_ARM64_MODE_MASK = 0x0F000000,97UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,98UNWIND_ARM64_MODE_DWARF = 0x03000000,99UNWIND_ARM64_MODE_FRAME = 0x04000000,100101UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,102UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,103UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,104UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,105UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,106UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,107UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,108UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,109UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,110111UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,112UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,113};114115FLAGS_ANONYMOUS_ENUM(){116UNWIND_ARM_MODE_MASK = 0x0F000000,117UNWIND_ARM_MODE_FRAME = 0x01000000,118UNWIND_ARM_MODE_FRAME_D = 0x02000000,119UNWIND_ARM_MODE_DWARF = 0x04000000,120121UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000,122123UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001,124UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002,125UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004,126127UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008,128UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010,129UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020,130UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040,131UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080,132133UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700,134135UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF,136};137}138139#ifndef UNWIND_SECOND_LEVEL_REGULAR140#define UNWIND_SECOND_LEVEL_REGULAR 2141#endif142143#ifndef UNWIND_SECOND_LEVEL_COMPRESSED144#define UNWIND_SECOND_LEVEL_COMPRESSED 3145#endif146147#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET148#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)149#endif150151#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX152#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \153((entry >> 24) & 0xFF)154#endif155156#define EXTRACT_BITS(value, mask) \157((value >> llvm::countr_zero(static_cast<uint32_t>(mask))) & \158(((1 << llvm::popcount(static_cast<uint32_t>(mask)))) - 1))159160// constructor161162CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp)163: m_objfile(objfile), m_section_sp(section_sp),164m_section_contents_if_encrypted(), m_mutex(), m_indexes(),165m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(),166m_unwindinfo_data_computed(false), m_unwind_header() {}167168// destructor169170CompactUnwindInfo::~CompactUnwindInfo() = default;171172bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr,173UnwindPlan &unwind_plan) {174if (!IsValid(target.GetProcessSP())) {175return false;176}177FunctionInfo function_info;178if (GetCompactUnwindInfoForFunction(target, addr, function_info)) {179// shortcut return for functions that have no compact unwind180if (function_info.encoding == 0)181return false;182183if (ArchSpec arch = m_objfile.GetArchitecture()) {184185Log *log = GetLog(LLDBLog::Unwind);186if (log && log->GetVerbose()) {187StreamString strm;188addr.Dump(189&strm, nullptr,190Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments,191Address::DumpStyle::DumpStyleFileAddress,192arch.GetAddressByteSize());193LLDB_LOGF(log, "Got compact unwind encoding 0x%x for function %s",194function_info.encoding, strm.GetData());195}196197if (function_info.valid_range_offset_start != 0 &&198function_info.valid_range_offset_end != 0) {199SectionList *sl = m_objfile.GetSectionList();200if (sl) {201addr_t func_range_start_file_addr =202function_info.valid_range_offset_start +203m_objfile.GetBaseAddress().GetFileAddress();204AddressRange func_range(func_range_start_file_addr,205function_info.valid_range_offset_end -206function_info.valid_range_offset_start,207sl);208unwind_plan.SetPlanValidAddressRange(func_range);209}210}211212if (arch.GetTriple().getArch() == llvm::Triple::x86_64) {213return CreateUnwindPlan_x86_64(target, function_info, unwind_plan,214addr);215}216if (arch.GetTriple().getArch() == llvm::Triple::aarch64 ||217arch.GetTriple().getArch() == llvm::Triple::aarch64_32) {218return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr);219}220if (arch.GetTriple().getArch() == llvm::Triple::x86) {221return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr);222}223if (arch.GetTriple().getArch() == llvm::Triple::arm ||224arch.GetTriple().getArch() == llvm::Triple::thumb) {225return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr);226}227}228}229return false;230}231232bool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) {233if (m_section_sp.get() == nullptr)234return false;235236if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)237return true;238239ScanIndex(process_sp);240241return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed;242}243244void CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) {245std::lock_guard<std::mutex> guard(m_mutex);246if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed)247return;248249// We can't read the index for some reason.250if (m_indexes_computed == eLazyBoolNo) {251return;252}253254Log *log = GetLog(LLDBLog::Unwind);255if (log)256m_objfile.GetModule()->LogMessage(257log, "Reading compact unwind first-level indexes");258259if (!m_unwindinfo_data_computed) {260if (m_section_sp->IsEncrypted()) {261// Can't get section contents of a protected/encrypted section until we262// have a live process and can read them out of memory.263if (process_sp.get() == nullptr)264return;265m_section_contents_if_encrypted =266std::make_shared<DataBufferHeap>(m_section_sp->GetByteSize(), 0);267Status error;268if (process_sp->ReadMemory(269m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()),270m_section_contents_if_encrypted->GetBytes(),271m_section_sp->GetByteSize(),272error) == m_section_sp->GetByteSize() &&273error.Success()) {274m_unwindinfo_data.SetAddressByteSize(275process_sp->GetTarget().GetArchitecture().GetAddressByteSize());276m_unwindinfo_data.SetByteOrder(277process_sp->GetTarget().GetArchitecture().GetByteOrder());278m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0);279}280} else {281m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data);282}283if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize())284return;285m_unwindinfo_data_computed = true;286}287288if (m_unwindinfo_data.GetByteSize() > 0) {289offset_t offset = 0;290291// struct unwind_info_section_header292// {293// uint32_t version; // UNWIND_SECTION_VERSION294// uint32_t commonEncodingsArraySectionOffset;295// uint32_t commonEncodingsArrayCount;296// uint32_t personalityArraySectionOffset;297// uint32_t personalityArrayCount;298// uint32_t indexSectionOffset;299// uint32_t indexCount;300301m_unwind_header.version = m_unwindinfo_data.GetU32(&offset);302m_unwind_header.common_encodings_array_offset =303m_unwindinfo_data.GetU32(&offset);304m_unwind_header.common_encodings_array_count =305m_unwindinfo_data.GetU32(&offset);306m_unwind_header.personality_array_offset =307m_unwindinfo_data.GetU32(&offset);308m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset);309uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset);310311uint32_t indexCount = m_unwindinfo_data.GetU32(&offset);312313if (m_unwind_header.common_encodings_array_offset >314m_unwindinfo_data.GetByteSize() ||315m_unwind_header.personality_array_offset >316m_unwindinfo_data.GetByteSize() ||317indexSectionOffset > m_unwindinfo_data.GetByteSize() ||318offset > m_unwindinfo_data.GetByteSize()) {319Debugger::ReportError(320"Invalid offset encountered in compact unwind info, skipping");321// don't trust anything from this compact_unwind section if it looks322// blatantly invalid data in the header.323m_indexes_computed = eLazyBoolNo;324return;325}326327// Parse the basic information from the indexes We wait to scan the second328// level page info until it's needed329330// struct unwind_info_section_header_index_entry {331// uint32_t functionOffset;332// uint32_t secondLevelPagesSectionOffset;333// uint32_t lsdaIndexArraySectionOffset;334// };335336bool clear_address_zeroth_bit = false;337if (ArchSpec arch = m_objfile.GetArchitecture()) {338if (arch.GetTriple().getArch() == llvm::Triple::arm ||339arch.GetTriple().getArch() == llvm::Triple::thumb)340clear_address_zeroth_bit = true;341}342343offset = indexSectionOffset;344for (uint32_t idx = 0; idx < indexCount; idx++) {345uint32_t function_offset =346m_unwindinfo_data.GetU32(&offset); // functionOffset347uint32_t second_level_offset =348m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset349uint32_t lsda_offset =350m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset351352if (second_level_offset > m_section_sp->GetByteSize() ||353lsda_offset > m_section_sp->GetByteSize()) {354m_indexes_computed = eLazyBoolNo;355}356357if (clear_address_zeroth_bit)358function_offset &= ~1ull;359360UnwindIndex this_index;361this_index.function_offset = function_offset;362this_index.second_level = second_level_offset;363this_index.lsda_array_start = lsda_offset;364365if (m_indexes.size() > 0) {366m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset;367}368369if (second_level_offset == 0) {370this_index.sentinal_entry = true;371}372373m_indexes.push_back(this_index);374}375m_indexes_computed = eLazyBoolYes;376} else {377m_indexes_computed = eLazyBoolNo;378}379}380381uint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset,382uint32_t lsda_count,383uint32_t function_offset) {384// struct unwind_info_section_header_lsda_index_entry {385// uint32_t functionOffset;386// uint32_t lsdaOffset;387// };388389offset_t first_entry = lsda_offset;390uint32_t low = 0;391uint32_t high = lsda_count;392while (low < high) {393uint32_t mid = (low + high) / 2;394offset_t offset = first_entry + (mid * 8);395uint32_t mid_func_offset =396m_unwindinfo_data.GetU32(&offset); // functionOffset397uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset398if (mid_func_offset == function_offset) {399return mid_lsda_offset;400}401if (mid_func_offset < function_offset) {402low = mid + 1;403} else {404high = mid;405}406}407return 0;408}409410lldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage(411uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset,412uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {413// typedef uint32_t compact_unwind_encoding_t;414// struct unwind_info_regular_second_level_entry {415// uint32_t functionOffset;416// compact_unwind_encoding_t encoding;417418offset_t first_entry = entry_page_offset;419420uint32_t low = 0;421uint32_t high = entry_count;422uint32_t last = high - 1;423while (low < high) {424uint32_t mid = (low + high) / 2;425offset_t offset = first_entry + (mid * 8);426uint32_t mid_func_offset =427m_unwindinfo_data.GetU32(&offset); // functionOffset428uint32_t next_func_offset = 0;429if (mid < last) {430offset = first_entry + ((mid + 1) * 8);431next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset432}433if (mid_func_offset <= function_offset) {434if (mid == last || (next_func_offset > function_offset)) {435if (entry_func_start_offset)436*entry_func_start_offset = mid_func_offset;437if (mid != last && entry_func_end_offset)438*entry_func_end_offset = next_func_offset;439return first_entry + (mid * 8);440} else {441low = mid + 1;442}443} else {444high = mid;445}446}447return LLDB_INVALID_OFFSET;448}449450uint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage(451uint32_t entry_page_offset, uint32_t entry_count,452uint32_t function_offset_to_find, uint32_t function_offset_base,453uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) {454offset_t first_entry = entry_page_offset;455456uint32_t low = 0;457uint32_t high = entry_count;458uint32_t last = high - 1;459while (low < high) {460uint32_t mid = (low + high) / 2;461offset_t offset = first_entry + (mid * 4);462uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry463uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry);464mid_func_offset += function_offset_base;465uint32_t next_func_offset = 0;466if (mid < last) {467offset = first_entry + ((mid + 1) * 4);468uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry469next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry);470next_func_offset += function_offset_base;471}472if (mid_func_offset <= function_offset_to_find) {473if (mid == last || (next_func_offset > function_offset_to_find)) {474if (entry_func_start_offset)475*entry_func_start_offset = mid_func_offset;476if (mid != last && entry_func_end_offset)477*entry_func_end_offset = next_func_offset;478return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry);479} else {480low = mid + 1;481}482} else {483high = mid;484}485}486487return UINT32_MAX;488}489490bool CompactUnwindInfo::GetCompactUnwindInfoForFunction(491Target &target, Address address, FunctionInfo &unwind_info) {492unwind_info.encoding = 0;493unwind_info.lsda_address.Clear();494unwind_info.personality_ptr_address.Clear();495496if (!IsValid(target.GetProcessSP()))497return false;498499addr_t text_section_file_address = LLDB_INVALID_ADDRESS;500SectionList *sl = m_objfile.GetSectionList();501if (sl) {502SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true);503if (text_sect.get()) {504text_section_file_address = text_sect->GetFileAddress();505}506}507if (text_section_file_address == LLDB_INVALID_ADDRESS)508return false;509510addr_t function_offset =511address.GetFileAddress() - m_objfile.GetBaseAddress().GetFileAddress();512513UnwindIndex key;514key.function_offset = function_offset;515516std::vector<UnwindIndex>::const_iterator it;517it = llvm::lower_bound(m_indexes, key);518if (it == m_indexes.end()) {519return false;520}521522if (it->function_offset != key.function_offset) {523if (it != m_indexes.begin())524--it;525}526527if (it->sentinal_entry) {528return false;529}530531auto next_it = it + 1;532if (next_it != m_indexes.end()) {533// initialize the function offset end range to be the start of the next534// index offset. If we find an entry which is at the end of the index535// table, this will establish the range end.536unwind_info.valid_range_offset_end = next_it->function_offset;537}538539offset_t second_page_offset = it->second_level;540offset_t lsda_array_start = it->lsda_array_start;541offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8;542543offset_t offset = second_page_offset;544uint32_t kind = m_unwindinfo_data.GetU32(545&offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED546547if (kind == UNWIND_SECOND_LEVEL_REGULAR) {548// struct unwind_info_regular_second_level_page_header {549// uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR550// uint16_t entryPageOffset;551// uint16_t entryCount;552553// typedef uint32_t compact_unwind_encoding_t;554// struct unwind_info_regular_second_level_entry {555// uint32_t functionOffset;556// compact_unwind_encoding_t encoding;557558uint16_t entry_page_offset =559m_unwindinfo_data.GetU16(&offset); // entryPageOffset560uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount561562offset_t entry_offset = BinarySearchRegularSecondPage(563second_page_offset + entry_page_offset, entry_count, function_offset,564&unwind_info.valid_range_offset_start,565&unwind_info.valid_range_offset_end);566if (entry_offset == LLDB_INVALID_OFFSET) {567return false;568}569entry_offset += 4; // skip over functionOffset570unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding571if (unwind_info.encoding & UNWIND_HAS_LSDA) {572SectionList *sl = m_objfile.GetSectionList();573if (sl) {574uint32_t lsda_offset = GetLSDAForFunctionOffset(575lsda_array_start, lsda_array_count, function_offset);576addr_t objfile_base_address =577m_objfile.GetBaseAddress().GetFileAddress();578unwind_info.lsda_address.ResolveAddressUsingFileSections(579objfile_base_address + lsda_offset, sl);580}581}582if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {583uint32_t personality_index =584EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);585586if (personality_index > 0) {587personality_index--;588if (personality_index < m_unwind_header.personality_array_count) {589offset_t offset = m_unwind_header.personality_array_offset;590offset += 4 * personality_index;591SectionList *sl = m_objfile.GetSectionList();592if (sl) {593uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);594addr_t objfile_base_address =595m_objfile.GetBaseAddress().GetFileAddress();596unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(597objfile_base_address + personality_offset, sl);598}599}600}601}602return true;603} else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) {604// struct unwind_info_compressed_second_level_page_header {605// uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED606// uint16_t entryPageOffset; // offset from this 2nd lvl page607// idx to array of entries608// // (an entry has a function609// offset and index into the610// encodings)611// // NB function offset from the612// entry in the compressed page613// // must be added to the index's614// functionOffset value.615// uint16_t entryCount;616// uint16_t encodingsPageOffset; // offset from this 2nd lvl page617// idx to array of encodings618// uint16_t encodingsCount;619620uint16_t entry_page_offset =621m_unwindinfo_data.GetU16(&offset); // entryPageOffset622uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount623uint16_t encodings_page_offset =624m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset625uint16_t encodings_count =626m_unwindinfo_data.GetU16(&offset); // encodingsCount627628uint32_t encoding_index = BinarySearchCompressedSecondPage(629second_page_offset + entry_page_offset, entry_count, function_offset,630it->function_offset, &unwind_info.valid_range_offset_start,631&unwind_info.valid_range_offset_end);632if (encoding_index == UINT32_MAX ||633encoding_index >=634encodings_count + m_unwind_header.common_encodings_array_count) {635return false;636}637uint32_t encoding = 0;638if (encoding_index < m_unwind_header.common_encodings_array_count) {639offset = m_unwind_header.common_encodings_array_offset +640(encoding_index * sizeof(uint32_t));641encoding = m_unwindinfo_data.GetU32(642&offset); // encoding entry from the commonEncodingsArray643} else {644uint32_t page_specific_entry_index =645encoding_index - m_unwind_header.common_encodings_array_count;646offset = second_page_offset + encodings_page_offset +647(page_specific_entry_index * sizeof(uint32_t));648encoding = m_unwindinfo_data.GetU32(649&offset); // encoding entry from the page-specific encoding array650}651if (encoding == 0)652return false;653654unwind_info.encoding = encoding;655if (unwind_info.encoding & UNWIND_HAS_LSDA) {656SectionList *sl = m_objfile.GetSectionList();657if (sl) {658uint32_t lsda_offset = GetLSDAForFunctionOffset(659lsda_array_start, lsda_array_count, function_offset);660addr_t objfile_base_address =661m_objfile.GetBaseAddress().GetFileAddress();662unwind_info.lsda_address.ResolveAddressUsingFileSections(663objfile_base_address + lsda_offset, sl);664}665}666if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) {667uint32_t personality_index =668EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK);669670if (personality_index > 0) {671personality_index--;672if (personality_index < m_unwind_header.personality_array_count) {673offset_t offset = m_unwind_header.personality_array_offset;674offset += 4 * personality_index;675SectionList *sl = m_objfile.GetSectionList();676if (sl) {677uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset);678addr_t objfile_base_address =679m_objfile.GetBaseAddress().GetFileAddress();680unwind_info.personality_ptr_address.ResolveAddressUsingFileSections(681objfile_base_address + personality_offset, sl);682}683}684}685}686return true;687}688return false;689}690691enum x86_64_eh_regnum {692rax = 0,693rdx = 1,694rcx = 2,695rbx = 3,696rsi = 4,697rdi = 5,698rbp = 6,699rsp = 7,700r8 = 8,701r9 = 9,702r10 = 10,703r11 = 11,704r12 = 12,705r13 = 13,706r14 = 14,707r15 = 15,708rip = 16 // this is officially the Return Address register number, but close709// enough710};711712// Convert the compact_unwind_info.h register numbering scheme to713// eRegisterKindEHFrame (eh_frame) register numbering scheme.714uint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) {715switch (unwind_regno) {716case UNWIND_X86_64_REG_RBX:717return x86_64_eh_regnum::rbx;718case UNWIND_X86_64_REG_R12:719return x86_64_eh_regnum::r12;720case UNWIND_X86_64_REG_R13:721return x86_64_eh_regnum::r13;722case UNWIND_X86_64_REG_R14:723return x86_64_eh_regnum::r14;724case UNWIND_X86_64_REG_R15:725return x86_64_eh_regnum::r15;726case UNWIND_X86_64_REG_RBP:727return x86_64_eh_regnum::rbp;728default:729return LLDB_INVALID_REGNUM;730}731}732733bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,734FunctionInfo &function_info,735UnwindPlan &unwind_plan,736Address pc_or_function_start) {737unwind_plan.SetSourceName("compact unwind info");738unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);739unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);740unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);741unwind_plan.SetRegisterKind(eRegisterKindEHFrame);742743unwind_plan.SetLSDAAddress(function_info.lsda_address);744unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);745746UnwindPlan::RowSP row(new UnwindPlan::Row);747748const int wordsize = 8;749int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK;750switch (mode) {751case UNWIND_X86_64_MODE_RBP_FRAME: {752row->GetCFAValue().SetIsRegisterPlusOffset(753translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP),7542 * wordsize);755row->SetOffset(0);756row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp,757wordsize * -2, true);758row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,759wordsize * -1, true);760row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);761762uint32_t saved_registers_offset =763EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET);764765uint32_t saved_registers_locations =766EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);767768saved_registers_offset += 2;769770for (int i = 0; i < 5; i++) {771uint32_t regnum = saved_registers_locations & 0x7;772switch (regnum) {773case UNWIND_X86_64_REG_NONE:774break;775case UNWIND_X86_64_REG_RBX:776case UNWIND_X86_64_REG_R12:777case UNWIND_X86_64_REG_R13:778case UNWIND_X86_64_REG_R14:779case UNWIND_X86_64_REG_R15:780row->SetRegisterLocationToAtCFAPlusOffset(781translate_to_eh_frame_regnum_x86_64(regnum),782wordsize * -saved_registers_offset, true);783break;784}785saved_registers_offset--;786saved_registers_locations >>= 3;787}788unwind_plan.AppendRow(row);789return true;790} break;791792case UNWIND_X86_64_MODE_STACK_IND: {793// The clang in Xcode 6 is emitting incorrect compact unwind encodings for794// this style of unwind. It was fixed in llvm r217020. The clang in Xcode795// 7 has this fixed.796return false;797} break;798799case UNWIND_X86_64_MODE_STACK_IMMD: {800uint32_t stack_size = EXTRACT_BITS(function_info.encoding,801UNWIND_X86_64_FRAMELESS_STACK_SIZE);802uint32_t register_count = EXTRACT_BITS(803function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);804uint32_t permutation = EXTRACT_BITS(805function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);806807if (mode == UNWIND_X86_64_MODE_STACK_IND &&808function_info.valid_range_offset_start != 0) {809uint32_t stack_adjust = EXTRACT_BITS(810function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);811812// offset into the function instructions; 0 == beginning of first813// instruction814uint32_t offset_to_subl_insn = EXTRACT_BITS(815function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);816817SectionList *sl = m_objfile.GetSectionList();818if (sl) {819ProcessSP process_sp = target.GetProcessSP();820if (process_sp) {821Address subl_payload_addr(function_info.valid_range_offset_start, sl);822subl_payload_addr.Slide(offset_to_subl_insn);823Status error;824uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(825subl_payload_addr.GetLoadAddress(&target), 4, 0, error);826if (large_stack_size != 0 && error.Success()) {827// Got the large stack frame size correctly - use it828stack_size = large_stack_size + (stack_adjust * wordsize);829} else {830return false;831}832} else {833return false;834}835} else {836return false;837}838}839840int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND841? stack_size842: stack_size * wordsize;843row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset);844845row->SetOffset(0);846row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip,847wordsize * -1, true);848row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true);849850if (register_count > 0) {851852// We need to include (up to) 6 registers in 10 bits. That would be 18853// bits if we just used 3 bits per reg to indicate the order they're854// saved on the stack.855//856// This is done with Lehmer code permutation, e.g. see857// http://stackoverflow.com/questions/1506078/fast-permutation-number-858// permutation-mapping-algorithms859int permunreg[6] = {0, 0, 0, 0, 0, 0};860861// This decodes the variable-base number in the 10 bits and gives us the862// Lehmer code sequence which can then be decoded.863864switch (register_count) {865case 6:866permunreg[0] = permutation / 120; // 120 == 5!867permutation -= (permunreg[0] * 120);868permunreg[1] = permutation / 24; // 24 == 4!869permutation -= (permunreg[1] * 24);870permunreg[2] = permutation / 6; // 6 == 3!871permutation -= (permunreg[2] * 6);872permunreg[3] = permutation / 2; // 2 == 2!873permutation -= (permunreg[3] * 2);874permunreg[4] = permutation; // 1 == 1!875permunreg[5] = 0;876break;877case 5:878permunreg[0] = permutation / 120;879permutation -= (permunreg[0] * 120);880permunreg[1] = permutation / 24;881permutation -= (permunreg[1] * 24);882permunreg[2] = permutation / 6;883permutation -= (permunreg[2] * 6);884permunreg[3] = permutation / 2;885permutation -= (permunreg[3] * 2);886permunreg[4] = permutation;887break;888case 4:889permunreg[0] = permutation / 60;890permutation -= (permunreg[0] * 60);891permunreg[1] = permutation / 12;892permutation -= (permunreg[1] * 12);893permunreg[2] = permutation / 3;894permutation -= (permunreg[2] * 3);895permunreg[3] = permutation;896break;897case 3:898permunreg[0] = permutation / 20;899permutation -= (permunreg[0] * 20);900permunreg[1] = permutation / 4;901permutation -= (permunreg[1] * 4);902permunreg[2] = permutation;903break;904case 2:905permunreg[0] = permutation / 5;906permutation -= (permunreg[0] * 5);907permunreg[1] = permutation;908break;909case 1:910permunreg[0] = permutation;911break;912}913914// Decode the Lehmer code for this permutation of the registers v.915// http://en.wikipedia.org/wiki/Lehmer_code916917int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,918UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE,919UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE};920bool used[7] = {false, false, false, false, false, false, false};921for (uint32_t i = 0; i < register_count; i++) {922int renum = 0;923for (int j = 1; j < 7; j++) {924if (!used[j]) {925if (renum == permunreg[i]) {926registers[i] = j;927used[j] = true;928break;929}930renum++;931}932}933}934935uint32_t saved_registers_offset = 1;936saved_registers_offset++;937938for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {939switch (registers[i]) {940case UNWIND_X86_64_REG_NONE:941break;942case UNWIND_X86_64_REG_RBX:943case UNWIND_X86_64_REG_R12:944case UNWIND_X86_64_REG_R13:945case UNWIND_X86_64_REG_R14:946case UNWIND_X86_64_REG_R15:947case UNWIND_X86_64_REG_RBP:948row->SetRegisterLocationToAtCFAPlusOffset(949translate_to_eh_frame_regnum_x86_64(registers[i]),950wordsize * -saved_registers_offset, true);951saved_registers_offset++;952break;953}954}955}956unwind_plan.AppendRow(row);957return true;958} break;959960case UNWIND_X86_64_MODE_DWARF: {961return false;962} break;963964case 0: {965return false;966} break;967}968return false;969}970971enum i386_eh_regnum {972eax = 0,973ecx = 1,974edx = 2,975ebx = 3,976ebp = 4,977esp = 5,978esi = 6,979edi = 7,980eip = 8 // this is officially the Return Address register number, but close981// enough982};983984// Convert the compact_unwind_info.h register numbering scheme to985// eRegisterKindEHFrame (eh_frame) register numbering scheme.986uint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) {987switch (unwind_regno) {988case UNWIND_X86_REG_EBX:989return i386_eh_regnum::ebx;990case UNWIND_X86_REG_ECX:991return i386_eh_regnum::ecx;992case UNWIND_X86_REG_EDX:993return i386_eh_regnum::edx;994case UNWIND_X86_REG_EDI:995return i386_eh_regnum::edi;996case UNWIND_X86_REG_ESI:997return i386_eh_regnum::esi;998case UNWIND_X86_REG_EBP:999return i386_eh_regnum::ebp;1000default:1001return LLDB_INVALID_REGNUM;1002}1003}10041005bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,1006FunctionInfo &function_info,1007UnwindPlan &unwind_plan,1008Address pc_or_function_start) {1009unwind_plan.SetSourceName("compact unwind info");1010unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);1011unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);1012unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);1013unwind_plan.SetRegisterKind(eRegisterKindEHFrame);10141015unwind_plan.SetLSDAAddress(function_info.lsda_address);1016unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);10171018UnwindPlan::RowSP row(new UnwindPlan::Row);10191020const int wordsize = 4;1021int mode = function_info.encoding & UNWIND_X86_MODE_MASK;1022switch (mode) {1023case UNWIND_X86_MODE_EBP_FRAME: {1024row->GetCFAValue().SetIsRegisterPlusOffset(1025translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize);1026row->SetOffset(0);1027row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp,1028wordsize * -2, true);1029row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,1030wordsize * -1, true);1031row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);10321033uint32_t saved_registers_offset =1034EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET);10351036uint32_t saved_registers_locations =1037EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS);10381039saved_registers_offset += 2;10401041for (int i = 0; i < 5; i++) {1042uint32_t regnum = saved_registers_locations & 0x7;1043switch (regnum) {1044case UNWIND_X86_REG_NONE:1045break;1046case UNWIND_X86_REG_EBX:1047case UNWIND_X86_REG_ECX:1048case UNWIND_X86_REG_EDX:1049case UNWIND_X86_REG_EDI:1050case UNWIND_X86_REG_ESI:1051row->SetRegisterLocationToAtCFAPlusOffset(1052translate_to_eh_frame_regnum_i386(regnum),1053wordsize * -saved_registers_offset, true);1054break;1055}1056saved_registers_offset--;1057saved_registers_locations >>= 3;1058}1059unwind_plan.AppendRow(row);1060return true;1061} break;10621063case UNWIND_X86_MODE_STACK_IND:1064case UNWIND_X86_MODE_STACK_IMMD: {1065uint32_t stack_size =1066EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);1067uint32_t register_count = EXTRACT_BITS(1068function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);1069uint32_t permutation = EXTRACT_BITS(1070function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);10711072if (mode == UNWIND_X86_MODE_STACK_IND &&1073function_info.valid_range_offset_start != 0) {1074uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding,1075UNWIND_X86_FRAMELESS_STACK_ADJUST);10761077// offset into the function instructions; 0 == beginning of first1078// instruction1079uint32_t offset_to_subl_insn =1080EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);10811082SectionList *sl = m_objfile.GetSectionList();1083if (sl) {1084ProcessSP process_sp = target.GetProcessSP();1085if (process_sp) {1086Address subl_payload_addr(function_info.valid_range_offset_start, sl);1087subl_payload_addr.Slide(offset_to_subl_insn);1088Status error;1089uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory(1090subl_payload_addr.GetLoadAddress(&target), 4, 0, error);1091if (large_stack_size != 0 && error.Success()) {1092// Got the large stack frame size correctly - use it1093stack_size = large_stack_size + (stack_adjust * wordsize);1094} else {1095return false;1096}1097} else {1098return false;1099}1100} else {1101return false;1102}1103}11041105int32_t offset =1106mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize;1107row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset);1108row->SetOffset(0);1109row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip,1110wordsize * -1, true);1111row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true);11121113if (register_count > 0) {11141115// We need to include (up to) 6 registers in 10 bits. That would be 181116// bits if we just used 3 bits per reg to indicate the order they're1117// saved on the stack.1118//1119// This is done with Lehmer code permutation, e.g. see1120// http://stackoverflow.com/questions/1506078/fast-permutation-number-1121// permutation-mapping-algorithms1122int permunreg[6] = {0, 0, 0, 0, 0, 0};11231124// This decodes the variable-base number in the 10 bits and gives us the1125// Lehmer code sequence which can then be decoded.11261127switch (register_count) {1128case 6:1129permunreg[0] = permutation / 120; // 120 == 5!1130permutation -= (permunreg[0] * 120);1131permunreg[1] = permutation / 24; // 24 == 4!1132permutation -= (permunreg[1] * 24);1133permunreg[2] = permutation / 6; // 6 == 3!1134permutation -= (permunreg[2] * 6);1135permunreg[3] = permutation / 2; // 2 == 2!1136permutation -= (permunreg[3] * 2);1137permunreg[4] = permutation; // 1 == 1!1138permunreg[5] = 0;1139break;1140case 5:1141permunreg[0] = permutation / 120;1142permutation -= (permunreg[0] * 120);1143permunreg[1] = permutation / 24;1144permutation -= (permunreg[1] * 24);1145permunreg[2] = permutation / 6;1146permutation -= (permunreg[2] * 6);1147permunreg[3] = permutation / 2;1148permutation -= (permunreg[3] * 2);1149permunreg[4] = permutation;1150break;1151case 4:1152permunreg[0] = permutation / 60;1153permutation -= (permunreg[0] * 60);1154permunreg[1] = permutation / 12;1155permutation -= (permunreg[1] * 12);1156permunreg[2] = permutation / 3;1157permutation -= (permunreg[2] * 3);1158permunreg[3] = permutation;1159break;1160case 3:1161permunreg[0] = permutation / 20;1162permutation -= (permunreg[0] * 20);1163permunreg[1] = permutation / 4;1164permutation -= (permunreg[1] * 4);1165permunreg[2] = permutation;1166break;1167case 2:1168permunreg[0] = permutation / 5;1169permutation -= (permunreg[0] * 5);1170permunreg[1] = permutation;1171break;1172case 1:1173permunreg[0] = permutation;1174break;1175}11761177// Decode the Lehmer code for this permutation of the registers v.1178// http://en.wikipedia.org/wiki/Lehmer_code11791180int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,1181UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE,1182UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE};1183bool used[7] = {false, false, false, false, false, false, false};1184for (uint32_t i = 0; i < register_count; i++) {1185int renum = 0;1186for (int j = 1; j < 7; j++) {1187if (!used[j]) {1188if (renum == permunreg[i]) {1189registers[i] = j;1190used[j] = true;1191break;1192}1193renum++;1194}1195}1196}11971198uint32_t saved_registers_offset = 1;1199saved_registers_offset++;12001201for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) {1202switch (registers[i]) {1203case UNWIND_X86_REG_NONE:1204break;1205case UNWIND_X86_REG_EBX:1206case UNWIND_X86_REG_ECX:1207case UNWIND_X86_REG_EDX:1208case UNWIND_X86_REG_EDI:1209case UNWIND_X86_REG_ESI:1210case UNWIND_X86_REG_EBP:1211row->SetRegisterLocationToAtCFAPlusOffset(1212translate_to_eh_frame_regnum_i386(registers[i]),1213wordsize * -saved_registers_offset, true);1214saved_registers_offset++;1215break;1216}1217}1218}12191220unwind_plan.AppendRow(row);1221return true;1222} break;12231224case UNWIND_X86_MODE_DWARF: {1225return false;1226} break;1227}1228return false;1229}12301231// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)"1232// doc by ARM12331234enum arm64_eh_regnum {1235x19 = 19,1236x20 = 20,1237x21 = 21,1238x22 = 22,1239x23 = 23,1240x24 = 24,1241x25 = 25,1242x26 = 26,1243x27 = 27,1244x28 = 28,12451246fp = 29,1247ra = 30,1248sp = 31,1249pc = 32,12501251// Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s1252// for the 64-bit fp regs. Normally in DWARF it's context sensitive - so it1253// knows it is fetching a 32- or 64-bit quantity from reg v8 to indicate s01254// or d0 - but the unwinder is operating at a lower level and we'd try to1255// fetch 128 bits if we were told that v8 were stored on the stack...1256v8 = 72,1257v9 = 73,1258v10 = 74,1259v11 = 75,1260v12 = 76,1261v13 = 77,1262v14 = 78,1263v15 = 79,1264};12651266enum arm_eh_regnum {1267arm_r0 = 0,1268arm_r1 = 1,1269arm_r2 = 2,1270arm_r3 = 3,1271arm_r4 = 4,1272arm_r5 = 5,1273arm_r6 = 6,1274arm_r7 = 7,1275arm_r8 = 8,1276arm_r9 = 9,1277arm_r10 = 10,1278arm_r11 = 11,1279arm_r12 = 12,12801281arm_sp = 13,1282arm_lr = 14,1283arm_pc = 15,12841285arm_d0 = 256,1286arm_d1 = 257,1287arm_d2 = 258,1288arm_d3 = 259,1289arm_d4 = 260,1290arm_d5 = 261,1291arm_d6 = 262,1292arm_d7 = 263,1293arm_d8 = 264,1294arm_d9 = 265,1295arm_d10 = 266,1296arm_d11 = 267,1297arm_d12 = 268,1298arm_d13 = 269,1299arm_d14 = 270,1300};13011302bool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,1303FunctionInfo &function_info,1304UnwindPlan &unwind_plan,1305Address pc_or_function_start) {1306unwind_plan.SetSourceName("compact unwind info");1307unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);1308unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);1309unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);1310unwind_plan.SetRegisterKind(eRegisterKindEHFrame);13111312unwind_plan.SetLSDAAddress(function_info.lsda_address);1313unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);13141315UnwindPlan::RowSP row(new UnwindPlan::Row);13161317const int wordsize = 8;1318int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK;13191320if (mode == UNWIND_ARM64_MODE_DWARF)1321return false;13221323if (mode == UNWIND_ARM64_MODE_FRAMELESS) {1324row->SetOffset(0);13251326uint32_t stack_size =1327(EXTRACT_BITS(function_info.encoding,1328UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) *132916;13301331// Our previous Call Frame Address is the stack pointer plus the stack size1332row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size);13331334// Our previous PC is in the LR1335row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra,1336true);13371338unwind_plan.AppendRow(row);1339return true;1340}13411342// Should not be possible1343if (mode != UNWIND_ARM64_MODE_FRAME)1344return false;13451346// mode == UNWIND_ARM64_MODE_FRAME13471348row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize);1349row->SetOffset(0);1350row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2,1351true);1352row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1,1353true);1354row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true);13551356int reg_pairs_saved_count = 1;13571358uint32_t saved_register_bits = function_info.encoding & 0xfff;13591360if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) {1361int cfa_offset = reg_pairs_saved_count * -2 * wordsize;1362cfa_offset -= wordsize;1363row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset,1364true);1365cfa_offset -= wordsize;1366row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset,1367true);1368reg_pairs_saved_count++;1369}13701371if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) {1372int cfa_offset = reg_pairs_saved_count * -2 * wordsize;1373cfa_offset -= wordsize;1374row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset,1375true);1376cfa_offset -= wordsize;1377row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset,1378true);1379reg_pairs_saved_count++;1380}13811382if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) {1383int cfa_offset = reg_pairs_saved_count * -2 * wordsize;1384cfa_offset -= wordsize;1385row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset,1386true);1387cfa_offset -= wordsize;1388row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset,1389true);1390reg_pairs_saved_count++;1391}13921393if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) {1394int cfa_offset = reg_pairs_saved_count * -2 * wordsize;1395cfa_offset -= wordsize;1396row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset,1397true);1398cfa_offset -= wordsize;1399row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset,1400true);1401reg_pairs_saved_count++;1402}14031404if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) {1405int cfa_offset = reg_pairs_saved_count * -2 * wordsize;1406cfa_offset -= wordsize;1407row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset,1408true);1409cfa_offset -= wordsize;1410row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset,1411true);1412reg_pairs_saved_count++;1413}14141415// If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits1416// off the stack;1417// not sure if we have a good way to represent the 64-bitness of these saves.14181419if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) {1420reg_pairs_saved_count++;1421}1422if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) {1423reg_pairs_saved_count++;1424}1425if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) {1426reg_pairs_saved_count++;1427}1428if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) {1429reg_pairs_saved_count++;1430}14311432unwind_plan.AppendRow(row);1433return true;1434}14351436bool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,1437FunctionInfo &function_info,1438UnwindPlan &unwind_plan,1439Address pc_or_function_start) {1440unwind_plan.SetSourceName("compact unwind info");1441unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);1442unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);1443unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);1444unwind_plan.SetRegisterKind(eRegisterKindEHFrame);14451446unwind_plan.SetLSDAAddress(function_info.lsda_address);1447unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);14481449UnwindPlan::RowSP row(new UnwindPlan::Row);14501451const int wordsize = 4;1452int mode = function_info.encoding & UNWIND_ARM_MODE_MASK;14531454if (mode == UNWIND_ARM_MODE_DWARF)1455return false;14561457uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding,1458UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) *1459wordsize;14601461row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7,1462(2 * wordsize) + stack_adjust);1463row->SetOffset(0);1464row->SetRegisterLocationToAtCFAPlusOffset(1465arm_r7, (wordsize * -2) - stack_adjust, true);1466row->SetRegisterLocationToAtCFAPlusOffset(1467arm_pc, (wordsize * -1) - stack_adjust, true);1468row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true);14691470int cfa_offset = -stack_adjust - (2 * wordsize);14711472uint32_t saved_register_bits = function_info.encoding & 0xff;14731474if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) {1475cfa_offset -= wordsize;1476row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true);1477}14781479if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) {1480cfa_offset -= wordsize;1481row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true);1482}14831484if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) {1485cfa_offset -= wordsize;1486row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true);1487}14881489if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) {1490cfa_offset -= wordsize;1491row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true);1492}14931494if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) {1495cfa_offset -= wordsize;1496row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true);1497}14981499if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) {1500cfa_offset -= wordsize;1501row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true);1502}15031504if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) {1505cfa_offset -= wordsize;1506row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true);1507}15081509if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) {1510cfa_offset -= wordsize;1511row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true);1512}15131514if (mode == UNWIND_ARM_MODE_FRAME_D) {1515uint32_t d_reg_bits =1516EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK);1517switch (d_reg_bits) {1518case 0:1519// vpush {d8}1520cfa_offset -= 8;1521row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);1522break;1523case 1:1524// vpush {d10}1525// vpush {d8}1526cfa_offset -= 8;1527row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);1528cfa_offset -= 8;1529row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);1530break;1531case 2:1532// vpush {d12}1533// vpush {d10}1534// vpush {d8}1535cfa_offset -= 8;1536row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);1537cfa_offset -= 8;1538row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);1539cfa_offset -= 8;1540row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);1541break;1542case 3:1543// vpush {d14}1544// vpush {d12}1545// vpush {d10}1546// vpush {d8}1547cfa_offset -= 8;1548row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);1549cfa_offset -= 8;1550row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);1551cfa_offset -= 8;1552row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true);1553cfa_offset -= 8;1554row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true);1555break;1556case 4:1557// vpush {d14}1558// vpush {d12}1559// sp = (sp - 24) & (-16);1560// vst {d8, d9, d10}1561cfa_offset -= 8;1562row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);1563cfa_offset -= 8;1564row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true);15651566// FIXME we don't have a way to represent reg saves at an specific1567// alignment short of1568// coming up with some DWARF location description.15691570break;1571case 5:1572// vpush {d14}1573// sp = (sp - 40) & (-16);1574// vst {d8, d9, d10, d11}1575// vst {d12}15761577cfa_offset -= 8;1578row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true);15791580// FIXME we don't have a way to represent reg saves at an specific1581// alignment short of1582// coming up with some DWARF location description.15831584break;1585case 6:1586// sp = (sp - 56) & (-16);1587// vst {d8, d9, d10, d11}1588// vst {d12, d13, d14}15891590// FIXME we don't have a way to represent reg saves at an specific1591// alignment short of1592// coming up with some DWARF location description.15931594break;1595case 7:1596// sp = (sp - 64) & (-16);1597// vst {d8, d9, d10, d11}1598// vst {d12, d13, d14, d15}15991600// FIXME we don't have a way to represent reg saves at an specific1601// alignment short of1602// coming up with some DWARF location description.16031604break;1605}1606}16071608unwind_plan.AppendRow(row);1609return true;1610}161116121613