-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
Conversation
@llvm/pr-subscribers-lldb Author: Pavel Labath (labath) Changes.. which prepares us for handling of discontinuous functions. The main Note to reviewers: This patch consists of three commits. The first two correspond to #134630 and #134662. For reviewing, I recommend looking at the last commit in isolation. Patch is 22.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/134806.diff 9 Files Affected:
diff --git a/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h
index 6cc24a02de257..526f322a770e4 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/include/lldb/Symbol/FuncUnwinders.h b/lldb/include/lldb/Symbol/FuncUnwinders.h
index 479ccf87b6e2c..c21a1af5c56a2 100644
--- a/lldb/include/lldb/Symbol/FuncUnwinders.h
+++ b/lldb/include/lldb/Symbol/FuncUnwinders.h
@@ -61,19 +61,6 @@ class FuncUnwinders {
});
}
- // A function may have a Language Specific Data Area specified -- a block of
- // data in
- // the object file which is used in the processing of an exception throw /
- // catch. If any of the UnwindPlans have the address of the LSDA region for
- // this function, this will return it.
- Address GetLSDAAddress(Target &target);
-
- // A function may have a Personality Routine associated with it -- used in the
- // processing of throwing an exception. If any of the UnwindPlans have the
- // address of the personality routine, this will return it. Read the target-
- // pointer at this address to get the personality function address.
- Address GetPersonalityRoutinePtrAddress(Target &target);
-
// The following methods to retrieve specific unwind plans should rarely be
// used. Instead, clients should ask for the *behavior* they are looking for,
// using one of the above UnwindPlan retrieval methods.
diff --git a/lldb/include/lldb/Symbol/UnwindPlan.h b/lldb/include/lldb/Symbol/UnwindPlan.h
index 6640a23a3e868..cd5451fed6c0c 100644
--- a/lldb/include/lldb/Symbol/UnwindPlan.h
+++ b/lldb/include/lldb/Symbol/UnwindPlan.h
@@ -356,11 +356,11 @@ class UnwindPlan {
void RemoveRegisterInfo(uint32_t reg_num);
- lldb::addr_t GetOffset() const { return m_offset; }
+ int64_t GetOffset() const { return m_offset; }
- void SetOffset(lldb::addr_t offset) { m_offset = offset; }
+ void SetOffset(int64_t offset) { m_offset = offset; }
- void SlideOffset(lldb::addr_t offset) { m_offset += offset; }
+ void SlideOffset(int64_t offset) { m_offset += offset; }
const FAValue &GetCFAValue() const { return m_cfa_value; }
FAValue &GetCFAValue() { return m_cfa_value; }
@@ -420,7 +420,7 @@ class UnwindPlan {
protected:
typedef std::map<uint32_t, AbstractRegisterLocation> collection;
- lldb::addr_t m_offset = 0; // Offset into the function for this row
+ int64_t m_offset = 0; // Offset into the function for this row
FAValue m_cfa_value;
FAValue m_afa_value;
@@ -445,9 +445,7 @@ class UnwindPlan {
m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler),
m_plan_is_valid_at_all_instruction_locations(
rhs.m_plan_is_valid_at_all_instruction_locations),
- m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap),
- m_lsda_address(rhs.m_lsda_address),
- m_personality_func_addr(rhs.m_personality_func_addr) {
+ m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap) {
m_row_list.reserve(rhs.m_row_list.size());
for (const RowSP &row_sp : rhs.m_row_list)
m_row_list.emplace_back(new Row(*row_sp));
@@ -472,7 +470,7 @@ class UnwindPlan {
// practice, the UnwindPlan for a function with no known start address will be
// the architectural default UnwindPlan which will only have one row.
const UnwindPlan::Row *
- GetRowForFunctionOffset(std::optional<int> offset) const;
+ GetRowForFunctionOffset(std::optional<int64_t> offset) const;
lldb::RegisterKind GetRegisterKind() const { return m_register_kind; }
@@ -553,22 +551,10 @@ class UnwindPlan {
m_plan_is_sourced_from_compiler = eLazyBoolCalculate;
m_plan_is_valid_at_all_instruction_locations = eLazyBoolCalculate;
m_plan_is_for_signal_trap = eLazyBoolCalculate;
- m_lsda_address.Clear();
- m_personality_func_addr.Clear();
}
const RegisterInfo *GetRegisterInfo(Thread *thread, uint32_t reg_num) const;
- Address GetLSDAAddress() const { return m_lsda_address; }
-
- void SetLSDAAddress(Address lsda_addr) { m_lsda_address = lsda_addr; }
-
- Address GetPersonalityFunctionPtr() const { return m_personality_func_addr; }
-
- void SetPersonalityFunctionPtr(Address presonality_func_ptr) {
- m_personality_func_addr = presonality_func_ptr;
- }
-
private:
std::vector<RowSP> m_row_list;
std::vector<AddressRange> m_plan_valid_ranges;
@@ -583,13 +569,6 @@ class UnwindPlan {
lldb_private::LazyBool m_plan_is_sourced_from_compiler;
lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
lldb_private::LazyBool m_plan_is_for_signal_trap;
-
- Address m_lsda_address; // Where the language specific data area exists in the
- // module - used
- // in exception handling.
- Address m_personality_func_addr; // The address of a pointer to the
- // personality function - used in
- // exception handling.
}; // class UnwindPlan
} // namespace lldb_private
diff --git a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
index 3eaa2f33fce3e..aaff278ca31e2 100644
--- a/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
@@ -1390,11 +1390,12 @@ bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite(
// If we already have one row for this instruction, we can continue.
while (row_id < unwind_plan.GetRowCount() &&
- unwind_plan.GetRowAtIndex(row_id)->GetOffset() <= offset) {
+ unwind_plan.GetRowAtIndex(row_id)->GetOffset() <=
+ static_cast<int64_t>(offset)) {
row_id++;
}
const UnwindPlan::Row *original_row = unwind_plan.GetRowAtIndex(row_id - 1);
- if (original_row->GetOffset() == offset) {
+ if (original_row->GetOffset() == static_cast<int64_t>(offset)) {
row = *original_row;
continue;
}
diff --git a/lldb/source/Symbol/CompactUnwindInfo.cpp b/lldb/source/Symbol/CompactUnwindInfo.cpp
index 3c97d2ca11fbc..cdbbeb554c688 100644
--- a/lldb/source/Symbol/CompactUnwindInfo.cpp
+++ b/lldb/source/Symbol/CompactUnwindInfo.cpp
@@ -741,9 +741,6 @@ bool CompactUnwindInfo::CreateUnwindPlan_x86_64(Target &target,
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
- unwind_plan.SetLSDAAddress(function_info.lsda_address);
- unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
-
UnwindPlan::Row row;
const int wordsize = 8;
@@ -1011,9 +1008,6 @@ bool CompactUnwindInfo::CreateUnwindPlan_i386(Target &target,
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
- unwind_plan.SetLSDAAddress(function_info.lsda_address);
- unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
-
UnwindPlan::Row row;
const int wordsize = 4;
@@ -1306,9 +1300,6 @@ bool CompactUnwindInfo::CreateUnwindPlan_arm64(Target &target,
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
- unwind_plan.SetLSDAAddress(function_info.lsda_address);
- unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
-
UnwindPlan::Row row;
const int wordsize = 8;
@@ -1437,9 +1428,6 @@ bool CompactUnwindInfo::CreateUnwindPlan_armv7(Target &target,
unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
unwind_plan.SetRegisterKind(eRegisterKindEHFrame);
- unwind_plan.SetLSDAAddress(function_info.lsda_address);
- unwind_plan.SetPersonalityFunctionPtr(function_info.personality_ptr_address);
-
UnwindPlan::Row row;
const int wordsize = 4;
diff --git a/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/lldb/source/Symbol/DWARFCallFrameInfo.cpp
index 957818e8d077f..a508adc82e167 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);
@@ -583,52 +594,19 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
m_objfile.GetSectionList());
range.SetByteSize(range_len);
- addr_t lsda_data_file_address = LLDB_INVALID_ADDRESS;
-
- if (cie->augmentation[0] == 'z') {
- uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
- if (aug_data_len != 0 && cie->lsda_addr_encoding != DW_EH_PE_omit) {
- lldb::offset_t saved_offset = offset;
- lsda_data_file_address =
- GetGNUEHPointer(m_cfi_data, &offset, cie->lsda_addr_encoding,
- pc_rel_addr, text_addr, data_addr);
- if (offset - saved_offset != aug_data_len) {
- // There is more in the augmentation region than we know how to process;
- // don't read anything.
- lsda_data_file_address = LLDB_INVALID_ADDRESS;
- }
- offset = saved_offset;
- }
- offset += aug_data_len;
- }
- unwind_plan.SetUnwindPlanForSignalTrap(
- strchr(cie->augmentation, 'S') ? eLazyBoolYes : eLazyBoolNo);
-
- Address lsda_data;
- Address personality_function_ptr;
+ // Skip the LSDA, if present.
+ if (cie->augmentation[0] == 'z')
+ offset += (uint32_t)m_cfi_data.GetULEB128(&offset);
- if (lsda_data_file_address != LLDB_INVALID_ADDRESS &&
- cie->personality_loc != LLDB_INVALID_ADDRESS) {
- m_objfile.GetModule()->ResolveFileAddress(lsda_data_file_address,
- lsda_data);
- m_objfile.GetModule()->ResolveFileAddress(cie->personality_loc,
- personality_function_ptr);
- }
-
- if (lsda_data.IsValid() && personality_function_ptr.IsValid()) {
- unwind_plan.SetLSDAAddress(lsda_data);
- unwind_plan.SetPersonalityFunctionPtr(personality_function_ptr);
- }
+ 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;
@@ -648,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;
}
@@ -664,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
@@ -685,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;
@@ -696,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;
}
@@ -706,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;
}
@@ -716,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;
}
@@ -727,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;
}
@@ -765,7 +739,7 @@ bool DWARFCallFrameInfo::FDEToUnwindPlan(dw_offset_t dwarf_offset,
__FUNCTION__, dwarf_offset, startaddr.GetFileAddress());
break;
}
- lldb::addr_t offset = row.GetOffset();
+ int64_t offset = row.GetOffset();
row = std::move(stack.back());
stack.pop_back();
row.SetOffset(offset);
@@ -792,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,
diff --git a/lldb/source/Symbol/FuncUnwinders.cpp b/lldb/source/Symbol/FuncUnwinders.cpp
index a74029d8343c7..11600825e8e38 100644
--- a/lldb/source/Symbol/FuncUnwinders.cpp
+++ b/lldb/source/Symbol/FuncUnwinders.cpp
@@ -537,39 +537,3 @@ FuncUnwinders::GetUnwindAssemblyProfiler(Target &target) {
}
return assembly_profiler_sp;
}
-
-Address FuncUnwinders::GetLSDAAddress(Target &target) {
- Address lsda_addr;
-
- std::shared_ptr<const UnwindPlan> unwind_plan_sp =
- GetEHFrameUnwindPlan(target);
- if (unwind_plan_sp.get() == nullptr) {
- unwind_plan_sp = GetCompactUnwindUnwindPlan(target);
- }
- if (unwind_plan_sp.get() == nullptr) {
- unwind_plan_sp = GetObjectFileUnwindPlan(target);
- }
- if (unwind_plan_sp.get() && unwind_plan_sp->GetLSDAAddress().IsValid()) {
- lsda_addr = unwind_plan_sp->GetLSDAAddress();
- }
- return lsda_addr;
-}
-
-Address FuncUnwinders::GetPersonalityRoutinePtrAddress(Target &target) {
- Address personality_addr;
-
- std::shared_ptr<const UnwindPlan> unwind_plan_sp =
- GetEHFrameUnwindPlan(target);
- if (unwind_plan_sp.get() == nullptr) {
- unwind_plan_sp = GetCompactUnwindUnwindPlan(target);
- }
- if (unwind_plan_sp.get() == nullptr) {
- unwind_plan_sp = GetObjectFileUnwindPlan(target);
- }
- if (unwind_plan_sp.get() &&
- unwind_plan_sp->GetPersonalityFunctionPtr().IsValid()) {
- personality_addr = unwind_plan_sp->GetPersonalityFunctionPtr();
- }
-
- return personality_addr;
-}
diff --git a/lldb/source/Symbol/UnwindPlan.cpp b/lldb/source/Symbol/UnwindPlan.cpp
index cfa8eefaa55bb..137466025c982 100644
--- a/lldb/source/Symbol/UnwindPlan.cpp
+++ b/lldb/source...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
.. 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 <[email protected]>
.. 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 <[email protected]>
.. 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 <[email protected]>
.. 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).
Note to reviewers: This patch consists of three commits. The first two correspond to #134630 and #134662. For reviewing, I recommend looking at the last commit in isolation.