CompactUnwindInfo.cpp revision 309124
1278332Semaste//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===// 2278332Semaste// 3278332Semaste// The LLVM Compiler Infrastructure 4278332Semaste// 5278332Semaste// This file is distributed under the University of Illinois Open Source 6278332Semaste// License. See LICENSE.TXT for details. 7278332Semaste// 8278332Semaste//===----------------------------------------------------------------------===// 9278332Semaste 10278332Semaste 11278332Semaste// C Includes 12278332Semaste// C++ Includes 13278332Semaste#include <algorithm> 14278332Semaste 15278332Semaste#include "lldb/Core/ArchSpec.h" 16288943Sdim#include "lldb/Core/DataBufferHeap.h" 17278332Semaste#include "lldb/Core/Log.h" 18278332Semaste#include "lldb/Core/Module.h" 19278332Semaste#include "lldb/Core/Section.h" 20278332Semaste#include "lldb/Core/Section.h" 21278332Semaste#include "lldb/Core/StreamString.h" 22278332Semaste#include "lldb/Symbol/CompactUnwindInfo.h" 23278332Semaste#include "lldb/Symbol/ObjectFile.h" 24278332Semaste#include "lldb/Symbol/UnwindPlan.h" 25278332Semaste#include "lldb/Target/Process.h" 26278332Semaste#include "lldb/Target/Target.h" 27278332Semaste 28278332Semaste#include "llvm/Support/MathExtras.h" 29278332Semaste 30278332Semasteusing namespace lldb; 31278332Semasteusing namespace lldb_private; 32278332Semaste 33278332Semaste 34278332Semastenamespace lldb_private { 35278332Semaste 36278332Semaste // Constants from <mach-o/compact_unwind_encoding.h> 37278332Semaste 38288943Sdim FLAGS_ANONYMOUS_ENUM() 39288943Sdim { 40278332Semaste UNWIND_IS_NOT_FUNCTION_START = 0x80000000, 41278332Semaste UNWIND_HAS_LSDA = 0x40000000, 42278332Semaste UNWIND_PERSONALITY_MASK = 0x30000000, 43278332Semaste }; 44278332Semaste 45288943Sdim FLAGS_ANONYMOUS_ENUM() 46288943Sdim { 47278332Semaste UNWIND_X86_MODE_MASK = 0x0F000000, 48278332Semaste UNWIND_X86_MODE_EBP_FRAME = 0x01000000, 49278332Semaste UNWIND_X86_MODE_STACK_IMMD = 0x02000000, 50278332Semaste UNWIND_X86_MODE_STACK_IND = 0x03000000, 51278332Semaste UNWIND_X86_MODE_DWARF = 0x04000000, 52278332Semaste 53278332Semaste UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, 54278332Semaste UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, 55278332Semaste 56278332Semaste UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, 57278332Semaste UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, 58278332Semaste UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 59278332Semaste UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 60278332Semaste 61278332Semaste UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, 62278332Semaste }; 63278332Semaste 64288943Sdim enum 65288943Sdim { 66278332Semaste UNWIND_X86_REG_NONE = 0, 67278332Semaste UNWIND_X86_REG_EBX = 1, 68278332Semaste UNWIND_X86_REG_ECX = 2, 69278332Semaste UNWIND_X86_REG_EDX = 3, 70278332Semaste UNWIND_X86_REG_EDI = 4, 71278332Semaste UNWIND_X86_REG_ESI = 5, 72278332Semaste UNWIND_X86_REG_EBP = 6, 73278332Semaste }; 74288943Sdim 75288943Sdim FLAGS_ANONYMOUS_ENUM() 76288943Sdim { 77278332Semaste UNWIND_X86_64_MODE_MASK = 0x0F000000, 78278332Semaste UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000, 79278332Semaste UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, 80278332Semaste UNWIND_X86_64_MODE_STACK_IND = 0x03000000, 81278332Semaste UNWIND_X86_64_MODE_DWARF = 0x04000000, 82278332Semaste 83278332Semaste UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, 84278332Semaste UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, 85278332Semaste 86278332Semaste UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000, 87278332Semaste UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000, 88278332Semaste UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 89278332Semaste UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 90278332Semaste 91278332Semaste UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 92278332Semaste }; 93278332Semaste 94288943Sdim enum 95288943Sdim { 96278332Semaste UNWIND_X86_64_REG_NONE = 0, 97278332Semaste UNWIND_X86_64_REG_RBX = 1, 98278332Semaste UNWIND_X86_64_REG_R12 = 2, 99278332Semaste UNWIND_X86_64_REG_R13 = 3, 100278332Semaste UNWIND_X86_64_REG_R14 = 4, 101278332Semaste UNWIND_X86_64_REG_R15 = 5, 102278332Semaste UNWIND_X86_64_REG_RBP = 6, 103278332Semaste }; 104309124Sdim 105309124Sdim FLAGS_ANONYMOUS_ENUM() 106309124Sdim { 107309124Sdim UNWIND_ARM64_MODE_MASK = 0x0F000000, 108309124Sdim UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, 109309124Sdim UNWIND_ARM64_MODE_DWARF = 0x03000000, 110309124Sdim UNWIND_ARM64_MODE_FRAME = 0x04000000, 111309124Sdim 112309124Sdim UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, 113309124Sdim UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, 114309124Sdim UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, 115309124Sdim UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, 116309124Sdim UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, 117309124Sdim UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, 118309124Sdim UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, 119309124Sdim UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, 120309124Sdim UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, 121309124Sdim 122309124Sdim UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, 123309124Sdim UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 124309124Sdim }; 125309124Sdim 126309124Sdim FLAGS_ANONYMOUS_ENUM() 127309124Sdim { 128309124Sdim UNWIND_ARM_MODE_MASK = 0x0F000000, 129309124Sdim UNWIND_ARM_MODE_FRAME = 0x01000000, 130309124Sdim UNWIND_ARM_MODE_FRAME_D = 0x02000000, 131309124Sdim UNWIND_ARM_MODE_DWARF = 0x04000000, 132309124Sdim 133309124Sdim UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000, 134309124Sdim 135309124Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001, 136309124Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002, 137309124Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004, 138309124Sdim 139309124Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008, 140309124Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010, 141309124Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020, 142309124Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040, 143309124Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080, 144309124Sdim 145309124Sdim UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700, 146309124Sdim 147309124Sdim UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF, 148309124Sdim }; 149309124Sdim 150288943Sdim} 151278332Semaste 152278332Semaste 153278332Semaste#ifndef UNWIND_SECOND_LEVEL_REGULAR 154278332Semaste#define UNWIND_SECOND_LEVEL_REGULAR 2 155278332Semaste#endif 156278332Semaste 157278332Semaste#ifndef UNWIND_SECOND_LEVEL_COMPRESSED 158278332Semaste#define UNWIND_SECOND_LEVEL_COMPRESSED 3 159278332Semaste#endif 160278332Semaste 161278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET 162278332Semaste#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF) 163278332Semaste#endif 164278332Semaste 165278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX 166278332Semaste#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF) 167278332Semaste#endif 168278332Semaste 169278332Semaste#define EXTRACT_BITS(value, mask) \ 170278332Semaste ( (value >> llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \ 171288943Sdim (((1 << llvm::countPopulation(static_cast<uint32_t>(mask))))-1) ) 172278332Semaste 173278332Semaste 174278332Semaste 175278332Semaste//---------------------- 176309124Sdim// constructor 177278332Semaste//---------------------- 178278332Semaste 179309124SdimCompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp) 180309124Sdim : m_objfile(objfile), 181309124Sdim m_section_sp(section_sp), 182309124Sdim m_section_contents_if_encrypted(), 183309124Sdim m_mutex(), 184309124Sdim m_indexes(), 185309124Sdim m_indexes_computed(eLazyBoolCalculate), 186309124Sdim m_unwindinfo_data(), 187309124Sdim m_unwindinfo_data_computed(false), 188309124Sdim m_unwind_header() 189278332Semaste{ 190278332Semaste} 191278332Semaste 192278332Semaste//---------------------- 193278332Semaste// destructor 194278332Semaste//---------------------- 195278332Semaste 196278332SemasteCompactUnwindInfo::~CompactUnwindInfo() 197278332Semaste{ 198278332Semaste} 199278332Semaste 200278332Semastebool 201278332SemasteCompactUnwindInfo::GetUnwindPlan (Target &target, Address addr, UnwindPlan& unwind_plan) 202278332Semaste{ 203278332Semaste if (!IsValid (target.GetProcessSP())) 204278332Semaste { 205278332Semaste return false; 206278332Semaste } 207278332Semaste FunctionInfo function_info; 208278332Semaste if (GetCompactUnwindInfoForFunction (target, addr, function_info)) 209278332Semaste { 210278332Semaste // shortcut return for functions that have no compact unwind 211278332Semaste if (function_info.encoding == 0) 212278332Semaste return false; 213278332Semaste 214278332Semaste ArchSpec arch; 215278332Semaste if (m_objfile.GetArchitecture (arch)) 216278332Semaste { 217278332Semaste 218278332Semaste Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 219278332Semaste if (log && log->GetVerbose()) 220278332Semaste { 221278332Semaste StreamString strm; 222309124Sdim addr.Dump (&strm, NULL, Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, Address::DumpStyle::DumpStyleFileAddress, arch.GetAddressByteSize()); 223278332Semaste log->Printf ("Got compact unwind encoding 0x%x for function %s", function_info.encoding, strm.GetData()); 224278332Semaste } 225278332Semaste 226278332Semaste if (function_info.valid_range_offset_start != 0 && function_info.valid_range_offset_end != 0) 227278332Semaste { 228278332Semaste SectionList *sl = m_objfile.GetSectionList (); 229278332Semaste if (sl) 230278332Semaste { 231309124Sdim addr_t func_range_start_file_addr = 232278332Semaste function_info.valid_range_offset_start + m_objfile.GetHeaderAddress().GetFileAddress(); 233278332Semaste AddressRange func_range (func_range_start_file_addr, 234278332Semaste function_info.valid_range_offset_end - function_info.valid_range_offset_start, 235278332Semaste sl); 236278332Semaste unwind_plan.SetPlanValidAddressRange (func_range); 237278332Semaste } 238278332Semaste } 239278332Semaste 240278332Semaste if (arch.GetTriple().getArch() == llvm::Triple::x86_64) 241278332Semaste { 242278332Semaste return CreateUnwindPlan_x86_64 (target, function_info, unwind_plan, addr); 243278332Semaste } 244309124Sdim if (arch.GetTriple().getArch() == llvm::Triple::aarch64) 245309124Sdim { 246309124Sdim return CreateUnwindPlan_arm64 (target, function_info, unwind_plan, addr); 247309124Sdim } 248278332Semaste if (arch.GetTriple().getArch() == llvm::Triple::x86) 249278332Semaste { 250278332Semaste return CreateUnwindPlan_i386 (target, function_info, unwind_plan, addr); 251278332Semaste } 252309124Sdim if (arch.GetTriple().getArch() == llvm::Triple::arm || arch.GetTriple().getArch() == llvm::Triple::thumb) 253309124Sdim { 254309124Sdim return CreateUnwindPlan_armv7 (target, function_info, unwind_plan, addr); 255309124Sdim } 256278332Semaste } 257278332Semaste } 258278332Semaste return false; 259278332Semaste} 260278332Semaste 261278332Semastebool 262278332SemasteCompactUnwindInfo::IsValid (const ProcessSP &process_sp) 263278332Semaste{ 264278332Semaste if (m_section_sp.get() == nullptr) 265278332Semaste return false; 266278332Semaste 267278332Semaste if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 268278332Semaste return true; 269278332Semaste 270278332Semaste ScanIndex (process_sp); 271278332Semaste 272278332Semaste return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed; 273278332Semaste} 274278332Semaste 275278332Semastevoid 276278332SemasteCompactUnwindInfo::ScanIndex (const ProcessSP &process_sp) 277278332Semaste{ 278309124Sdim std::lock_guard<std::mutex> guard(m_mutex); 279278332Semaste if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 280278332Semaste return; 281278332Semaste 282278332Semaste // We can't read the index for some reason. 283278332Semaste if (m_indexes_computed == eLazyBoolNo) 284278332Semaste { 285278332Semaste return; 286278332Semaste } 287278332Semaste 288278332Semaste Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND)); 289278332Semaste if (log) 290278332Semaste m_objfile.GetModule()->LogMessage(log, "Reading compact unwind first-level indexes"); 291278332Semaste 292278332Semaste if (m_unwindinfo_data_computed == false) 293278332Semaste { 294278332Semaste if (m_section_sp->IsEncrypted()) 295278332Semaste { 296278332Semaste // Can't get section contents of a protected/encrypted section until we have a live 297278332Semaste // process and can read them out of memory. 298278332Semaste if (process_sp.get() == nullptr) 299278332Semaste return; 300278332Semaste m_section_contents_if_encrypted.reset (new DataBufferHeap (m_section_sp->GetByteSize(), 0)); 301278332Semaste Error error; 302278332Semaste if (process_sp->ReadMemory ( 303309124Sdim m_section_sp->GetLoadBaseAddress (&process_sp->GetTarget()), 304309124Sdim m_section_contents_if_encrypted->GetBytes(), 305278332Semaste m_section_sp->GetByteSize(), error) == m_section_sp->GetByteSize() && error.Success()) 306278332Semaste { 307278332Semaste m_unwindinfo_data.SetAddressByteSize (process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); 308278332Semaste m_unwindinfo_data.SetByteOrder (process_sp->GetTarget().GetArchitecture().GetByteOrder()); 309278332Semaste m_unwindinfo_data.SetData (m_section_contents_if_encrypted, 0); 310278332Semaste } 311278332Semaste } 312278332Semaste else 313278332Semaste { 314278332Semaste m_objfile.ReadSectionData (m_section_sp.get(), m_unwindinfo_data); 315278332Semaste } 316278332Semaste if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize()) 317278332Semaste return; 318278332Semaste m_unwindinfo_data_computed = true; 319278332Semaste } 320278332Semaste 321278332Semaste if (m_unwindinfo_data.GetByteSize() > 0) 322278332Semaste { 323278332Semaste offset_t offset = 0; 324278332Semaste 325278332Semaste // struct unwind_info_section_header 326278332Semaste // { 327278332Semaste // uint32_t version; // UNWIND_SECTION_VERSION 328278332Semaste // uint32_t commonEncodingsArraySectionOffset; 329278332Semaste // uint32_t commonEncodingsArrayCount; 330278332Semaste // uint32_t personalityArraySectionOffset; 331278332Semaste // uint32_t personalityArrayCount; 332278332Semaste // uint32_t indexSectionOffset; 333278332Semaste // uint32_t indexCount; 334309124Sdim 335278332Semaste m_unwind_header.version = m_unwindinfo_data.GetU32(&offset); 336278332Semaste m_unwind_header.common_encodings_array_offset = m_unwindinfo_data.GetU32(&offset); 337278332Semaste m_unwind_header.common_encodings_array_count = m_unwindinfo_data.GetU32(&offset); 338278332Semaste m_unwind_header.personality_array_offset = m_unwindinfo_data.GetU32(&offset); 339278332Semaste m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset); 340278332Semaste uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset); 341278332Semaste 342278332Semaste uint32_t indexCount = m_unwindinfo_data.GetU32(&offset); 343278332Semaste 344288943Sdim if (m_unwind_header.common_encodings_array_offset > m_unwindinfo_data.GetByteSize() 345288943Sdim || m_unwind_header.personality_array_offset > m_unwindinfo_data.GetByteSize() 346288943Sdim || indexSectionOffset > m_unwindinfo_data.GetByteSize() 347288943Sdim || offset > m_unwindinfo_data.GetByteSize()) 348278332Semaste { 349288943Sdim Host::SystemLog (Host::eSystemLogError, 350288943Sdim "error: Invalid offset encountered in compact unwind info, skipping\n"); 351288943Sdim // don't trust anything from this compact_unwind section if it looks 352296417Sdim // blatantly invalid data in the header. 353278332Semaste m_indexes_computed = eLazyBoolNo; 354288943Sdim return; 355278332Semaste } 356278332Semaste 357278332Semaste // Parse the basic information from the indexes 358278332Semaste // We wait to scan the second level page info until it's needed 359278332Semaste 360309124Sdim // struct unwind_info_section_header_index_entry 361278332Semaste // { 362278332Semaste // uint32_t functionOffset; 363278332Semaste // uint32_t secondLevelPagesSectionOffset; 364278332Semaste // uint32_t lsdaIndexArraySectionOffset; 365278332Semaste // }; 366278332Semaste 367309124Sdim bool clear_address_zeroth_bit = false; 368309124Sdim ArchSpec arch; 369309124Sdim if (m_objfile.GetArchitecture (arch)) 370309124Sdim { 371309124Sdim if (arch.GetTriple().getArch() == llvm::Triple::arm || arch.GetTriple().getArch() == llvm::Triple::thumb) 372309124Sdim clear_address_zeroth_bit = true; 373309124Sdim } 374309124Sdim 375278332Semaste offset = indexSectionOffset; 376278332Semaste for (uint32_t idx = 0; idx < indexCount; idx++) 377278332Semaste { 378278332Semaste uint32_t function_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 379278332Semaste uint32_t second_level_offset = m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset 380278332Semaste uint32_t lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset 381278332Semaste 382278332Semaste if (second_level_offset > m_section_sp->GetByteSize() || lsda_offset > m_section_sp->GetByteSize()) 383278332Semaste { 384278332Semaste m_indexes_computed = eLazyBoolNo; 385278332Semaste } 386278332Semaste 387309124Sdim if (clear_address_zeroth_bit) 388309124Sdim function_offset &= ~1ull; 389309124Sdim 390278332Semaste UnwindIndex this_index; 391309124Sdim this_index.function_offset = function_offset; 392278332Semaste this_index.second_level = second_level_offset; 393278332Semaste this_index.lsda_array_start = lsda_offset; 394278332Semaste 395278332Semaste if (m_indexes.size() > 0) 396278332Semaste { 397278332Semaste m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset; 398278332Semaste } 399278332Semaste 400278332Semaste if (second_level_offset == 0) 401278332Semaste { 402278332Semaste this_index.sentinal_entry = true; 403278332Semaste } 404278332Semaste 405278332Semaste m_indexes.push_back (this_index); 406278332Semaste } 407278332Semaste m_indexes_computed = eLazyBoolYes; 408278332Semaste } 409278332Semaste else 410278332Semaste { 411278332Semaste m_indexes_computed = eLazyBoolNo; 412278332Semaste } 413278332Semaste} 414278332Semaste 415278332Semasteuint32_t 416278332SemasteCompactUnwindInfo::GetLSDAForFunctionOffset (uint32_t lsda_offset, uint32_t lsda_count, uint32_t function_offset) 417278332Semaste{ 418309124Sdim // struct unwind_info_section_header_lsda_index_entry 419278332Semaste // { 420278332Semaste // uint32_t functionOffset; 421278332Semaste // uint32_t lsdaOffset; 422278332Semaste // }; 423278332Semaste 424278332Semaste offset_t first_entry = lsda_offset; 425278332Semaste uint32_t low = 0; 426278332Semaste uint32_t high = lsda_count; 427278332Semaste while (low < high) 428278332Semaste { 429278332Semaste uint32_t mid = (low + high) / 2; 430278332Semaste offset_t offset = first_entry + (mid * 8); 431278332Semaste uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 432278332Semaste uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset 433278332Semaste if (mid_func_offset == function_offset) 434278332Semaste { 435278332Semaste return mid_lsda_offset; 436278332Semaste } 437278332Semaste if (mid_func_offset < function_offset) 438278332Semaste { 439278332Semaste low = mid + 1; 440278332Semaste } 441278332Semaste else 442278332Semaste { 443278332Semaste high = mid; 444278332Semaste } 445278332Semaste } 446278332Semaste return 0; 447278332Semaste} 448278332Semaste 449278332Semastelldb::offset_t 450278332SemasteCompactUnwindInfo::BinarySearchRegularSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) 451278332Semaste{ 452278332Semaste // typedef uint32_t compact_unwind_encoding_t; 453309124Sdim // struct unwind_info_regular_second_level_entry 454278332Semaste // { 455278332Semaste // uint32_t functionOffset; 456278332Semaste // compact_unwind_encoding_t encoding; 457278332Semaste 458278332Semaste offset_t first_entry = entry_page_offset; 459278332Semaste 460278332Semaste uint32_t low = 0; 461278332Semaste uint32_t high = entry_count; 462278332Semaste uint32_t last = high - 1; 463278332Semaste while (low < high) 464278332Semaste { 465278332Semaste uint32_t mid = (low + high) / 2; 466278332Semaste offset_t offset = first_entry + (mid * 8); 467278332Semaste uint32_t mid_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 468278332Semaste uint32_t next_func_offset = 0; 469278332Semaste if (mid < last) 470278332Semaste { 471278332Semaste offset = first_entry + ((mid + 1) * 8); 472278332Semaste next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 473278332Semaste } 474278332Semaste if (mid_func_offset <= function_offset) 475278332Semaste { 476278332Semaste if (mid == last || (next_func_offset > function_offset)) 477278332Semaste { 478278332Semaste if (entry_func_start_offset) 479278332Semaste *entry_func_start_offset = mid_func_offset; 480278332Semaste if (mid != last && entry_func_end_offset) 481278332Semaste *entry_func_end_offset = next_func_offset; 482278332Semaste return first_entry + (mid * 8); 483278332Semaste } 484278332Semaste else 485278332Semaste { 486278332Semaste low = mid + 1; 487278332Semaste } 488278332Semaste } 489278332Semaste else 490278332Semaste { 491278332Semaste high = mid; 492278332Semaste } 493278332Semaste } 494278332Semaste return LLDB_INVALID_OFFSET; 495278332Semaste} 496278332Semaste 497278332Semasteuint32_t 498278332SemasteCompactUnwindInfo::BinarySearchCompressedSecondPage (uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset_to_find, uint32_t function_offset_base, uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) 499278332Semaste{ 500278332Semaste offset_t first_entry = entry_page_offset; 501278332Semaste 502278332Semaste uint32_t low = 0; 503278332Semaste uint32_t high = entry_count; 504278332Semaste uint32_t last = high - 1; 505278332Semaste while (low < high) 506278332Semaste { 507278332Semaste uint32_t mid = (low + high) / 2; 508278332Semaste offset_t offset = first_entry + (mid * 4); 509278332Semaste uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry 510278332Semaste uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (entry); 511278332Semaste mid_func_offset += function_offset_base; 512278332Semaste uint32_t next_func_offset = 0; 513278332Semaste if (mid < last) 514278332Semaste { 515278332Semaste offset = first_entry + ((mid + 1) * 4); 516278332Semaste uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry 517278332Semaste next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET (next_entry); 518278332Semaste next_func_offset += function_offset_base; 519278332Semaste } 520278332Semaste if (mid_func_offset <= function_offset_to_find) 521278332Semaste { 522278332Semaste if (mid == last || (next_func_offset > function_offset_to_find)) 523278332Semaste { 524278332Semaste if (entry_func_start_offset) 525278332Semaste *entry_func_start_offset = mid_func_offset; 526278332Semaste if (mid != last && entry_func_end_offset) 527278332Semaste *entry_func_end_offset = next_func_offset; 528278332Semaste return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX (entry); 529278332Semaste } 530278332Semaste else 531278332Semaste { 532278332Semaste low = mid + 1; 533278332Semaste } 534278332Semaste } 535278332Semaste else 536278332Semaste { 537278332Semaste high = mid; 538278332Semaste } 539278332Semaste } 540278332Semaste 541278332Semaste return UINT32_MAX; 542278332Semaste} 543278332Semaste 544278332Semastebool 545278332SemasteCompactUnwindInfo::GetCompactUnwindInfoForFunction (Target &target, Address address, FunctionInfo &unwind_info) 546278332Semaste{ 547278332Semaste unwind_info.encoding = 0; 548278332Semaste unwind_info.lsda_address.Clear(); 549278332Semaste unwind_info.personality_ptr_address.Clear(); 550278332Semaste 551278332Semaste if (!IsValid (target.GetProcessSP())) 552278332Semaste return false; 553278332Semaste 554278332Semaste addr_t text_section_file_address = LLDB_INVALID_ADDRESS; 555278332Semaste SectionList *sl = m_objfile.GetSectionList (); 556278332Semaste if (sl) 557278332Semaste { 558278332Semaste SectionSP text_sect = sl->FindSectionByType (eSectionTypeCode, true); 559278332Semaste if (text_sect.get()) 560278332Semaste { 561278332Semaste text_section_file_address = text_sect->GetFileAddress(); 562278332Semaste } 563278332Semaste } 564278332Semaste if (text_section_file_address == LLDB_INVALID_ADDRESS) 565278332Semaste return false; 566278332Semaste 567278332Semaste addr_t function_offset = address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress(); 568309124Sdim 569278332Semaste UnwindIndex key; 570278332Semaste key.function_offset = function_offset; 571309124Sdim 572278332Semaste std::vector<UnwindIndex>::const_iterator it; 573278332Semaste it = std::lower_bound (m_indexes.begin(), m_indexes.end(), key); 574278332Semaste if (it == m_indexes.end()) 575278332Semaste { 576278332Semaste return false; 577278332Semaste } 578278332Semaste 579278332Semaste if (it->function_offset != key.function_offset) 580278332Semaste { 581278332Semaste if (it != m_indexes.begin()) 582278332Semaste --it; 583278332Semaste } 584278332Semaste 585278332Semaste if (it->sentinal_entry == true) 586278332Semaste { 587278332Semaste return false; 588278332Semaste } 589278332Semaste 590278332Semaste auto next_it = it + 1; 591288943Sdim if (next_it != m_indexes.end()) 592278332Semaste { 593309124Sdim // initialize the function offset end range to be the start of the 594278332Semaste // next index offset. If we find an entry which is at the end of 595278332Semaste // the index table, this will establish the range end. 596278332Semaste unwind_info.valid_range_offset_end = next_it->function_offset; 597278332Semaste } 598278332Semaste 599278332Semaste offset_t second_page_offset = it->second_level; 600278332Semaste offset_t lsda_array_start = it->lsda_array_start; 601278332Semaste offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8; 602278332Semaste 603278332Semaste offset_t offset = second_page_offset; 604278332Semaste uint32_t kind = m_unwindinfo_data.GetU32(&offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED 605278332Semaste 606278332Semaste if (kind == UNWIND_SECOND_LEVEL_REGULAR) 607278332Semaste { 608278332Semaste // struct unwind_info_regular_second_level_page_header 609278332Semaste // { 610278332Semaste // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR 611278332Semaste // uint16_t entryPageOffset; 612278332Semaste // uint16_t entryCount; 613278332Semaste 614278332Semaste // typedef uint32_t compact_unwind_encoding_t; 615309124Sdim // struct unwind_info_regular_second_level_entry 616278332Semaste // { 617278332Semaste // uint32_t functionOffset; 618278332Semaste // compact_unwind_encoding_t encoding; 619278332Semaste 620278332Semaste uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset 621278332Semaste uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 622278332Semaste 623278332Semaste offset_t entry_offset = BinarySearchRegularSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end); 624278332Semaste if (entry_offset == LLDB_INVALID_OFFSET) 625278332Semaste { 626278332Semaste return false; 627278332Semaste } 628278332Semaste entry_offset += 4; // skip over functionOffset 629278332Semaste unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding 630278332Semaste if (unwind_info.encoding & UNWIND_HAS_LSDA) 631278332Semaste { 632278332Semaste SectionList *sl = m_objfile.GetSectionList (); 633278332Semaste if (sl) 634278332Semaste { 635278332Semaste uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset); 636278332Semaste addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress(); 637278332Semaste unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl); 638278332Semaste } 639278332Semaste } 640278332Semaste if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) 641278332Semaste { 642278332Semaste uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK); 643278332Semaste 644278332Semaste if (personality_index > 0) 645278332Semaste { 646278332Semaste personality_index--; 647278332Semaste if (personality_index < m_unwind_header.personality_array_count) 648278332Semaste { 649278332Semaste offset_t offset = m_unwind_header.personality_array_offset; 650278332Semaste offset += 4 * personality_index; 651278332Semaste SectionList *sl = m_objfile.GetSectionList (); 652278332Semaste if (sl) 653278332Semaste { 654278332Semaste uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 655278332Semaste addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress(); 656278332Semaste unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl); 657278332Semaste } 658278332Semaste } 659278332Semaste } 660278332Semaste } 661278332Semaste return true; 662278332Semaste } 663278332Semaste else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) 664278332Semaste { 665278332Semaste // struct unwind_info_compressed_second_level_page_header 666278332Semaste // { 667278332Semaste // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED 668278332Semaste // uint16_t entryPageOffset; // offset from this 2nd lvl page idx to array of entries 669278332Semaste // // (an entry has a function offset and index into the encodings) 670309124Sdim // // NB function offset from the entry in the compressed page 671278332Semaste // // must be added to the index's functionOffset value. 672309124Sdim // uint16_t entryCount; 673278332Semaste // uint16_t encodingsPageOffset; // offset from this 2nd lvl page idx to array of encodings 674278332Semaste // uint16_t encodingsCount; 675278332Semaste 676278332Semaste uint16_t entry_page_offset = m_unwindinfo_data.GetU16(&offset); // entryPageOffset 677278332Semaste uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 678278332Semaste uint16_t encodings_page_offset = m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset 679278332Semaste uint16_t encodings_count = m_unwindinfo_data.GetU16(&offset); // encodingsCount 680278332Semaste 681278332Semaste uint32_t encoding_index = BinarySearchCompressedSecondPage (second_page_offset + entry_page_offset, entry_count, function_offset, it->function_offset, &unwind_info.valid_range_offset_start, &unwind_info.valid_range_offset_end); 682278332Semaste if (encoding_index == UINT32_MAX || encoding_index >= encodings_count + m_unwind_header.common_encodings_array_count) 683278332Semaste { 684278332Semaste return false; 685278332Semaste } 686278332Semaste uint32_t encoding = 0; 687278332Semaste if (encoding_index < m_unwind_header.common_encodings_array_count) 688278332Semaste { 689278332Semaste offset = m_unwind_header.common_encodings_array_offset + (encoding_index * sizeof (uint32_t)); 690278332Semaste encoding = m_unwindinfo_data.GetU32(&offset); // encoding entry from the commonEncodingsArray 691278332Semaste } 692309124Sdim else 693278332Semaste { 694278332Semaste uint32_t page_specific_entry_index = encoding_index - m_unwind_header.common_encodings_array_count; 695278332Semaste offset = second_page_offset + encodings_page_offset + (page_specific_entry_index * sizeof (uint32_t)); 696278332Semaste encoding = m_unwindinfo_data.GetU32(&offset); // encoding entry from the page-specific encoding array 697278332Semaste } 698278332Semaste if (encoding == 0) 699278332Semaste return false; 700278332Semaste 701278332Semaste unwind_info.encoding = encoding; 702278332Semaste if (unwind_info.encoding & UNWIND_HAS_LSDA) 703278332Semaste { 704278332Semaste SectionList *sl = m_objfile.GetSectionList (); 705278332Semaste if (sl) 706278332Semaste { 707278332Semaste uint32_t lsda_offset = GetLSDAForFunctionOffset (lsda_array_start, lsda_array_count, function_offset); 708278332Semaste addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress(); 709278332Semaste unwind_info.lsda_address.ResolveAddressUsingFileSections (objfile_header_file_address + lsda_offset, sl); 710278332Semaste } 711278332Semaste } 712278332Semaste if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) 713278332Semaste { 714278332Semaste uint32_t personality_index = EXTRACT_BITS (unwind_info.encoding, UNWIND_PERSONALITY_MASK); 715278332Semaste 716278332Semaste if (personality_index > 0) 717278332Semaste { 718278332Semaste personality_index--; 719278332Semaste if (personality_index < m_unwind_header.personality_array_count) 720278332Semaste { 721278332Semaste offset_t offset = m_unwind_header.personality_array_offset; 722278332Semaste offset += 4 * personality_index; 723278332Semaste SectionList *sl = m_objfile.GetSectionList (); 724278332Semaste if (sl) 725278332Semaste { 726278332Semaste uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 727278332Semaste addr_t objfile_header_file_address = m_objfile.GetHeaderAddress().GetFileAddress(); 728278332Semaste unwind_info.personality_ptr_address.ResolveAddressUsingFileSections (objfile_header_file_address + personality_offset, sl); 729278332Semaste } 730278332Semaste } 731278332Semaste } 732278332Semaste } 733278332Semaste return true; 734278332Semaste } 735278332Semaste return false; 736278332Semaste} 737278332Semaste 738278332Semasteenum x86_64_eh_regnum { 739278332Semaste rax = 0, 740278332Semaste rdx = 1, 741278332Semaste rcx = 2, 742278332Semaste rbx = 3, 743278332Semaste rsi = 4, 744278332Semaste rdi = 5, 745278332Semaste rbp = 6, 746278332Semaste rsp = 7, 747278332Semaste r8 = 8, 748278332Semaste r9 = 9, 749278332Semaste r10 = 10, 750278332Semaste r11 = 11, 751278332Semaste r12 = 12, 752278332Semaste r13 = 13, 753278332Semaste r14 = 14, 754278332Semaste r15 = 15, 755278332Semaste rip = 16 // this is officially the Return Address register number, but close enough 756278332Semaste}; 757278332Semaste 758278332Semaste// Convert the compact_unwind_info.h register numbering scheme 759296417Sdim// to eRegisterKindEHFrame (eh_frame) register numbering scheme. 760278332Semasteuint32_t 761278332Semastetranslate_to_eh_frame_regnum_x86_64 (uint32_t unwind_regno) 762278332Semaste{ 763278332Semaste switch (unwind_regno) 764278332Semaste { 765278332Semaste case UNWIND_X86_64_REG_RBX: 766278332Semaste return x86_64_eh_regnum::rbx; 767278332Semaste case UNWIND_X86_64_REG_R12: 768278332Semaste return x86_64_eh_regnum::r12; 769278332Semaste case UNWIND_X86_64_REG_R13: 770278332Semaste return x86_64_eh_regnum::r13; 771278332Semaste case UNWIND_X86_64_REG_R14: 772278332Semaste return x86_64_eh_regnum::r14; 773278332Semaste case UNWIND_X86_64_REG_R15: 774278332Semaste return x86_64_eh_regnum::r15; 775278332Semaste case UNWIND_X86_64_REG_RBP: 776278332Semaste return x86_64_eh_regnum::rbp; 777278332Semaste default: 778278332Semaste return LLDB_INVALID_REGNUM; 779278332Semaste } 780278332Semaste} 781278332Semaste 782278332Semastebool 783278332SemasteCompactUnwindInfo::CreateUnwindPlan_x86_64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) 784278332Semaste{ 785278332Semaste unwind_plan.SetSourceName ("compact unwind info"); 786278332Semaste unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); 787278332Semaste unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); 788296417Sdim unwind_plan.SetRegisterKind (eRegisterKindEHFrame); 789278332Semaste 790278332Semaste unwind_plan.SetLSDAAddress (function_info.lsda_address); 791278332Semaste unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); 792278332Semaste 793278332Semaste UnwindPlan::RowSP row (new UnwindPlan::Row); 794278332Semaste 795278332Semaste const int wordsize = 8; 796278332Semaste int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK; 797278332Semaste switch (mode) 798278332Semaste { 799278332Semaste case UNWIND_X86_64_MODE_RBP_FRAME: 800278332Semaste { 801288943Sdim row->GetCFAValue().SetIsRegisterPlusOffset ( 802288943Sdim translate_to_eh_frame_regnum_x86_64 (UNWIND_X86_64_REG_RBP), 803288943Sdim 2 * wordsize); 804278332Semaste row->SetOffset (0); 805278332Semaste row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rbp, wordsize * -2, true); 806278332Semaste row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); 807278332Semaste row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true); 808309124Sdim 809278332Semaste uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET); 810278332Semaste 811278332Semaste uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); 812278332Semaste 813278332Semaste saved_registers_offset += 2; 814278332Semaste 815278332Semaste for (int i = 0; i < 5; i++) 816278332Semaste { 817278332Semaste uint32_t regnum = saved_registers_locations & 0x7; 818278332Semaste switch (regnum) 819278332Semaste { 820278332Semaste case UNWIND_X86_64_REG_NONE: 821278332Semaste break; 822278332Semaste case UNWIND_X86_64_REG_RBX: 823278332Semaste case UNWIND_X86_64_REG_R12: 824278332Semaste case UNWIND_X86_64_REG_R13: 825278332Semaste case UNWIND_X86_64_REG_R14: 826278332Semaste case UNWIND_X86_64_REG_R15: 827278332Semaste row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (regnum), wordsize * -saved_registers_offset, true); 828278332Semaste break; 829278332Semaste } 830278332Semaste saved_registers_offset--; 831278332Semaste saved_registers_locations >>= 3; 832278332Semaste } 833278332Semaste unwind_plan.AppendRow (row); 834278332Semaste return true; 835278332Semaste } 836278332Semaste break; 837278332Semaste 838278332Semaste case UNWIND_X86_64_MODE_STACK_IND: 839278332Semaste { 840278332Semaste // The clang in Xcode 6 is emitting incorrect compact unwind encodings for this 841309124Sdim // style of unwind. It was fixed in llvm r217020. 842288943Sdim // The clang in Xcode 7 has this fixed. 843278332Semaste return false; 844278332Semaste } 845278332Semaste break; 846278332Semaste 847278332Semaste case UNWIND_X86_64_MODE_STACK_IMMD: 848278332Semaste { 849278332Semaste uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 850278332Semaste uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); 851278332Semaste uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); 852278332Semaste 853278332Semaste if (mode == UNWIND_X86_64_MODE_STACK_IND && function_info.valid_range_offset_start != 0) 854278332Semaste { 855278332Semaste uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); 856278332Semaste 857278332Semaste // offset into the function instructions; 0 == beginning of first instruction 858278332Semaste uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 859278332Semaste 860278332Semaste SectionList *sl = m_objfile.GetSectionList (); 861278332Semaste if (sl) 862278332Semaste { 863278332Semaste ProcessSP process_sp = target.GetProcessSP(); 864278332Semaste if (process_sp) 865278332Semaste { 866278332Semaste Address subl_payload_addr (function_info.valid_range_offset_start, sl); 867278332Semaste subl_payload_addr.Slide (offset_to_subl_insn); 868278332Semaste Error error; 869278332Semaste uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target), 870278332Semaste 4, 0, error); 871278332Semaste if (large_stack_size != 0 && error.Success ()) 872278332Semaste { 873278332Semaste // Got the large stack frame size correctly - use it 874278332Semaste stack_size = large_stack_size + (stack_adjust * wordsize); 875278332Semaste } 876278332Semaste else 877278332Semaste { 878278332Semaste return false; 879278332Semaste } 880278332Semaste } 881278332Semaste else 882278332Semaste { 883278332Semaste return false; 884278332Semaste } 885278332Semaste } 886278332Semaste else 887278332Semaste { 888278332Semaste return false; 889278332Semaste } 890278332Semaste } 891278332Semaste 892288943Sdim int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND ? stack_size : stack_size * wordsize; 893288943Sdim row->GetCFAValue().SetIsRegisterPlusOffset (x86_64_eh_regnum::rsp, offset); 894288943Sdim 895278332Semaste row->SetOffset (0); 896278332Semaste row->SetRegisterLocationToAtCFAPlusOffset (x86_64_eh_regnum::rip, wordsize * -1, true); 897278332Semaste row->SetRegisterLocationToIsCFAPlusOffset (x86_64_eh_regnum::rsp, 0, true); 898278332Semaste 899278332Semaste if (register_count > 0) 900278332Semaste { 901278332Semaste 902278332Semaste // We need to include (up to) 6 registers in 10 bits. 903278332Semaste // That would be 18 bits if we just used 3 bits per reg to indicate 904309124Sdim // the order they're saved on the stack. 905278332Semaste // 906278332Semaste // This is done with Lehmer code permutation, e.g. see 907278332Semaste // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms 908288943Sdim int permunreg[6] = {0, 0, 0, 0, 0, 0}; 909278332Semaste 910278332Semaste // This decodes the variable-base number in the 10 bits 911278332Semaste // and gives us the Lehmer code sequence which can then 912278332Semaste // be decoded. 913278332Semaste 914309124Sdim switch (register_count) 915278332Semaste { 916278332Semaste case 6: 917278332Semaste permunreg[0] = permutation/120; // 120 == 5! 918278332Semaste permutation -= (permunreg[0]*120); 919278332Semaste permunreg[1] = permutation/24; // 24 == 4! 920278332Semaste permutation -= (permunreg[1]*24); 921278332Semaste permunreg[2] = permutation/6; // 6 == 3! 922278332Semaste permutation -= (permunreg[2]*6); 923278332Semaste permunreg[3] = permutation/2; // 2 == 2! 924278332Semaste permutation -= (permunreg[3]*2); 925278332Semaste permunreg[4] = permutation; // 1 == 1! 926278332Semaste permunreg[5] = 0; 927278332Semaste break; 928278332Semaste case 5: 929278332Semaste permunreg[0] = permutation/120; 930278332Semaste permutation -= (permunreg[0]*120); 931278332Semaste permunreg[1] = permutation/24; 932278332Semaste permutation -= (permunreg[1]*24); 933278332Semaste permunreg[2] = permutation/6; 934278332Semaste permutation -= (permunreg[2]*6); 935278332Semaste permunreg[3] = permutation/2; 936278332Semaste permutation -= (permunreg[3]*2); 937278332Semaste permunreg[4] = permutation; 938278332Semaste break; 939278332Semaste case 4: 940278332Semaste permunreg[0] = permutation/60; 941278332Semaste permutation -= (permunreg[0]*60); 942278332Semaste permunreg[1] = permutation/12; 943278332Semaste permutation -= (permunreg[1]*12); 944278332Semaste permunreg[2] = permutation/3; 945278332Semaste permutation -= (permunreg[2]*3); 946278332Semaste permunreg[3] = permutation; 947278332Semaste break; 948278332Semaste case 3: 949278332Semaste permunreg[0] = permutation/20; 950278332Semaste permutation -= (permunreg[0]*20); 951278332Semaste permunreg[1] = permutation/4; 952278332Semaste permutation -= (permunreg[1]*4); 953278332Semaste permunreg[2] = permutation; 954278332Semaste break; 955278332Semaste case 2: 956278332Semaste permunreg[0] = permutation/5; 957278332Semaste permutation -= (permunreg[0]*5); 958278332Semaste permunreg[1] = permutation; 959278332Semaste break; 960278332Semaste case 1: 961278332Semaste permunreg[0] = permutation; 962278332Semaste break; 963278332Semaste } 964309124Sdim 965278332Semaste // Decode the Lehmer code for this permutation of 966278332Semaste // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 967278332Semaste 968288943Sdim int registers[6] = { UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE }; 969278332Semaste bool used[7] = { false, false, false, false, false, false, false }; 970278332Semaste for (uint32_t i = 0; i < register_count; i++) 971278332Semaste { 972278332Semaste int renum = 0; 973278332Semaste for (int j = 1; j < 7; j++) 974278332Semaste { 975278332Semaste if (used[j] == false) 976278332Semaste { 977278332Semaste if (renum == permunreg[i]) 978278332Semaste { 979278332Semaste registers[i] = j; 980278332Semaste used[j] = true; 981278332Semaste break; 982278332Semaste } 983278332Semaste renum++; 984278332Semaste } 985278332Semaste } 986278332Semaste } 987278332Semaste 988278332Semaste uint32_t saved_registers_offset = 1; 989278332Semaste saved_registers_offset++; 990278332Semaste 991278332Semaste for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--) 992278332Semaste { 993278332Semaste switch (registers[i]) 994278332Semaste { 995278332Semaste case UNWIND_X86_64_REG_NONE: 996278332Semaste break; 997278332Semaste case UNWIND_X86_64_REG_RBX: 998278332Semaste case UNWIND_X86_64_REG_R12: 999278332Semaste case UNWIND_X86_64_REG_R13: 1000278332Semaste case UNWIND_X86_64_REG_R14: 1001278332Semaste case UNWIND_X86_64_REG_R15: 1002278332Semaste case UNWIND_X86_64_REG_RBP: 1003288943Sdim row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_x86_64 (registers[i]), wordsize * -saved_registers_offset, true); 1004288943Sdim saved_registers_offset++; 1005278332Semaste break; 1006278332Semaste } 1007278332Semaste } 1008278332Semaste } 1009278332Semaste unwind_plan.AppendRow (row); 1010278332Semaste return true; 1011278332Semaste } 1012278332Semaste break; 1013278332Semaste 1014278332Semaste case UNWIND_X86_64_MODE_DWARF: 1015278332Semaste { 1016278332Semaste return false; 1017278332Semaste } 1018278332Semaste break; 1019278332Semaste 1020278332Semaste case 0: 1021278332Semaste { 1022278332Semaste return false; 1023278332Semaste } 1024278332Semaste break; 1025278332Semaste } 1026278332Semaste return false; 1027278332Semaste} 1028278332Semaste 1029278332Semasteenum i386_eh_regnum { 1030278332Semaste eax = 0, 1031278332Semaste ecx = 1, 1032278332Semaste edx = 2, 1033278332Semaste ebx = 3, 1034278332Semaste ebp = 4, 1035278332Semaste esp = 5, 1036278332Semaste esi = 6, 1037278332Semaste edi = 7, 1038278332Semaste eip = 8 // this is officially the Return Address register number, but close enough 1039278332Semaste}; 1040278332Semaste 1041278332Semaste// Convert the compact_unwind_info.h register numbering scheme 1042296417Sdim// to eRegisterKindEHFrame (eh_frame) register numbering scheme. 1043278332Semasteuint32_t 1044278332Semastetranslate_to_eh_frame_regnum_i386 (uint32_t unwind_regno) 1045278332Semaste{ 1046278332Semaste switch (unwind_regno) 1047278332Semaste { 1048278332Semaste case UNWIND_X86_REG_EBX: 1049278332Semaste return i386_eh_regnum::ebx; 1050278332Semaste case UNWIND_X86_REG_ECX: 1051278332Semaste return i386_eh_regnum::ecx; 1052278332Semaste case UNWIND_X86_REG_EDX: 1053278332Semaste return i386_eh_regnum::edx; 1054278332Semaste case UNWIND_X86_REG_EDI: 1055278332Semaste return i386_eh_regnum::edi; 1056278332Semaste case UNWIND_X86_REG_ESI: 1057278332Semaste return i386_eh_regnum::esi; 1058278332Semaste case UNWIND_X86_REG_EBP: 1059278332Semaste return i386_eh_regnum::ebp; 1060278332Semaste default: 1061278332Semaste return LLDB_INVALID_REGNUM; 1062278332Semaste } 1063278332Semaste} 1064278332Semaste 1065278332Semaste 1066278332Semastebool 1067278332SemasteCompactUnwindInfo::CreateUnwindPlan_i386 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) 1068278332Semaste{ 1069278332Semaste unwind_plan.SetSourceName ("compact unwind info"); 1070278332Semaste unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); 1071278332Semaste unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); 1072296417Sdim unwind_plan.SetRegisterKind (eRegisterKindEHFrame); 1073278332Semaste 1074278332Semaste unwind_plan.SetLSDAAddress (function_info.lsda_address); 1075278332Semaste unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); 1076278332Semaste 1077278332Semaste UnwindPlan::RowSP row (new UnwindPlan::Row); 1078278332Semaste 1079278332Semaste const int wordsize = 4; 1080278332Semaste int mode = function_info.encoding & UNWIND_X86_MODE_MASK; 1081278332Semaste switch (mode) 1082278332Semaste { 1083278332Semaste case UNWIND_X86_MODE_EBP_FRAME: 1084278332Semaste { 1085288943Sdim row->GetCFAValue().SetIsRegisterPlusOffset ( 1086288943Sdim translate_to_eh_frame_regnum_i386 (UNWIND_X86_REG_EBP), 2 * wordsize); 1087278332Semaste row->SetOffset (0); 1088278332Semaste row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::ebp, wordsize * -2, true); 1089278332Semaste row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true); 1090278332Semaste row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true); 1091309124Sdim 1092278332Semaste uint32_t saved_registers_offset = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET); 1093278332Semaste 1094278332Semaste uint32_t saved_registers_locations = EXTRACT_BITS (function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS); 1095278332Semaste 1096278332Semaste saved_registers_offset += 2; 1097278332Semaste 1098278332Semaste for (int i = 0; i < 5; i++) 1099278332Semaste { 1100278332Semaste uint32_t regnum = saved_registers_locations & 0x7; 1101278332Semaste switch (regnum) 1102278332Semaste { 1103278332Semaste case UNWIND_X86_REG_NONE: 1104278332Semaste break; 1105278332Semaste case UNWIND_X86_REG_EBX: 1106278332Semaste case UNWIND_X86_REG_ECX: 1107278332Semaste case UNWIND_X86_REG_EDX: 1108278332Semaste case UNWIND_X86_REG_EDI: 1109278332Semaste case UNWIND_X86_REG_ESI: 1110278332Semaste row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (regnum), wordsize * -saved_registers_offset, true); 1111278332Semaste break; 1112278332Semaste } 1113278332Semaste saved_registers_offset--; 1114278332Semaste saved_registers_locations >>= 3; 1115278332Semaste } 1116278332Semaste unwind_plan.AppendRow (row); 1117278332Semaste return true; 1118278332Semaste } 1119278332Semaste break; 1120278332Semaste 1121278332Semaste case UNWIND_X86_MODE_STACK_IND: 1122278332Semaste case UNWIND_X86_MODE_STACK_IMMD: 1123278332Semaste { 1124278332Semaste uint32_t stack_size = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1125278332Semaste uint32_t register_count = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); 1126278332Semaste uint32_t permutation = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); 1127278332Semaste 1128278332Semaste if (mode == UNWIND_X86_MODE_STACK_IND && function_info.valid_range_offset_start != 0) 1129278332Semaste { 1130278332Semaste uint32_t stack_adjust = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); 1131278332Semaste 1132278332Semaste // offset into the function instructions; 0 == beginning of first instruction 1133278332Semaste uint32_t offset_to_subl_insn = EXTRACT_BITS (function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1134278332Semaste 1135278332Semaste SectionList *sl = m_objfile.GetSectionList (); 1136278332Semaste if (sl) 1137278332Semaste { 1138278332Semaste ProcessSP process_sp = target.GetProcessSP(); 1139278332Semaste if (process_sp) 1140278332Semaste { 1141278332Semaste Address subl_payload_addr (function_info.valid_range_offset_start, sl); 1142278332Semaste subl_payload_addr.Slide (offset_to_subl_insn); 1143278332Semaste Error error; 1144278332Semaste uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory (subl_payload_addr.GetLoadAddress (&target), 1145278332Semaste 4, 0, error); 1146278332Semaste if (large_stack_size != 0 && error.Success ()) 1147278332Semaste { 1148278332Semaste // Got the large stack frame size correctly - use it 1149278332Semaste stack_size = large_stack_size + (stack_adjust * wordsize); 1150278332Semaste } 1151278332Semaste else 1152278332Semaste { 1153278332Semaste return false; 1154278332Semaste } 1155278332Semaste } 1156278332Semaste else 1157278332Semaste { 1158278332Semaste return false; 1159278332Semaste } 1160278332Semaste } 1161278332Semaste else 1162278332Semaste { 1163278332Semaste return false; 1164278332Semaste } 1165278332Semaste } 1166278332Semaste 1167288943Sdim int32_t offset = mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize; 1168288943Sdim row->GetCFAValue().SetIsRegisterPlusOffset (i386_eh_regnum::esp, offset); 1169278332Semaste row->SetOffset (0); 1170278332Semaste row->SetRegisterLocationToAtCFAPlusOffset (i386_eh_regnum::eip, wordsize * -1, true); 1171278332Semaste row->SetRegisterLocationToIsCFAPlusOffset (i386_eh_regnum::esp, 0, true); 1172309124Sdim 1173278332Semaste if (register_count > 0) 1174278332Semaste { 1175278332Semaste 1176278332Semaste // We need to include (up to) 6 registers in 10 bits. 1177278332Semaste // That would be 18 bits if we just used 3 bits per reg to indicate 1178309124Sdim // the order they're saved on the stack. 1179278332Semaste // 1180278332Semaste // This is done with Lehmer code permutation, e.g. see 1181278332Semaste // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms 1182288943Sdim int permunreg[6] = {0, 0, 0, 0, 0, 0}; 1183278332Semaste 1184278332Semaste // This decodes the variable-base number in the 10 bits 1185278332Semaste // and gives us the Lehmer code sequence which can then 1186278332Semaste // be decoded. 1187278332Semaste 1188309124Sdim switch (register_count) 1189278332Semaste { 1190278332Semaste case 6: 1191278332Semaste permunreg[0] = permutation/120; // 120 == 5! 1192278332Semaste permutation -= (permunreg[0]*120); 1193278332Semaste permunreg[1] = permutation/24; // 24 == 4! 1194278332Semaste permutation -= (permunreg[1]*24); 1195278332Semaste permunreg[2] = permutation/6; // 6 == 3! 1196278332Semaste permutation -= (permunreg[2]*6); 1197278332Semaste permunreg[3] = permutation/2; // 2 == 2! 1198278332Semaste permutation -= (permunreg[3]*2); 1199278332Semaste permunreg[4] = permutation; // 1 == 1! 1200278332Semaste permunreg[5] = 0; 1201278332Semaste break; 1202278332Semaste case 5: 1203278332Semaste permunreg[0] = permutation/120; 1204278332Semaste permutation -= (permunreg[0]*120); 1205278332Semaste permunreg[1] = permutation/24; 1206278332Semaste permutation -= (permunreg[1]*24); 1207278332Semaste permunreg[2] = permutation/6; 1208278332Semaste permutation -= (permunreg[2]*6); 1209278332Semaste permunreg[3] = permutation/2; 1210278332Semaste permutation -= (permunreg[3]*2); 1211278332Semaste permunreg[4] = permutation; 1212278332Semaste break; 1213278332Semaste case 4: 1214278332Semaste permunreg[0] = permutation/60; 1215278332Semaste permutation -= (permunreg[0]*60); 1216278332Semaste permunreg[1] = permutation/12; 1217278332Semaste permutation -= (permunreg[1]*12); 1218278332Semaste permunreg[2] = permutation/3; 1219278332Semaste permutation -= (permunreg[2]*3); 1220278332Semaste permunreg[3] = permutation; 1221278332Semaste break; 1222278332Semaste case 3: 1223278332Semaste permunreg[0] = permutation/20; 1224278332Semaste permutation -= (permunreg[0]*20); 1225278332Semaste permunreg[1] = permutation/4; 1226278332Semaste permutation -= (permunreg[1]*4); 1227278332Semaste permunreg[2] = permutation; 1228278332Semaste break; 1229278332Semaste case 2: 1230278332Semaste permunreg[0] = permutation/5; 1231278332Semaste permutation -= (permunreg[0]*5); 1232278332Semaste permunreg[1] = permutation; 1233278332Semaste break; 1234278332Semaste case 1: 1235278332Semaste permunreg[0] = permutation; 1236278332Semaste break; 1237278332Semaste } 1238309124Sdim 1239278332Semaste // Decode the Lehmer code for this permutation of 1240278332Semaste // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 1241278332Semaste 1242288943Sdim int registers[6] = { UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE }; 1243278332Semaste bool used[7] = { false, false, false, false, false, false, false }; 1244278332Semaste for (uint32_t i = 0; i < register_count; i++) 1245278332Semaste { 1246278332Semaste int renum = 0; 1247278332Semaste for (int j = 1; j < 7; j++) 1248278332Semaste { 1249278332Semaste if (used[j] == false) 1250278332Semaste { 1251278332Semaste if (renum == permunreg[i]) 1252278332Semaste { 1253278332Semaste registers[i] = j; 1254278332Semaste used[j] = true; 1255278332Semaste break; 1256278332Semaste } 1257278332Semaste renum++; 1258278332Semaste } 1259278332Semaste } 1260278332Semaste } 1261278332Semaste 1262278332Semaste uint32_t saved_registers_offset = 1; 1263278332Semaste saved_registers_offset++; 1264278332Semaste 1265278332Semaste for (int i = (sizeof (registers) / sizeof (int)) - 1; i >= 0; i--) 1266278332Semaste { 1267278332Semaste switch (registers[i]) 1268278332Semaste { 1269278332Semaste case UNWIND_X86_REG_NONE: 1270278332Semaste break; 1271278332Semaste case UNWIND_X86_REG_EBX: 1272278332Semaste case UNWIND_X86_REG_ECX: 1273278332Semaste case UNWIND_X86_REG_EDX: 1274278332Semaste case UNWIND_X86_REG_EDI: 1275278332Semaste case UNWIND_X86_REG_ESI: 1276278332Semaste case UNWIND_X86_REG_EBP: 1277288943Sdim row->SetRegisterLocationToAtCFAPlusOffset (translate_to_eh_frame_regnum_i386 (registers[i]), wordsize * -saved_registers_offset, true); 1278288943Sdim saved_registers_offset++; 1279278332Semaste break; 1280278332Semaste } 1281278332Semaste } 1282278332Semaste } 1283278332Semaste 1284278332Semaste unwind_plan.AppendRow (row); 1285278332Semaste return true; 1286278332Semaste } 1287278332Semaste break; 1288278332Semaste 1289278332Semaste case UNWIND_X86_MODE_DWARF: 1290278332Semaste { 1291278332Semaste return false; 1292278332Semaste } 1293278332Semaste break; 1294278332Semaste } 1295278332Semaste return false; 1296278332Semaste} 1297309124Sdim 1298309124Sdim 1299309124Sdim 1300309124Sdim// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)" doc by ARM 1301309124Sdim 1302309124Sdimenum arm64_eh_regnum { 1303309124Sdim x19 = 19, 1304309124Sdim x20 = 20, 1305309124Sdim x21 = 21, 1306309124Sdim x22 = 22, 1307309124Sdim x23 = 23, 1308309124Sdim x24 = 24, 1309309124Sdim x25 = 25, 1310309124Sdim x26 = 26, 1311309124Sdim x27 = 27, 1312309124Sdim x28 = 28, 1313309124Sdim 1314309124Sdim fp = 29, 1315309124Sdim ra = 30, 1316309124Sdim sp = 31, 1317309124Sdim pc = 32, 1318309124Sdim 1319309124Sdim // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s for the 64-bit 1320309124Sdim // fp regs. Normally in DWARF it's context sensitive - so it knows it is fetching a 1321309124Sdim // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder is operating 1322309124Sdim // at a lower level and we'd try to fetch 128 bits if we were told that v8 were stored on 1323309124Sdim // the stack... 1324309124Sdim v8 = 72, 1325309124Sdim v9 = 73, 1326309124Sdim v10 = 74, 1327309124Sdim v11 = 75, 1328309124Sdim v12 = 76, 1329309124Sdim v13 = 77, 1330309124Sdim v14 = 78, 1331309124Sdim v15 = 79, 1332309124Sdim}; 1333309124Sdim 1334309124Sdimenum arm_eh_regnum { 1335309124Sdim arm_r0 = 0, 1336309124Sdim arm_r1 = 1, 1337309124Sdim arm_r2 = 2, 1338309124Sdim arm_r3 = 3, 1339309124Sdim arm_r4 = 4, 1340309124Sdim arm_r5 = 5, 1341309124Sdim arm_r6 = 6, 1342309124Sdim arm_r7 = 7, 1343309124Sdim arm_r8 = 8, 1344309124Sdim arm_r9 = 9, 1345309124Sdim arm_r10 = 10, 1346309124Sdim arm_r11 = 11, 1347309124Sdim arm_r12 = 12, 1348309124Sdim 1349309124Sdim arm_sp = 13, 1350309124Sdim arm_lr = 14, 1351309124Sdim arm_pc = 15, 1352309124Sdim 1353309124Sdim arm_d0 = 256, 1354309124Sdim arm_d1 = 257, 1355309124Sdim arm_d2 = 258, 1356309124Sdim arm_d3 = 259, 1357309124Sdim arm_d4 = 260, 1358309124Sdim arm_d5 = 261, 1359309124Sdim arm_d6 = 262, 1360309124Sdim arm_d7 = 263, 1361309124Sdim arm_d8 = 264, 1362309124Sdim arm_d9 = 265, 1363309124Sdim arm_d10 = 266, 1364309124Sdim arm_d11 = 267, 1365309124Sdim arm_d12 = 268, 1366309124Sdim arm_d13 = 269, 1367309124Sdim arm_d14 = 270, 1368309124Sdim}; 1369309124Sdim 1370309124Sdim 1371309124Sdim 1372309124Sdimbool 1373309124SdimCompactUnwindInfo::CreateUnwindPlan_arm64 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) 1374309124Sdim{ 1375309124Sdim unwind_plan.SetSourceName ("compact unwind info"); 1376309124Sdim unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); 1377309124Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); 1378309124Sdim unwind_plan.SetRegisterKind (eRegisterKindEHFrame); 1379309124Sdim 1380309124Sdim unwind_plan.SetLSDAAddress (function_info.lsda_address); 1381309124Sdim unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); 1382309124Sdim 1383309124Sdim UnwindPlan::RowSP row (new UnwindPlan::Row); 1384309124Sdim 1385309124Sdim const int wordsize = 8; 1386309124Sdim int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK; 1387309124Sdim 1388309124Sdim if (mode == UNWIND_ARM64_MODE_DWARF) 1389309124Sdim return false; 1390309124Sdim 1391309124Sdim if (mode == UNWIND_ARM64_MODE_FRAMELESS) 1392309124Sdim { 1393309124Sdim row->SetOffset (0); 1394309124Sdim 1395309124Sdim uint32_t stack_size = (EXTRACT_BITS (function_info.encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) * 16; 1396309124Sdim 1397309124Sdim // Our previous Call Frame Address is the stack pointer plus the stack size 1398309124Sdim row->GetCFAValue().SetIsRegisterPlusOffset (arm64_eh_regnum::sp, stack_size); 1399309124Sdim 1400309124Sdim // Our previous PC is in the LR 1401309124Sdim row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra, true); 1402309124Sdim 1403309124Sdim unwind_plan.AppendRow (row); 1404309124Sdim return true; 1405309124Sdim } 1406309124Sdim 1407309124Sdim // Should not be possible 1408309124Sdim if (mode != UNWIND_ARM64_MODE_FRAME) 1409309124Sdim return false; 1410309124Sdim 1411309124Sdim 1412309124Sdim // mode == UNWIND_ARM64_MODE_FRAME 1413309124Sdim 1414309124Sdim row->GetCFAValue().SetIsRegisterPlusOffset (arm64_eh_regnum::fp , 2 * wordsize); 1415309124Sdim row->SetOffset (0); 1416309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::fp, wordsize * -2, true); 1417309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::pc, wordsize * -1, true); 1418309124Sdim row->SetRegisterLocationToIsCFAPlusOffset (arm64_eh_regnum::sp, 0, true); 1419309124Sdim 1420309124Sdim int reg_pairs_saved_count = 1; 1421309124Sdim 1422309124Sdim uint32_t saved_register_bits = function_info.encoding & 0xfff; 1423309124Sdim 1424309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) 1425309124Sdim { 1426309124Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1427309124Sdim cfa_offset -= wordsize; 1428309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x19, cfa_offset, true); 1429309124Sdim cfa_offset -= wordsize; 1430309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x20, cfa_offset, true); 1431309124Sdim reg_pairs_saved_count++; 1432309124Sdim } 1433309124Sdim 1434309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) 1435309124Sdim { 1436309124Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1437309124Sdim cfa_offset -= wordsize; 1438309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x21, cfa_offset, true); 1439309124Sdim cfa_offset -= wordsize; 1440309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x22, cfa_offset, true); 1441309124Sdim reg_pairs_saved_count++; 1442309124Sdim } 1443309124Sdim 1444309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) 1445309124Sdim { 1446309124Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1447309124Sdim cfa_offset -= wordsize; 1448309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x23, cfa_offset, true); 1449309124Sdim cfa_offset -= wordsize; 1450309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x24, cfa_offset, true); 1451309124Sdim reg_pairs_saved_count++; 1452309124Sdim } 1453309124Sdim 1454309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) 1455309124Sdim { 1456309124Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1457309124Sdim cfa_offset -= wordsize; 1458309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x25, cfa_offset, true); 1459309124Sdim cfa_offset -= wordsize; 1460309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x26, cfa_offset, true); 1461309124Sdim reg_pairs_saved_count++; 1462309124Sdim } 1463309124Sdim 1464309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) 1465309124Sdim { 1466309124Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1467309124Sdim cfa_offset -= wordsize; 1468309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x27, cfa_offset, true); 1469309124Sdim cfa_offset -= wordsize; 1470309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm64_eh_regnum::x28, cfa_offset, true); 1471309124Sdim reg_pairs_saved_count++; 1472309124Sdim } 1473309124Sdim 1474309124Sdim // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits off the stack; 1475309124Sdim // not sure if we have a good way to represent the 64-bitness of these saves. 1476309124Sdim 1477309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) 1478309124Sdim { 1479309124Sdim reg_pairs_saved_count++; 1480309124Sdim } 1481309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) 1482309124Sdim { 1483309124Sdim reg_pairs_saved_count++; 1484309124Sdim } 1485309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) 1486309124Sdim { 1487309124Sdim reg_pairs_saved_count++; 1488309124Sdim } 1489309124Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) 1490309124Sdim { 1491309124Sdim reg_pairs_saved_count++; 1492309124Sdim } 1493309124Sdim 1494309124Sdim unwind_plan.AppendRow (row); 1495309124Sdim return true; 1496309124Sdim} 1497309124Sdim 1498309124Sdimbool 1499309124SdimCompactUnwindInfo::CreateUnwindPlan_armv7 (Target &target, FunctionInfo &function_info, UnwindPlan &unwind_plan, Address pc_or_function_start) 1500309124Sdim{ 1501309124Sdim unwind_plan.SetSourceName ("compact unwind info"); 1502309124Sdim unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); 1503309124Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); 1504309124Sdim unwind_plan.SetRegisterKind (eRegisterKindEHFrame); 1505309124Sdim 1506309124Sdim unwind_plan.SetLSDAAddress (function_info.lsda_address); 1507309124Sdim unwind_plan.SetPersonalityFunctionPtr (function_info.personality_ptr_address); 1508309124Sdim 1509309124Sdim UnwindPlan::RowSP row (new UnwindPlan::Row); 1510309124Sdim 1511309124Sdim const int wordsize = 4; 1512309124Sdim int mode = function_info.encoding & UNWIND_ARM_MODE_MASK; 1513309124Sdim 1514309124Sdim if (mode == UNWIND_ARM_MODE_DWARF) 1515309124Sdim return false; 1516309124Sdim 1517309124Sdim uint32_t stack_adjust = (EXTRACT_BITS (function_info.encoding, UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) * wordsize; 1518309124Sdim 1519309124Sdim row->GetCFAValue().SetIsRegisterPlusOffset (arm_r7 , (2 * wordsize) + stack_adjust); 1520309124Sdim row->SetOffset (0); 1521309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r7, (wordsize * -2) - stack_adjust, true); 1522309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_pc, (wordsize * -1) - stack_adjust, true); 1523309124Sdim row->SetRegisterLocationToIsCFAPlusOffset (arm_sp, 0, true); 1524309124Sdim 1525309124Sdim int cfa_offset = -stack_adjust - (2 * wordsize); 1526309124Sdim 1527309124Sdim uint32_t saved_register_bits = function_info.encoding & 0xff; 1528309124Sdim 1529309124Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) 1530309124Sdim { 1531309124Sdim cfa_offset -= wordsize; 1532309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r6, cfa_offset, true); 1533309124Sdim } 1534309124Sdim 1535309124Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) 1536309124Sdim { 1537309124Sdim cfa_offset -= wordsize; 1538309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r5, cfa_offset, true); 1539309124Sdim } 1540309124Sdim 1541309124Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) 1542309124Sdim { 1543309124Sdim cfa_offset -= wordsize; 1544309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r4, cfa_offset, true); 1545309124Sdim } 1546309124Sdim 1547309124Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) 1548309124Sdim { 1549309124Sdim cfa_offset -= wordsize; 1550309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r12, cfa_offset, true); 1551309124Sdim } 1552309124Sdim 1553309124Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) 1554309124Sdim { 1555309124Sdim cfa_offset -= wordsize; 1556309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r11, cfa_offset, true); 1557309124Sdim } 1558309124Sdim 1559309124Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) 1560309124Sdim { 1561309124Sdim cfa_offset -= wordsize; 1562309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r10, cfa_offset, true); 1563309124Sdim } 1564309124Sdim 1565309124Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) 1566309124Sdim { 1567309124Sdim cfa_offset -= wordsize; 1568309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r9, cfa_offset, true); 1569309124Sdim } 1570309124Sdim 1571309124Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) 1572309124Sdim { 1573309124Sdim cfa_offset -= wordsize; 1574309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_r8, cfa_offset, true); 1575309124Sdim } 1576309124Sdim 1577309124Sdim 1578309124Sdim if (mode == UNWIND_ARM_MODE_FRAME_D) 1579309124Sdim { 1580309124Sdim uint32_t d_reg_bits = EXTRACT_BITS (function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK); 1581309124Sdim switch (d_reg_bits) 1582309124Sdim { 1583309124Sdim case 0: 1584309124Sdim // vpush {d8} 1585309124Sdim cfa_offset -= 8; 1586309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d8, cfa_offset, true); 1587309124Sdim break; 1588309124Sdim case 1: 1589309124Sdim // vpush {d10} 1590309124Sdim // vpush {d8} 1591309124Sdim cfa_offset -= 8; 1592309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d10, cfa_offset, true); 1593309124Sdim cfa_offset -= 8; 1594309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d8, cfa_offset, true); 1595309124Sdim break; 1596309124Sdim case 2: 1597309124Sdim // vpush {d12} 1598309124Sdim // vpush {d10} 1599309124Sdim // vpush {d8} 1600309124Sdim cfa_offset -= 8; 1601309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d12, cfa_offset, true); 1602309124Sdim cfa_offset -= 8; 1603309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d10, cfa_offset, true); 1604309124Sdim cfa_offset -= 8; 1605309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d8, cfa_offset, true); 1606309124Sdim break; 1607309124Sdim case 3: 1608309124Sdim // vpush {d14} 1609309124Sdim // vpush {d12} 1610309124Sdim // vpush {d10} 1611309124Sdim // vpush {d8} 1612309124Sdim cfa_offset -= 8; 1613309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d14, cfa_offset, true); 1614309124Sdim cfa_offset -= 8; 1615309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d12, cfa_offset, true); 1616309124Sdim cfa_offset -= 8; 1617309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d10, cfa_offset, true); 1618309124Sdim cfa_offset -= 8; 1619309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d8, cfa_offset, true); 1620309124Sdim break; 1621309124Sdim case 4: 1622309124Sdim // vpush {d14} 1623309124Sdim // vpush {d12} 1624309124Sdim // sp = (sp - 24) & (-16); 1625309124Sdim // vst {d8, d9, d10} 1626309124Sdim cfa_offset -= 8; 1627309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d14, cfa_offset, true); 1628309124Sdim cfa_offset -= 8; 1629309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d12, cfa_offset, true); 1630309124Sdim 1631309124Sdim // FIXME we don't have a way to represent reg saves at an specific alignment short of 1632309124Sdim // coming up with some DWARF location description. 1633309124Sdim 1634309124Sdim break; 1635309124Sdim case 5: 1636309124Sdim // vpush {d14} 1637309124Sdim // sp = (sp - 40) & (-16); 1638309124Sdim // vst {d8, d9, d10, d11} 1639309124Sdim // vst {d12} 1640309124Sdim 1641309124Sdim cfa_offset -= 8; 1642309124Sdim row->SetRegisterLocationToAtCFAPlusOffset (arm_d14, cfa_offset, true); 1643309124Sdim 1644309124Sdim // FIXME we don't have a way to represent reg saves at an specific alignment short of 1645309124Sdim // coming up with some DWARF location description. 1646309124Sdim 1647309124Sdim break; 1648309124Sdim case 6: 1649309124Sdim // sp = (sp - 56) & (-16); 1650309124Sdim // vst {d8, d9, d10, d11} 1651309124Sdim // vst {d12, d13, d14} 1652309124Sdim 1653309124Sdim // FIXME we don't have a way to represent reg saves at an specific alignment short of 1654309124Sdim // coming up with some DWARF location description. 1655309124Sdim 1656309124Sdim break; 1657309124Sdim case 7: 1658309124Sdim // sp = (sp - 64) & (-16); 1659309124Sdim // vst {d8, d9, d10, d11} 1660309124Sdim // vst {d12, d13, d14, d15} 1661309124Sdim 1662309124Sdim // FIXME we don't have a way to represent reg saves at an specific alignment short of 1663309124Sdim // coming up with some DWARF location description. 1664309124Sdim 1665309124Sdim break; 1666309124Sdim } 1667309124Sdim } 1668309124Sdim 1669309124Sdim unwind_plan.AppendRow (row); 1670309124Sdim return true; 1671309124Sdim} 1672309124Sdim 1673309124Sdim 1674