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
This commit is contained in:
Todd Fiala 2014-08-25 21:39:30 +00:00
parent 4229228389
commit 1767e11594
1 changed files with 33 additions and 9 deletions

View File

@ -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;