[Lldb-commits] [lldb] 23c9cfc - [lldb] Small refactor of eh_frame parsing (#134806)
via lldb-commits
lldb-commits at lists.llvm.org
Fri Apr 11 00:28:00 PDT 2025
Author: Pavel Labath
Date: 2025-04-11T09:27:56+02:00
New Revision: 23c9cfcb7494b2331a80661a0cb83f95a422833c
URL: https://github.com/llvm/llvm-project/commit/23c9cfcb7494b2331a80661a0cb83f95a422833c
DIFF: https://github.com/llvm/llvm-project/commit/23c9cfcb7494b2331a80661a0cb83f95a422833c.diff
LOG: [lldb] Small refactor of eh_frame parsing (#134806)
.. which prepares us for handling of discontinuous functions. The main
change there is that we can have multiple FDEs contributing towards an
unwind plan of a single function. This patch separates the logic for
parsing of a single FDE from the construction of an UnwindPlan (so that
another patch can change the latter to combine several unwind plans).
Co-authored-by: Jonas Devlieghere <jonas at devlieghere.com>
Added:
Modified:
lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
lldb/source/Symbol/DWARFCallFrameInfo.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
index 6cc24a02de257..679f652c7f2e0 100644
--- a/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
+++ b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
@@ -128,8 +128,14 @@ class DWARFCallFrameInfo {
void GetFDEIndex();
- bool FDEToUnwindPlan(dw_offset_t offset, Address startaddr,
- UnwindPlan &unwind_plan);
+ /// Parsed representation of a Frame Descriptor Entry.
+ struct FDE {
+ AddressRange range;
+ bool for_signal_trap = false;
+ uint32_t return_addr_reg_num = LLDB_INVALID_REGNUM;
+ std::vector<UnwindPlan::Row> rows;
+ };
+ std::optional<FDE> ParseFDE(dw_offset_t offset, const Address &startaddr);
const CIE *GetCIE(dw_offset_t cie_offset);
diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
index dac4cd9745f96..fb57c61d413aa 100644
--- a/lldb/source/Symbol/DWARFCallFrameInfo.cpp
+++ b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
@@ -168,9 +168,32 @@ bool DWARFCallFrameInfo::GetUnwindPlan(const AddressRange &range,
module_sp->GetObjectFile() != &m_objfile)
return false;
- if (std::optional<FDEEntryMap::Entry> entry = GetFirstFDEEntryInRange(range))
- return FDEToUnwindPlan(entry->data, addr, unwind_plan);
- return false;
+ std::optional<FDEEntryMap::Entry> entry = GetFirstFDEEntryInRange(range);
+ if (!entry)
+ return false;
+
+ std::optional<FDE> fde = ParseFDE(entry->data, addr);
+ if (!fde)
+ return false;
+
+ unwind_plan.SetSourceName(m_type == EH ? "eh_frame CFI" : "DWARF CFI");
+ // In theory the debug_frame info should be valid at all call sites
+ // ("asynchronous unwind info" as it is sometimes called) but in practice
+ // gcc et al all emit call frame info for the prologue and call sites, but
+ // not for the epilogue or all the other locations during the function
+ // reliably.
+ unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
+ unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
+ unwind_plan.SetRegisterKind(GetRegisterKind());
+
+ unwind_plan.SetPlanValidAddressRanges({fde->range});
+ unwind_plan.SetUnwindPlanForSignalTrap(fde->for_signal_trap ? eLazyBoolYes
+ : eLazyBoolNo);
+ unwind_plan.SetReturnAddressRegister(fde->return_addr_reg_num);
+ for (UnwindPlan::Row &row : fde->rows)
+ unwind_plan.AppendRow(std::move(row));
+
+ return true;
}
bool DWARFCallFrameInfo::GetAddressRange(Address addr, AddressRange &range) {
@@ -522,15 +545,15 @@ void DWARFCallFrameInfo::GetFDEIndex() {
m_fde_index_initialized = true;
}
-bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
- Address startaddr,
- UnwindPlan &unwind_plan) {
+std::optional<DWARFCallFrameInfo::FDE>
+DWARFCallFrameInfo::ParseFDE(dw_offset_t dwarf_offset,
+ const Address &startaddr) {
Log *log = GetLog(LLDBLog::Unwind);
lldb::offset_t offset = dwarf_offset;
lldb::offset_t current_entry = offset;
- if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())
- return false;
+ if (!m_section_sp || m_section_sp->IsEncrypted())
+ return std::nullopt;
if (!m_cfi_data_initialized)
GetCFIData();
@@ -550,20 +573,8 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
// Translate the CIE_id from the eh_frame format, which is relative to the
// FDE offset, into a __eh_frame section offset
- if (m_type == EH) {
- unwind_plan.SetSourceName("eh_frame CFI");
+ if (m_type == EH)
cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;
- unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
- } else {
- unwind_plan.SetSourceName("DWARF CFI");
- // In theory the debug_frame info should be valid at all call sites
- // ("asynchronous unwind info" as it is sometimes called) but in practice
- // gcc et al all emit call frame info for the prologue and call sites, but
- // not for the epilogue or all the other locations during the function
- // reliably.
- unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
- }
- unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
const CIE *cie = GetCIE(cie_offset);
assert(cie != nullptr);
@@ -587,18 +598,15 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
if (cie->augmentation[0] == 'z')
offset += (uint32_t)m_cfi_data.GetULEB128(&offset);
- unwind_plan.SetUnwindPlanForSignalTrap(
- strchr(cie->augmentation, 'S') ? eLazyBoolYes : eLazyBoolNo);
+ FDE fde;
+ fde.for_signal_trap = strchr(cie->augmentation, 'S') != nullptr;
+ fde.range = range;
+ fde.return_addr_reg_num = cie->return_addr_reg_num;
uint32_t code_align = cie->code_align;
int32_t data_align = cie->data_align;
- unwind_plan.SetPlanValidAddressRanges({range});
UnwindPlan::Row row = cie->initial_row;
-
- unwind_plan.SetRegisterKind(GetRegisterKind());
- unwind_plan.SetReturnAddressRegister(cie->return_addr_reg_num);
-
std::vector<UnwindPlan::Row> stack;
UnwindPlan::Row::AbstractRegisterLocation reg_location;
@@ -618,7 +626,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
// that is computed by taking the current entry's location value and
// adding (delta * code_align). All other values in the new row are
// initially identical to the current row.
- unwind_plan.AppendRow(row);
+ fde.rows.push_back(row);
row.SlideOffset(extended_opcode * code_align);
break;
}
@@ -634,9 +642,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
// state, so we need to convert our eh_frame register number from the
// EH frame info, to a register index
- if (unwind_plan.IsValidRowIndex(0) &&
- unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
- reg_location))
+ if (fde.rows[0].GetRegisterInfo(reg_num, reg_location))
row.SetRegisterInfo(reg_num, reg_location);
else {
// If the register was not set in the first row, remove the
@@ -655,7 +661,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
// specified address as the location. All other values in the new row
// are initially identical to the current row. The new location value
// should always be greater than the current one.
- unwind_plan.AppendRow(row);
+ fde.rows.push_back(row);
row.SetOffset(m_cfi_data.GetAddress(&offset) -
startaddr.GetFileAddress());
break;
@@ -666,7 +672,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
// encoding and size of the delta argument.
- unwind_plan.AppendRow(row);
+ fde.rows.push_back(row);
row.SlideOffset(m_cfi_data.GetU8(&offset) * code_align);
break;
}
@@ -676,7 +682,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
// encoding and size of the delta argument.
- unwind_plan.AppendRow(row);
+ fde.rows.push_back(row);
row.SlideOffset(m_cfi_data.GetU16(&offset) * code_align);
break;
}
@@ -686,7 +692,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
// takes a single uword argument that represents a constant delta.
// This instruction is identical to DW_CFA_advance_loc except for the
// encoding and size of the delta argument.
- unwind_plan.AppendRow(row);
+ fde.rows.push_back(row);
row.SlideOffset(m_cfi_data.GetU32(&offset) * code_align);
break;
}
@@ -697,9 +703,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
// number. This instruction is identical to DW_CFA_restore except for
// the encoding and size of the register argument.
uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
- if (unwind_plan.IsValidRowIndex(0) &&
- unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
- reg_location))
+ if (fde.rows[0].GetRegisterInfo(reg_num, reg_location))
row.SetRegisterInfo(reg_num, reg_location);
break;
}
@@ -762,9 +766,8 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
}
}
}
- unwind_plan.AppendRow(row);
-
- return true;
+ fde.rows.push_back(row);
+ return fde;
}
bool DWARFCallFrameInfo::HandleCommonDwarfOpcode(uint8_t primary_opcode,
More information about the lldb-commits
mailing list