https://github.com/labath updated https://github.com/llvm/llvm-project/pull/134806
>From eeaad560a727ea2b113ab3eff218f66a46e30c83 Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Fri, 4 Apr 2025 13:36:06 +0200 Subject: [PATCH 1/2] [lldb] Small refactor of eh_frame parsing .. 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). --- lldb/include/lldb/Symbol/DWARFCallFrameInfo.h | 10 ++- lldb/source/Symbol/DWARFCallFrameInfo.cpp | 87 ++++++++++--------- 2 files changed, 53 insertions(+), 44 deletions(-) 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/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, >From bdeeefdd6b41452dc6799cee5cde60c7086d145e Mon Sep 17 00:00:00 2001 From: Pavel Labath <pa...@labath.sk> Date: Thu, 10 Apr 2025 14:59:09 +0200 Subject: [PATCH 2/2] Update lldb/include/lldb/Symbol/DWARFCallFrameInfo.h Co-authored-by: Jonas Devlieghere <jo...@devlieghere.com> --- lldb/include/lldb/Symbol/DWARFCallFrameInfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h index 526f322a770e4..679f652c7f2e0 100644 --- a/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h +++ b/lldb/include/lldb/Symbol/DWARFCallFrameInfo.h @@ -128,7 +128,7 @@ class DWARFCallFrameInfo { void GetFDEIndex(); - // Parsed representation of a Frame Descriptor Entry. + /// Parsed representation of a Frame Descriptor Entry. struct FDE { AddressRange range; bool for_signal_trap = false; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits