Skip to content

Commit 9677e81

Browse files
authored
[lldb/dwarf] Fix DW_IDX_parent processing for split dwarf (#92745)
DWARFDebugInfo only knows how to resolve references in its own file, but in split dwarf, the index entries will refer to DIEs in the separate (DWO) file. To resolve the DIERef correctly we'd either need to go through the SymbolFileDWARF to get the full logic for resolving a DIERef, or use the fact that ToDIERef already looks up the correct unit while computing its result. This patch does the latter. This bug manifested itself in not being able to find type definitions for types in namespaces, so I've modified one of our type resolving test cases to run with debug_names, and added a namespaced class into it (it originally contained only a top-level class).
1 parent bb3d261 commit 9677e81

File tree

12 files changed

+105
-84
lines changed

12 files changed

+105
-84
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,3 @@ DWARFDebugInfo::GetDIE(const DIERef &die_ref) {
259259
return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset());
260260
return DWARFDIE(); // Not found
261261
}
262-
263-
llvm::StringRef DWARFDebugInfo::PeekDIEName(const DIERef &die_ref) {
264-
if (DWARFUnit *cu = GetUnit(die_ref))
265-
return cu->GetNonSkeletonUnit().PeekDIEName(die_ref.die_offset());
266-
return llvm::StringRef();
267-
}

lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,6 @@ class DWARFDebugInfo {
4444
bool ContainsTypeUnits();
4545
DWARFDIE GetDIE(const DIERef &die_ref);
4646

47-
/// Returns the AT_Name of this DIE, if it exists, without parsing the entire
48-
/// compile unit. An empty is string is returned upon error or if the
49-
/// attribute is not present.
50-
llvm::StringRef PeekDIEName(const DIERef &die_ref);
51-
5247
enum {
5348
eDumpFlag_Verbose = (1 << 0), // Verbose dumping
5449
eDumpFlag_ShowForm = (1 << 1), // Show the DW_form type

lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,26 +48,30 @@ DebugNamesDWARFIndex::GetUnits(const DebugNames &debug_names) {
4848
return result;
4949
}
5050

51-
std::optional<DIERef>
52-
DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) const {
51+
DWARFUnit *
52+
DebugNamesDWARFIndex::GetNonSkeletonUnit(const DebugNames::Entry &entry) const {
5353
// Look for a DWARF unit offset (CU offset or local TU offset) as they are
5454
// both offsets into the .debug_info section.
5555
std::optional<uint64_t> unit_offset = entry.getCUOffset();
5656
if (!unit_offset) {
5757
unit_offset = entry.getLocalTUOffset();
5858
if (!unit_offset)
59-
return std::nullopt;
59+
return nullptr;
6060
}
6161

6262
DWARFUnit *cu =
6363
m_debug_info.GetUnitAtOffset(DIERef::Section::DebugInfo, *unit_offset);
64-
if (!cu)
65-
return std::nullopt;
64+
return cu ? &cu->GetNonSkeletonUnit() : nullptr;
65+
}
6666

67-
cu = &cu->GetNonSkeletonUnit();
67+
std::optional<DIERef>
68+
DebugNamesDWARFIndex::ToDIERef(const DebugNames::Entry &entry) const {
69+
DWARFUnit *unit = GetNonSkeletonUnit(entry);
70+
if (!unit)
71+
return std::nullopt;
6872
if (std::optional<uint64_t> die_offset = entry.getDIEUnitOffset())
69-
return DIERef(cu->GetSymbolFileDWARF().GetFileIndex(),
70-
DIERef::Section::DebugInfo, cu->GetOffset() + *die_offset);
73+
return DIERef(unit->GetSymbolFileDWARF().GetFileIndex(),
74+
DIERef::Section::DebugInfo, unit->GetOffset() + *die_offset);
7175

7276
return std::nullopt;
7377
}
@@ -306,10 +310,10 @@ bool DebugNamesDWARFIndex::SameParentChain(
306310
auto maybe_dieoffset = entry.getDIEUnitOffset();
307311
if (!maybe_dieoffset)
308312
return false;
309-
auto die_ref = ToDIERef(entry);
310-
if (!die_ref)
313+
DWARFUnit *unit = GetNonSkeletonUnit(entry);
314+
if (!unit)
311315
return false;
312-
return name == m_debug_info.PeekDIEName(*die_ref);
316+
return name == unit->PeekDIEName(unit->GetOffset() + *maybe_dieoffset);
313317
};
314318

315319
// If the AT_name of any parent fails to match the expected name, we don't

lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class DebugNamesDWARFIndex : public DWARFIndex {
8484
std::unique_ptr<DebugNames> m_debug_names_up;
8585
ManualDWARFIndex m_fallback;
8686

87+
DWARFUnit *GetNonSkeletonUnit(const DebugNames::Entry &entry) const;
8788
std::optional<DIERef> ToDIERef(const DebugNames::Entry &entry) const;
8889
bool ProcessEntry(const DebugNames::Entry &entry,
8990
llvm::function_ref<bool(DWARFDIE die)> callback);
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
CXX_SOURCES = main.cpp derived.cpp base.cpp
22

3-
CFLAGS_EXTRAS = $(LIMIT_DEBUG_INFO_FLAGS)
4-
53
include Makefile.rules

lldb/test/API/lang/cpp/limit-debug-info/TestWithLimitDebugInfo.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,8 @@
55

66

77
class TestWithLimitDebugInfo(TestBase):
8-
@add_test_categories(["dwarf", "dwo"])
9-
def test_limit_debug_info(self):
10-
self.build()
11-
12-
src_file = os.path.join(self.getSourceDir(), "main.cpp")
13-
src_file_spec = lldb.SBFileSpec(src_file)
14-
self.assertTrue(src_file_spec.IsValid(), "breakpoint file")
8+
def _run_test(self, build_dict):
9+
self.build(dictionary=build_dict)
1510

1611
# Get the path of the executable
1712
exe_path = self.getBuildArtifact("a.out")
@@ -21,9 +16,11 @@ def test_limit_debug_info(self):
2116
self.assertTrue(target.IsValid(), VALID_TARGET)
2217

2318
# Break on main function
24-
breakpoint = target.BreakpointCreateBySourceRegex("break here", src_file_spec)
25-
self.assertTrue(
26-
breakpoint.IsValid() and breakpoint.GetNumLocations() >= 1, VALID_BREAKPOINT
19+
lldbutil.run_break_set_by_file_and_line(
20+
self, "derived.h", line_number("derived.h", "// break1")
21+
)
22+
lldbutil.run_break_set_by_file_and_line(
23+
self, "derived.h", line_number("derived.h", "// break2")
2724
)
2825

2926
# Launch the process
@@ -32,14 +29,23 @@ def test_limit_debug_info(self):
3229

3330
# Get the thread of the process
3431
self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
35-
thread = lldbutil.get_stopped_thread(process, lldb.eStopReasonBreakpoint)
36-
thread.StepInto()
3732

38-
# Get frame for current thread
39-
frame = thread.GetSelectedFrame()
33+
self.expect_expr("1", result_type="int", result_value="1")
34+
self.expect_expr("this", result_type="Foo *")
35+
self.expect_expr("this->x", result_type="int", result_value="12345")
36+
37+
self.runCmd("continue")
4038

4139
self.expect_expr("1", result_type="int", result_value="1")
40+
self.expect_expr("this", result_type="ns::Foo2 *")
41+
self.expect_expr("this->x", result_type="int", result_value="23456")
4242

43-
v2 = frame.EvaluateExpression("this")
44-
self.assertTrue(v2.IsValid(), "'expr this' results in a valid SBValue object")
45-
self.assertSuccess(v2.GetError(), "'expr this' succeeds without an error.")
43+
@add_test_categories(["dwarf", "dwo"])
44+
def test_default(self):
45+
self._run_test(dict(CFLAGS_EXTRAS="$(LIMIT_DEBUG_INFO_FLAGS)"))
46+
47+
@add_test_categories(["dwarf", "dwo"])
48+
def test_debug_names(self):
49+
self._run_test(
50+
dict(CFLAGS_EXTRAS="$(LIMIT_DEBUG_INFO_FLAGS) -gdwarf-5 -gpubnames")
51+
)
Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#include "base.h"
22

3-
FooNS::FooNS() : x(12345) {}
4-
5-
void FooNS::bar() {
6-
x = 54321;
7-
}
3+
FooBase::FooBase() : x(12345) {}
4+
ns::Foo2Base::Foo2Base() : x(23456) {}
85

6+
void FooBase::bar() {}
7+
void ns::Foo2Base::bar() {}
Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
class FooNS
2-
{
1+
class FooBase {
32
public:
4-
virtual void bar();
5-
virtual char baz() = 0;
3+
virtual void bar();
64

75
protected:
8-
FooNS();
6+
FooBase();
97

10-
int x;
8+
int x;
119
};
1210

11+
namespace ns {
12+
class Foo2Base {
13+
public:
14+
virtual void bar();
15+
16+
protected:
17+
Foo2Base();
18+
19+
int x;
20+
};
21+
22+
} // namespace ns
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
#include "derived.h"
22

3-
Foo foo1;
4-
Foo foo2;
5-
63
Foo::Foo() { a = 12345; }
4+
ns::Foo2::Foo2() { a = 23456; }
75

8-
char Foo::baz() {
9-
return (char)(x&0xff);
10-
}
6+
Foo foo1;
7+
Foo foo2;
118

9+
ns::Foo2 foo2_1;
10+
ns::Foo2 foo2_2;
Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,36 @@
11
#include "base.h"
22

3-
class Foo : public FooNS
4-
{
3+
class Foo : public FooBase {
54
public:
6-
Foo();
5+
Foo();
76

8-
// Deliberately defined by hand.
9-
Foo &operator=(const Foo &rhs) {
10-
a = rhs.a;
11-
return *this;
12-
}
7+
// Deliberately defined by hand.
8+
Foo &operator=(const Foo &rhs) {
9+
x = rhs.x; // break1
10+
a = rhs.a;
11+
return *this;
12+
}
13+
int a;
14+
};
15+
16+
namespace ns {
17+
class Foo2 : public Foo2Base {
18+
public:
19+
Foo2();
1320

14-
char baz() override;
15-
int a;
21+
// Deliberately defined by hand.
22+
Foo2 &operator=(const Foo2 &rhs) {
23+
x = rhs.x; // break2
24+
a = rhs.a;
25+
return *this;
26+
}
27+
28+
int a;
1629
};
30+
} // namespace ns
1731

1832
extern Foo foo1;
1933
extern Foo foo2;
34+
35+
extern ns::Foo2 foo2_1;
36+
extern ns::Foo2 foo2_2;
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#include "derived.h"
22

33
int main() {
4-
foo1 = foo2; // break here
5-
6-
foo1.bar();
7-
return foo1.baz();
4+
foo1 = foo2;
5+
foo2_1 = foo2_2;
86
}

lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "Plugins/SymbolFile/DWARF/DWARFDIE.h"
1010
#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
1111
#include "TestingSupport/Symbol/YAMLModuleTester.h"
12+
#include "lldb/Core/dwarf.h"
1213
#include "llvm/ADT/STLExtras.h"
1314
#include "gmock/gmock.h"
1415
#include "gtest/gtest.h"
@@ -169,21 +170,20 @@ TEST(DWARFDIETest, PeekName) {
169170
YAMLModuleTester t(yamldata);
170171
auto *symbol_file =
171172
llvm::cast<SymbolFileDWARF>(t.GetModule()->GetSymbolFile());
172-
auto &debug_info = symbol_file->DebugInfo();
173+
DWARFUnit *unit = symbol_file->DebugInfo().GetUnitAtIndex(0);
173174

174-
DIERef first_die(std::nullopt, DIERef::Section::DebugInfo,
175-
11 /*FirstDIEOffset*/);
176-
EXPECT_EQ(debug_info.PeekDIEName(first_die), "");
175+
dw_offset_t first_die_offset = 11;
176+
EXPECT_EQ(unit->PeekDIEName(first_die_offset), "");
177177

178-
DIERef second_die(std::nullopt, DIERef::Section::DebugInfo, 14);
179-
EXPECT_EQ(debug_info.PeekDIEName(second_die), "NameType1");
178+
dw_offset_t second_die_offset = 14;
179+
EXPECT_EQ(unit->PeekDIEName(second_die_offset), "NameType1");
180180

181-
DIERef third_die(std::nullopt, DIERef::Section::DebugInfo, 19);
182-
EXPECT_EQ(debug_info.PeekDIEName(third_die), "NameType2");
181+
dw_offset_t third_die_offset = 19;
182+
EXPECT_EQ(unit->PeekDIEName(third_die_offset), "NameType2");
183183

184-
DIERef fourth_die(std::nullopt, DIERef::Section::DebugInfo, 24);
185-
EXPECT_EQ(debug_info.PeekDIEName(fourth_die), "NameType1");
184+
dw_offset_t fourth_die_offset = 24;
185+
EXPECT_EQ(unit->PeekDIEName(fourth_die_offset), "NameType1");
186186

187-
DIERef fifth_die(std::nullopt, DIERef::Section::DebugInfo, 26);
188-
EXPECT_EQ(debug_info.PeekDIEName(fifth_die), "NameType2");
187+
dw_offset_t fifth_die_offset = 26;
188+
EXPECT_EQ(unit->PeekDIEName(fifth_die_offset), "NameType2");
189189
}

0 commit comments

Comments
 (0)