Index: lldb/trunk/include/lldb/Symbol/ArmUnwindInfo.h =================================================================== --- lldb/trunk/include/lldb/Symbol/ArmUnwindInfo.h +++ lldb/trunk/include/lldb/Symbol/ArmUnwindInfo.h @@ -0,0 +1,55 @@ +//===-- ArmUnwindInfo.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ArmUnwindInfo_h_ +#define liblldb_ArmUnwindInfo_h_ + +#include + +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RangeMap.h" +#include "lldb/Host/Mutex.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/lldb-private.h" + +/* + * Unwind information reader and parser for the ARM exception handling ABI + * + * Implemented based on: + * Exception Handling ABI for the ARM Architecture + * Document number: ARM IHI 0038A (current through ABI r2.09) + * Date of Issue: 25th January 2007, reissued 30th November 2012 + * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf + */ + +namespace lldb_private { + +class ArmUnwindInfo +{ +public: + ArmUnwindInfo (ObjectFile& objfile, lldb::SectionSP& arm_exidx, lldb::SectionSP& arm_extab); + ~ArmUnwindInfo(); + + bool + GetUnwindPlan (Target &target, const Address& addr, UnwindPlan& unwind_plan); + +private: + const uint8_t* + GetExceptionHandlingTableEntry(const Address& addr); + + lldb::SectionSP m_arm_exidx_sp; // .ARM.exidx section + lldb::SectionSP m_arm_extab_sp; // .ARM.extab section + + DataExtractor m_arm_exidx_data; // .ARM.exidx section data + DataExtractor m_arm_extab_data; // .ARM.extab section data +}; + +} // namespace lldb_private + +#endif // liblldb_ArmUnwindInfo_h_ Index: lldb/trunk/include/lldb/Symbol/FuncUnwinders.h =================================================================== --- lldb/trunk/include/lldb/Symbol/FuncUnwinders.h +++ lldb/trunk/include/lldb/Symbol/FuncUnwinders.h @@ -103,6 +103,9 @@ GetCompactUnwindUnwindPlan (Target &target, int current_offset); lldb::UnwindPlanSP + GetArmUnwindUnwindPlan (Target &target, int current_offset); + + lldb::UnwindPlanSP GetArchDefaultUnwindPlan (Thread &thread); lldb::UnwindPlanSP @@ -122,6 +125,7 @@ lldb::UnwindPlanSP m_unwind_plan_eh_frame_sp; lldb::UnwindPlanSP m_unwind_plan_eh_frame_augmented_sp; // augmented by assembly inspection so it's valid everywhere std::vector m_unwind_plan_compact_unwind; + lldb::UnwindPlanSP m_unwind_plan_arm_unwind_sp; lldb::UnwindPlanSP m_unwind_plan_fast_sp; lldb::UnwindPlanSP m_unwind_plan_arch_default_sp; lldb::UnwindPlanSP m_unwind_plan_arch_default_at_func_entry_sp; @@ -132,6 +136,7 @@ m_tried_unwind_plan_eh_frame:1, m_tried_unwind_plan_eh_frame_augmented:1, m_tried_unwind_plan_compact_unwind:1, + m_tried_unwind_plan_arm_unwind:1, m_tried_unwind_fast:1, m_tried_unwind_arch_default:1, m_tried_unwind_arch_default_at_func_entry:1; Index: lldb/trunk/include/lldb/Symbol/UnwindTable.h =================================================================== --- lldb/trunk/include/lldb/Symbol/UnwindTable.h +++ lldb/trunk/include/lldb/Symbol/UnwindTable.h @@ -34,6 +34,9 @@ lldb_private::CompactUnwindInfo * GetCompactUnwindInfo (); + ArmUnwindInfo * + GetArmUnwindInfo (); + lldb::FuncUnwindersSP GetFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc); @@ -65,9 +68,10 @@ bool m_initialized; // delay some initialization until ObjectFile is set up Mutex m_mutex; - DWARFCallFrameInfo* m_eh_frame; - CompactUnwindInfo *m_compact_unwind; - + std::unique_ptr m_eh_frame_up; + std::unique_ptr m_compact_unwind_up; + std::unique_ptr m_arm_unwind_up; + DISALLOW_COPY_AND_ASSIGN (UnwindTable); }; Index: lldb/trunk/include/lldb/lldb-enumerations.h =================================================================== --- lldb/trunk/include/lldb/lldb-enumerations.h +++ lldb/trunk/include/lldb/lldb-enumerations.h @@ -616,6 +616,8 @@ eSectionTypeELFRelocationEntries, // Elf SHT_REL or SHT_REL section eSectionTypeELFDynamicLinkInfo, // Elf SHT_DYNAMIC section eSectionTypeEHFrame, + eSectionTypeARMexidx, + eSectionTypeARMextab, eSectionTypeCompactUnwind, // compact unwind section in Mach-O, __TEXT,__unwind_info eSectionTypeGoSymtab, eSectionTypeOther Index: lldb/trunk/include/lldb/lldb-forward.h =================================================================== --- lldb/trunk/include/lldb/lldb-forward.h +++ lldb/trunk/include/lldb/lldb-forward.h @@ -25,6 +25,7 @@ class AddressRange; class AddressResolver; class ArchSpec; +class ArmUnwindInfo; class Args; class ASTResultSynthesizer; class ASTStructExtractor; Index: lldb/trunk/source/Commands/CommandObjectTarget.cpp =================================================================== --- lldb/trunk/source/Commands/CommandObjectTarget.cpp +++ lldb/trunk/source/Commands/CommandObjectTarget.cpp @@ -3819,6 +3819,14 @@ result.GetOutputStream().Printf("\n"); } + UnwindPlanSP arm_unwind_sp = func_unwinders_sp->GetArmUnwindUnwindPlan(*target, 0); + if (arm_unwind_sp) + { + result.GetOutputStream().Printf("ARM.exidx unwind UnwindPlan:\n"); + arm_unwind_sp->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS); + result.GetOutputStream().Printf("\n"); + } + UnwindPlanSP compact_unwind_sp = func_unwinders_sp->GetCompactUnwindUnwindPlan(*target, 0); if (compact_unwind_sp) { Index: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp =================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1720,6 +1720,8 @@ static ConstString g_sect_name_dwarf_debug_str_dwo (".debug_str.dwo"); static ConstString g_sect_name_dwarf_debug_str_offsets_dwo (".debug_str_offsets.dwo"); static ConstString g_sect_name_eh_frame (".eh_frame"); + static ConstString g_sect_name_arm_exidx (".ARM.exidx"); + static ConstString g_sect_name_arm_extab (".ARM.extab"); static ConstString g_sect_name_go_symtab (".gosymtab"); SectionType sect_type = eSectionTypeOther; @@ -1773,6 +1775,8 @@ else if (name == g_sect_name_dwarf_debug_str_dwo) sect_type = eSectionTypeDWARFDebugStr; else if (name == g_sect_name_dwarf_debug_str_offsets_dwo) sect_type = eSectionTypeDWARFDebugStrOffsets; else if (name == g_sect_name_eh_frame) sect_type = eSectionTypeEHFrame; + else if (name == g_sect_name_arm_exidx) sect_type = eSectionTypeARMexidx; + else if (name == g_sect_name_arm_extab) sect_type = eSectionTypeARMextab; else if (name == g_sect_name_go_symtab) sect_type = eSectionTypeGoSymtab; switch (header.sh_type) Index: lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp =================================================================== --- lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ lldb/trunk/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -1342,6 +1342,8 @@ return eAddressClassDebug; case eSectionTypeEHFrame: + case eSectionTypeARMexidx: + case eSectionTypeARMextab: case eSectionTypeCompactUnwind: return eAddressClassRuntime; Index: lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp =================================================================== --- lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp +++ lldb/trunk/source/Plugins/Process/Utility/RegisterContextLLDB.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/ArmUnwindInfo.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/Function.h" @@ -794,24 +795,38 @@ func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx); } - // No FuncUnwinders available for this pc (i.e. a stripped function symbol and -fomit-frame-pointer). - // Try using the eh_frame information relative to the current PC, - // and finally fall back on the architectural default unwind. + // No FuncUnwinders available for this pc (stripped function symbols, lldb could not augment its + // function table with another source, like LC_FUNCTION_STARTS or eh_frame in ObjectFileMachO). + // See if eh_frame or the .ARM.exidx tables have unwind information for this address, else fall + // back to the architectural default unwind. if (!func_unwinders_sp) { - DWARFCallFrameInfo *eh_frame = pc_module_sp && pc_module_sp->GetObjectFile() ? - pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo() : nullptr; - m_frame_type = eNormalFrame; - if (eh_frame && m_current_pc.IsValid()) + + if (!pc_module_sp || !pc_module_sp->GetObjectFile() || !m_current_pc.IsValid()) + return arch_default_unwind_plan_sp; + + // Even with -fomit-frame-pointer, we can try eh_frame to get back on track. + DWARFCallFrameInfo *eh_frame = pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo(); + if (eh_frame) { unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); - // Even with -fomit-frame-pointer, we can try eh_frame to get back on track. if (eh_frame->GetUnwindPlan (m_current_pc, *unwind_plan_sp)) return unwind_plan_sp; else unwind_plan_sp.reset(); } + + ArmUnwindInfo *arm_exidx = pc_module_sp->GetObjectFile()->GetUnwindTable().GetArmUnwindInfo(); + if (arm_exidx) + { + unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); + if (arm_exidx->GetUnwindPlan (exe_ctx.GetTargetRef(), m_current_pc, *unwind_plan_sp)) + return unwind_plan_sp; + else + unwind_plan_sp.reset(); + } + return arch_default_unwind_plan_sp; } Index: lldb/trunk/source/Symbol/ArmUnwindInfo.cpp =================================================================== --- lldb/trunk/source/Symbol/ArmUnwindInfo.cpp +++ lldb/trunk/source/Symbol/ArmUnwindInfo.cpp @@ -0,0 +1,425 @@ +//===-- ArmUnwindInfo.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include + +#include "lldb/Core/Module.h" +#include "lldb/Core/Section.h" +#include "lldb/Symbol/ArmUnwindInfo.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/UnwindPlan.h" +#include "Utility/ARM_DWARF_Registers.h" + +/* + * Unwind information reader and parser for the ARM exception handling ABI + * + * Implemented based on: + * Exception Handling ABI for the ARM Architecture + * Document number: ARM IHI 0038A (current through ABI r2.09) + * Date of Issue: 25th January 2007, reissued 30th November 2012 + * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf + */ + +using namespace lldb; +using namespace lldb_private; + +namespace +{ + struct ArmExidxEntry + { + uint32_t address; + uint32_t data; + }; +}; + +ArmUnwindInfo::ArmUnwindInfo(ObjectFile& objfile, SectionSP& arm_exidx, SectionSP& arm_extab) : + m_arm_exidx_sp(arm_exidx), + m_arm_extab_sp(arm_extab) +{ + objfile.ReadSectionData(arm_exidx.get(), m_arm_exidx_data); + objfile.ReadSectionData(arm_extab.get(), m_arm_extab_data); +} + +ArmUnwindInfo::~ArmUnwindInfo() +{ +} + +static uint8_t +GetNextByte(const uint32_t* data, uint16_t offset) +{ + data += offset / 4; + offset = offset % 4; + return (data[0] >> ((3 - offset) * 8)) & 0xff; +} + +static uint64_t +GetULEB128(const uint32_t* data, uint16_t& offset, uint16_t max_offset) +{ + uint64_t result = 0; + uint8_t shift = 0; + while (offset < max_offset) + { + uint8_t byte = GetNextByte(data, offset++); + result |= (byte & 0x7f) << shift; + if ((byte & 0x80) == 0) + break; + shift += 7; + } + return result; +} + +bool +ArmUnwindInfo::GetUnwindPlan(Target &target, const Address& addr, UnwindPlan& unwind_plan) +{ + const uint32_t* data = (const uint32_t*)GetExceptionHandlingTableEntry(addr.GetFileAddress()); + if (data == nullptr) + return false; // No unwind information for the function + + if (data[0] == 0x1) + return false; // EXIDX_CANTUNWIND + + uint16_t byte_count = 0; + uint16_t byte_offset = 0; + if (data[0] & 0x80000000) + { + switch ((data[0] >> 24) & 0x0f) + { + case 0: + byte_count = 4; + byte_offset = 1; + break; + case 1: + case 2: + byte_count = 4 * ((data[0] >> 16) & 0xff) + 4; + byte_offset = 2; + break; + default: + // Unhandled personality routine index + return false; + } + } + else + { + byte_count = 4 * ((data[1] >> 24) & 0xff) + 8; + byte_offset = 5; + } + + uint8_t vsp_reg = dwarf_sp; + int32_t vsp = 0; + std::vector> register_offsets; // register -> (offset from vsp_reg) + + while (byte_offset < byte_count) + { + uint8_t byte1 = GetNextByte(data, byte_offset++); + if ((byte1&0xc0) == 0x00) + { + // 00xxxxxx + // vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive + vsp += ((byte1 & 0x3f) << 2) + 4; + } + else if ((byte1&0xc0) == 0x40) + { + // 01xxxxxx + // vsp = vsp – (xxxxxx << 2) - 4. Covers range 0x04-0x100 inclusive + vsp -= ((byte1 & 0x3f) << 2) + 4; + } + else if ((byte1&0xf0) == 0x80) + { + if (byte_offset >= byte_count) + return false; + + uint8_t byte2 = GetNextByte(data, byte_offset++); + if (byte1 == 0x80 && byte2 == 0) + { + // 10000000 00000000 + // Refuse to unwind (for example, out of a cleanup) (see remark a) + return false; + } + else + { + // 1000iiii iiiiiiii (i not all 0) + // Pop up to 12 integer registers under masks {r15-r12}, {r11-r4} (see remark b) + uint16_t regs = ((byte1&0x0f) << 8) | byte2; + for (uint8_t i = 0; i < 12; ++i) + { + if (regs & (1<= byte_count) + return false; + + uint8_t byte2 = GetNextByte(data, byte_offset++); + if ((byte2&0xff) == 0x00) + { + // 10110001 00000000 + // Spare (see remark f) + return false; + } + else if ((byte2&0xf0) == 0x00) + { + // 10110001 0000iiii (i not all 0) + // Pop integer registers under mask {r3, r2, r1, r0} + for (uint8_t i = 0; i < 4; ++i) + { + if (byte2 & (1<= byte_count) + return false; + + uint8_t byte2 = GetNextByte(data, byte_offset++); + uint8_t s = (byte2&0xf0) >> 4; + uint8_t c = (byte2&0x0f) >> 0; + for (uint8_t i = 0; i <= c; ++i) + { + register_offsets.emplace_back(dwarf_d0 + s + i, vsp); + vsp += 8; + } + vsp += 4; + } + else if ((byte1&0xfc) == 0xb4) + { + // 101101nn + // Spare (was Pop FPA) + return false; + } + else if ((byte1&0xf8) == 0xb8) + { + // 10111nnn + // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by FSTMFDX (see remark d) + uint8_t n = byte1&0x07; + for (uint8_t i = 0; i <= n; ++i) + { + register_offsets.emplace_back(dwarf_d8 + i, vsp); + vsp += 8; + } + vsp += 4; + } + else if ((byte1&0xf8) == 0xc0) + { + // 11000nnn (nnn != 6,7) + // Intel Wireless MMX pop wR[10]-wR[10+nnn] + + // 11000110 sssscccc + // Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e) + + // 11000111 00000000 + // Spare + + // 11000111 0000iiii + // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} + + // 11000111 xxxxyyyy + // Spare (xxxx != 0000) + + return false; + } + else if ((byte1&0xff) == 0xc8) + { + // 11001000 sssscccc + // Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] saved (as if) by FSTMFDD (see remarks d,e) + if (byte_offset >= byte_count) + return false; + + uint8_t byte2 = GetNextByte(data, byte_offset++); + uint8_t s = (byte2&0xf0) >> 4; + uint8_t c = (byte2&0x0f) >> 0; + for (uint8_t i = 0; i <= c; ++i) + { + register_offsets.emplace_back(dwarf_d16 + s + i, vsp); + vsp += 8; + } + } + else if ((byte1&0xff) == 0xc9) + { + // 11001001 sssscccc + // Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved (as if) by FSTMFDD (see remark d) + if (byte_offset >= byte_count) + return false; + + uint8_t byte2 = GetNextByte(data, byte_offset++); + uint8_t s = (byte2&0xf0) >> 4; + uint8_t c = (byte2&0x0f) >> 0; + for (uint8_t i = 0; i <= c; ++i) + { + register_offsets.emplace_back(dwarf_d0 + s + i, vsp); + vsp += 8; + } + } + else if ((byte1&0xf8) == 0xc8) + { + // 11001yyy + // Spare (yyy != 000, 001) + return false; + } + else if ((byte1&0xf8) == 0xc0) + { + // 11010nnn + // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by FSTMFDD (see remark d) + uint8_t n = byte1&0x07; + for (uint8_t i = 0; i <= n; ++i) + { + register_offsets.emplace_back(dwarf_d8 + i, vsp); + vsp += 8; + } + } + else if ((byte1&0xc0) == 0xc0) + { + // 11xxxyyy Spare (xxx != 000, 001, 010) + return false; + } + else + { + return false; + } + } + + UnwindPlan::RowSP row = std::make_shared(); + row->SetOffset(0); + row->GetCFAValue().SetIsRegisterPlusOffset(vsp_reg, vsp); + + bool have_location_for_pc = false; + for (const auto& offset : register_offsets) + { + have_location_for_pc |= offset.first == dwarf_pc; + row->SetRegisterLocationToAtCFAPlusOffset(offset.first, offset.second - vsp, true); + } + + if (!have_location_for_pc) + { + UnwindPlan::Row::RegisterLocation lr_location; + if (row->GetRegisterInfo(dwarf_lr, lr_location)) + row->SetRegisterInfo(dwarf_pc, lr_location); + } + + unwind_plan.AppendRow(row); + unwind_plan.SetSourceName ("ARM.exidx unwind info"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolYes); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); + unwind_plan.SetRegisterKind (eRegisterKindDWARF); + + return true; +} + +const uint8_t* +ArmUnwindInfo::GetExceptionHandlingTableEntry(const Address& addr) +{ + uint32_t file_addr = addr.GetFileAddress(); + uint32_t exidx_base_addr = m_arm_exidx_sp->GetFileAddress(); + + const ArmExidxEntry* exidx_start = (const ArmExidxEntry*)m_arm_exidx_data.GetDataStart(); + uint32_t bs_start = 0, bs_end = m_arm_exidx_data.GetByteSize() / sizeof(ArmExidxEntry); + while (bs_start + 1 < bs_end) + { + uint32_t mid = (bs_start + bs_end) / 2; + uint32_t mid_addr = exidx_base_addr + exidx_start[mid].address + mid * sizeof(ArmExidxEntry); + mid_addr &= 0x7fffffff; + if (mid_addr > file_addr) + bs_end = mid; + else + bs_start = mid; + } + + uint32_t exidx_addr = exidx_base_addr + + exidx_start[bs_start].address + + bs_start * sizeof(ArmExidxEntry); + exidx_addr &= 0x7fffffff; + if (exidx_addr > file_addr) + return nullptr; + + if (exidx_start[bs_start].data == 0x1) + return nullptr; // EXIDX_CANTUNWIND + + if (exidx_start[bs_start].data & 0x80000000) + return (const uint8_t*)&exidx_start[bs_start].data; + + uint32_t data_file_addr = exidx_base_addr + + 8 * bs_start + 4 + + exidx_start[bs_start].data; + data_file_addr &= 0x7fffffff; + return m_arm_extab_data.GetDataStart() + (data_file_addr - m_arm_extab_sp->GetFileAddress()); +} Index: lldb/trunk/source/Symbol/CMakeLists.txt =================================================================== --- lldb/trunk/source/Symbol/CMakeLists.txt +++ lldb/trunk/source/Symbol/CMakeLists.txt @@ -1,4 +1,5 @@ add_lldb_library(lldbSymbol + ArmUnwindInfo.cpp Block.cpp ClangASTContext.cpp ClangASTImporter.cpp Index: lldb/trunk/source/Symbol/FuncUnwinders.cpp =================================================================== --- lldb/trunk/source/Symbol/FuncUnwinders.cpp +++ lldb/trunk/source/Symbol/FuncUnwinders.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/AddressRange.h" #include "lldb/Core/Address.h" #include "lldb/Symbol/FuncUnwinders.h" +#include "lldb/Symbol/ArmUnwindInfo.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" #include "lldb/Symbol/CompactUnwindInfo.h" #include "lldb/Symbol/ObjectFile.h" @@ -37,6 +38,7 @@ m_unwind_plan_eh_frame_sp (), m_unwind_plan_eh_frame_augmented_sp (), m_unwind_plan_compact_unwind (), + m_unwind_plan_arm_unwind_sp (), m_unwind_plan_fast_sp (), m_unwind_plan_arch_default_sp (), m_unwind_plan_arch_default_at_func_entry_sp (), @@ -44,6 +46,7 @@ m_tried_unwind_plan_eh_frame (false), m_tried_unwind_plan_eh_frame_augmented (false), m_tried_unwind_plan_compact_unwind (false), + m_tried_unwind_plan_arm_unwind (false), m_tried_unwind_fast (false), m_tried_unwind_arch_default (false), m_tried_unwind_arch_default_at_func_entry (false), @@ -65,12 +68,18 @@ Mutex::Locker locker (m_mutex); UnwindPlanSP unwind_plan_sp = GetEHFrameUnwindPlan (target, current_offset); - if (unwind_plan_sp.get() == nullptr) - { - unwind_plan_sp = GetCompactUnwindUnwindPlan (target, current_offset); - } + if (unwind_plan_sp) + return unwind_plan_sp; - return unwind_plan_sp; + unwind_plan_sp = GetCompactUnwindUnwindPlan (target, current_offset); + if (unwind_plan_sp) + return unwind_plan_sp; + + unwind_plan_sp = GetArmUnwindUnwindPlan (target, current_offset); + if (unwind_plan_sp) + return unwind_plan_sp; + + return nullptr; } UnwindPlanSP @@ -127,6 +136,30 @@ } UnwindPlanSP +FuncUnwinders::GetArmUnwindUnwindPlan (Target &target, int current_offset) +{ + if (m_unwind_plan_arm_unwind_sp.get() || m_tried_unwind_plan_arm_unwind) + return m_unwind_plan_arm_unwind_sp; + + Mutex::Locker lock (m_mutex); + m_tried_unwind_plan_arm_unwind = true; + if (m_range.GetBaseAddress().IsValid()) + { + Address current_pc (m_range.GetBaseAddress ()); + if (current_offset != -1) + current_pc.SetOffset (current_pc.GetOffset() + current_offset); + ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo(); + if (arm_unwind_info) + { + m_unwind_plan_arm_unwind_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric)); + if (!arm_unwind_info->GetUnwindPlan (target, current_pc, *m_unwind_plan_arm_unwind_sp)) + m_unwind_plan_arm_unwind_sp.reset(); + } + } + return m_unwind_plan_arm_unwind_sp; +} + +UnwindPlanSP FuncUnwinders::GetEHFrameAugmentedUnwindPlan (Target &target, Thread &thread, int current_offset) { if (m_unwind_plan_eh_frame_augmented_sp.get() || m_tried_unwind_plan_eh_frame_augmented) Index: lldb/trunk/source/Symbol/ObjectFile.cpp =================================================================== --- lldb/trunk/source/Symbol/ObjectFile.cpp +++ lldb/trunk/source/Symbol/ObjectFile.cpp @@ -373,6 +373,8 @@ case eSectionTypeDWARFAppleObjC: return eAddressClassDebug; case eSectionTypeEHFrame: + case eSectionTypeARMexidx: + case eSectionTypeARMextab: case eSectionTypeCompactUnwind: return eAddressClassRuntime; case eSectionTypeELFSymbolTable: Index: lldb/trunk/source/Symbol/UnwindTable.cpp =================================================================== --- lldb/trunk/source/Symbol/UnwindTable.cpp +++ lldb/trunk/source/Symbol/UnwindTable.cpp @@ -17,6 +17,7 @@ #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" +#include "lldb/Symbol/ArmUnwindInfo.h" #include "lldb/Symbol/CompactUnwindInfo.h" // There is one UnwindTable object per ObjectFile. @@ -31,8 +32,9 @@ m_unwinds (), m_initialized (false), m_mutex (), - m_eh_frame (nullptr), - m_compact_unwind (nullptr) + m_eh_frame_up (), + m_compact_unwind_up (), + m_arm_unwind_up () { } @@ -56,12 +58,21 @@ SectionSP sect = sl->FindSectionByType (eSectionTypeEHFrame, true); if (sect.get()) { - m_eh_frame = new DWARFCallFrameInfo(m_object_file, sect, eRegisterKindEHFrame, true); + m_eh_frame_up.reset(new DWARFCallFrameInfo(m_object_file, sect, eRegisterKindEHFrame, true)); } sect = sl->FindSectionByType (eSectionTypeCompactUnwind, true); if (sect.get()) { - m_compact_unwind = new CompactUnwindInfo(m_object_file, sect); + m_compact_unwind_up.reset(new CompactUnwindInfo(m_object_file, sect)); + } + sect = sl->FindSectionByType (eSectionTypeARMexidx, true); + if (sect.get()) + { + SectionSP sect_extab = sl->FindSectionByType (eSectionTypeARMextab, true); + if (sect_extab.get()) + { + m_arm_unwind_up.reset(new ArmUnwindInfo(m_object_file, sect, sect_extab)); + } } } @@ -70,8 +81,6 @@ UnwindTable::~UnwindTable () { - if (m_eh_frame) - delete m_eh_frame; } FuncUnwindersSP @@ -102,7 +111,7 @@ if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, range) || !range.GetBaseAddress().IsValid()) { // Does the eh_frame unwind info has a function bounds for this addr? - if (m_eh_frame == nullptr || !m_eh_frame->GetAddressRange (addr, range)) + if (m_eh_frame_up == nullptr || !m_eh_frame_up->GetAddressRange (addr, range)) { return no_unwind_found; } @@ -129,7 +138,7 @@ if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, range) || !range.GetBaseAddress().IsValid()) { // Does the eh_frame unwind info has a function bounds for this addr? - if (m_eh_frame == nullptr || !m_eh_frame->GetAddressRange (addr, range)) + if (m_eh_frame_up == nullptr || !m_eh_frame_up->GetAddressRange (addr, range)) { return no_unwind_found; } @@ -158,14 +167,21 @@ UnwindTable::GetEHFrameInfo () { Initialize(); - return m_eh_frame; + return m_eh_frame_up.get(); } CompactUnwindInfo * UnwindTable::GetCompactUnwindInfo () { Initialize(); - return m_compact_unwind; + return m_compact_unwind_up.get(); +} + +ArmUnwindInfo * +UnwindTable::GetArmUnwindInfo () +{ + Initialize(); + return m_arm_unwind_up.get(); } bool Index: lldb/trunk/source/Utility/ConvertEnum.cpp =================================================================== --- lldb/trunk/source/Utility/ConvertEnum.cpp +++ lldb/trunk/source/Utility/ConvertEnum.cpp @@ -105,6 +105,10 @@ return "apple-objc"; case eSectionTypeEHFrame: return "eh-frame"; + case eSectionTypeARMexidx: + return "ARM.exidx"; + case eSectionTypeARMextab: + return "ARM.extab"; case eSectionTypeCompactUnwind: return "compact-unwind"; case eSectionTypeGoSymtab: