diff options
Diffstat (limited to 'src/common/dwarf/dwarf2reader_die_unittest.cc')
-rw-r--r-- | src/common/dwarf/dwarf2reader_die_unittest.cc | 678 |
1 files changed, 576 insertions, 102 deletions
diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index ca44cad0..fc639a64 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -1,5 +1,4 @@ -// Copyright (c) 2012, Google Inc. -// All rights reserved. +// Copyright 2012 Google LLC // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are @@ -11,7 +10,7 @@ // 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 +// * Neither the name of Google LLC nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // @@ -29,7 +28,7 @@ // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> -// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit +// dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit #include <stdint.h> #include <stdlib.h> @@ -51,16 +50,16 @@ using google_breakpad::test_assembler::Section; using google_breakpad::test_assembler::kBigEndian; using google_breakpad::test_assembler::kLittleEndian; -using dwarf2reader::ByteReader; -using dwarf2reader::CompilationUnit; -using dwarf2reader::Dwarf2Handler; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfHasChild; -using dwarf2reader::DwarfTag; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; -using dwarf2reader::SectionMap; +using google_breakpad::ByteReader; +using google_breakpad::CompilationUnit; +using google_breakpad::Dwarf2Handler; +using google_breakpad::DwarfAttribute; +using google_breakpad::DwarfForm; +using google_breakpad::DwarfHasChild; +using google_breakpad::DwarfTag; +using google_breakpad::ENDIANNESS_BIG; +using google_breakpad::ENDIANNESS_LITTLE; +using google_breakpad::SectionMap; using std::vector; using testing::InSequence; @@ -93,7 +92,7 @@ class MockDwarf2Handler: public Dwarf2Handler { MOCK_METHOD5(ProcessAttributeBuffer, void(uint64_t offset, enum DwarfAttribute attr, enum DwarfForm form, - const uint8_t *data, + const uint8_t* data, uint64_t len)); MOCK_METHOD4(ProcessAttributeString, void(uint64_t offset, enum DwarfAttribute attr, @@ -128,17 +127,17 @@ struct DIEFixture { // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This // function returns a reference to the same SectionMap each time; new // calls wipe out maps established by earlier calls. - const SectionMap &MakeSectionMap() { + const SectionMap& MakeSectionMap() { // Copy the sections' contents into strings that will live as long as // the map itself. assert(info.GetContents(&info_contents)); assert(abbrevs.GetContents(&abbrevs_contents)); section_map.clear(); section_map[".debug_info"].first - = reinterpret_cast<const uint8_t *>(info_contents.data()); + = reinterpret_cast<const uint8_t*>(info_contents.data()); section_map[".debug_info"].second = info_contents.size(); section_map[".debug_abbrev"].first - = reinterpret_cast<const uint8_t *>(abbrevs_contents.data()); + = reinterpret_cast<const uint8_t*>(abbrevs_contents.data()); section_map[".debug_abbrev"].second = abbrevs_contents.size(); return section_map; } @@ -152,13 +151,15 @@ struct DIEFixture { struct DwarfHeaderParams { DwarfHeaderParams(Endianness endianness, size_t format_size, - int version, size_t address_size) + int version, size_t address_size, int header_type) : endianness(endianness), format_size(format_size), - version(version), address_size(address_size) { } + version(version), address_size(address_size), header_type(header_type) + { } Endianness endianness; size_t format_size; // 4-byte or 8-byte DWARF offsets int version; size_t address_size; + int header_type; // DW_UT_{compile, type, partial, skeleton, etc} }; class DwarfHeader: public DIEFixture, @@ -166,16 +167,17 @@ class DwarfHeader: public DIEFixture, TEST_P(DwarfHeader, Header) { Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_children_yes) - .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string) + abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_children_yes) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string) .EndAbbrev() .EndTable(); info.set_format_size(GetParam().format_size); info.set_endianness(GetParam().endianness); - info.Header(GetParam().version, abbrev_table, GetParam().address_size) + info.Header(GetParam().version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_compile) .ULEB128(1) // DW_TAG_compile_unit, with children .AppendCString("sam") // DW_AT_name, DW_FORM_string .D8(0); // end of children @@ -188,10 +190,10 @@ TEST_P(DwarfHeader, Header) { GetParam().format_size, _, GetParam().version)) .WillOnce(Return(true)); - EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit)) + EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_compile_unit)) .WillOnce(Return(true)); - EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_string, + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_string, "sam")) .WillOnce(Return()); EXPECT_CALL(handler, EndDIE(_)) @@ -204,44 +206,91 @@ TEST_P(DwarfHeader, Header) { EXPECT_EQ(parser.Start(), info_contents.size()); } -INSTANTIATE_TEST_CASE_P( +TEST_P(DwarfHeader, TypeUnitHeader) { + Label abbrev_table = abbrevs.Here(); + int version = 5; + abbrevs.Abbrev(1, google_breakpad::DW_TAG_type_unit, + google_breakpad::DW_children_yes) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string) + .EndAbbrev() + .EndTable(); + + info.set_format_size(GetParam().format_size); + info.set_endianness(GetParam().endianness); + + info.Header(version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_type) + .ULEB128(0x41) // DW_TAG_type_unit, with children + .AppendCString("sam") // DW_AT_name, DW_FORM_string + .D8(0); // end of children + info.Finish(); + + { + InSequence s; + EXPECT_CALL(handler, + StartCompilationUnit(0, GetParam().address_size, + GetParam().format_size, _, + version)) + .WillOnce(Return(true)); + // If the type unit is handled properly, these calls will be skipped. + EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_type_unit)) + .Times(0); + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_string, + "sam")) + .Times(0); + EXPECT_CALL(handler, EndDIE(_)) + .Times(0); + } + + ByteReader byte_reader(GetParam().endianness == kLittleEndian ? + ENDIANNESS_LITTLE : ENDIANNESS_BIG); + CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler); + EXPECT_EQ(parser.Start(), info_contents.size()); +} + +INSTANTIATE_TEST_SUITE_P( HeaderVariants, DwarfHeader, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - DwarfHeaderParams(kLittleEndian, 4, 2, 8), - DwarfHeaderParams(kLittleEndian, 4, 3, 4), - DwarfHeaderParams(kLittleEndian, 4, 3, 8), - DwarfHeaderParams(kLittleEndian, 4, 4, 4), - DwarfHeaderParams(kLittleEndian, 4, 4, 8), - DwarfHeaderParams(kLittleEndian, 8, 2, 4), - DwarfHeaderParams(kLittleEndian, 8, 2, 8), - DwarfHeaderParams(kLittleEndian, 8, 3, 4), - DwarfHeaderParams(kLittleEndian, 8, 3, 8), - DwarfHeaderParams(kLittleEndian, 8, 4, 4), - DwarfHeaderParams(kLittleEndian, 8, 4, 8), - DwarfHeaderParams(kBigEndian, 4, 2, 4), - DwarfHeaderParams(kBigEndian, 4, 2, 8), - DwarfHeaderParams(kBigEndian, 4, 3, 4), - DwarfHeaderParams(kBigEndian, 4, 3, 8), - DwarfHeaderParams(kBigEndian, 4, 4, 4), - DwarfHeaderParams(kBigEndian, 4, 4, 8), - DwarfHeaderParams(kBigEndian, 8, 2, 4), - DwarfHeaderParams(kBigEndian, 8, 2, 8), - DwarfHeaderParams(kBigEndian, 8, 3, 4), - DwarfHeaderParams(kBigEndian, 8, 3, 8), - DwarfHeaderParams(kBigEndian, 8, 4, 4), - DwarfHeaderParams(kBigEndian, 8, 4, 8))); + ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 5, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 5, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 5, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 5, 8, 1))); struct DwarfFormsFixture: public DIEFixture { // Start a compilation unit, as directed by |params|, containing one // childless DIE of the given tag, with one attribute of the given name // and form. The 'info' fixture member is left just after the abbrev // code, waiting for the attribute value to be appended. - void StartSingleAttributeDIE(const DwarfHeaderParams ¶ms, + void StartSingleAttributeDIE(const DwarfHeaderParams& params, DwarfTag tag, DwarfAttribute name, DwarfForm form) { // Create the abbreviation table. Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no) + abbrevs.Abbrev(1, tag, google_breakpad::DW_children_no) .Attribute(name, form) .EndAbbrev() .EndTable(); @@ -249,14 +298,15 @@ struct DwarfFormsFixture: public DIEFixture { // Create the compilation unit, up to the attribute value. info.set_format_size(params.format_size); info.set_endianness(params.endianness); - info.Header(params.version, abbrev_table, params.address_size) + info.Header(params.version, abbrev_table, params.address_size, + google_breakpad::DW_UT_compile) .ULEB128(1); // abbrev code } // Set up handler to expect a compilation unit matching |params|, // containing one childless DIE of the given tag, in the sequence s. Stop // just before the expectations. - void ExpectBeginCompilationUnit(const DwarfHeaderParams ¶ms, + void ExpectBeginCompilationUnit(const DwarfHeaderParams& params, DwarfTag tag, uint64_t offset=0) { EXPECT_CALL(handler, StartCompilationUnit(offset, params.address_size, @@ -275,7 +325,7 @@ struct DwarfFormsFixture: public DIEFixture { .WillOnce(Return()); } - void ParseCompilationUnit(const DwarfHeaderParams ¶ms, + void ParseCompilationUnit(const DwarfHeaderParams& params, uint64_t offset=0) { ByteReader byte_reader(params.endianness == kLittleEndian ? ENDIANNESS_LITTLE : ENDIANNESS_BIG); @@ -291,9 +341,9 @@ struct DwarfForms: public DwarfFormsFixture, public TestWithParam<DwarfHeaderParams> { }; TEST_P(DwarfForms, addr) { - StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr); + StartSingleAttributeDIE(GetParam(), google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr); uint64_t value; if (GetParam().address_size == 4) { value = 0xc8e9ffcc; @@ -304,9 +354,93 @@ TEST_P(DwarfForms, addr) { } info.Finish(); - ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit); - EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, + ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, + value)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + +TEST_P(DwarfForms, strx1) { + if (GetParam().version != 5) { + return; + } + Label abbrev_table = abbrevs.Here(); + abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit, + google_breakpad::DW_children_no) + .Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_strx1) + .Attribute(google_breakpad::DW_AT_low_pc, google_breakpad::DW_FORM_addr) + .Attribute(google_breakpad::DW_AT_str_offsets_base, + google_breakpad::DW_FORM_sec_offset) + .EndAbbrev() + .EndTable(); + + info.set_format_size(GetParam().format_size); + info.set_endianness(GetParam().endianness); + info.Header(GetParam().version, abbrev_table, GetParam().address_size, + google_breakpad::DW_UT_compile) + .ULEB128(1) // abbrev index + .D8(2); // string index + + uint64_t value; + uint64_t offsets_base; + if (GetParam().address_size == 4) { + value = 0xc8e9ffcc; + offsets_base = 8; + info.D32(value); // low pc + info.D32(offsets_base); // str_offsets_base + } else { + value = 0xe942517fc2768564ULL; + offsets_base = 16; + info.D64(value); // low_pc + info.D64(offsets_base); // str_offsets_base + } + info.Finish(); + + Section debug_strings; + // no header, just a series of null-terminated strings. + debug_strings.AppendCString("apple"); // offset = 0 + debug_strings.AppendCString("bird"); // offset = 6 + debug_strings.AppendCString("canary"); // offset = 11 + debug_strings.AppendCString("dinosaur"); // offset = 18 + + Section str_offsets; + str_offsets.set_endianness(GetParam().endianness); + // Header for .debug_str_offsets + if (GetParam().address_size == 4) { + str_offsets.D32(24); // section length (4 bytes) + } else { + str_offsets.D32(0xffffffff); + str_offsets.D64(48); // section length (12 bytes) + } + str_offsets.D16(GetParam().version); // version (2 bytes) + str_offsets.D16(0); // padding (2 bytes) + + // .debug_str_offsets data (the offsets) + if (GetParam().address_size == 4) { + str_offsets.D32(0); + str_offsets.D32(6); + str_offsets.D32(11); + str_offsets.D32(18); + } else { + str_offsets.D64(0); + str_offsets.D64(6); + str_offsets.D64(11); + str_offsets.D64(18); + } + + + ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit); + EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name, + google_breakpad::DW_FORM_strx1, + "bird")) + .WillOnce(Return()); + EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc, + google_breakpad::DW_FORM_addr, value)) .InSequence(s) .WillOnce(Return()); @@ -318,13 +452,13 @@ TEST_P(DwarfForms, addr) { TEST_P(DwarfForms, block2_empty) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); + google_breakpad::DW_FORM_block2); info.D16(0); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, + google_breakpad::DW_FORM_block2, _, 0)) .InSequence(s) .WillOnce(Return()); @@ -336,7 +470,7 @@ TEST_P(DwarfForms, block2_empty) { TEST_P(DwarfForms, block2) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); + google_breakpad::DW_FORM_block2); unsigned char data[258]; memset(data, '*', sizeof(data)); info.D16(sizeof(data)) @@ -345,7 +479,7 @@ TEST_P(DwarfForms, block2) { ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, + google_breakpad::DW_FORM_block2, Pointee('*'), 258)) .InSequence(s) .WillOnce(Return()); @@ -357,14 +491,14 @@ TEST_P(DwarfForms, block2) { TEST_P(DwarfForms, flag_present) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2, (DwarfAttribute) 0x359d1972, - dwarf2reader::DW_FORM_flag_present); + google_breakpad::DW_FORM_flag_present); // DW_FORM_flag_present occupies no space in the DIE. info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2); EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972, - dwarf2reader::DW_FORM_flag_present, + google_breakpad::DW_FORM_flag_present, 1)) .InSequence(s) .WillOnce(Return()); @@ -376,7 +510,7 @@ TEST_P(DwarfForms, flag_present) { TEST_P(DwarfForms, sec_offset) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689, (DwarfAttribute) 0xa060bfd1, - dwarf2reader::DW_FORM_sec_offset); + google_breakpad::DW_FORM_sec_offset); uint64_t value; if (GetParam().format_size == 4) { value = 0xacc9c388; @@ -389,7 +523,7 @@ TEST_P(DwarfForms, sec_offset) { ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689); EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1, - dwarf2reader::DW_FORM_sec_offset, + google_breakpad::DW_FORM_sec_offset, value)) .InSequence(s) .WillOnce(Return()); @@ -401,14 +535,14 @@ TEST_P(DwarfForms, sec_offset) { TEST_P(DwarfForms, exprloc) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb, (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc); + google_breakpad::DW_FORM_exprloc); info.ULEB128(29) .Append(29, 173); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb); EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc, + google_breakpad::DW_FORM_exprloc, Pointee(173), 29)) .InSequence(s) .WillOnce(Return()); @@ -420,13 +554,13 @@ TEST_P(DwarfForms, exprloc) { TEST_P(DwarfForms, ref_sig8) { StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); + google_breakpad::DW_FORM_ref_sig8); info.D64(0xf72fa0cb6ddcf9d6ULL); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8, + google_breakpad::DW_FORM_ref_sig8, 0xf72fa0cb6ddcf9d6ULL)) .InSequence(s) .WillOnce(Return()); @@ -444,13 +578,13 @@ TEST_P(DwarfForms, ref_sig8_not_first) { info.Append(98, '*'); StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); + google_breakpad::DW_FORM_ref_sig8); info.D64(0xf72fa0cb6ddcf9d6ULL); info.Finish(); ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98); EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8, + google_breakpad::DW_FORM_ref_sig8, 0xf72fa0cb6ddcf9d6ULL)) .InSequence(s) .WillOnce(Return()); @@ -459,31 +593,371 @@ TEST_P(DwarfForms, ref_sig8_not_first) { ParseCompilationUnit(GetParam(), 98); } +TEST_P(DwarfForms, implicit_const) { + const DwarfHeaderParams& params = GetParam(); + const uint64_t implicit_constant_value = 0x1234; + // Create the abbreviation table. + Label abbrev_table = abbrevs.Here(); + abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, google_breakpad::DW_children_no) + .Attribute((DwarfAttribute) 0xd708d908, + google_breakpad::DW_FORM_implicit_const) + .ULEB128(implicit_constant_value); + abbrevs.EndAbbrev().EndTable(); + + info.set_format_size(params.format_size); + info.set_endianness(params.endianness); + info.Header(params.version, abbrev_table, params.address_size, + google_breakpad::DW_UT_compile) + .ULEB128(1); // abbrev code + info.Finish(); + + ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); + EXPECT_CALL(handler, + ProcessAttributeUnsigned(_, (DwarfAttribute) 0xd708d908, + google_breakpad::DW_FORM_implicit_const, + implicit_constant_value)) + .InSequence(s) + .WillOnce(Return()); + ExpectEndCompilationUnit(); + + ParseCompilationUnit(GetParam()); +} + // Tests for the other attribute forms could go here. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( HeaderVariants, DwarfForms, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - DwarfHeaderParams(kLittleEndian, 4, 2, 8), - DwarfHeaderParams(kLittleEndian, 4, 3, 4), - DwarfHeaderParams(kLittleEndian, 4, 3, 8), - DwarfHeaderParams(kLittleEndian, 4, 4, 4), - DwarfHeaderParams(kLittleEndian, 4, 4, 8), - DwarfHeaderParams(kLittleEndian, 8, 2, 4), - DwarfHeaderParams(kLittleEndian, 8, 2, 8), - DwarfHeaderParams(kLittleEndian, 8, 3, 4), - DwarfHeaderParams(kLittleEndian, 8, 3, 8), - DwarfHeaderParams(kLittleEndian, 8, 4, 4), - DwarfHeaderParams(kLittleEndian, 8, 4, 8), - DwarfHeaderParams(kBigEndian, 4, 2, 4), - DwarfHeaderParams(kBigEndian, 4, 2, 8), - DwarfHeaderParams(kBigEndian, 4, 3, 4), - DwarfHeaderParams(kBigEndian, 4, 3, 8), - DwarfHeaderParams(kBigEndian, 4, 4, 4), - DwarfHeaderParams(kBigEndian, 4, 4, 8), - DwarfHeaderParams(kBigEndian, 8, 2, 4), - DwarfHeaderParams(kBigEndian, 8, 2, 8), - DwarfHeaderParams(kBigEndian, 8, 3, 4), - DwarfHeaderParams(kBigEndian, 8, 3, 8), - DwarfHeaderParams(kBigEndian, 8, 4, 4), - DwarfHeaderParams(kBigEndian, 8, 4, 8))); + ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1), + DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 4, 4, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 2, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 3, 8, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 4, 1), + DwarfHeaderParams(kBigEndian, 8, 4, 8, 1))); + +class MockRangeListHandler: public google_breakpad::RangeListHandler { + public: + MOCK_METHOD(void, AddRange, (uint64_t begin, uint64_t end)); + MOCK_METHOD(void, Finish, ()); +}; + +TEST(RangeList, Dwarf4ReadRangeList) { + using google_breakpad::RangeListReader; + using google_breakpad::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<const uint8_t*>(section_contents.data()); + cu_info.size_ = section_contents.size(); + + MockRangeListHandler handler; + google_breakpad::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_rnglists) { + using google_breakpad::RangeListReader; + using google_breakpad::DW_RLE_base_addressx; + using google_breakpad::DW_RLE_startx_endx; + using google_breakpad::DW_RLE_startx_length; + using google_breakpad::DW_RLE_offset_pair; + using google_breakpad::DW_RLE_end_of_list; + using google_breakpad::DW_RLE_base_address; + using google_breakpad::DW_RLE_start_end; + using google_breakpad::DW_RLE_start_length; + using google_breakpad::DW_FORM_sec_offset; + using google_breakpad::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); + // 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 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(); + + // Offset entries. + Label range0; + rnglists1.Append(kBigEndian, 4, range0); + Label range1; + rnglists1.Append(kBigEndian, 4, range1); + + // 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 = 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; + cu_info.version_ = 5; + cu_info.base_address_ = 1; + cu_info.ranges_base_ = ranges_base_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; + google_breakpad::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; + google_breakpad::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 google_breakpad::RangeListReader; + using google_breakpad::DW_RLE_base_addressx; + using google_breakpad::DW_RLE_startx_endx; + using google_breakpad::DW_RLE_startx_length; + using google_breakpad::DW_RLE_offset_pair; + using google_breakpad::DW_RLE_end_of_list; + using google_breakpad::DW_RLE_base_address; + using google_breakpad::DW_RLE_start_end; + using google_breakpad::DW_RLE_start_length; + using google_breakpad::DW_FORM_sec_offset; + using google_breakpad::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; + google_breakpad::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())); +} |