diff --git a/src/common/dwarf/dwarf2enums.h b/src/common/dwarf/dwarf2enums.h index 7bd39792..b93510a7 100644 --- a/src/common/dwarf/dwarf2enums.h +++ b/src/common/dwarf/dwarf2enums.h @@ -169,6 +169,7 @@ enum DwarfForm { DW_FORM_ref_sig8 = 0x20, // Added in DWARF 5: + DW_FORM_rnglistx = 0x23, DW_FORM_strx1 = 0x25, DW_FORM_strx2 = 0x26, DW_FORM_strx3 = 0x27, @@ -264,6 +265,9 @@ enum DwarfAttribute { DW_AT_call_line = 0x59, // DWARF 4 DW_AT_linkage_name = 0x6e, + // DWARF 5 + DW_AT_addr_base = 0x73, + DW_AT_rnglists_base = 0x74, // SGI/MIPS extensions. DW_AT_MIPS_fde = 0x2001, DW_AT_MIPS_loop_begin = 0x2002, @@ -316,6 +320,18 @@ enum DwarfAttribute { DW_AT_PGI_lstride = 0x3a02 }; +// .debug_rngslist entry types +enum DwarfRngListEntry { + DW_RLE_end_of_list = 0, + DW_RLE_base_addressx = 1, + DW_RLE_startx_endx = 2, + DW_RLE_startx_length = 3, + DW_RLE_offset_pair = 4, + DW_RLE_base_address = 5, + DW_RLE_start_end = 6, + DW_RLE_start_length = 7, +}; + // Line number content type codes (DWARF 5). enum DwarfLineNumberContentType { DW_LNCT_path = 1, diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index aca83677..f1f4007d 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -226,6 +226,7 @@ const uint8_t* CompilationUnit::SkipAttribute(const uint8_t* start, case DW_FORM_GNU_str_index: case DW_FORM_GNU_addr_index: case DW_FORM_addrx: + case DW_FORM_rnglistx: reader_->ReadUnsignedLEB128(start, &len); return start + len; @@ -657,6 +658,10 @@ const uint8_t* CompilationUnit::ProcessAttribute( ProcessAttributeAddrIndex( dieoffset, attr, form, reader_->ReadFourBytes(start)); return start + 4; + case DW_FORM_rnglistx: + ProcessAttributeUnsigned( + dieoffset, attr, form, reader_->ReadUnsignedLEB128(start, &len)); + return start + len; } fprintf(stderr, "Unhandled form type\n"); return NULL; @@ -1568,11 +1573,76 @@ void LineInfo::ReadLines() { after_header_ = lengthstart + header_.total_length; } -RangeListReader::RangeListReader(const uint8_t* buffer, uint64_t size, - ByteReader* reader, RangeListHandler* handler) - : buffer_(buffer), size_(size), reader_(reader), handler_(handler) { } +bool RangeListReader::SetRangesBase(uint64_t offset) { + // Versions less than 5 don't use ranges base. + if (cu_info_->version_ < 5) { + return true; + } + // Length may not be 12 bytes, but if 12 bytes aren't available + // at this point, then the header is too short. + if (offset + 12 >= cu_info_->size_) { + return false; + } + // The length of this CU's contribution. + uint64_t cu_length = reader_->ReadFourBytes(cu_info_->buffer_ + offset); + offset += 4; + if (cu_length == 0xffffffffUL) { + cu_length = reader_->ReadEightBytes(cu_info_->buffer_ + offset); + offset += 8; + } -bool RangeListReader::ReadRangeList(uint64_t offset) { + // Truncating size here results in correctly ignoring everything not from + // this cu from here on out. + cu_info_->size_ = offset + cu_length; + + // Check for the rest of the header in advance. + if (offset + 8 >= cu_info_->size_) { + return false; + } + // Version. Can only read version 5. + if (reader_->ReadTwoBytes(cu_info_->buffer_ + offset) != 5) { + return false; + } + offset += 2; + // Address size + if (reader_->ReadOneByte(cu_info_->buffer_ + offset) != + reader_->AddressSize()) { + return false; + } + offset += 1; + // Segment selectors are unsupported + if (reader_->ReadOneByte(cu_info_->buffer_ + offset) != 0) { + return false; + } + offset += 1; + offset_entry_count_ = reader_->ReadFourBytes(cu_info_->buffer_ + offset); + offset += 4; + offset_array_ = offset; + return true; +} + +bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) { + if (form == DW_FORM_sec_offset) { + if (cu_info_->version_ <= 4) { + return ReadDebugRanges(data); + } else { + return ReadDebugRngList(data); + } + } else if (form == DW_FORM_rnglistx) { + SetRangesBase(cu_info_->ranges_base_); + if (data >= offset_entry_count_) { + return false; + } + uint64_t index_offset = reader_->AddressSize() * data; + uint64_t range_list_offset = + reader_->ReadAddress(cu_info_->buffer_ + offset_array_ + index_offset); + + return ReadDebugRngList(range_list_offset); + } + return false; +} + +bool RangeListReader::ReadDebugRanges(uint64_t offset) { const uint64_t max_address = (reader_->AddressSize() == 4) ? 0xffffffffUL : 0xffffffffffffffffULL; @@ -1580,21 +1650,22 @@ bool RangeListReader::ReadRangeList(uint64_t offset) { bool list_end = false; do { - if (offset > size_ - entry_size) { + if (offset > cu_info_->size_ - entry_size) { return false; // Invalid range detected } - uint64_t start_address = reader_->ReadAddress(buffer_ + offset); - uint64_t end_address = - reader_->ReadAddress(buffer_ + offset + reader_->AddressSize()); + uint64_t start_address = reader_->ReadAddress(cu_info_->buffer_ + offset); + uint64_t end_address = reader_->ReadAddress( + cu_info_->buffer_ + offset + reader_->AddressSize()); if (start_address == max_address) { // Base address selection - handler_->SetBaseAddress(end_address); + cu_info_->base_address_ = 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); + handler_->AddRange(start_address + cu_info_->base_address_, + end_address + cu_info_->base_address_); } offset += entry_size; @@ -1603,6 +1674,62 @@ bool RangeListReader::ReadRangeList(uint64_t offset) { return true; } +bool RangeListReader::ReadDebugRngList(uint64_t offset) { + uint64_t start = 0; + uint64_t end = 0; + uint64_t range_len = 0; + uint64_t index = 0; + // A uleb128's length isn't known until after it has been read, so overruns + // are only caught after an entire entry. + while (offset < cu_info_->size_) { + uint8_t entry_type = reader_->ReadOneByte(cu_info_->buffer_ + offset); + offset += 1; + // Handle each entry type per Dwarf 5 Standard, section 2.17.3. + switch (entry_type) { + case DW_RLE_end_of_list: + handler_->Finish(); + return true; + case DW_RLE_base_addressx: + offset += ReadULEB(offset, &index); + cu_info_->base_address_ = GetAddressAtIndex(index); + break; + case DW_RLE_startx_endx: + offset += ReadULEB(offset, &index); + start = GetAddressAtIndex(index); + offset += ReadULEB(offset, &index); + end = GetAddressAtIndex(index); + handler_->AddRange(start, end); + break; + case DW_RLE_startx_length: + offset += ReadULEB(offset, &index); + start = GetAddressAtIndex(index); + offset += ReadULEB(offset, &range_len); + handler_->AddRange(start, start + range_len); + break; + case DW_RLE_offset_pair: + offset += ReadULEB(offset, &start); + offset += ReadULEB(offset, &end); + handler_->AddRange(start + cu_info_->base_address_, + end + cu_info_->base_address_); + break; + case DW_RLE_base_address: + offset += ReadAddress(offset, &cu_info_->base_address_); + break; + case DW_RLE_start_end: + offset += ReadAddress(offset, &start); + offset += ReadAddress(offset, &end); + handler_->AddRange(start, end); + break; + case DW_RLE_start_length: + offset += ReadAddress(offset, &start); + offset += ReadULEB(offset, &end); + handler_->AddRange(start, start + end); + break; + } + } + return false; +} + // 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 e405e3a7..d041dd86 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -234,25 +234,78 @@ class RangeListHandler { // Add a range. virtual void AddRange(uint64_t begin, uint64_t end) { }; - // A new base address must be set for computing the ranges' addresses. - virtual void SetBaseAddress(uint64_t base_address) { }; - // Finish processing the range list. virtual void Finish() { }; }; class RangeListReader { public: - RangeListReader(const uint8_t* buffer, uint64_t size, ByteReader* reader, - RangeListHandler* handler); + // Reading a range list requires quite a bit of information + // from the compilation unit. Package it conveniently. + struct CURangesInfo { + CURangesInfo() : + version_(0), base_address_(0), ranges_base_(0), + buffer_(nullptr), size_(0), addr_buffer_(nullptr), + addr_buffer_size_(0), addr_base_(0) { } - bool ReadRangeList(uint64_t offset); + uint16_t version_; + // Ranges base address. Ordinarily the CU's low_pc. + uint64_t base_address_; + // Offset into .debug_rnglists for this CU's rangelists. + uint64_t ranges_base_; + // Contents of either .debug_ranges or .debug_rnglists. + const uint8_t* buffer_; + uint64_t size_; + // Contents of .debug_addr. This cu's contribution starts at + // addr_base_ + const uint8_t* addr_buffer_; + uint64_t addr_buffer_size_; + uint64_t addr_base_; + }; + + RangeListReader(ByteReader* reader, CURangesInfo* cu_info, + RangeListHandler* handler) : + reader_(reader), cu_info_(cu_info), handler_(handler), + offset_array_(0), offset_entry_count_(0) { } + + // Read ranges from cu_info as specified by form and data. + bool ReadRanges(enum DwarfForm form, uint64_t data); private: - const uint8_t* buffer_; - uint64_t size_; + bool SetRangesBase(uint64_t base); + + // Read dwarf4 .debug_ranges at offset. + bool ReadDebugRanges(uint64_t offset); + // Read dwarf5 .debug_rngslist at offset. + bool ReadDebugRngList(uint64_t offset); + + // Convenience functions to handle the mechanics of reading entries in the + // ranges section. + uint64_t ReadULEB(uint64_t offset, uint64_t* value) { + uint64_t len; + *value = reader_->ReadUnsignedLEB128(cu_info_->buffer_ + offset, &len); + return len; + } + + uint64_t ReadAddress(uint64_t offset, uint64_t* value) { + *value = reader_->ReadAddress(cu_info_->buffer_ + offset); + return reader_->AddressSize(); + } + + // Read the address at this CU's addr_index in the .debug_addr section. + uint64_t GetAddressAtIndex(uint64_t addr_index) { + assert(cu_info_->addr_buffer_ != nullptr); + uint64_t offset = + cu_info_->addr_base_ + addr_index * reader_->AddressSize(); + assert(offset < cu_info_->addr_buffer_size_); + return reader_->ReadAddress(cu_info_->addr_buffer_ + offset); + } + ByteReader* reader_; + CURangesInfo* cu_info_; RangeListHandler* handler_; + uint64_t offset_array_; + uint64_t offset_entry_count_; }; // This class is the main interface between the reader and the @@ -492,7 +545,7 @@ class CompilationUnit { else if (attr == DW_AT_GNU_addr_base) { addr_base_ = data; } - else if (attr == DW_AT_GNU_ranges_base) { + else if (attr == DW_AT_GNU_ranges_base || attr == DW_AT_rnglists_base) { ranges_base_ = data; } // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, @@ -654,7 +707,8 @@ class CompilationUnit { // from the skeleton CU. uint64_t skeleton_dwo_id_; - // The value of the DW_AT_GNU_ranges_base attribute, if any. + // The value of the DW_AT_GNU_ranges_base or DW_AT_rnglists_base attribute, + // if any. uint64_t ranges_base_; // The value of the DW_AT_GNU_addr_base attribute, if any. diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index 87819322..0d8811bb 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -491,3 +491,142 @@ INSTANTIATE_TEST_CASE_P( DwarfHeaderParams(kBigEndian, 8, 3, 8), DwarfHeaderParams(kBigEndian, 8, 4, 4), DwarfHeaderParams(kBigEndian, 8, 4, 8))); + +class MockRangeListHandler: public dwarf2reader::RangeListHandler { + public: + MOCK_METHOD(void, AddRange, (uint64_t begin, uint64_t end)); + MOCK_METHOD(void, Finish, ()); +}; + +TEST(RangeList, Dwarf4ReadRangeList) { + using dwarf2reader::RangeListReader; + using dwarf2reader::DW_FORM_sec_offset; + + // Create a dwarf4 .debug_ranges section. + google_breakpad::test_assembler::Section ranges(kBigEndian); + std::string padding_offset = "padding offset"; + ranges.Append(padding_offset); + const uint64_t section_offset = ranges.Size(); + ranges.D32(1).D32(2); // (2, 3) + ranges.D32(0xFFFFFFFF).D32(3); // base_address = 3. + ranges.D32(1).D32(2); // (4, 5) + ranges.D32(0).D32(1); // (3, 4) An out of order entry is legal. + ranges.D32(0).D32(0); // End of range. + + std::string section_contents; + ranges.GetContents(§ion_contents); + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + + RangeListReader::CURangesInfo cu_info; + // Only set the fields that matter for dwarf 4. + cu_info.version_ = 4; + cu_info.base_address_ = 1; + cu_info.buffer_ = reinterpret_cast(section_contents.data()); + cu_info.size_ = section_contents.size(); + + MockRangeListHandler handler; + dwarf2reader::RangeListReader range_list_reader(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(3, 4)); + EXPECT_CALL(handler, Finish()); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + section_offset)); +} + +TEST(RangeList, Dwarf5ReadRangeList) { + using dwarf2reader::RangeListReader; + using dwarf2reader::DW_RLE_base_addressx; + using dwarf2reader::DW_RLE_startx_endx; + using dwarf2reader::DW_RLE_startx_length; + using dwarf2reader::DW_RLE_offset_pair; + using dwarf2reader::DW_RLE_end_of_list; + using dwarf2reader::DW_RLE_base_address; + using dwarf2reader::DW_RLE_offset_pair; + using dwarf2reader::DW_RLE_start_end; + using dwarf2reader::DW_RLE_start_length; + using dwarf2reader::DW_RLE_end_of_list; + using dwarf2reader::DW_FORM_sec_offset; + using dwarf2reader::DW_FORM_rnglistx; + + // .debug_addr for the indexed entries like startx. + Section addr; + addr.set_endianness(kBigEndian); + // Test addr_base handling with a padding address at 0. + addr.D32(0).D32(1).D32(2).D32(3).D32(4); + std::string addr_contents; + assert(addr.GetContents(&addr_contents)); + + // .debug_rnglists is the dwarf 5 section. + Section rnglists; + rnglists.set_endianness(kBigEndian); + std::string padding_offset = "padding offset"; + rnglists.Append(padding_offset); + const uint64_t ranges_base = rnglists.Size(); + + // Header + Label section_size; + rnglists.Append(kBigEndian, 4, section_size); + rnglists.D16(5); // Version + rnglists.D8(4); // Address size + rnglists.D8(0); // Segment selector size + rnglists.D32(2); // Offset entry count + // Offset entries. + Label range0; + rnglists.Append(kBigEndian, 4, range0); + Label range1; + rnglists.Append(kBigEndian, 4, range1); + + // Range 0 (will be read via DW_AT_ranges, DW_FORM_sec_offset). + range0 = rnglists.Size(); + rnglists.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // (2, 3) + rnglists.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // (4, 5) + rnglists.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // (6, 7) + rnglists.D8(DW_RLE_end_of_list); + + // Range 1 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range1 = rnglists.Size(); + rnglists.D8(DW_RLE_base_address).D32(8); // base_addr = 8 + rnglists.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // (9, 10) + rnglists.D8(DW_RLE_start_end).D32(10).D32(11); // (10, 11) + rnglists.D8(DW_RLE_start_length).D32(12).ULEB128(1); // (12, 13) + rnglists.D8(DW_RLE_end_of_list); + section_size = rnglists.Size(); + std::string rnglists_contents; + assert(rnglists.GetContents(&rnglists_contents)); + + RangeListReader::CURangesInfo cu_info; + // Only set the fields that matter for dwarf 4. + cu_info.version_ = 5; + cu_info.base_address_ = 1; + cu_info.ranges_base_ = ranges_base; + cu_info.buffer_ = + reinterpret_cast(rnglists_contents.data()); + cu_info.size_ = rnglists_contents.size(); + cu_info.addr_buffer_ = + reinterpret_cast(addr_contents.data()); + cu_info.addr_buffer_size_ = addr_contents.size(); + cu_info.addr_base_ = 4; + + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + MockRangeListHandler handler; + dwarf2reader::RangeListReader range_list_reader(&byte_reader, &cu_info, + &handler); + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(9, 10)); + EXPECT_CALL(handler, AddRange(10, 11)); + EXPECT_CALL(handler, AddRange(12, 13)); + EXPECT_CALL(handler, Finish()).Times(2); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_rnglistx, 1)); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + range0.Value())); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_rnglistx, 2)); +} diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc index a5bc7d6c..168c4665 100644 --- a/src/common/dwarf_cu_to_module.cc +++ b/src/common/dwarf_cu_to_module.cc @@ -172,13 +172,16 @@ bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference( struct DwarfCUToModule::CUContext { CUContext(FileContext* file_context_arg, WarningReporter* reporter_arg, RangesHandler* ranges_handler_arg) - : file_context(file_context_arg), + : version(0), + file_context(file_context_arg), reporter(reporter_arg), ranges_handler(ranges_handler_arg), language(Language::CPlusPlus), low_pc(0), high_pc(0), - ranges(0) {} + ranges_form(dwarf2reader::DW_FORM_sec_offset), + ranges_data(0), + ranges_base(0) { } ~CUContext() { for (vector::iterator it = functions.begin(); @@ -187,6 +190,9 @@ struct DwarfCUToModule::CUContext { } }; + // Dwarf version of the source CU. + uint8_t version; + // The DWARF-bearing file into which this CU was incorporated. FileContext* file_context; @@ -200,11 +206,54 @@ struct DwarfCUToModule::CUContext { 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. + // low_pc to high_pc, otherwise ranges_data is non-zero and low_pc represents + // the base address of the ranges covered by the CU. ranges_data will define + // the CU's actual ranges. uint64_t low_pc; uint64_t high_pc; - uint64_t ranges; + + // Ranges for this CU are read according to this form. + enum dwarf2reader::DwarfForm ranges_form; + uint64_t ranges_data; + + // Offset into .debug_rngslists where this CU's ranges are stored. + // Data in DW_FORM_rnglistx is relative to this offset. + uint64_t ranges_base; + + // Offset into .debug_addr where this CU's addresses are stored. Data in + // form DW_FORM_addrxX is relative to this offset. + uint64_t addr_base; + + // Collect all the data from the CU that a RangeListReader needs to read a + // range. + bool AssembleRangeListInfo( + dwarf2reader::RangeListReader::CURangesInfo* info) { + const dwarf2reader::SectionMap& section_map + = file_context->section_map(); + info->version_ = version; + info->base_address_ = low_pc; + info->ranges_base_ = ranges_base; + const char* section_name = (version <= 4 ? + ".debug_ranges" : ".debug_rnglists"); + dwarf2reader::SectionMap::const_iterator map_entry + = dwarf2reader::GetSectionByName(section_map, section_name); + if (map_entry == section_map.end()) { + return false; + } + info->buffer_ = map_entry->second.first; + info->size_ = map_entry->second.second; + if (version > 4) { + dwarf2reader::SectionMap::const_iterator map_entry + = dwarf2reader::GetSectionByName(section_map, ".debug_addr"); + if (map_entry == section_map.end()) { + return false; + } + info->addr_buffer_ = map_entry->second.first; + info->addr_buffer_size_ = map_entry->second.second; + info->addr_base_ = addr_base; + } + return true; + } // The functions defined in this compilation unit. We accumulate // them here during parsing. Then, in DwarfCUToModule::Finish, we @@ -470,7 +519,9 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { uint64_t offset) : GenericDIEHandler(cu_context, parent_context, offset), low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr), - ranges_(0), abstract_origin_(NULL), inline_(false) { } + ranges_form_(dwarf2reader::DW_FORM_sec_offset), ranges_data_(0), + abstract_origin_(NULL), inline_(false) { } + void ProcessAttributeUnsigned(enum DwarfAttribute attr, enum DwarfForm form, uint64_t data); @@ -490,7 +541,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler { string name_; uint64_t 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_t ranges_; // DW_AT_ranges + DwarfForm ranges_form_; // DW_FORM_sec_offset or DW_FORM_rnglistx + uint64_t ranges_data_; // DW_AT_ranges const AbstractOrigin* abstract_origin_; bool inline_; }; @@ -511,7 +563,8 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( high_pc_ = data; break; case dwarf2reader::DW_AT_ranges: - ranges_ = data; + ranges_data_ = data; + ranges_form_ = form; break; default: @@ -590,7 +643,7 @@ void DwarfCUToModule::FuncHandler::Finish() { iter->second->name = name_; } - if (!ranges_) { + if (!ranges_data_) { // Make high_pc_ an address, if it isn't already. if (high_pc_form_ != dwarf2reader::DW_FORM_addr && high_pc_form_ != dwarf2reader::DW_FORM_GNU_addr_index && @@ -606,14 +659,17 @@ void DwarfCUToModule::FuncHandler::Finish() { 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_); + dwarf2reader::RangeListReader::CURangesInfo cu_info; + if (cu_context_->AssembleRangeListInfo(&cu_info)) { + if (!ranges_handler->ReadRanges(ranges_form_, ranges_data_, + &cu_info, &ranges)) { + ranges.clear(); + cu_context_->reporter->MalformedRangeList(ranges_data_); + } + } else { + cu_context_->reporter->MissingRanges(); } - } else { - cu_context_->reporter->MissingRanges(); } } @@ -843,7 +899,15 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, cu_context_->high_pc = data; break; case dwarf2reader::DW_AT_ranges: - cu_context_->ranges = data; + cu_context_->ranges_data = data; + cu_context_->ranges_form = form; + break; + case dwarf2reader::DW_AT_rnglists_base: + cu_context_->ranges_base = data; + break; + case dwarf2reader::DW_AT_addr_base: + case dwarf2reader::DW_AT_GNU_addr_base: + cu_context_->addr_base = data; break; default: @@ -1262,6 +1326,7 @@ bool DwarfCUToModule::StartCompilationUnit(uint64_t offset, uint8_t offset_size, uint64_t cu_length, uint8_t dwarf_version) { + cu_context_->version = dwarf_version; return dwarf_version >= 2; } diff --git a/src/common/dwarf_cu_to_module.h b/src/common/dwarf_cu_to_module.h index 3e15b667..386d6281 100644 --- a/src/common/dwarf_cu_to_module.h +++ b/src/common/dwarf_cu_to_module.h @@ -45,7 +45,6 @@ #include "common/language.h" #include "common/module.h" -#include "common/dwarf/bytereader.h" #include "common/dwarf/dwarf2diehandler.h" #include "common/dwarf/dwarf2reader.h" #include "common/scoped_ptr.h" @@ -131,12 +130,11 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler { 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_t offset, Module::Address base_address, - vector* ranges) = 0; + // The entries are read according to the form and data. + virtual bool ReadRanges( + enum dwarf2reader::DwarfForm form, uint64_t data, + dwarf2reader::RangeListReader::CURangesInfo* cu_info, + vector* ranges) = 0; }; // An abstract base class for handlers that handle DWARF line data diff --git a/src/common/dwarf_range_list_handler.cc b/src/common/dwarf_range_list_handler.cc index 58982aac..3fecb564 100644 --- a/src/common/dwarf_range_list_handler.cc +++ b/src/common/dwarf_range_list_handler.cc @@ -40,15 +40,11 @@ namespace google_breakpad { void DwarfRangeListHandler::AddRange(uint64_t begin, uint64_t end) { - Module::Range r(begin + base_address_, end - begin); + Module::Range r(begin, end - begin); ranges_->push_back(r); } -void DwarfRangeListHandler::SetBaseAddress(uint64_t base_address) { - base_address_ = base_address; -} - void DwarfRangeListHandler::Finish() { std::sort(ranges_->begin(), ranges_->end(), [](const Module::Range& a, const Module::Range& b) { diff --git a/src/common/dwarf_range_list_handler.h b/src/common/dwarf_range_list_handler.h index 2adb2f9a..5db5d1e9 100644 --- a/src/common/dwarf_range_list_handler.h +++ b/src/common/dwarf_range_list_handler.h @@ -51,25 +51,18 @@ namespace google_breakpad { class DwarfRangeListHandler: public dwarf2reader::RangeListHandler { public: - DwarfRangeListHandler(uint64_t base_address, vector* ranges) - : base_address_(base_address), ranges_(ranges) { } + DwarfRangeListHandler(vector* ranges) + : ranges_(ranges) { } ~DwarfRangeListHandler() { } // Add a range to the list void AddRange(uint64_t begin, uint64_t end); - // Record the new base address and use it for the following entries - void SetBaseAddress(uint64_t 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_t base_address_; - // The list of ranges to be populated vector* ranges_; }; diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index 8ecf0bc4..0514f5a2 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -232,22 +232,20 @@ bool LoadStabs(const typename ElfClass::Ehdr* elf_header, // owned by a function) with the results. class DumperRangesHandler : public DwarfCUToModule::RangesHandler { public: - DumperRangesHandler(const uint8_t* buffer, uint64_t size, - dwarf2reader::ByteReader* reader) - : buffer_(buffer), size_(size), reader_(reader) { } + DumperRangesHandler(dwarf2reader::ByteReader* reader) : + reader_(reader) { } - bool ReadRanges(uint64_t offset, Module::Address base_address, - vector* ranges) { - DwarfRangeListHandler handler(base_address, ranges); - dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_, - &handler); - - return rangelist_reader.ReadRangeList(offset); + bool ReadRanges( + enum dwarf2reader::DwarfForm form, uint64_t data, + dwarf2reader::RangeListReader::CURangesInfo* cu_info, + vector* ranges) { + DwarfRangeListHandler handler(ranges); + dwarf2reader::RangeListReader range_list_reader(reader_, cu_info, + &handler); + return range_list_reader.ReadRanges(form, data); } private: - const uint8_t* buffer_; - uint64_t size_; dwarf2reader::ByteReader* reader_; }; @@ -313,17 +311,8 @@ bool LoadDwarf(const string& dwarf_filename, file_context.AddSectionToSectionMap(name, contents, section->sh_size); } - // Optional .debug_ranges reader - scoped_ptr 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)); - } + // .debug_ranges and .debug_rnglists reader + DumperRangesHandler ranges_handler(&byte_reader); // Parse all the compilation units in the .debug_info section. DumperLineToModule line_to_module(&byte_reader); @@ -341,7 +330,7 @@ bool LoadDwarf(const string& dwarf_filename, // data that was found. DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset); DwarfCUToModule root_handler(&file_context, &line_to_module, - ranges_handler.get(), &reporter); + &ranges_handler, &reporter); // Make a Dwarf2Handler that drives the DIEHandler. dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET. diff --git a/src/common/mac/dump_syms.cc b/src/common/mac/dump_syms.cc index 24bcd653..672323c8 100644 --- a/src/common/mac/dump_syms.cc +++ b/src/common/mac/dump_syms.cc @@ -311,22 +311,20 @@ string DumpSymbols::Identifier() { class DumpSymbols::DumperRangesHandler: public DwarfCUToModule::RangesHandler { public: - DumperRangesHandler(const uint8_t* buffer, uint64_t size, - dwarf2reader::ByteReader* reader) - : buffer_(buffer), size_(size), reader_(reader) { } + DumperRangesHandler(dwarf2reader::ByteReader* reader) : + reader_(reader) { } - bool ReadRanges(uint64_t offset, Module::Address base_address, - vector* ranges) { - DwarfRangeListHandler handler(base_address, ranges); - dwarf2reader::RangeListReader rangelist_reader(buffer_, size_, reader_, - &handler); - - return rangelist_reader.ReadRangeList(offset); + bool ReadRanges( + enum dwarf2reader::DwarfForm form, uint64_t data, + dwarf2reader::RangeListReader::CURangesInfo* cu_info, + vector* ranges) { + DwarfRangeListHandler handler(ranges); + dwarf2reader::RangeListReader range_list_reader(reader_, cu_info, + &handler); + return range_list_reader.ReadRanges(form, data); } private: - const uint8_t* buffer_; - uint64_t size_; dwarf2reader::ByteReader* reader_; }; @@ -456,17 +454,8 @@ void 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)); - } + // .debug_ranges and .debug_rngslists reader + DumperRangesHandler ranges_handler(&byte_reader); // Walk the __debug_info section, one compilation unit at a time. uint64_t debug_info_length = debug_info_section.second; @@ -476,7 +465,7 @@ void DumpSymbols::ReadDwarf(google_breakpad::Module* module, DwarfCUToModule::WarningReporter reporter(selected_object_name_, offset); DwarfCUToModule root_handler(&file_context, &line_to_module, - ranges_handler.get(), &reporter); + &ranges_handler, &reporter); // Make a Dwarf2Handler that drives our DIEHandler. dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); // Make a DWARF parser for the compilation unit at OFFSET.