aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabriele Svelto <gsvelto@mozilla.com>2018-08-04 00:59:34 +0200
committerTed Mielczarek <ted.mielczarek@gmail.com>2018-08-13 19:12:00 +0000
commit16e08520e6027df4bf1934abbfd5e1a088ffb69c (patch)
treee80f0e6a8b46b31a9dd56c12dddebb51e1895795 /src
parentSet new ARM64 context flags (diff)
downloadbreakpad-16e08520e6027df4bf1934abbfd5e1a088ffb69c.tar.xz
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 <ted.mielczarek@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/common/dwarf/dwarf2reader.cc35
-rw-r--r--src/common/dwarf/dwarf2reader.h30
-rw-r--r--src/common/dwarf/functioninfo.cc3
-rw-r--r--src/common/dwarf/functioninfo.h2
-rw-r--r--src/common/dwarf_cu_to_module.cc240
-rw-r--r--src/common/dwarf_cu_to_module.h28
-rw-r--r--src/common/dwarf_cu_to_module_unittest.cc20
-rw-r--r--src/common/dwarf_range_list_handler.cc60
-rw-r--r--src/common/dwarf_range_list_handler.h79
-rw-r--r--src/common/linux/dump_symbols.cc41
-rw-r--r--src/common/mac/dump_syms.cc42
-rw-r--r--src/common/mac/dump_syms.h1
-rw-r--r--src/common/module.cc39
-rw-r--r--src/common/module.h15
-rw-r--r--src/common/module_unittest.cc35
-rw-r--r--src/common/stabs_to_module.cc10
-rw-r--r--src/common/stabs_to_module_unittest.cc8
17 files changed, 577 insertions, 111 deletions
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 <stdio.h>
#include <algorithm>
+#include <numeric>
#include <utility>
#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<Module::Function *>::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<Module::Range> 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<Module::Range> 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<Module::Function> 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<DwarfLanguage>(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<FunctionRange> &dest_ranges,
+ vector<Module::Function *> *functions) {
+ for (vector<Module::Function *>::const_iterator func_it = functions->cbegin();
+ func_it != functions->cend();
+ func_it++)
+ {
+ Module::Function *func = *func_it;
+ vector<Module::Range> &ranges = func->ranges;
+ for (vector<Module::Range>::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 <class T>
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<Module::Function *>::iterator func_it = functions->begin();
+ // Prepare a sorted list of ranges with range-to-function mapping
+ vector<FunctionRange> 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<FunctionRange>::iterator range_it = sorted_ranges.begin();
vector<Module::Line>::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<FilePrivate> 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<Module::Range>* 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<CUContext> 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 <gsvelto@mozilla.com>
+// <gabriele.svelto@gmail.com>
+
+// dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class.
+// See dwarf_range_list_handler.h for details.
+
+#include <algorithm>
+
+#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 <gsvelto@mozilla.com>
+// <gabriele.svelto@gmail.com>
+
+// 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 <vector>
+
+#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<Module::Range> *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<Module::Range> *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<Module::Range>* 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<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>& 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<Module::Range>* 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<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>& 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<Line>::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<Line>::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<Range> 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<Module::Address>(address));
@@ -167,14 +168,14 @@ void StabsToModule::Finalize() {
vector<Module::Address>::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());
}