CompactUnwindInfo.cpp revision 327952
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 10327952Sdim#include "lldb/Symbol/CompactUnwindInfo.h" 11278332Semaste#include "lldb/Core/Module.h" 12278332Semaste#include "lldb/Core/Section.h" 13278332Semaste#include "lldb/Symbol/ObjectFile.h" 14278332Semaste#include "lldb/Symbol/UnwindPlan.h" 15278332Semaste#include "lldb/Target/Process.h" 16278332Semaste#include "lldb/Target/Target.h" 17327952Sdim#include "lldb/Utility/ArchSpec.h" 18321369Sdim#include "lldb/Utility/DataBufferHeap.h" 19321369Sdim#include "lldb/Utility/Log.h" 20321369Sdim#include "lldb/Utility/StreamString.h" 21327952Sdim#include <algorithm> 22278332Semaste 23278332Semaste#include "llvm/Support/MathExtras.h" 24278332Semaste 25278332Semasteusing namespace lldb; 26278332Semasteusing namespace lldb_private; 27278332Semaste 28278332Semastenamespace lldb_private { 29278332Semaste 30314564Sdim// Constants from <mach-o/compact_unwind_encoding.h> 31278332Semaste 32314564SdimFLAGS_ANONYMOUS_ENUM(){ 33314564Sdim UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000, 34314564Sdim UNWIND_PERSONALITY_MASK = 0x30000000, 35314564Sdim}; 36278332Semaste 37314564SdimFLAGS_ANONYMOUS_ENUM(){ 38314564Sdim UNWIND_X86_MODE_MASK = 0x0F000000, 39314564Sdim UNWIND_X86_MODE_EBP_FRAME = 0x01000000, 40314564Sdim UNWIND_X86_MODE_STACK_IMMD = 0x02000000, 41314564Sdim UNWIND_X86_MODE_STACK_IND = 0x03000000, 42314564Sdim UNWIND_X86_MODE_DWARF = 0x04000000, 43278332Semaste 44314564Sdim UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, 45314564Sdim UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, 46278332Semaste 47314564Sdim UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, 48314564Sdim UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, 49314564Sdim UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 50314564Sdim UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 51278332Semaste 52314564Sdim UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, 53314564Sdim}; 54278332Semaste 55314564Sdimenum { 56314564Sdim UNWIND_X86_REG_NONE = 0, 57314564Sdim UNWIND_X86_REG_EBX = 1, 58314564Sdim UNWIND_X86_REG_ECX = 2, 59314564Sdim UNWIND_X86_REG_EDX = 3, 60314564Sdim UNWIND_X86_REG_EDI = 4, 61314564Sdim UNWIND_X86_REG_ESI = 5, 62314564Sdim UNWIND_X86_REG_EBP = 6, 63314564Sdim}; 64288943Sdim 65314564SdimFLAGS_ANONYMOUS_ENUM(){ 66314564Sdim UNWIND_X86_64_MODE_MASK = 0x0F000000, 67314564Sdim UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000, 68314564Sdim UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, 69314564Sdim UNWIND_X86_64_MODE_STACK_IND = 0x03000000, 70314564Sdim UNWIND_X86_64_MODE_DWARF = 0x04000000, 71278332Semaste 72314564Sdim UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, 73314564Sdim UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, 74278332Semaste 75314564Sdim UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000, 76314564Sdim UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000, 77314564Sdim UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 78314564Sdim UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 79278332Semaste 80314564Sdim UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 81314564Sdim}; 82278332Semaste 83314564Sdimenum { 84314564Sdim UNWIND_X86_64_REG_NONE = 0, 85314564Sdim UNWIND_X86_64_REG_RBX = 1, 86314564Sdim UNWIND_X86_64_REG_R12 = 2, 87314564Sdim UNWIND_X86_64_REG_R13 = 3, 88314564Sdim UNWIND_X86_64_REG_R14 = 4, 89314564Sdim UNWIND_X86_64_REG_R15 = 5, 90314564Sdim UNWIND_X86_64_REG_RBP = 6, 91314564Sdim}; 92309124Sdim 93314564SdimFLAGS_ANONYMOUS_ENUM(){ 94314564Sdim UNWIND_ARM64_MODE_MASK = 0x0F000000, 95314564Sdim UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, 96314564Sdim UNWIND_ARM64_MODE_DWARF = 0x03000000, 97314564Sdim UNWIND_ARM64_MODE_FRAME = 0x04000000, 98309124Sdim 99314564Sdim UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, 100314564Sdim UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, 101314564Sdim UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, 102314564Sdim UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, 103314564Sdim UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, 104314564Sdim UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, 105314564Sdim UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, 106314564Sdim UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, 107314564Sdim UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, 108309124Sdim 109314564Sdim UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, 110314564Sdim UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 111314564Sdim}; 112309124Sdim 113314564SdimFLAGS_ANONYMOUS_ENUM(){ 114314564Sdim UNWIND_ARM_MODE_MASK = 0x0F000000, 115314564Sdim UNWIND_ARM_MODE_FRAME = 0x01000000, 116314564Sdim UNWIND_ARM_MODE_FRAME_D = 0x02000000, 117314564Sdim UNWIND_ARM_MODE_DWARF = 0x04000000, 118309124Sdim 119314564Sdim UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000, 120309124Sdim 121314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001, 122314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002, 123314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004, 124309124Sdim 125314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008, 126314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010, 127314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020, 128314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040, 129314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080, 130309124Sdim 131314564Sdim UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700, 132309124Sdim 133314564Sdim UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF, 134314564Sdim}; 135288943Sdim} 136278332Semaste 137278332Semaste#ifndef UNWIND_SECOND_LEVEL_REGULAR 138278332Semaste#define UNWIND_SECOND_LEVEL_REGULAR 2 139278332Semaste#endif 140278332Semaste 141278332Semaste#ifndef UNWIND_SECOND_LEVEL_COMPRESSED 142278332Semaste#define UNWIND_SECOND_LEVEL_COMPRESSED 3 143278332Semaste#endif 144278332Semaste 145278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET 146314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF) 147278332Semaste#endif 148278332Semaste 149278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX 150314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \ 151314564Sdim ((entry >> 24) & 0xFF) 152278332Semaste#endif 153278332Semaste 154314564Sdim#define EXTRACT_BITS(value, mask) \ 155314564Sdim ((value >> \ 156314564Sdim llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \ 157314564Sdim (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1)) 158278332Semaste 159278332Semaste//---------------------- 160309124Sdim// constructor 161278332Semaste//---------------------- 162278332Semaste 163309124SdimCompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp) 164314564Sdim : m_objfile(objfile), m_section_sp(section_sp), 165314564Sdim m_section_contents_if_encrypted(), m_mutex(), m_indexes(), 166314564Sdim m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(), 167314564Sdim m_unwindinfo_data_computed(false), m_unwind_header() {} 168278332Semaste 169278332Semaste//---------------------- 170278332Semaste// destructor 171278332Semaste//---------------------- 172278332Semaste 173314564SdimCompactUnwindInfo::~CompactUnwindInfo() {} 174278332Semaste 175314564Sdimbool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr, 176314564Sdim UnwindPlan &unwind_plan) { 177314564Sdim if (!IsValid(target.GetProcessSP())) { 178314564Sdim return false; 179314564Sdim } 180314564Sdim FunctionInfo function_info; 181314564Sdim if (GetCompactUnwindInfoForFunction(target, addr, function_info)) { 182314564Sdim // shortcut return for functions that have no compact unwind 183314564Sdim if (function_info.encoding == 0) 184314564Sdim return false; 185278332Semaste 186314564Sdim ArchSpec arch; 187314564Sdim if (m_objfile.GetArchitecture(arch)) { 188278332Semaste 189314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 190314564Sdim if (log && log->GetVerbose()) { 191314564Sdim StreamString strm; 192314564Sdim addr.Dump( 193314564Sdim &strm, NULL, 194314564Sdim Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, 195314564Sdim Address::DumpStyle::DumpStyleFileAddress, 196314564Sdim arch.GetAddressByteSize()); 197314564Sdim log->Printf("Got compact unwind encoding 0x%x for function %s", 198314564Sdim function_info.encoding, strm.GetData()); 199314564Sdim } 200278332Semaste 201314564Sdim if (function_info.valid_range_offset_start != 0 && 202314564Sdim function_info.valid_range_offset_end != 0) { 203314564Sdim SectionList *sl = m_objfile.GetSectionList(); 204314564Sdim if (sl) { 205314564Sdim addr_t func_range_start_file_addr = 206314564Sdim function_info.valid_range_offset_start + 207314564Sdim m_objfile.GetHeaderAddress().GetFileAddress(); 208314564Sdim AddressRange func_range(func_range_start_file_addr, 209314564Sdim function_info.valid_range_offset_end - 210314564Sdim function_info.valid_range_offset_start, 211314564Sdim sl); 212314564Sdim unwind_plan.SetPlanValidAddressRange(func_range); 213314564Sdim } 214314564Sdim } 215278332Semaste 216314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::x86_64) { 217314564Sdim return CreateUnwindPlan_x86_64(target, function_info, unwind_plan, 218314564Sdim addr); 219314564Sdim } 220314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::aarch64) { 221314564Sdim return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr); 222314564Sdim } 223314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::x86) { 224314564Sdim return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr); 225314564Sdim } 226314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::arm || 227314564Sdim arch.GetTriple().getArch() == llvm::Triple::thumb) { 228314564Sdim return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr); 229314564Sdim } 230278332Semaste } 231314564Sdim } 232314564Sdim return false; 233278332Semaste} 234278332Semaste 235314564Sdimbool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) { 236314564Sdim if (m_section_sp.get() == nullptr) 237314564Sdim return false; 238278332Semaste 239314564Sdim if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 240314564Sdim return true; 241278332Semaste 242314564Sdim ScanIndex(process_sp); 243278332Semaste 244314564Sdim return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed; 245278332Semaste} 246278332Semaste 247314564Sdimvoid CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) { 248314564Sdim std::lock_guard<std::mutex> guard(m_mutex); 249314564Sdim if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 250314564Sdim return; 251278332Semaste 252314564Sdim // We can't read the index for some reason. 253314564Sdim if (m_indexes_computed == eLazyBoolNo) { 254314564Sdim return; 255314564Sdim } 256278332Semaste 257314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 258314564Sdim if (log) 259314564Sdim m_objfile.GetModule()->LogMessage( 260314564Sdim log, "Reading compact unwind first-level indexes"); 261278332Semaste 262314564Sdim if (m_unwindinfo_data_computed == false) { 263314564Sdim if (m_section_sp->IsEncrypted()) { 264314564Sdim // Can't get section contents of a protected/encrypted section until we 265314564Sdim // have a live 266314564Sdim // process and can read them out of memory. 267314564Sdim if (process_sp.get() == nullptr) 268314564Sdim return; 269314564Sdim m_section_contents_if_encrypted.reset( 270314564Sdim new DataBufferHeap(m_section_sp->GetByteSize(), 0)); 271321369Sdim Status error; 272314564Sdim if (process_sp->ReadMemory( 273314564Sdim m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()), 274314564Sdim m_section_contents_if_encrypted->GetBytes(), 275314564Sdim m_section_sp->GetByteSize(), 276314564Sdim error) == m_section_sp->GetByteSize() && 277314564Sdim error.Success()) { 278314564Sdim m_unwindinfo_data.SetAddressByteSize( 279314564Sdim process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); 280314564Sdim m_unwindinfo_data.SetByteOrder( 281314564Sdim process_sp->GetTarget().GetArchitecture().GetByteOrder()); 282314564Sdim m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0); 283314564Sdim } 284314564Sdim } else { 285314564Sdim m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data); 286278332Semaste } 287314564Sdim if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize()) 288314564Sdim return; 289314564Sdim m_unwindinfo_data_computed = true; 290314564Sdim } 291278332Semaste 292314564Sdim if (m_unwindinfo_data.GetByteSize() > 0) { 293314564Sdim offset_t offset = 0; 294278332Semaste 295314564Sdim // struct unwind_info_section_header 296314564Sdim // { 297314564Sdim // uint32_t version; // UNWIND_SECTION_VERSION 298314564Sdim // uint32_t commonEncodingsArraySectionOffset; 299314564Sdim // uint32_t commonEncodingsArrayCount; 300314564Sdim // uint32_t personalityArraySectionOffset; 301314564Sdim // uint32_t personalityArrayCount; 302314564Sdim // uint32_t indexSectionOffset; 303314564Sdim // uint32_t indexCount; 304309124Sdim 305314564Sdim m_unwind_header.version = m_unwindinfo_data.GetU32(&offset); 306314564Sdim m_unwind_header.common_encodings_array_offset = 307314564Sdim m_unwindinfo_data.GetU32(&offset); 308314564Sdim m_unwind_header.common_encodings_array_count = 309314564Sdim m_unwindinfo_data.GetU32(&offset); 310314564Sdim m_unwind_header.personality_array_offset = 311314564Sdim m_unwindinfo_data.GetU32(&offset); 312314564Sdim m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset); 313314564Sdim uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset); 314278332Semaste 315314564Sdim uint32_t indexCount = m_unwindinfo_data.GetU32(&offset); 316278332Semaste 317314564Sdim if (m_unwind_header.common_encodings_array_offset > 318314564Sdim m_unwindinfo_data.GetByteSize() || 319314564Sdim m_unwind_header.personality_array_offset > 320314564Sdim m_unwindinfo_data.GetByteSize() || 321314564Sdim indexSectionOffset > m_unwindinfo_data.GetByteSize() || 322314564Sdim offset > m_unwindinfo_data.GetByteSize()) { 323314564Sdim Host::SystemLog(Host::eSystemLogError, "error: Invalid offset " 324314564Sdim "encountered in compact unwind " 325314564Sdim "info, skipping\n"); 326314564Sdim // don't trust anything from this compact_unwind section if it looks 327314564Sdim // blatantly invalid data in the header. 328314564Sdim m_indexes_computed = eLazyBoolNo; 329314564Sdim return; 330314564Sdim } 331278332Semaste 332314564Sdim // Parse the basic information from the indexes 333314564Sdim // We wait to scan the second level page info until it's needed 334278332Semaste 335314564Sdim // struct unwind_info_section_header_index_entry 336314564Sdim // { 337314564Sdim // uint32_t functionOffset; 338314564Sdim // uint32_t secondLevelPagesSectionOffset; 339314564Sdim // uint32_t lsdaIndexArraySectionOffset; 340314564Sdim // }; 341278332Semaste 342314564Sdim bool clear_address_zeroth_bit = false; 343314564Sdim ArchSpec arch; 344314564Sdim if (m_objfile.GetArchitecture(arch)) { 345314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::arm || 346314564Sdim arch.GetTriple().getArch() == llvm::Triple::thumb) 347314564Sdim clear_address_zeroth_bit = true; 348314564Sdim } 349309124Sdim 350314564Sdim offset = indexSectionOffset; 351314564Sdim for (uint32_t idx = 0; idx < indexCount; idx++) { 352314564Sdim uint32_t function_offset = 353314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 354314564Sdim uint32_t second_level_offset = 355314564Sdim m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset 356314564Sdim uint32_t lsda_offset = 357314564Sdim m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset 358278332Semaste 359314564Sdim if (second_level_offset > m_section_sp->GetByteSize() || 360314564Sdim lsda_offset > m_section_sp->GetByteSize()) { 361314564Sdim m_indexes_computed = eLazyBoolNo; 362314564Sdim } 363278332Semaste 364314564Sdim if (clear_address_zeroth_bit) 365314564Sdim function_offset &= ~1ull; 366309124Sdim 367314564Sdim UnwindIndex this_index; 368314564Sdim this_index.function_offset = function_offset; 369314564Sdim this_index.second_level = second_level_offset; 370314564Sdim this_index.lsda_array_start = lsda_offset; 371278332Semaste 372314564Sdim if (m_indexes.size() > 0) { 373314564Sdim m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset; 374314564Sdim } 375278332Semaste 376314564Sdim if (second_level_offset == 0) { 377314564Sdim this_index.sentinal_entry = true; 378314564Sdim } 379278332Semaste 380314564Sdim m_indexes.push_back(this_index); 381278332Semaste } 382314564Sdim m_indexes_computed = eLazyBoolYes; 383314564Sdim } else { 384314564Sdim m_indexes_computed = eLazyBoolNo; 385314564Sdim } 386278332Semaste} 387278332Semaste 388314564Sdimuint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset, 389314564Sdim uint32_t lsda_count, 390314564Sdim uint32_t function_offset) { 391314564Sdim // struct unwind_info_section_header_lsda_index_entry 392314564Sdim // { 393314564Sdim // uint32_t functionOffset; 394314564Sdim // uint32_t lsdaOffset; 395314564Sdim // }; 396278332Semaste 397314564Sdim offset_t first_entry = lsda_offset; 398314564Sdim uint32_t low = 0; 399314564Sdim uint32_t high = lsda_count; 400314564Sdim while (low < high) { 401314564Sdim uint32_t mid = (low + high) / 2; 402314564Sdim offset_t offset = first_entry + (mid * 8); 403314564Sdim uint32_t mid_func_offset = 404314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 405314564Sdim uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset 406314564Sdim if (mid_func_offset == function_offset) { 407314564Sdim return mid_lsda_offset; 408278332Semaste } 409314564Sdim if (mid_func_offset < function_offset) { 410314564Sdim low = mid + 1; 411314564Sdim } else { 412314564Sdim high = mid; 413314564Sdim } 414314564Sdim } 415314564Sdim return 0; 416278332Semaste} 417278332Semaste 418314564Sdimlldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage( 419314564Sdim uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, 420314564Sdim uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) { 421314564Sdim // typedef uint32_t compact_unwind_encoding_t; 422314564Sdim // struct unwind_info_regular_second_level_entry 423314564Sdim // { 424314564Sdim // uint32_t functionOffset; 425314564Sdim // compact_unwind_encoding_t encoding; 426278332Semaste 427314564Sdim offset_t first_entry = entry_page_offset; 428278332Semaste 429314564Sdim uint32_t low = 0; 430314564Sdim uint32_t high = entry_count; 431314564Sdim uint32_t last = high - 1; 432314564Sdim while (low < high) { 433314564Sdim uint32_t mid = (low + high) / 2; 434314564Sdim offset_t offset = first_entry + (mid * 8); 435314564Sdim uint32_t mid_func_offset = 436314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 437314564Sdim uint32_t next_func_offset = 0; 438314564Sdim if (mid < last) { 439314564Sdim offset = first_entry + ((mid + 1) * 8); 440314564Sdim next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 441278332Semaste } 442314564Sdim if (mid_func_offset <= function_offset) { 443314564Sdim if (mid == last || (next_func_offset > function_offset)) { 444314564Sdim if (entry_func_start_offset) 445314564Sdim *entry_func_start_offset = mid_func_offset; 446314564Sdim if (mid != last && entry_func_end_offset) 447314564Sdim *entry_func_end_offset = next_func_offset; 448314564Sdim return first_entry + (mid * 8); 449314564Sdim } else { 450314564Sdim low = mid + 1; 451314564Sdim } 452314564Sdim } else { 453314564Sdim high = mid; 454314564Sdim } 455314564Sdim } 456314564Sdim return LLDB_INVALID_OFFSET; 457278332Semaste} 458278332Semaste 459314564Sdimuint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage( 460314564Sdim uint32_t entry_page_offset, uint32_t entry_count, 461314564Sdim uint32_t function_offset_to_find, uint32_t function_offset_base, 462314564Sdim uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) { 463314564Sdim offset_t first_entry = entry_page_offset; 464278332Semaste 465314564Sdim uint32_t low = 0; 466314564Sdim uint32_t high = entry_count; 467314564Sdim uint32_t last = high - 1; 468314564Sdim while (low < high) { 469314564Sdim uint32_t mid = (low + high) / 2; 470314564Sdim offset_t offset = first_entry + (mid * 4); 471314564Sdim uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry 472314564Sdim uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry); 473314564Sdim mid_func_offset += function_offset_base; 474314564Sdim uint32_t next_func_offset = 0; 475314564Sdim if (mid < last) { 476314564Sdim offset = first_entry + ((mid + 1) * 4); 477314564Sdim uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry 478314564Sdim next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry); 479314564Sdim next_func_offset += function_offset_base; 480278332Semaste } 481314564Sdim if (mid_func_offset <= function_offset_to_find) { 482314564Sdim if (mid == last || (next_func_offset > function_offset_to_find)) { 483314564Sdim if (entry_func_start_offset) 484314564Sdim *entry_func_start_offset = mid_func_offset; 485314564Sdim if (mid != last && entry_func_end_offset) 486314564Sdim *entry_func_end_offset = next_func_offset; 487314564Sdim return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry); 488314564Sdim } else { 489314564Sdim low = mid + 1; 490314564Sdim } 491314564Sdim } else { 492314564Sdim high = mid; 493314564Sdim } 494314564Sdim } 495278332Semaste 496314564Sdim return UINT32_MAX; 497278332Semaste} 498278332Semaste 499314564Sdimbool CompactUnwindInfo::GetCompactUnwindInfoForFunction( 500314564Sdim Target &target, Address address, FunctionInfo &unwind_info) { 501314564Sdim unwind_info.encoding = 0; 502314564Sdim unwind_info.lsda_address.Clear(); 503314564Sdim unwind_info.personality_ptr_address.Clear(); 504278332Semaste 505314564Sdim if (!IsValid(target.GetProcessSP())) 506314564Sdim return false; 507278332Semaste 508314564Sdim addr_t text_section_file_address = LLDB_INVALID_ADDRESS; 509314564Sdim SectionList *sl = m_objfile.GetSectionList(); 510314564Sdim if (sl) { 511314564Sdim SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true); 512314564Sdim if (text_sect.get()) { 513314564Sdim text_section_file_address = text_sect->GetFileAddress(); 514278332Semaste } 515314564Sdim } 516314564Sdim if (text_section_file_address == LLDB_INVALID_ADDRESS) 517314564Sdim return false; 518278332Semaste 519314564Sdim addr_t function_offset = 520314564Sdim address.GetFileAddress() - m_objfile.GetHeaderAddress().GetFileAddress(); 521309124Sdim 522314564Sdim UnwindIndex key; 523314564Sdim key.function_offset = function_offset; 524309124Sdim 525314564Sdim std::vector<UnwindIndex>::const_iterator it; 526314564Sdim it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key); 527314564Sdim if (it == m_indexes.end()) { 528314564Sdim return false; 529314564Sdim } 530278332Semaste 531314564Sdim if (it->function_offset != key.function_offset) { 532314564Sdim if (it != m_indexes.begin()) 533314564Sdim --it; 534314564Sdim } 535278332Semaste 536314564Sdim if (it->sentinal_entry == true) { 537314564Sdim return false; 538314564Sdim } 539278332Semaste 540314564Sdim auto next_it = it + 1; 541314564Sdim if (next_it != m_indexes.end()) { 542314564Sdim // initialize the function offset end range to be the start of the 543314564Sdim // next index offset. If we find an entry which is at the end of 544314564Sdim // the index table, this will establish the range end. 545314564Sdim unwind_info.valid_range_offset_end = next_it->function_offset; 546314564Sdim } 547278332Semaste 548314564Sdim offset_t second_page_offset = it->second_level; 549314564Sdim offset_t lsda_array_start = it->lsda_array_start; 550314564Sdim offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8; 551278332Semaste 552314564Sdim offset_t offset = second_page_offset; 553314564Sdim uint32_t kind = m_unwindinfo_data.GetU32( 554314564Sdim &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED 555278332Semaste 556314564Sdim if (kind == UNWIND_SECOND_LEVEL_REGULAR) { 557314564Sdim // struct unwind_info_regular_second_level_page_header 558314564Sdim // { 559314564Sdim // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR 560314564Sdim // uint16_t entryPageOffset; 561314564Sdim // uint16_t entryCount; 562278332Semaste 563314564Sdim // typedef uint32_t compact_unwind_encoding_t; 564314564Sdim // struct unwind_info_regular_second_level_entry 565314564Sdim // { 566314564Sdim // uint32_t functionOffset; 567314564Sdim // compact_unwind_encoding_t encoding; 568278332Semaste 569314564Sdim uint16_t entry_page_offset = 570314564Sdim m_unwindinfo_data.GetU16(&offset); // entryPageOffset 571314564Sdim uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 572278332Semaste 573314564Sdim offset_t entry_offset = BinarySearchRegularSecondPage( 574314564Sdim second_page_offset + entry_page_offset, entry_count, function_offset, 575314564Sdim &unwind_info.valid_range_offset_start, 576314564Sdim &unwind_info.valid_range_offset_end); 577314564Sdim if (entry_offset == LLDB_INVALID_OFFSET) { 578314564Sdim return false; 579314564Sdim } 580314564Sdim entry_offset += 4; // skip over functionOffset 581314564Sdim unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding 582314564Sdim if (unwind_info.encoding & UNWIND_HAS_LSDA) { 583314564Sdim SectionList *sl = m_objfile.GetSectionList(); 584314564Sdim if (sl) { 585314564Sdim uint32_t lsda_offset = GetLSDAForFunctionOffset( 586314564Sdim lsda_array_start, lsda_array_count, function_offset); 587314564Sdim addr_t objfile_header_file_address = 588314564Sdim m_objfile.GetHeaderAddress().GetFileAddress(); 589314564Sdim unwind_info.lsda_address.ResolveAddressUsingFileSections( 590314564Sdim objfile_header_file_address + lsda_offset, sl); 591314564Sdim } 592314564Sdim } 593314564Sdim if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) { 594314564Sdim uint32_t personality_index = 595314564Sdim EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK); 596278332Semaste 597314564Sdim if (personality_index > 0) { 598314564Sdim personality_index--; 599314564Sdim if (personality_index < m_unwind_header.personality_array_count) { 600314564Sdim offset_t offset = m_unwind_header.personality_array_offset; 601314564Sdim offset += 4 * personality_index; 602314564Sdim SectionList *sl = m_objfile.GetSectionList(); 603314564Sdim if (sl) { 604314564Sdim uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 605314564Sdim addr_t objfile_header_file_address = 606314564Sdim m_objfile.GetHeaderAddress().GetFileAddress(); 607314564Sdim unwind_info.personality_ptr_address.ResolveAddressUsingFileSections( 608314564Sdim objfile_header_file_address + personality_offset, sl); 609314564Sdim } 610278332Semaste } 611314564Sdim } 612278332Semaste } 613314564Sdim return true; 614314564Sdim } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) { 615314564Sdim // struct unwind_info_compressed_second_level_page_header 616314564Sdim // { 617314564Sdim // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED 618314564Sdim // uint16_t entryPageOffset; // offset from this 2nd lvl page 619314564Sdim // idx to array of entries 620314564Sdim // // (an entry has a function 621314564Sdim // offset and index into the 622314564Sdim // encodings) 623314564Sdim // // NB function offset from the 624314564Sdim // entry in the compressed page 625314564Sdim // // must be added to the index's 626314564Sdim // functionOffset value. 627314564Sdim // uint16_t entryCount; 628314564Sdim // uint16_t encodingsPageOffset; // offset from this 2nd lvl page 629314564Sdim // idx to array of encodings 630314564Sdim // uint16_t encodingsCount; 631278332Semaste 632314564Sdim uint16_t entry_page_offset = 633314564Sdim m_unwindinfo_data.GetU16(&offset); // entryPageOffset 634314564Sdim uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 635314564Sdim uint16_t encodings_page_offset = 636314564Sdim m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset 637314564Sdim uint16_t encodings_count = 638314564Sdim m_unwindinfo_data.GetU16(&offset); // encodingsCount 639278332Semaste 640314564Sdim uint32_t encoding_index = BinarySearchCompressedSecondPage( 641314564Sdim second_page_offset + entry_page_offset, entry_count, function_offset, 642314564Sdim it->function_offset, &unwind_info.valid_range_offset_start, 643314564Sdim &unwind_info.valid_range_offset_end); 644314564Sdim if (encoding_index == UINT32_MAX || 645314564Sdim encoding_index >= 646314564Sdim encodings_count + m_unwind_header.common_encodings_array_count) { 647314564Sdim return false; 648314564Sdim } 649314564Sdim uint32_t encoding = 0; 650314564Sdim if (encoding_index < m_unwind_header.common_encodings_array_count) { 651314564Sdim offset = m_unwind_header.common_encodings_array_offset + 652314564Sdim (encoding_index * sizeof(uint32_t)); 653314564Sdim encoding = m_unwindinfo_data.GetU32( 654314564Sdim &offset); // encoding entry from the commonEncodingsArray 655314564Sdim } else { 656314564Sdim uint32_t page_specific_entry_index = 657314564Sdim encoding_index - m_unwind_header.common_encodings_array_count; 658314564Sdim offset = second_page_offset + encodings_page_offset + 659314564Sdim (page_specific_entry_index * sizeof(uint32_t)); 660314564Sdim encoding = m_unwindinfo_data.GetU32( 661314564Sdim &offset); // encoding entry from the page-specific encoding array 662314564Sdim } 663314564Sdim if (encoding == 0) 664314564Sdim return false; 665278332Semaste 666314564Sdim unwind_info.encoding = encoding; 667314564Sdim if (unwind_info.encoding & UNWIND_HAS_LSDA) { 668314564Sdim SectionList *sl = m_objfile.GetSectionList(); 669314564Sdim if (sl) { 670314564Sdim uint32_t lsda_offset = GetLSDAForFunctionOffset( 671314564Sdim lsda_array_start, lsda_array_count, function_offset); 672314564Sdim addr_t objfile_header_file_address = 673314564Sdim m_objfile.GetHeaderAddress().GetFileAddress(); 674314564Sdim unwind_info.lsda_address.ResolveAddressUsingFileSections( 675314564Sdim objfile_header_file_address + lsda_offset, sl); 676314564Sdim } 677314564Sdim } 678314564Sdim if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) { 679314564Sdim uint32_t personality_index = 680314564Sdim EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK); 681278332Semaste 682314564Sdim if (personality_index > 0) { 683314564Sdim personality_index--; 684314564Sdim if (personality_index < m_unwind_header.personality_array_count) { 685314564Sdim offset_t offset = m_unwind_header.personality_array_offset; 686314564Sdim offset += 4 * personality_index; 687314564Sdim SectionList *sl = m_objfile.GetSectionList(); 688314564Sdim if (sl) { 689314564Sdim uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 690314564Sdim addr_t objfile_header_file_address = 691314564Sdim m_objfile.GetHeaderAddress().GetFileAddress(); 692314564Sdim unwind_info.personality_ptr_address.ResolveAddressUsingFileSections( 693314564Sdim objfile_header_file_address + personality_offset, sl); 694314564Sdim } 695278332Semaste } 696314564Sdim } 697278332Semaste } 698314564Sdim return true; 699314564Sdim } 700314564Sdim return false; 701278332Semaste} 702278332Semaste 703278332Semasteenum x86_64_eh_regnum { 704314564Sdim rax = 0, 705314564Sdim rdx = 1, 706314564Sdim rcx = 2, 707314564Sdim rbx = 3, 708314564Sdim rsi = 4, 709314564Sdim rdi = 5, 710314564Sdim rbp = 6, 711314564Sdim rsp = 7, 712314564Sdim r8 = 8, 713314564Sdim r9 = 9, 714314564Sdim r10 = 10, 715314564Sdim r11 = 11, 716314564Sdim r12 = 12, 717314564Sdim r13 = 13, 718314564Sdim r14 = 14, 719314564Sdim r15 = 15, 720314564Sdim rip = 16 // this is officially the Return Address register number, but close 721314564Sdim // enough 722278332Semaste}; 723278332Semaste 724278332Semaste// Convert the compact_unwind_info.h register numbering scheme 725296417Sdim// to eRegisterKindEHFrame (eh_frame) register numbering scheme. 726314564Sdimuint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) { 727314564Sdim switch (unwind_regno) { 728314564Sdim case UNWIND_X86_64_REG_RBX: 729314564Sdim return x86_64_eh_regnum::rbx; 730314564Sdim case UNWIND_X86_64_REG_R12: 731314564Sdim return x86_64_eh_regnum::r12; 732314564Sdim case UNWIND_X86_64_REG_R13: 733314564Sdim return x86_64_eh_regnum::r13; 734314564Sdim case UNWIND_X86_64_REG_R14: 735314564Sdim return x86_64_eh_regnum::r14; 736314564Sdim case UNWIND_X86_64_REG_R15: 737314564Sdim return x86_64_eh_regnum::r15; 738314564Sdim case UNWIND_X86_64_REG_RBP: 739314564Sdim return x86_64_eh_regnum::rbp; 740314564Sdim default: 741314564Sdim return LLDB_INVALID_REGNUM; 742314564Sdim } 743278332Semaste} 744278332Semaste 745314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target, 746314564Sdim FunctionInfo &function_info, 747314564Sdim UnwindPlan &unwind_plan, 748314564Sdim Address pc_or_function_start) { 749314564Sdim unwind_plan.SetSourceName("compact unwind info"); 750314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 751314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 752314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 753278332Semaste 754314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 755314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 756278332Semaste 757314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 758278332Semaste 759314564Sdim const int wordsize = 8; 760314564Sdim int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK; 761314564Sdim switch (mode) { 762314564Sdim case UNWIND_X86_64_MODE_RBP_FRAME: { 763314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset( 764314564Sdim translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP), 765314564Sdim 2 * wordsize); 766314564Sdim row->SetOffset(0); 767314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp, 768314564Sdim wordsize * -2, true); 769314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip, 770314564Sdim wordsize * -1, true); 771314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true); 772309124Sdim 773314564Sdim uint32_t saved_registers_offset = 774314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET); 775278332Semaste 776314564Sdim uint32_t saved_registers_locations = 777314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); 778278332Semaste 779314564Sdim saved_registers_offset += 2; 780278332Semaste 781314564Sdim for (int i = 0; i < 5; i++) { 782314564Sdim uint32_t regnum = saved_registers_locations & 0x7; 783314564Sdim switch (regnum) { 784314564Sdim case UNWIND_X86_64_REG_NONE: 785278332Semaste break; 786314564Sdim case UNWIND_X86_64_REG_RBX: 787314564Sdim case UNWIND_X86_64_REG_R12: 788314564Sdim case UNWIND_X86_64_REG_R13: 789314564Sdim case UNWIND_X86_64_REG_R14: 790314564Sdim case UNWIND_X86_64_REG_R15: 791314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 792314564Sdim translate_to_eh_frame_regnum_x86_64(regnum), 793314564Sdim wordsize * -saved_registers_offset, true); 794278332Semaste break; 795314564Sdim } 796314564Sdim saved_registers_offset--; 797314564Sdim saved_registers_locations >>= 3; 798314564Sdim } 799314564Sdim unwind_plan.AppendRow(row); 800314564Sdim return true; 801314564Sdim } break; 802278332Semaste 803314564Sdim case UNWIND_X86_64_MODE_STACK_IND: { 804314564Sdim // The clang in Xcode 6 is emitting incorrect compact unwind encodings for 805314564Sdim // this 806314564Sdim // style of unwind. It was fixed in llvm r217020. 807314564Sdim // The clang in Xcode 7 has this fixed. 808314564Sdim return false; 809314564Sdim } break; 810278332Semaste 811314564Sdim case UNWIND_X86_64_MODE_STACK_IMMD: { 812314564Sdim uint32_t stack_size = EXTRACT_BITS(function_info.encoding, 813314564Sdim UNWIND_X86_64_FRAMELESS_STACK_SIZE); 814314564Sdim uint32_t register_count = EXTRACT_BITS( 815314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); 816314564Sdim uint32_t permutation = EXTRACT_BITS( 817314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); 818278332Semaste 819314564Sdim if (mode == UNWIND_X86_64_MODE_STACK_IND && 820314564Sdim function_info.valid_range_offset_start != 0) { 821314564Sdim uint32_t stack_adjust = EXTRACT_BITS( 822314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); 823278332Semaste 824314564Sdim // offset into the function instructions; 0 == beginning of first 825314564Sdim // instruction 826314564Sdim uint32_t offset_to_subl_insn = EXTRACT_BITS( 827314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 828278332Semaste 829314564Sdim SectionList *sl = m_objfile.GetSectionList(); 830314564Sdim if (sl) { 831314564Sdim ProcessSP process_sp = target.GetProcessSP(); 832314564Sdim if (process_sp) { 833314564Sdim Address subl_payload_addr(function_info.valid_range_offset_start, sl); 834314564Sdim subl_payload_addr.Slide(offset_to_subl_insn); 835321369Sdim Status error; 836314564Sdim uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory( 837314564Sdim subl_payload_addr.GetLoadAddress(&target), 4, 0, error); 838314564Sdim if (large_stack_size != 0 && error.Success()) { 839314564Sdim // Got the large stack frame size correctly - use it 840314564Sdim stack_size = large_stack_size + (stack_adjust * wordsize); 841314564Sdim } else { 842314564Sdim return false; 843314564Sdim } 844314564Sdim } else { 845314564Sdim return false; 846314564Sdim } 847314564Sdim } else { 848314564Sdim return false; 849314564Sdim } 850314564Sdim } 851288943Sdim 852314564Sdim int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND 853314564Sdim ? stack_size 854314564Sdim : stack_size * wordsize; 855314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset); 856278332Semaste 857314564Sdim row->SetOffset(0); 858314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip, 859314564Sdim wordsize * -1, true); 860314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true); 861278332Semaste 862314564Sdim if (register_count > 0) { 863278332Semaste 864314564Sdim // We need to include (up to) 6 registers in 10 bits. 865314564Sdim // That would be 18 bits if we just used 3 bits per reg to indicate 866314564Sdim // the order they're saved on the stack. 867314564Sdim // 868314564Sdim // This is done with Lehmer code permutation, e.g. see 869314564Sdim // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms 870314564Sdim int permunreg[6] = {0, 0, 0, 0, 0, 0}; 871278332Semaste 872314564Sdim // This decodes the variable-base number in the 10 bits 873314564Sdim // and gives us the Lehmer code sequence which can then 874314564Sdim // be decoded. 875309124Sdim 876314564Sdim switch (register_count) { 877314564Sdim case 6: 878314564Sdim permunreg[0] = permutation / 120; // 120 == 5! 879314564Sdim permutation -= (permunreg[0] * 120); 880314564Sdim permunreg[1] = permutation / 24; // 24 == 4! 881314564Sdim permutation -= (permunreg[1] * 24); 882314564Sdim permunreg[2] = permutation / 6; // 6 == 3! 883314564Sdim permutation -= (permunreg[2] * 6); 884314564Sdim permunreg[3] = permutation / 2; // 2 == 2! 885314564Sdim permutation -= (permunreg[3] * 2); 886314564Sdim permunreg[4] = permutation; // 1 == 1! 887314564Sdim permunreg[5] = 0; 888314564Sdim break; 889314564Sdim case 5: 890314564Sdim permunreg[0] = permutation / 120; 891314564Sdim permutation -= (permunreg[0] * 120); 892314564Sdim permunreg[1] = permutation / 24; 893314564Sdim permutation -= (permunreg[1] * 24); 894314564Sdim permunreg[2] = permutation / 6; 895314564Sdim permutation -= (permunreg[2] * 6); 896314564Sdim permunreg[3] = permutation / 2; 897314564Sdim permutation -= (permunreg[3] * 2); 898314564Sdim permunreg[4] = permutation; 899314564Sdim break; 900314564Sdim case 4: 901314564Sdim permunreg[0] = permutation / 60; 902314564Sdim permutation -= (permunreg[0] * 60); 903314564Sdim permunreg[1] = permutation / 12; 904314564Sdim permutation -= (permunreg[1] * 12); 905314564Sdim permunreg[2] = permutation / 3; 906314564Sdim permutation -= (permunreg[2] * 3); 907314564Sdim permunreg[3] = permutation; 908314564Sdim break; 909314564Sdim case 3: 910314564Sdim permunreg[0] = permutation / 20; 911314564Sdim permutation -= (permunreg[0] * 20); 912314564Sdim permunreg[1] = permutation / 4; 913314564Sdim permutation -= (permunreg[1] * 4); 914314564Sdim permunreg[2] = permutation; 915314564Sdim break; 916314564Sdim case 2: 917314564Sdim permunreg[0] = permutation / 5; 918314564Sdim permutation -= (permunreg[0] * 5); 919314564Sdim permunreg[1] = permutation; 920314564Sdim break; 921314564Sdim case 1: 922314564Sdim permunreg[0] = permutation; 923314564Sdim break; 924314564Sdim } 925278332Semaste 926314564Sdim // Decode the Lehmer code for this permutation of 927314564Sdim // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 928278332Semaste 929314564Sdim int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, 930314564Sdim UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, 931314564Sdim UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE}; 932314564Sdim bool used[7] = {false, false, false, false, false, false, false}; 933314564Sdim for (uint32_t i = 0; i < register_count; i++) { 934314564Sdim int renum = 0; 935314564Sdim for (int j = 1; j < 7; j++) { 936314564Sdim if (used[j] == false) { 937314564Sdim if (renum == permunreg[i]) { 938314564Sdim registers[i] = j; 939314564Sdim used[j] = true; 940314564Sdim break; 941278332Semaste } 942314564Sdim renum++; 943314564Sdim } 944278332Semaste } 945314564Sdim } 946278332Semaste 947314564Sdim uint32_t saved_registers_offset = 1; 948314564Sdim saved_registers_offset++; 949278332Semaste 950314564Sdim for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) { 951314564Sdim switch (registers[i]) { 952314564Sdim case UNWIND_X86_64_REG_NONE: 953314564Sdim break; 954314564Sdim case UNWIND_X86_64_REG_RBX: 955314564Sdim case UNWIND_X86_64_REG_R12: 956314564Sdim case UNWIND_X86_64_REG_R13: 957314564Sdim case UNWIND_X86_64_REG_R14: 958314564Sdim case UNWIND_X86_64_REG_R15: 959314564Sdim case UNWIND_X86_64_REG_RBP: 960314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 961314564Sdim translate_to_eh_frame_regnum_x86_64(registers[i]), 962314564Sdim wordsize * -saved_registers_offset, true); 963314564Sdim saved_registers_offset++; 964314564Sdim break; 965278332Semaste } 966314564Sdim } 967278332Semaste } 968314564Sdim unwind_plan.AppendRow(row); 969314564Sdim return true; 970314564Sdim } break; 971314564Sdim 972314564Sdim case UNWIND_X86_64_MODE_DWARF: { 973278332Semaste return false; 974314564Sdim } break; 975314564Sdim 976314564Sdim case 0: { 977314564Sdim return false; 978314564Sdim } break; 979314564Sdim } 980314564Sdim return false; 981278332Semaste} 982278332Semaste 983278332Semasteenum i386_eh_regnum { 984314564Sdim eax = 0, 985314564Sdim ecx = 1, 986314564Sdim edx = 2, 987314564Sdim ebx = 3, 988314564Sdim ebp = 4, 989314564Sdim esp = 5, 990314564Sdim esi = 6, 991314564Sdim edi = 7, 992314564Sdim eip = 8 // this is officially the Return Address register number, but close 993314564Sdim // enough 994278332Semaste}; 995278332Semaste 996278332Semaste// Convert the compact_unwind_info.h register numbering scheme 997296417Sdim// to eRegisterKindEHFrame (eh_frame) register numbering scheme. 998314564Sdimuint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) { 999314564Sdim switch (unwind_regno) { 1000314564Sdim case UNWIND_X86_REG_EBX: 1001314564Sdim return i386_eh_regnum::ebx; 1002314564Sdim case UNWIND_X86_REG_ECX: 1003314564Sdim return i386_eh_regnum::ecx; 1004314564Sdim case UNWIND_X86_REG_EDX: 1005314564Sdim return i386_eh_regnum::edx; 1006314564Sdim case UNWIND_X86_REG_EDI: 1007314564Sdim return i386_eh_regnum::edi; 1008314564Sdim case UNWIND_X86_REG_ESI: 1009314564Sdim return i386_eh_regnum::esi; 1010314564Sdim case UNWIND_X86_REG_EBP: 1011314564Sdim return i386_eh_regnum::ebp; 1012314564Sdim default: 1013314564Sdim return LLDB_INVALID_REGNUM; 1014314564Sdim } 1015278332Semaste} 1016278332Semaste 1017314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target, 1018314564Sdim FunctionInfo &function_info, 1019314564Sdim UnwindPlan &unwind_plan, 1020314564Sdim Address pc_or_function_start) { 1021314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1022314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1023314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1024314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1025278332Semaste 1026314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1027314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1028278332Semaste 1029314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1030278332Semaste 1031314564Sdim const int wordsize = 4; 1032314564Sdim int mode = function_info.encoding & UNWIND_X86_MODE_MASK; 1033314564Sdim switch (mode) { 1034314564Sdim case UNWIND_X86_MODE_EBP_FRAME: { 1035314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset( 1036314564Sdim translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize); 1037314564Sdim row->SetOffset(0); 1038314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp, 1039314564Sdim wordsize * -2, true); 1040314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip, 1041314564Sdim wordsize * -1, true); 1042314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true); 1043278332Semaste 1044314564Sdim uint32_t saved_registers_offset = 1045314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET); 1046309124Sdim 1047314564Sdim uint32_t saved_registers_locations = 1048314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS); 1049278332Semaste 1050314564Sdim saved_registers_offset += 2; 1051278332Semaste 1052314564Sdim for (int i = 0; i < 5; i++) { 1053314564Sdim uint32_t regnum = saved_registers_locations & 0x7; 1054314564Sdim switch (regnum) { 1055314564Sdim case UNWIND_X86_REG_NONE: 1056278332Semaste break; 1057314564Sdim case UNWIND_X86_REG_EBX: 1058314564Sdim case UNWIND_X86_REG_ECX: 1059314564Sdim case UNWIND_X86_REG_EDX: 1060314564Sdim case UNWIND_X86_REG_EDI: 1061314564Sdim case UNWIND_X86_REG_ESI: 1062314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1063314564Sdim translate_to_eh_frame_regnum_i386(regnum), 1064314564Sdim wordsize * -saved_registers_offset, true); 1065314564Sdim break; 1066314564Sdim } 1067314564Sdim saved_registers_offset--; 1068314564Sdim saved_registers_locations >>= 3; 1069314564Sdim } 1070314564Sdim unwind_plan.AppendRow(row); 1071314564Sdim return true; 1072314564Sdim } break; 1073278332Semaste 1074314564Sdim case UNWIND_X86_MODE_STACK_IND: 1075314564Sdim case UNWIND_X86_MODE_STACK_IMMD: { 1076314564Sdim uint32_t stack_size = 1077314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1078314564Sdim uint32_t register_count = EXTRACT_BITS( 1079314564Sdim function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); 1080314564Sdim uint32_t permutation = EXTRACT_BITS( 1081314564Sdim function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); 1082278332Semaste 1083314564Sdim if (mode == UNWIND_X86_MODE_STACK_IND && 1084314564Sdim function_info.valid_range_offset_start != 0) { 1085314564Sdim uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding, 1086314564Sdim UNWIND_X86_FRAMELESS_STACK_ADJUST); 1087278332Semaste 1088314564Sdim // offset into the function instructions; 0 == beginning of first 1089314564Sdim // instruction 1090314564Sdim uint32_t offset_to_subl_insn = 1091314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1092278332Semaste 1093314564Sdim SectionList *sl = m_objfile.GetSectionList(); 1094314564Sdim if (sl) { 1095314564Sdim ProcessSP process_sp = target.GetProcessSP(); 1096314564Sdim if (process_sp) { 1097314564Sdim Address subl_payload_addr(function_info.valid_range_offset_start, sl); 1098314564Sdim subl_payload_addr.Slide(offset_to_subl_insn); 1099321369Sdim Status error; 1100314564Sdim uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory( 1101314564Sdim subl_payload_addr.GetLoadAddress(&target), 4, 0, error); 1102314564Sdim if (large_stack_size != 0 && error.Success()) { 1103314564Sdim // Got the large stack frame size correctly - use it 1104314564Sdim stack_size = large_stack_size + (stack_adjust * wordsize); 1105314564Sdim } else { 1106314564Sdim return false; 1107314564Sdim } 1108314564Sdim } else { 1109314564Sdim return false; 1110314564Sdim } 1111314564Sdim } else { 1112314564Sdim return false; 1113314564Sdim } 1114314564Sdim } 1115278332Semaste 1116314564Sdim int32_t offset = 1117314564Sdim mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize; 1118314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset); 1119314564Sdim row->SetOffset(0); 1120314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip, 1121314564Sdim wordsize * -1, true); 1122314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true); 1123309124Sdim 1124314564Sdim if (register_count > 0) { 1125278332Semaste 1126314564Sdim // We need to include (up to) 6 registers in 10 bits. 1127314564Sdim // That would be 18 bits if we just used 3 bits per reg to indicate 1128314564Sdim // the order they're saved on the stack. 1129314564Sdim // 1130314564Sdim // This is done with Lehmer code permutation, e.g. see 1131314564Sdim // http://stackoverflow.com/questions/1506078/fast-permutation-number-permutation-mapping-algorithms 1132314564Sdim int permunreg[6] = {0, 0, 0, 0, 0, 0}; 1133278332Semaste 1134314564Sdim // This decodes the variable-base number in the 10 bits 1135314564Sdim // and gives us the Lehmer code sequence which can then 1136314564Sdim // be decoded. 1137278332Semaste 1138314564Sdim switch (register_count) { 1139314564Sdim case 6: 1140314564Sdim permunreg[0] = permutation / 120; // 120 == 5! 1141314564Sdim permutation -= (permunreg[0] * 120); 1142314564Sdim permunreg[1] = permutation / 24; // 24 == 4! 1143314564Sdim permutation -= (permunreg[1] * 24); 1144314564Sdim permunreg[2] = permutation / 6; // 6 == 3! 1145314564Sdim permutation -= (permunreg[2] * 6); 1146314564Sdim permunreg[3] = permutation / 2; // 2 == 2! 1147314564Sdim permutation -= (permunreg[3] * 2); 1148314564Sdim permunreg[4] = permutation; // 1 == 1! 1149314564Sdim permunreg[5] = 0; 1150314564Sdim break; 1151314564Sdim case 5: 1152314564Sdim permunreg[0] = permutation / 120; 1153314564Sdim permutation -= (permunreg[0] * 120); 1154314564Sdim permunreg[1] = permutation / 24; 1155314564Sdim permutation -= (permunreg[1] * 24); 1156314564Sdim permunreg[2] = permutation / 6; 1157314564Sdim permutation -= (permunreg[2] * 6); 1158314564Sdim permunreg[3] = permutation / 2; 1159314564Sdim permutation -= (permunreg[3] * 2); 1160314564Sdim permunreg[4] = permutation; 1161314564Sdim break; 1162314564Sdim case 4: 1163314564Sdim permunreg[0] = permutation / 60; 1164314564Sdim permutation -= (permunreg[0] * 60); 1165314564Sdim permunreg[1] = permutation / 12; 1166314564Sdim permutation -= (permunreg[1] * 12); 1167314564Sdim permunreg[2] = permutation / 3; 1168314564Sdim permutation -= (permunreg[2] * 3); 1169314564Sdim permunreg[3] = permutation; 1170314564Sdim break; 1171314564Sdim case 3: 1172314564Sdim permunreg[0] = permutation / 20; 1173314564Sdim permutation -= (permunreg[0] * 20); 1174314564Sdim permunreg[1] = permutation / 4; 1175314564Sdim permutation -= (permunreg[1] * 4); 1176314564Sdim permunreg[2] = permutation; 1177314564Sdim break; 1178314564Sdim case 2: 1179314564Sdim permunreg[0] = permutation / 5; 1180314564Sdim permutation -= (permunreg[0] * 5); 1181314564Sdim permunreg[1] = permutation; 1182314564Sdim break; 1183314564Sdim case 1: 1184314564Sdim permunreg[0] = permutation; 1185314564Sdim break; 1186314564Sdim } 1187309124Sdim 1188314564Sdim // Decode the Lehmer code for this permutation of 1189314564Sdim // the registers v. http://en.wikipedia.org/wiki/Lehmer_code 1190278332Semaste 1191314564Sdim int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, 1192314564Sdim UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, 1193314564Sdim UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE}; 1194314564Sdim bool used[7] = {false, false, false, false, false, false, false}; 1195314564Sdim for (uint32_t i = 0; i < register_count; i++) { 1196314564Sdim int renum = 0; 1197314564Sdim for (int j = 1; j < 7; j++) { 1198314564Sdim if (used[j] == false) { 1199314564Sdim if (renum == permunreg[i]) { 1200314564Sdim registers[i] = j; 1201314564Sdim used[j] = true; 1202314564Sdim break; 1203278332Semaste } 1204314564Sdim renum++; 1205314564Sdim } 1206278332Semaste } 1207314564Sdim } 1208278332Semaste 1209314564Sdim uint32_t saved_registers_offset = 1; 1210314564Sdim saved_registers_offset++; 1211314564Sdim 1212314564Sdim for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) { 1213314564Sdim switch (registers[i]) { 1214314564Sdim case UNWIND_X86_REG_NONE: 1215314564Sdim break; 1216314564Sdim case UNWIND_X86_REG_EBX: 1217314564Sdim case UNWIND_X86_REG_ECX: 1218314564Sdim case UNWIND_X86_REG_EDX: 1219314564Sdim case UNWIND_X86_REG_EDI: 1220314564Sdim case UNWIND_X86_REG_ESI: 1221314564Sdim case UNWIND_X86_REG_EBP: 1222314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1223314564Sdim translate_to_eh_frame_regnum_i386(registers[i]), 1224314564Sdim wordsize * -saved_registers_offset, true); 1225314564Sdim saved_registers_offset++; 1226314564Sdim break; 1227278332Semaste } 1228314564Sdim } 1229278332Semaste } 1230314564Sdim 1231314564Sdim unwind_plan.AppendRow(row); 1232314564Sdim return true; 1233314564Sdim } break; 1234314564Sdim 1235314564Sdim case UNWIND_X86_MODE_DWARF: { 1236278332Semaste return false; 1237314564Sdim } break; 1238314564Sdim } 1239314564Sdim return false; 1240278332Semaste} 1241309124Sdim 1242314564Sdim// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)" 1243314564Sdim// doc by ARM 1244309124Sdim 1245309124Sdimenum arm64_eh_regnum { 1246314564Sdim x19 = 19, 1247314564Sdim x20 = 20, 1248314564Sdim x21 = 21, 1249314564Sdim x22 = 22, 1250314564Sdim x23 = 23, 1251314564Sdim x24 = 24, 1252314564Sdim x25 = 25, 1253314564Sdim x26 = 26, 1254314564Sdim x27 = 27, 1255314564Sdim x28 = 28, 1256309124Sdim 1257314564Sdim fp = 29, 1258314564Sdim ra = 30, 1259314564Sdim sp = 31, 1260314564Sdim pc = 32, 1261309124Sdim 1262314564Sdim // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s 1263314564Sdim // for the 64-bit 1264314564Sdim // fp regs. Normally in DWARF it's context sensitive - so it knows it is 1265314564Sdim // fetching a 1266314564Sdim // 32- or 64-bit quantity from reg v8 to indicate s0 or d0 - but the unwinder 1267314564Sdim // is operating 1268314564Sdim // at a lower level and we'd try to fetch 128 bits if we were told that v8 1269314564Sdim // were stored on 1270314564Sdim // the stack... 1271314564Sdim v8 = 72, 1272314564Sdim v9 = 73, 1273314564Sdim v10 = 74, 1274314564Sdim v11 = 75, 1275314564Sdim v12 = 76, 1276314564Sdim v13 = 77, 1277314564Sdim v14 = 78, 1278314564Sdim v15 = 79, 1279309124Sdim}; 1280309124Sdim 1281309124Sdimenum arm_eh_regnum { 1282314564Sdim arm_r0 = 0, 1283314564Sdim arm_r1 = 1, 1284314564Sdim arm_r2 = 2, 1285314564Sdim arm_r3 = 3, 1286314564Sdim arm_r4 = 4, 1287314564Sdim arm_r5 = 5, 1288314564Sdim arm_r6 = 6, 1289314564Sdim arm_r7 = 7, 1290314564Sdim arm_r8 = 8, 1291314564Sdim arm_r9 = 9, 1292314564Sdim arm_r10 = 10, 1293314564Sdim arm_r11 = 11, 1294314564Sdim arm_r12 = 12, 1295309124Sdim 1296314564Sdim arm_sp = 13, 1297314564Sdim arm_lr = 14, 1298314564Sdim arm_pc = 15, 1299309124Sdim 1300314564Sdim arm_d0 = 256, 1301314564Sdim arm_d1 = 257, 1302314564Sdim arm_d2 = 258, 1303314564Sdim arm_d3 = 259, 1304314564Sdim arm_d4 = 260, 1305314564Sdim arm_d5 = 261, 1306314564Sdim arm_d6 = 262, 1307314564Sdim arm_d7 = 263, 1308314564Sdim arm_d8 = 264, 1309314564Sdim arm_d9 = 265, 1310314564Sdim arm_d10 = 266, 1311314564Sdim arm_d11 = 267, 1312314564Sdim arm_d12 = 268, 1313314564Sdim arm_d13 = 269, 1314314564Sdim arm_d14 = 270, 1315309124Sdim}; 1316309124Sdim 1317314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target, 1318314564Sdim FunctionInfo &function_info, 1319314564Sdim UnwindPlan &unwind_plan, 1320314564Sdim Address pc_or_function_start) { 1321314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1322314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1323314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1324314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1325309124Sdim 1326314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1327314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1328309124Sdim 1329314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1330309124Sdim 1331314564Sdim const int wordsize = 8; 1332314564Sdim int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK; 1333309124Sdim 1334314564Sdim if (mode == UNWIND_ARM64_MODE_DWARF) 1335314564Sdim return false; 1336309124Sdim 1337314564Sdim if (mode == UNWIND_ARM64_MODE_FRAMELESS) { 1338314564Sdim row->SetOffset(0); 1339309124Sdim 1340314564Sdim uint32_t stack_size = 1341314564Sdim (EXTRACT_BITS(function_info.encoding, 1342314564Sdim UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) * 1343314564Sdim 16; 1344309124Sdim 1345314564Sdim // Our previous Call Frame Address is the stack pointer plus the stack size 1346314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size); 1347309124Sdim 1348314564Sdim // Our previous PC is in the LR 1349314564Sdim row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra, 1350314564Sdim true); 1351309124Sdim 1352314564Sdim unwind_plan.AppendRow(row); 1353314564Sdim return true; 1354314564Sdim } 1355309124Sdim 1356314564Sdim // Should not be possible 1357314564Sdim if (mode != UNWIND_ARM64_MODE_FRAME) 1358314564Sdim return false; 1359309124Sdim 1360314564Sdim // mode == UNWIND_ARM64_MODE_FRAME 1361309124Sdim 1362314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize); 1363314564Sdim row->SetOffset(0); 1364314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2, 1365314564Sdim true); 1366314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1, 1367314564Sdim true); 1368314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true); 1369309124Sdim 1370314564Sdim int reg_pairs_saved_count = 1; 1371309124Sdim 1372314564Sdim uint32_t saved_register_bits = function_info.encoding & 0xfff; 1373309124Sdim 1374314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) { 1375314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1376314564Sdim cfa_offset -= wordsize; 1377314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset, 1378314564Sdim true); 1379314564Sdim cfa_offset -= wordsize; 1380314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset, 1381314564Sdim true); 1382314564Sdim reg_pairs_saved_count++; 1383314564Sdim } 1384309124Sdim 1385314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) { 1386314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1387314564Sdim cfa_offset -= wordsize; 1388314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset, 1389314564Sdim true); 1390314564Sdim cfa_offset -= wordsize; 1391314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset, 1392314564Sdim true); 1393314564Sdim reg_pairs_saved_count++; 1394314564Sdim } 1395309124Sdim 1396314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) { 1397314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1398314564Sdim cfa_offset -= wordsize; 1399314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset, 1400314564Sdim true); 1401314564Sdim cfa_offset -= wordsize; 1402314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset, 1403314564Sdim true); 1404314564Sdim reg_pairs_saved_count++; 1405314564Sdim } 1406309124Sdim 1407314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) { 1408314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1409314564Sdim cfa_offset -= wordsize; 1410314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset, 1411314564Sdim true); 1412314564Sdim cfa_offset -= wordsize; 1413314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset, 1414314564Sdim true); 1415314564Sdim reg_pairs_saved_count++; 1416314564Sdim } 1417309124Sdim 1418314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) { 1419314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1420314564Sdim cfa_offset -= wordsize; 1421314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset, 1422314564Sdim true); 1423314564Sdim cfa_offset -= wordsize; 1424314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset, 1425314564Sdim true); 1426314564Sdim reg_pairs_saved_count++; 1427314564Sdim } 1428309124Sdim 1429314564Sdim // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits 1430314564Sdim // off the stack; 1431314564Sdim // not sure if we have a good way to represent the 64-bitness of these saves. 1432309124Sdim 1433314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) { 1434314564Sdim reg_pairs_saved_count++; 1435314564Sdim } 1436314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) { 1437314564Sdim reg_pairs_saved_count++; 1438314564Sdim } 1439314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) { 1440314564Sdim reg_pairs_saved_count++; 1441314564Sdim } 1442314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) { 1443314564Sdim reg_pairs_saved_count++; 1444314564Sdim } 1445309124Sdim 1446314564Sdim unwind_plan.AppendRow(row); 1447314564Sdim return true; 1448309124Sdim} 1449309124Sdim 1450314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target, 1451314564Sdim FunctionInfo &function_info, 1452314564Sdim UnwindPlan &unwind_plan, 1453314564Sdim Address pc_or_function_start) { 1454314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1455314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1456314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1457314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1458309124Sdim 1459314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1460314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1461309124Sdim 1462314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1463309124Sdim 1464314564Sdim const int wordsize = 4; 1465314564Sdim int mode = function_info.encoding & UNWIND_ARM_MODE_MASK; 1466309124Sdim 1467314564Sdim if (mode == UNWIND_ARM_MODE_DWARF) 1468314564Sdim return false; 1469309124Sdim 1470314564Sdim uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding, 1471314564Sdim UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) * 1472314564Sdim wordsize; 1473309124Sdim 1474314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7, 1475314564Sdim (2 * wordsize) + stack_adjust); 1476314564Sdim row->SetOffset(0); 1477314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1478314564Sdim arm_r7, (wordsize * -2) - stack_adjust, true); 1479314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1480314564Sdim arm_pc, (wordsize * -1) - stack_adjust, true); 1481314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true); 1482309124Sdim 1483314564Sdim int cfa_offset = -stack_adjust - (2 * wordsize); 1484309124Sdim 1485314564Sdim uint32_t saved_register_bits = function_info.encoding & 0xff; 1486309124Sdim 1487314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) { 1488314564Sdim cfa_offset -= wordsize; 1489314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true); 1490314564Sdim } 1491309124Sdim 1492314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) { 1493314564Sdim cfa_offset -= wordsize; 1494314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true); 1495314564Sdim } 1496309124Sdim 1497314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) { 1498314564Sdim cfa_offset -= wordsize; 1499314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true); 1500314564Sdim } 1501309124Sdim 1502314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) { 1503314564Sdim cfa_offset -= wordsize; 1504314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true); 1505314564Sdim } 1506309124Sdim 1507314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) { 1508314564Sdim cfa_offset -= wordsize; 1509314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true); 1510314564Sdim } 1511309124Sdim 1512314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) { 1513314564Sdim cfa_offset -= wordsize; 1514314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true); 1515314564Sdim } 1516309124Sdim 1517314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) { 1518314564Sdim cfa_offset -= wordsize; 1519314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true); 1520314564Sdim } 1521309124Sdim 1522314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) { 1523314564Sdim cfa_offset -= wordsize; 1524314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true); 1525314564Sdim } 1526309124Sdim 1527314564Sdim if (mode == UNWIND_ARM_MODE_FRAME_D) { 1528314564Sdim uint32_t d_reg_bits = 1529314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK); 1530314564Sdim switch (d_reg_bits) { 1531314564Sdim case 0: 1532314564Sdim // vpush {d8} 1533314564Sdim cfa_offset -= 8; 1534314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1535314564Sdim break; 1536314564Sdim case 1: 1537314564Sdim // vpush {d10} 1538314564Sdim // vpush {d8} 1539314564Sdim cfa_offset -= 8; 1540314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1541314564Sdim cfa_offset -= 8; 1542314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1543314564Sdim break; 1544314564Sdim case 2: 1545314564Sdim // vpush {d12} 1546314564Sdim // vpush {d10} 1547314564Sdim // vpush {d8} 1548314564Sdim cfa_offset -= 8; 1549314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1550314564Sdim cfa_offset -= 8; 1551314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1552314564Sdim cfa_offset -= 8; 1553314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1554314564Sdim break; 1555314564Sdim case 3: 1556314564Sdim // vpush {d14} 1557314564Sdim // vpush {d12} 1558314564Sdim // vpush {d10} 1559314564Sdim // vpush {d8} 1560314564Sdim cfa_offset -= 8; 1561314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1562314564Sdim cfa_offset -= 8; 1563314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1564314564Sdim cfa_offset -= 8; 1565314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1566314564Sdim cfa_offset -= 8; 1567314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1568314564Sdim break; 1569314564Sdim case 4: 1570314564Sdim // vpush {d14} 1571314564Sdim // vpush {d12} 1572314564Sdim // sp = (sp - 24) & (-16); 1573314564Sdim // vst {d8, d9, d10} 1574314564Sdim cfa_offset -= 8; 1575314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1576314564Sdim cfa_offset -= 8; 1577314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1578309124Sdim 1579314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1580314564Sdim // alignment short of 1581314564Sdim // coming up with some DWARF location description. 1582309124Sdim 1583314564Sdim break; 1584314564Sdim case 5: 1585314564Sdim // vpush {d14} 1586314564Sdim // sp = (sp - 40) & (-16); 1587314564Sdim // vst {d8, d9, d10, d11} 1588314564Sdim // vst {d12} 1589309124Sdim 1590314564Sdim cfa_offset -= 8; 1591314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1592309124Sdim 1593314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1594314564Sdim // alignment short of 1595314564Sdim // coming up with some DWARF location description. 1596309124Sdim 1597314564Sdim break; 1598314564Sdim case 6: 1599314564Sdim // sp = (sp - 56) & (-16); 1600314564Sdim // vst {d8, d9, d10, d11} 1601314564Sdim // vst {d12, d13, d14} 1602309124Sdim 1603314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1604314564Sdim // alignment short of 1605314564Sdim // coming up with some DWARF location description. 1606309124Sdim 1607314564Sdim break; 1608314564Sdim case 7: 1609314564Sdim // sp = (sp - 64) & (-16); 1610314564Sdim // vst {d8, d9, d10, d11} 1611314564Sdim // vst {d12, d13, d14, d15} 1612309124Sdim 1613314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1614314564Sdim // alignment short of 1615314564Sdim // coming up with some DWARF location description. 1616309124Sdim 1617314564Sdim break; 1618309124Sdim } 1619314564Sdim } 1620309124Sdim 1621314564Sdim unwind_plan.AppendRow(row); 1622314564Sdim return true; 1623309124Sdim} 1624