Refactor rangelist handling to prepare for dwarf5 .debug_rngslist

Dwarf5 introduces a new .debug_rngslist section, to take the place
of the Dwarf4 .debug_ranges. However, the dwarf version is CU-based,
and not file-based, so there can be both sections, and which section
the CU needs isn't known until the dwarf parser encounters either
DW_AT_ranges (dwarf 4 and lower) or DW_AT_rnglists_base (dwarf 5).

This change refactors the code around range lists and range list
readers to defer the decision of what section to parse until
the relevant attribute is found. It moves the range list section
reader from the range-list handler itself (which doesn't know which
section it will use) to the CU context, and then lets the handler
know when it encounters DW_AT_ranges.

I will add a reader for the new dwarf5 section, along with the code to
interpret the new section, and its forms and such in a subsequent patch.

Change-Id: Ie92e4c9daa3f0acb98d7ef74f6b9c2065db849b1
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2433684
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Sterling Augustine 2020-09-26 16:48:02 -07:00
parent 9c4671f2e3
commit 2b936b06c1
6 changed files with 59 additions and 48 deletions

View file

@ -1569,10 +1569,11 @@ void LineInfo::ReadLines() {
} }
RangeListReader::RangeListReader(const uint8_t* buffer, uint64_t size, RangeListReader::RangeListReader(const uint8_t* buffer, uint64_t size,
ByteReader* reader, RangeListHandler* handler) ByteReader* reader)
: buffer_(buffer), size_(size), reader_(reader), handler_(handler) { } : buffer_(buffer), size_(size), reader_(reader) { }
bool RangeListReader::ReadRangeList(uint64_t offset) { bool RangeListReader::ReadRangeList(uint64_t offset,
RangeListHandler* handler) {
const uint64_t max_address = const uint64_t max_address =
(reader_->AddressSize() == 4) ? 0xffffffffUL (reader_->AddressSize() == 4) ? 0xffffffffUL
: 0xffffffffffffffffULL; : 0xffffffffffffffffULL;
@ -1589,12 +1590,12 @@ bool RangeListReader::ReadRangeList(uint64_t offset) {
reader_->ReadAddress(buffer_ + offset + reader_->AddressSize()); reader_->ReadAddress(buffer_ + offset + reader_->AddressSize());
if (start_address == max_address) { // Base address selection if (start_address == max_address) { // Base address selection
handler_->SetBaseAddress(end_address); handler->SetBaseAddress(end_address);
} else if (start_address == 0 && end_address == 0) { // End-of-list } else if (start_address == 0 && end_address == 0) { // End-of-list
handler_->Finish(); handler->Finish();
list_end = true; list_end = true;
} else { // Add a range entry } else { // Add a range entry
handler_->AddRange(start_address, end_address); handler->AddRange(start_address, end_address);
} }
offset += entry_size; offset += entry_size;

View file

@ -243,16 +243,14 @@ class RangeListHandler {
class RangeListReader { class RangeListReader {
public: public:
RangeListReader(const uint8_t* buffer, uint64_t size, ByteReader* reader, RangeListReader(const uint8_t* buffer, uint64_t size, ByteReader* reader);
RangeListHandler* handler);
bool ReadRangeList(uint64_t offset); bool ReadRangeList(uint64_t offset, RangeListHandler* handler);
private: private:
const uint8_t* buffer_; const uint8_t* buffer_;
uint64_t size_; uint64_t size_;
ByteReader* reader_; ByteReader* reader_;
RangeListHandler* handler_;
}; };
// This class is the main interface between the reader and the // This class is the main interface between the reader and the

View file

@ -134,6 +134,7 @@ DwarfCUToModule::FileContext::FileContext(const string& filename,
: filename_(filename), : filename_(filename),
module_(module), module_(module),
handle_inter_cu_refs_(handle_inter_cu_refs), handle_inter_cu_refs_(handle_inter_cu_refs),
range_list_reader_(nullptr, 0, nullptr),
file_private_(new FilePrivate()) { file_private_(new FilePrivate()) {
} }
@ -193,7 +194,7 @@ struct DwarfCUToModule::CUContext {
// For printing error messages. // For printing error messages.
WarningReporter* reporter; WarningReporter* reporter;
// For reading ranges from the .debug_ranges section // For handling ranges, however they may be specified.
RangesHandler* ranges_handler; RangesHandler* ranges_handler;
// The source language of this compilation unit. // The source language of this compilation unit.
@ -206,6 +207,9 @@ struct DwarfCUToModule::CUContext {
uint64_t high_pc; uint64_t high_pc;
uint64_t ranges; uint64_t ranges;
// For reading dwarf4 ranges.
scoped_ptr<dwarf2reader::RangeListReader> range_list_reader_;
// The functions defined in this compilation unit. We accumulate // The functions defined in this compilation unit. We accumulate
// them here during parsing. Then, in DwarfCUToModule::Finish, we // them here during parsing. Then, in DwarfCUToModule::Finish, we
// assign them lines and add them to file_context->module. // assign them lines and add them to file_context->module.
@ -512,6 +516,15 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned(
break; break;
case dwarf2reader::DW_AT_ranges: case dwarf2reader::DW_AT_ranges:
ranges_ = data; ranges_ = data;
if (cu_context_->ranges_handler) {
cu_context_->ranges_handler->SetRangesReader(
&cu_context_->file_context->range_list_reader_);
} else {
cu_context_->reporter->MissingRanges();
// The rest of the code will fall back to low-pc, which is better than
// nothing.
ranges_ = 0;
}
break; break;
default: default:

View file

@ -89,6 +89,11 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
const uint8_t* contents, const uint8_t* contents,
uint64_t length); uint64_t length);
void SetDebugRangeInfo(const uint8_t* contents, uint64_t size,
dwarf2reader::ByteReader* reader) {
range_list_reader_ = dwarf2reader::RangeListReader(contents, size, reader);
}
// Clear the section map for testing. // Clear the section map for testing.
void ClearSectionMapForTest(); void ClearSectionMapForTest();
@ -119,6 +124,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// True if we are handling references between compilation units. // True if we are handling references between compilation units.
const bool handle_inter_cu_refs_; const bool handle_inter_cu_refs_;
// Reader for .debug_ranges section, which is global to the file.
dwarf2reader::RangeListReader range_list_reader_;
// Inter-compilation unit data used internally by the handlers. // Inter-compilation unit data used internally by the handlers.
scoped_ptr<FilePrivate> file_private_; scoped_ptr<FilePrivate> file_private_;
}; };
@ -127,16 +135,23 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
// DwarfCUToModule. // DwarfCUToModule.
class RangesHandler { class RangesHandler {
public: public:
RangesHandler() { } RangesHandler() : reader_(nullptr) { }
virtual ~RangesHandler() { } virtual ~RangesHandler() { }
// Called when finishing a function to populate the function's ranges. // Called when finishing a function to populate the function's ranges.
// The ranges' entries are read starting from offset in the .debug_ranges // base_address holds the base PC the range list values are offsets
// section, base_address holds the base PC the range list values are // off. Return false if the rangelist falls out of the relevant section.
// offsets off. Return false if the rangelist falls out of the
// .debug_ranges section.
virtual bool ReadRanges(uint64_t offset, Module::Address base_address, virtual bool ReadRanges(uint64_t offset, Module::Address base_address,
vector<Module::Range>* ranges) = 0; vector<Module::Range>* ranges) = 0;
// Read ranges from this buffer and interpret them according to attr. Called
// upon seeing a DW_AT_ranges or DW_AT_rngslist attribute.
void SetRangesReader(dwarf2reader::RangeListReader* reader) {
reader_ = reader;
}
protected:
dwarf2reader::RangeListReader* reader_;
}; };
// An abstract base class for handlers that handle DWARF line data // An abstract base class for handlers that handle DWARF line data

View file

@ -232,23 +232,14 @@ bool LoadStabs(const typename ElfClass::Ehdr* elf_header,
// owned by a function) with the results. // owned by a function) with the results.
class DumperRangesHandler : public DwarfCUToModule::RangesHandler { class DumperRangesHandler : public DwarfCUToModule::RangesHandler {
public: public:
DumperRangesHandler(const uint8_t* buffer, uint64_t size, DumperRangesHandler() { }
dwarf2reader::ByteReader* reader)
: buffer_(buffer), size_(size), reader_(reader) { }
bool ReadRanges(uint64_t offset, Module::Address base_address, bool ReadRanges(uint64_t offset, Module::Address base_address,
vector<Module::Range>* ranges) { vector<Module::Range>* ranges) {
DwarfRangeListHandler handler(base_address, ranges); DwarfRangeListHandler handler(base_address, ranges);
dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
&handler);
return rangelist_reader.ReadRangeList(offset); return reader_->ReadRangeList(offset, &handler);
} }
private:
const uint8_t* buffer_;
uint64_t size_;
dwarf2reader::ByteReader* reader_;
}; };
// A line-to-module loader that accepts line number info parsed by // A line-to-module loader that accepts line number info parsed by
@ -314,17 +305,18 @@ bool LoadDwarf(const string& dwarf_filename,
} }
// Optional .debug_ranges reader // Optional .debug_ranges reader
scoped_ptr<DumperRangesHandler> ranges_handler;
dwarf2reader::SectionMap::const_iterator ranges_entry = dwarf2reader::SectionMap::const_iterator ranges_entry =
file_context.section_map().find(".debug_ranges"); file_context.section_map().find(".debug_ranges");
if (ranges_entry != file_context.section_map().end()) { if (ranges_entry != file_context.section_map().end()) {
const std::pair<const uint8_t*, uint64_t>& ranges_section = const std::pair<const uint8_t*, uint64_t>& ranges_section =
ranges_entry->second; ranges_entry->second;
ranges_handler.reset( file_context.SetDebugRangeInfo(ranges_section.first,
new DumperRangesHandler(ranges_section.first, ranges_section.second, ranges_section.second,
&byte_reader)); &byte_reader);
} }
DumperRangesHandler ranges_handler;
// Parse all the compilation units in the .debug_info section. // Parse all the compilation units in the .debug_info section.
DumperLineToModule line_to_module(&byte_reader); DumperLineToModule line_to_module(&byte_reader);
dwarf2reader::SectionMap::const_iterator debug_info_entry = dwarf2reader::SectionMap::const_iterator debug_info_entry =
@ -341,7 +333,7 @@ bool LoadDwarf(const string& dwarf_filename,
// data that was found. // data that was found.
DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset); DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
DwarfCUToModule root_handler(&file_context, &line_to_module, DwarfCUToModule root_handler(&file_context, &line_to_module,
ranges_handler.get(), &reporter); &ranges_handler, &reporter);
// Make a Dwarf2Handler that drives the DIEHandler. // Make a Dwarf2Handler that drives the DIEHandler.
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET. // Make a DWARF parser for the compilation unit at OFFSET.

View file

@ -311,23 +311,14 @@ string DumpSymbols::Identifier() {
class DumpSymbols::DumperRangesHandler: class DumpSymbols::DumperRangesHandler:
public DwarfCUToModule::RangesHandler { public DwarfCUToModule::RangesHandler {
public: public:
DumperRangesHandler(const uint8_t* buffer, uint64_t size, DumperRangesHandler() { }
dwarf2reader::ByteReader* reader)
: buffer_(buffer), size_(size), reader_(reader) { }
bool ReadRanges(uint64_t offset, Module::Address base_address, bool ReadRanges(uint64_t offset, Module::Address base_address,
vector<Module::Range>* ranges) { vector<Module::Range>* ranges) {
DwarfRangeListHandler handler(base_address, ranges); DwarfRangeListHandler handler(base_address, ranges);
dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
&handler);
return rangelist_reader.ReadRangeList(offset); return reader_->ReadRangeList(offset, &handler);
} }
private:
const uint8_t* buffer_;
uint64_t size_;
dwarf2reader::ByteReader* reader_;
}; };
// A line-to-module loader that accepts line number info parsed by // A line-to-module loader that accepts line number info parsed by
@ -457,17 +448,18 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module,
DumperLineToModule line_to_module(&byte_reader); DumperLineToModule line_to_module(&byte_reader);
// Optional .debug_ranges reader // Optional .debug_ranges reader
scoped_ptr<DumperRangesHandler> ranges_handler;
dwarf2reader::SectionMap::const_iterator ranges_entry = dwarf2reader::SectionMap::const_iterator ranges_entry =
file_context.section_map().find("__debug_ranges"); file_context.section_map().find("__debug_ranges");
if (ranges_entry != file_context.section_map().end()) { if (ranges_entry != file_context.section_map().end()) {
const std::pair<const uint8_t*, uint64_t>& ranges_section = const std::pair<const uint8_t*, uint64_t>& ranges_section =
ranges_entry->second; ranges_entry->second;
ranges_handler.reset( file_context.SetDebugRangeInfo(ranges_section.first,
new DumperRangesHandler(ranges_section.first, ranges_section.second, ranges_section.second,
&byte_reader)); &byte_reader);
} }
DumperRangesHandler ranges_handler;
// Walk the __debug_info section, one compilation unit at a time. // Walk the __debug_info section, one compilation unit at a time.
uint64_t debug_info_length = debug_info_section.second; uint64_t debug_info_length = debug_info_section.second;
for (uint64_t offset = 0; offset < debug_info_length;) { for (uint64_t offset = 0; offset < debug_info_length;) {
@ -476,7 +468,7 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module,
DwarfCUToModule::WarningReporter reporter(selected_object_name_, DwarfCUToModule::WarningReporter reporter(selected_object_name_,
offset); offset);
DwarfCUToModule root_handler(&file_context, &line_to_module, DwarfCUToModule root_handler(&file_context, &line_to_module,
ranges_handler.get(), &reporter); &ranges_handler, &reporter);
// Make a Dwarf2Handler that drives our DIEHandler. // Make a Dwarf2Handler that drives our DIEHandler.
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET. // Make a DWARF parser for the compilation unit at OFFSET.