From 1767e115945f9f18f3032433887bb9b231edb5ce Mon Sep 17 00:00:00 2001 From: Todd Fiala Date: Mon, 25 Aug 2014 21:39:30 +0000 Subject: [PATCH] Add 64-bit eh_frame section CFI support. In practice, 64bit eh_frame is not used even for x86_64 binaries. The main reason is in eh_frame we almost always use pc-relative addressing, so addresses are within 32bits and gcc just sticks to 32bit eh_frame. I generated 64bit eh_frame for Android Java runtime and unwind successfully in gdb, and in lldb with this patch. Patch by Tong Shen. llvm-svn: 216409 --- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 42 ++++++++++++++++++----- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp index e4b55383a823..a9da631eb452 100644 --- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -146,9 +146,17 @@ DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset) lldb::offset_t offset = cie_offset; if (m_cfi_data_initialized == false) GetCFIData(); - const uint32_t length = m_cfi_data.GetU32(&offset); - const dw_offset_t cie_id = m_cfi_data.GetU32(&offset); - const dw_offset_t end_offset = cie_offset + length + 4; + uint32_t length = m_cfi_data.GetU32(&offset); + dw_offset_t cie_id, end_offset; + bool is_64bit = (length == UINT32_MAX); + if (is_64bit) { + length = m_cfi_data.GetU64(&offset); + cie_id = m_cfi_data.GetU64(&offset); + end_offset = cie_offset + length + 12; + } else { + cie_id = m_cfi_data.GetU32(&offset); + end_offset = cie_offset + length + 4; + } if (length > 0 && ((!m_is_eh_frame && cie_id == UINT32_MAX) || (m_is_eh_frame && cie_id == 0ul))) { size_t i; @@ -337,9 +345,19 @@ DWARFCallFrameInfo::GetFDEIndex () while (m_cfi_data.ValidOffsetForDataOfSize (offset, 8)) { const dw_offset_t current_entry = offset; + dw_offset_t cie_id, next_entry, cie_offset; uint32_t len = m_cfi_data.GetU32 (&offset); - dw_offset_t next_entry = current_entry + len + 4; - dw_offset_t cie_id = m_cfi_data.GetU32 (&offset); + bool is_64bit = (len == UINT32_MAX); + if (is_64bit) { + len = m_cfi_data.GetU64 (&offset); + cie_id = m_cfi_data.GetU64 (&offset); + next_entry = current_entry + len + 12; + cie_offset = current_entry + 12 - cie_id; + } else { + cie_id = m_cfi_data.GetU32 (&offset); + next_entry = current_entry + len + 4; + cie_offset = current_entry + 4 - cie_id; + } if (cie_id == 0 || cie_id == UINT32_MAX || len == 0) { @@ -348,7 +366,6 @@ DWARFCallFrameInfo::GetFDEIndex () continue; } - const dw_offset_t cie_offset = current_entry + 4 - cie_id; const CIE *cie = GetCIE (cie_offset); if (cie) { @@ -388,7 +405,14 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr GetCFIData(); uint32_t length = m_cfi_data.GetU32 (&offset); - dw_offset_t cie_offset = m_cfi_data.GetU32 (&offset); + dw_offset_t cie_offset; + bool is_64bit = (length == UINT32_MAX); + if (is_64bit) { + length = m_cfi_data.GetU64 (&offset); + cie_offset = m_cfi_data.GetU64 (&offset); + } else { + cie_offset = m_cfi_data.GetU32 (&offset); + } assert (cie_offset != 0 && cie_offset != UINT32_MAX); @@ -398,7 +422,7 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr if (m_is_eh_frame) { unwind_plan.SetSourceName ("eh_frame CFI"); - cie_offset = current_entry + 4 - cie_offset; + cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset; unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo); } else @@ -415,7 +439,7 @@ DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr const CIE *cie = GetCIE (cie_offset); assert (cie != nullptr); - const dw_offset_t end_offset = current_entry + length + 4; + const dw_offset_t end_offset = current_entry + length + (is_64bit ? 12 : 4); const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress(); const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;