From 3c528da94cb76fd48e6fe5a9815350a32a59c4a4 Mon Sep 17 00:00:00 2001 From: Caroline Tice Date: Sat, 16 Jan 2021 17:05:32 -0800 Subject: [PATCH] Dwarf5 fixes [4 of 5]: Skip processing Dwarf5 type units. Fourth of 5 small patches to fix various breakpad issues found while testing dump_syms on DWARF v5 in ChromeOS. Dwarfv5 adds many new Type Unit sections to debug information. Since these only contain type information, they are of no interest to dump_syms. This CL gets dump_syms to skip trying to process the type unit sections. Without this CL, dump_syms takes ~ 3 hours to process the DWARF v5 Chrome binary. With this CL, dump_syms takes ~ 8 minutes to process the DWARF v5 Chrome binary (about the same time as it takes for DWARF v4). This CL also adds a test case to verify that type units are being skipped. Change-Id: Ie0bb2d675718f7041b8e9b3186ed44f80a3ad39c Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/2634549 Reviewed-by: Sterling Augustine --- src/common/dwarf/dwarf2reader.cc | 5 +- src/common/dwarf/dwarf2reader.h | 3 + src/common/dwarf/dwarf2reader_die_unittest.cc | 170 +++++++++++------- src/common/dwarf/dwarf2reader_test_common.h | 13 +- 4 files changed, 128 insertions(+), 63 deletions(-) diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index e9af9b24..9db1ba92 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -74,7 +74,7 @@ CompilationUnit::CompilationUnit(const string& path, line_string_buffer_(NULL), line_string_buffer_length_(0), str_offsets_buffer_(NULL), str_offsets_buffer_length_(0), addr_buffer_(NULL), addr_buffer_length_(0), - is_split_dwarf_(false), dwo_id_(0), dwo_name_(), + is_split_dwarf_(false), is_type_unit_(false), dwo_id_(0), dwo_name_(), skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), str_offsets_base_(0), have_checked_for_dwp_(false), dwp_path_(), dwp_byte_reader_(), dwp_reader_() {} @@ -358,6 +358,7 @@ void CompilationUnit::ReadHeader() { break; case DW_UT_type: case DW_UT_split_type: + is_type_unit_ = true; headerptr += ReadTypeSignature(headerptr); headerptr += ReadTypeOffset(headerptr); break; @@ -404,6 +405,8 @@ uint64_t CompilationUnit::Start() { header_.length, header_.version)) return ourlength; + else if (header_.version == 5 && is_type_unit_) + return ourlength; // Otherwise, continue by reading our abbreviation entries. ReadAbbrevs(); diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index 92a05efe..3ff3e07b 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -714,6 +714,9 @@ class CompilationUnit { // associated with the skeleton compilation unit. bool is_split_dwarf_; + // Flag indicating if it's a Type Unit (only applicable to DWARF v5). + bool is_type_unit_; + // The value of the DW_AT_GNU_dwo_id attribute, if any. uint64_t dwo_id_; diff --git a/src/common/dwarf/dwarf2reader_die_unittest.cc b/src/common/dwarf/dwarf2reader_die_unittest.cc index e329630c..ea54bf07 100644 --- a/src/common/dwarf/dwarf2reader_die_unittest.cc +++ b/src/common/dwarf/dwarf2reader_die_unittest.cc @@ -152,13 +152,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, @@ -175,7 +177,8 @@ TEST_P(DwarfHeader, Header) { 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, + dwarf2reader::DW_UT_compile) .ULEB128(1) // DW_TAG_compile_unit, with children .AppendCString("sam") // DW_AT_name, DW_FORM_string .D8(0); // end of children @@ -190,7 +193,7 @@ TEST_P(DwarfHeader, Header) { .WillOnce(Return(true)); EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit)) .WillOnce(Return(true)); - EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, + EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string, "sam")) .WillOnce(Return()); @@ -204,36 +207,79 @@ TEST_P(DwarfHeader, Header) { EXPECT_EQ(parser.Start(), info_contents.size()); } -INSTANTIATE_TEST_SUITE_P( +TEST_P(DwarfHeader, TypeUnitHeader) { + Label abbrev_table = abbrevs.Here(); + int version = 5; + abbrevs.Abbrev(1, dwarf2reader::DW_TAG_type_unit, + dwarf2reader::DW_children_yes) + .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::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, + dwarf2reader::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(_, dwarf2reader::DW_TAG_type_unit)) + .Times(0); + EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, + dwarf2reader::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_CASE_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(kLittleEndian, 8, 5, 4), - DwarfHeaderParams(kLittleEndian, 8, 5, 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), - DwarfHeaderParams(kBigEndian, 8, 5, 4), - DwarfHeaderParams(kBigEndian, 8, 5, 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 @@ -253,7 +299,8 @@ 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, + dwarf2reader::DW_UT_compile) .ULEB128(1); // abbrev code } @@ -560,7 +607,8 @@ TEST_P(DwarfForms, implicit_const) { 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, + dwarf2reader::DW_UT_compile) .ULEB128(1); // abbrev code info.Finish(); @@ -578,32 +626,32 @@ TEST_P(DwarfForms, implicit_const) { // Tests for the other attribute forms could go here. -INSTANTIATE_TEST_SUITE_P( +INSTANTIATE_TEST_CASE_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 dwarf2reader::RangeListHandler { public: @@ -658,8 +706,10 @@ 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; diff --git a/src/common/dwarf/dwarf2reader_test_common.h b/src/common/dwarf/dwarf2reader_test_common.h index 1934094d..5a0586c9 100644 --- a/src/common/dwarf/dwarf2reader_test_common.h +++ b/src/common/dwarf/dwarf2reader_test_common.h @@ -71,7 +71,7 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { // Append a DWARF compilation unit header to the section, with the given // DWARF version, abbrev table offset, and address size. TestCompilationUnit& Header(int version, const Label& abbrev_offset, - size_t address_size) { + size_t address_size, int header_type) { if (format_size_ == 4) { D32(length_); } else { @@ -84,9 +84,18 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section { SectionOffset(abbrev_offset); D8(address_size); } else { - D8(0x01); // DW_UT_compile + D8(header_type); // DW_UT_compile, DW_UT_type, etc. D8(address_size); SectionOffset(abbrev_offset); + if (header_type == dwarf2reader::DW_UT_type) { + uint64 dummy_type_signature = 0xdeadbeef; + uint64 dummy_type_offset = 0x2b; + D64(dummy_type_signature); + if (format_size_ == 4) + D32(dummy_type_offset); + else + D64(dummy_type_offset); + } } return *this; }