From 0b5d6e5d0e093377e3b212093b999c3fec9c2b69 Mon Sep 17 00:00:00 2001 From: Hafiz Abid Qadeer Date: Thu, 25 May 2017 10:21:29 +0000 Subject: [PATCH] Fix FDE indexing while scan debug_info section. There are some differences between eh_frame and debug_frame formats that are not considered by DWARFCallFrameInfo::GetFDEIndex. An FDE entry contains CIE_pointer in debug_frame in same place as cie_id in eh_frame. As described in dwarf standard (section 6.4.1), CIE_pointer is an "offset into the .debug_frame section". So, variable cie_offset should be equal cie_id for debug_frame. FDE entries with zeroth CIE pointer (which is actually placed in cie_id variable) shouldn't be ignored also. I have also added a little change which allow to use debug_info section when eh_frame is absent. This case really can take place on some platforms. Patch from tatyana-krasnukha. https://reviews.llvm.org/D33504 llvm-svn: 303847 --- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 31 ++++++++++++++++++++----------- lldb/source/Symbol/UnwindTable.cpp | 7 +++++++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index 015ecd856..df8a8cf 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -461,11 +461,25 @@ void DWARFCallFrameInfo::GetFDEIndex() { m_fde_index_initialized = true; return; } + + // An FDE entry contains CIE_pointer in debug_frame in same place as cie_id + // in eh_frame. CIE_pointer is an offset into the .debug_frame section. + // So, variable cie_offset should be equal cie_id for debug_frame. + // FDE entries with cie_id == 0 shouldn't be ignored for it. + if ((cie_id == 0 && m_is_eh_frame) || cie_id == UINT32_MAX || len == 0) { + m_cie_map[current_entry] = ParseCIE(current_entry); + offset = next_entry; + continue; + } + + if (!m_is_eh_frame) + cie_offset = cie_id; + if (cie_offset > m_cfi_data.GetByteSize()) { - Host::SystemLog( - Host::eSystemLogError, - "error: Invalid cie offset of 0x%x found in cie/fde at 0x%x\n", - cie_offset, current_entry); + Host::SystemLog(Host::eSystemLogError, + "error: Invalid cie offset of 0x%x " + "found in cie/fde at 0x%x\n", + cie_offset, current_entry); // Don't trust anything in this eh_frame section if we find blatantly // invalid data. m_fde_index.Clear(); @@ -473,12 +487,6 @@ void DWARFCallFrameInfo::GetFDEIndex() { return; } - if (cie_id == 0 || cie_id == UINT32_MAX || len == 0) { - m_cie_map[current_entry] = ParseCIE(current_entry); - offset = next_entry; - continue; - } - const CIE *cie = GetCIE(cie_offset); if (cie) { const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress(); @@ -531,7 +539,8 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset, cie_offset = m_cfi_data.GetU32(&offset); } - assert(cie_offset != 0 && cie_offset != UINT32_MAX); + // FDE entries with zero cie_offset may occur for debug_frame. + assert(!(m_is_eh_frame && 0 == cie_offset) && cie_offset != UINT32_MAX); // Translate the CIE_id from the eh_frame format, which // is relative to the FDE offset, into a __eh_frame section diff --git a/lldb/source/Symbol/UnwindTable.cpp b/lldb/source/Symbol/UnwindTable.cpp index 336f0c3..f417f35 100644 --- a/lldb/source/Symbol/UnwindTable.cpp +++ b/lldb/source/Symbol/UnwindTable.cpp @@ -51,6 +51,13 @@ void UnwindTable::Initialize() { if (sect.get()) { m_eh_frame_up.reset(new DWARFCallFrameInfo(m_object_file, sect, eRegisterKindEHFrame, true)); + } else { + // Try to find .debug_frame section if .eh_frame doesn't exist. + sect = sl->FindSectionByType(eSectionTypeDWARFDebugFrame, true); + if (sect.get()) { + m_eh_frame_up.reset(new DWARFCallFrameInfo(m_object_file, sect, + eRegisterKindDWARF, false)); + } } sect = sl->FindSectionByType(eSectionTypeCompactUnwind, true); if (sect.get()) { -- 2.7.4