diff options
-rw-r--r-- | src/common/dwarf/cfi_assembler.cc | 8 | ||||
-rw-r--r-- | src/common/dwarf/cfi_assembler.h | 4 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2reader.cc | 48 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2reader.h | 8 | ||||
-rw-r--r-- | src/common/dwarf/dwarf2reader_cfi_unittest.cc | 87 |
5 files changed, 147 insertions, 8 deletions
diff --git a/src/common/dwarf/cfi_assembler.cc b/src/common/dwarf/cfi_assembler.cc index dbc2efae..2dc22085 100644 --- a/src/common/dwarf/cfi_assembler.cc +++ b/src/common/dwarf/cfi_assembler.cc @@ -46,7 +46,9 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, unsigned return_address_register, uint8_t version, const string &augmentation, - bool dwarf64) { + bool dwarf64, + uint8_t address_size, + uint8_t segment_size) { assert(!entry_length_); entry_length_ = new PendingLength(); in_fde_ = false; @@ -63,6 +65,10 @@ CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, } D8(version); AppendCString(augmentation); + if (version >= 4) { + D8(address_size); + D8(segment_size); + } ULEB128(code_alignment_factor); LEB128(data_alignment_factor); if (version == 1) diff --git a/src/common/dwarf/cfi_assembler.h b/src/common/dwarf/cfi_assembler.h index 227812b5..bd7354d1 100644 --- a/src/common/dwarf/cfi_assembler.h +++ b/src/common/dwarf/cfi_assembler.h @@ -138,7 +138,9 @@ class CFISection: public Section { unsigned return_address_register, uint8_t version = 3, const string &augmentation = "", - bool dwarf64 = false); + bool dwarf64 = false, + uint8_t address_size = 8, + uint8_t segment_size = 0); // Append a Frame Description Entry header to this section with the // given values. If dwarf64 is true, use the 64-bit DWARF initial diff --git a/src/common/dwarf/dwarf2reader.cc b/src/common/dwarf/dwarf2reader.cc index a65b43c8..fda049dd 100644 --- a/src/common/dwarf/dwarf2reader.cc +++ b/src/common/dwarf/dwarf2reader.cc @@ -2253,11 +2253,11 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { cursor++; // If we don't recognize the version, we can't parse any more fields of the - // CIE. For DWARF CFI, we handle versions 1 through 3 (there was never a - // version 2 of CFI data). For .eh_frame, we handle versions 1 and 3 as well; + // CIE. For DWARF CFI, we handle versions 1 through 4 (there was never a + // version 2 of CFI data). For .eh_frame, we handle versions 1 and 4 as well; // the difference between those versions seems to be the same as for // .debug_frame. - if (cie->version < 1 || cie->version > 3) { + if (cie->version < 1 || cie->version > 4) { reporter_->UnrecognizedVersion(cie->offset, cie->version); return false; } @@ -2287,16 +2287,36 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { } } + if (cie->version >= 4) { + uint8_t address_size = *cursor++; + if (address_size != 8) { + // TODO(scottmg): Only supporting x64 for now. + reporter_->UnexpectedAddressSize(cie->offset, address_size); + return false; + } + + uint8_t segment_size = *cursor++; + if (segment_size != 0) { + // TODO(scottmg): Only supporting x64 for now. + // I would have perhaps expected 4 here, but LLVM emits a 0, near + // http://llvm.org/docs/doxygen/html/MCDwarf_8cpp_source.html#l00606. As + // we are not using the value, only succeed for now if it's the expected + // 0. + reporter_->UnexpectedSegmentSize(cie->offset, segment_size); + return false; + } + } + // Parse the code alignment factor. cie->code_alignment_factor = reader_->ReadUnsignedLEB128(cursor, &len); if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); cursor += len; - + // Parse the data alignment factor. cie->data_alignment_factor = reader_->ReadSignedLEB128(cursor, &len); if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); cursor += len; - + // Parse the return address register. This is a ubyte in version 1, and // a ULEB128 in version 3. if (cie->version == 1) { @@ -2407,7 +2427,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) { return true; } - + bool CallFrameInfo::ReadFDEFields(FDE *fde) { const uint8_t *cursor = fde->fields; size_t size; @@ -2648,6 +2668,22 @@ void CallFrameInfo::Reporter::BadCIEId(uint64 offset, uint64 cie_offset) { filename_.c_str(), offset, section_.c_str(), cie_offset); } +void CallFrameInfo::Reporter::UnexpectedAddressSize(uint64 offset, + uint8_t address_size) { + fprintf(stderr, + "%s: CFI frame description entry at offset 0x%llx in '%s':" + " CIE specifies unexpected address size: %d\n", + filename_.c_str(), offset, section_.c_str(), address_size); +} + +void CallFrameInfo::Reporter::UnexpectedSegmentSize(uint64 offset, + uint8_t segment_size) { + fprintf(stderr, + "%s: CFI frame description entry at offset 0x%llx in '%s':" + " CIE specifies unexpected segment size: %d\n", + filename_.c_str(), offset, section_.c_str(), segment_size); +} + void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) { fprintf(stderr, "%s: CFI frame description entry at offset 0x%llx in '%s':" diff --git a/src/common/dwarf/dwarf2reader.h b/src/common/dwarf/dwarf2reader.h index 064c42bc..5d2d7f60 100644 --- a/src/common/dwarf/dwarf2reader.h +++ b/src/common/dwarf/dwarf2reader.h @@ -1227,6 +1227,14 @@ class CallFrameInfo::Reporter { // there is not a CIE. virtual void BadCIEId(uint64 offset, uint64 cie_offset); + // The FDE at OFFSET refers to a CIE with an address size we don't know how + // to handle. + virtual void UnexpectedAddressSize(uint64 offset, uint8_t address_size); + + // The FDE at OFFSET refers to a CIE with an segment descriptor size we + // don't know how to handle. + virtual void UnexpectedSegmentSize(uint64 offset, uint8_t segment_size); + // The FDE at OFFSET refers to a CIE with version number VERSION, // which we don't recognize. We cannot parse DWARF CFI if it uses // a version number we don't recognize. diff --git a/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/src/common/dwarf/dwarf2reader_cfi_unittest.cc index e50ea5fb..38cc7ea3 100644 --- a/src/common/dwarf/dwarf2reader_cfi_unittest.cc +++ b/src/common/dwarf/dwarf2reader_cfi_unittest.cc @@ -126,6 +126,8 @@ class MockCallFrameErrorReporter: public CallFrameInfo::Reporter { MOCK_METHOD1(EarlyEHTerminator, void(uint64)); MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64)); MOCK_METHOD2(BadCIEId, void(uint64, uint64)); + MOCK_METHOD2(UnexpectedAddressSize, void(uint64, uint8_t)); + MOCK_METHOD2(UnexpectedSegmentSize, void(uint64, uint8_t)); MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version)); MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &)); MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8)); @@ -605,6 +607,91 @@ TEST_F(CFI, CIEVersion3ReturnColumn) { EXPECT_TRUE(parser.Start()); } +TEST_F(CFI, CIEVersion4AdditionalFields) { + CFISection section(kBigEndian, 4); + Label cie; + section + .Mark(&cie) + // CIE version 4 with expected address and segment size. + .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 4, "", true, 8, 0) + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section); + + { + InSequence s; + EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 4, "", 0x89)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(4); + CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedAddressSize) { + CFISection section(kBigEndian, 4); + Label cie; + + section + .Mark(&cie) + // Unexpected address size. + .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 4, "", true, 3, 0) + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedAddress", section); + + EXPECT_CALL(reporter, UnexpectedAddressSize(_, 3)) + .WillOnce(Return()); + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(8); + CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +TEST_F(CFI, CIEVersion4AdditionalFieldsUnexpectedSegmentSize) { + CFISection section(kBigEndian, 4); + Label cie; + + section + .Mark(&cie) + .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 4, "", true, 8, 7) + .FinishEntry() + .FDEHeader(cie, 0x7bf0fda0, 0xcbcd28d8) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("AdditionalFieldsUnexpectedSegment", section); + + EXPECT_CALL(reporter, UnexpectedSegmentSize(_, 7)) + .WillOnce(Return()); + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader byte_reader(ENDIANNESS_BIG); + byte_reader.SetAddressSize(8); + CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), + contents.size(), + &byte_reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + struct CFIInsnFixture: public CFIFixture { CFIInsnFixture() : CFIFixture() { data_factor = 0xb6f; |