Implement dwarf5 range lists.

This is a big change. dwarf5 range lists are quite a bit more complicated
than dwarf 4 range lists, both in the contextual information required, and
in their own representation and interpretation.

The big design choice here is how to pass the CU information all the
way down to the reader. I chose a structure, because otherwise the
parameter list gets very long and error prone (and has to be passed
down several levels). This structure could be made a parto of the CU
context itself, or the range handler, so it wouldn't have to be
separately assembled at range-list read time, but both of those
solutions get even more invasive, and harder to follow.

I've tried to figure out how to break this into smaller changes, but it
affects nearly everything that has to do with a compilation unit's
own addresses and when decisions must be made about how to read them.
Dependency injection will do that to you.

It does add tests for range list reading, which did not exist before.

Change-Id: I923b9a2c3379a0f52609bc05310097de5cbb7227
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2446635
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Sterling Augustine 2020-10-02 11:14:49 -07:00
parent 5c7535af78
commit 9ecccc5512
10 changed files with 471 additions and 105 deletions

View file

@ -232,22 +232,20 @@ bool LoadStabs(const typename ElfClass::Ehdr* elf_header,
// owned by a function) with the results.
class DumperRangesHandler : public DwarfCUToModule::RangesHandler {
public:
DumperRangesHandler(const uint8_t* buffer, uint64_t size,
dwarf2reader::ByteReader* reader)
: buffer_(buffer), size_(size), reader_(reader) { }
DumperRangesHandler(dwarf2reader::ByteReader* reader) :
reader_(reader) { }
bool ReadRanges(uint64_t offset, Module::Address base_address,
vector<Module::Range>* ranges) {
DwarfRangeListHandler handler(base_address, ranges);
dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_,
&handler);
return rangelist_reader.ReadRangeList(offset);
bool ReadRanges(
enum dwarf2reader::DwarfForm form, uint64_t data,
dwarf2reader::RangeListReader::CURangesInfo* cu_info,
vector<Module::Range>* ranges) {
DwarfRangeListHandler handler(ranges);
dwarf2reader::RangeListReader range_list_reader(reader_, cu_info,
&handler);
return range_list_reader.ReadRanges(form, data);
}
private:
const uint8_t* buffer_;
uint64_t size_;
dwarf2reader::ByteReader* reader_;
};
@ -313,17 +311,8 @@ bool LoadDwarf(const string& dwarf_filename,
file_context.AddSectionToSectionMap(name, contents, section->sh_size);
}
// Optional .debug_ranges reader
scoped_ptr<DumperRangesHandler> ranges_handler;
dwarf2reader::SectionMap::const_iterator ranges_entry =
file_context.section_map().find(".debug_ranges");
if (ranges_entry != file_context.section_map().end()) {
const std::pair<const uint8_t*, uint64_t>& ranges_section =
ranges_entry->second;
ranges_handler.reset(
new DumperRangesHandler(ranges_section.first, ranges_section.second,
&byte_reader));
}
// .debug_ranges and .debug_rnglists reader
DumperRangesHandler ranges_handler(&byte_reader);
// Parse all the compilation units in the .debug_info section.
DumperLineToModule line_to_module(&byte_reader);
@ -341,7 +330,7 @@ bool LoadDwarf(const string& dwarf_filename,
// data that was found.
DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
DwarfCUToModule root_handler(&file_context, &line_to_module,
ranges_handler.get(), &reporter);
&ranges_handler, &reporter);
// Make a Dwarf2Handler that drives the DIEHandler.
dwarf2reader::DIEDispatcher die_dispatcher(&root_handler);
// Make a DWARF parser for the compilation unit at OFFSET.