| // Copyright 2024 The Fuchsia 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 <lib/elfldltl/dwarf/cfi-entry.h> |
| #include <lib/elfldltl/dwarf/eh-frame-hdr.h> |
| #include <lib/elfldltl/dwarf/encoding.h> |
| #include <lib/elfldltl/dwarf/section-data.h> |
| #include <lib/elfldltl/memory.h> |
| #include <lib/elfldltl/testing/diagnostics.h> |
| #include <lib/elfldltl/testing/typed-test.h> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| namespace { |
| |
| using ::testing::AllOf; |
| using ::testing::ElementsAre; |
| using ::testing::ElementsAreArray; |
| using ::testing::Eq; |
| using ::testing::Field; |
| using ::testing::FieldsAre; |
| using ::testing::Optional; |
| |
| FORMAT_TYPED_TEST_SUITE(ElfldltlDwarfTests); |
| |
| template <class Elf> |
| struct InitialLength32 { |
| typename Elf::Word length = 0; |
| }; |
| |
| template <class Elf> |
| struct [[gnu::packed]] InitialLength64 { |
| constexpr InitialLength64() = default; |
| |
| constexpr explicit InitialLength64(uint64_t n) : length{n} {} |
| |
| [[gnu::packed]] const uint32_t dwarf64_marker = 0xffffffff; |
| [[gnu::packed]] typename Elf::Xword length = 0; |
| }; |
| |
| template <class Length, typename T> |
| struct [[gnu::packed]] TestData { |
| constexpr TestData() = default; |
| |
| explicit constexpr TestData(const T& data) : contents{data} {} |
| |
| [[gnu::packed]] Length initial_length{sizeof(T)}; |
| [[gnu::packed]] T contents{}; |
| }; |
| |
| template <typename T> |
| constexpr cpp20::span<const std::byte> AsBytes(T& data) { |
| return cpp20::as_bytes(cpp20::span{&data, 1}); |
| } |
| |
| constexpr elfldltl::FileAddress kErrorArg{0x123u}; |
| |
| constexpr cpp20::span<const std::byte> kNoBytes{}; |
| |
| TYPED_TEST(ElfldltlDwarfTests, SectionDataEmpty) { |
| using Elf = typename TestFixture::Elf; |
| |
| elfldltl::dwarf::SectionData section_data; |
| EXPECT_TRUE(section_data.contents().empty()); |
| |
| auto diag = elfldltl::testing::ExpectOkDiagnostics(); |
| |
| { |
| constexpr InitialLength32<Elf> kEmpty; |
| auto read = elfldltl::dwarf::SectionData::Read<Elf>(diag, AsBytes(kEmpty)); |
| ASSERT_TRUE(read); |
| EXPECT_EQ(read->size_bytes(), 4u); |
| EXPECT_EQ(read->contents().size_bytes(), 0u); |
| } |
| |
| { |
| constexpr InitialLength64<Elf> kEmpty; |
| auto read = elfldltl::dwarf::SectionData::Read<Elf>(diag, AsBytes(kEmpty)); |
| ASSERT_TRUE(read); |
| EXPECT_EQ(read->size_bytes(), 12u); |
| EXPECT_EQ(read->contents().size_bytes(), 0u); |
| } |
| } |
| |
| TYPED_TEST(ElfldltlDwarfTests, SectionDataRead) { |
| using Elf = typename TestFixture::Elf; |
| |
| auto diag = elfldltl::testing::ExpectOkDiagnostics(); |
| |
| static constexpr std::byte kOneByte{17}; |
| { |
| constexpr TestData<InitialLength32<Elf>, std::byte> kOneByteData{kOneByte}; |
| auto read = elfldltl::dwarf::SectionData::Read<Elf>(diag, AsBytes(kOneByteData)); |
| ASSERT_TRUE(read); |
| EXPECT_EQ(read->size_bytes(), sizeof(kOneByteData)); |
| EXPECT_EQ(read->format(), elfldltl::dwarf::SectionData::Format::kDwarf32); |
| EXPECT_EQ(read->initial_length_size(), 4u); |
| EXPECT_EQ(read->offset_size(), 4u); |
| EXPECT_EQ(read->contents().size(), 1u); |
| EXPECT_THAT(read->contents(), ElementsAre(kOneByte)); |
| } |
| { |
| constexpr TestData<InitialLength64<Elf>, std::byte> kOneByteData{kOneByte}; |
| auto read = elfldltl::dwarf::SectionData::Read<Elf>(diag, AsBytes(kOneByteData)); |
| ASSERT_TRUE(read); |
| EXPECT_EQ(read->size_bytes(), sizeof(kOneByteData)); |
| EXPECT_EQ(read->format(), elfldltl::dwarf::SectionData::Format::kDwarf64); |
| EXPECT_EQ(read->initial_length_size(), 12u); |
| EXPECT_EQ(read->offset_size(), 8u); |
| EXPECT_EQ(read->contents().size(), 1u); |
| EXPECT_THAT(read->contents(), ElementsAre(kOneByte)); |
| } |
| } |
| |
| TYPED_TEST(ElfldltlDwarfTests, SectionDataConsume) { |
| using Elf = typename TestFixture::Elf; |
| |
| auto diag = elfldltl::testing::ExpectOkDiagnostics(); |
| |
| static constexpr std::byte kOneByte{17}; |
| constexpr struct { |
| TestData<InitialLength32<Elf>, std::byte> data{kOneByte}; |
| std::array<std::byte, 3> rest{std::byte{1}, std::byte{2}, std::byte{3}}; |
| } kData; |
| |
| auto [read, rest] = elfldltl::dwarf::SectionData::Consume<Elf>(diag, AsBytes(kData)); |
| ASSERT_TRUE(read); |
| EXPECT_EQ(read->contents().size(), 1u); |
| EXPECT_THAT(read->contents(), ElementsAre(kOneByte)); |
| EXPECT_THAT(rest, ElementsAreArray(kData.rest)); |
| } |
| |
| TYPED_TEST(ElfldltlDwarfTests, SectionDataReadOffset) { |
| using Elf = typename TestFixture::Elf; |
| |
| auto diag = elfldltl::testing::ExpectOkDiagnostics(); |
| |
| { |
| struct [[gnu::packed]] DataWithOffset { |
| std::byte extra_byte{23}; |
| [[gnu::packed]] typename Elf::Word offset{1234}; |
| }; |
| constexpr TestData<InitialLength32<Elf>, DataWithOffset> kDataWithOffset; |
| auto read = elfldltl::dwarf::SectionData::Read<Elf>(diag, AsBytes(kDataWithOffset)); |
| ASSERT_TRUE(read); |
| EXPECT_EQ(read->contents().size_bytes(), 5u); |
| auto offset = read->template read_offset<Elf>(1); |
| EXPECT_THAT(offset, Optional(Eq(1234u))); |
| } |
| { |
| struct [[gnu::packed]] DataWithOffset { |
| std::byte extra_byte{23}; |
| [[gnu::packed]] typename Elf::Xword offset{1234567890}; |
| }; |
| constexpr TestData<InitialLength64<Elf>, DataWithOffset> kDataWithOffset; |
| auto read = elfldltl::dwarf::SectionData::Read<Elf>(diag, AsBytes(kDataWithOffset)); |
| ASSERT_TRUE(read); |
| EXPECT_EQ(read->contents().size_bytes(), 9u); |
| auto offset = read->template read_offset<Elf>(1); |
| EXPECT_THAT(offset, Optional(Eq(1234567890u))); |
| } |
| } |
| |
| TYPED_TEST(ElfldltlDwarfTests, SectionDataReadFail) { |
| using Elf = typename TestFixture::Elf; |
| |
| // Empty buffer. |
| { |
| elfldltl::testing::ExpectedSingleError expected{ |
| "data size ", |
| 0, |
| " too small for DWARF header", |
| kErrorArg, |
| }; |
| auto read = elfldltl::dwarf::SectionData::Read<Elf>(expected, kNoBytes, kErrorArg); |
| EXPECT_FALSE(read); |
| } |
| |
| // Buffer too short for any initial length. |
| { |
| constexpr std::array<std::byte, 3> kTooShortForHeader = {}; |
| elfldltl::testing::ExpectedSingleError expected{ |
| "data size ", |
| kTooShortForHeader.size(), |
| " too small for DWARF header", |
| kErrorArg, |
| }; |
| auto read = |
| elfldltl::dwarf::SectionData::Read<Elf>(expected, AsBytes(kTooShortForHeader), kErrorArg); |
| EXPECT_FALSE(read); |
| } |
| |
| // Buffer too short for 64-bit initial length. |
| { |
| constexpr std::array<std::byte, 8> kTooShortForHeader64 = { |
| std::byte{0xff}, |
| std::byte{0xff}, |
| std::byte{0xff}, |
| std::byte{0xff}, |
| }; |
| elfldltl::testing::ExpectedSingleError expected{ |
| "data size ", |
| kTooShortForHeader64.size(), |
| " too small for DWARF header", |
| kErrorArg, |
| }; |
| auto read = |
| elfldltl::dwarf::SectionData::Read<Elf>(expected, AsBytes(kTooShortForHeader64), kErrorArg); |
| EXPECT_FALSE(read); |
| } |
| |
| // Reserved initial length values. |
| for (uint32_t value = elfldltl::dwarf::kDwarf32Limit; value < elfldltl::dwarf::kDwarf64Length; |
| ++value) { |
| const InitialLength32<Elf> kReserved{value}; |
| elfldltl::testing::ExpectedSingleError expected{ |
| "Reserved initial-length value ", |
| value, |
| " used in DWARF header", |
| kErrorArg, |
| }; |
| auto read = elfldltl::dwarf::SectionData::Read<Elf>(expected, AsBytes(kReserved), kErrorArg); |
| EXPECT_FALSE(read); |
| } |
| |
| // Truncated contents for 32-bit length. |
| { |
| constexpr InitialLength32<Elf> kTooShortForLength{1}; |
| elfldltl::testing::ExpectedSingleError expected{ |
| "data size ", 4, " < ", 5, " required by DWARF header", kErrorArg, |
| }; |
| auto read = |
| elfldltl::dwarf::SectionData::Read<Elf>(expected, AsBytes(kTooShortForLength), kErrorArg); |
| EXPECT_FALSE(read); |
| } |
| |
| // Truncated contents for 64-bit length. |
| { |
| constexpr InitialLength64<Elf> kTooShortForLength64{1}; |
| elfldltl::testing::ExpectedSingleError expected{ |
| "data size ", 12, " < ", 13, " required by DWARF header", kErrorArg, |
| }; |
| auto read = |
| elfldltl::dwarf::SectionData::Read<Elf>(expected, AsBytes(kTooShortForLength64), kErrorArg); |
| EXPECT_FALSE(read); |
| } |
| } |
| |
| TEST(ElfldltlDwarfTests, Uleb128) { |
| EXPECT_EQ(elfldltl::dwarf::Uleb128::Read(kNoBytes), std::nullopt); |
| |
| constexpr uint8_t kOneByte{17}; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kOneByte)), Optional(FieldsAre(17u, 1u))); |
| |
| constexpr uint8_t kTwoByte[] = {0x80 | (0xaau & 0x7f), 0xaau >> 7}; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kTwoByte)), Optional(FieldsAre(0xaau, 2u))); |
| |
| constexpr uint8_t kThreeByte[] = { |
| 0x80 | (0xaabbu & 0x7f), |
| 0x80 | ((0xaabbu >> 7) & 0x7f), |
| ((0xaabbu >> 14) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kThreeByte)), |
| Optional(FieldsAre(0xaabbu, 3u))); |
| |
| constexpr uint8_t kFourByte[] = { |
| 0x80 | (0xaabbccu & 0x7f), |
| 0x80 | ((0xaabbccu >> 7) & 0x7f), |
| 0x80 | ((0xaabbccu >> 14) & 0x7f), |
| ((0xaabbccu >> 21) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kFourByte)), |
| Optional(FieldsAre(0xaabbccu, 4u))); |
| |
| constexpr uint8_t kFiveByte[] = { |
| 0x80 | (0xaabbccddu & 0x7f), 0x80 | ((0xaabbccddu >> 7) & 0x7f), |
| 0x80 | ((0xaabbccddu >> 14) & 0x7f), 0x80 | ((0xaabbccddu >> 21) & 0x7f), |
| ((0xaabbccdd >> 28) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kFiveByte)), |
| Optional(FieldsAre(0xaabbccddu, 5u))); |
| |
| constexpr uint8_t kSixByte[] = { |
| 0x80 | (0xaabbccddeeu & 0x7f), 0x80 | ((0xaabbccddeeu >> 7) & 0x7f), |
| 0x80 | ((0xaabbccddeeu >> 14) & 0x7f), 0x80 | ((0xaabbccddeeu >> 21) & 0x7f), |
| 0x80 | ((0xaabbccddeeu >> 28) & 0x7f), ((0xaabbccddeeu >> 35) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kSixByte)), |
| Optional(FieldsAre(0xaabbccddeeu, 6u))); |
| |
| constexpr uint8_t kSevenByte[] = { |
| 0x80 | (0xaabbccddeeffu & 0x7f), 0x80 | ((0xaabbccddeeffu >> 7) & 0x7f), |
| 0x80 | ((0xaabbccddeeffu >> 14) & 0x7f), 0x80 | ((0xaabbccddeeffu >> 21) & 0x7f), |
| 0x80 | ((0xaabbccddeeffu >> 28) & 0x7f), 0x80 | ((0xaabbccddeeffu >> 35) & 0x7f), |
| ((0xaabbccddeeffu >> 42) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kSevenByte)), |
| Optional(FieldsAre(0xaabbccddeeffu, 7u))); |
| |
| constexpr uint8_t kEightByte[] = { |
| 0x80 | (0xaabbccddeeff11u & 0x7f), 0x80 | ((0xaabbccddeeff11u >> 7) & 0x7f), |
| 0x80 | ((0xaabbccddeeff11u >> 14) & 0x7f), 0x80 | ((0xaabbccddeeff11u >> 21) & 0x7f), |
| 0x80 | ((0xaabbccddeeff11u >> 28) & 0x7f), 0x80 | ((0xaabbccddeeff11u >> 35) & 0x7f), |
| 0x80 | ((0xaabbccddeeff11u >> 42) & 0x7f), ((0xaabbccddeeff11u >> 49) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kEightByte)), |
| Optional(FieldsAre(0xaabbccddeeff11u, 8u))); |
| |
| constexpr uint8_t kNineByte[] = { |
| 0x80 | (0x77bbccddeeff1122u & 0x7f), 0x80 | ((0x77bbccddeeff1122u >> 7) & 0x7f), |
| 0x80 | ((0x77bbccddeeff1122u >> 14) & 0x7f), 0x80 | ((0x77bbccddeeff1122u >> 21) & 0x7f), |
| 0x80 | ((0x77bbccddeeff1122u >> 28) & 0x7f), 0x80 | ((0x77bbccddeeff1122u >> 35) & 0x7f), |
| 0x80 | ((0x77bbccddeeff1122u >> 42) & 0x7f), 0x80 | ((0x77bbccddeeff1122u >> 49) & 0x7f), |
| ((0x77bbccddeeff1122u >> 56) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kNineByte)), |
| Optional(FieldsAre(0x77bbccddeeff1122u, 9u))); |
| |
| constexpr uint8_t kTenByte[] = { |
| 0x80 | (0xffffffffffffffffu & 0x7f), 0x80 | ((0xffffffffffffffffu >> 7) & 0x7f), |
| 0x80 | ((0xffffffffffffffffu >> 14) & 0x7f), 0x80 | ((0xffffffffffffffffu >> 21) & 0x7f), |
| 0x80 | ((0xffffffffffffffffu >> 28) & 0x7f), 0x80 | ((0xffffffffffffffffu >> 35) & 0x7f), |
| 0x80 | ((0xffffffffffffffffu >> 42) & 0x7f), 0x80 | ((0xffffffffffffffffu >> 49) & 0x7f), |
| 0x80 | ((0xffffffffffffffffu >> 56) & 0x7f), ((0xffffffffffffffffu >> 63) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Uleb128::Read(AsBytes(kTenByte)), |
| Optional(FieldsAre(0xffffffffffffffffu, 10u))); |
| |
| constexpr uint8_t kTooManyBytes[17] = {0x80 | 23, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
| 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0}; |
| EXPECT_EQ(elfldltl::dwarf::Uleb128::Read(AsBytes(kTooManyBytes)), std::nullopt); |
| } |
| |
| TEST(ElfldltlDwarfTests, Sleb128) { |
| EXPECT_EQ(elfldltl::dwarf::Sleb128::Read(kNoBytes), std::nullopt); |
| |
| constexpr uint8_t kOneByte{17}; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kOneByte)), Optional(FieldsAre(17, 1u))); |
| |
| constexpr uint8_t kTwoByte[] = {0x80 | (0xaau & 0x7f), 0xaau >> 7}; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kTwoByte)), Optional(FieldsAre(0xaa, 2u))); |
| |
| constexpr uint8_t kThreeByte[] = { |
| 0x80 | (0xaabbu & 0x7f), |
| 0x80 | ((0xaabbu >> 7) & 0x7f), |
| ((0xaabbu >> 14) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kThreeByte)), Optional(FieldsAre(0xaabb, 3u))); |
| |
| constexpr uint8_t kFourByte[] = { |
| 0x80 | (0xaabbcc & 0x7f), |
| 0x80 | ((0xaabbcc >> 7) & 0x7f), |
| 0x80 | ((0xaabbcc >> 14) & 0x7f), |
| ((0xaabbcc >> 21) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kFourByte)), Optional(FieldsAre(0xaabbcc, 4))); |
| |
| constexpr uint8_t kFiveByte[] = { |
| 0x80 | (0xaabbccdd & 0x7f), 0x80 | ((0xaabbccdd >> 7) & 0x7f), |
| 0x80 | ((0xaabbccdd >> 14) & 0x7f), 0x80 | ((0xaabbccdd >> 21) & 0x7f), |
| ((0xaabbccdd >> 28) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kFiveByte)), |
| Optional(FieldsAre(0xaabbccdd, 5u))); |
| |
| constexpr uint8_t kSixByte[] = { |
| 0x80 | (0xaabbccddee & 0x7f), 0x80 | ((0xaabbccddee >> 7) & 0x7f), |
| 0x80 | ((0xaabbccddee >> 14) & 0x7f), 0x80 | ((0xaabbccddee >> 21) & 0x7f), |
| 0x80 | ((0xaabbccddee >> 28) & 0x7f), ((0xaabbccddee >> 35) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kSixByte)), |
| Optional(FieldsAre(0xaabbccddee, 6u))); |
| |
| constexpr uint8_t kSevenByte[] = { |
| 0x80 | (0xaabbccddeeff & 0x7f), 0x80 | ((0xaabbccddeeff >> 7) & 0x7f), |
| 0x80 | ((0xaabbccddeeff >> 14) & 0x7f), 0x80 | ((0xaabbccddeeff >> 21) & 0x7f), |
| 0x80 | ((0xaabbccddeeff >> 28) & 0x7f), 0x80 | ((0xaabbccddeeff >> 35) & 0x7f), |
| ((0xaabbccddeeff >> 42) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kSevenByte)), |
| Optional(FieldsAre(0xaabbccddeeff, 7u))); |
| |
| constexpr uint8_t kEightByte[] = { |
| 0x80 | (0x7abbccddeeff11 & 0x7f), 0x80 | ((0x7abbccddeeff11 >> 7) & 0x7f), |
| 0x80 | ((0x7abbccddeeff11 >> 14) & 0x7f), 0x80 | ((0x7abbccddeeff11 >> 21) & 0x7f), |
| 0x80 | ((0x7abbccddeeff11 >> 28) & 0x7f), 0x80 | ((0x7abbccddeeff11 >> 35) & 0x7f), |
| 0x80 | ((0x7abbccddeeff11 >> 42) & 0x7f), ((0x7abbccddeeff11 >> 49) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kEightByte)), |
| Optional(FieldsAre(0x7abbccddeeff11, 8u))); |
| |
| constexpr uint8_t kNineByte[] = { |
| 0x80 | (0x33bbccddeeff1122 & 0x7f), 0x80 | ((0x33bbccddeeff1122 >> 7) & 0x7f), |
| 0x80 | ((0x33bbccddeeff1122 >> 14) & 0x7f), 0x80 | ((0x33bbccddeeff1122 >> 21) & 0x7f), |
| 0x80 | ((0x33bbccddeeff1122 >> 28) & 0x7f), 0x80 | ((0x33bbccddeeff1122 >> 35) & 0x7f), |
| 0x80 | ((0x33bbccddeeff1122 >> 42) & 0x7f), 0x80 | ((0x33bbccddeeff1122 >> 49) & 0x7f), |
| ((0x33bbccddeeff1122 >> 56) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kNineByte)), |
| Optional(FieldsAre(0x33bbccddeeff1122, 9u))); |
| |
| constexpr uint8_t kOneByteNegative{-17 & 0x7f}; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kOneByteNegative)), |
| Optional(FieldsAre(-17, 1u))); |
| |
| constexpr uint8_t kTwoByteNegative[] = {0x80 | (-0xaa & 0x7f), (-0xaau >> 7) & 0x7f}; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kTwoByteNegative)), |
| Optional(FieldsAre(-0xaa, 2u))); |
| |
| constexpr uint8_t kThreeByteNegative[] = { |
| 0x80 | (-0xaabb & 0x7f), |
| 0x80 | ((-0xaabb >> 7) & 0x7f), |
| ((-0xaabb >> 14) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kThreeByteNegative)), |
| Optional(FieldsAre(-0xaabb, 3u))); |
| |
| constexpr uint8_t kFourByteNegative[] = { |
| 0x80 | (-0xaabbcc & 0x7f), |
| 0x80 | ((-0xaabbcc >> 7) & 0x7f), |
| 0x80 | ((-0xaabbcc >> 14) & 0x7f), |
| ((-0xaabbcc >> 21) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kFourByteNegative)), |
| Optional(FieldsAre(-0xaabbcc, 4))); |
| |
| constexpr uint8_t kFiveByteNegative[] = { |
| 0x80 | (-0xaabbccdd & 0x7f), 0x80 | ((-0xaabbccdd >> 7) & 0x7f), |
| 0x80 | ((-0xaabbccdd >> 14) & 0x7f), 0x80 | ((-0xaabbccdd >> 21) & 0x7f), |
| ((-0xaabbccdd >> 28) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kFiveByteNegative)), |
| Optional(FieldsAre(-0xaabbccdd, 5u))); |
| |
| constexpr uint8_t kSixByteNegative[] = { |
| 0x80 | (-0x33bbccddee & 0x7f), 0x80 | ((-0x33bbccddee >> 7) & 0x7f), |
| 0x80 | ((-0x33bbccddee >> 14) & 0x7f), 0x80 | ((-0x33bbccddee >> 21) & 0x7f), |
| 0x80 | ((-0x33bbccddee >> 28) & 0x7f), ((-0x33bbccddee >> 35) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kSixByteNegative)), |
| Optional(FieldsAre(-0x33bbccddee, 6u))); |
| |
| constexpr uint8_t kSevenByteNegative[] = { |
| 0x80 | (-0x33bbccddeeff & 0x7f), 0x80 | ((-0x33bbccddeeff >> 7) & 0x7f), |
| 0x80 | ((-0x33bbccddeeff >> 14) & 0x7f), 0x80 | ((-0x33bbccddeeff >> 21) & 0x7f), |
| 0x80 | ((-0x33bbccddeeff >> 28) & 0x7f), 0x80 | ((-0x33bbccddeeff >> 35) & 0x7f), |
| ((-0x33bbccddeeff >> 42) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kSevenByteNegative)), |
| Optional(FieldsAre(-0x33bbccddeeff, 7u))); |
| |
| constexpr uint8_t kEightByteNegative[] = { |
| 0x80 | (-0x7abbccddeeff11 & 0x7f), 0x80 | ((-0x7abbccddeeff11 >> 7) & 0x7f), |
| 0x80 | ((-0x7abbccddeeff11 >> 14) & 0x7f), 0x80 | ((-0x7abbccddeeff11 >> 21) & 0x7f), |
| 0x80 | ((-0x7abbccddeeff11 >> 28) & 0x7f), 0x80 | ((-0x7abbccddeeff11 >> 35) & 0x7f), |
| 0x80 | ((-0x7abbccddeeff11 >> 42) & 0x7f), ((-0x7abbccddeeff11 >> 49) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kEightByteNegative)), |
| Optional(FieldsAre(-0x7abbccddeeff11, 8u))); |
| |
| constexpr uint8_t kNineByteNegative[] = { |
| 0x80 | (-0x33bbccddeeff1122 & 0x7f), 0x80 | ((-0x33bbccddeeff1122 >> 7) & 0x7f), |
| 0x80 | ((-0x33bbccddeeff1122 >> 14) & 0x7f), 0x80 | ((-0x33bbccddeeff1122 >> 21) & 0x7f), |
| 0x80 | ((-0x33bbccddeeff1122 >> 28) & 0x7f), 0x80 | ((-0x33bbccddeeff1122 >> 35) & 0x7f), |
| 0x80 | ((-0x33bbccddeeff1122 >> 42) & 0x7f), 0x80 | ((-0x33bbccddeeff1122 >> 49) & 0x7f), |
| ((-0x33bbccddeeff1122 >> 56) & 0x7f), |
| }; |
| EXPECT_THAT(elfldltl::dwarf::Sleb128::Read(AsBytes(kNineByteNegative)), |
| Optional(FieldsAre(-0x33bbccddeeff1122, 9u))); |
| |
| constexpr uint8_t kTooManyBytes[17] = {0x80 | (-23 & 0x7f), |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0x80, |
| 0}; |
| EXPECT_EQ(elfldltl::dwarf::Sleb128::Read(AsBytes(kTooManyBytes)), std::nullopt); |
| } |
| |
| template <typename T> |
| constexpr uint8_t kSize = sizeof(T); |
| |
| TYPED_TEST(ElfldltlDwarfTests, EncodedPtr) { |
| using elfldltl::dwarf::EncodedPtr; |
| using Elf = typename TestFixture::Elf; |
| using Addr = typename Elf::Addr; |
| using Half = typename Elf::Half; |
| using Word = typename Elf::Word; |
| using Xword = typename Elf::Xword; |
| |
| EncodedPtr ptr; |
| EXPECT_EQ(ptr.ptr, 0u); |
| EXPECT_EQ(ptr.encoded_size, 0u); |
| EXPECT_EQ(ptr.encoding, EncodedPtr::kOmit); |
| EXPECT_EQ(EncodedPtr::Type(ptr.encoding), EncodedPtr::kOmit); |
| EXPECT_EQ(EncodedPtr::Modifier(ptr.encoding), EncodedPtr::kAbs); |
| EXPECT_FALSE(EncodedPtr::Signed(ptr.encoding)); |
| EXPECT_FALSE(EncodedPtr::Indirect(ptr.encoding)); |
| |
| EXPECT_EQ(EncodedPtr::Normalize<Elf>(EncodedPtr::kPtr), |
| kSize<Addr> == 4 ? EncodedPtr::kUdata4 : EncodedPtr::kUdata8); |
| |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kOmit, kSize<Addr>), 0u); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kPtr, kSize<Addr>), kSize<Addr>); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kSigned, kSize<Addr>), kSize<Addr>); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kUdata2, kSize<Addr>), 2u); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kUdata4, kSize<Addr>), 4u); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kUdata8, kSize<Addr>), 8u); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kSdata2, kSize<Addr>), 2u); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kSdata4, kSize<Addr>), 4u); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kSdata8, kSize<Addr>), 8u); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kUleb128, kSize<Addr>), EncodedPtr::kDynamicSize); |
| EXPECT_EQ(EncodedPtr::EncodedSize(EncodedPtr::kSleb128, kSize<Addr>), EncodedPtr::kDynamicSize); |
| |
| EXPECT_EQ(EncodedPtr::Read<Elf>(EncodedPtr::kPtr, kNoBytes), std::nullopt); |
| |
| constexpr Addr addr = 0x12345678; |
| EXPECT_THAT( |
| EncodedPtr::Read<Elf>(EncodedPtr::kPtr, AsBytes(addr)), |
| Optional(AllOf(Field(&EncodedPtr::ptr, addr), Field(&EncodedPtr::encoding, EncodedPtr::kPtr), |
| Field(&EncodedPtr::encoded_size, kSize<Addr>)))); |
| |
| constexpr Half half = 0x1234; |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kUdata2, AsBytes(half)), |
| Optional(AllOf(Field(&EncodedPtr::ptr, half), |
| Field(&EncodedPtr::encoding, EncodedPtr::kUdata2), |
| Field(&EncodedPtr::encoded_size, kSize<Half>)))); |
| |
| constexpr Word word = 0x12345678; |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kUdata4, AsBytes(word)), |
| Optional(AllOf(Field(&EncodedPtr::ptr, word), |
| Field(&EncodedPtr::encoding, EncodedPtr::kUdata4), |
| Field(&EncodedPtr::encoded_size, kSize<Word>)))); |
| |
| constexpr Xword xword = 0x12345678abcdef12; |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kUdata8, AsBytes(xword)), |
| Optional(AllOf(Field(&EncodedPtr::ptr, xword), |
| Field(&EncodedPtr::encoding, EncodedPtr::kUdata8), |
| Field(&EncodedPtr::encoded_size, kSize<Xword>)))); |
| |
| constexpr typename Half::Signed shalf = -0x1234; |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kSdata2, AsBytes(shalf)), |
| Optional(AllOf(Field(&EncodedPtr::sptr, shalf), |
| Field(&EncodedPtr::encoding, EncodedPtr::kSdata2), |
| Field(&EncodedPtr::encoded_size, kSize<Half>)))); |
| |
| constexpr typename Word::Signed sword = -0x12345678; |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kSdata4, AsBytes(sword)), |
| Optional(AllOf(Field(&EncodedPtr::sptr, sword), |
| Field(&EncodedPtr::encoding, EncodedPtr::kSdata4), |
| Field(&EncodedPtr::encoded_size, kSize<Word>)))); |
| |
| constexpr typename Xword::Signed sxword = -0x12345678abcdef12; |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kSdata8, AsBytes(sxword)), |
| Optional(AllOf(Field(&EncodedPtr::sptr, sxword), |
| Field(&EncodedPtr::encoding, EncodedPtr::kSdata8), |
| Field(&EncodedPtr::encoded_size, kSize<Xword>)))); |
| |
| constexpr uint8_t kThreeByte[] = { |
| 0x80 | (0xaabbu & 0x7f), |
| 0x80 | ((0xaabbu >> 7) & 0x7f), |
| ((0xaabbu >> 14) & 0x7f), |
| }; |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kUleb128, AsBytes(kThreeByte)), |
| Optional(AllOf(Field(&EncodedPtr::ptr, 0xaabbu), |
| Field(&EncodedPtr::encoding, EncodedPtr::kUleb128), |
| Field(&EncodedPtr::encoded_size, uint8_t{3})))); |
| |
| constexpr uint8_t kThreeByteNegative[] = { |
| 0x80 | (-0xaabb & 0x7f), |
| 0x80 | ((-0xaabb >> 7) & 0x7f), |
| ((-0xaabb >> 14) & 0x7f), |
| }; |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kSleb128, AsBytes(kThreeByte)), |
| Optional(AllOf(Field(&EncodedPtr::ptr, 0xaabbu), |
| Field(&EncodedPtr::encoding, EncodedPtr::kSleb128), |
| Field(&EncodedPtr::encoded_size, uint8_t{3})))); |
| EXPECT_THAT(EncodedPtr::Read<Elf>(EncodedPtr::kSleb128, AsBytes(kThreeByteNegative)), |
| Optional(AllOf(Field(&EncodedPtr::ptr, -0xaabb), |
| Field(&EncodedPtr::encoding, EncodedPtr::kSleb128), |
| Field(&EncodedPtr::encoded_size, uint8_t{3})))); |
| } |
| |
| TYPED_TEST(ElfldltlDwarfTests, EncodedPtrFromMemory) { |
| using elfldltl::dwarf::EncodedPtr; |
| using Elf = typename TestFixture::Elf; |
| using Addr = typename Elf::Addr; |
| using size_type = typename Elf::size_type; |
| |
| static constexpr size_type kMemoryBase = 0x12345000; |
| static constexpr size_type kEncodedAt = 0x12345ea0; |
| static constexpr size_type kIndirectEncodedAt = 0x12345bb0; |
| static constexpr size_type kRelIndirectEncodedAt = 0x12345bc0; |
| static constexpr size_type kBadIndirectEncodedAt = 0x12345bd0; |
| static constexpr size_type kIndirectedTo = 0x12345120; |
| static constexpr size_type kDirectValue = 0xabcdef12; |
| static constexpr Addr kIndirectValue = 0x1234abcd; |
| static constexpr auto kData = []() { |
| std::array<Addr, 0x1000 / sizeof(Addr)> words{}; |
| for (Addr& word : words) { |
| word = 0xdeadbeef; |
| } |
| auto set = [&words](size_type addr, Addr value) { |
| words[(addr - kMemoryBase) / sizeof(Addr)] = value; |
| }; |
| set(kEncodedAt, kDirectValue); |
| set(kIndirectEncodedAt, kIndirectedTo); |
| set(kRelIndirectEncodedAt, kIndirectedTo - kRelIndirectEncodedAt); |
| set(kBadIndirectEncodedAt, 0xbad1230 - kBadIndirectEncodedAt); |
| set(kIndirectedTo, kIndirectValue); |
| return words; |
| }(); |
| const cpp20::span<std::byte> kImage{ |
| const_cast<std::byte*>(cpp20::as_bytes(cpp20::span{kData}).data()), |
| cpp20::span(kData).size_bytes(), |
| }; |
| |
| elfldltl::DirectMemory memory{kImage, kMemoryBase}; |
| |
| EXPECT_EQ(EncodedPtr::FromMemory<Elf>(EncodedPtr::kPtr, memory, 0xbad10000, kSize<Addr>), |
| std::nullopt); |
| |
| EXPECT_THAT(EncodedPtr::FromMemory<Elf>(EncodedPtr::kPtr, memory, kEncodedAt, kSize<Addr>), |
| Optional(kDirectValue)); |
| |
| EXPECT_THAT( |
| EncodedPtr::FromMemory<Elf>(static_cast<uint8_t>(EncodedPtr::kPtr) | EncodedPtr::kPcrel, |
| memory, kEncodedAt, kSize<Addr>), |
| Optional(kEncodedAt + kDirectValue)); |
| |
| EXPECT_THAT(EncodedPtr::FromMemory<Elf>(EncodedPtr::kPtr | EncodedPtr::kIndirect, memory, |
| kIndirectEncodedAt, kSize<Addr>), |
| Optional(kIndirectValue)); |
| |
| EXPECT_THAT( |
| EncodedPtr::FromMemory<Elf>(EncodedPtr::kPtr | EncodedPtr::kIndirect | EncodedPtr::kPcrel, |
| memory, kRelIndirectEncodedAt, kSize<Addr>), |
| Optional(kIndirectValue)); |
| |
| EXPECT_EQ(EncodedPtr::FromMemory<Elf>(EncodedPtr::kPtr | EncodedPtr::kIndirect, memory, |
| kBadIndirectEncodedAt, kSize<Addr>), |
| std::nullopt); |
| } |
| |
| TYPED_TEST(ElfldltlDwarfTests, EhFrameHdr) { |
| using Elf = typename TestFixture::Elf; |
| using size_type = typename Elf::size_type; |
| using Word = typename Elf::Word; |
| using Phdr = typename Elf::Phdr; |
| using value_type = elfldltl::dwarf::EhFrameHdrEntry<size_type>; |
| |
| elfldltl::dwarf::EhFrameHdr<Elf> eh_frame_hdr; |
| EXPECT_TRUE(eh_frame_hdr.empty()); |
| |
| auto diag = elfldltl::testing::ExpectOkDiagnostics(); |
| |
| constexpr std::array kEntries{ |
| value_type{0x1000, 0x370}, |
| value_type{0x1005, 0x3f0}, |
| value_type{0x1011, 0x46c}, |
| }; |
| |
| std::stringstream os; |
| for (const value_type& entry : kEntries) { |
| os << entry << "\n"; |
| } |
| EXPECT_EQ(os.str(), R"""([PC 0x1000 -> FDE 0x370] |
| [PC 0x1005 -> FDE 0x3f0] |
| [PC 0x1011 -> FDE 0x46c] |
| )"""); |
| |
| constexpr size_type kVaddr = 0x334; |
| constexpr size_type kEhFrameVaddr = 0x358; |
| static constexpr std::array<Word, 9> kData = { |
| Word{std::array{ |
| std::byte{0x01}, // version 1 |
| std::byte{0x1b}, // eh_frame_ptr sdata pcrel |
| std::byte{0x03}, // fde_count udata4 |
| std::byte{0x3b}, // fde_table sdata4 datarel |
| }}, |
| 0x20, // eh_frame_ptr |
| 3, // FDE count |
| 0xccc, |
| 0x3c, |
| 0xcd1, |
| 0xbc, |
| 0xcdd, |
| 0x138, |
| }; |
| const cpp20::span<std::byte> kImage{ |
| const_cast<std::byte*>(cpp20::as_bytes(cpp20::span{kData}).data()), |
| cpp20::span(kData).size_bytes(), |
| }; |
| |
| elfldltl::DirectMemory memory{kImage, kVaddr}; |
| |
| constexpr Phdr kPhdr = { |
| .type = elfldltl::ElfPhdrType::kEhFrameHdr, |
| .vaddr = kVaddr, |
| .filesz = sizeof(kData), |
| }; |
| |
| ASSERT_TRUE(eh_frame_hdr.Init(diag, memory, kPhdr)); |
| |
| EXPECT_EQ(eh_frame_hdr.eh_frame_ptr(), kEhFrameVaddr); |
| |
| EXPECT_EQ(eh_frame_hdr.size(), 3u); |
| |
| EXPECT_THAT(eh_frame_hdr, ElementsAreArray(kEntries)); |
| } |
| |
| constexpr uint32_t kFdeVaddr = 0x370; |
| |
| template <class Elf> |
| struct [[gnu::packed]] TestEhFrame { |
| using Addr = typename Elf::Addr; |
| using Word = typename Elf::Word; |
| |
| struct TestCie { |
| [[gnu::packed]] Word cie_id = elfldltl::dwarf::kEhFrameCieId; |
| uint8_t version = 1; |
| char augmentation[4] = "zLR"; |
| uint8_t code_alignment_factor = 1; |
| uint8_t data_alignment_factor = -8 & 0x7f; |
| uint8_t return_address_register = 16; |
| uint8_t augmentation_data[3] = {2, 0, 0x1b}; |
| uint8_t instructions[5] = {0x0c, 0x07, 0x08, 0x90, 0x01}; |
| }; |
| using CieData = TestData<InitialLength32<Elf>, TestCie>; |
| |
| struct TestFde { |
| [[gnu::packed]] Word cie_pointer = sizeof(CieData) + sizeof(Word); |
| [[gnu::packed]] Word initial_location = // sdata4 | pcrel encoded: |
| 0x1000 - // Absolute address. |
| (kFdeVaddr + // FDE start address. |
| sizeof(Word) + // Initial length |
| sizeof(Word)); // CIE_pointer |
| [[gnu::packed]] Word address_range = 5; |
| uint8_t augmentation_data_size = sizeof(Addr); |
| [[gnu::packed]] Addr lsda = 0x534c55; |
| uint8_t instructions[3] = {0x08, 0x00, 0}; |
| }; |
| using FdeData = TestData<InitialLength32<Elf>, TestFde>; |
| |
| [[gnu::packed]] CieData cie; |
| [[gnu::packed]] FdeData fde; |
| }; |
| |
| template <class Elf> |
| constexpr TestEhFrame<Elf> kTestEhFrame{}; |
| |
| TYPED_TEST(ElfldltlDwarfTests, CfiEntry) { |
| using Elf = typename TestFixture::Elf; |
| |
| auto diag = elfldltl::testing::ExpectOkDiagnostics(); |
| |
| cpp20::span kData = AsBytes(kTestEhFrame<Elf>); |
| const cpp20::span<std::byte> kImage{ |
| const_cast<std::byte*>(kData.data()), |
| cpp20::span(kData).size_bytes(), |
| }; |
| elfldltl::DirectMemory memory{kImage, 0x358}; |
| |
| auto fde = elfldltl::dwarf::CfiEntry::ReadEhFrameFromMemory<Elf>(diag, memory, kFdeVaddr); |
| ASSERT_TRUE(fde); |
| |
| auto cie = fde->template ReadEhFrameCieFromMemory<Elf>(diag, memory); |
| ASSERT_TRUE(cie); |
| |
| auto cie_info = cie->template DecodeCie<Elf>(diag, *fde->cie_pointer()); |
| ASSERT_TRUE(cie_info); |
| |
| EXPECT_EQ(cie_info->return_address_register, 16u); |
| EXPECT_EQ(cie_info->initial_instructions.size_bytes(), 5u); |
| EXPECT_FALSE(cie_info->signal_frame); |
| |
| auto fde_info = fde->template DecodeFde<Elf>(diag, kFdeVaddr, *cie_info); |
| ASSERT_TRUE(fde_info); |
| |
| EXPECT_EQ(fde_info->initial_location, 0x1000u); |
| EXPECT_EQ(fde_info->address_range, 5u); |
| EXPECT_EQ(fde_info->lsda, 0x534c55u); |
| EXPECT_EQ(fde_info->instructions.size_bytes(), 3u); |
| } |
| |
| } // namespace |