From 13ba5a1549bc4845f0f6bb6cc511a28c2ceb280e Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Thu, 13 May 2021 14:02:08 -0700 Subject: [PATCH] Fix parsing .debug_rnglists section Change-Id: I1bab1517c04684b8251984498eb0d43e1505fd30 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2888265 Reviewed-by: Sterling Augustine Reviewed-by: Joshua Peraza --- src/common/dwarf/dwarf2reader.cc | 57 +--- src/common/dwarf/dwarf2reader.h | 5 +- src/common/dwarf/dwarf2reader_die_unittest.cc | 255 +++++++++++++++--- 3 files changed, 217 insertions(+), 100 deletions(-) diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index 1a9a451f..9f8bad4a 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -1776,54 +1776,6 @@ void LineInfo::ReadLines() { after_header_ = lengthstart + header_.total_length; } -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; - } - - // 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) { @@ -1832,15 +1784,12 @@ bool RangeListReader::ReadRanges(enum DwarfForm form, uint64_t data) { return ReadDebugRngList(data); } } else if (form == DW_FORM_rnglistx) { - SetRangesBase(cu_info_->ranges_base_); - if (data >= offset_entry_count_) { - return false; - } + offset_array_ = cu_info_->ranges_base_; uint64_t index_offset = reader_->AddressSize() * data; uint64_t range_list_offset = - reader_->ReadAddress(cu_info_->buffer_ + offset_array_ + index_offset); + reader_->ReadOffset(cu_info_->buffer_ + offset_array_ + index_offset); - return ReadDebugRngList(range_list_offset); + return ReadDebugRngList(offset_array_ + range_list_offset); } return false; } diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index 3ff3e07b..849b3648 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -277,14 +277,12 @@ class RangeListReader { RangeListReader(ByteReader* reader, CURangesInfo* cu_info, RangeListHandler* handler) : reader_(reader), cu_info_(cu_info), handler_(handler), - offset_array_(0), offset_entry_count_(0) { } + offset_array_(0) { } // Read ranges from cu_info as specified by form and data. bool ReadRanges(enum DwarfForm form, uint64_t data); private: - bool SetRangesBase(uint64_t base); - // Read dwarf4 .debug_ranges at offset. bool ReadDebugRanges(uint64_t offset); // Read dwarf5 .debug_rngslist at offset. @@ -316,7 +314,6 @@ class RangeListReader { 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 diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index 3ff26f85..e80c0b71 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -698,7 +698,7 @@ TEST(RangeList, Dwarf4ReadRangeList) { section_offset)); } -TEST(RangeList, Dwarf5ReadRangeList) { +TEST(RangeList, Dwarf5ReadRangeList_rnglists) { using dwarf2reader::RangeListReader; using dwarf2reader::DW_RLE_base_addressx; using dwarf2reader::DW_RLE_startx_endx; @@ -706,13 +706,16 @@ TEST(RangeList, Dwarf5ReadRangeList) { 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; + // Size of header + const uint64_t header_size = 12; + // Size of length field in header + const uint64_t length_size = 4; + // .debug_addr for the indexed entries like startx. Section addr; addr.set_endianness(kBigEndian); @@ -722,49 +725,83 @@ TEST(RangeList, Dwarf5ReadRangeList) { 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(); + Section rnglists1(kBigEndian); + Section rnglists2(kBigEndian); + + // First header and body. + Label section_size1; + rnglists1.Append(kBigEndian, length_size, section_size1); + rnglists1.D16(5); // Version + rnglists1.D8(4); // Address size + rnglists1.D8(0); // Segment selector size + rnglists1.D32(2); // Offset entry count + const uint64_t ranges_base_1 = rnglists1.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); + rnglists1.Append(kBigEndian, 4, range0); Label range1; - rnglists.Append(kBigEndian, 4, range1); + rnglists1.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 0 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range0 = rnglists1.Size() - header_size; + rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists1.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)); + range1 = rnglists1.Size() - header_size; + rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8 + rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10) + rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11) + rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13) + rnglists1.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size1 = rnglists1.Size() - length_size; + + // Second header and body. + Label section_size2; + rnglists2.Append(kBigEndian, length_size, section_size2); + rnglists2.D16(5); // Version + rnglists2.D8(4); // Address size + rnglists2.D8(0); // Segment selector size + rnglists2.D32(2); // Offset entry count + const uint64_t ranges_base_2 = rnglists1.Size() + rnglists2.Size(); + + // Offset entries. + Label range2; + rnglists2.Append(kBigEndian, 4, range2); + Label range3; + rnglists2.Append(kBigEndian, 4, range3); + + // Range 2 (will be read via DW_AT_ranges, DW_FORM_sec_offset). + range2 = rnglists2.Size() - header_size; + rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists2.D8(DW_RLE_end_of_list); + + // Range 3 (will be read via DW_AT_ranges, DW_FORM_rnglistx). + range3 = rnglists2.Size() - header_size; + rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15 + rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17) + rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18) + rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20) + rnglists2.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size2 = rnglists2.Size() - length_size; + + rnglists1.Append(rnglists2); + string rnglists_contents; + assert(rnglists1.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.ranges_base_ = ranges_base_1; cu_info.buffer_ = reinterpret_cast(rnglists_contents.data()); cu_info.size_ = rnglists_contents.size(); @@ -772,12 +809,13 @@ TEST(RangeList, Dwarf5ReadRangeList) { 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.SetOffsetSize(4); byte_reader.SetAddressSize(4); MockRangeListHandler handler; - dwarf2reader::RangeListReader range_list_reader(&byte_reader, &cu_info, - &handler); + dwarf2reader::RangeListReader range_list_reader1(&byte_reader, &cu_info, + &handler); EXPECT_CALL(handler, AddRange(2, 3)); EXPECT_CALL(handler, AddRange(4, 5)); EXPECT_CALL(handler, AddRange(6, 7)); @@ -785,9 +823,142 @@ TEST(RangeList, Dwarf5ReadRangeList) { 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())); + EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 0)); + EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 1)); // Out of range index, should result in no calls. - EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_rnglistx, 2)); + EXPECT_FALSE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 2)); + + // Set to new ranges_base + cu_info.ranges_base_ = ranges_base_2; + dwarf2reader::RangeListReader range_list_reader2(&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(16, 17)); + EXPECT_CALL(handler, AddRange(17, 18)); + EXPECT_CALL(handler, AddRange(19, 20)); + EXPECT_CALL(handler, Finish()).Times(2); + EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 0)); + EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 1)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 2)); +} + +TEST(RangeList, Dwarf5ReadRangeList_sec_offset) { + 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_start_end; + using dwarf2reader::DW_RLE_start_length; + using dwarf2reader::DW_FORM_sec_offset; + using dwarf2reader::DW_FORM_rnglistx; + + // Size of length field in header + const uint64_t length_size = 4; + + // .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).D32(21).D32(22); + std::string addr_contents; + assert(addr.GetContents(&addr_contents)); + + // .debug_rnglists is the dwarf 5 section. + Section rnglists1(kBigEndian); + Section rnglists2(kBigEndian); + + // First header and body. + Label section_size1; + rnglists1.Append(kBigEndian, length_size, section_size1); + rnglists1.D16(5); // Version + rnglists1.D8(4); // Address size + rnglists1.D8(0); // Segment selector size + rnglists1.D32(0); // Offset entry count + + const uint64_t offset1 = rnglists1.Size(); + + rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8 + rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10) + rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11) + rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13) + rnglists1.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size1 = rnglists1.Size() - length_size; + + // Second header and body. + Label section_size2; + rnglists2.Append(kBigEndian, length_size, section_size2); + rnglists2.D16(5); // Version + rnglists2.D8(4); // Address size + rnglists2.D8(0); // Segment selector size + rnglists2.D32(0); // Offset entry count + + const uint64_t offset2 = rnglists1.Size() + rnglists2.Size(); + + rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1 + rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3) + rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5) + rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7) + rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15 + rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17) + rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18) + rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20) + rnglists2.D8(DW_RLE_end_of_list); + // The size doesn't include the size of length field itself. + section_size2 = rnglists2.Size() - length_size; + + rnglists1.Append(rnglists2); + string rnglists_contents; + assert(rnglists1.GetContents(&rnglists_contents)); + + RangeListReader::CURangesInfo cu_info; + cu_info.version_ = 5; + cu_info.base_address_ = 1; + 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.SetOffsetSize(4); + 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(1); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset1)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + rnglists_contents.size())); + + EXPECT_CALL(handler, AddRange(2, 3)); + EXPECT_CALL(handler, AddRange(4, 5)); + EXPECT_CALL(handler, AddRange(6, 7)); + EXPECT_CALL(handler, AddRange(16, 17)); + EXPECT_CALL(handler, AddRange(17, 18)); + EXPECT_CALL(handler, AddRange(19, 20)); + EXPECT_CALL(handler, Finish()).Times(1); + EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset2)); + // Out of range index, should result in no calls. + EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset, + rnglists_contents.size())); }