Skip to content

Commit f7d6ba6

Browse files
jeffreytan81jeffreytan81
authored andcommitted
Fix debug info size statistics for split dwarf (llvm#80218)
`statistics dump` command relies on `SymbolFile::GetDebugInfoSize()` to get total debug info size. The current implementation is missing debug info for split dwarf scenarios which requires getting debug info from separate dwo/dwp files. This patch fixes this issue for split dwarf by parsing debug info from dwp/dwo. New yaml tests are added. --------- Co-authored-by: jeffreytan81 <[email protected]>
1 parent e51bd52 commit f7d6ba6

File tree

8 files changed

+1520
-0
lines changed

8 files changed

+1520
-0
lines changed

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2667,6 +2667,29 @@ static bool UpdateCompilerContextForSimpleTemplateNames(TypeQuery &match) {
26672667
}
26682668
return any_context_updated;
26692669
}
2670+
2671+
uint64_t SymbolFileDWARF::GetDebugInfoSize() {
2672+
DWARFDebugInfo &info = DebugInfo();
2673+
uint32_t num_comp_units = info.GetNumUnits();
2674+
2675+
uint64_t debug_info_size = SymbolFileCommon::GetDebugInfoSize();
2676+
// In dwp scenario, debug info == skeleton debug info + dwp debug info.
2677+
if (std::shared_ptr<SymbolFileDWARFDwo> dwp_sp = GetDwpSymbolFile())
2678+
return debug_info_size + dwp_sp->GetDebugInfoSize();
2679+
2680+
// In dwo scenario, debug info == skeleton debug info + all dwo debug info.
2681+
for (uint32_t i = 0; i < num_comp_units; i++) {
2682+
DWARFUnit *cu = info.GetUnitAtIndex(i);
2683+
if (cu == nullptr)
2684+
continue;
2685+
2686+
SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile();
2687+
if (dwo)
2688+
debug_info_size += dwo->GetDebugInfoSize();
2689+
}
2690+
return debug_info_size;
2691+
}
2692+
26702693
void SymbolFileDWARF::FindTypes(const TypeQuery &query, TypeResults &results) {
26712694

26722695
// Make sure we haven't already searched this SymbolFile before.

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ class SymbolFileDWARF : public SymbolFileCommon {
186186
GetMangledNamesForFunction(const std::string &scope_qualified_name,
187187
std::vector<ConstString> &mangled_names) override;
188188

189+
uint64_t GetDebugInfoSize() override;
190+
189191
void FindTypes(const lldb_private::TypeQuery &match,
190192
lldb_private::TypeResults &results) override;
191193

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,17 @@ lldb::offset_t SymbolFileDWARFDwo::GetVendorDWARFOpcodeSize(
8585
return GetBaseSymbolFile().GetVendorDWARFOpcodeSize(data, data_offset, op);
8686
}
8787

88+
uint64_t SymbolFileDWARFDwo::GetDebugInfoSize() {
89+
// Directly get debug info from current dwo object file's section list
90+
// instead of asking SymbolFileCommon::GetDebugInfo() which parses from
91+
// owning module which is wrong.
92+
SectionList *section_list =
93+
m_objfile_sp->GetSectionList(/*update_module_section_list=*/false);
94+
if (section_list)
95+
return section_list->GetDebugInfoSize();
96+
return 0;
97+
}
98+
8899
bool SymbolFileDWARFDwo::ParseVendorDWARFOpcode(
89100
uint8_t op, const lldb_private::DataExtractor &opcodes,
90101
lldb::offset_t &offset, std::vector<lldb_private::Value> &stack) const {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF {
4747
const lldb::offset_t data_offset,
4848
const uint8_t op) const override;
4949

50+
uint64_t GetDebugInfoSize() override;
51+
5052
bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
5153
lldb::offset_t &offset,
5254
std::vector<Value> &stack) const override;
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
"""
2+
Test SBTarget.GetStatistics() reporting for dwo files.
3+
"""
4+
5+
import json
6+
import os
7+
8+
from lldbsuite.test import lldbtest, lldbutil
9+
from lldbsuite.test.decorators import *
10+
from lldbsuite.test_event.build_exception import BuildError
11+
12+
13+
SKELETON_DEBUGINFO_SIZE = 602
14+
MAIN_DWO_DEBUGINFO_SIZE = 385
15+
FOO_DWO_DEBUGINFO_SIZE = 380
16+
17+
18+
class TestDebugInfoSize(lldbtest.TestBase):
19+
# Concurrency is the primary test factor here, not debug info variants.
20+
NO_DEBUG_INFO_TESTCASE = True
21+
22+
def get_output_from_yaml(self):
23+
exe = self.getBuildArtifact("a.out")
24+
main_dwo = self.getBuildArtifact("a.out-main.dwo")
25+
foo_dwo = self.getBuildArtifact("a.out-foo.dwo")
26+
27+
src_dir = self.getSourceDir()
28+
exe_yaml_path = os.path.join(src_dir, "a.out.yaml")
29+
self.yaml2obj(exe_yaml_path, exe)
30+
31+
main_dwo_yaml_path = os.path.join(src_dir, "a.out-main.dwo.yaml")
32+
self.yaml2obj(main_dwo_yaml_path, main_dwo)
33+
34+
foo_dwo_yaml_path = os.path.join(src_dir, "a.out-foo.dwo.yaml")
35+
self.yaml2obj(foo_dwo_yaml_path, foo_dwo)
36+
return (exe, main_dwo, foo_dwo)
37+
38+
@add_test_categories(["dwo"])
39+
def test_dwo(self):
40+
(exe, main_dwo, foo_dwo) = self.get_output_from_yaml()
41+
42+
# Make sure dwo files exist
43+
self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
44+
self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
45+
46+
target = self.dbg.CreateTarget(exe)
47+
self.assertTrue(target, lldbtest.VALID_TARGET)
48+
49+
stats = target.GetStatistics()
50+
stream = lldb.SBStream()
51+
res = stats.GetAsJSON(stream)
52+
debug_stats = json.loads(stream.GetData())
53+
self.assertIn(
54+
"totalDebugInfoByteSize",
55+
debug_stats,
56+
'Make sure the "totalDebugInfoByteSize" key is in target.GetStatistics()',
57+
)
58+
self.assertEqual(
59+
debug_stats["totalDebugInfoByteSize"],
60+
SKELETON_DEBUGINFO_SIZE + MAIN_DWO_DEBUGINFO_SIZE + FOO_DWO_DEBUGINFO_SIZE,
61+
)
62+
63+
@add_test_categories(["dwo"])
64+
def test_only_load_skeleton_debuginfo(self):
65+
(exe, main_dwo, foo_dwo) = self.get_output_from_yaml()
66+
67+
# REMOVE one of the dwo files
68+
os.unlink(main_dwo)
69+
os.unlink(foo_dwo)
70+
71+
target = self.dbg.CreateTarget(exe)
72+
self.assertTrue(target, lldbtest.VALID_TARGET)
73+
74+
stats = target.GetStatistics()
75+
stream = lldb.SBStream()
76+
res = stats.GetAsJSON(stream)
77+
debug_stats = json.loads(stream.GetData())
78+
self.assertIn(
79+
"totalDebugInfoByteSize",
80+
debug_stats,
81+
'Make sure the "totalDebugInfoByteSize" key is in target.GetStatistics()',
82+
)
83+
self.assertEqual(debug_stats["totalDebugInfoByteSize"], SKELETON_DEBUGINFO_SIZE)
84+
85+
@add_test_categories(["dwo"])
86+
def test_load_partial_dwos(self):
87+
(exe, main_dwo, foo_dwo) = self.get_output_from_yaml()
88+
89+
# REMOVE one of the dwo files
90+
os.unlink(main_dwo)
91+
92+
target = self.dbg.CreateTarget(exe)
93+
self.assertTrue(target, lldbtest.VALID_TARGET)
94+
95+
stats = target.GetStatistics()
96+
stream = lldb.SBStream()
97+
res = stats.GetAsJSON(stream)
98+
debug_stats = json.loads(stream.GetData())
99+
self.assertIn(
100+
"totalDebugInfoByteSize",
101+
debug_stats,
102+
'Make sure the "totalDebugInfoByteSize" key is in target.GetStatistics()',
103+
)
104+
self.assertEqual(
105+
debug_stats["totalDebugInfoByteSize"],
106+
SKELETON_DEBUGINFO_SIZE + FOO_DWO_DEBUGINFO_SIZE,
107+
)
108+
109+
@add_test_categories(["dwo"])
110+
def test_dwos_loaded_symbols_on_demand(self):
111+
(exe, main_dwo, foo_dwo) = self.get_output_from_yaml()
112+
113+
# Make sure dwo files exist
114+
self.assertTrue(os.path.exists(main_dwo), f'Make sure "{main_dwo}" file exists')
115+
self.assertTrue(os.path.exists(foo_dwo), f'Make sure "{foo_dwo}" file exists')
116+
117+
# Load symbols on-demand
118+
self.runCmd("settings set symbols.load-on-demand true")
119+
120+
target = self.dbg.CreateTarget(exe)
121+
self.assertTrue(target, lldbtest.VALID_TARGET)
122+
123+
stats = target.GetStatistics()
124+
stream = lldb.SBStream()
125+
res = stats.GetAsJSON(stream)
126+
debug_stats = json.loads(stream.GetData())
127+
self.assertIn(
128+
"totalDebugInfoByteSize",
129+
debug_stats,
130+
'Make sure the "totalDebugInfoByteSize" key is in target.GetStatistics()',
131+
)
132+
self.assertEqual(
133+
debug_stats["totalDebugInfoByteSize"],
134+
SKELETON_DEBUGINFO_SIZE + MAIN_DWO_DEBUGINFO_SIZE + FOO_DWO_DEBUGINFO_SIZE,
135+
)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--- !ELF
2+
FileHeader:
3+
Class: ELFCLASS64
4+
Data: ELFDATA2LSB
5+
Type: ET_REL
6+
Machine: EM_X86_64
7+
SectionHeaderStringTable: .strtab
8+
Sections:
9+
- Name: .debug_str_offsets.dwo
10+
Type: SHT_PROGBITS
11+
Flags: [ SHF_EXCLUDE ]
12+
AddressAlign: 0x1
13+
Content: 180000000500000000000000040000000800000097000000F6000000
14+
- Name: .debug_str.dwo
15+
Type: SHT_PROGBITS
16+
Flags: [ SHF_EXCLUDE, SHF_MERGE, SHF_STRINGS ]
17+
AddressAlign: 0x1
18+
EntSize: 0x1
19+
Content: 666F6F00696E740046616365626F6F6B20636C616E672076657273696F6E2031352E302E3020287373683A2F2F6769742E7669702E66616365626F6F6B2E636F6D2F646174612F6769747265706F732F6F736D6574612F65787465726E616C2F6C6C766D2D70726F6A656374203435616538646332373465366362636264343064353734353136643533343337393662653135323729002F686F6D652F6A65666672657974616E2F6C6C766D2D73616E642F65787465726E616C2F6C6C766D2D70726F6A6563742F6C6C64622F746573742F4150492F636F6D6D616E64732F7461726765742F6465627567696E666F2F666F6F2E6300612E6F75742D666F6F2E64776F00
20+
- Name: .debug_info.dwo
21+
Type: SHT_PROGBITS
22+
Flags: [ SHF_EXCLUDE ]
23+
AddressAlign: 0x1
24+
Content: 2A0000000500050800000000495EA96AE5C99FC401021D00030402000B0000000156000003290000000301050400
25+
- Name: .debug_abbrev.dwo
26+
Type: SHT_PROGBITS
27+
Flags: [ SHF_EXCLUDE ]
28+
AddressAlign: 0x1
29+
Content: 01110125251305032576250000022E00111B1206401803253A0B3B0B49133F19000003240003253E0B0B0B000000
30+
- Type: SectionHeaderTable
31+
Sections:
32+
- Name: .strtab
33+
- Name: .debug_str_offsets.dwo
34+
- Name: .debug_str.dwo
35+
- Name: .debug_info.dwo
36+
- Name: .debug_abbrev.dwo
37+
...
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--- !ELF
2+
FileHeader:
3+
Class: ELFCLASS64
4+
Data: ELFDATA2LSB
5+
Type: ET_REL
6+
Machine: EM_X86_64
7+
SectionHeaderStringTable: .strtab
8+
Sections:
9+
- Name: .debug_str_offsets.dwo
10+
Type: SHT_PROGBITS
11+
Flags: [ SHF_EXCLUDE ]
12+
AddressAlign: 0x1
13+
Content: 180000000500000000000000050000000900000098000000F8000000
14+
- Name: .debug_str.dwo
15+
Type: SHT_PROGBITS
16+
Flags: [ SHF_EXCLUDE, SHF_MERGE, SHF_STRINGS ]
17+
AddressAlign: 0x1
18+
EntSize: 0x1
19+
Content: 6D61696E00696E740046616365626F6F6B20636C616E672076657273696F6E2031352E302E3020287373683A2F2F6769742E7669702E66616365626F6F6B2E636F6D2F646174612F6769747265706F732F6F736D6574612F65787465726E616C2F6C6C766D2D70726F6A656374203435616538646332373465366362636264343064353734353136643533343337393662653135323729002F686F6D652F6A65666672657974616E2F6C6C766D2D73616E642F65787465726E616C2F6C6C766D2D70726F6A6563742F6C6C64622F746573742F4150492F636F6D6D616E64732F7461726765742F6465627567696E666F2F6D61696E2E6300612E6F75742D6D61696E2E64776F00
20+
- Name: .debug_info.dwo
21+
Type: SHT_PROGBITS
22+
Flags: [ SHF_EXCLUDE ]
23+
AddressAlign: 0x1
24+
Content: 2A000000050005080000000037AA38DE48449DD701021D00030402001C0000000156000103290000000301050400
25+
- Name: .debug_abbrev.dwo
26+
Type: SHT_PROGBITS
27+
Flags: [ SHF_EXCLUDE ]
28+
AddressAlign: 0x1
29+
Content: 01110125251305032576250000022E00111B1206401803253A0B3B0B271949133F19000003240003253E0B0B0B000000
30+
- Type: SectionHeaderTable
31+
Sections:
32+
- Name: .strtab
33+
- Name: .debug_str_offsets.dwo
34+
- Name: .debug_str.dwo
35+
- Name: .debug_info.dwo
36+
- Name: .debug_abbrev.dwo
37+
...

0 commit comments

Comments
 (0)