Chromium Code Reviews| Index: test/unittests/eh-frame-writer-unittest.cc |
| diff --git a/test/unittests/eh-frame-writer-unittest.cc b/test/unittests/eh-frame-writer-unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..b1d60e458d3d837e2154430f914525480679f336 |
| --- /dev/null |
| +++ b/test/unittests/eh-frame-writer-unittest.cc |
| @@ -0,0 +1,362 @@ |
| +// Copyright 2016 the V8 project authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "src/eh-frame.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +// Test enabled only on supported architectures. |
| +#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM) || \ |
| + defined(V8_TARGET_ARCH_ARM64) |
| + |
| +using namespace v8::internal; |
| + |
| +namespace v8 { |
| +namespace internal { |
| + |
| +class EhFrameWriterInternals : public testing::Test { |
| + protected: |
| + // Being a non-negative 6bit value, this also serves as its LEB128 encoding. |
| + static const int kTestRegisterCode = 0; |
|
rmcilroy
2016/07/05 10:56:13
I would test a more interesting code than '0', tha
|
| + |
| + void WriteULEB128(int value) { writer_.WriteULEB128(value); } |
| + void WriteSLEB128(int value) { writer_.WriteSLEB128(value); } |
| + void Align() { writer_.Align(); } |
| + void WriteByte(byte c) { writer_.WriteByte(c); } |
| + |
| + static uint32_t DecodeULEB128(const byte* data, int* decoded_size) { |
| + return EhFrameWriter::DecodeULEB128(data, decoded_size); |
| + } |
| + |
| + static int32_t DecodeSLEB128(const byte* data, int* decoded_size) { |
| + return EhFrameWriter::DecodeSLEB128(data, decoded_size); |
| + } |
| + |
| + byte* eh_frame_buffer() { return writer_.eh_frame_buffer_.data(); } |
| + int eh_frame_offset() const { return writer_.eh_frame_offset(); } |
| + int cie_size() const { return writer_.cie_size_; } |
| + int fde_offset() const { return writer_.fde_offset(); } |
| + int procedure_address_offset() const { |
| + return writer_.procedure_address_offset(); |
| + } |
| + int procedure_size_offset() const { return writer_.procedure_size_offset(); } |
| + |
| + EhFrameWriter writer_; |
| +}; |
| + |
| +STATIC_CONST_MEMBER_DEFINITION const int |
| + EhFrameWriterInternals::kTestRegisterCode; |
|
rmcilroy
2016/07/05 10:56:13
Don't think you should need this?
Stefano Sanfilippo
2016/07/05 16:02:14
Also in this case, omitting this bit results in a
|
| + |
| +} // namespace internal |
| +} // namespace v8 |
| + |
| +TEST_F(EhFrameWriterInternals, RecordsAlignment) { |
|
rmcilroy
2016/07/05 10:56:13
The fixture should be named EhFrameWriterTest
Stefano Sanfilippo
2016/07/05 16:02:14
Done.
|
| + writer_.Finish(100); |
| + EXPECT_EQ(4, EhFrameWriter::kTerminatorSize); |
| + EXPECT_EQ(0, EhFrameHdr::kRecordSize % 4); |
| + EXPECT_EQ(0, (eh_frame_offset() - EhFrameHdr::kRecordSize - |
| + EhFrameWriter::kTerminatorSize) % |
| + 8); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, Align) { |
| + // Ensure the buffer size is not already aligned. |
| + if (eh_frame_offset() % 8 == 0) WriteByte(0); |
| + Align(); |
| + EXPECT_EQ(eh_frame_offset() % 8, 0); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, AlignNop) { |
| + Align(); |
| + int first_size = eh_frame_offset(); |
| + // This second align should result in a nop |
| + Align(); |
| + int second_size = eh_frame_offset(); |
| + EXPECT_EQ(first_size, second_size); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, ProcedureBoundaries) { |
| + writer_.Finish(100); |
| + int32_t procedure_offset = |
| + ReadUnalignedUInt32(eh_frame_buffer() + procedure_address_offset()); |
| + EXPECT_EQ(-(procedure_address_offset() + RoundUp(100, 8)), procedure_offset); |
| + uint32_t procedure_size = |
| + ReadUnalignedUInt32(eh_frame_buffer() + procedure_size_offset()); |
| + EXPECT_EQ(100, procedure_size); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, CIESize) { |
| + writer_.Finish(42); |
| + uint32_t encoded_cie_size = ReadUnalignedUInt32(eh_frame_buffer()); |
| + // The encoded CIE size does not include the size field itself. |
| + EXPECT_EQ(cie_size(), encoded_cie_size + kInt32Size); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, FDESize) { |
| + writer_.Finish(42); |
| + uint32_t fde_size = ReadUnalignedUInt32(eh_frame_buffer() + fde_offset()); |
| + EXPECT_EQ(eh_frame_offset() - EhFrameHdr::kRecordSize - cie_size() - |
| + EhFrameWriter::kTerminatorSize, |
| + fde_size); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SetOffset) { |
| + Register base_register_before_update = writer_.base_register(); |
| + int start = eh_frame_offset(); |
| + writer_.SetBaseAddressOffset(64); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(64, writer_.base_offset()); |
| + EXPECT_TRUE(base_register_before_update.is(writer_.base_register())); |
| + EXPECT_EQ(2, end - start); |
| + EXPECT_EQ(EhFrameWriter::kDefCfaOffset, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(64, eh_frame_buffer()[start + 1]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, IncreaseOffset) { |
| + int base_offset_before_update = writer_.base_offset(); |
| + Register base_register_before_update = writer_.base_register(); |
| + int start = eh_frame_offset(); |
| + writer_.IncreaseBaseAddressOffset(16); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(base_offset_before_update + 16, writer_.base_offset()); |
| + EXPECT_TRUE(base_register_before_update.is(writer_.base_register())); |
| + EXPECT_EQ(2, end - start); |
| + EXPECT_EQ(EhFrameWriter::kDefCfaOffset, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(base_offset_before_update + 16, eh_frame_buffer()[start + 1]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SetRegister) { |
| + int base_offset_before_update = writer_.base_offset(); |
| + int start = eh_frame_offset(); |
| + Register test_register = Register::from_code(kTestRegisterCode); |
| + writer_.SetBaseAddressRegister(test_register); |
| + int end = eh_frame_offset(); |
| + EXPECT_TRUE(writer_.base_register().is(test_register)); |
| + EXPECT_EQ(base_offset_before_update, writer_.base_offset()); |
| + EXPECT_EQ(2, end - start); |
| + EXPECT_EQ(EhFrameWriter::kDefCfaRegister, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(kTestRegisterCode, eh_frame_buffer()[start + 1]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SetRegisterAndOffset) { |
| + int start = eh_frame_offset(); |
| + Register test_register = Register::from_code(0); |
| + writer_.SetBaseAddressRegisterAndOffset(test_register, 24); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(24, writer_.base_offset()); |
| + EXPECT_TRUE(writer_.base_register().is(test_register)); |
| + EXPECT_EQ(3, end - start); |
| + EXPECT_EQ(EhFrameWriter::kDefCfa, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(kTestRegisterCode, eh_frame_buffer()[start + 1]); |
| + EXPECT_EQ(24, eh_frame_buffer()[start + 2]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, ULEB128Encoding) { |
| + int start = eh_frame_offset(); |
| + WriteULEB128(624485); |
| + int end = eh_frame_offset(); |
| + static const byte kExpectedEncoding[] = {0xe5, 0x8e, 0x26}; |
| + |
| + EXPECT_EQ(sizeof(kExpectedEncoding), end - start); |
| + EXPECT_EQ(kExpectedEncoding[0], eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(kExpectedEncoding[1], eh_frame_buffer()[start + 1]); |
| + EXPECT_EQ(kExpectedEncoding[2], eh_frame_buffer()[start + 2]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SLEB128EncodingPositive) { |
| + int start = eh_frame_offset(); |
| + WriteSLEB128(624485); |
| + int end = eh_frame_offset(); |
| + static const byte kExpectedEncoding[] = {0xe5, 0x8e, 0x26}; |
| + |
| + EXPECT_EQ(sizeof(kExpectedEncoding), end - start); |
| + EXPECT_EQ(kExpectedEncoding[0], eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(kExpectedEncoding[1], eh_frame_buffer()[start + 1]); |
| + EXPECT_EQ(kExpectedEncoding[2], eh_frame_buffer()[start + 2]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SLEB128EncodingNegative) { |
| + int start = eh_frame_offset(); |
| + WriteSLEB128(-624485); |
| + int end = eh_frame_offset(); |
| + static const byte kExpectedEncoding[] = {0x9b, 0xf1, 0x59}; |
| + |
| + EXPECT_EQ(sizeof(kExpectedEncoding), end - start); |
| + EXPECT_EQ(kExpectedEncoding[0], eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(kExpectedEncoding[1], eh_frame_buffer()[start + 1]); |
| + EXPECT_EQ(kExpectedEncoding[2], eh_frame_buffer()[start + 2]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, ULEB128Decoding) { |
| + static const byte kEncoded[] = {0xe5, 0x8e, 0x26}; |
| + int size = 0; |
| + uint32_t value = DecodeULEB128(kEncoded, &size); |
| + EXPECT_EQ(static_cast<int>(sizeof(kEncoded)), size); |
| + EXPECT_EQ(624485, value); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SLEB128DecodingPositive) { |
| + static const byte kEncoded[] = {0xe5, 0x8e, 0x26}; |
| + int size = 0; |
| + int32_t value = DecodeSLEB128(kEncoded, &size); |
| + EXPECT_EQ(static_cast<int>(sizeof(kEncoded)), size); |
| + EXPECT_EQ(624485, value); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SLEB128DecodingNegative) { |
| + static const byte kEncoded[] = {0x9b, 0xf1, 0x59}; |
| + int size = 0; |
| + int32_t value = DecodeSLEB128(kEncoded, &size); |
| + EXPECT_EQ(static_cast<int>(sizeof(kEncoded)), size); |
| + EXPECT_EQ(-624485, value); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, PcOffsetEncoding6bit) { |
| + EXPECT_EQ(0, writer_.last_pc_offset()); |
| + int start = eh_frame_offset(); |
| + writer_.AdvanceLocation(42); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(1, end - start); |
| + EXPECT_EQ((1 << 6) | 42, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(42, writer_.last_pc_offset()); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, PcOffsetEncoding6bitDelta) { |
| + writer_.AdvanceLocation(42); |
| + int start = eh_frame_offset(); |
| + writer_.AdvanceLocation(65); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(1, end - start); |
| + EXPECT_EQ((1 << 6) | (65 - 42), eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(65, writer_.last_pc_offset()); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, PcOffsetEncoding8bit) { |
| + EXPECT_EQ(0, writer_.last_pc_offset()); |
| + int start = eh_frame_offset(); |
| + writer_.AdvanceLocation(0x42); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(1 + sizeof(uint8_t), end - start); |
| + EXPECT_EQ(EhFrameWriter::kAdvanceLoc1, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(0x42, eh_frame_buffer()[start + 1]); |
| + EXPECT_EQ(0x42, writer_.last_pc_offset()); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, PcOffsetEncoding8bitDelta) { |
| + writer_.AdvanceLocation(0x10); |
| + int start = eh_frame_offset(); |
| + writer_.AdvanceLocation(0x70); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(1 + sizeof(uint8_t), end - start); |
| + EXPECT_EQ(0x70 - 0x10, eh_frame_buffer()[start + 1]); |
| + EXPECT_EQ(0x70, writer_.last_pc_offset()); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, PcOffsetEncoding16bit) { |
| + EXPECT_EQ(0, writer_.last_pc_offset()); |
| + int start = eh_frame_offset(); |
| + writer_.AdvanceLocation(42 + kMaxUInt8); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(1 + sizeof(uint16_t), end - start); |
| + EXPECT_EQ(EhFrameWriter::kAdvanceLoc2, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(42 + kMaxUInt8, ReadUnalignedUInt16(eh_frame_buffer() + start + 1)); |
| + EXPECT_EQ(42 + kMaxUInt8, writer_.last_pc_offset()); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, PcOffsetEncoding16bitDelta) { |
| + writer_.AdvanceLocation(41); |
| + int start = eh_frame_offset(); |
| + writer_.AdvanceLocation(62 + kMaxUInt8); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(1 + sizeof(uint16_t), end - start); |
| + EXPECT_EQ(62 + kMaxUInt8 - 41, |
| + ReadUnalignedUInt16(eh_frame_buffer() + start + 1)); |
| + EXPECT_EQ(62 + kMaxUInt8, writer_.last_pc_offset()); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, PcOffsetEncoding32bit) { |
| + EXPECT_EQ(0, writer_.last_pc_offset()); |
| + int start = eh_frame_offset(); |
| + writer_.AdvanceLocation(42 + kMaxUInt16); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(1 + sizeof(uint32_t), end - start); |
| + EXPECT_EQ(EhFrameWriter::kAdvanceLoc4, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(42 + kMaxUInt16, |
| + ReadUnalignedUInt32(eh_frame_buffer() + start + 1)); |
| + EXPECT_EQ(42 + kMaxUInt16, writer_.last_pc_offset()); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, PcOffsetEncoding32bitDelta) { |
| + writer_.AdvanceLocation(41); |
| + int start = eh_frame_offset(); |
| + writer_.AdvanceLocation(62 + kMaxUInt16); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(1 + sizeof(uint32_t), end - start); |
| + EXPECT_EQ(62 + kMaxUInt16 - 41, |
| + ReadUnalignedUInt32(eh_frame_buffer() + start + 1)); |
| + EXPECT_EQ(62 + kMaxUInt16, writer_.last_pc_offset()); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, GetEhFrame) { |
| + writer_.Finish(42); |
| + CodeDesc code_desc; |
| + writer_.GetEhFrame(&code_desc); |
| + EXPECT_EQ(eh_frame_offset(), code_desc.unwinding_info_size); |
| + EXPECT_EQ(0, memcmp(eh_frame_buffer(), code_desc.unwinding_info, |
| + eh_frame_offset())); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SaveRegisterPositiveOffset) { |
| + int start = eh_frame_offset(); |
| + Register test_register = Register::from_code(kTestRegisterCode); |
| + writer_.RegisterSavedToStack(test_register, 16); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(2, end - start); |
| + EXPECT_EQ((2 << 6) | kTestRegisterCode, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(16 / std::abs(EhFrameWriter::kDataAlignmentFactor), |
| + eh_frame_buffer()[start + 1]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SaveRegisterNegativeOffset) { |
| + int start = eh_frame_offset(); |
| + Register test_register = Register::from_code(kTestRegisterCode); |
| + writer_.RegisterSavedToStack(test_register, -16); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(3, end - start); |
| + EXPECT_EQ(EhFrameWriter::kOffsetExtendedSf, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(kTestRegisterCode, eh_frame_buffer()[start + 1]); |
| + if (EhFrameWriter::kDataAlignmentFactor == -4) { |
| + EXPECT_EQ(0x7c, eh_frame_buffer()[start + 2]); // -4 SLEB128 encoded. |
| + } else if (EhFrameWriter::kDataAlignmentFactor == -8) { |
| + EXPECT_EQ(0x7e, eh_frame_buffer()[start + 2]); // -2 SLEB128 encoded. |
| + } else { |
| + EXPECT_TRUE(false && "Data alignment not handled in test."); |
| + } |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, SaveRegisterToTop) { |
| + int base_offset_before_call = writer_.base_offset(); |
| + int start = eh_frame_offset(); |
| + Register test_register = Register::from_code(kTestRegisterCode); |
| + writer_.RegisterSavedToStack(test_register); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(base_offset_before_call, writer_.base_offset()); |
| + EXPECT_GE(base_offset_before_call, 0); |
| + EXPECT_EQ(2, end - start); |
| + EXPECT_EQ((2 << 6) | kTestRegisterCode, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ( |
| + base_offset_before_call / std::abs(EhFrameWriter::kDataAlignmentFactor), |
| + eh_frame_buffer()[start + 1]); |
| +} |
| + |
| +TEST_F(EhFrameWriterInternals, RegisterIsValid) { |
| + Register test_register = Register::from_code(kTestRegisterCode); |
| + int start = eh_frame_offset(); |
| + writer_.RegisterIsValid(test_register); |
| + int end = eh_frame_offset(); |
| + EXPECT_EQ(2, end - start); |
| + EXPECT_EQ(EhFrameWriter::kSameValue, eh_frame_buffer()[start + 0]); |
| + EXPECT_EQ(kTestRegisterCode, eh_frame_buffer()[start + 1]); |
| +} |
| + |
| +#endif |