Fix parsing .debug_rnglists section

Change-Id: I1bab1517c04684b8251984498eb0d43e1505fd30
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2888265
Reviewed-by: Sterling Augustine <saugustine@google.com>
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Zequan Wu 2021-05-13 14:02:08 -07:00 committed by Joshua Peraza
parent 5c4b5d89e4
commit 13ba5a1549
3 changed files with 217 additions and 100 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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<const uint8_t*>(rnglists_contents.data());
cu_info.size_ = rnglists_contents.size();
@ -774,6 +811,129 @@ TEST(RangeList, Dwarf5ReadRangeList) {
cu_info.addr_base_ = 4;
ByteReader byte_reader(ENDIANNESS_BIG);
byte_reader.SetOffsetSize(4);
byte_reader.SetAddressSize(4);
MockRangeListHandler 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));
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_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_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<const uint8_t*>(rnglists_contents.data());
cu_info.size_ = rnglists_contents.size();
cu_info.addr_buffer_ =
reinterpret_cast<const uint8_t*>(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,
@ -784,10 +944,21 @@ TEST(RangeList, Dwarf5ReadRangeList) {
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()));
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_rnglistx, 2));
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()));
}