Skip to content

[lldb] Small refactor of eh_frame parsing #134806

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
87 changes: 45 additions & 42 deletions lldb/source/Symbol/DWARFCallFrameInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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,
Expand Down