blob: ca767bcfb50f5d6982234707980ec0cba48c3a62 [file] [log] [blame]
// Copyright 2021 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/diagnostics.h>
#include <lib/elfldltl/layout.h>
#include <lib/elfldltl/machine.h>
#include <lib/elfldltl/testing/diagnostics.h>
#include <lib/elfldltl/testing/typed-test.h>
#include <lib/elfldltl/tls-layout.h>
#include <tuple>
#include <type_traits>
#include <gtest/gtest.h>
namespace {
using elfldltl::testing::ExpectedSingleError;
using elfldltl::testing::ExpectOkDiagnostics;
using Elf32Little = elfldltl::Elf32<elfldltl::ElfData::k2Lsb>;
using Elf64Little = elfldltl::Elf64<elfldltl::ElfData::k2Lsb>;
using Elf32Big = elfldltl::Elf32<elfldltl::ElfData::k2Msb>;
using Elf64Big = elfldltl::Elf64<elfldltl::ElfData::k2Msb>;
TEST(ElfldltlLayoutTests, Magic) {
constexpr std::array<uint8_t, 4> kMagic = {0x7f, 'E', 'L', 'F'};
EXPECT_EQ(memcmp(&(*kMagic.begin()), &Elf32Little::Ehdr::kMagic, 4), 0);
EXPECT_EQ(memcmp(&(*kMagic.begin()), &Elf64Little::Ehdr::kMagic, 4), 0);
EXPECT_EQ(memcmp(&(*kMagic.begin()), &Elf32Big::Ehdr::kMagic, 4), 0);
EXPECT_EQ(memcmp(&(*kMagic.begin()), &Elf64Big::Ehdr::kMagic, 4), 0);
}
TEST(ElfldltlLayoutTests, Sizes) {
static_assert(sizeof(elfldltl::Elf32<>::Ehdr) == 52);
static_assert(alignof(elfldltl::Elf32<>::Ehdr) <= 4);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf32<>::Ehdr>);
static_assert(sizeof(elfldltl::Elf64<>::Ehdr) == 64);
static_assert(alignof(elfldltl::Elf64<>::Ehdr) <= 8);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf64<>::Ehdr>);
static_assert(sizeof(elfldltl::Elf32<>::Phdr) == 32);
static_assert(alignof(elfldltl::Elf32<>::Phdr) <= 4);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf32<>::Phdr>);
static_assert(sizeof(elfldltl::Elf64<>::Phdr) == 56);
static_assert(alignof(elfldltl::Elf64<>::Phdr) <= 8);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf64<>::Phdr>);
static_assert(sizeof(elfldltl::Elf32<>::Shdr) == 40);
static_assert(alignof(elfldltl::Elf32<>::Shdr) <= 4);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf32<>::Shdr>);
static_assert(sizeof(elfldltl::Elf64<>::Shdr) == 64);
static_assert(alignof(elfldltl::Elf64<>::Shdr) <= 8);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf64<>::Shdr>);
static_assert(sizeof(elfldltl::Elf32<>::Dyn) == 8);
static_assert(alignof(elfldltl::Elf32<>::Dyn) <= 4);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf32<>::Dyn>);
static_assert(sizeof(elfldltl::Elf64<>::Dyn) == 16);
static_assert(alignof(elfldltl::Elf64<>::Dyn) <= 8);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf64<>::Dyn>);
static_assert(sizeof(elfldltl::Elf32<>::Sym) == 16);
static_assert(alignof(elfldltl::Elf32<>::Sym) <= 4);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf32<>::Sym>);
static_assert(sizeof(elfldltl::Elf64<>::Sym) == 24);
static_assert(alignof(elfldltl::Elf64<>::Sym) <= 8);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf64<>::Sym>);
static_assert(sizeof(elfldltl::Elf32<>::Rel) == 8);
static_assert(alignof(elfldltl::Elf32<>::Rel) <= 4);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf32<>::Rel>);
static_assert(sizeof(elfldltl::Elf64<>::Rel) == 16);
static_assert(alignof(elfldltl::Elf64<>::Rel) <= 8);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf64<>::Rel>);
static_assert(sizeof(elfldltl::Elf32<>::Rela) == 12);
static_assert(alignof(elfldltl::Elf32<>::Rela) <= 4);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf32<>::Rela>);
static_assert(sizeof(elfldltl::Elf64<>::Rela) == 24);
static_assert(alignof(elfldltl::Elf64<>::Rela) <= 8);
static_assert(std::has_unique_object_representations_v<elfldltl::Elf64<>::Rela>);
}
// Just instantiating this tests the constexpr Elf::Ehdr methods.
template <class Elf, auto Machine>
struct EhdrTests {
static_assert(Elf::template kIsLayout<typename Elf::Addr>);
static_assert(elfldltl::kIsLayout<typename Elf::Addr>);
static_assert(Elf::template kIsLayout<typename Elf::Word>);
static_assert(elfldltl::kIsLayout<typename Elf::Word>);
static_assert(Elf::template kIsLayout<typename Elf::Half>);
static_assert(elfldltl::kIsLayout<typename Elf::Half>);
static_assert(Elf::template kIsLayout<typename Elf::Ehdr>);
static_assert(elfldltl::kIsLayout<typename Elf::Ehdr>);
static_assert(Elf::template kIsLayout<typename Elf::Phdr>);
static_assert(elfldltl::kIsLayout<typename Elf::Phdr>);
static_assert(Elf::template kIsLayout<typename Elf::Shdr>);
static_assert(elfldltl::kIsLayout<typename Elf::Shdr>);
static_assert(Elf::template kIsLayout<typename Elf::Sym>);
static_assert(elfldltl::kIsLayout<typename Elf::Sym>);
static_assert(Elf::template kIsLayout<typename Elf::Addend>);
static_assert(elfldltl::kIsLayout<typename Elf::Addend>);
static_assert(Elf::template kIsLayout<typename Elf::Nhdr>);
static_assert(elfldltl::kIsLayout<typename Elf::Nhdr>);
static_assert(Elf::template kIsLayout<elfldltl::TlsLayout<Elf>>);
static_assert(elfldltl::kIsLayout<elfldltl::TlsLayout<Elf>>);
static_assert(!Elf::template kIsLayout<uint32_t>);
static_assert(!elfldltl::kIsLayout<uint32_t>);
static_assert(!Elf::template kIsLayout<uint64_t>);
static_assert(!elfldltl::kIsLayout<uint64_t>);
static constexpr typename Elf::Ehdr kGood = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kGood),
};
static_assert(kGood.Valid());
static constexpr typename Elf::Ehdr kBadMagic = {
.magic = 0xabcdef,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kBadMagic),
};
static_assert(!kBadMagic.Valid());
static void BadMagicDiagnostic() {
ExpectedSingleError expected{"not an ELF file"};
EXPECT_FALSE(kBadMagic.Valid(expected));
}
static constexpr typename Elf::Ehdr kBadIdentVersion = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kBadIdentVersion),
};
static_assert(!kBadIdentVersion.Valid());
static void BadIdentVersionDiagnostic() {
ExpectedSingleError expected{"wrong EI_VERSION value"};
EXPECT_FALSE(kBadIdentVersion.Valid(expected));
}
static constexpr typename Elf::Ehdr kBadVersion = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.machine = Machine,
.ehsize = sizeof(kBadVersion),
};
static_assert(!kBadVersion.Valid());
static void BadVersionDiagnostic() {
ExpectedSingleError expected{"wrong e_version value"};
EXPECT_FALSE(kBadVersion.Valid(expected));
}
static constexpr typename Elf::Ehdr kBadSize = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = 17,
};
static_assert(!kBadSize.Valid());
static void BadSizeDiagnostic() {
ExpectedSingleError expected{"wrong e_ehsize value"};
EXPECT_FALSE(kBadSize.Valid(expected));
}
static constexpr typename Elf::Ehdr kBadClass = {
.magic = Elf::Ehdr::kMagic,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kBadClass),
};
static_assert(!kBadClass.Valid());
static void BadClassDiagnostic() {
ExpectedSingleError expected{"wrong ELF class (bit-width)"};
EXPECT_FALSE(kBadClass.Valid(expected));
}
static constexpr auto kNotMyClass = Elf::kClass == elfldltl::ElfClass::k64 //
? elfldltl::ElfClass::k32
: elfldltl::ElfClass::k64;
static constexpr typename Elf::Ehdr kWrongClass = {
.magic = Elf::Ehdr::kMagic,
.elfclass = kNotMyClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kWrongClass),
};
static_assert(!kWrongClass.Valid());
static void WrongClassDiagnostic() {
ExpectedSingleError expected{"wrong ELF class (bit-width)"};
EXPECT_FALSE(kWrongClass.Valid(expected));
}
static constexpr typename Elf::Ehdr kBadData = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.ident_version = elfldltl::ElfVersion::kCurrent,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kBadData),
};
static_assert(!kBadData.Valid());
static void BadDataDiagnostic() {
ExpectedSingleError expected{"wrong byte order"};
EXPECT_FALSE(kBadData.Valid(expected));
}
static constexpr auto kNotMyData = Elf::kData == elfldltl::ElfData::k2Lsb //
? elfldltl::ElfData::k2Msb
: elfldltl::ElfData::k2Lsb;
static constexpr typename Elf::Ehdr kWrongData = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = kNotMyData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kWrongData),
};
static_assert(!kWrongData.Valid());
static void WrongDataDiagnostic() {
ExpectedSingleError expected{"wrong byte order"};
EXPECT_FALSE(kWrongData.Valid(expected));
}
static constexpr typename Elf::Ehdr kExec = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.type = elfldltl::ElfType::kExec,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kExec),
};
static_assert(kExec.Valid());
static_assert(!kExec.Loadable(Machine));
static void ExecDiagnostic() {
ExpectOkDiagnostics expected_valid;
EXPECT_TRUE(kExec.Valid(expected_valid));
ExpectedSingleError expected_loadable{
"loading ET_EXEC files is not supported, only ET_DYN files;"
" be sure to compile and link as PIE (-fPIE, -pie)"};
EXPECT_FALSE(kExec.Loadable(expected_loadable, Machine));
}
static constexpr typename Elf::Ehdr kDyn = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.type = elfldltl::ElfType::kDyn,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kDyn),
};
static_assert(kDyn.Valid());
static_assert(kDyn.Loadable(Machine));
static void DynDiagnostic() {
ExpectOkDiagnostics expected;
EXPECT_TRUE(kDyn.Valid(expected));
EXPECT_TRUE(kDyn.Loadable(expected, Machine));
}
static constexpr typename Elf::Ehdr kCore = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.type = elfldltl::ElfType::kCore,
.machine = Machine,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kCore),
};
static_assert(kCore.Valid());
static_assert(!kCore.Loadable(Machine));
static void CoreDiagnostic() {
ExpectOkDiagnostics expected_valid;
EXPECT_TRUE(kCore.Valid(expected_valid));
ExpectedSingleError expected_loadable{"ET_CORE files cannot be loaded"};
EXPECT_FALSE(kCore.Loadable(expected_loadable, Machine));
}
static constexpr typename Elf::Ehdr kWrongMachine = {
.magic = Elf::Ehdr::kMagic,
.elfclass = Elf::kClass,
.elfdata = Elf::kData,
.ident_version = elfldltl::ElfVersion::kCurrent,
.type = elfldltl::ElfType::kDyn,
.machine = elfldltl::ElfMachine::kNone,
.version = elfldltl::ElfVersion::kCurrent,
.ehsize = sizeof(kDyn),
};
static_assert(kWrongMachine.Valid());
static_assert(!kWrongMachine.Loadable(Machine));
static void WrongMachineDiagnostic() {
ExpectOkDiagnostics expected_valid;
EXPECT_TRUE(kWrongMachine.Valid(expected_valid));
ExpectedSingleError expected_loadable{"wrong e_machine for architecture"};
EXPECT_FALSE(kWrongMachine.Loadable(expected_loadable, Machine));
}
static void DiagnosticsTests() {
ASSERT_NO_FATAL_FAILURE(BadMagicDiagnostic());
ASSERT_NO_FATAL_FAILURE(BadIdentVersionDiagnostic());
ASSERT_NO_FATAL_FAILURE(BadVersionDiagnostic());
ASSERT_NO_FATAL_FAILURE(BadSizeDiagnostic());
ASSERT_NO_FATAL_FAILURE(BadClassDiagnostic());
ASSERT_NO_FATAL_FAILURE(WrongClassDiagnostic());
ASSERT_NO_FATAL_FAILURE(BadDataDiagnostic());
ASSERT_NO_FATAL_FAILURE(WrongDataDiagnostic());
ASSERT_NO_FATAL_FAILURE(ExecDiagnostic());
ASSERT_NO_FATAL_FAILURE(DynDiagnostic());
ASSERT_NO_FATAL_FAILURE(CoreDiagnostic());
ASSERT_NO_FATAL_FAILURE(WrongMachineDiagnostic());
}
};
template <class Elf>
struct AllMachinesEhdrTests {
template <elfldltl::ElfMachine... Machine>
using Tests = std::tuple<EhdrTests<Elf, Machine>...>;
static constexpr elfldltl::AllSupportedMachines<Tests> kTests;
};
template <class... Elf>
using AllFormatsEhdrTests = std::tuple<AllMachinesEhdrTests<Elf>...>;
// This instantiates all the types to do their static_assert checks.
[[maybe_unused]] elfldltl::AllFormats<AllFormatsEhdrTests> kEhdrTests;
FORMAT_TYPED_TEST_SUITE(ElfldltlLayoutTests);
TYPED_TEST(ElfldltlLayoutTests, DiagnosticsTests) {
std::apply([](auto... test) { (decltype(test)::DiagnosticsTests(), ...); },
AllMachinesEhdrTests<typename TestFixture::Elf>::kTests);
}
TYPED_TEST(ElfldltlLayoutTests, DesignatedInitializers) {
using Elf = typename TestFixture::Elf;
[[maybe_unused]] constexpr typename Elf::Ehdr ehdr{.magic = 0};
[[maybe_unused]] constexpr typename Elf::Nhdr nhdr{.namesz = 0};
[[maybe_unused]] constexpr typename Elf::Phdr phdr{.offset = 0};
[[maybe_unused]] constexpr typename Elf::Shdr shdr{.name = 0};
[[maybe_unused]] constexpr typename Elf::Dyn dyn{.val = 0};
[[maybe_unused]] constexpr typename Elf::Sym sym{.name = 0};
[[maybe_unused]] constexpr typename Elf::Rel rel{.offset = 0};
[[maybe_unused]] constexpr typename Elf::Rela rela{.offset = 0};
}
} // namespace