Skip to content

Commit 17aca79

Browse files
authored
[lldb] Teach FuncUnwinders about discontinuous functions (#133072)
The main change here is that we're now able to correctly look up plans for these functions. Previously, due to caching, we could end up with one entry covering most of the address space (because part of the function was at the beginning and one at the end). Now, we can correctly recognise that the part in between does not belong to that function, and we can create a different FuncUnwinders instance for it. It doesn't help the discontinuous function much (its plan will still be garbled), but we can at least properly unwind out of the simple functions in between. Fixing the unwind plans for discontinuous functions requires handling each unwind source specially, and this setup allows us to make the transition incrementally.
1 parent a6e5616 commit 17aca79

File tree

8 files changed

+409
-37
lines changed

8 files changed

+409
-37
lines changed

lldb/include/lldb/Symbol/FuncUnwinders.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ class UnwindTable;
1313
class FuncUnwinders {
1414
public:
1515
// FuncUnwinders objects are used to track UnwindPlans for a function (named
16-
// or not - really just an address range)
16+
// or not - really just a set of address ranges)
1717

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

34-
FuncUnwinders(lldb_private::UnwindTable &unwind_table, AddressRange range);
34+
FuncUnwinders(lldb_private::UnwindTable &unwind_table, Address addr,
35+
AddressRanges ranges);
3536

3637
~FuncUnwinders();
3738

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

5657
bool ContainsAddress(const Address &addr) const {
57-
return m_range.ContainsFileAddress(addr);
58+
return llvm::any_of(m_ranges, [&](const AddressRange range) {
59+
return range.ContainsFileAddress(addr);
60+
});
5861
}
5962

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

115118
UnwindTable &m_unwind_table;
119+
120+
/// Start address of the function described by this object.
121+
Address m_addr;
122+
123+
/// The address ranges of the function.
124+
AddressRanges m_ranges;
125+
126+
/// The smallest address range covering the entire function.
127+
/// DEPRECATED: Use m_ranges instead.
116128
AddressRange m_range;
117129

118130
std::recursive_mutex m_mutex;

lldb/include/lldb/Symbol/UnwindTable.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,7 @@ class UnwindTable {
6666
void Dump(Stream &s);
6767

6868
void Initialize();
69-
std::optional<AddressRange> GetAddressRange(const Address &addr,
70-
const SymbolContext &sc);
69+
AddressRanges GetAddressRanges(const Address &addr, const SymbolContext &sc);
7170

7271
typedef std::map<lldb::addr_t, lldb::FuncUnwindersSP> collection;
7372
typedef collection::iterator iterator;

lldb/source/Symbol/FuncUnwinders.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,29 @@
3131
using namespace lldb;
3232
using namespace lldb_private;
3333

34-
/// constructor
35-
36-
FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range)
37-
: m_unwind_table(unwind_table), m_range(range), m_mutex(),
38-
m_unwind_plan_assembly_sp(), m_unwind_plan_eh_frame_sp(),
39-
m_unwind_plan_eh_frame_augmented_sp(), m_unwind_plan_compact_unwind(),
40-
m_unwind_plan_arm_unwind_sp(), m_unwind_plan_fast_sp(),
41-
m_unwind_plan_arch_default_sp(),
42-
m_unwind_plan_arch_default_at_func_entry_sp(),
34+
static AddressRange CollapseRanges(llvm::ArrayRef<AddressRange> ranges) {
35+
if (ranges.empty())
36+
return AddressRange();
37+
if (ranges.size() == 1)
38+
return ranges[0];
39+
40+
Address lowest_addr = ranges[0].GetBaseAddress();
41+
addr_t highest_addr = lowest_addr.GetFileAddress() + ranges[0].GetByteSize();
42+
for (const AddressRange &range : ranges.drop_front()) {
43+
Address range_begin = range.GetBaseAddress();
44+
addr_t range_end = range_begin.GetFileAddress() + range.GetByteSize();
45+
if (range_begin.GetFileAddress() < lowest_addr.GetFileAddress())
46+
lowest_addr = range_begin;
47+
if (range_end > highest_addr)
48+
highest_addr = range_end;
49+
}
50+
return AddressRange(lowest_addr, highest_addr - lowest_addr.GetFileAddress());
51+
}
52+
53+
FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, Address addr,
54+
AddressRanges ranges)
55+
: m_unwind_table(unwind_table), m_addr(std::move(addr)),
56+
m_ranges(std::move(ranges)), m_range(CollapseRanges(m_ranges)),
4357
m_tried_unwind_plan_assembly(false), m_tried_unwind_plan_eh_frame(false),
4458
m_tried_unwind_plan_object_file(false),
4559
m_tried_unwind_plan_debug_frame(false),
@@ -511,9 +525,7 @@ Address &FuncUnwinders::GetFirstNonPrologueInsn(Target &target) {
511525
return m_first_non_prologue_insn;
512526
}
513527

514-
const Address &FuncUnwinders::GetFunctionStartAddress() const {
515-
return m_range.GetBaseAddress();
516-
}
528+
const Address &FuncUnwinders::GetFunctionStartAddress() const { return m_addr; }
517529

518530
lldb::UnwindAssemblySP
519531
FuncUnwinders::GetUnwindAssemblyProfiler(Target &target) {

lldb/source/Symbol/UnwindTable.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -91,30 +91,35 @@ void UnwindTable::ModuleWasUpdated() {
9191

9292
UnwindTable::~UnwindTable() = default;
9393

94-
std::optional<AddressRange>
95-
UnwindTable::GetAddressRange(const Address &addr, const SymbolContext &sc) {
94+
AddressRanges UnwindTable::GetAddressRanges(const Address &addr,
95+
const SymbolContext &sc) {
9696
AddressRange range;
9797

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

103103
// Check the symbol context
104-
if (sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0,
105-
false, range) &&
106-
range.GetBaseAddress().IsValid())
107-
return range;
104+
AddressRanges result;
105+
for (size_t idx = 0;
106+
sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, idx,
107+
false, range) &&
108+
range.GetBaseAddress().IsValid();
109+
++idx)
110+
result.push_back(range);
111+
if (!result.empty())
112+
return result;
108113

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

113118
// Try debug_frame as well
114119
if (m_debug_frame_up && m_debug_frame_up->GetAddressRange(addr, range))
115-
return range;
120+
return {range};
116121

117-
return std::nullopt;
122+
return {};
118123
}
119124

120125
FuncUnwindersSP
@@ -140,14 +145,14 @@ UnwindTable::GetFuncUnwindersContainingAddress(const Address &addr,
140145
return pos->second;
141146
}
142147

143-
auto range_or = GetAddressRange(addr, sc);
144-
if (!range_or)
148+
AddressRanges ranges = GetAddressRanges(addr, sc);
149+
if (ranges.empty())
145150
return nullptr;
146151

147-
FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, *range_or));
148-
m_unwinds.insert(insert_pos,
149-
std::make_pair(range_or->GetBaseAddress().GetFileAddress(),
150-
func_unwinder_sp));
152+
auto func_unwinder_sp = std::make_shared<FuncUnwinders>(*this, addr, ranges);
153+
for (const AddressRange &range : ranges)
154+
m_unwinds.emplace_hint(insert_pos, range.GetBaseAddress().GetFileAddress(),
155+
func_unwinder_sp);
151156
return func_unwinder_sp;
152157
}
153158

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

162-
auto range_or = GetAddressRange(addr, sc);
163-
if (!range_or)
167+
AddressRanges ranges = GetAddressRanges(addr, sc);
168+
if (ranges.empty())
164169
return nullptr;
165170

166-
return std::make_shared<FuncUnwinders>(*this, *range_or);
171+
return std::make_shared<FuncUnwinders>(*this, addr, std::move(ranges));
167172
}
168173

169174
void UnwindTable::Dump(Stream &s) {

0 commit comments

Comments
 (0)