CompactUnwindInfo.cpp revision 353358
1278332Semaste//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===// 2278332Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6278332Semaste// 7278332Semaste//===----------------------------------------------------------------------===// 8278332Semaste 9327952Sdim#include "lldb/Symbol/CompactUnwindInfo.h" 10278332Semaste#include "lldb/Core/Module.h" 11278332Semaste#include "lldb/Core/Section.h" 12278332Semaste#include "lldb/Symbol/ObjectFile.h" 13278332Semaste#include "lldb/Symbol/UnwindPlan.h" 14278332Semaste#include "lldb/Target/Process.h" 15278332Semaste#include "lldb/Target/Target.h" 16327952Sdim#include "lldb/Utility/ArchSpec.h" 17321369Sdim#include "lldb/Utility/DataBufferHeap.h" 18321369Sdim#include "lldb/Utility/Log.h" 19321369Sdim#include "lldb/Utility/StreamString.h" 20278332Semaste 21278332Semaste#include "llvm/Support/MathExtras.h" 22278332Semaste 23353358Sdim#include <algorithm> 24353358Sdim#include <memory> 25353358Sdim 26278332Semasteusing namespace lldb; 27278332Semasteusing namespace lldb_private; 28278332Semaste 29278332Semastenamespace lldb_private { 30278332Semaste 31314564Sdim// Constants from <mach-o/compact_unwind_encoding.h> 32278332Semaste 33314564SdimFLAGS_ANONYMOUS_ENUM(){ 34314564Sdim UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000, 35314564Sdim UNWIND_PERSONALITY_MASK = 0x30000000, 36314564Sdim}; 37278332Semaste 38314564SdimFLAGS_ANONYMOUS_ENUM(){ 39314564Sdim UNWIND_X86_MODE_MASK = 0x0F000000, 40314564Sdim UNWIND_X86_MODE_EBP_FRAME = 0x01000000, 41314564Sdim UNWIND_X86_MODE_STACK_IMMD = 0x02000000, 42314564Sdim UNWIND_X86_MODE_STACK_IND = 0x03000000, 43314564Sdim UNWIND_X86_MODE_DWARF = 0x04000000, 44278332Semaste 45314564Sdim UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, 46314564Sdim UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, 47278332Semaste 48314564Sdim UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, 49314564Sdim UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, 50314564Sdim UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 51314564Sdim UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 52278332Semaste 53314564Sdim UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, 54314564Sdim}; 55278332Semaste 56314564Sdimenum { 57314564Sdim UNWIND_X86_REG_NONE = 0, 58314564Sdim UNWIND_X86_REG_EBX = 1, 59314564Sdim UNWIND_X86_REG_ECX = 2, 60314564Sdim UNWIND_X86_REG_EDX = 3, 61314564Sdim UNWIND_X86_REG_EDI = 4, 62314564Sdim UNWIND_X86_REG_ESI = 5, 63314564Sdim UNWIND_X86_REG_EBP = 6, 64314564Sdim}; 65288943Sdim 66314564SdimFLAGS_ANONYMOUS_ENUM(){ 67314564Sdim UNWIND_X86_64_MODE_MASK = 0x0F000000, 68314564Sdim UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000, 69314564Sdim UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, 70314564Sdim UNWIND_X86_64_MODE_STACK_IND = 0x03000000, 71314564Sdim UNWIND_X86_64_MODE_DWARF = 0x04000000, 72278332Semaste 73314564Sdim UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, 74314564Sdim UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, 75278332Semaste 76314564Sdim UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000, 77314564Sdim UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000, 78314564Sdim UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 79314564Sdim UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 80278332Semaste 81314564Sdim UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 82314564Sdim}; 83278332Semaste 84314564Sdimenum { 85314564Sdim UNWIND_X86_64_REG_NONE = 0, 86314564Sdim UNWIND_X86_64_REG_RBX = 1, 87314564Sdim UNWIND_X86_64_REG_R12 = 2, 88314564Sdim UNWIND_X86_64_REG_R13 = 3, 89314564Sdim UNWIND_X86_64_REG_R14 = 4, 90314564Sdim UNWIND_X86_64_REG_R15 = 5, 91314564Sdim UNWIND_X86_64_REG_RBP = 6, 92314564Sdim}; 93309124Sdim 94314564SdimFLAGS_ANONYMOUS_ENUM(){ 95314564Sdim UNWIND_ARM64_MODE_MASK = 0x0F000000, 96314564Sdim UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, 97314564Sdim UNWIND_ARM64_MODE_DWARF = 0x03000000, 98314564Sdim UNWIND_ARM64_MODE_FRAME = 0x04000000, 99309124Sdim 100314564Sdim UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, 101314564Sdim UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, 102314564Sdim UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, 103314564Sdim UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, 104314564Sdim UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, 105314564Sdim UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, 106314564Sdim UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, 107314564Sdim UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, 108314564Sdim UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, 109309124Sdim 110314564Sdim UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, 111314564Sdim UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 112314564Sdim}; 113309124Sdim 114314564SdimFLAGS_ANONYMOUS_ENUM(){ 115314564Sdim UNWIND_ARM_MODE_MASK = 0x0F000000, 116314564Sdim UNWIND_ARM_MODE_FRAME = 0x01000000, 117314564Sdim UNWIND_ARM_MODE_FRAME_D = 0x02000000, 118314564Sdim UNWIND_ARM_MODE_DWARF = 0x04000000, 119309124Sdim 120314564Sdim UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000, 121309124Sdim 122314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001, 123314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002, 124314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004, 125309124Sdim 126314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008, 127314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010, 128314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020, 129314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040, 130314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080, 131309124Sdim 132314564Sdim UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700, 133309124Sdim 134314564Sdim UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF, 135314564Sdim}; 136288943Sdim} 137278332Semaste 138278332Semaste#ifndef UNWIND_SECOND_LEVEL_REGULAR 139278332Semaste#define UNWIND_SECOND_LEVEL_REGULAR 2 140278332Semaste#endif 141278332Semaste 142278332Semaste#ifndef UNWIND_SECOND_LEVEL_COMPRESSED 143278332Semaste#define UNWIND_SECOND_LEVEL_COMPRESSED 3 144278332Semaste#endif 145278332Semaste 146278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET 147314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF) 148278332Semaste#endif 149278332Semaste 150278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX 151314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \ 152314564Sdim ((entry >> 24) & 0xFF) 153278332Semaste#endif 154278332Semaste 155314564Sdim#define EXTRACT_BITS(value, mask) \ 156314564Sdim ((value >> \ 157314564Sdim llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \ 158314564Sdim (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1)) 159278332Semaste 160309124Sdim// constructor 161278332Semaste 162309124SdimCompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp) 163314564Sdim : m_objfile(objfile), m_section_sp(section_sp), 164314564Sdim m_section_contents_if_encrypted(), m_mutex(), m_indexes(), 165314564Sdim m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(), 166314564Sdim m_unwindinfo_data_computed(false), m_unwind_header() {} 167278332Semaste 168278332Semaste// destructor 169278332Semaste 170314564SdimCompactUnwindInfo::~CompactUnwindInfo() {} 171278332Semaste 172314564Sdimbool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr, 173314564Sdim UnwindPlan &unwind_plan) { 174314564Sdim if (!IsValid(target.GetProcessSP())) { 175314564Sdim return false; 176314564Sdim } 177314564Sdim FunctionInfo function_info; 178314564Sdim if (GetCompactUnwindInfoForFunction(target, addr, function_info)) { 179314564Sdim // shortcut return for functions that have no compact unwind 180314564Sdim if (function_info.encoding == 0) 181314564Sdim return false; 182278332Semaste 183344779Sdim if (ArchSpec arch = m_objfile.GetArchitecture()) { 184278332Semaste 185314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 186314564Sdim if (log && log->GetVerbose()) { 187314564Sdim StreamString strm; 188314564Sdim addr.Dump( 189353358Sdim &strm, nullptr, 190314564Sdim Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, 191314564Sdim Address::DumpStyle::DumpStyleFileAddress, 192314564Sdim arch.GetAddressByteSize()); 193314564Sdim log->Printf("Got compact unwind encoding 0x%x for function %s", 194314564Sdim function_info.encoding, strm.GetData()); 195314564Sdim } 196278332Semaste 197314564Sdim if (function_info.valid_range_offset_start != 0 && 198314564Sdim function_info.valid_range_offset_end != 0) { 199314564Sdim SectionList *sl = m_objfile.GetSectionList(); 200314564Sdim if (sl) { 201314564Sdim addr_t func_range_start_file_addr = 202314564Sdim function_info.valid_range_offset_start + 203344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 204314564Sdim AddressRange func_range(func_range_start_file_addr, 205314564Sdim function_info.valid_range_offset_end - 206314564Sdim function_info.valid_range_offset_start, 207314564Sdim sl); 208314564Sdim unwind_plan.SetPlanValidAddressRange(func_range); 209314564Sdim } 210314564Sdim } 211278332Semaste 212314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::x86_64) { 213314564Sdim return CreateUnwindPlan_x86_64(target, function_info, unwind_plan, 214314564Sdim addr); 215314564Sdim } 216314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::aarch64) { 217314564Sdim return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr); 218314564Sdim } 219314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::x86) { 220314564Sdim return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr); 221314564Sdim } 222314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::arm || 223314564Sdim arch.GetTriple().getArch() == llvm::Triple::thumb) { 224314564Sdim return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr); 225314564Sdim } 226278332Semaste } 227314564Sdim } 228314564Sdim return false; 229278332Semaste} 230278332Semaste 231314564Sdimbool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) { 232314564Sdim if (m_section_sp.get() == nullptr) 233314564Sdim return false; 234278332Semaste 235314564Sdim if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 236314564Sdim return true; 237278332Semaste 238314564Sdim ScanIndex(process_sp); 239278332Semaste 240314564Sdim return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed; 241278332Semaste} 242278332Semaste 243314564Sdimvoid CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) { 244314564Sdim std::lock_guard<std::mutex> guard(m_mutex); 245314564Sdim if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 246314564Sdim return; 247278332Semaste 248314564Sdim // We can't read the index for some reason. 249314564Sdim if (m_indexes_computed == eLazyBoolNo) { 250314564Sdim return; 251314564Sdim } 252278332Semaste 253314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 254314564Sdim if (log) 255314564Sdim m_objfile.GetModule()->LogMessage( 256314564Sdim log, "Reading compact unwind first-level indexes"); 257278332Semaste 258344779Sdim if (!m_unwindinfo_data_computed) { 259314564Sdim if (m_section_sp->IsEncrypted()) { 260314564Sdim // Can't get section contents of a protected/encrypted section until we 261341825Sdim // have a live process and can read them out of memory. 262314564Sdim if (process_sp.get() == nullptr) 263314564Sdim return; 264353358Sdim m_section_contents_if_encrypted = 265353358Sdim std::make_shared<DataBufferHeap>(m_section_sp->GetByteSize(), 0); 266321369Sdim Status error; 267314564Sdim if (process_sp->ReadMemory( 268314564Sdim m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()), 269314564Sdim m_section_contents_if_encrypted->GetBytes(), 270314564Sdim m_section_sp->GetByteSize(), 271314564Sdim error) == m_section_sp->GetByteSize() && 272314564Sdim error.Success()) { 273314564Sdim m_unwindinfo_data.SetAddressByteSize( 274314564Sdim process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); 275314564Sdim m_unwindinfo_data.SetByteOrder( 276314564Sdim process_sp->GetTarget().GetArchitecture().GetByteOrder()); 277314564Sdim m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0); 278314564Sdim } 279314564Sdim } else { 280314564Sdim m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data); 281278332Semaste } 282314564Sdim if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize()) 283314564Sdim return; 284314564Sdim m_unwindinfo_data_computed = true; 285314564Sdim } 286278332Semaste 287314564Sdim if (m_unwindinfo_data.GetByteSize() > 0) { 288314564Sdim offset_t offset = 0; 289278332Semaste 290314564Sdim // struct unwind_info_section_header 291314564Sdim // { 292314564Sdim // uint32_t version; // UNWIND_SECTION_VERSION 293314564Sdim // uint32_t commonEncodingsArraySectionOffset; 294314564Sdim // uint32_t commonEncodingsArrayCount; 295314564Sdim // uint32_t personalityArraySectionOffset; 296314564Sdim // uint32_t personalityArrayCount; 297314564Sdim // uint32_t indexSectionOffset; 298314564Sdim // uint32_t indexCount; 299309124Sdim 300314564Sdim m_unwind_header.version = m_unwindinfo_data.GetU32(&offset); 301314564Sdim m_unwind_header.common_encodings_array_offset = 302314564Sdim m_unwindinfo_data.GetU32(&offset); 303314564Sdim m_unwind_header.common_encodings_array_count = 304314564Sdim m_unwindinfo_data.GetU32(&offset); 305314564Sdim m_unwind_header.personality_array_offset = 306314564Sdim m_unwindinfo_data.GetU32(&offset); 307314564Sdim m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset); 308314564Sdim uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset); 309278332Semaste 310314564Sdim uint32_t indexCount = m_unwindinfo_data.GetU32(&offset); 311278332Semaste 312314564Sdim if (m_unwind_header.common_encodings_array_offset > 313314564Sdim m_unwindinfo_data.GetByteSize() || 314314564Sdim m_unwind_header.personality_array_offset > 315314564Sdim m_unwindinfo_data.GetByteSize() || 316314564Sdim indexSectionOffset > m_unwindinfo_data.GetByteSize() || 317314564Sdim offset > m_unwindinfo_data.GetByteSize()) { 318314564Sdim Host::SystemLog(Host::eSystemLogError, "error: Invalid offset " 319314564Sdim "encountered in compact unwind " 320314564Sdim "info, skipping\n"); 321314564Sdim // don't trust anything from this compact_unwind section if it looks 322314564Sdim // blatantly invalid data in the header. 323314564Sdim m_indexes_computed = eLazyBoolNo; 324314564Sdim return; 325314564Sdim } 326278332Semaste 327341825Sdim // Parse the basic information from the indexes We wait to scan the second 328341825Sdim // level page info until it's needed 329278332Semaste 330341825Sdim // struct unwind_info_section_header_index_entry { 331314564Sdim // uint32_t functionOffset; 332314564Sdim // uint32_t secondLevelPagesSectionOffset; 333314564Sdim // uint32_t lsdaIndexArraySectionOffset; 334314564Sdim // }; 335278332Semaste 336314564Sdim bool clear_address_zeroth_bit = false; 337344779Sdim if (ArchSpec arch = m_objfile.GetArchitecture()) { 338314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::arm || 339314564Sdim arch.GetTriple().getArch() == llvm::Triple::thumb) 340314564Sdim clear_address_zeroth_bit = true; 341314564Sdim } 342309124Sdim 343314564Sdim offset = indexSectionOffset; 344314564Sdim for (uint32_t idx = 0; idx < indexCount; idx++) { 345314564Sdim uint32_t function_offset = 346314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 347314564Sdim uint32_t second_level_offset = 348314564Sdim m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset 349314564Sdim uint32_t lsda_offset = 350314564Sdim m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset 351278332Semaste 352314564Sdim if (second_level_offset > m_section_sp->GetByteSize() || 353314564Sdim lsda_offset > m_section_sp->GetByteSize()) { 354314564Sdim m_indexes_computed = eLazyBoolNo; 355314564Sdim } 356278332Semaste 357314564Sdim if (clear_address_zeroth_bit) 358314564Sdim function_offset &= ~1ull; 359309124Sdim 360314564Sdim UnwindIndex this_index; 361314564Sdim this_index.function_offset = function_offset; 362314564Sdim this_index.second_level = second_level_offset; 363314564Sdim this_index.lsda_array_start = lsda_offset; 364278332Semaste 365314564Sdim if (m_indexes.size() > 0) { 366314564Sdim m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset; 367314564Sdim } 368278332Semaste 369314564Sdim if (second_level_offset == 0) { 370314564Sdim this_index.sentinal_entry = true; 371314564Sdim } 372278332Semaste 373314564Sdim m_indexes.push_back(this_index); 374278332Semaste } 375314564Sdim m_indexes_computed = eLazyBoolYes; 376314564Sdim } else { 377314564Sdim m_indexes_computed = eLazyBoolNo; 378314564Sdim } 379278332Semaste} 380278332Semaste 381314564Sdimuint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset, 382314564Sdim uint32_t lsda_count, 383314564Sdim uint32_t function_offset) { 384341825Sdim // struct unwind_info_section_header_lsda_index_entry { 385314564Sdim // uint32_t functionOffset; 386314564Sdim // uint32_t lsdaOffset; 387314564Sdim // }; 388278332Semaste 389314564Sdim offset_t first_entry = lsda_offset; 390314564Sdim uint32_t low = 0; 391314564Sdim uint32_t high = lsda_count; 392314564Sdim while (low < high) { 393314564Sdim uint32_t mid = (low + high) / 2; 394314564Sdim offset_t offset = first_entry + (mid * 8); 395314564Sdim uint32_t mid_func_offset = 396314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 397314564Sdim uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset 398314564Sdim if (mid_func_offset == function_offset) { 399314564Sdim return mid_lsda_offset; 400278332Semaste } 401314564Sdim if (mid_func_offset < function_offset) { 402314564Sdim low = mid + 1; 403314564Sdim } else { 404314564Sdim high = mid; 405314564Sdim } 406314564Sdim } 407314564Sdim return 0; 408278332Semaste} 409278332Semaste 410314564Sdimlldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage( 411314564Sdim uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, 412314564Sdim uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) { 413314564Sdim // typedef uint32_t compact_unwind_encoding_t; 414341825Sdim // struct unwind_info_regular_second_level_entry { 415314564Sdim // uint32_t functionOffset; 416314564Sdim // compact_unwind_encoding_t encoding; 417278332Semaste 418314564Sdim offset_t first_entry = entry_page_offset; 419278332Semaste 420314564Sdim uint32_t low = 0; 421314564Sdim uint32_t high = entry_count; 422314564Sdim uint32_t last = high - 1; 423314564Sdim while (low < high) { 424314564Sdim uint32_t mid = (low + high) / 2; 425314564Sdim offset_t offset = first_entry + (mid * 8); 426314564Sdim uint32_t mid_func_offset = 427314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 428314564Sdim uint32_t next_func_offset = 0; 429314564Sdim if (mid < last) { 430314564Sdim offset = first_entry + ((mid + 1) * 8); 431314564Sdim next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 432278332Semaste } 433314564Sdim if (mid_func_offset <= function_offset) { 434314564Sdim if (mid == last || (next_func_offset > function_offset)) { 435314564Sdim if (entry_func_start_offset) 436314564Sdim *entry_func_start_offset = mid_func_offset; 437314564Sdim if (mid != last && entry_func_end_offset) 438314564Sdim *entry_func_end_offset = next_func_offset; 439314564Sdim return first_entry + (mid * 8); 440314564Sdim } else { 441314564Sdim low = mid + 1; 442314564Sdim } 443314564Sdim } else { 444314564Sdim high = mid; 445314564Sdim } 446314564Sdim } 447314564Sdim return LLDB_INVALID_OFFSET; 448278332Semaste} 449278332Semaste 450314564Sdimuint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage( 451314564Sdim uint32_t entry_page_offset, uint32_t entry_count, 452314564Sdim uint32_t function_offset_to_find, uint32_t function_offset_base, 453314564Sdim uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) { 454314564Sdim offset_t first_entry = entry_page_offset; 455278332Semaste 456314564Sdim uint32_t low = 0; 457314564Sdim uint32_t high = entry_count; 458314564Sdim uint32_t last = high - 1; 459314564Sdim while (low < high) { 460314564Sdim uint32_t mid = (low + high) / 2; 461314564Sdim offset_t offset = first_entry + (mid * 4); 462314564Sdim uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry 463314564Sdim uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry); 464314564Sdim mid_func_offset += function_offset_base; 465314564Sdim uint32_t next_func_offset = 0; 466314564Sdim if (mid < last) { 467314564Sdim offset = first_entry + ((mid + 1) * 4); 468314564Sdim uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry 469314564Sdim next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry); 470314564Sdim next_func_offset += function_offset_base; 471278332Semaste } 472314564Sdim if (mid_func_offset <= function_offset_to_find) { 473314564Sdim if (mid == last || (next_func_offset > function_offset_to_find)) { 474314564Sdim if (entry_func_start_offset) 475314564Sdim *entry_func_start_offset = mid_func_offset; 476314564Sdim if (mid != last && entry_func_end_offset) 477314564Sdim *entry_func_end_offset = next_func_offset; 478314564Sdim return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry); 479314564Sdim } else { 480314564Sdim low = mid + 1; 481314564Sdim } 482314564Sdim } else { 483314564Sdim high = mid; 484314564Sdim } 485314564Sdim } 486278332Semaste 487314564Sdim return UINT32_MAX; 488278332Semaste} 489278332Semaste 490314564Sdimbool CompactUnwindInfo::GetCompactUnwindInfoForFunction( 491314564Sdim Target &target, Address address, FunctionInfo &unwind_info) { 492314564Sdim unwind_info.encoding = 0; 493314564Sdim unwind_info.lsda_address.Clear(); 494314564Sdim unwind_info.personality_ptr_address.Clear(); 495278332Semaste 496314564Sdim if (!IsValid(target.GetProcessSP())) 497314564Sdim return false; 498278332Semaste 499314564Sdim addr_t text_section_file_address = LLDB_INVALID_ADDRESS; 500314564Sdim SectionList *sl = m_objfile.GetSectionList(); 501314564Sdim if (sl) { 502314564Sdim SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true); 503314564Sdim if (text_sect.get()) { 504314564Sdim text_section_file_address = text_sect->GetFileAddress(); 505278332Semaste } 506314564Sdim } 507314564Sdim if (text_section_file_address == LLDB_INVALID_ADDRESS) 508314564Sdim return false; 509278332Semaste 510314564Sdim addr_t function_offset = 511344779Sdim address.GetFileAddress() - m_objfile.GetBaseAddress().GetFileAddress(); 512309124Sdim 513314564Sdim UnwindIndex key; 514314564Sdim key.function_offset = function_offset; 515309124Sdim 516314564Sdim std::vector<UnwindIndex>::const_iterator it; 517314564Sdim it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key); 518314564Sdim if (it == m_indexes.end()) { 519314564Sdim return false; 520314564Sdim } 521278332Semaste 522314564Sdim if (it->function_offset != key.function_offset) { 523314564Sdim if (it != m_indexes.begin()) 524314564Sdim --it; 525314564Sdim } 526278332Semaste 527344779Sdim if (it->sentinal_entry) { 528314564Sdim return false; 529314564Sdim } 530278332Semaste 531314564Sdim auto next_it = it + 1; 532314564Sdim if (next_it != m_indexes.end()) { 533341825Sdim // initialize the function offset end range to be the start of the next 534341825Sdim // index offset. If we find an entry which is at the end of the index 535341825Sdim // table, this will establish the range end. 536314564Sdim unwind_info.valid_range_offset_end = next_it->function_offset; 537314564Sdim } 538278332Semaste 539314564Sdim offset_t second_page_offset = it->second_level; 540314564Sdim offset_t lsda_array_start = it->lsda_array_start; 541314564Sdim offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8; 542278332Semaste 543314564Sdim offset_t offset = second_page_offset; 544314564Sdim uint32_t kind = m_unwindinfo_data.GetU32( 545314564Sdim &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED 546278332Semaste 547314564Sdim if (kind == UNWIND_SECOND_LEVEL_REGULAR) { 548341825Sdim // struct unwind_info_regular_second_level_page_header { 549314564Sdim // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR 550314564Sdim // uint16_t entryPageOffset; 551314564Sdim // uint16_t entryCount; 552278332Semaste 553314564Sdim // typedef uint32_t compact_unwind_encoding_t; 554341825Sdim // struct unwind_info_regular_second_level_entry { 555314564Sdim // uint32_t functionOffset; 556314564Sdim // compact_unwind_encoding_t encoding; 557278332Semaste 558314564Sdim uint16_t entry_page_offset = 559314564Sdim m_unwindinfo_data.GetU16(&offset); // entryPageOffset 560314564Sdim uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 561278332Semaste 562314564Sdim offset_t entry_offset = BinarySearchRegularSecondPage( 563314564Sdim second_page_offset + entry_page_offset, entry_count, function_offset, 564314564Sdim &unwind_info.valid_range_offset_start, 565314564Sdim &unwind_info.valid_range_offset_end); 566314564Sdim if (entry_offset == LLDB_INVALID_OFFSET) { 567314564Sdim return false; 568314564Sdim } 569314564Sdim entry_offset += 4; // skip over functionOffset 570314564Sdim unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding 571314564Sdim if (unwind_info.encoding & UNWIND_HAS_LSDA) { 572314564Sdim SectionList *sl = m_objfile.GetSectionList(); 573314564Sdim if (sl) { 574314564Sdim uint32_t lsda_offset = GetLSDAForFunctionOffset( 575314564Sdim lsda_array_start, lsda_array_count, function_offset); 576344779Sdim addr_t objfile_base_address = 577344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 578314564Sdim unwind_info.lsda_address.ResolveAddressUsingFileSections( 579344779Sdim objfile_base_address + lsda_offset, sl); 580314564Sdim } 581314564Sdim } 582314564Sdim if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) { 583314564Sdim uint32_t personality_index = 584314564Sdim EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK); 585278332Semaste 586314564Sdim if (personality_index > 0) { 587314564Sdim personality_index--; 588314564Sdim if (personality_index < m_unwind_header.personality_array_count) { 589314564Sdim offset_t offset = m_unwind_header.personality_array_offset; 590314564Sdim offset += 4 * personality_index; 591314564Sdim SectionList *sl = m_objfile.GetSectionList(); 592314564Sdim if (sl) { 593314564Sdim uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 594344779Sdim addr_t objfile_base_address = 595344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 596314564Sdim unwind_info.personality_ptr_address.ResolveAddressUsingFileSections( 597344779Sdim objfile_base_address + personality_offset, sl); 598314564Sdim } 599278332Semaste } 600314564Sdim } 601278332Semaste } 602314564Sdim return true; 603314564Sdim } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) { 604341825Sdim // struct unwind_info_compressed_second_level_page_header { 605314564Sdim // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED 606314564Sdim // uint16_t entryPageOffset; // offset from this 2nd lvl page 607314564Sdim // idx to array of entries 608314564Sdim // // (an entry has a function 609314564Sdim // offset and index into the 610314564Sdim // encodings) 611314564Sdim // // NB function offset from the 612314564Sdim // entry in the compressed page 613314564Sdim // // must be added to the index's 614314564Sdim // functionOffset value. 615314564Sdim // uint16_t entryCount; 616314564Sdim // uint16_t encodingsPageOffset; // offset from this 2nd lvl page 617314564Sdim // idx to array of encodings 618314564Sdim // uint16_t encodingsCount; 619278332Semaste 620314564Sdim uint16_t entry_page_offset = 621314564Sdim m_unwindinfo_data.GetU16(&offset); // entryPageOffset 622314564Sdim uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 623314564Sdim uint16_t encodings_page_offset = 624314564Sdim m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset 625314564Sdim uint16_t encodings_count = 626314564Sdim m_unwindinfo_data.GetU16(&offset); // encodingsCount 627278332Semaste 628314564Sdim uint32_t encoding_index = BinarySearchCompressedSecondPage( 629314564Sdim second_page_offset + entry_page_offset, entry_count, function_offset, 630314564Sdim it->function_offset, &unwind_info.valid_range_offset_start, 631314564Sdim &unwind_info.valid_range_offset_end); 632314564Sdim if (encoding_index == UINT32_MAX || 633314564Sdim encoding_index >= 634314564Sdim encodings_count + m_unwind_header.common_encodings_array_count) { 635314564Sdim return false; 636314564Sdim } 637314564Sdim uint32_t encoding = 0; 638314564Sdim if (encoding_index < m_unwind_header.common_encodings_array_count) { 639314564Sdim offset = m_unwind_header.common_encodings_array_offset + 640314564Sdim (encoding_index * sizeof(uint32_t)); 641314564Sdim encoding = m_unwindinfo_data.GetU32( 642314564Sdim &offset); // encoding entry from the commonEncodingsArray 643314564Sdim } else { 644314564Sdim uint32_t page_specific_entry_index = 645314564Sdim encoding_index - m_unwind_header.common_encodings_array_count; 646314564Sdim offset = second_page_offset + encodings_page_offset + 647314564Sdim (page_specific_entry_index * sizeof(uint32_t)); 648314564Sdim encoding = m_unwindinfo_data.GetU32( 649314564Sdim &offset); // encoding entry from the page-specific encoding array 650314564Sdim } 651314564Sdim if (encoding == 0) 652314564Sdim return false; 653278332Semaste 654314564Sdim unwind_info.encoding = encoding; 655314564Sdim if (unwind_info.encoding & UNWIND_HAS_LSDA) { 656314564Sdim SectionList *sl = m_objfile.GetSectionList(); 657314564Sdim if (sl) { 658314564Sdim uint32_t lsda_offset = GetLSDAForFunctionOffset( 659314564Sdim lsda_array_start, lsda_array_count, function_offset); 660344779Sdim addr_t objfile_base_address = 661344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 662314564Sdim unwind_info.lsda_address.ResolveAddressUsingFileSections( 663344779Sdim objfile_base_address + lsda_offset, sl); 664314564Sdim } 665314564Sdim } 666314564Sdim if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) { 667314564Sdim uint32_t personality_index = 668314564Sdim EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK); 669278332Semaste 670314564Sdim if (personality_index > 0) { 671314564Sdim personality_index--; 672314564Sdim if (personality_index < m_unwind_header.personality_array_count) { 673314564Sdim offset_t offset = m_unwind_header.personality_array_offset; 674314564Sdim offset += 4 * personality_index; 675314564Sdim SectionList *sl = m_objfile.GetSectionList(); 676314564Sdim if (sl) { 677314564Sdim uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 678344779Sdim addr_t objfile_base_address = 679344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 680314564Sdim unwind_info.personality_ptr_address.ResolveAddressUsingFileSections( 681344779Sdim objfile_base_address + personality_offset, sl); 682314564Sdim } 683278332Semaste } 684314564Sdim } 685278332Semaste } 686314564Sdim return true; 687314564Sdim } 688314564Sdim return false; 689278332Semaste} 690278332Semaste 691278332Semasteenum x86_64_eh_regnum { 692314564Sdim rax = 0, 693314564Sdim rdx = 1, 694314564Sdim rcx = 2, 695314564Sdim rbx = 3, 696314564Sdim rsi = 4, 697314564Sdim rdi = 5, 698314564Sdim rbp = 6, 699314564Sdim rsp = 7, 700314564Sdim r8 = 8, 701314564Sdim r9 = 9, 702314564Sdim r10 = 10, 703314564Sdim r11 = 11, 704314564Sdim r12 = 12, 705314564Sdim r13 = 13, 706314564Sdim r14 = 14, 707314564Sdim r15 = 15, 708314564Sdim rip = 16 // this is officially the Return Address register number, but close 709314564Sdim // enough 710278332Semaste}; 711278332Semaste 712341825Sdim// Convert the compact_unwind_info.h register numbering scheme to 713341825Sdim// eRegisterKindEHFrame (eh_frame) register numbering scheme. 714314564Sdimuint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) { 715314564Sdim switch (unwind_regno) { 716314564Sdim case UNWIND_X86_64_REG_RBX: 717314564Sdim return x86_64_eh_regnum::rbx; 718314564Sdim case UNWIND_X86_64_REG_R12: 719314564Sdim return x86_64_eh_regnum::r12; 720314564Sdim case UNWIND_X86_64_REG_R13: 721314564Sdim return x86_64_eh_regnum::r13; 722314564Sdim case UNWIND_X86_64_REG_R14: 723314564Sdim return x86_64_eh_regnum::r14; 724314564Sdim case UNWIND_X86_64_REG_R15: 725314564Sdim return x86_64_eh_regnum::r15; 726314564Sdim case UNWIND_X86_64_REG_RBP: 727314564Sdim return x86_64_eh_regnum::rbp; 728314564Sdim default: 729314564Sdim return LLDB_INVALID_REGNUM; 730314564Sdim } 731278332Semaste} 732278332Semaste 733314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target, 734314564Sdim FunctionInfo &function_info, 735314564Sdim UnwindPlan &unwind_plan, 736314564Sdim Address pc_or_function_start) { 737314564Sdim unwind_plan.SetSourceName("compact unwind info"); 738314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 739314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 740314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 741278332Semaste 742314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 743314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 744278332Semaste 745314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 746278332Semaste 747314564Sdim const int wordsize = 8; 748314564Sdim int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK; 749314564Sdim switch (mode) { 750314564Sdim case UNWIND_X86_64_MODE_RBP_FRAME: { 751314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset( 752314564Sdim translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP), 753314564Sdim 2 * wordsize); 754314564Sdim row->SetOffset(0); 755314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp, 756314564Sdim wordsize * -2, true); 757314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip, 758314564Sdim wordsize * -1, true); 759314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true); 760309124Sdim 761314564Sdim uint32_t saved_registers_offset = 762314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET); 763278332Semaste 764314564Sdim uint32_t saved_registers_locations = 765314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); 766278332Semaste 767314564Sdim saved_registers_offset += 2; 768278332Semaste 769314564Sdim for (int i = 0; i < 5; i++) { 770314564Sdim uint32_t regnum = saved_registers_locations & 0x7; 771314564Sdim switch (regnum) { 772314564Sdim case UNWIND_X86_64_REG_NONE: 773278332Semaste break; 774314564Sdim case UNWIND_X86_64_REG_RBX: 775314564Sdim case UNWIND_X86_64_REG_R12: 776314564Sdim case UNWIND_X86_64_REG_R13: 777314564Sdim case UNWIND_X86_64_REG_R14: 778314564Sdim case UNWIND_X86_64_REG_R15: 779314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 780314564Sdim translate_to_eh_frame_regnum_x86_64(regnum), 781314564Sdim wordsize * -saved_registers_offset, true); 782278332Semaste break; 783314564Sdim } 784314564Sdim saved_registers_offset--; 785314564Sdim saved_registers_locations >>= 3; 786314564Sdim } 787314564Sdim unwind_plan.AppendRow(row); 788314564Sdim return true; 789314564Sdim } break; 790278332Semaste 791314564Sdim case UNWIND_X86_64_MODE_STACK_IND: { 792314564Sdim // The clang in Xcode 6 is emitting incorrect compact unwind encodings for 793341825Sdim // this style of unwind. It was fixed in llvm r217020. The clang in Xcode 794341825Sdim // 7 has this fixed. 795314564Sdim return false; 796314564Sdim } break; 797278332Semaste 798314564Sdim case UNWIND_X86_64_MODE_STACK_IMMD: { 799314564Sdim uint32_t stack_size = EXTRACT_BITS(function_info.encoding, 800314564Sdim UNWIND_X86_64_FRAMELESS_STACK_SIZE); 801314564Sdim uint32_t register_count = EXTRACT_BITS( 802314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); 803314564Sdim uint32_t permutation = EXTRACT_BITS( 804314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); 805278332Semaste 806314564Sdim if (mode == UNWIND_X86_64_MODE_STACK_IND && 807314564Sdim function_info.valid_range_offset_start != 0) { 808314564Sdim uint32_t stack_adjust = EXTRACT_BITS( 809314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); 810278332Semaste 811314564Sdim // offset into the function instructions; 0 == beginning of first 812314564Sdim // instruction 813314564Sdim uint32_t offset_to_subl_insn = EXTRACT_BITS( 814314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 815278332Semaste 816314564Sdim SectionList *sl = m_objfile.GetSectionList(); 817314564Sdim if (sl) { 818314564Sdim ProcessSP process_sp = target.GetProcessSP(); 819314564Sdim if (process_sp) { 820314564Sdim Address subl_payload_addr(function_info.valid_range_offset_start, sl); 821314564Sdim subl_payload_addr.Slide(offset_to_subl_insn); 822321369Sdim Status error; 823314564Sdim uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory( 824314564Sdim subl_payload_addr.GetLoadAddress(&target), 4, 0, error); 825314564Sdim if (large_stack_size != 0 && error.Success()) { 826314564Sdim // Got the large stack frame size correctly - use it 827314564Sdim stack_size = large_stack_size + (stack_adjust * wordsize); 828314564Sdim } else { 829314564Sdim return false; 830314564Sdim } 831314564Sdim } else { 832314564Sdim return false; 833314564Sdim } 834314564Sdim } else { 835314564Sdim return false; 836314564Sdim } 837314564Sdim } 838288943Sdim 839314564Sdim int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND 840314564Sdim ? stack_size 841314564Sdim : stack_size * wordsize; 842314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset); 843278332Semaste 844314564Sdim row->SetOffset(0); 845314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip, 846314564Sdim wordsize * -1, true); 847314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true); 848278332Semaste 849314564Sdim if (register_count > 0) { 850278332Semaste 851341825Sdim // We need to include (up to) 6 registers in 10 bits. That would be 18 852341825Sdim // bits if we just used 3 bits per reg to indicate the order they're 853341825Sdim // saved on the stack. 854314564Sdim // 855314564Sdim // This is done with Lehmer code permutation, e.g. see 856341825Sdim // http://stackoverflow.com/questions/1506078/fast-permutation-number- 857341825Sdim // permutation-mapping-algorithms 858314564Sdim int permunreg[6] = {0, 0, 0, 0, 0, 0}; 859278332Semaste 860341825Sdim // This decodes the variable-base number in the 10 bits and gives us the 861341825Sdim // Lehmer code sequence which can then be decoded. 862309124Sdim 863314564Sdim switch (register_count) { 864314564Sdim case 6: 865314564Sdim permunreg[0] = permutation / 120; // 120 == 5! 866314564Sdim permutation -= (permunreg[0] * 120); 867314564Sdim permunreg[1] = permutation / 24; // 24 == 4! 868314564Sdim permutation -= (permunreg[1] * 24); 869314564Sdim permunreg[2] = permutation / 6; // 6 == 3! 870314564Sdim permutation -= (permunreg[2] * 6); 871314564Sdim permunreg[3] = permutation / 2; // 2 == 2! 872314564Sdim permutation -= (permunreg[3] * 2); 873314564Sdim permunreg[4] = permutation; // 1 == 1! 874314564Sdim permunreg[5] = 0; 875314564Sdim break; 876314564Sdim case 5: 877314564Sdim permunreg[0] = permutation / 120; 878314564Sdim permutation -= (permunreg[0] * 120); 879314564Sdim permunreg[1] = permutation / 24; 880314564Sdim permutation -= (permunreg[1] * 24); 881314564Sdim permunreg[2] = permutation / 6; 882314564Sdim permutation -= (permunreg[2] * 6); 883314564Sdim permunreg[3] = permutation / 2; 884314564Sdim permutation -= (permunreg[3] * 2); 885314564Sdim permunreg[4] = permutation; 886314564Sdim break; 887314564Sdim case 4: 888314564Sdim permunreg[0] = permutation / 60; 889314564Sdim permutation -= (permunreg[0] * 60); 890314564Sdim permunreg[1] = permutation / 12; 891314564Sdim permutation -= (permunreg[1] * 12); 892314564Sdim permunreg[2] = permutation / 3; 893314564Sdim permutation -= (permunreg[2] * 3); 894314564Sdim permunreg[3] = permutation; 895314564Sdim break; 896314564Sdim case 3: 897314564Sdim permunreg[0] = permutation / 20; 898314564Sdim permutation -= (permunreg[0] * 20); 899314564Sdim permunreg[1] = permutation / 4; 900314564Sdim permutation -= (permunreg[1] * 4); 901314564Sdim permunreg[2] = permutation; 902314564Sdim break; 903314564Sdim case 2: 904314564Sdim permunreg[0] = permutation / 5; 905314564Sdim permutation -= (permunreg[0] * 5); 906314564Sdim permunreg[1] = permutation; 907314564Sdim break; 908314564Sdim case 1: 909314564Sdim permunreg[0] = permutation; 910314564Sdim break; 911314564Sdim } 912278332Semaste 913341825Sdim // Decode the Lehmer code for this permutation of the registers v. 914341825Sdim // http://en.wikipedia.org/wiki/Lehmer_code 915278332Semaste 916314564Sdim int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, 917314564Sdim UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, 918314564Sdim UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE}; 919314564Sdim bool used[7] = {false, false, false, false, false, false, false}; 920314564Sdim for (uint32_t i = 0; i < register_count; i++) { 921314564Sdim int renum = 0; 922314564Sdim for (int j = 1; j < 7; j++) { 923344779Sdim if (!used[j]) { 924314564Sdim if (renum == permunreg[i]) { 925314564Sdim registers[i] = j; 926314564Sdim used[j] = true; 927314564Sdim break; 928278332Semaste } 929314564Sdim renum++; 930314564Sdim } 931278332Semaste } 932314564Sdim } 933278332Semaste 934314564Sdim uint32_t saved_registers_offset = 1; 935314564Sdim saved_registers_offset++; 936278332Semaste 937314564Sdim for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) { 938314564Sdim switch (registers[i]) { 939314564Sdim case UNWIND_X86_64_REG_NONE: 940314564Sdim break; 941314564Sdim case UNWIND_X86_64_REG_RBX: 942314564Sdim case UNWIND_X86_64_REG_R12: 943314564Sdim case UNWIND_X86_64_REG_R13: 944314564Sdim case UNWIND_X86_64_REG_R14: 945314564Sdim case UNWIND_X86_64_REG_R15: 946314564Sdim case UNWIND_X86_64_REG_RBP: 947314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 948314564Sdim translate_to_eh_frame_regnum_x86_64(registers[i]), 949314564Sdim wordsize * -saved_registers_offset, true); 950314564Sdim saved_registers_offset++; 951314564Sdim break; 952278332Semaste } 953314564Sdim } 954278332Semaste } 955314564Sdim unwind_plan.AppendRow(row); 956314564Sdim return true; 957314564Sdim } break; 958314564Sdim 959314564Sdim case UNWIND_X86_64_MODE_DWARF: { 960278332Semaste return false; 961314564Sdim } break; 962314564Sdim 963314564Sdim case 0: { 964314564Sdim return false; 965314564Sdim } break; 966314564Sdim } 967314564Sdim return false; 968278332Semaste} 969278332Semaste 970278332Semasteenum i386_eh_regnum { 971314564Sdim eax = 0, 972314564Sdim ecx = 1, 973314564Sdim edx = 2, 974314564Sdim ebx = 3, 975314564Sdim ebp = 4, 976314564Sdim esp = 5, 977314564Sdim esi = 6, 978314564Sdim edi = 7, 979314564Sdim eip = 8 // this is officially the Return Address register number, but close 980314564Sdim // enough 981278332Semaste}; 982278332Semaste 983341825Sdim// Convert the compact_unwind_info.h register numbering scheme to 984341825Sdim// eRegisterKindEHFrame (eh_frame) register numbering scheme. 985314564Sdimuint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) { 986314564Sdim switch (unwind_regno) { 987314564Sdim case UNWIND_X86_REG_EBX: 988314564Sdim return i386_eh_regnum::ebx; 989314564Sdim case UNWIND_X86_REG_ECX: 990314564Sdim return i386_eh_regnum::ecx; 991314564Sdim case UNWIND_X86_REG_EDX: 992314564Sdim return i386_eh_regnum::edx; 993314564Sdim case UNWIND_X86_REG_EDI: 994314564Sdim return i386_eh_regnum::edi; 995314564Sdim case UNWIND_X86_REG_ESI: 996314564Sdim return i386_eh_regnum::esi; 997314564Sdim case UNWIND_X86_REG_EBP: 998314564Sdim return i386_eh_regnum::ebp; 999314564Sdim default: 1000314564Sdim return LLDB_INVALID_REGNUM; 1001314564Sdim } 1002278332Semaste} 1003278332Semaste 1004314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target, 1005314564Sdim FunctionInfo &function_info, 1006314564Sdim UnwindPlan &unwind_plan, 1007314564Sdim Address pc_or_function_start) { 1008314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1009314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1010314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1011314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1012278332Semaste 1013314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1014314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1015278332Semaste 1016314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1017278332Semaste 1018314564Sdim const int wordsize = 4; 1019314564Sdim int mode = function_info.encoding & UNWIND_X86_MODE_MASK; 1020314564Sdim switch (mode) { 1021314564Sdim case UNWIND_X86_MODE_EBP_FRAME: { 1022314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset( 1023314564Sdim translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize); 1024314564Sdim row->SetOffset(0); 1025314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp, 1026314564Sdim wordsize * -2, true); 1027314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip, 1028314564Sdim wordsize * -1, true); 1029314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true); 1030278332Semaste 1031314564Sdim uint32_t saved_registers_offset = 1032314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET); 1033309124Sdim 1034314564Sdim uint32_t saved_registers_locations = 1035314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS); 1036278332Semaste 1037314564Sdim saved_registers_offset += 2; 1038278332Semaste 1039314564Sdim for (int i = 0; i < 5; i++) { 1040314564Sdim uint32_t regnum = saved_registers_locations & 0x7; 1041314564Sdim switch (regnum) { 1042314564Sdim case UNWIND_X86_REG_NONE: 1043278332Semaste break; 1044314564Sdim case UNWIND_X86_REG_EBX: 1045314564Sdim case UNWIND_X86_REG_ECX: 1046314564Sdim case UNWIND_X86_REG_EDX: 1047314564Sdim case UNWIND_X86_REG_EDI: 1048314564Sdim case UNWIND_X86_REG_ESI: 1049314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1050314564Sdim translate_to_eh_frame_regnum_i386(regnum), 1051314564Sdim wordsize * -saved_registers_offset, true); 1052314564Sdim break; 1053314564Sdim } 1054314564Sdim saved_registers_offset--; 1055314564Sdim saved_registers_locations >>= 3; 1056314564Sdim } 1057314564Sdim unwind_plan.AppendRow(row); 1058314564Sdim return true; 1059314564Sdim } break; 1060278332Semaste 1061314564Sdim case UNWIND_X86_MODE_STACK_IND: 1062314564Sdim case UNWIND_X86_MODE_STACK_IMMD: { 1063314564Sdim uint32_t stack_size = 1064314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1065314564Sdim uint32_t register_count = EXTRACT_BITS( 1066314564Sdim function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); 1067314564Sdim uint32_t permutation = EXTRACT_BITS( 1068314564Sdim function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); 1069278332Semaste 1070314564Sdim if (mode == UNWIND_X86_MODE_STACK_IND && 1071314564Sdim function_info.valid_range_offset_start != 0) { 1072314564Sdim uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding, 1073314564Sdim UNWIND_X86_FRAMELESS_STACK_ADJUST); 1074278332Semaste 1075314564Sdim // offset into the function instructions; 0 == beginning of first 1076314564Sdim // instruction 1077314564Sdim uint32_t offset_to_subl_insn = 1078314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1079278332Semaste 1080314564Sdim SectionList *sl = m_objfile.GetSectionList(); 1081314564Sdim if (sl) { 1082314564Sdim ProcessSP process_sp = target.GetProcessSP(); 1083314564Sdim if (process_sp) { 1084314564Sdim Address subl_payload_addr(function_info.valid_range_offset_start, sl); 1085314564Sdim subl_payload_addr.Slide(offset_to_subl_insn); 1086321369Sdim Status error; 1087314564Sdim uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory( 1088314564Sdim subl_payload_addr.GetLoadAddress(&target), 4, 0, error); 1089314564Sdim if (large_stack_size != 0 && error.Success()) { 1090314564Sdim // Got the large stack frame size correctly - use it 1091314564Sdim stack_size = large_stack_size + (stack_adjust * wordsize); 1092314564Sdim } else { 1093314564Sdim return false; 1094314564Sdim } 1095314564Sdim } else { 1096314564Sdim return false; 1097314564Sdim } 1098314564Sdim } else { 1099314564Sdim return false; 1100314564Sdim } 1101314564Sdim } 1102278332Semaste 1103314564Sdim int32_t offset = 1104314564Sdim mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize; 1105314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset); 1106314564Sdim row->SetOffset(0); 1107314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip, 1108314564Sdim wordsize * -1, true); 1109314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true); 1110309124Sdim 1111314564Sdim if (register_count > 0) { 1112278332Semaste 1113341825Sdim // We need to include (up to) 6 registers in 10 bits. That would be 18 1114341825Sdim // bits if we just used 3 bits per reg to indicate the order they're 1115341825Sdim // saved on the stack. 1116314564Sdim // 1117314564Sdim // This is done with Lehmer code permutation, e.g. see 1118341825Sdim // http://stackoverflow.com/questions/1506078/fast-permutation-number- 1119341825Sdim // permutation-mapping-algorithms 1120314564Sdim int permunreg[6] = {0, 0, 0, 0, 0, 0}; 1121278332Semaste 1122341825Sdim // This decodes the variable-base number in the 10 bits and gives us the 1123341825Sdim // Lehmer code sequence which can then be decoded. 1124278332Semaste 1125314564Sdim switch (register_count) { 1126314564Sdim case 6: 1127314564Sdim permunreg[0] = permutation / 120; // 120 == 5! 1128314564Sdim permutation -= (permunreg[0] * 120); 1129314564Sdim permunreg[1] = permutation / 24; // 24 == 4! 1130314564Sdim permutation -= (permunreg[1] * 24); 1131314564Sdim permunreg[2] = permutation / 6; // 6 == 3! 1132314564Sdim permutation -= (permunreg[2] * 6); 1133314564Sdim permunreg[3] = permutation / 2; // 2 == 2! 1134314564Sdim permutation -= (permunreg[3] * 2); 1135314564Sdim permunreg[4] = permutation; // 1 == 1! 1136314564Sdim permunreg[5] = 0; 1137314564Sdim break; 1138314564Sdim case 5: 1139314564Sdim permunreg[0] = permutation / 120; 1140314564Sdim permutation -= (permunreg[0] * 120); 1141314564Sdim permunreg[1] = permutation / 24; 1142314564Sdim permutation -= (permunreg[1] * 24); 1143314564Sdim permunreg[2] = permutation / 6; 1144314564Sdim permutation -= (permunreg[2] * 6); 1145314564Sdim permunreg[3] = permutation / 2; 1146314564Sdim permutation -= (permunreg[3] * 2); 1147314564Sdim permunreg[4] = permutation; 1148314564Sdim break; 1149314564Sdim case 4: 1150314564Sdim permunreg[0] = permutation / 60; 1151314564Sdim permutation -= (permunreg[0] * 60); 1152314564Sdim permunreg[1] = permutation / 12; 1153314564Sdim permutation -= (permunreg[1] * 12); 1154314564Sdim permunreg[2] = permutation / 3; 1155314564Sdim permutation -= (permunreg[2] * 3); 1156314564Sdim permunreg[3] = permutation; 1157314564Sdim break; 1158314564Sdim case 3: 1159314564Sdim permunreg[0] = permutation / 20; 1160314564Sdim permutation -= (permunreg[0] * 20); 1161314564Sdim permunreg[1] = permutation / 4; 1162314564Sdim permutation -= (permunreg[1] * 4); 1163314564Sdim permunreg[2] = permutation; 1164314564Sdim break; 1165314564Sdim case 2: 1166314564Sdim permunreg[0] = permutation / 5; 1167314564Sdim permutation -= (permunreg[0] * 5); 1168314564Sdim permunreg[1] = permutation; 1169314564Sdim break; 1170314564Sdim case 1: 1171314564Sdim permunreg[0] = permutation; 1172314564Sdim break; 1173314564Sdim } 1174309124Sdim 1175341825Sdim // Decode the Lehmer code for this permutation of the registers v. 1176341825Sdim // http://en.wikipedia.org/wiki/Lehmer_code 1177278332Semaste 1178314564Sdim int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, 1179314564Sdim UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, 1180314564Sdim UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE}; 1181314564Sdim bool used[7] = {false, false, false, false, false, false, false}; 1182314564Sdim for (uint32_t i = 0; i < register_count; i++) { 1183314564Sdim int renum = 0; 1184314564Sdim for (int j = 1; j < 7; j++) { 1185344779Sdim if (!used[j]) { 1186314564Sdim if (renum == permunreg[i]) { 1187314564Sdim registers[i] = j; 1188314564Sdim used[j] = true; 1189314564Sdim break; 1190278332Semaste } 1191314564Sdim renum++; 1192314564Sdim } 1193278332Semaste } 1194314564Sdim } 1195278332Semaste 1196314564Sdim uint32_t saved_registers_offset = 1; 1197314564Sdim saved_registers_offset++; 1198314564Sdim 1199314564Sdim for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) { 1200314564Sdim switch (registers[i]) { 1201314564Sdim case UNWIND_X86_REG_NONE: 1202314564Sdim break; 1203314564Sdim case UNWIND_X86_REG_EBX: 1204314564Sdim case UNWIND_X86_REG_ECX: 1205314564Sdim case UNWIND_X86_REG_EDX: 1206314564Sdim case UNWIND_X86_REG_EDI: 1207314564Sdim case UNWIND_X86_REG_ESI: 1208314564Sdim case UNWIND_X86_REG_EBP: 1209314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1210314564Sdim translate_to_eh_frame_regnum_i386(registers[i]), 1211314564Sdim wordsize * -saved_registers_offset, true); 1212314564Sdim saved_registers_offset++; 1213314564Sdim break; 1214278332Semaste } 1215314564Sdim } 1216278332Semaste } 1217314564Sdim 1218314564Sdim unwind_plan.AppendRow(row); 1219314564Sdim return true; 1220314564Sdim } break; 1221314564Sdim 1222314564Sdim case UNWIND_X86_MODE_DWARF: { 1223278332Semaste return false; 1224314564Sdim } break; 1225314564Sdim } 1226314564Sdim return false; 1227278332Semaste} 1228309124Sdim 1229314564Sdim// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)" 1230314564Sdim// doc by ARM 1231309124Sdim 1232309124Sdimenum arm64_eh_regnum { 1233314564Sdim x19 = 19, 1234314564Sdim x20 = 20, 1235314564Sdim x21 = 21, 1236314564Sdim x22 = 22, 1237314564Sdim x23 = 23, 1238314564Sdim x24 = 24, 1239314564Sdim x25 = 25, 1240314564Sdim x26 = 26, 1241314564Sdim x27 = 27, 1242314564Sdim x28 = 28, 1243309124Sdim 1244314564Sdim fp = 29, 1245314564Sdim ra = 30, 1246314564Sdim sp = 31, 1247314564Sdim pc = 32, 1248309124Sdim 1249314564Sdim // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s 1250341825Sdim // for the 64-bit fp regs. Normally in DWARF it's context sensitive - so it 1251341825Sdim // knows it is fetching a 32- or 64-bit quantity from reg v8 to indicate s0 1252341825Sdim // or d0 - but the unwinder is operating at a lower level and we'd try to 1253341825Sdim // fetch 128 bits if we were told that v8 were stored on the stack... 1254314564Sdim v8 = 72, 1255314564Sdim v9 = 73, 1256314564Sdim v10 = 74, 1257314564Sdim v11 = 75, 1258314564Sdim v12 = 76, 1259314564Sdim v13 = 77, 1260314564Sdim v14 = 78, 1261314564Sdim v15 = 79, 1262309124Sdim}; 1263309124Sdim 1264309124Sdimenum arm_eh_regnum { 1265314564Sdim arm_r0 = 0, 1266314564Sdim arm_r1 = 1, 1267314564Sdim arm_r2 = 2, 1268314564Sdim arm_r3 = 3, 1269314564Sdim arm_r4 = 4, 1270314564Sdim arm_r5 = 5, 1271314564Sdim arm_r6 = 6, 1272314564Sdim arm_r7 = 7, 1273314564Sdim arm_r8 = 8, 1274314564Sdim arm_r9 = 9, 1275314564Sdim arm_r10 = 10, 1276314564Sdim arm_r11 = 11, 1277314564Sdim arm_r12 = 12, 1278309124Sdim 1279314564Sdim arm_sp = 13, 1280314564Sdim arm_lr = 14, 1281314564Sdim arm_pc = 15, 1282309124Sdim 1283314564Sdim arm_d0 = 256, 1284314564Sdim arm_d1 = 257, 1285314564Sdim arm_d2 = 258, 1286314564Sdim arm_d3 = 259, 1287314564Sdim arm_d4 = 260, 1288314564Sdim arm_d5 = 261, 1289314564Sdim arm_d6 = 262, 1290314564Sdim arm_d7 = 263, 1291314564Sdim arm_d8 = 264, 1292314564Sdim arm_d9 = 265, 1293314564Sdim arm_d10 = 266, 1294314564Sdim arm_d11 = 267, 1295314564Sdim arm_d12 = 268, 1296314564Sdim arm_d13 = 269, 1297314564Sdim arm_d14 = 270, 1298309124Sdim}; 1299309124Sdim 1300314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target, 1301314564Sdim FunctionInfo &function_info, 1302314564Sdim UnwindPlan &unwind_plan, 1303314564Sdim Address pc_or_function_start) { 1304314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1305314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1306314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1307314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1308309124Sdim 1309314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1310314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1311309124Sdim 1312314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1313309124Sdim 1314314564Sdim const int wordsize = 8; 1315314564Sdim int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK; 1316309124Sdim 1317314564Sdim if (mode == UNWIND_ARM64_MODE_DWARF) 1318314564Sdim return false; 1319309124Sdim 1320314564Sdim if (mode == UNWIND_ARM64_MODE_FRAMELESS) { 1321314564Sdim row->SetOffset(0); 1322309124Sdim 1323314564Sdim uint32_t stack_size = 1324314564Sdim (EXTRACT_BITS(function_info.encoding, 1325314564Sdim UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) * 1326314564Sdim 16; 1327309124Sdim 1328314564Sdim // Our previous Call Frame Address is the stack pointer plus the stack size 1329314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size); 1330309124Sdim 1331314564Sdim // Our previous PC is in the LR 1332314564Sdim row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra, 1333314564Sdim true); 1334309124Sdim 1335314564Sdim unwind_plan.AppendRow(row); 1336314564Sdim return true; 1337314564Sdim } 1338309124Sdim 1339314564Sdim // Should not be possible 1340314564Sdim if (mode != UNWIND_ARM64_MODE_FRAME) 1341314564Sdim return false; 1342309124Sdim 1343314564Sdim // mode == UNWIND_ARM64_MODE_FRAME 1344309124Sdim 1345314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize); 1346314564Sdim row->SetOffset(0); 1347314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2, 1348314564Sdim true); 1349314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1, 1350314564Sdim true); 1351314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true); 1352309124Sdim 1353314564Sdim int reg_pairs_saved_count = 1; 1354309124Sdim 1355314564Sdim uint32_t saved_register_bits = function_info.encoding & 0xfff; 1356309124Sdim 1357314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) { 1358314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1359314564Sdim cfa_offset -= wordsize; 1360314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset, 1361314564Sdim true); 1362314564Sdim cfa_offset -= wordsize; 1363314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset, 1364314564Sdim true); 1365314564Sdim reg_pairs_saved_count++; 1366314564Sdim } 1367309124Sdim 1368314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) { 1369314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1370314564Sdim cfa_offset -= wordsize; 1371314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset, 1372314564Sdim true); 1373314564Sdim cfa_offset -= wordsize; 1374314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset, 1375314564Sdim true); 1376314564Sdim reg_pairs_saved_count++; 1377314564Sdim } 1378309124Sdim 1379314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) { 1380314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1381314564Sdim cfa_offset -= wordsize; 1382314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset, 1383314564Sdim true); 1384314564Sdim cfa_offset -= wordsize; 1385314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset, 1386314564Sdim true); 1387314564Sdim reg_pairs_saved_count++; 1388314564Sdim } 1389309124Sdim 1390314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) { 1391314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1392314564Sdim cfa_offset -= wordsize; 1393314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset, 1394314564Sdim true); 1395314564Sdim cfa_offset -= wordsize; 1396314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset, 1397314564Sdim true); 1398314564Sdim reg_pairs_saved_count++; 1399314564Sdim } 1400309124Sdim 1401314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) { 1402314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1403314564Sdim cfa_offset -= wordsize; 1404314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset, 1405314564Sdim true); 1406314564Sdim cfa_offset -= wordsize; 1407314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset, 1408314564Sdim true); 1409314564Sdim reg_pairs_saved_count++; 1410314564Sdim } 1411309124Sdim 1412314564Sdim // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits 1413314564Sdim // off the stack; 1414314564Sdim // not sure if we have a good way to represent the 64-bitness of these saves. 1415309124Sdim 1416314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) { 1417314564Sdim reg_pairs_saved_count++; 1418314564Sdim } 1419314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) { 1420314564Sdim reg_pairs_saved_count++; 1421314564Sdim } 1422314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) { 1423314564Sdim reg_pairs_saved_count++; 1424314564Sdim } 1425314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) { 1426314564Sdim reg_pairs_saved_count++; 1427314564Sdim } 1428309124Sdim 1429314564Sdim unwind_plan.AppendRow(row); 1430314564Sdim return true; 1431309124Sdim} 1432309124Sdim 1433314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target, 1434314564Sdim FunctionInfo &function_info, 1435314564Sdim UnwindPlan &unwind_plan, 1436314564Sdim Address pc_or_function_start) { 1437314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1438314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1439314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1440314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1441309124Sdim 1442314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1443314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1444309124Sdim 1445314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1446309124Sdim 1447314564Sdim const int wordsize = 4; 1448314564Sdim int mode = function_info.encoding & UNWIND_ARM_MODE_MASK; 1449309124Sdim 1450314564Sdim if (mode == UNWIND_ARM_MODE_DWARF) 1451314564Sdim return false; 1452309124Sdim 1453314564Sdim uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding, 1454314564Sdim UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) * 1455314564Sdim wordsize; 1456309124Sdim 1457314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7, 1458314564Sdim (2 * wordsize) + stack_adjust); 1459314564Sdim row->SetOffset(0); 1460314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1461314564Sdim arm_r7, (wordsize * -2) - stack_adjust, true); 1462314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1463314564Sdim arm_pc, (wordsize * -1) - stack_adjust, true); 1464314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true); 1465309124Sdim 1466314564Sdim int cfa_offset = -stack_adjust - (2 * wordsize); 1467309124Sdim 1468314564Sdim uint32_t saved_register_bits = function_info.encoding & 0xff; 1469309124Sdim 1470314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) { 1471314564Sdim cfa_offset -= wordsize; 1472314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true); 1473314564Sdim } 1474309124Sdim 1475314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) { 1476314564Sdim cfa_offset -= wordsize; 1477314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true); 1478314564Sdim } 1479309124Sdim 1480314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) { 1481314564Sdim cfa_offset -= wordsize; 1482314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true); 1483314564Sdim } 1484309124Sdim 1485314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) { 1486314564Sdim cfa_offset -= wordsize; 1487314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true); 1488314564Sdim } 1489309124Sdim 1490314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) { 1491314564Sdim cfa_offset -= wordsize; 1492314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true); 1493314564Sdim } 1494309124Sdim 1495314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) { 1496314564Sdim cfa_offset -= wordsize; 1497314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true); 1498314564Sdim } 1499309124Sdim 1500314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) { 1501314564Sdim cfa_offset -= wordsize; 1502314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true); 1503314564Sdim } 1504309124Sdim 1505314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) { 1506314564Sdim cfa_offset -= wordsize; 1507314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true); 1508314564Sdim } 1509309124Sdim 1510314564Sdim if (mode == UNWIND_ARM_MODE_FRAME_D) { 1511314564Sdim uint32_t d_reg_bits = 1512314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK); 1513314564Sdim switch (d_reg_bits) { 1514314564Sdim case 0: 1515314564Sdim // vpush {d8} 1516314564Sdim cfa_offset -= 8; 1517314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1518314564Sdim break; 1519314564Sdim case 1: 1520314564Sdim // vpush {d10} 1521314564Sdim // vpush {d8} 1522314564Sdim cfa_offset -= 8; 1523314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1524314564Sdim cfa_offset -= 8; 1525314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1526314564Sdim break; 1527314564Sdim case 2: 1528314564Sdim // vpush {d12} 1529314564Sdim // vpush {d10} 1530314564Sdim // vpush {d8} 1531314564Sdim cfa_offset -= 8; 1532314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1533314564Sdim cfa_offset -= 8; 1534314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1535314564Sdim cfa_offset -= 8; 1536314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1537314564Sdim break; 1538314564Sdim case 3: 1539314564Sdim // vpush {d14} 1540314564Sdim // vpush {d12} 1541314564Sdim // vpush {d10} 1542314564Sdim // vpush {d8} 1543314564Sdim cfa_offset -= 8; 1544314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1545314564Sdim cfa_offset -= 8; 1546314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1547314564Sdim cfa_offset -= 8; 1548314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1549314564Sdim cfa_offset -= 8; 1550314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1551314564Sdim break; 1552314564Sdim case 4: 1553314564Sdim // vpush {d14} 1554314564Sdim // vpush {d12} 1555314564Sdim // sp = (sp - 24) & (-16); 1556314564Sdim // vst {d8, d9, d10} 1557314564Sdim cfa_offset -= 8; 1558314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1559314564Sdim cfa_offset -= 8; 1560314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1561309124Sdim 1562314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1563314564Sdim // alignment short of 1564314564Sdim // coming up with some DWARF location description. 1565309124Sdim 1566314564Sdim break; 1567314564Sdim case 5: 1568314564Sdim // vpush {d14} 1569314564Sdim // sp = (sp - 40) & (-16); 1570314564Sdim // vst {d8, d9, d10, d11} 1571314564Sdim // vst {d12} 1572309124Sdim 1573314564Sdim cfa_offset -= 8; 1574314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1575309124Sdim 1576314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1577314564Sdim // alignment short of 1578314564Sdim // coming up with some DWARF location description. 1579309124Sdim 1580314564Sdim break; 1581314564Sdim case 6: 1582314564Sdim // sp = (sp - 56) & (-16); 1583314564Sdim // vst {d8, d9, d10, d11} 1584314564Sdim // vst {d12, d13, d14} 1585309124Sdim 1586314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1587314564Sdim // alignment short of 1588314564Sdim // coming up with some DWARF location description. 1589309124Sdim 1590314564Sdim break; 1591314564Sdim case 7: 1592314564Sdim // sp = (sp - 64) & (-16); 1593314564Sdim // vst {d8, d9, d10, d11} 1594314564Sdim // vst {d12, d13, d14, d15} 1595309124Sdim 1596314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1597314564Sdim // alignment short of 1598314564Sdim // coming up with some DWARF location description. 1599309124Sdim 1600314564Sdim break; 1601309124Sdim } 1602314564Sdim } 1603309124Sdim 1604314564Sdim unwind_plan.AppendRow(row); 1605314564Sdim return true; 1606309124Sdim} 1607