Skip to content

[lldb] Teach FuncUnwinders about discontinuous functions #133072

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 1 commit into from
Mar 27, 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
20 changes: 16 additions & 4 deletions lldb/include/lldb/Symbol/FuncUnwinders.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class UnwindTable;
class FuncUnwinders {
public:
// FuncUnwinders objects are used to track UnwindPlans for a function (named
// or not - really just an address range)
// or not - really just a set of address ranges)

// We'll record four different UnwindPlans for each address range:
// We'll record four different UnwindPlans for each function:
//
// 1. Unwinding from a call site (a valid exception throw location)
// This is often sourced from the eh_frame exception handling info
Expand All @@ -31,7 +31,8 @@ class FuncUnwinders {
// instructions are finished for migrating breakpoints past the stack frame
// setup instructions when we don't have line table information.

FuncUnwinders(lldb_private::UnwindTable &unwind_table, AddressRange range);
FuncUnwinders(lldb_private::UnwindTable &unwind_table, Address addr,
AddressRanges ranges);

~FuncUnwinders();

Expand All @@ -54,7 +55,9 @@ class FuncUnwinders {
const Address &GetFunctionStartAddress() const;

bool ContainsAddress(const Address &addr) const {
return m_range.ContainsFileAddress(addr);
return llvm::any_of(m_ranges, [&](const AddressRange range) {
return range.ContainsFileAddress(addr);
});
}

// A function may have a Language Specific Data Area specified -- a block of
Expand Down Expand Up @@ -113,6 +116,15 @@ class FuncUnwinders {
Thread &thread, const lldb::UnwindPlanSP &a, const lldb::UnwindPlanSP &b);

UnwindTable &m_unwind_table;

/// Start address of the function described by this object.
Address m_addr;

/// The address ranges of the function.
AddressRanges m_ranges;

/// The smallest address range covering the entire function.
/// DEPRECATED: Use m_ranges instead.
AddressRange m_range;

std::recursive_mutex m_mutex;
Expand Down
3 changes: 1 addition & 2 deletions lldb/include/lldb/Symbol/UnwindTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ class UnwindTable {
void Dump(Stream &s);

void Initialize();
std::optional<AddressRange> GetAddressRange(const Address &addr,
const SymbolContext &sc);
AddressRanges GetAddressRanges(const Address &addr, const SymbolContext &sc);

typedef std::map<lldb::addr_t, lldb::FuncUnwindersSP> collection;
typedef collection::iterator iterator;
Expand Down
36 changes: 24 additions & 12 deletions lldb/source/Symbol/FuncUnwinders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,29 @@
using namespace lldb;
using namespace lldb_private;

/// constructor

FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range)
: m_unwind_table(unwind_table), m_range(range), m_mutex(),
m_unwind_plan_assembly_sp(), m_unwind_plan_eh_frame_sp(),
m_unwind_plan_eh_frame_augmented_sp(), m_unwind_plan_compact_unwind(),
m_unwind_plan_arm_unwind_sp(), m_unwind_plan_fast_sp(),
m_unwind_plan_arch_default_sp(),
m_unwind_plan_arch_default_at_func_entry_sp(),
static AddressRange CollapseRanges(llvm::ArrayRef<AddressRange> ranges) {
if (ranges.empty())
return AddressRange();
if (ranges.size() == 1)
return ranges[0];

Address lowest_addr = ranges[0].GetBaseAddress();
addr_t highest_addr = lowest_addr.GetFileAddress() + ranges[0].GetByteSize();
for (const AddressRange &range : ranges.drop_front()) {
Address range_begin = range.GetBaseAddress();
addr_t range_end = range_begin.GetFileAddress() + range.GetByteSize();
if (range_begin.GetFileAddress() < lowest_addr.GetFileAddress())
lowest_addr = range_begin;
if (range_end > highest_addr)
highest_addr = range_end;
}
return AddressRange(lowest_addr, highest_addr - lowest_addr.GetFileAddress());
}

FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, Address addr,
AddressRanges ranges)
: m_unwind_table(unwind_table), m_addr(std::move(addr)),
m_ranges(std::move(ranges)), m_range(CollapseRanges(m_ranges)),
m_tried_unwind_plan_assembly(false), m_tried_unwind_plan_eh_frame(false),
m_tried_unwind_plan_object_file(false),
m_tried_unwind_plan_debug_frame(false),
Expand Down Expand Up @@ -511,9 +525,7 @@ Address &FuncUnwinders::GetFirstNonPrologueInsn(Target &target) {
return m_first_non_prologue_insn;
}

const Address &FuncUnwinders::GetFunctionStartAddress() const {
return m_range.GetBaseAddress();
}
const Address &FuncUnwinders::GetFunctionStartAddress() const { return m_addr; }

lldb::UnwindAssemblySP
FuncUnwinders::GetUnwindAssemblyProfiler(Target &target) {
Expand Down
43 changes: 24 additions & 19 deletions lldb/source/Symbol/UnwindTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,30 +91,35 @@ void UnwindTable::ModuleWasUpdated() {

UnwindTable::~UnwindTable() = default;

std::optional<AddressRange>
UnwindTable::GetAddressRange(const Address &addr, const SymbolContext &sc) {
AddressRanges UnwindTable::GetAddressRanges(const Address &addr,
const SymbolContext &sc) {
AddressRange range;

// First check the unwind info from the object file plugin
if (m_object_file_unwind_up &&
m_object_file_unwind_up->GetAddressRange(addr, range))
return range;
return {range};

// Check the symbol context
if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
false, range) &&
range.GetBaseAddress().IsValid())
return range;
AddressRanges result;
for (size_t idx = 0;
sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, idx,
false, range) &&
range.GetBaseAddress().IsValid();
++idx)
result.push_back(range);
if (!result.empty())
return result;

// Does the eh_frame unwind info has a function bounds for this addr?
if (m_eh_frame_up && m_eh_frame_up->GetAddressRange(addr, range))
return range;
return {range};

// Try debug_frame as well
if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))
return range;
return {range};

return std::nullopt;
return {};
}

FuncUnwindersSP
Expand All @@ -140,14 +145,14 @@ UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
return pos->second;
}

auto range_or = GetAddressRange(addr, sc);
if (!range_or)
AddressRanges ranges = GetAddressRanges(addr, sc);
if (ranges.empty())
return nullptr;

FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or));
m_unwinds.insert(insert_pos,
std::make_pair(range_or->GetBaseAddress().GetFileAddress(),
func_unwinder_sp));
auto func_unwinder_sp = std::make_shared<FuncUnwinders>(*this, addr, ranges);
for (const AddressRange &range : ranges)
m_unwinds.emplace_hint(insert_pos, range.GetBaseAddress().GetFileAddress(),
func_unwinder_sp);
return func_unwinder_sp;
}

Expand All @@ -159,11 +164,11 @@ FuncUnwindersSP UnwindTable::GetUncachedFuncUnwindersContainingAddress(
const Address &addr, const SymbolContext &sc) {
Initialize();

auto range_or = GetAddressRange(addr, sc);
if (!range_or)
AddressRanges ranges = GetAddressRanges(addr, sc);
if (ranges.empty())
return nullptr;

return std::make_shared<FuncUnwinders>(*this, *range_or);
return std::make_shared<FuncUnwinders>(*this, addr, std::move(ranges));
}

void UnwindTable::Dump(Stream &s) {
Expand Down
Loading