Skip to content

Commit 23c9cfc

Browse files
labathJDevlieghere
andauthored
[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@devlieghere.com>
1 parent b3397ba commit 23c9cfc

File tree

2 files changed

+53
-44
lines changed

2 files changed

+53
-44
lines changed

lldb/include/lldb/Symbol/DWARFCallFrameInfo.h

+8-2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,14 @@ class DWARFCallFrameInfo {
128128

129129
void GetFDEIndex();
130130

131-
bool FDEToUnwindPlan(dw_offset_t offset, Address startaddr,
132-
UnwindPlan &unwind_plan);
131+
/// Parsed representation of a Frame Descriptor Entry.
132+
struct FDE {
133+
AddressRange range;
134+
bool for_signal_trap = false;
135+
uint32_t return_addr_reg_num = LLDB_INVALID_REGNUM;
136+
std::vector<UnwindPlan::Row> rows;
137+
};
138+
std::optional<FDE> ParseFDE(dw_offset_t offset, const Address &startaddr);
133139

134140
const CIE *GetCIE(dw_offset_t cie_offset);
135141

lldb/source/Symbol/DWARFCallFrameInfo.cpp

+45-42
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,32 @@ bool DWARFCallFrameInfo::GetUnwindPlan(const AddressRange &range,
168168
module_sp->GetObjectFile() != &m_objfile)
169169
return false;
170170

171-
if (std::optional<FDEEntryMap::Entry> entry = GetFirstFDEEntryInRange(range))
172-
return FDEToUnwindPlan(entry->data, addr, unwind_plan);
173-
return false;
171+
std::optional<FDEEntryMap::Entry> entry = GetFirstFDEEntryInRange(range);
172+
if (!entry)
173+
return false;
174+
175+
std::optional<FDE> fde = ParseFDE(entry->data, addr);
176+
if (!fde)
177+
return false;
178+
179+
unwind_plan.SetSourceName(m_type == EH ? "eh_frame CFI" : "DWARF CFI");
180+
// In theory the debug_frame info should be valid at all call sites
181+
// ("asynchronous unwind info" as it is sometimes called) but in practice
182+
// gcc et al all emit call frame info for the prologue and call sites, but
183+
// not for the epilogue or all the other locations during the function
184+
// reliably.
185+
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
186+
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
187+
unwind_plan.SetRegisterKind(GetRegisterKind());
188+
189+
unwind_plan.SetPlanValidAddressRanges({fde->range});
190+
unwind_plan.SetUnwindPlanForSignalTrap(fde->for_signal_trap ? eLazyBoolYes
191+
: eLazyBoolNo);
192+
unwind_plan.SetReturnAddressRegister(fde->return_addr_reg_num);
193+
for (UnwindPlan::Row &row : fde->rows)
194+
unwind_plan.AppendRow(std::move(row));
195+
196+
return true;
174197
}
175198

176199
bool DWARFCallFrameInfo::GetAddressRange(Address addr, AddressRange &range) {
@@ -522,15 +545,15 @@ void DWARFCallFrameInfo::GetFDEIndex() {
522545
m_fde_index_initialized = true;
523546
}
524547

525-
bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
526-
Address startaddr,
527-
UnwindPlan &unwind_plan) {
548+
std::optional<DWARFCallFrameInfo::FDE>
549+
DWARFCallFrameInfo::ParseFDE(dw_offset_t dwarf_offset,
550+
const Address &startaddr) {
528551
Log *log = GetLog(LLDBLog::Unwind);
529552
lldb::offset_t offset = dwarf_offset;
530553
lldb::offset_t current_entry = offset;
531554

532-
if (m_section_sp.get() == nullptr || m_section_sp->IsEncrypted())
533-
return false;
555+
if (!m_section_sp || m_section_sp->IsEncrypted())
556+
return std::nullopt;
534557

535558
if (!m_cfi_data_initialized)
536559
GetCFIData();
@@ -550,20 +573,8 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
550573

551574
// Translate the CIE_id from the eh_frame format, which is relative to the
552575
// FDE offset, into a __eh_frame section offset
553-
if (m_type == EH) {
554-
unwind_plan.SetSourceName("eh_frame CFI");
576+
if (m_type == EH)
555577
cie_offset = current_entry + (is_64bit ? 12 : 4) - cie_offset;
556-
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
557-
} else {
558-
unwind_plan.SetSourceName("DWARF CFI");
559-
// In theory the debug_frame info should be valid at all call sites
560-
// ("asynchronous unwind info" as it is sometimes called) but in practice
561-
// gcc et al all emit call frame info for the prologue and call sites, but
562-
// not for the epilogue or all the other locations during the function
563-
// reliably.
564-
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
565-
}
566-
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
567578

568579
const CIE *cie = GetCIE(cie_offset);
569580
assert(cie != nullptr);
@@ -587,18 +598,15 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
587598
if (cie->augmentation[0] == 'z')
588599
offset += (uint32_t)m_cfi_data.GetULEB128(&offset);
589600

590-
unwind_plan.SetUnwindPlanForSignalTrap(
591-
strchr(cie->augmentation, 'S') ? eLazyBoolYes : eLazyBoolNo);
601+
FDE fde;
602+
fde.for_signal_trap = strchr(cie->augmentation, 'S') != nullptr;
603+
fde.range = range;
604+
fde.return_addr_reg_num = cie->return_addr_reg_num;
592605

593606
uint32_t code_align = cie->code_align;
594607
int32_t data_align = cie->data_align;
595608

596-
unwind_plan.SetPlanValidAddressRanges({range});
597609
UnwindPlan::Row row = cie->initial_row;
598-
599-
unwind_plan.SetRegisterKind(GetRegisterKind());
600-
unwind_plan.SetReturnAddressRegister(cie->return_addr_reg_num);
601-
602610
std::vector<UnwindPlan::Row> stack;
603611

604612
UnwindPlan::Row::AbstractRegisterLocation reg_location;
@@ -618,7 +626,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
618626
// that is computed by taking the current entry's location value and
619627
// adding (delta * code_align). All other values in the new row are
620628
// initially identical to the current row.
621-
unwind_plan.AppendRow(row);
629+
fde.rows.push_back(row);
622630
row.SlideOffset(extended_opcode * code_align);
623631
break;
624632
}
@@ -634,9 +642,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
634642
// state, so we need to convert our eh_frame register number from the
635643
// EH frame info, to a register index
636644

637-
if (unwind_plan.IsValidRowIndex(0) &&
638-
unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
639-
reg_location))
645+
if (fde.rows[0].GetRegisterInfo(reg_num, reg_location))
640646
row.SetRegisterInfo(reg_num, reg_location);
641647
else {
642648
// If the register was not set in the first row, remove the
@@ -655,7 +661,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
655661
// specified address as the location. All other values in the new row
656662
// are initially identical to the current row. The new location value
657663
// should always be greater than the current one.
658-
unwind_plan.AppendRow(row);
664+
fde.rows.push_back(row);
659665
row.SetOffset(m_cfi_data.GetAddress(&offset) -
660666
startaddr.GetFileAddress());
661667
break;
@@ -666,7 +672,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
666672
// takes a single uword argument that represents a constant delta.
667673
// This instruction is identical to DW_CFA_advance_loc except for the
668674
// encoding and size of the delta argument.
669-
unwind_plan.AppendRow(row);
675+
fde.rows.push_back(row);
670676
row.SlideOffset(m_cfi_data.GetU8(&offset) * code_align);
671677
break;
672678
}
@@ -676,7 +682,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
676682
// takes a single uword argument that represents a constant delta.
677683
// This instruction is identical to DW_CFA_advance_loc except for the
678684
// encoding and size of the delta argument.
679-
unwind_plan.AppendRow(row);
685+
fde.rows.push_back(row);
680686
row.SlideOffset(m_cfi_data.GetU16(&offset) * code_align);
681687
break;
682688
}
@@ -686,7 +692,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
686692
// takes a single uword argument that represents a constant delta.
687693
// This instruction is identical to DW_CFA_advance_loc except for the
688694
// encoding and size of the delta argument.
689-
unwind_plan.AppendRow(row);
695+
fde.rows.push_back(row);
690696
row.SlideOffset(m_cfi_data.GetU32(&offset) * code_align);
691697
break;
692698
}
@@ -697,9 +703,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
697703
// number. This instruction is identical to DW_CFA_restore except for
698704
// the encoding and size of the register argument.
699705
uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
700-
if (unwind_plan.IsValidRowIndex(0) &&
701-
unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num,
702-
reg_location))
706+
if (fde.rows[0].GetRegisterInfo(reg_num, reg_location))
703707
row.SetRegisterInfo(reg_num, reg_location);
704708
break;
705709
}
@@ -762,9 +766,8 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
762766
}
763767
}
764768
}
765-
unwind_plan.AppendRow(row);
766-
767-
return true;
769+
fde.rows.push_back(row);
770+
return fde;
768771
}
769772

770773
bool DWARFCallFrameInfo::HandleCommonDwarfOpcode(uint8_t primary_opcode,

0 commit comments

Comments
 (0)