Skip to content

Commit 45c6bf1

Browse files
Improved debug_lines parsing based on the stmt_list attribute of a compilation unit (#71)
1 parent 7c06f50 commit 45c6bf1

File tree

2 files changed

+30
-8
lines changed

2 files changed

+30
-8
lines changed

src/dwarf.cpp

+28-6
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,14 @@ void line_header::read(freader& s, bool needs_byteswap) {
317317
_include_directories.push_back(cur_directory);
318318
}
319319

320+
// REVIST (fosterbrereton): The reading here isn't entirely accurate. The current code stops the
321+
// first time an empty name is found, and interprets that as the end of the file names (and thus
322+
// the `line_header`). However, the spec (as the end of section 6.2.4) states "A compiler may
323+
// generate a single null byte for the file names field and define file names using the
324+
// extended opcode DW_LNE_define_file." This loop, then, should iterate through the end of the
325+
// defined size of `_header_length` instead of using an empty name as a sentry. Any additional
326+
// null bytes should be interpreted as a placeholder file name description. (Admittedly, I
327+
// haven't seen one of these in the wild yet.)
320328
while (true) {
321329
file_name cur_file_name;
322330
cur_file_name._name = s.read_c_string_view();
@@ -420,7 +428,7 @@ struct dwarf::implementation {
420428
std::int32_t read_sleb();
421429

422430
void read_abbreviations();
423-
void read_lines();
431+
void read_lines(std::size_t header_offset);
424432
const abbrev& find_abbreviation(std::uint32_t code) const;
425433

426434
pool_string read_debug_str(std::size_t offset);
@@ -519,10 +527,10 @@ void dwarf::implementation::read_abbreviations() {
519527

520528
/**************************************************************************************************/
521529

522-
void dwarf::implementation::read_lines() {
530+
void dwarf::implementation::read_lines(std::size_t header_offset) {
523531
ZoneScoped;
524532

525-
temp_seek(_s, _debug_line._offset, [&] {
533+
temp_seek(_s, _debug_line._offset + header_offset, [&] {
526534
line_header header;
527535
header.read(_s, _details._needs_byteswap);
528536

@@ -538,7 +546,8 @@ void dwarf::implementation::read_lines() {
538546
}
539547
}
540548

541-
// We don't need to process the rest of __debug__line. We're only here for the file table.
549+
// We don't need to process the rest of this __debug__line subsection.
550+
// We're only here for the file table.
542551
});
543552
}
544553

@@ -1296,8 +1305,6 @@ bool dwarf::implementation::register_sections_done() {
12961305

12971306
read_abbreviations();
12981307

1299-
read_lines();
1300-
13011308
_ready = true;
13021309

13031310
return true;
@@ -1433,6 +1440,21 @@ void dwarf::implementation::process_all_dies() {
14331440

14341441
continue;
14351442
} else if (die._tag == dw::tag::compile_unit || die._tag == dw::tag::partial_unit) {
1443+
// Spec (section 3.1.1) says that compilation and partial units may specify which
1444+
// __debug_line subsection they want to draw their decl_files list from. This also
1445+
// means we need to clear our current decl_files list (from index 1 to the end)
1446+
// whenever we do hit either of these two dies. (What's the right action to take
1447+
// when a unit doesn't have a stmt_list attribute? Where do we get our file names
1448+
// from? Or is the expectation that the DWARF information won't specify any in that
1449+
// case?)
1450+
1451+
assert(!_decl_files.empty());
1452+
_decl_files.erase(std::next(_decl_files.begin()), _decl_files.end());
1453+
1454+
if (attributes.has_uint(dw::at::stmt_list)) {
1455+
read_lines(attributes.uint(dw::at::stmt_list));
1456+
}
1457+
14361458
// REVISIT (fosterbrereton): If the name is a relative path, there may be a
14371459
// DW_AT_comp_dir attribute that specifies the path it is relative from.
14381460
// Is it worth making this path absolute?

src/main.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,8 @@ auto epilogue(bool exception) {
379379
if (log_level_at_least(settings::log_level::warning)) {
380380
cout_safe([&](auto& s) {
381381
s << "ORC complete.\n"
382-
<< " " << g._odrv_count << " ODRVs reported\n"
383-
<< " " << g._object_file_count << " compilation units processed\n"
382+
<< " " << g._odrv_count << " ODRV(s) reported\n"
383+
<< " " << g._object_file_count << " object file(s) processed\n"
384384
<< " " << g._die_processed_count << " dies processed\n"
385385
<< " " << g._die_skipped_count << " dies skipped (" << format_pct(g._die_skipped_count, g._die_processed_count) << ")\n"
386386
<< " " << g._unique_symbol_count << " unique symbols\n"

0 commit comments

Comments
 (0)