Skip to content

[lldb] Disable some unwind plans for discontinuous functions #140927

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
May 22, 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
6 changes: 4 additions & 2 deletions lldb/include/lldb/Symbol/CallFrameInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ class CallFrameInfo {

virtual bool GetAddressRange(Address addr, AddressRange &range) = 0;

virtual bool GetUnwindPlan(const Address &addr, UnwindPlan &unwind_plan) = 0;
virtual bool GetUnwindPlan(const AddressRange &range, UnwindPlan &unwind_plan) = 0;
virtual std::unique_ptr<UnwindPlan>
GetUnwindPlan(llvm::ArrayRef<AddressRange> ranges, const Address &addr) = 0;

virtual std::unique_ptr<UnwindPlan> GetUnwindPlan(const Address &addr) = 0;
};

} // namespace lldb_private
Expand Down
6 changes: 0 additions & 6 deletions lldb/include/lldb/Symbol/FuncUnwinders.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ class FuncUnwinders {
std::shared_ptr<const UnwindPlan>
GetUnwindPlanArchitectureDefaultAtFunctionEntry(lldb_private::Thread &thread);

Address &GetFirstNonPrologueInsn(Target &target);

const Address &GetFunctionStartAddress() const;

bool ContainsAddress(const Address &addr) const {
Expand Down Expand Up @@ -114,10 +112,6 @@ class FuncUnwinders {
/// 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;

std::shared_ptr<const UnwindPlan> m_unwind_plan_assembly_sp;
Expand Down
35 changes: 17 additions & 18 deletions lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,27 +455,26 @@ bool PECallFrameInfo::GetAddressRange(Address addr, AddressRange &range) {
return true;
}

bool PECallFrameInfo::GetUnwindPlan(const Address &addr,
UnwindPlan &unwind_plan) {
return GetUnwindPlan(AddressRange(addr, 1), unwind_plan);
}

bool PECallFrameInfo::GetUnwindPlan(const AddressRange &range,
UnwindPlan &unwind_plan) {
unwind_plan.Clear();

unwind_plan.SetSourceName("PE EH info");
unwind_plan.SetSourcedFromCompiler(eLazyBoolYes);
unwind_plan.SetRegisterKind(eRegisterKindLLDB);
std::unique_ptr<UnwindPlan> PECallFrameInfo::GetUnwindPlan(
llvm::ArrayRef<lldb_private::AddressRange> ranges,
const lldb_private::Address &addr) {
// Only continuous functions are supported.
if (ranges.size() != 1)
return nullptr;
const AddressRange &range = ranges[0];

const RuntimeFunction *runtime_function =
FindRuntimeFunctionIntersectsWithRange(range);
if (!runtime_function)
return false;
return nullptr;

auto plan_up = std::make_unique<UnwindPlan>(eRegisterKindLLDB);
plan_up->SetSourceName("PE EH info");
plan_up->SetSourcedFromCompiler(eLazyBoolYes);

EHProgramBuilder builder(m_object_file, runtime_function->UnwindInfoOffset);
if (!builder.Build())
return false;
return nullptr;

std::vector<UnwindPlan::Row> rows;

Expand All @@ -493,14 +492,14 @@ bool PECallFrameInfo::GetUnwindPlan(const AddressRange &range,
}

for (auto it = rows.rbegin(); it != rows.rend(); ++it)
unwind_plan.AppendRow(std::move(*it));
plan_up->AppendRow(std::move(*it));

unwind_plan.SetPlanValidAddressRanges({AddressRange(
plan_up->SetPlanValidAddressRanges({AddressRange(
m_object_file.GetAddress(runtime_function->StartAddress),
runtime_function->EndAddress - runtime_function->StartAddress)});
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
plan_up->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);

return true;
return plan_up;
}

const RuntimeFunction *PECallFrameInfo::FindRuntimeFunctionIntersectsWithRange(
Expand Down
14 changes: 10 additions & 4 deletions lldb/source/Plugins/ObjectFile/PECOFF/PECallFrameInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_PECOFF_PECALLFRAMEINFO_H
#define LLDB_SOURCE_PLUGINS_OBJECTFILE_PECOFF_PECALLFRAMEINFO_H

#include "lldb/Core/AddressRange.h"
#include "lldb/Symbol/CallFrameInfo.h"
#include "lldb/Symbol/UnwindPlan.h"
#include "lldb/Utility/DataExtractor.h"

class ObjectFilePECOFF;
Expand All @@ -31,10 +33,14 @@ class PECallFrameInfo : public virtual lldb_private::CallFrameInfo {
bool GetAddressRange(lldb_private::Address addr,
lldb_private::AddressRange &range) override;

bool GetUnwindPlan(const lldb_private::Address &addr,
lldb_private::UnwindPlan &unwind_plan) override;
bool GetUnwindPlan(const lldb_private::AddressRange &range,
lldb_private::UnwindPlan &unwind_plan) override;
std::unique_ptr<lldb_private::UnwindPlan>
GetUnwindPlan(const lldb_private::Address &addr) override {
return GetUnwindPlan({lldb_private::AddressRange(addr, 1)}, addr);
}

std::unique_ptr<lldb_private::UnwindPlan>
GetUnwindPlan(llvm::ArrayRef<lldb_private::AddressRange> ranges,
const lldb_private::Address &addr) override;

private:
const llvm::Win64EH::RuntimeFunction *FindRuntimeFunctionIntersectsWithRange(
Expand Down
105 changes: 38 additions & 67 deletions lldb/source/Symbol/FuncUnwinders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,11 @@
using namespace lldb;
using namespace lldb_private;

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_ranges(std::move(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),
m_tried_unwind_plan_object_file_augmented(false),
Expand Down Expand Up @@ -106,8 +87,9 @@ FuncUnwinders::GetCompactUnwindUnwindPlan(Target &target) {
return nullptr;

m_tried_unwind_plan_compact_unwind = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
// Only continuous functions are supported.
if (m_ranges.size() == 1) {
Address current_pc(m_ranges[0].GetBaseAddress());
CompactUnwindInfo *compact_unwind = m_unwind_table.GetCompactUnwindInfo();
if (compact_unwind) {
auto unwind_plan_sp =
Expand All @@ -131,14 +113,10 @@ FuncUnwinders::GetObjectFileUnwindPlan(Target &target) {
return m_unwind_plan_object_file_sp;

m_tried_unwind_plan_object_file = true;
if (m_range.GetBaseAddress().IsValid()) {
CallFrameInfo *object_file_frame = m_unwind_table.GetObjectFileUnwindInfo();
if (object_file_frame) {
auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
if (object_file_frame->GetUnwindPlan(m_range, *plan_sp))
m_unwind_plan_object_file_sp = std::move(plan_sp);
}
}
if (CallFrameInfo *object_file_frame =
m_unwind_table.GetObjectFileUnwindInfo())
m_unwind_plan_object_file_sp =
object_file_frame->GetUnwindPlan(m_ranges, m_addr);
return m_unwind_plan_object_file_sp;
}

Expand Down Expand Up @@ -178,8 +156,9 @@ FuncUnwinders::GetArmUnwindUnwindPlan(Target &target) {
return m_unwind_plan_arm_unwind_sp;

m_tried_unwind_plan_arm_unwind = true;
if (m_range.GetBaseAddress().IsValid()) {
Address current_pc(m_range.GetBaseAddress());
// Only continuous functions are supported.
if (m_ranges.size() == 1) {
Address current_pc = m_ranges[0].GetBaseAddress();
ArmUnwindInfo *arm_unwind_info = m_unwind_table.GetArmUnwindInfo();
if (arm_unwind_info) {
auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
Expand Down Expand Up @@ -215,9 +194,10 @@ FuncUnwinders::GetSymbolFileUnwindPlan(Thread &thread) {
return m_unwind_plan_symbol_file_sp;

m_tried_unwind_plan_symbol_file = true;
if (SymbolFile *symfile = m_unwind_table.GetSymbolFile()) {
if (SymbolFile *symfile = m_unwind_table.GetSymbolFile();
symfile && m_ranges.size() == 1) {
m_unwind_plan_symbol_file_sp = symfile->GetUnwindPlan(
m_range.GetBaseAddress(),
m_ranges[0].GetBaseAddress(),
RegisterContextToInfo(*thread.GetRegisterContext()));
}
return m_unwind_plan_symbol_file_sp;
Expand All @@ -242,10 +222,11 @@ FuncUnwinders::GetObjectFileAugmentedUnwindPlan(Target &target,
// so the UnwindPlan can be used at any instruction in the function.

UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
// Only continuous functions are supported.
if (assembly_profiler_sp && m_ranges.size() == 1) {
auto plan_sp = std::make_shared<UnwindPlan>(*object_file_unwind_plan);

if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_range, thread,
if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_ranges[0], thread,
*plan_sp))
m_unwind_plan_object_file_augmented_sp = std::move(plan_sp);
}
Expand Down Expand Up @@ -280,9 +261,10 @@ FuncUnwinders::GetEHFrameAugmentedUnwindPlan(Target &target, Thread &thread) {
// so the UnwindPlan can be used at any instruction in the function.

UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
// Only continuous functions are supported.
if (assembly_profiler_sp && m_ranges.size() == 1) {
auto plan_sp = std::make_shared<UnwindPlan>(*eh_frame_plan);
if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_range, thread,
if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_ranges[0], thread,
*plan_sp))
m_unwind_plan_eh_frame_augmented_sp = std::move(plan_sp);
}
Expand Down Expand Up @@ -319,10 +301,11 @@ FuncUnwinders::GetDebugFrameAugmentedUnwindPlan(Target &target,
// function.

UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
// Only continuous functions are supported.
if (assembly_profiler_sp && m_ranges.size() == 1) {
auto plan_sp = std::make_shared<UnwindPlan>(*debug_frame_plan);

if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_range, thread,
if (assembly_profiler_sp->AugmentUnwindPlanFromCallSite(m_ranges[0], thread,
*plan_sp))
m_unwind_plan_debug_frame_augmented_sp = std::move(plan_sp);
}
Expand All @@ -339,18 +322,19 @@ FuncUnwinders::GetAssemblyUnwindPlan(Target &target, Thread &thread) {

m_tried_unwind_plan_assembly = true;

// Don't analyze more than 10 megabytes of instructions,
// if a function is legitimately larger than that, we'll
// miss the epilogue instructions, but guard against a
// bogusly large function and analyzing large amounts of
// non-instruction data.
AddressRange range = m_range;
const addr_t func_size =
std::min(range.GetByteSize(), (addr_t)1024 * 10 * 10);
range.SetByteSize(func_size);

UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
// Only continuous functions are supported.
if (assembly_profiler_sp && m_ranges.size() == 1) {
// Don't analyze more than 10 megabytes of instructions,
// if a function is legitimately larger than that, we'll
// miss the epilogue instructions, but guard against a
// bogusly large function and analyzing large amounts of
// non-instruction data.
AddressRange range = m_ranges[0];
const addr_t func_size =
std::min(range.GetByteSize(), (addr_t)1024 * 10 * 10);
range.SetByteSize(func_size);

auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
if (assembly_profiler_sp->GetNonCallSiteUnwindPlanFromAssembly(
range, thread, *plan_sp))
Expand Down Expand Up @@ -457,9 +441,9 @@ FuncUnwinders::GetUnwindPlanFastUnwind(Target &target, Thread &thread) {
m_tried_unwind_fast = true;

UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp) {
if (assembly_profiler_sp && m_ranges.size() == 1) {
auto plan_sp = std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
if (assembly_profiler_sp->GetFastUnwindPlan(m_range, thread, *plan_sp))
if (assembly_profiler_sp->GetFastUnwindPlan(m_ranges[0], thread, *plan_sp))
m_unwind_plan_fast_sp = std::move(plan_sp);
}
return m_unwind_plan_fast_sp;
Expand Down Expand Up @@ -503,19 +487,6 @@ FuncUnwinders::GetUnwindPlanArchitectureDefaultAtFunctionEntry(Thread &thread) {
return m_unwind_plan_arch_default_at_func_entry_sp;
}

Address &FuncUnwinders::GetFirstNonPrologueInsn(Target &target) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_first_non_prologue_insn.IsValid())
return m_first_non_prologue_insn;

ExecutionContext exe_ctx(target.shared_from_this(), false);
UnwindAssemblySP assembly_profiler_sp(GetUnwindAssemblyProfiler(target));
if (assembly_profiler_sp)
assembly_profiler_sp->FirstNonPrologueInsn(m_range, exe_ctx,
m_first_non_prologue_insn);
return m_first_non_prologue_insn;
}

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

lldb::UnwindAssemblySP
Expand Down
7 changes: 3 additions & 4 deletions lldb/source/Target/RegisterContextUnwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -880,10 +880,9 @@ RegisterContextUnwind::GetFullUnwindPlanForFrame() {
CallFrameInfo *object_file_unwind =
pc_module_sp->GetUnwindTable().GetObjectFileUnwindInfo();
if (object_file_unwind) {
auto unwind_plan_sp =
std::make_shared<UnwindPlan>(lldb::eRegisterKindGeneric);
if (object_file_unwind->GetUnwindPlan(m_current_pc, *unwind_plan_sp))
return unwind_plan_sp;
if (std::unique_ptr<UnwindPlan> plan_up =
object_file_unwind->GetUnwindPlan(m_current_pc))
return plan_up;
}

return arch_default_unwind_plan_sp;
Expand Down
Loading
Loading