From 16e08520e6027df4bf1934abbfd5e1a088ffb69c Mon Sep 17 00:00:00 2001 From: Gabriele Svelto Date: Sat, 4 Aug 2018 00:59:34 +0200 Subject: Add support for parsing the DW_AT_ranges attributes This enables the DWARF reader to properly parse DW_AT_ranges attributes in compilation units and functions. Code covered by a function is now represented by a vector of ranges instead of a single contiguous range and DW_AT_ranges entries are used to populate it. All the code and tests that assumed functions to be contiguous entities has been updated to reflect the change. DW_AT_ranges attributes found in compilation units are parsed but no data is generated for them as it is not currently needed. BUG=754 Change-Id: I310391b525aaba0dd329f1e3187486f2e0c6d442 Reviewed-on: https://chromium-review.googlesource.com/1124721 Reviewed-by: Ted Mielczarek --- src/common/dwarf/dwarf2reader.cc | 35 +++++ src/common/dwarf/dwarf2reader.h | 30 ++++ src/common/dwarf/functioninfo.cc | 3 + src/common/dwarf/functioninfo.h | 2 + src/common/dwarf_cu_to_module.cc | 240 ++++++++++++++++++++++-------- src/common/dwarf_cu_to_module.h | 28 ++++ src/common/dwarf_cu_to_module_unittest.cc | 20 +-- src/common/dwarf_range_list_handler.cc | 60 ++++++++ src/common/dwarf_range_list_handler.h | 79 ++++++++++ src/common/linux/dump_symbols.cc | 41 ++++- src/common/mac/dump_syms.cc | 42 +++++- src/common/mac/dump_syms.h | 1 + src/common/module.cc | 39 +++-- src/common/module.h | 15 +- src/common/module_unittest.cc | 35 +++-- src/common/stabs_to_module.cc | 10 +- src/common/stabs_to_module_unittest.cc | 8 +- 17 files changed, 577 insertions(+), 111 deletions(-) create mode 100644 src/common/dwarf_range_list_handler.cc create mode 100644 src/common/dwarf_range_list_handler.h (limited to 'src/common') diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index f2dc4afe..27f3a83e 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -1247,6 +1247,41 @@ void LineInfo::ReadLines() { after_header_ = lengthstart + header_.total_length; } +RangeListReader::RangeListReader(const uint8_t *buffer, uint64 size, + ByteReader *reader, RangeListHandler *handler) + : buffer_(buffer), size_(size), reader_(reader), handler_(handler) { } + +bool RangeListReader::ReadRangeList(uint64 offset) { + const uint64 max_address = + (reader_->AddressSize() == 4) ? 0xffffffffUL + : 0xffffffffffffffffULL; + const uint64 entry_size = reader_->AddressSize() * 2; + bool list_end = false; + + do { + if (offset > size_ - entry_size) { + return false; // Invalid range detected + } + + uint64 start_address = reader_->ReadAddress(buffer_ + offset); + uint64 end_address = + reader_->ReadAddress(buffer_ + offset + reader_->AddressSize()); + + if (start_address == max_address) { // Base address selection + handler_->SetBaseAddress(end_address); + } else if (start_address == 0 && end_address == 0) { // End-of-list + handler_->Finish(); + list_end = true; + } else { // Add a range entry + handler_->AddRange(start_address, end_address); + } + + offset += entry_size; + } while (!list_end); + + return true; +} + // A DWARF rule for recovering the address or value of a register, or // computing the canonical frame address. There is one subclass of this for // each '*Rule' member function in CallFrameInfo::Handler. diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index 5d2d7f60..cf3ba3cd 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -187,6 +187,36 @@ class LineInfoHandler { uint32 file_num, uint32 line_num, uint32 column_num) { } }; +class RangeListHandler { + public: + RangeListHandler() { } + + virtual ~RangeListHandler() { } + + // Add a range. + virtual void AddRange(uint64 begin, uint64 end) { }; + + // A new base address must be set for computing the ranges' addresses. + virtual void SetBaseAddress(uint64 base_address) { }; + + // Finish processing the range list. + virtual void Finish() { }; +}; + +class RangeListReader { + public: + RangeListReader(const uint8_t *buffer, uint64 size, ByteReader *reader, + RangeListHandler *handler); + + bool ReadRangeList(uint64 offset); + + private: + const uint8_t *buffer_; + uint64 size_; + ByteReader* reader_; + RangeListHandler *handler_; +}; + // This class is the main interface between the reader and the // client. The virtual functions inside this get called for // interesting events that happen during DWARF2 reading. diff --git a/src/common/dwarf/functioninfo.cc b/src/common/dwarf/functioninfo.cc index 55a255ed..a0def62e 100644 --- a/src/common/dwarf/functioninfo.cc +++ b/src/common/dwarf/functioninfo.cc @@ -184,6 +184,9 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset, case DW_AT_decl_file: current_function_info_->file = files_->at(data).name; break; + case DW_AT_ranges: + current_function_info->ranges = data; + break; default: break; } diff --git a/src/common/dwarf/functioninfo.h b/src/common/dwarf/functioninfo.h index 0b08a5fc..9efae6d4 100644 --- a/src/common/dwarf/functioninfo.h +++ b/src/common/dwarf/functioninfo.h @@ -58,6 +58,8 @@ struct FunctionInfo { uint64 lowpc; // End address for this function. uint64 highpc; + // Ranges offset + uint64 ranges; }; struct SourceFileInfo { diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index 38fc4c16..f5a03b42 100644 --- a/src/common/dwarf_cu_to_module.cc +++ b/src/common/dwarf_cu_to_module.cc @@ -44,6 +44,7 @@ #include #include +#include #include #include "common/dwarf_line_to_module.h" @@ -51,6 +52,7 @@ namespace google_breakpad { +using std::accumulate; using std::map; using std::pair; using std::sort; @@ -167,10 +169,15 @@ bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference( // parsing. This is for data shared across the CU's entire DIE tree, // and parameters from the code invoking the CU parser. struct DwarfCUToModule::CUContext { - CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg) + CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg, + RangesHandler *ranges_handler_arg) : file_context(file_context_arg), reporter(reporter_arg), - language(Language::CPlusPlus) {} + ranges_handler(ranges_handler_arg), + language(Language::CPlusPlus), + low_pc(0), + high_pc(0), + ranges(0) {} ~CUContext() { for (vector::iterator it = functions.begin(); @@ -185,9 +192,19 @@ struct DwarfCUToModule::CUContext { // For printing error messages. WarningReporter *reporter; + // For reading ranges from the .debug_ranges section + RangesHandler *ranges_handler; + // The source language of this compilation unit. const Language *language; + // Addresses covered by this CU. If high_pc_ is non-zero then the CU covers + // low_pc to high_pc, otherwise ranges is non-zero and low_pc represents + // the base address of the ranges covered by the CU. + uint64 low_pc; + uint64 high_pc; + uint64 ranges; + // The functions defined in this compilation unit. We accumulate // them here during parsing. Then, in DwarfCUToModule::Finish, we // assign them lines and add them to file_context->module. @@ -445,7 +462,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { uint64 offset) : GenericDIEHandler(cu_context, parent_context, offset), low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr), - abstract_origin_(NULL), inline_(false) { } + ranges_(0), abstract_origin_(NULL), inline_(false) { } void ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, uint64 data); @@ -465,6 +482,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { string name_; uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address. + uint64 ranges_; // DW_AT_ranges const AbstractOrigin* abstract_origin_; bool inline_; }; @@ -484,6 +502,9 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( high_pc_form_ = form; high_pc_ = data; break; + case dwarf2reader::DW_AT_ranges: + ranges_ = data; + break; default: GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); @@ -537,17 +558,47 @@ bool DwarfCUToModule::FuncHandler::EndAttributes() { return true; } +static bool IsEmptyRange(vector ranges) { + uint64 size = accumulate(ranges.cbegin(), ranges.cend(), 0, + [](uint64 total, Module::Range entry) { + return total + entry.size; + } + ); + + return size == 0; +} + void DwarfCUToModule::FuncHandler::Finish() { - // Make high_pc_ an address, if it isn't already. - if (high_pc_form_ != dwarf2reader::DW_FORM_addr) { - high_pc_ += low_pc_; + vector ranges; + + if (!ranges_) { + // Make high_pc_ an address, if it isn't already. + if (high_pc_form_ != dwarf2reader::DW_FORM_addr) { + high_pc_ += low_pc_; + } + + Module::Range range(low_pc_, high_pc_ - low_pc_); + ranges.push_back(range); + } else { + RangesHandler *ranges_handler = cu_context_->ranges_handler; + + if (ranges_handler) { + if (!ranges_handler->ReadRanges(ranges_, cu_context_->low_pc, &ranges)) { + ranges.clear(); + cu_context_->reporter->MalformedRangeList(ranges_); + } + } else { + cu_context_->reporter->MissingRanges(); + } } // Did we collect the information we need? Not all DWARF function - // entries have low and high addresses (for example, inlined - // functions that were never used), but all the ones we're - // interested in cover a non-empty range of bytes. - if (low_pc_ < high_pc_) { + // entries are non-empty (for example, inlined functions that were never + // used), but all the ones we're interested in cover a non-empty range of + // bytes. + if (!IsEmptyRange(ranges)) { + low_pc_ = ranges.front().address; + // Malformed DWARF may omit the name, but all Module::Functions must // have names. string name; @@ -561,7 +612,7 @@ void DwarfCUToModule::FuncHandler::Finish() { // Create a Module::Function based on the data we've gathered, and // add it to the functions_ list. scoped_ptr func(new Module::Function(name, low_pc_)); - func->size = high_pc_ - low_pc_; + func->ranges = ranges; func->parameter_size = 0; if (func->address) { // If the function address is zero this is a sign that this function @@ -663,7 +714,7 @@ void DwarfCUToModule::WarningReporter::UncoveredFunction( return; UncoveredHeading(); fprintf(stderr, " function%s: %s\n", - function.size == 0 ? " (zero-length)" : "", + IsEmptyRange(function.ranges) ? " (zero-length)" : "", function.name.c_str()); } @@ -697,11 +748,25 @@ void DwarfCUToModule::WarningReporter::UnhandledInterCUReference( filename_.c_str(), offset, target); } +void DwarfCUToModule::WarningReporter::MalformedRangeList(uint64 offset) { + CUHeading(); + fprintf(stderr, "%s: warning: the range list at offset 0x%llx falls out of " + "the .debug_ranges section.\n", + filename_.c_str(), offset); +} + +void DwarfCUToModule::WarningReporter::MissingRanges() { + CUHeading(); + fprintf(stderr, "%s: warning: A DW_AT_ranges attribute was encountered but " + "the .debug_ranges section is missing.\n", filename_.c_str()); +} + DwarfCUToModule::DwarfCUToModule(FileContext *file_context, LineToModuleHandler *line_reader, + RangesHandler *ranges_handler, WarningReporter *reporter) : line_reader_(line_reader), - cu_context_(new CUContext(file_context, reporter)), + cu_context_(new CUContext(file_context, reporter, ranges_handler)), child_context_(new DIEContext()), has_source_line_info_(false) { } @@ -732,6 +797,16 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, case dwarf2reader::DW_AT_language: // source language of this CU SetLanguage(static_cast(data)); break; + case dwarf2reader::DW_AT_low_pc: + cu_context_->low_pc = data; + break; + case dwarf2reader::DW_AT_high_pc: + cu_context_->high_pc = data; + break; + case dwarf2reader::DW_AT_ranges: + cu_context_->ranges = data; + break; + default: break; } @@ -841,6 +916,46 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) { } namespace { +class FunctionRange { + public: + FunctionRange(const Module::Range &range, Module::Function *function) : + address(range.address), size(range.size), function(function) { } + + void AddLine(Module::Line &line) { + function->lines.push_back(line); + } + + Module::Address address; + Module::Address size; + Module::Function *function; +}; + +// Fills an array of ranges with pointers to the functions which owns them. +// The array is sorted in ascending order and the ranges are non-overlapping. + +static void FillSortedFunctionRanges(vector &dest_ranges, + vector *functions) { + for (vector::const_iterator func_it = functions->cbegin(); + func_it != functions->cend(); + func_it++) + { + Module::Function *func = *func_it; + vector &ranges = func->ranges; + for (vector::const_iterator ranges_it = ranges.cbegin(); + ranges_it != ranges.cend(); + ++ranges_it) { + FunctionRange range(*ranges_it, func); + dest_ranges.push_back(range); + } + } + + sort(dest_ranges.begin(), dest_ranges.end(), + [](const FunctionRange &fr1, const FunctionRange &fr2) { + return fr1.address < fr2.address; + } + ); +} + // Return true if ADDRESS falls within the range of ITEM. template inline bool within(const T &item, Module::Address address) { @@ -880,47 +995,50 @@ void DwarfCUToModule::AssignLinesToFunctions() { const Module::Function *last_function_cited = NULL; const Module::Line *last_line_cited = NULL; - // Make a single pass through both vectors from lower to higher - // addresses, populating each Function's lines vector with lines - // from our lines_ vector that fall within the function's address - // range. - vector::iterator func_it = functions->begin(); + // Prepare a sorted list of ranges with range-to-function mapping + vector sorted_ranges; + FillSortedFunctionRanges(sorted_ranges, functions); + + // Make a single pass through both the range and line vectors from lower to + // higher addresses, populating each range's function lines vector with lines + // from our lines_ vector that fall within the range. + vector::iterator range_it = sorted_ranges.begin(); vector::const_iterator line_it = lines_.begin(); Module::Address current; // Pointers to the referents of func_it and line_it, or NULL if the // iterator is at the end of the sequence. - Module::Function *func; + FunctionRange *range; const Module::Line *line; // Start current at the beginning of the first line or function, // whichever is earlier. - if (func_it != functions->end() && line_it != lines_.end()) { - func = *func_it; + if (range_it != sorted_ranges.end() && line_it != lines_.end()) { + range = &*range_it; line = &*line_it; - current = std::min(func->address, line->address); + current = std::min(range->address, line->address); } else if (line_it != lines_.end()) { - func = NULL; + range = NULL; line = &*line_it; current = line->address; - } else if (func_it != functions->end()) { - func = *func_it; + } else if (range_it != sorted_ranges.end()) { + range = &*range_it; line = NULL; - current = (*func_it)->address; + current = range->address; } else { return; } - while (func || line) { + while (range || line) { // This loop has two invariants that hold at the top. // // First, at least one of the iterators is not at the end of its // sequence, and those that are not refer to the earliest - // function or line that contains or starts after CURRENT. + // range or line that contains or starts after CURRENT. // // Note that every byte is in one of four states: it is covered - // or not covered by a function, and, independently, it is + // or not covered by a range, and, independently, it is // covered or not covered by a line. // // The second invariant is that CURRENT refers to a byte whose @@ -930,7 +1048,7 @@ void DwarfCUToModule::AssignLinesToFunctions() { // // Note that, although each iteration advances CURRENT from one // transition address to the next in each iteration, it might - // not advance the iterators. Suppose we have a function that + // not advance the iterators. Suppose we have a range that // starts with a line, has a gap, and then a second line, and // suppose that we enter an iteration with CURRENT at the end of // the first line. The next transition address is the start of @@ -938,11 +1056,11 @@ void DwarfCUToModule::AssignLinesToFunctions() { // advance CURRENT to that point. At the head of that iteration, // the invariants require that the line iterator be pointing at // the second line. But this is also true at the head of the - // next. And clearly, the iteration must not change the function + // next. And clearly, the iteration must not change the range // iterator. So neither iterator moves. // Assert the first invariant (see above). - assert(!func || current < func->address || within(*func, current)); + assert(!range || current < range->address || within(*range, current)); assert(!line || current < line->address || within(*line, current)); // The next transition after CURRENT. @@ -950,33 +1068,33 @@ void DwarfCUToModule::AssignLinesToFunctions() { // Figure out which state we're in, add lines or warn, and compute // the next transition address. - if (func && current >= func->address) { + if (range && current >= range->address) { if (line && current >= line->address) { - // Covered by both a line and a function. - Module::Address func_left = func->size - (current - func->address); + // Covered by both a line and a range. + Module::Address range_left = range->size - (current - range->address); Module::Address line_left = line->size - (current - line->address); // This may overflow, but things work out. - next_transition = current + std::min(func_left, line_left); + next_transition = current + std::min(range_left, line_left); Module::Line l = *line; l.address = current; l.size = next_transition - current; - func->lines.push_back(l); + range->AddLine(l); last_line_used = line; } else { - // Covered by a function, but no line. - if (func != last_function_cited) { - reporter->UncoveredFunction(*func); - last_function_cited = func; + // Covered by a range, but no line. + if (range->function != last_function_cited) { + reporter->UncoveredFunction(*(range->function)); + last_function_cited = range->function; } - if (line && within(*func, line->address)) + if (line && within(*range, line->address)) next_transition = line->address; else // If this overflows, we'll catch it below. - next_transition = func->address + func->size; + next_transition = range->address + range->size; } } else { if (line && current >= line->address) { - // Covered by a line, but no function. + // Covered by a line, but no range. // // If GCC emits padding after one function to align the start // of the next, then it will attribute the padding @@ -988,27 +1106,27 @@ void DwarfCUToModule::AssignLinesToFunctions() { // start of the next function, then assume this is what // happened, and don't warn. if (line != last_line_cited - && !(func + && !(range && line == last_line_used - && func->address - line->address == line->size)) { + && range->address - line->address == line->size)) { reporter->UncoveredLine(*line); last_line_cited = line; } - if (func && within(*line, func->address)) - next_transition = func->address; + if (range && within(*line, range->address)) + next_transition = range->address; else // If this overflows, we'll catch it below. next_transition = line->address + line->size; } else { - // Covered by neither a function nor a line. By the invariant, - // both func and line begin after CURRENT. The next transition - // is the start of the next function or next line, whichever + // Covered by neither a range nor a line. By the invariant, + // both range and line begin after CURRENT. The next transition + // is the start of the next range or next line, whichever // is earliest. - assert(func || line); - if (func && line) - next_transition = std::min(func->address, line->address); - else if (func) - next_transition = func->address; + assert(range || line); + if (range && line) + next_transition = std::min(range->address, line->address); + else if (range) + next_transition = range->address; else next_transition = line->address; } @@ -1025,11 +1143,11 @@ void DwarfCUToModule::AssignLinesToFunctions() { // then we could go around more than once. We don't worry too much // about what result we produce in that case, just as long as we don't // hang or crash. - while (func_it != functions->end() - && next_transition >= (*func_it)->address - && !within(**func_it, next_transition)) - func_it++; - func = (func_it != functions->end()) ? *func_it : NULL; + while (range_it != sorted_ranges.end() + && next_transition >= range_it->address + && !within(*range_it, next_transition)) + range_it++; + range = (range_it != sorted_ranges.end()) ? &(*range_it) : NULL; while (line_it != lines_.end() && next_transition >= line_it->address && !within(*line_it, next_transition)) diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h index a36b82b0..c1135dd0 100644 --- a/src/common/dwarf_cu_to_module.h +++ b/src/common/dwarf_cu_to_module.h @@ -123,6 +123,22 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { scoped_ptr file_private_; }; + // An abstract base class for handlers that handle DWARF range lists for + // DwarfCUToModule. + class RangesHandler { + public: + RangesHandler() { } + virtual ~RangesHandler() { } + + // Called when finishing a function to populate the function's ranges. + // The ranges' entries are read starting from offset in the .debug_ranges + // section, base_address holds the base PC the range list values are + // offsets off. Return false if the rangelist falls out of the + // .debug_ranges section. + virtual bool ReadRanges(uint64 offset, Module::Address base_address, + vector* ranges) = 0; + }; + // An abstract base class for handlers that handle DWARF line data // for DwarfCUToModule. DwarfCUToModule could certainly just use // dwarf2reader::LineInfo itself directly, but decoupling things @@ -208,6 +224,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // FilePrivate did not retain the inter-CU specification data. virtual void UnhandledInterCUReference(uint64 offset, uint64 target); + // The DW_AT_ranges at offset is malformed (truncated or outside of the + // .debug_ranges section's bound). + virtual void MalformedRangeList(uint64 offset); + + // A DW_AT_ranges attribute was encountered but the no .debug_ranges + // section was found. + virtual void MissingRanges(); + uint64 cu_offset() const { return cu_offset_; } @@ -235,6 +259,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // data we find. DwarfCUToModule(FileContext *file_context, LineToModuleHandler *line_reader, + RangesHandler *ranges_handler, WarningReporter *reporter); ~DwarfCUToModule(); @@ -296,6 +321,9 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { // The handler to use to handle line number data. LineToModuleHandler *line_reader_; + // The handler to use to handle range lists. + RangesHandler *ranges_handler_; + // This compilation unit's context. scoped_ptr cu_context_; diff --git a/src/common/dwarf_cu_to_module_unittest.cc b/src/common/dwarf_cu_to_module_unittest.cc index 2ce4a609..aef69221 100644 --- a/src/common/dwarf_cu_to_module_unittest.cc +++ b/src/common/dwarf_cu_to_module_unittest.cc @@ -128,7 +128,8 @@ class CUFixtureBase { language_signed_(false), appender_(&lines_), reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL), - root_handler_(&file_context_, &line_reader_, &reporter_), + root_handler_(&file_context_, &line_reader_, + /* ranges_reader */ nullptr, &reporter_), functions_filled_(false) { // By default, expect no warnings to be reported, and expect the // compilation unit's name to be provided. The test can override @@ -597,7 +598,7 @@ void CUFixtureBase::TestFunction(int i, const string &name, Module::Function *function = functions_[i]; EXPECT_EQ(name, function->name); EXPECT_EQ(address, function->address); - EXPECT_EQ(size, function->size); + EXPECT_EQ(size, function->ranges[0].size); EXPECT_EQ(0U, function->parameter_size); } @@ -1515,7 +1516,7 @@ TEST_F(Specifications, InterCU) { // First CU. Declares class_A. { - DwarfCUToModule root1_handler(&fc, &lr, &reporter_); + DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root1_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit)); @@ -1528,7 +1529,7 @@ TEST_F(Specifications, InterCU) { // Second CU. Defines class_A, declares member_func_B. { - DwarfCUToModule root2_handler(&fc, &lr, &reporter_); + DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root2_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit)); @@ -1545,7 +1546,7 @@ TEST_F(Specifications, InterCU) { // Third CU. Defines member_func_B. { - DwarfCUToModule root3_handler(&fc, &lr, &reporter_); + DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root3_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit)); @@ -1574,7 +1575,7 @@ TEST_F(Specifications, UnhandledInterCU) { // First CU. Declares class_A. { - DwarfCUToModule root1_handler(&fc, &lr, &reporter_); + DwarfCUToModule root1_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root1_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit)); @@ -1587,7 +1588,7 @@ TEST_F(Specifications, UnhandledInterCU) { // Second CU. Defines class_A, declares member_func_B. { - DwarfCUToModule root2_handler(&fc, &lr, &reporter_); + DwarfCUToModule root2_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root2_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit)); @@ -1605,7 +1606,7 @@ TEST_F(Specifications, UnhandledInterCU) { // Third CU. Defines member_func_B. { - DwarfCUToModule root3_handler(&fc, &lr, &reporter_); + DwarfCUToModule root3_handler(&fc, &lr, nullptr, &reporter_); ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); ASSERT_TRUE(root3_handler.StartRootDIE(1, dwarf2reader::DW_TAG_compile_unit)); @@ -1791,7 +1792,8 @@ struct Reporter: public Test { file("source file name") { reporter.SetCUName("compilation-unit-name"); - function.size = 0x89808a5bdfa0a6a3ULL; + Module::Range range(0x19c45c30770c1eb0ULL, 0x89808a5bdfa0a6a3ULL); + function.ranges.push_back(range); function.parameter_size = 0x6a329f18683dcd51ULL; line.address = 0x3606ac6267aebeccULL; diff --git a/src/common/dwarf_range_list_handler.cc b/src/common/dwarf_range_list_handler.cc new file mode 100644 index 00000000..8733df36 --- /dev/null +++ b/src/common/dwarf_range_list_handler.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2018 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Gabriele Svelto +// + +// dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class. +// See dwarf_range_list_handler.h for details. + +#include + +#include "common/dwarf_range_list_handler.h" + +namespace google_breakpad { + +void DwarfRangeListHandler::AddRange(uint64 begin, uint64 end) { + Module::Range r(begin + base_address_, end - begin); + + ranges_->push_back(r); +} + +void DwarfRangeListHandler::SetBaseAddress(uint64 base_address) { + base_address_ = base_address; +} + +void DwarfRangeListHandler::Finish() { + std::sort(ranges_->begin(), ranges_->end(), + [](const Module::Range &a, const Module::Range &b) { + return a.address < b.address; + } + ); +} + +} // namespace google_breakpad diff --git a/src/common/dwarf_range_list_handler.h b/src/common/dwarf_range_list_handler.h new file mode 100644 index 00000000..bd099686 --- /dev/null +++ b/src/common/dwarf_range_list_handler.h @@ -0,0 +1,79 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2018 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Gabriele Svelto +// + +// The DwarfRangeListHandler class accepts rangelist data from a DWARF parser +// and adds it to a google_breakpad::Function or other objects supporting +// ranges. + +#ifndef COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H +#define COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H + +#include + +#include "common/module.h" +#include "common/dwarf/dwarf2reader.h" + +namespace google_breakpad { + +// A class for producing a vector of google_breakpad::Module::Range +// instances from a parsed DWARF range list. + +class DwarfRangeListHandler: public dwarf2reader::RangeListHandler { + public: + DwarfRangeListHandler(uint64 base_address, vector *ranges) + : base_address_(base_address), ranges_(ranges) { } + + ~DwarfRangeListHandler() { } + + // Add a range to the list + void AddRange(uint64 begin, uint64 end); + + // Record the new base address and use it for the following entries + void SetBaseAddress(uint64 base_address); + + // Sort the ranges so that they are in ascending order of starting address + void Finish(); + + private: + // The current PC to add to every entry, this can be overridden by a special + // list entry + uint64 base_address_; + + // The list of ranges to be populated + vector *ranges_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index e7a74ccb..1110cb9d 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -58,6 +58,7 @@ #include "common/dwarf_cfi_to_module.h" #include "common/dwarf_cu_to_module.h" #include "common/dwarf_line_to_module.h" +#include "common/dwarf_range_list_handler.h" #include "common/linux/crc32.h" #include "common/linux/eintr_wrapper.h" #include "common/linux/elfutils.h" @@ -81,6 +82,7 @@ using google_breakpad::DumpOptions; using google_breakpad::DwarfCFIToModule; using google_breakpad::DwarfCUToModule; using google_breakpad::DwarfLineToModule; +using google_breakpad::DwarfRangeListHandler; using google_breakpad::ElfClass; using google_breakpad::ElfClass32; using google_breakpad::ElfClass64; @@ -207,6 +209,30 @@ bool LoadStabs(const typename ElfClass::Ehdr* elf_header, } #endif // NO_STABS_SUPPORT +// A range handler that accepts rangelist data parsed by +// dwarf2reader::RangeListReader and populates a range vector (typically +// owned by a function) with the results. +class DumperRangesHandler : public DwarfCUToModule::RangesHandler { + public: + DumperRangesHandler(const uint8_t *buffer, uint64 size, + dwarf2reader::ByteReader* reader) + : buffer_(buffer), size_(size), reader_(reader) { } + + bool ReadRanges(uint64 offset, Module::Address base_address, + vector* ranges) { + DwarfRangeListHandler handler(base_address, ranges); + dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_, + &handler); + + return rangelist_reader.ReadRangeList(offset); + } + + private: + const uint8_t *buffer_; + uint64 size_; + dwarf2reader::ByteReader* reader_; +}; + // A line-to-module loader that accepts line number info parsed by // dwarf2reader::LineInfo and populates a Module and a line vector // with the results. @@ -261,6 +287,18 @@ bool LoadDwarf(const string& dwarf_filename, file_context.AddSectionToSectionMap(name, contents, section->sh_size); } + // Optional .debug_ranges reader + scoped_ptr 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& ranges_section = + ranges_entry->second; + ranges_handler.reset( + new DumperRangesHandler(ranges_section.first, ranges_section.second, + &byte_reader)); + } + // Parse all the compilation units in the .debug_info section. DumperLineToModule line_to_module(&byte_reader); dwarf2reader::SectionMap::const_iterator debug_info_entry = @@ -276,7 +314,8 @@ bool LoadDwarf(const string& dwarf_filename, // Make a handler for the root DIE that populates MODULE with the // data that was found. DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset); - DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter); + DwarfCUToModule root_handler(&file_context, &line_to_module, + ranges_handler.get(), &reporter); // Make a Dwarf2Handler that drives the DIEHandler. dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET. diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc index 66757cda..fef489d0 100644 --- a/src/common/mac/dump_syms.cc +++ b/src/common/mac/dump_syms.cc @@ -55,6 +55,7 @@ #include "common/dwarf_cfi_to_module.h" #include "common/dwarf_cu_to_module.h" #include "common/dwarf_line_to_module.h" +#include "common/dwarf_range_list_handler.h" #include "common/mac/file_id.h" #include "common/mac/arch_utilities.h" #include "common/mac/macho_reader.h" @@ -76,6 +77,7 @@ using dwarf2reader::ByteReader; using google_breakpad::DwarfCUToModule; using google_breakpad::DwarfLineToModule; +using google_breakpad::DwarfRangeListHandler; using google_breakpad::FileID; using google_breakpad::mach_o::FatReader; using google_breakpad::mach_o::Section; @@ -303,6 +305,31 @@ string DumpSymbols::Identifier() { return compacted; } +// A range handler that accepts rangelist data parsed by +// dwarf2reader::RangeListReader and populates a range vector (typically +// owned by a function) with the results. +class DumpSymbols::DumperRangesHandler: + public DwarfCUToModule::RangesHandler { + public: + DumperRangesHandler(const uint8_t *buffer, uint64 size, + dwarf2reader::ByteReader* reader) + : buffer_(buffer), size_(size), reader_(reader) { } + + bool ReadRanges(uint64 offset, Module::Address base_address, + vector* ranges) { + DwarfRangeListHandler handler(base_address, ranges); + dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_, + &handler); + + return rangelist_reader.ReadRangeList(offset); + } + + private: + const uint8_t *buffer_; + uint64 size_; + dwarf2reader::ByteReader* reader_; +}; + // A line-to-module loader that accepts line number info parsed by // dwarf2reader::LineInfo and populates a Module and a line vector // with the results. @@ -425,6 +452,18 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module, // Build a line-to-module loader for the root handler to use. DumperLineToModule line_to_module(&byte_reader); + // Optional .debug_ranges reader + scoped_ptr 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& ranges_section = + ranges_entry->second; + ranges_handler.reset( + new DumperRangesHandler(ranges_section.first, ranges_section.second, + &byte_reader)); + } + // Walk the __debug_info section, one compilation unit at a time. uint64 debug_info_length = debug_info_section.second; for (uint64 offset = 0; offset < debug_info_length;) { @@ -432,7 +471,8 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module, // debug info. DwarfCUToModule::WarningReporter reporter(selected_object_name_, offset); - DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter); + DwarfCUToModule root_handler(&file_context, &line_to_module, + ranges_handler.get(), &reporter); // Make a Dwarf2Handler that drives our DIEHandler. dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET. diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h index 9463f7dc..ab8a99d1 100644 --- a/src/common/mac/dump_syms.h +++ b/src/common/mac/dump_syms.h @@ -125,6 +125,7 @@ class DumpSymbols { private: // Used internally. class DumperLineToModule; + class DumperRangesHandler; class LoadCommandDumper; // This method behaves similarly to NXFindBestFatArch, but it supports diff --git a/src/common/module.cc b/src/common/module.cc index 13c46475..11bfc444 100644 --- a/src/common/module.cc +++ b/src/common/module.cc @@ -258,24 +258,33 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) { for (FunctionSet::const_iterator func_it = functions_.begin(); func_it != functions_.end(); ++func_it) { Function *func = *func_it; - stream << "FUNC " << hex - << (func->address - load_address_) << " " - << func->size << " " - << func->parameter_size << " " - << func->name << dec << "\n"; - if (!stream.good()) - return ReportError(); + vector::iterator line_it = func->lines.begin(); + for (auto range_it = func->ranges.cbegin(); + range_it != func->ranges.cend(); ++range_it) { + stream << "FUNC " << hex + << (range_it->address - load_address_) << " " + << range_it->size << " " + << func->parameter_size << " " + << func->name << dec << "\n"; - for (vector::iterator line_it = func->lines.begin(); - line_it != func->lines.end(); ++line_it) { - stream << hex - << (line_it->address - load_address_) << " " - << line_it->size << " " - << dec - << line_it->number << " " - << line_it->file->source_id << "\n"; if (!stream.good()) return ReportError(); + + while ((line_it != func->lines.end()) && + (line_it->address >= range_it->address) && + (line_it->address < (range_it->address + range_it->size))) { + stream << hex + << (line_it->address - load_address_) << " " + << line_it->size << " " + << dec + << line_it->number << " " + << line_it->file->source_id << "\n"; + + if (!stream.good()) + return ReportError(); + + ++line_it; + } } } diff --git a/src/common/module.h b/src/common/module.h index 6c2bb278..7b1a0db0 100644 --- a/src/common/module.h +++ b/src/common/module.h @@ -85,10 +85,19 @@ class Module { int source_id; }; + // An address range. + struct Range { + Range(const Address address_input, const Address size_input) : + address(address_input), size(size_input) { } + + Address address; + Address size; + }; + // A function. struct Function { Function(const string &name_input, const Address &address_input) : - name(name_input), address(address_input), size(0), parameter_size(0) {} + name(name_input), address(address_input), parameter_size(0) {} // For sorting by address. (Not style-guide compliant, but it's // stupid not to put this in the struct.) @@ -99,9 +108,9 @@ class Module { // The function's name. const string name; - // The start address and length of the function's code. + // The start address and the address ranges covered by the function. const Address address; - Address size; + vector ranges; // The function's parameter size. Address parameter_size; diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc index 78406e37..819fa035 100644 --- a/src/common/module_unittest.cc +++ b/src/common/module_unittest.cc @@ -55,7 +55,8 @@ static Module::Function *generate_duplicate_function(const string &name) { const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL; Module::Function *function = new Module::Function(name, DUP_ADDRESS); - function->size = DUP_SIZE; + Module::Range range(DUP_ADDRESS, DUP_SIZE); + function->ranges.push_back(range); function->parameter_size = DUP_PARAMETER_SIZE; return function; } @@ -92,7 +93,8 @@ TEST(Write, OneLineFunc) { Module::File *file = m.FindFile("file_name.cc"); Module::Function *function = new Module::Function( "function_name", 0xe165bf8023b9d9abLL); - function->size = 0x1e4bb0eb1cbf5b09LL; + Module::Range range(0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL); + function->ranges.push_back(range); function->parameter_size = 0x772beee89114358aLL; Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL, file, 67519080 }; @@ -120,7 +122,8 @@ TEST(Write, RelativeLoadAddress) { // A function. Module::Function *function = new Module::Function( "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL); - function->size = 0x2922088f98d3f6fcLL; + Module::Range range(0xbec774ea5dd935f3LL, 0x2922088f98d3f6fcLL); + function->ranges.push_back(range); function->parameter_size = 0xe5e9aa008bd5f0d0LL; // Some source lines. The module should not sort these. @@ -177,13 +180,14 @@ TEST(Write, OmitUnusedFiles) { // Create a function. Module::Function *function = new Module::Function( "function_name", 0x9b926d464f0b9384LL); - function->size = 0x4f524a4ba795e6a6LL; + Module::Range range(0x9b926d464f0b9384LL, 0x4f524a4ba795e6a6LL); + function->ranges.push_back(range); function->parameter_size = 0xbbe8133a6641c9b7LL; // Source files that refer to some files, but not others. - Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL, + Module::Line line1 = { 0xab415089485e1a20LL, 0x126e3124979291f2LL, file1, 137850127 }; - Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL, + Module::Line line2 = { 0xb2675b5c3c2ed33fLL, 0x1df77f5551dbd68cLL, file3, 28113549 }; function->lines.push_back(line1); function->lines.push_back(line2); @@ -210,8 +214,8 @@ TEST(Write, OmitUnusedFiles) { "FILE 1 filename3\n" "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" " function_name\n" - "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n" - "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n", + "ab415089485e1a20 126e3124979291f2 137850127 0\n" + "b2675b5c3c2ed33f 1df77f5551dbd68c 28113549 1\n", contents.c_str()); } @@ -225,7 +229,8 @@ TEST(Write, NoCFI) { // A function. Module::Function *function = new Module::Function( "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL); - function->size = 0x2922088f98d3f6fcLL; + Module::Range range(0xbec774ea5dd935f3LL, 0x2922088f98d3f6fcLL); + function->ranges.push_back(range); function->parameter_size = 0xe5e9aa008bd5f0d0LL; // Some source lines. The module should not sort these. @@ -267,12 +272,14 @@ TEST(Construct, AddFunctions) { // Two functions. Module::Function *function1 = new Module::Function( "_without_form", 0xd35024aa7ca7da5cLL); - function1->size = 0x200b26e605f99071LL; + Module::Range r1(0xd35024aa7ca7da5cLL, 0x200b26e605f99071LL); + function1->ranges.push_back(r1); function1->parameter_size = 0xf14ac4fed48c4a99LL; Module::Function *function2 = new Module::Function( "_and_void", 0x2987743d0b35b13fLL); - function2->size = 0xb369db048deb3010LL; + Module::Range r2(0x2987743d0b35b13fLL, 0xb369db048deb3010LL); + function2->ranges.push_back(r2); function2->parameter_size = 0x938e556cb5a79988LL; // Put them in a vector. @@ -504,7 +511,8 @@ TEST(Construct, FunctionsAndExternsWithSameAddress) { m.AddExtern(extern2); Module::Function* function = new Module::Function("_xyz", 0xfff0); - function->size = 0x10; + Module::Range range(0xfff0, 0x10); + function->ranges.push_back(range); function->parameter_size = 0; m.AddFunction(function); @@ -541,7 +549,8 @@ TEST(Construct, FunctionsAndThumbExternsWithSameAddress) { // The corresponding function from the DWARF debug data have the actual // address. Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0); - function->size = 0x10; + Module::Range range(0xfff0, 0x10); + function->ranges.push_back(range); function->parameter_size = 0; m.AddFunction(function); diff --git a/src/common/stabs_to_module.cc b/src/common/stabs_to_module.cc index 0a83cf21..049a6cc6 100644 --- a/src/common/stabs_to_module.cc +++ b/src/common/stabs_to_module.cc @@ -91,7 +91,8 @@ bool StabsToModule::StartFunction(const string &name, uint64_t address) { assert(!current_function_); Module::Function *f = new Module::Function(Demangle(name), address); - f->size = 0; // We compute this in StabsToModule::Finalize(). + Module::Range r(address, 0); // We compute this in StabsToModule::Finalize(). + f->ranges.push_back(r); f->parameter_size = 0; // We don't provide this information. current_function_ = f; boundaries_.push_back(static_cast(address)); @@ -167,14 +168,14 @@ void StabsToModule::Finalize() { vector::const_iterator boundary = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address); if (boundary != boundaries_.end()) - f->size = *boundary - f->address; + f->ranges[0].size = *boundary - f->address; else // If this is the last function in the module, and the STABS // reader was unable to give us its ending address, then assign // it a bogus, very large value. This will happen at most once // per module: since we've added all functions' addresses to the // boundary table, only one can be the last. - f->size = kFallbackSize; + f->ranges[0].size = kFallbackSize; // Compute sizes for each of the function f's lines --- if it has any. if (!f->lines.empty()) { @@ -185,7 +186,8 @@ void StabsToModule::Finalize() { line_it != last_line; line_it++) line_it[0].size = line_it[1].address - line_it[0].address; // Compute the size of the last line from f's end address. - last_line->size = (f->address + f->size) - last_line->address; + last_line->size = + (f->ranges[0].address + f->ranges[0].size) - last_line->address; } } // Now that everything has a size, add our functions to the module, and diff --git a/src/common/stabs_to_module_unittest.cc b/src/common/stabs_to_module_unittest.cc index d445d1d6..aae00476 100644 --- a/src/common/stabs_to_module_unittest.cc +++ b/src/common/stabs_to_module_unittest.cc @@ -64,7 +64,7 @@ TEST(StabsToModule, SimpleCU) { Module::Function *function = functions[0]; EXPECT_STREQ("function", function->name.c_str()); EXPECT_EQ(0xfde4abbed390c394LL, function->address); - EXPECT_EQ(0x10U, function->size); + EXPECT_EQ(0x10U, function->ranges[0].size); EXPECT_EQ(0U, function->parameter_size); ASSERT_EQ((size_t) 1, function->lines.size()); Module::Line *line = &function->lines[0]; @@ -130,7 +130,7 @@ TEST(StabsToModule, DuplicateFunctionNames) { Module::Function *function = functions[0]; EXPECT_EQ(0xf2cfda36ecf7f46dLL, function->address); - EXPECT_LT(0U, function->size); // should have used dummy size + EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size EXPECT_EQ(0U, function->parameter_size); ASSERT_EQ(0U, function->lines.size()); } @@ -166,7 +166,7 @@ TEST(InferSizes, LineSize) { Module::Function *function = functions[0]; EXPECT_STREQ("function", function->name.c_str()); EXPECT_EQ(0xb4513962eff94e92LL, function->address); - EXPECT_EQ(0x1000100000000ULL, function->size); // inferred from CU end + EXPECT_EQ(0x1000100000000ULL, function->ranges[0].size); // inferred from CU end EXPECT_EQ(0U, function->parameter_size); ASSERT_EQ((size_t) 2, function->lines.size()); @@ -216,7 +216,7 @@ TEST(FunctionNames, Mangled) { "push_back(unsigned long long const&)", function->name.c_str()); EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address); - EXPECT_LT(0U, function->size); // should have used dummy size + EXPECT_LT(0U, function->ranges[0].size); // should have used dummy size EXPECT_EQ(0U, function->parameter_size); ASSERT_EQ(0U, function->lines.size()); } -- cgit v1.2.1