1278332Semaste//===-- CompactUnwindInfo.cpp -----------------------------------*- C++ -*-===// 2278332Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6278332Semaste// 7278332Semaste//===----------------------------------------------------------------------===// 8278332Semaste 9327952Sdim#include "lldb/Symbol/CompactUnwindInfo.h" 10278332Semaste#include "lldb/Core/Module.h" 11278332Semaste#include "lldb/Core/Section.h" 12278332Semaste#include "lldb/Symbol/ObjectFile.h" 13278332Semaste#include "lldb/Symbol/UnwindPlan.h" 14278332Semaste#include "lldb/Target/Process.h" 15278332Semaste#include "lldb/Target/Target.h" 16327952Sdim#include "lldb/Utility/ArchSpec.h" 17321369Sdim#include "lldb/Utility/DataBufferHeap.h" 18321369Sdim#include "lldb/Utility/Log.h" 19321369Sdim#include "lldb/Utility/StreamString.h" 20278332Semaste 21278332Semaste#include "llvm/Support/MathExtras.h" 22278332Semaste 23353358Sdim#include <algorithm> 24353358Sdim#include <memory> 25353358Sdim 26278332Semasteusing namespace lldb; 27278332Semasteusing namespace lldb_private; 28278332Semaste 29278332Semastenamespace lldb_private { 30278332Semaste 31314564Sdim// Constants from <mach-o/compact_unwind_encoding.h> 32278332Semaste 33314564SdimFLAGS_ANONYMOUS_ENUM(){ 34314564Sdim UNWIND_IS_NOT_FUNCTION_START = 0x80000000, UNWIND_HAS_LSDA = 0x40000000, 35314564Sdim UNWIND_PERSONALITY_MASK = 0x30000000, 36314564Sdim}; 37278332Semaste 38314564SdimFLAGS_ANONYMOUS_ENUM(){ 39314564Sdim UNWIND_X86_MODE_MASK = 0x0F000000, 40314564Sdim UNWIND_X86_MODE_EBP_FRAME = 0x01000000, 41314564Sdim UNWIND_X86_MODE_STACK_IMMD = 0x02000000, 42314564Sdim UNWIND_X86_MODE_STACK_IND = 0x03000000, 43314564Sdim UNWIND_X86_MODE_DWARF = 0x04000000, 44278332Semaste 45314564Sdim UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, 46314564Sdim UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, 47278332Semaste 48314564Sdim UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, 49314564Sdim UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, 50314564Sdim UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 51314564Sdim UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 52278332Semaste 53314564Sdim UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, 54314564Sdim}; 55278332Semaste 56314564Sdimenum { 57314564Sdim UNWIND_X86_REG_NONE = 0, 58314564Sdim UNWIND_X86_REG_EBX = 1, 59314564Sdim UNWIND_X86_REG_ECX = 2, 60314564Sdim UNWIND_X86_REG_EDX = 3, 61314564Sdim UNWIND_X86_REG_EDI = 4, 62314564Sdim UNWIND_X86_REG_ESI = 5, 63314564Sdim UNWIND_X86_REG_EBP = 6, 64314564Sdim}; 65288943Sdim 66314564SdimFLAGS_ANONYMOUS_ENUM(){ 67314564Sdim UNWIND_X86_64_MODE_MASK = 0x0F000000, 68314564Sdim UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000, 69314564Sdim UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, 70314564Sdim UNWIND_X86_64_MODE_STACK_IND = 0x03000000, 71314564Sdim UNWIND_X86_64_MODE_DWARF = 0x04000000, 72278332Semaste 73314564Sdim UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, 74314564Sdim UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, 75278332Semaste 76314564Sdim UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000, 77314564Sdim UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000, 78314564Sdim UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00, 79314564Sdim UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, 80278332Semaste 81314564Sdim UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 82314564Sdim}; 83278332Semaste 84314564Sdimenum { 85314564Sdim UNWIND_X86_64_REG_NONE = 0, 86314564Sdim UNWIND_X86_64_REG_RBX = 1, 87314564Sdim UNWIND_X86_64_REG_R12 = 2, 88314564Sdim UNWIND_X86_64_REG_R13 = 3, 89314564Sdim UNWIND_X86_64_REG_R14 = 4, 90314564Sdim UNWIND_X86_64_REG_R15 = 5, 91314564Sdim UNWIND_X86_64_REG_RBP = 6, 92314564Sdim}; 93309124Sdim 94314564SdimFLAGS_ANONYMOUS_ENUM(){ 95314564Sdim UNWIND_ARM64_MODE_MASK = 0x0F000000, 96314564Sdim UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, 97314564Sdim UNWIND_ARM64_MODE_DWARF = 0x03000000, 98314564Sdim UNWIND_ARM64_MODE_FRAME = 0x04000000, 99309124Sdim 100314564Sdim UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, 101314564Sdim UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, 102314564Sdim UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, 103314564Sdim UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, 104314564Sdim UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, 105314564Sdim UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, 106314564Sdim UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, 107314564Sdim UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, 108314564Sdim UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, 109309124Sdim 110314564Sdim UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, 111314564Sdim UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, 112314564Sdim}; 113309124Sdim 114314564SdimFLAGS_ANONYMOUS_ENUM(){ 115314564Sdim UNWIND_ARM_MODE_MASK = 0x0F000000, 116314564Sdim UNWIND_ARM_MODE_FRAME = 0x01000000, 117314564Sdim UNWIND_ARM_MODE_FRAME_D = 0x02000000, 118314564Sdim UNWIND_ARM_MODE_DWARF = 0x04000000, 119309124Sdim 120314564Sdim UNWIND_ARM_FRAME_STACK_ADJUST_MASK = 0x00C00000, 121309124Sdim 122314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R4 = 0x00000001, 123314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R5 = 0x00000002, 124314564Sdim UNWIND_ARM_FRAME_FIRST_PUSH_R6 = 0x00000004, 125309124Sdim 126314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R8 = 0x00000008, 127314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R9 = 0x00000010, 128314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R10 = 0x00000020, 129314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R11 = 0x00000040, 130314564Sdim UNWIND_ARM_FRAME_SECOND_PUSH_R12 = 0x00000080, 131309124Sdim 132314564Sdim UNWIND_ARM_FRAME_D_REG_COUNT_MASK = 0x00000700, 133309124Sdim 134314564Sdim UNWIND_ARM_DWARF_SECTION_OFFSET = 0x00FFFFFF, 135314564Sdim}; 136288943Sdim} 137278332Semaste 138278332Semaste#ifndef UNWIND_SECOND_LEVEL_REGULAR 139278332Semaste#define UNWIND_SECOND_LEVEL_REGULAR 2 140278332Semaste#endif 141278332Semaste 142278332Semaste#ifndef UNWIND_SECOND_LEVEL_COMPRESSED 143278332Semaste#define UNWIND_SECOND_LEVEL_COMPRESSED 3 144278332Semaste#endif 145278332Semaste 146278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET 147314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF) 148278332Semaste#endif 149278332Semaste 150278332Semaste#ifndef UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX 151314564Sdim#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) \ 152314564Sdim ((entry >> 24) & 0xFF) 153278332Semaste#endif 154278332Semaste 155314564Sdim#define EXTRACT_BITS(value, mask) \ 156314564Sdim ((value >> \ 157314564Sdim llvm::countTrailingZeros(static_cast<uint32_t>(mask), llvm::ZB_Width)) & \ 158314564Sdim (((1 << llvm::countPopulation(static_cast<uint32_t>(mask)))) - 1)) 159278332Semaste 160309124Sdim// constructor 161278332Semaste 162309124SdimCompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp) 163314564Sdim : m_objfile(objfile), m_section_sp(section_sp), 164314564Sdim m_section_contents_if_encrypted(), m_mutex(), m_indexes(), 165314564Sdim m_indexes_computed(eLazyBoolCalculate), m_unwindinfo_data(), 166314564Sdim m_unwindinfo_data_computed(false), m_unwind_header() {} 167278332Semaste 168278332Semaste// destructor 169278332Semaste 170314564SdimCompactUnwindInfo::~CompactUnwindInfo() {} 171278332Semaste 172314564Sdimbool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr, 173314564Sdim UnwindPlan &unwind_plan) { 174314564Sdim if (!IsValid(target.GetProcessSP())) { 175314564Sdim return false; 176314564Sdim } 177314564Sdim FunctionInfo function_info; 178314564Sdim if (GetCompactUnwindInfoForFunction(target, addr, function_info)) { 179314564Sdim // shortcut return for functions that have no compact unwind 180314564Sdim if (function_info.encoding == 0) 181314564Sdim return false; 182278332Semaste 183344779Sdim if (ArchSpec arch = m_objfile.GetArchitecture()) { 184278332Semaste 185314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 186314564Sdim if (log && log->GetVerbose()) { 187314564Sdim StreamString strm; 188314564Sdim addr.Dump( 189353358Sdim &strm, nullptr, 190314564Sdim Address::DumpStyle::DumpStyleResolvedDescriptionNoFunctionArguments, 191314564Sdim Address::DumpStyle::DumpStyleFileAddress, 192314564Sdim arch.GetAddressByteSize()); 193360784Sdim LLDB_LOGF(log, "Got compact unwind encoding 0x%x for function %s", 194360784Sdim function_info.encoding, strm.GetData()); 195314564Sdim } 196278332Semaste 197314564Sdim if (function_info.valid_range_offset_start != 0 && 198314564Sdim function_info.valid_range_offset_end != 0) { 199314564Sdim SectionList *sl = m_objfile.GetSectionList(); 200314564Sdim if (sl) { 201314564Sdim addr_t func_range_start_file_addr = 202314564Sdim function_info.valid_range_offset_start + 203344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 204314564Sdim AddressRange func_range(func_range_start_file_addr, 205314564Sdim function_info.valid_range_offset_end - 206314564Sdim function_info.valid_range_offset_start, 207314564Sdim sl); 208314564Sdim unwind_plan.SetPlanValidAddressRange(func_range); 209314564Sdim } 210314564Sdim } 211278332Semaste 212314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::x86_64) { 213314564Sdim return CreateUnwindPlan_x86_64(target, function_info, unwind_plan, 214314564Sdim addr); 215314564Sdim } 216360784Sdim if (arch.GetTriple().getArch() == llvm::Triple::aarch64 || 217360784Sdim arch.GetTriple().getArch() == llvm::Triple::aarch64_32) { 218314564Sdim return CreateUnwindPlan_arm64(target, function_info, unwind_plan, addr); 219314564Sdim } 220314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::x86) { 221314564Sdim return CreateUnwindPlan_i386(target, function_info, unwind_plan, addr); 222314564Sdim } 223314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::arm || 224314564Sdim arch.GetTriple().getArch() == llvm::Triple::thumb) { 225314564Sdim return CreateUnwindPlan_armv7(target, function_info, unwind_plan, addr); 226314564Sdim } 227278332Semaste } 228314564Sdim } 229314564Sdim return false; 230278332Semaste} 231278332Semaste 232314564Sdimbool CompactUnwindInfo::IsValid(const ProcessSP &process_sp) { 233314564Sdim if (m_section_sp.get() == nullptr) 234314564Sdim return false; 235278332Semaste 236314564Sdim if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 237314564Sdim return true; 238278332Semaste 239314564Sdim ScanIndex(process_sp); 240278332Semaste 241314564Sdim return m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed; 242278332Semaste} 243278332Semaste 244314564Sdimvoid CompactUnwindInfo::ScanIndex(const ProcessSP &process_sp) { 245314564Sdim std::lock_guard<std::mutex> guard(m_mutex); 246314564Sdim if (m_indexes_computed == eLazyBoolYes && m_unwindinfo_data_computed) 247314564Sdim return; 248278332Semaste 249314564Sdim // We can't read the index for some reason. 250314564Sdim if (m_indexes_computed == eLazyBoolNo) { 251314564Sdim return; 252314564Sdim } 253278332Semaste 254314564Sdim Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); 255314564Sdim if (log) 256314564Sdim m_objfile.GetModule()->LogMessage( 257314564Sdim log, "Reading compact unwind first-level indexes"); 258278332Semaste 259344779Sdim if (!m_unwindinfo_data_computed) { 260314564Sdim if (m_section_sp->IsEncrypted()) { 261314564Sdim // Can't get section contents of a protected/encrypted section until we 262341825Sdim // have a live process and can read them out of memory. 263314564Sdim if (process_sp.get() == nullptr) 264314564Sdim return; 265353358Sdim m_section_contents_if_encrypted = 266353358Sdim std::make_shared<DataBufferHeap>(m_section_sp->GetByteSize(), 0); 267321369Sdim Status error; 268314564Sdim if (process_sp->ReadMemory( 269314564Sdim m_section_sp->GetLoadBaseAddress(&process_sp->GetTarget()), 270314564Sdim m_section_contents_if_encrypted->GetBytes(), 271314564Sdim m_section_sp->GetByteSize(), 272314564Sdim error) == m_section_sp->GetByteSize() && 273314564Sdim error.Success()) { 274314564Sdim m_unwindinfo_data.SetAddressByteSize( 275314564Sdim process_sp->GetTarget().GetArchitecture().GetAddressByteSize()); 276314564Sdim m_unwindinfo_data.SetByteOrder( 277314564Sdim process_sp->GetTarget().GetArchitecture().GetByteOrder()); 278314564Sdim m_unwindinfo_data.SetData(m_section_contents_if_encrypted, 0); 279314564Sdim } 280314564Sdim } else { 281314564Sdim m_objfile.ReadSectionData(m_section_sp.get(), m_unwindinfo_data); 282278332Semaste } 283314564Sdim if (m_unwindinfo_data.GetByteSize() != m_section_sp->GetByteSize()) 284314564Sdim return; 285314564Sdim m_unwindinfo_data_computed = true; 286314564Sdim } 287278332Semaste 288314564Sdim if (m_unwindinfo_data.GetByteSize() > 0) { 289314564Sdim offset_t offset = 0; 290278332Semaste 291314564Sdim // struct unwind_info_section_header 292314564Sdim // { 293314564Sdim // uint32_t version; // UNWIND_SECTION_VERSION 294314564Sdim // uint32_t commonEncodingsArraySectionOffset; 295314564Sdim // uint32_t commonEncodingsArrayCount; 296314564Sdim // uint32_t personalityArraySectionOffset; 297314564Sdim // uint32_t personalityArrayCount; 298314564Sdim // uint32_t indexSectionOffset; 299314564Sdim // uint32_t indexCount; 300309124Sdim 301314564Sdim m_unwind_header.version = m_unwindinfo_data.GetU32(&offset); 302314564Sdim m_unwind_header.common_encodings_array_offset = 303314564Sdim m_unwindinfo_data.GetU32(&offset); 304314564Sdim m_unwind_header.common_encodings_array_count = 305314564Sdim m_unwindinfo_data.GetU32(&offset); 306314564Sdim m_unwind_header.personality_array_offset = 307314564Sdim m_unwindinfo_data.GetU32(&offset); 308314564Sdim m_unwind_header.personality_array_count = m_unwindinfo_data.GetU32(&offset); 309314564Sdim uint32_t indexSectionOffset = m_unwindinfo_data.GetU32(&offset); 310278332Semaste 311314564Sdim uint32_t indexCount = m_unwindinfo_data.GetU32(&offset); 312278332Semaste 313314564Sdim if (m_unwind_header.common_encodings_array_offset > 314314564Sdim m_unwindinfo_data.GetByteSize() || 315314564Sdim m_unwind_header.personality_array_offset > 316314564Sdim m_unwindinfo_data.GetByteSize() || 317314564Sdim indexSectionOffset > m_unwindinfo_data.GetByteSize() || 318314564Sdim offset > m_unwindinfo_data.GetByteSize()) { 319314564Sdim Host::SystemLog(Host::eSystemLogError, "error: Invalid offset " 320314564Sdim "encountered in compact unwind " 321314564Sdim "info, skipping\n"); 322314564Sdim // don't trust anything from this compact_unwind section if it looks 323314564Sdim // blatantly invalid data in the header. 324314564Sdim m_indexes_computed = eLazyBoolNo; 325314564Sdim return; 326314564Sdim } 327278332Semaste 328341825Sdim // Parse the basic information from the indexes We wait to scan the second 329341825Sdim // level page info until it's needed 330278332Semaste 331341825Sdim // struct unwind_info_section_header_index_entry { 332314564Sdim // uint32_t functionOffset; 333314564Sdim // uint32_t secondLevelPagesSectionOffset; 334314564Sdim // uint32_t lsdaIndexArraySectionOffset; 335314564Sdim // }; 336278332Semaste 337314564Sdim bool clear_address_zeroth_bit = false; 338344779Sdim if (ArchSpec arch = m_objfile.GetArchitecture()) { 339314564Sdim if (arch.GetTriple().getArch() == llvm::Triple::arm || 340314564Sdim arch.GetTriple().getArch() == llvm::Triple::thumb) 341314564Sdim clear_address_zeroth_bit = true; 342314564Sdim } 343309124Sdim 344314564Sdim offset = indexSectionOffset; 345314564Sdim for (uint32_t idx = 0; idx < indexCount; idx++) { 346314564Sdim uint32_t function_offset = 347314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 348314564Sdim uint32_t second_level_offset = 349314564Sdim m_unwindinfo_data.GetU32(&offset); // secondLevelPagesSectionOffset 350314564Sdim uint32_t lsda_offset = 351314564Sdim m_unwindinfo_data.GetU32(&offset); // lsdaIndexArraySectionOffset 352278332Semaste 353314564Sdim if (second_level_offset > m_section_sp->GetByteSize() || 354314564Sdim lsda_offset > m_section_sp->GetByteSize()) { 355314564Sdim m_indexes_computed = eLazyBoolNo; 356314564Sdim } 357278332Semaste 358314564Sdim if (clear_address_zeroth_bit) 359314564Sdim function_offset &= ~1ull; 360309124Sdim 361314564Sdim UnwindIndex this_index; 362314564Sdim this_index.function_offset = function_offset; 363314564Sdim this_index.second_level = second_level_offset; 364314564Sdim this_index.lsda_array_start = lsda_offset; 365278332Semaste 366314564Sdim if (m_indexes.size() > 0) { 367314564Sdim m_indexes[m_indexes.size() - 1].lsda_array_end = lsda_offset; 368314564Sdim } 369278332Semaste 370314564Sdim if (second_level_offset == 0) { 371314564Sdim this_index.sentinal_entry = true; 372314564Sdim } 373278332Semaste 374314564Sdim m_indexes.push_back(this_index); 375278332Semaste } 376314564Sdim m_indexes_computed = eLazyBoolYes; 377314564Sdim } else { 378314564Sdim m_indexes_computed = eLazyBoolNo; 379314564Sdim } 380278332Semaste} 381278332Semaste 382314564Sdimuint32_t CompactUnwindInfo::GetLSDAForFunctionOffset(uint32_t lsda_offset, 383314564Sdim uint32_t lsda_count, 384314564Sdim uint32_t function_offset) { 385341825Sdim // struct unwind_info_section_header_lsda_index_entry { 386314564Sdim // uint32_t functionOffset; 387314564Sdim // uint32_t lsdaOffset; 388314564Sdim // }; 389278332Semaste 390314564Sdim offset_t first_entry = lsda_offset; 391314564Sdim uint32_t low = 0; 392314564Sdim uint32_t high = lsda_count; 393314564Sdim while (low < high) { 394314564Sdim uint32_t mid = (low + high) / 2; 395314564Sdim offset_t offset = first_entry + (mid * 8); 396314564Sdim uint32_t mid_func_offset = 397314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 398314564Sdim uint32_t mid_lsda_offset = m_unwindinfo_data.GetU32(&offset); // lsdaOffset 399314564Sdim if (mid_func_offset == function_offset) { 400314564Sdim return mid_lsda_offset; 401278332Semaste } 402314564Sdim if (mid_func_offset < function_offset) { 403314564Sdim low = mid + 1; 404314564Sdim } else { 405314564Sdim high = mid; 406314564Sdim } 407314564Sdim } 408314564Sdim return 0; 409278332Semaste} 410278332Semaste 411314564Sdimlldb::offset_t CompactUnwindInfo::BinarySearchRegularSecondPage( 412314564Sdim uint32_t entry_page_offset, uint32_t entry_count, uint32_t function_offset, 413314564Sdim uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) { 414314564Sdim // typedef uint32_t compact_unwind_encoding_t; 415341825Sdim // struct unwind_info_regular_second_level_entry { 416314564Sdim // uint32_t functionOffset; 417314564Sdim // compact_unwind_encoding_t encoding; 418278332Semaste 419314564Sdim offset_t first_entry = entry_page_offset; 420278332Semaste 421314564Sdim uint32_t low = 0; 422314564Sdim uint32_t high = entry_count; 423314564Sdim uint32_t last = high - 1; 424314564Sdim while (low < high) { 425314564Sdim uint32_t mid = (low + high) / 2; 426314564Sdim offset_t offset = first_entry + (mid * 8); 427314564Sdim uint32_t mid_func_offset = 428314564Sdim m_unwindinfo_data.GetU32(&offset); // functionOffset 429314564Sdim uint32_t next_func_offset = 0; 430314564Sdim if (mid < last) { 431314564Sdim offset = first_entry + ((mid + 1) * 8); 432314564Sdim next_func_offset = m_unwindinfo_data.GetU32(&offset); // functionOffset 433278332Semaste } 434314564Sdim if (mid_func_offset <= function_offset) { 435314564Sdim if (mid == last || (next_func_offset > function_offset)) { 436314564Sdim if (entry_func_start_offset) 437314564Sdim *entry_func_start_offset = mid_func_offset; 438314564Sdim if (mid != last && entry_func_end_offset) 439314564Sdim *entry_func_end_offset = next_func_offset; 440314564Sdim return first_entry + (mid * 8); 441314564Sdim } else { 442314564Sdim low = mid + 1; 443314564Sdim } 444314564Sdim } else { 445314564Sdim high = mid; 446314564Sdim } 447314564Sdim } 448314564Sdim return LLDB_INVALID_OFFSET; 449278332Semaste} 450278332Semaste 451314564Sdimuint32_t CompactUnwindInfo::BinarySearchCompressedSecondPage( 452314564Sdim uint32_t entry_page_offset, uint32_t entry_count, 453314564Sdim uint32_t function_offset_to_find, uint32_t function_offset_base, 454314564Sdim uint32_t *entry_func_start_offset, uint32_t *entry_func_end_offset) { 455314564Sdim offset_t first_entry = entry_page_offset; 456278332Semaste 457314564Sdim uint32_t low = 0; 458314564Sdim uint32_t high = entry_count; 459314564Sdim uint32_t last = high - 1; 460314564Sdim while (low < high) { 461314564Sdim uint32_t mid = (low + high) / 2; 462314564Sdim offset_t offset = first_entry + (mid * 4); 463314564Sdim uint32_t entry = m_unwindinfo_data.GetU32(&offset); // entry 464314564Sdim uint32_t mid_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry); 465314564Sdim mid_func_offset += function_offset_base; 466314564Sdim uint32_t next_func_offset = 0; 467314564Sdim if (mid < last) { 468314564Sdim offset = first_entry + ((mid + 1) * 4); 469314564Sdim uint32_t next_entry = m_unwindinfo_data.GetU32(&offset); // entry 470314564Sdim next_func_offset = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(next_entry); 471314564Sdim next_func_offset += function_offset_base; 472278332Semaste } 473314564Sdim if (mid_func_offset <= function_offset_to_find) { 474314564Sdim if (mid == last || (next_func_offset > function_offset_to_find)) { 475314564Sdim if (entry_func_start_offset) 476314564Sdim *entry_func_start_offset = mid_func_offset; 477314564Sdim if (mid != last && entry_func_end_offset) 478314564Sdim *entry_func_end_offset = next_func_offset; 479314564Sdim return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry); 480314564Sdim } else { 481314564Sdim low = mid + 1; 482314564Sdim } 483314564Sdim } else { 484314564Sdim high = mid; 485314564Sdim } 486314564Sdim } 487278332Semaste 488314564Sdim return UINT32_MAX; 489278332Semaste} 490278332Semaste 491314564Sdimbool CompactUnwindInfo::GetCompactUnwindInfoForFunction( 492314564Sdim Target &target, Address address, FunctionInfo &unwind_info) { 493314564Sdim unwind_info.encoding = 0; 494314564Sdim unwind_info.lsda_address.Clear(); 495314564Sdim unwind_info.personality_ptr_address.Clear(); 496278332Semaste 497314564Sdim if (!IsValid(target.GetProcessSP())) 498314564Sdim return false; 499278332Semaste 500314564Sdim addr_t text_section_file_address = LLDB_INVALID_ADDRESS; 501314564Sdim SectionList *sl = m_objfile.GetSectionList(); 502314564Sdim if (sl) { 503314564Sdim SectionSP text_sect = sl->FindSectionByType(eSectionTypeCode, true); 504314564Sdim if (text_sect.get()) { 505314564Sdim text_section_file_address = text_sect->GetFileAddress(); 506278332Semaste } 507314564Sdim } 508314564Sdim if (text_section_file_address == LLDB_INVALID_ADDRESS) 509314564Sdim return false; 510278332Semaste 511314564Sdim addr_t function_offset = 512344779Sdim address.GetFileAddress() - m_objfile.GetBaseAddress().GetFileAddress(); 513309124Sdim 514314564Sdim UnwindIndex key; 515314564Sdim key.function_offset = function_offset; 516309124Sdim 517314564Sdim std::vector<UnwindIndex>::const_iterator it; 518314564Sdim it = std::lower_bound(m_indexes.begin(), m_indexes.end(), key); 519314564Sdim if (it == m_indexes.end()) { 520314564Sdim return false; 521314564Sdim } 522278332Semaste 523314564Sdim if (it->function_offset != key.function_offset) { 524314564Sdim if (it != m_indexes.begin()) 525314564Sdim --it; 526314564Sdim } 527278332Semaste 528344779Sdim if (it->sentinal_entry) { 529314564Sdim return false; 530314564Sdim } 531278332Semaste 532314564Sdim auto next_it = it + 1; 533314564Sdim if (next_it != m_indexes.end()) { 534341825Sdim // initialize the function offset end range to be the start of the next 535341825Sdim // index offset. If we find an entry which is at the end of the index 536341825Sdim // table, this will establish the range end. 537314564Sdim unwind_info.valid_range_offset_end = next_it->function_offset; 538314564Sdim } 539278332Semaste 540314564Sdim offset_t second_page_offset = it->second_level; 541314564Sdim offset_t lsda_array_start = it->lsda_array_start; 542314564Sdim offset_t lsda_array_count = (it->lsda_array_end - it->lsda_array_start) / 8; 543278332Semaste 544314564Sdim offset_t offset = second_page_offset; 545314564Sdim uint32_t kind = m_unwindinfo_data.GetU32( 546314564Sdim &offset); // UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED 547278332Semaste 548314564Sdim if (kind == UNWIND_SECOND_LEVEL_REGULAR) { 549341825Sdim // struct unwind_info_regular_second_level_page_header { 550314564Sdim // uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR 551314564Sdim // uint16_t entryPageOffset; 552314564Sdim // uint16_t entryCount; 553278332Semaste 554314564Sdim // typedef uint32_t compact_unwind_encoding_t; 555341825Sdim // struct unwind_info_regular_second_level_entry { 556314564Sdim // uint32_t functionOffset; 557314564Sdim // compact_unwind_encoding_t encoding; 558278332Semaste 559314564Sdim uint16_t entry_page_offset = 560314564Sdim m_unwindinfo_data.GetU16(&offset); // entryPageOffset 561314564Sdim uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 562278332Semaste 563314564Sdim offset_t entry_offset = BinarySearchRegularSecondPage( 564314564Sdim second_page_offset + entry_page_offset, entry_count, function_offset, 565314564Sdim &unwind_info.valid_range_offset_start, 566314564Sdim &unwind_info.valid_range_offset_end); 567314564Sdim if (entry_offset == LLDB_INVALID_OFFSET) { 568314564Sdim return false; 569314564Sdim } 570314564Sdim entry_offset += 4; // skip over functionOffset 571314564Sdim unwind_info.encoding = m_unwindinfo_data.GetU32(&entry_offset); // encoding 572314564Sdim if (unwind_info.encoding & UNWIND_HAS_LSDA) { 573314564Sdim SectionList *sl = m_objfile.GetSectionList(); 574314564Sdim if (sl) { 575314564Sdim uint32_t lsda_offset = GetLSDAForFunctionOffset( 576314564Sdim lsda_array_start, lsda_array_count, function_offset); 577344779Sdim addr_t objfile_base_address = 578344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 579314564Sdim unwind_info.lsda_address.ResolveAddressUsingFileSections( 580344779Sdim objfile_base_address + lsda_offset, sl); 581314564Sdim } 582314564Sdim } 583314564Sdim if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) { 584314564Sdim uint32_t personality_index = 585314564Sdim EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK); 586278332Semaste 587314564Sdim if (personality_index > 0) { 588314564Sdim personality_index--; 589314564Sdim if (personality_index < m_unwind_header.personality_array_count) { 590314564Sdim offset_t offset = m_unwind_header.personality_array_offset; 591314564Sdim offset += 4 * personality_index; 592314564Sdim SectionList *sl = m_objfile.GetSectionList(); 593314564Sdim if (sl) { 594314564Sdim uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 595344779Sdim addr_t objfile_base_address = 596344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 597314564Sdim unwind_info.personality_ptr_address.ResolveAddressUsingFileSections( 598344779Sdim objfile_base_address + personality_offset, sl); 599314564Sdim } 600278332Semaste } 601314564Sdim } 602278332Semaste } 603314564Sdim return true; 604314564Sdim } else if (kind == UNWIND_SECOND_LEVEL_COMPRESSED) { 605341825Sdim // struct unwind_info_compressed_second_level_page_header { 606314564Sdim // uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED 607314564Sdim // uint16_t entryPageOffset; // offset from this 2nd lvl page 608314564Sdim // idx to array of entries 609314564Sdim // // (an entry has a function 610314564Sdim // offset and index into the 611314564Sdim // encodings) 612314564Sdim // // NB function offset from the 613314564Sdim // entry in the compressed page 614314564Sdim // // must be added to the index's 615314564Sdim // functionOffset value. 616314564Sdim // uint16_t entryCount; 617314564Sdim // uint16_t encodingsPageOffset; // offset from this 2nd lvl page 618314564Sdim // idx to array of encodings 619314564Sdim // uint16_t encodingsCount; 620278332Semaste 621314564Sdim uint16_t entry_page_offset = 622314564Sdim m_unwindinfo_data.GetU16(&offset); // entryPageOffset 623314564Sdim uint16_t entry_count = m_unwindinfo_data.GetU16(&offset); // entryCount 624314564Sdim uint16_t encodings_page_offset = 625314564Sdim m_unwindinfo_data.GetU16(&offset); // encodingsPageOffset 626314564Sdim uint16_t encodings_count = 627314564Sdim m_unwindinfo_data.GetU16(&offset); // encodingsCount 628278332Semaste 629314564Sdim uint32_t encoding_index = BinarySearchCompressedSecondPage( 630314564Sdim second_page_offset + entry_page_offset, entry_count, function_offset, 631314564Sdim it->function_offset, &unwind_info.valid_range_offset_start, 632314564Sdim &unwind_info.valid_range_offset_end); 633314564Sdim if (encoding_index == UINT32_MAX || 634314564Sdim encoding_index >= 635314564Sdim encodings_count + m_unwind_header.common_encodings_array_count) { 636314564Sdim return false; 637314564Sdim } 638314564Sdim uint32_t encoding = 0; 639314564Sdim if (encoding_index < m_unwind_header.common_encodings_array_count) { 640314564Sdim offset = m_unwind_header.common_encodings_array_offset + 641314564Sdim (encoding_index * sizeof(uint32_t)); 642314564Sdim encoding = m_unwindinfo_data.GetU32( 643314564Sdim &offset); // encoding entry from the commonEncodingsArray 644314564Sdim } else { 645314564Sdim uint32_t page_specific_entry_index = 646314564Sdim encoding_index - m_unwind_header.common_encodings_array_count; 647314564Sdim offset = second_page_offset + encodings_page_offset + 648314564Sdim (page_specific_entry_index * sizeof(uint32_t)); 649314564Sdim encoding = m_unwindinfo_data.GetU32( 650314564Sdim &offset); // encoding entry from the page-specific encoding array 651314564Sdim } 652314564Sdim if (encoding == 0) 653314564Sdim return false; 654278332Semaste 655314564Sdim unwind_info.encoding = encoding; 656314564Sdim if (unwind_info.encoding & UNWIND_HAS_LSDA) { 657314564Sdim SectionList *sl = m_objfile.GetSectionList(); 658314564Sdim if (sl) { 659314564Sdim uint32_t lsda_offset = GetLSDAForFunctionOffset( 660314564Sdim lsda_array_start, lsda_array_count, function_offset); 661344779Sdim addr_t objfile_base_address = 662344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 663314564Sdim unwind_info.lsda_address.ResolveAddressUsingFileSections( 664344779Sdim objfile_base_address + lsda_offset, sl); 665314564Sdim } 666314564Sdim } 667314564Sdim if (unwind_info.encoding & UNWIND_PERSONALITY_MASK) { 668314564Sdim uint32_t personality_index = 669314564Sdim EXTRACT_BITS(unwind_info.encoding, UNWIND_PERSONALITY_MASK); 670278332Semaste 671314564Sdim if (personality_index > 0) { 672314564Sdim personality_index--; 673314564Sdim if (personality_index < m_unwind_header.personality_array_count) { 674314564Sdim offset_t offset = m_unwind_header.personality_array_offset; 675314564Sdim offset += 4 * personality_index; 676314564Sdim SectionList *sl = m_objfile.GetSectionList(); 677314564Sdim if (sl) { 678314564Sdim uint32_t personality_offset = m_unwindinfo_data.GetU32(&offset); 679344779Sdim addr_t objfile_base_address = 680344779Sdim m_objfile.GetBaseAddress().GetFileAddress(); 681314564Sdim unwind_info.personality_ptr_address.ResolveAddressUsingFileSections( 682344779Sdim objfile_base_address + personality_offset, sl); 683314564Sdim } 684278332Semaste } 685314564Sdim } 686278332Semaste } 687314564Sdim return true; 688314564Sdim } 689314564Sdim return false; 690278332Semaste} 691278332Semaste 692278332Semasteenum x86_64_eh_regnum { 693314564Sdim rax = 0, 694314564Sdim rdx = 1, 695314564Sdim rcx = 2, 696314564Sdim rbx = 3, 697314564Sdim rsi = 4, 698314564Sdim rdi = 5, 699314564Sdim rbp = 6, 700314564Sdim rsp = 7, 701314564Sdim r8 = 8, 702314564Sdim r9 = 9, 703314564Sdim r10 = 10, 704314564Sdim r11 = 11, 705314564Sdim r12 = 12, 706314564Sdim r13 = 13, 707314564Sdim r14 = 14, 708314564Sdim r15 = 15, 709314564Sdim rip = 16 // this is officially the Return Address register number, but close 710314564Sdim // enough 711278332Semaste}; 712278332Semaste 713341825Sdim// Convert the compact_unwind_info.h register numbering scheme to 714341825Sdim// eRegisterKindEHFrame (eh_frame) register numbering scheme. 715314564Sdimuint32_t translate_to_eh_frame_regnum_x86_64(uint32_t unwind_regno) { 716314564Sdim switch (unwind_regno) { 717314564Sdim case UNWIND_X86_64_REG_RBX: 718314564Sdim return x86_64_eh_regnum::rbx; 719314564Sdim case UNWIND_X86_64_REG_R12: 720314564Sdim return x86_64_eh_regnum::r12; 721314564Sdim case UNWIND_X86_64_REG_R13: 722314564Sdim return x86_64_eh_regnum::r13; 723314564Sdim case UNWIND_X86_64_REG_R14: 724314564Sdim return x86_64_eh_regnum::r14; 725314564Sdim case UNWIND_X86_64_REG_R15: 726314564Sdim return x86_64_eh_regnum::r15; 727314564Sdim case UNWIND_X86_64_REG_RBP: 728314564Sdim return x86_64_eh_regnum::rbp; 729314564Sdim default: 730314564Sdim return LLDB_INVALID_REGNUM; 731314564Sdim } 732278332Semaste} 733278332Semaste 734314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target, 735314564Sdim FunctionInfo &function_info, 736314564Sdim UnwindPlan &unwind_plan, 737314564Sdim Address pc_or_function_start) { 738314564Sdim unwind_plan.SetSourceName("compact unwind info"); 739314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 740314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 741360784Sdim unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); 742314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 743278332Semaste 744314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 745314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 746278332Semaste 747314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 748278332Semaste 749314564Sdim const int wordsize = 8; 750314564Sdim int mode = function_info.encoding & UNWIND_X86_64_MODE_MASK; 751314564Sdim switch (mode) { 752314564Sdim case UNWIND_X86_64_MODE_RBP_FRAME: { 753314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset( 754314564Sdim translate_to_eh_frame_regnum_x86_64(UNWIND_X86_64_REG_RBP), 755314564Sdim 2 * wordsize); 756314564Sdim row->SetOffset(0); 757314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rbp, 758314564Sdim wordsize * -2, true); 759314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip, 760314564Sdim wordsize * -1, true); 761314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true); 762309124Sdim 763314564Sdim uint32_t saved_registers_offset = 764314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_OFFSET); 765278332Semaste 766314564Sdim uint32_t saved_registers_locations = 767314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); 768278332Semaste 769314564Sdim saved_registers_offset += 2; 770278332Semaste 771314564Sdim for (int i = 0; i < 5; i++) { 772314564Sdim uint32_t regnum = saved_registers_locations & 0x7; 773314564Sdim switch (regnum) { 774314564Sdim case UNWIND_X86_64_REG_NONE: 775278332Semaste break; 776314564Sdim case UNWIND_X86_64_REG_RBX: 777314564Sdim case UNWIND_X86_64_REG_R12: 778314564Sdim case UNWIND_X86_64_REG_R13: 779314564Sdim case UNWIND_X86_64_REG_R14: 780314564Sdim case UNWIND_X86_64_REG_R15: 781314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 782314564Sdim translate_to_eh_frame_regnum_x86_64(regnum), 783314564Sdim wordsize * -saved_registers_offset, true); 784278332Semaste break; 785314564Sdim } 786314564Sdim saved_registers_offset--; 787314564Sdim saved_registers_locations >>= 3; 788314564Sdim } 789314564Sdim unwind_plan.AppendRow(row); 790314564Sdim return true; 791314564Sdim } break; 792278332Semaste 793314564Sdim case UNWIND_X86_64_MODE_STACK_IND: { 794314564Sdim // The clang in Xcode 6 is emitting incorrect compact unwind encodings for 795341825Sdim // this style of unwind. It was fixed in llvm r217020. The clang in Xcode 796341825Sdim // 7 has this fixed. 797314564Sdim return false; 798314564Sdim } break; 799278332Semaste 800314564Sdim case UNWIND_X86_64_MODE_STACK_IMMD: { 801314564Sdim uint32_t stack_size = EXTRACT_BITS(function_info.encoding, 802314564Sdim UNWIND_X86_64_FRAMELESS_STACK_SIZE); 803314564Sdim uint32_t register_count = EXTRACT_BITS( 804314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); 805314564Sdim uint32_t permutation = EXTRACT_BITS( 806314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); 807278332Semaste 808314564Sdim if (mode == UNWIND_X86_64_MODE_STACK_IND && 809314564Sdim function_info.valid_range_offset_start != 0) { 810314564Sdim uint32_t stack_adjust = EXTRACT_BITS( 811314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); 812278332Semaste 813314564Sdim // offset into the function instructions; 0 == beginning of first 814314564Sdim // instruction 815314564Sdim uint32_t offset_to_subl_insn = EXTRACT_BITS( 816314564Sdim function_info.encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); 817278332Semaste 818314564Sdim SectionList *sl = m_objfile.GetSectionList(); 819314564Sdim if (sl) { 820314564Sdim ProcessSP process_sp = target.GetProcessSP(); 821314564Sdim if (process_sp) { 822314564Sdim Address subl_payload_addr(function_info.valid_range_offset_start, sl); 823314564Sdim subl_payload_addr.Slide(offset_to_subl_insn); 824321369Sdim Status error; 825314564Sdim uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory( 826314564Sdim subl_payload_addr.GetLoadAddress(&target), 4, 0, error); 827314564Sdim if (large_stack_size != 0 && error.Success()) { 828314564Sdim // Got the large stack frame size correctly - use it 829314564Sdim stack_size = large_stack_size + (stack_adjust * wordsize); 830314564Sdim } else { 831314564Sdim return false; 832314564Sdim } 833314564Sdim } else { 834314564Sdim return false; 835314564Sdim } 836314564Sdim } else { 837314564Sdim return false; 838314564Sdim } 839314564Sdim } 840288943Sdim 841314564Sdim int32_t offset = mode == UNWIND_X86_64_MODE_STACK_IND 842314564Sdim ? stack_size 843314564Sdim : stack_size * wordsize; 844314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(x86_64_eh_regnum::rsp, offset); 845278332Semaste 846314564Sdim row->SetOffset(0); 847314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(x86_64_eh_regnum::rip, 848314564Sdim wordsize * -1, true); 849314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(x86_64_eh_regnum::rsp, 0, true); 850278332Semaste 851314564Sdim if (register_count > 0) { 852278332Semaste 853341825Sdim // We need to include (up to) 6 registers in 10 bits. That would be 18 854341825Sdim // bits if we just used 3 bits per reg to indicate the order they're 855341825Sdim // saved on the stack. 856314564Sdim // 857314564Sdim // This is done with Lehmer code permutation, e.g. see 858341825Sdim // http://stackoverflow.com/questions/1506078/fast-permutation-number- 859341825Sdim // permutation-mapping-algorithms 860314564Sdim int permunreg[6] = {0, 0, 0, 0, 0, 0}; 861278332Semaste 862341825Sdim // This decodes the variable-base number in the 10 bits and gives us the 863341825Sdim // Lehmer code sequence which can then be decoded. 864309124Sdim 865314564Sdim switch (register_count) { 866314564Sdim case 6: 867314564Sdim permunreg[0] = permutation / 120; // 120 == 5! 868314564Sdim permutation -= (permunreg[0] * 120); 869314564Sdim permunreg[1] = permutation / 24; // 24 == 4! 870314564Sdim permutation -= (permunreg[1] * 24); 871314564Sdim permunreg[2] = permutation / 6; // 6 == 3! 872314564Sdim permutation -= (permunreg[2] * 6); 873314564Sdim permunreg[3] = permutation / 2; // 2 == 2! 874314564Sdim permutation -= (permunreg[3] * 2); 875314564Sdim permunreg[4] = permutation; // 1 == 1! 876314564Sdim permunreg[5] = 0; 877314564Sdim break; 878314564Sdim case 5: 879314564Sdim permunreg[0] = permutation / 120; 880314564Sdim permutation -= (permunreg[0] * 120); 881314564Sdim permunreg[1] = permutation / 24; 882314564Sdim permutation -= (permunreg[1] * 24); 883314564Sdim permunreg[2] = permutation / 6; 884314564Sdim permutation -= (permunreg[2] * 6); 885314564Sdim permunreg[3] = permutation / 2; 886314564Sdim permutation -= (permunreg[3] * 2); 887314564Sdim permunreg[4] = permutation; 888314564Sdim break; 889314564Sdim case 4: 890314564Sdim permunreg[0] = permutation / 60; 891314564Sdim permutation -= (permunreg[0] * 60); 892314564Sdim permunreg[1] = permutation / 12; 893314564Sdim permutation -= (permunreg[1] * 12); 894314564Sdim permunreg[2] = permutation / 3; 895314564Sdim permutation -= (permunreg[2] * 3); 896314564Sdim permunreg[3] = permutation; 897314564Sdim break; 898314564Sdim case 3: 899314564Sdim permunreg[0] = permutation / 20; 900314564Sdim permutation -= (permunreg[0] * 20); 901314564Sdim permunreg[1] = permutation / 4; 902314564Sdim permutation -= (permunreg[1] * 4); 903314564Sdim permunreg[2] = permutation; 904314564Sdim break; 905314564Sdim case 2: 906314564Sdim permunreg[0] = permutation / 5; 907314564Sdim permutation -= (permunreg[0] * 5); 908314564Sdim permunreg[1] = permutation; 909314564Sdim break; 910314564Sdim case 1: 911314564Sdim permunreg[0] = permutation; 912314564Sdim break; 913314564Sdim } 914278332Semaste 915341825Sdim // Decode the Lehmer code for this permutation of the registers v. 916341825Sdim // http://en.wikipedia.org/wiki/Lehmer_code 917278332Semaste 918314564Sdim int registers[6] = {UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, 919314564Sdim UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE, 920314564Sdim UNWIND_X86_64_REG_NONE, UNWIND_X86_64_REG_NONE}; 921314564Sdim bool used[7] = {false, false, false, false, false, false, false}; 922314564Sdim for (uint32_t i = 0; i < register_count; i++) { 923314564Sdim int renum = 0; 924314564Sdim for (int j = 1; j < 7; j++) { 925344779Sdim if (!used[j]) { 926314564Sdim if (renum == permunreg[i]) { 927314564Sdim registers[i] = j; 928314564Sdim used[j] = true; 929314564Sdim break; 930278332Semaste } 931314564Sdim renum++; 932314564Sdim } 933278332Semaste } 934314564Sdim } 935278332Semaste 936314564Sdim uint32_t saved_registers_offset = 1; 937314564Sdim saved_registers_offset++; 938278332Semaste 939314564Sdim for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) { 940314564Sdim switch (registers[i]) { 941314564Sdim case UNWIND_X86_64_REG_NONE: 942314564Sdim break; 943314564Sdim case UNWIND_X86_64_REG_RBX: 944314564Sdim case UNWIND_X86_64_REG_R12: 945314564Sdim case UNWIND_X86_64_REG_R13: 946314564Sdim case UNWIND_X86_64_REG_R14: 947314564Sdim case UNWIND_X86_64_REG_R15: 948314564Sdim case UNWIND_X86_64_REG_RBP: 949314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 950314564Sdim translate_to_eh_frame_regnum_x86_64(registers[i]), 951314564Sdim wordsize * -saved_registers_offset, true); 952314564Sdim saved_registers_offset++; 953314564Sdim break; 954278332Semaste } 955314564Sdim } 956278332Semaste } 957314564Sdim unwind_plan.AppendRow(row); 958314564Sdim return true; 959314564Sdim } break; 960314564Sdim 961314564Sdim case UNWIND_X86_64_MODE_DWARF: { 962278332Semaste return false; 963314564Sdim } break; 964314564Sdim 965314564Sdim case 0: { 966314564Sdim return false; 967314564Sdim } break; 968314564Sdim } 969314564Sdim return false; 970278332Semaste} 971278332Semaste 972278332Semasteenum i386_eh_regnum { 973314564Sdim eax = 0, 974314564Sdim ecx = 1, 975314564Sdim edx = 2, 976314564Sdim ebx = 3, 977314564Sdim ebp = 4, 978314564Sdim esp = 5, 979314564Sdim esi = 6, 980314564Sdim edi = 7, 981314564Sdim eip = 8 // this is officially the Return Address register number, but close 982314564Sdim // enough 983278332Semaste}; 984278332Semaste 985341825Sdim// Convert the compact_unwind_info.h register numbering scheme to 986341825Sdim// eRegisterKindEHFrame (eh_frame) register numbering scheme. 987314564Sdimuint32_t translate_to_eh_frame_regnum_i386(uint32_t unwind_regno) { 988314564Sdim switch (unwind_regno) { 989314564Sdim case UNWIND_X86_REG_EBX: 990314564Sdim return i386_eh_regnum::ebx; 991314564Sdim case UNWIND_X86_REG_ECX: 992314564Sdim return i386_eh_regnum::ecx; 993314564Sdim case UNWIND_X86_REG_EDX: 994314564Sdim return i386_eh_regnum::edx; 995314564Sdim case UNWIND_X86_REG_EDI: 996314564Sdim return i386_eh_regnum::edi; 997314564Sdim case UNWIND_X86_REG_ESI: 998314564Sdim return i386_eh_regnum::esi; 999314564Sdim case UNWIND_X86_REG_EBP: 1000314564Sdim return i386_eh_regnum::ebp; 1001314564Sdim default: 1002314564Sdim return LLDB_INVALID_REGNUM; 1003314564Sdim } 1004278332Semaste} 1005278332Semaste 1006314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target, 1007314564Sdim FunctionInfo &function_info, 1008314564Sdim UnwindPlan &unwind_plan, 1009314564Sdim Address pc_or_function_start) { 1010314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1011314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1012314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1013360784Sdim unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); 1014314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1015278332Semaste 1016314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1017314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1018278332Semaste 1019314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1020278332Semaste 1021314564Sdim const int wordsize = 4; 1022314564Sdim int mode = function_info.encoding & UNWIND_X86_MODE_MASK; 1023314564Sdim switch (mode) { 1024314564Sdim case UNWIND_X86_MODE_EBP_FRAME: { 1025314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset( 1026314564Sdim translate_to_eh_frame_regnum_i386(UNWIND_X86_REG_EBP), 2 * wordsize); 1027314564Sdim row->SetOffset(0); 1028314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::ebp, 1029314564Sdim wordsize * -2, true); 1030314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip, 1031314564Sdim wordsize * -1, true); 1032314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true); 1033278332Semaste 1034314564Sdim uint32_t saved_registers_offset = 1035314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_OFFSET); 1036309124Sdim 1037314564Sdim uint32_t saved_registers_locations = 1038314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_EBP_FRAME_REGISTERS); 1039278332Semaste 1040314564Sdim saved_registers_offset += 2; 1041278332Semaste 1042314564Sdim for (int i = 0; i < 5; i++) { 1043314564Sdim uint32_t regnum = saved_registers_locations & 0x7; 1044314564Sdim switch (regnum) { 1045314564Sdim case UNWIND_X86_REG_NONE: 1046278332Semaste break; 1047314564Sdim case UNWIND_X86_REG_EBX: 1048314564Sdim case UNWIND_X86_REG_ECX: 1049314564Sdim case UNWIND_X86_REG_EDX: 1050314564Sdim case UNWIND_X86_REG_EDI: 1051314564Sdim case UNWIND_X86_REG_ESI: 1052314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1053314564Sdim translate_to_eh_frame_regnum_i386(regnum), 1054314564Sdim wordsize * -saved_registers_offset, true); 1055314564Sdim break; 1056314564Sdim } 1057314564Sdim saved_registers_offset--; 1058314564Sdim saved_registers_locations >>= 3; 1059314564Sdim } 1060314564Sdim unwind_plan.AppendRow(row); 1061314564Sdim return true; 1062314564Sdim } break; 1063278332Semaste 1064314564Sdim case UNWIND_X86_MODE_STACK_IND: 1065314564Sdim case UNWIND_X86_MODE_STACK_IMMD: { 1066314564Sdim uint32_t stack_size = 1067314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1068314564Sdim uint32_t register_count = EXTRACT_BITS( 1069314564Sdim function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); 1070314564Sdim uint32_t permutation = EXTRACT_BITS( 1071314564Sdim function_info.encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); 1072278332Semaste 1073314564Sdim if (mode == UNWIND_X86_MODE_STACK_IND && 1074314564Sdim function_info.valid_range_offset_start != 0) { 1075314564Sdim uint32_t stack_adjust = EXTRACT_BITS(function_info.encoding, 1076314564Sdim UNWIND_X86_FRAMELESS_STACK_ADJUST); 1077278332Semaste 1078314564Sdim // offset into the function instructions; 0 == beginning of first 1079314564Sdim // instruction 1080314564Sdim uint32_t offset_to_subl_insn = 1081314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); 1082278332Semaste 1083314564Sdim SectionList *sl = m_objfile.GetSectionList(); 1084314564Sdim if (sl) { 1085314564Sdim ProcessSP process_sp = target.GetProcessSP(); 1086314564Sdim if (process_sp) { 1087314564Sdim Address subl_payload_addr(function_info.valid_range_offset_start, sl); 1088314564Sdim subl_payload_addr.Slide(offset_to_subl_insn); 1089321369Sdim Status error; 1090314564Sdim uint64_t large_stack_size = process_sp->ReadUnsignedIntegerFromMemory( 1091314564Sdim subl_payload_addr.GetLoadAddress(&target), 4, 0, error); 1092314564Sdim if (large_stack_size != 0 && error.Success()) { 1093314564Sdim // Got the large stack frame size correctly - use it 1094314564Sdim stack_size = large_stack_size + (stack_adjust * wordsize); 1095314564Sdim } else { 1096314564Sdim return false; 1097314564Sdim } 1098314564Sdim } else { 1099314564Sdim return false; 1100314564Sdim } 1101314564Sdim } else { 1102314564Sdim return false; 1103314564Sdim } 1104314564Sdim } 1105278332Semaste 1106314564Sdim int32_t offset = 1107314564Sdim mode == UNWIND_X86_MODE_STACK_IND ? stack_size : stack_size * wordsize; 1108314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(i386_eh_regnum::esp, offset); 1109314564Sdim row->SetOffset(0); 1110314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(i386_eh_regnum::eip, 1111314564Sdim wordsize * -1, true); 1112314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(i386_eh_regnum::esp, 0, true); 1113309124Sdim 1114314564Sdim if (register_count > 0) { 1115278332Semaste 1116341825Sdim // We need to include (up to) 6 registers in 10 bits. That would be 18 1117341825Sdim // bits if we just used 3 bits per reg to indicate the order they're 1118341825Sdim // saved on the stack. 1119314564Sdim // 1120314564Sdim // This is done with Lehmer code permutation, e.g. see 1121341825Sdim // http://stackoverflow.com/questions/1506078/fast-permutation-number- 1122341825Sdim // permutation-mapping-algorithms 1123314564Sdim int permunreg[6] = {0, 0, 0, 0, 0, 0}; 1124278332Semaste 1125341825Sdim // This decodes the variable-base number in the 10 bits and gives us the 1126341825Sdim // Lehmer code sequence which can then be decoded. 1127278332Semaste 1128314564Sdim switch (register_count) { 1129314564Sdim case 6: 1130314564Sdim permunreg[0] = permutation / 120; // 120 == 5! 1131314564Sdim permutation -= (permunreg[0] * 120); 1132314564Sdim permunreg[1] = permutation / 24; // 24 == 4! 1133314564Sdim permutation -= (permunreg[1] * 24); 1134314564Sdim permunreg[2] = permutation / 6; // 6 == 3! 1135314564Sdim permutation -= (permunreg[2] * 6); 1136314564Sdim permunreg[3] = permutation / 2; // 2 == 2! 1137314564Sdim permutation -= (permunreg[3] * 2); 1138314564Sdim permunreg[4] = permutation; // 1 == 1! 1139314564Sdim permunreg[5] = 0; 1140314564Sdim break; 1141314564Sdim case 5: 1142314564Sdim permunreg[0] = permutation / 120; 1143314564Sdim permutation -= (permunreg[0] * 120); 1144314564Sdim permunreg[1] = permutation / 24; 1145314564Sdim permutation -= (permunreg[1] * 24); 1146314564Sdim permunreg[2] = permutation / 6; 1147314564Sdim permutation -= (permunreg[2] * 6); 1148314564Sdim permunreg[3] = permutation / 2; 1149314564Sdim permutation -= (permunreg[3] * 2); 1150314564Sdim permunreg[4] = permutation; 1151314564Sdim break; 1152314564Sdim case 4: 1153314564Sdim permunreg[0] = permutation / 60; 1154314564Sdim permutation -= (permunreg[0] * 60); 1155314564Sdim permunreg[1] = permutation / 12; 1156314564Sdim permutation -= (permunreg[1] * 12); 1157314564Sdim permunreg[2] = permutation / 3; 1158314564Sdim permutation -= (permunreg[2] * 3); 1159314564Sdim permunreg[3] = permutation; 1160314564Sdim break; 1161314564Sdim case 3: 1162314564Sdim permunreg[0] = permutation / 20; 1163314564Sdim permutation -= (permunreg[0] * 20); 1164314564Sdim permunreg[1] = permutation / 4; 1165314564Sdim permutation -= (permunreg[1] * 4); 1166314564Sdim permunreg[2] = permutation; 1167314564Sdim break; 1168314564Sdim case 2: 1169314564Sdim permunreg[0] = permutation / 5; 1170314564Sdim permutation -= (permunreg[0] * 5); 1171314564Sdim permunreg[1] = permutation; 1172314564Sdim break; 1173314564Sdim case 1: 1174314564Sdim permunreg[0] = permutation; 1175314564Sdim break; 1176314564Sdim } 1177309124Sdim 1178341825Sdim // Decode the Lehmer code for this permutation of the registers v. 1179341825Sdim // http://en.wikipedia.org/wiki/Lehmer_code 1180278332Semaste 1181314564Sdim int registers[6] = {UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, 1182314564Sdim UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE, 1183314564Sdim UNWIND_X86_REG_NONE, UNWIND_X86_REG_NONE}; 1184314564Sdim bool used[7] = {false, false, false, false, false, false, false}; 1185314564Sdim for (uint32_t i = 0; i < register_count; i++) { 1186314564Sdim int renum = 0; 1187314564Sdim for (int j = 1; j < 7; j++) { 1188344779Sdim if (!used[j]) { 1189314564Sdim if (renum == permunreg[i]) { 1190314564Sdim registers[i] = j; 1191314564Sdim used[j] = true; 1192314564Sdim break; 1193278332Semaste } 1194314564Sdim renum++; 1195314564Sdim } 1196278332Semaste } 1197314564Sdim } 1198278332Semaste 1199314564Sdim uint32_t saved_registers_offset = 1; 1200314564Sdim saved_registers_offset++; 1201314564Sdim 1202314564Sdim for (int i = (sizeof(registers) / sizeof(int)) - 1; i >= 0; i--) { 1203314564Sdim switch (registers[i]) { 1204314564Sdim case UNWIND_X86_REG_NONE: 1205314564Sdim break; 1206314564Sdim case UNWIND_X86_REG_EBX: 1207314564Sdim case UNWIND_X86_REG_ECX: 1208314564Sdim case UNWIND_X86_REG_EDX: 1209314564Sdim case UNWIND_X86_REG_EDI: 1210314564Sdim case UNWIND_X86_REG_ESI: 1211314564Sdim case UNWIND_X86_REG_EBP: 1212314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1213314564Sdim translate_to_eh_frame_regnum_i386(registers[i]), 1214314564Sdim wordsize * -saved_registers_offset, true); 1215314564Sdim saved_registers_offset++; 1216314564Sdim break; 1217278332Semaste } 1218314564Sdim } 1219278332Semaste } 1220314564Sdim 1221314564Sdim unwind_plan.AppendRow(row); 1222314564Sdim return true; 1223314564Sdim } break; 1224314564Sdim 1225314564Sdim case UNWIND_X86_MODE_DWARF: { 1226278332Semaste return false; 1227314564Sdim } break; 1228314564Sdim } 1229314564Sdim return false; 1230278332Semaste} 1231309124Sdim 1232314564Sdim// DWARF register numbers from "DWARF for the ARM 64-bit Architecture (AArch64)" 1233314564Sdim// doc by ARM 1234309124Sdim 1235309124Sdimenum arm64_eh_regnum { 1236314564Sdim x19 = 19, 1237314564Sdim x20 = 20, 1238314564Sdim x21 = 21, 1239314564Sdim x22 = 22, 1240314564Sdim x23 = 23, 1241314564Sdim x24 = 24, 1242314564Sdim x25 = 25, 1243314564Sdim x26 = 26, 1244314564Sdim x27 = 27, 1245314564Sdim x28 = 28, 1246309124Sdim 1247314564Sdim fp = 29, 1248314564Sdim ra = 30, 1249314564Sdim sp = 31, 1250314564Sdim pc = 32, 1251309124Sdim 1252314564Sdim // Compact unwind encodes d8-d15 but we don't have eh_frame / dwarf reg #'s 1253341825Sdim // for the 64-bit fp regs. Normally in DWARF it's context sensitive - so it 1254341825Sdim // knows it is fetching a 32- or 64-bit quantity from reg v8 to indicate s0 1255341825Sdim // or d0 - but the unwinder is operating at a lower level and we'd try to 1256341825Sdim // fetch 128 bits if we were told that v8 were stored on the stack... 1257314564Sdim v8 = 72, 1258314564Sdim v9 = 73, 1259314564Sdim v10 = 74, 1260314564Sdim v11 = 75, 1261314564Sdim v12 = 76, 1262314564Sdim v13 = 77, 1263314564Sdim v14 = 78, 1264314564Sdim v15 = 79, 1265309124Sdim}; 1266309124Sdim 1267309124Sdimenum arm_eh_regnum { 1268314564Sdim arm_r0 = 0, 1269314564Sdim arm_r1 = 1, 1270314564Sdim arm_r2 = 2, 1271314564Sdim arm_r3 = 3, 1272314564Sdim arm_r4 = 4, 1273314564Sdim arm_r5 = 5, 1274314564Sdim arm_r6 = 6, 1275314564Sdim arm_r7 = 7, 1276314564Sdim arm_r8 = 8, 1277314564Sdim arm_r9 = 9, 1278314564Sdim arm_r10 = 10, 1279314564Sdim arm_r11 = 11, 1280314564Sdim arm_r12 = 12, 1281309124Sdim 1282314564Sdim arm_sp = 13, 1283314564Sdim arm_lr = 14, 1284314564Sdim arm_pc = 15, 1285309124Sdim 1286314564Sdim arm_d0 = 256, 1287314564Sdim arm_d1 = 257, 1288314564Sdim arm_d2 = 258, 1289314564Sdim arm_d3 = 259, 1290314564Sdim arm_d4 = 260, 1291314564Sdim arm_d5 = 261, 1292314564Sdim arm_d6 = 262, 1293314564Sdim arm_d7 = 263, 1294314564Sdim arm_d8 = 264, 1295314564Sdim arm_d9 = 265, 1296314564Sdim arm_d10 = 266, 1297314564Sdim arm_d11 = 267, 1298314564Sdim arm_d12 = 268, 1299314564Sdim arm_d13 = 269, 1300314564Sdim arm_d14 = 270, 1301309124Sdim}; 1302309124Sdim 1303314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target, 1304314564Sdim FunctionInfo &function_info, 1305314564Sdim UnwindPlan &unwind_plan, 1306314564Sdim Address pc_or_function_start) { 1307314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1308314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1309314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1310360784Sdim unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); 1311314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1312309124Sdim 1313314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1314314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1315309124Sdim 1316314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1317309124Sdim 1318314564Sdim const int wordsize = 8; 1319314564Sdim int mode = function_info.encoding & UNWIND_ARM64_MODE_MASK; 1320309124Sdim 1321314564Sdim if (mode == UNWIND_ARM64_MODE_DWARF) 1322314564Sdim return false; 1323309124Sdim 1324314564Sdim if (mode == UNWIND_ARM64_MODE_FRAMELESS) { 1325314564Sdim row->SetOffset(0); 1326309124Sdim 1327314564Sdim uint32_t stack_size = 1328314564Sdim (EXTRACT_BITS(function_info.encoding, 1329314564Sdim UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK)) * 1330314564Sdim 16; 1331309124Sdim 1332314564Sdim // Our previous Call Frame Address is the stack pointer plus the stack size 1333314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::sp, stack_size); 1334309124Sdim 1335314564Sdim // Our previous PC is in the LR 1336314564Sdim row->SetRegisterLocationToRegister(arm64_eh_regnum::pc, arm64_eh_regnum::ra, 1337314564Sdim true); 1338309124Sdim 1339314564Sdim unwind_plan.AppendRow(row); 1340314564Sdim return true; 1341314564Sdim } 1342309124Sdim 1343314564Sdim // Should not be possible 1344314564Sdim if (mode != UNWIND_ARM64_MODE_FRAME) 1345314564Sdim return false; 1346309124Sdim 1347314564Sdim // mode == UNWIND_ARM64_MODE_FRAME 1348309124Sdim 1349314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm64_eh_regnum::fp, 2 * wordsize); 1350314564Sdim row->SetOffset(0); 1351314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::fp, wordsize * -2, 1352314564Sdim true); 1353314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::pc, wordsize * -1, 1354314564Sdim true); 1355314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(arm64_eh_regnum::sp, 0, true); 1356309124Sdim 1357314564Sdim int reg_pairs_saved_count = 1; 1358309124Sdim 1359314564Sdim uint32_t saved_register_bits = function_info.encoding & 0xfff; 1360309124Sdim 1361314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X19_X20_PAIR) { 1362314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1363314564Sdim cfa_offset -= wordsize; 1364314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x19, cfa_offset, 1365314564Sdim true); 1366314564Sdim cfa_offset -= wordsize; 1367314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x20, cfa_offset, 1368314564Sdim true); 1369314564Sdim reg_pairs_saved_count++; 1370314564Sdim } 1371309124Sdim 1372314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X21_X22_PAIR) { 1373314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1374314564Sdim cfa_offset -= wordsize; 1375314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x21, cfa_offset, 1376314564Sdim true); 1377314564Sdim cfa_offset -= wordsize; 1378314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x22, cfa_offset, 1379314564Sdim true); 1380314564Sdim reg_pairs_saved_count++; 1381314564Sdim } 1382309124Sdim 1383314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X23_X24_PAIR) { 1384314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1385314564Sdim cfa_offset -= wordsize; 1386314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x23, cfa_offset, 1387314564Sdim true); 1388314564Sdim cfa_offset -= wordsize; 1389314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x24, cfa_offset, 1390314564Sdim true); 1391314564Sdim reg_pairs_saved_count++; 1392314564Sdim } 1393309124Sdim 1394314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X25_X26_PAIR) { 1395314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1396314564Sdim cfa_offset -= wordsize; 1397314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x25, cfa_offset, 1398314564Sdim true); 1399314564Sdim cfa_offset -= wordsize; 1400314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x26, cfa_offset, 1401314564Sdim true); 1402314564Sdim reg_pairs_saved_count++; 1403314564Sdim } 1404309124Sdim 1405314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_X27_X28_PAIR) { 1406314564Sdim int cfa_offset = reg_pairs_saved_count * -2 * wordsize; 1407314564Sdim cfa_offset -= wordsize; 1408314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x27, cfa_offset, 1409314564Sdim true); 1410314564Sdim cfa_offset -= wordsize; 1411314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm64_eh_regnum::x28, cfa_offset, 1412314564Sdim true); 1413314564Sdim reg_pairs_saved_count++; 1414314564Sdim } 1415309124Sdim 1416314564Sdim // If we use the v8-v15 regnums here, the unwinder will try to grab 128 bits 1417314564Sdim // off the stack; 1418314564Sdim // not sure if we have a good way to represent the 64-bitness of these saves. 1419309124Sdim 1420314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D8_D9_PAIR) { 1421314564Sdim reg_pairs_saved_count++; 1422314564Sdim } 1423314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D10_D11_PAIR) { 1424314564Sdim reg_pairs_saved_count++; 1425314564Sdim } 1426314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D12_D13_PAIR) { 1427314564Sdim reg_pairs_saved_count++; 1428314564Sdim } 1429314564Sdim if (saved_register_bits & UNWIND_ARM64_FRAME_D14_D15_PAIR) { 1430314564Sdim reg_pairs_saved_count++; 1431314564Sdim } 1432309124Sdim 1433314564Sdim unwind_plan.AppendRow(row); 1434314564Sdim return true; 1435309124Sdim} 1436309124Sdim 1437314564Sdimbool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target, 1438314564Sdim FunctionInfo &function_info, 1439314564Sdim UnwindPlan &unwind_plan, 1440314564Sdim Address pc_or_function_start) { 1441314564Sdim unwind_plan.SetSourceName("compact unwind info"); 1442314564Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolYes); 1443314564Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo); 1444360784Sdim unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); 1445314564Sdim unwind_plan.SetRegisterKind(eRegisterKindEHFrame); 1446309124Sdim 1447314564Sdim unwind_plan.SetLSDAAddress(function_info.lsda_address); 1448314564Sdim unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address); 1449309124Sdim 1450314564Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 1451309124Sdim 1452314564Sdim const int wordsize = 4; 1453314564Sdim int mode = function_info.encoding & UNWIND_ARM_MODE_MASK; 1454309124Sdim 1455314564Sdim if (mode == UNWIND_ARM_MODE_DWARF) 1456314564Sdim return false; 1457309124Sdim 1458314564Sdim uint32_t stack_adjust = (EXTRACT_BITS(function_info.encoding, 1459314564Sdim UNWIND_ARM_FRAME_STACK_ADJUST_MASK)) * 1460314564Sdim wordsize; 1461309124Sdim 1462314564Sdim row->GetCFAValue().SetIsRegisterPlusOffset(arm_r7, 1463314564Sdim (2 * wordsize) + stack_adjust); 1464314564Sdim row->SetOffset(0); 1465314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1466314564Sdim arm_r7, (wordsize * -2) - stack_adjust, true); 1467314564Sdim row->SetRegisterLocationToAtCFAPlusOffset( 1468314564Sdim arm_pc, (wordsize * -1) - stack_adjust, true); 1469314564Sdim row->SetRegisterLocationToIsCFAPlusOffset(arm_sp, 0, true); 1470309124Sdim 1471314564Sdim int cfa_offset = -stack_adjust - (2 * wordsize); 1472309124Sdim 1473314564Sdim uint32_t saved_register_bits = function_info.encoding & 0xff; 1474309124Sdim 1475314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R6) { 1476314564Sdim cfa_offset -= wordsize; 1477314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r6, cfa_offset, true); 1478314564Sdim } 1479309124Sdim 1480314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R5) { 1481314564Sdim cfa_offset -= wordsize; 1482314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r5, cfa_offset, true); 1483314564Sdim } 1484309124Sdim 1485314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_FIRST_PUSH_R4) { 1486314564Sdim cfa_offset -= wordsize; 1487314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r4, cfa_offset, true); 1488314564Sdim } 1489309124Sdim 1490314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R12) { 1491314564Sdim cfa_offset -= wordsize; 1492314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r12, cfa_offset, true); 1493314564Sdim } 1494309124Sdim 1495314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R11) { 1496314564Sdim cfa_offset -= wordsize; 1497314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r11, cfa_offset, true); 1498314564Sdim } 1499309124Sdim 1500314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R10) { 1501314564Sdim cfa_offset -= wordsize; 1502314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r10, cfa_offset, true); 1503314564Sdim } 1504309124Sdim 1505314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R9) { 1506314564Sdim cfa_offset -= wordsize; 1507314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r9, cfa_offset, true); 1508314564Sdim } 1509309124Sdim 1510314564Sdim if (saved_register_bits & UNWIND_ARM_FRAME_SECOND_PUSH_R8) { 1511314564Sdim cfa_offset -= wordsize; 1512314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_r8, cfa_offset, true); 1513314564Sdim } 1514309124Sdim 1515314564Sdim if (mode == UNWIND_ARM_MODE_FRAME_D) { 1516314564Sdim uint32_t d_reg_bits = 1517314564Sdim EXTRACT_BITS(function_info.encoding, UNWIND_ARM_FRAME_D_REG_COUNT_MASK); 1518314564Sdim switch (d_reg_bits) { 1519314564Sdim case 0: 1520314564Sdim // vpush {d8} 1521314564Sdim cfa_offset -= 8; 1522314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1523314564Sdim break; 1524314564Sdim case 1: 1525314564Sdim // vpush {d10} 1526314564Sdim // vpush {d8} 1527314564Sdim cfa_offset -= 8; 1528314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1529314564Sdim cfa_offset -= 8; 1530314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1531314564Sdim break; 1532314564Sdim case 2: 1533314564Sdim // vpush {d12} 1534314564Sdim // vpush {d10} 1535314564Sdim // vpush {d8} 1536314564Sdim cfa_offset -= 8; 1537314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1538314564Sdim cfa_offset -= 8; 1539314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1540314564Sdim cfa_offset -= 8; 1541314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1542314564Sdim break; 1543314564Sdim case 3: 1544314564Sdim // vpush {d14} 1545314564Sdim // vpush {d12} 1546314564Sdim // vpush {d10} 1547314564Sdim // vpush {d8} 1548314564Sdim cfa_offset -= 8; 1549314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1550314564Sdim cfa_offset -= 8; 1551314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1552314564Sdim cfa_offset -= 8; 1553314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d10, cfa_offset, true); 1554314564Sdim cfa_offset -= 8; 1555314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d8, cfa_offset, true); 1556314564Sdim break; 1557314564Sdim case 4: 1558314564Sdim // vpush {d14} 1559314564Sdim // vpush {d12} 1560314564Sdim // sp = (sp - 24) & (-16); 1561314564Sdim // vst {d8, d9, d10} 1562314564Sdim cfa_offset -= 8; 1563314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1564314564Sdim cfa_offset -= 8; 1565314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d12, cfa_offset, true); 1566309124Sdim 1567314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1568314564Sdim // alignment short of 1569314564Sdim // coming up with some DWARF location description. 1570309124Sdim 1571314564Sdim break; 1572314564Sdim case 5: 1573314564Sdim // vpush {d14} 1574314564Sdim // sp = (sp - 40) & (-16); 1575314564Sdim // vst {d8, d9, d10, d11} 1576314564Sdim // vst {d12} 1577309124Sdim 1578314564Sdim cfa_offset -= 8; 1579314564Sdim row->SetRegisterLocationToAtCFAPlusOffset(arm_d14, cfa_offset, true); 1580309124Sdim 1581314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1582314564Sdim // alignment short of 1583314564Sdim // coming up with some DWARF location description. 1584309124Sdim 1585314564Sdim break; 1586314564Sdim case 6: 1587314564Sdim // sp = (sp - 56) & (-16); 1588314564Sdim // vst {d8, d9, d10, d11} 1589314564Sdim // vst {d12, d13, d14} 1590309124Sdim 1591314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1592314564Sdim // alignment short of 1593314564Sdim // coming up with some DWARF location description. 1594309124Sdim 1595314564Sdim break; 1596314564Sdim case 7: 1597314564Sdim // sp = (sp - 64) & (-16); 1598314564Sdim // vst {d8, d9, d10, d11} 1599314564Sdim // vst {d12, d13, d14, d15} 1600309124Sdim 1601314564Sdim // FIXME we don't have a way to represent reg saves at an specific 1602314564Sdim // alignment short of 1603314564Sdim // coming up with some DWARF location description. 1604309124Sdim 1605314564Sdim break; 1606309124Sdim } 1607314564Sdim } 1608309124Sdim 1609314564Sdim unwind_plan.AppendRow(row); 1610314564Sdim return true; 1611309124Sdim} 1612