aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/dwarf/cfi_assembler.cc8
-rw-r--r--src/common/dwarf/cfi_assembler.h4
-rw-r--r--src/common/dwarf/dwarf2reader.cc48
-rw-r--r--src/common/dwarf/dwarf2reader.h8
-rw-r--r--src/common/dwarf/dwarf2reader_cfi_unittest.cc87
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;