Skip to content
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

Fix various issues with debug_lines parsing, and support DWARF5 #383

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
32 changes: 15 additions & 17 deletions src/dwarf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -724,25 +724,23 @@ void ReadDWARFInlines(const dwarf::File& file, RangeSink* sink,
dwarf::InfoReader reader(file);
dwarf::CUIter iter = reader.GetCUIter(dwarf::InfoReader::Section::kDebugInfo);
dwarf::CU cu;
dwarf::DIEReader die_reader = cu.GetDIEReader();
dwarf::LineInfoReader line_info_reader(file);

if (!iter.NextCU(reader, &cu)) {
THROW("debug info is present, but empty");
}

while (auto abbrev = die_reader.ReadCode(cu)) {
absl::optional<uint64_t> stmt_list;
die_reader.ReadAttributes(
cu, abbrev, [&stmt_list, &cu](uint16_t tag, dwarf::AttrValue val) {
if (tag == DW_AT_stmt_list) {
stmt_list = val.ToUint(cu);
}
});

if (stmt_list) {
line_info_reader.SeekToOffset(*stmt_list, cu.unit_sizes().address_size());
ReadDWARFStmtList(include_line, &line_info_reader, sink);
while (iter.NextCU(reader, &cu)) {
dwarf::DIEReader die_reader = cu.GetDIEReader();
while (auto abbrev = die_reader.ReadCode(cu)) {
absl::optional<uint64_t> stmt_list;
die_reader.ReadAttributes(cu, abbrev,
[&](uint16_t tag, dwarf::AttrValue val) {
if (tag == DW_AT_stmt_list) {
stmt_list = val.ToUint(cu);
}});

if (stmt_list) {
line_info_reader.SeekToOffset(*stmt_list, cu.unit_sizes().address_size());
ReadDWARFStmtList(include_line, &line_info_reader, sink);
}
break; // only root-level unit entries have DW_AT_stmt_list attributes.
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/dwarf/attr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ AttrValue AttrValue::ParseAttr(const CU& cu, uint16_t form, string_view* data) {
case DW_FORM_ref8:
return AttrValue(form, ReadFixed<uint64_t>(data));
case DW_FORM_ref_udata:
return AttrValue(form, ReadLEB128<uint64_t>(data));
case DW_FORM_strx1:
return AttrValue::UnresolvedString(form, ReadFixed<uint8_t>(data));
case DW_FORM_strx2:
Expand Down
140 changes: 115 additions & 25 deletions src/dwarf/line_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,19 @@ void LineInfoReader::SeekToOffset(uint64_t offset, uint8_t address_size) {
sizes_.SetAddressSize(address_size);
data = sizes_.ReadInitialLength(&data);
sizes_.ReadDWARFVersion(&data);
if (sizes_.dwarf_version() >= 5) {
auto encoded_addr_size = ReadFixed<uint8_t>(&data);
auto encoded_selector_size = ReadFixed<uint8_t>(&data);
assert(encoded_addr_size == address_size);
(void)encoded_selector_size;
}

uint64_t header_length = sizes_.ReadDWARFOffset(&data);
string_view program = data;
SkipBytes(header_length, &program);

params_.minimum_instruction_length = ReadFixed<uint8_t>(&data);
if (sizes_.dwarf_version() == 4) {
if (sizes_.dwarf_version() >= 4) {
params_.maximum_operations_per_instruction = ReadFixed<uint8_t>(&data);

if (params_.maximum_operations_per_instruction == 0) {
Expand All @@ -109,37 +116,120 @@ void LineInfoReader::SeekToOffset(uint64_t offset, uint8_t address_size) {

// Read include_directories.
include_directories_.clear();
filenames_.clear();
expanded_filenames_.clear();

// Implicit current directory entry.
include_directories_.push_back(string_view());
if (sizes_.dwarf_version() <= 4) {
// Implicit current directory entry.
include_directories_.push_back(string_view());

while (true) {
string_view dir = ReadNullTerminated(&data);
if (dir.empty()) {
break;
while (true) {
string_view dir = ReadNullTerminated(&data);
if (dir.empty()) {
break;
}
include_directories_.push_back(dir);
}
include_directories_.push_back(dir);
}

// Read file_names.
filenames_.clear();
expanded_filenames_.clear();
// Read file_names.

// Filename 0 is unused.
filenames_.push_back(FileName());
while (true) {
FileName file_name;
file_name.name = ReadNullTerminated(&data);
if (file_name.name.empty()) {
break;
// Filename 0 is unused.
filenames_.push_back(FileName());
while (true) {
FileName file_name;
file_name.name = ReadNullTerminated(&data);
if (file_name.name.empty()) {
break;
}
file_name.directory_index = ReadLEB128<uint32_t>(&data);
file_name.modified_time = ReadLEB128<uint64_t>(&data);
file_name.file_size = ReadLEB128<uint64_t>(&data);
if (file_name.directory_index >= include_directories_.size()) {
THROW("directory index out of range");
}
filenames_.push_back(file_name);
}
} else {
// Dwarf V5 and beyond.
//
auto readPath = [&] (DwarfForm form) {
switch (form) {
case DW_FORM_string:
return ReadNullTerminated(&data);
case DW_FORM_line_strp: {
auto offset = sizes_.ReadDWARFOffset(&data);
return ReadDebugStrEntry(file_.debug_line_str, offset);
}
default:
THROW("directory index out of range");
}
};

auto readEntryFormats = [&]() {
std::vector<std::pair<DwarfLineNumberContentType, DwarfForm>> entryFormats;
auto formatCount = ReadFixed<uint8_t>(&data);
for (uint8_t i = 0; i < formatCount; ++i) {
auto type = static_cast<DwarfLineNumberContentType>(
ReadLEB128<uint32_t>(&data));
auto form = static_cast<DwarfForm>(ReadLEB128<uint32_t>(&data));
entryFormats.emplace_back(type, form);
}
return entryFormats;
};

auto entryFormats = readEntryFormats();

auto directoryCount = ReadLEB128<uint32_t>(&data);
while (directoryCount--) {
std::string_view path = "";
for (auto [ type, form ] : entryFormats) {
switch (type) {
case DW_LNCT_path:
path = readPath(form);
break;
default:
THROW("unhandled directory entry format");
}
}
include_directories_.push_back(path);
}
file_name.directory_index = ReadLEB128<uint32_t>(&data);
file_name.modified_time = ReadLEB128<uint64_t>(&data);
file_name.file_size = ReadLEB128<uint64_t>(&data);
if (file_name.directory_index >= include_directories_.size()) {
THROW("directory index out of range");
auto fileFormats = readEntryFormats();
auto fileCount = ReadLEB128<uint32_t>(&data);
while (fileCount--) {
FileName file_name;
auto &idx = file_name.directory_index;
idx = 0;
for (auto &[ type, form ] : fileFormats) {
switch (type) {
case DW_LNCT_path:
file_name.name = readPath(form);
break;
case DW_LNCT_directory_index: {
switch (form) {
case DW_FORM_udata:
idx = ReadLEB128<uint32_t>(&data);
break;
case DW_FORM_data1:
idx = ReadFixed<uint8_t>(&data);
break;
case DW_FORM_data2:
idx = ReadFixed<uint16_t>(&data);
break;
case DW_FORM_data4:
idx = ReadFixed<uint32_t>(&data);
break;
default:
THROW("unhandled form for directory index");
}
break;
}
default: {
THROW("unhandled type for file format");
}
}
}
filenames_.push_back(file_name);
}
filenames_.push_back(file_name);
}

info_ = LineInfo(params_.default_is_stmt);
Expand Down
Loading