ELFObjectFileTest.cpp 4.65 KB
//===- ELFObjectFileTest.cpp - Tests for ELFObjectFile --------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace llvm::object;

template <class ELFT>
static Expected<ELFObjectFile<ELFT>> create(ArrayRef<uint8_t> Data) {
  return ELFObjectFile<ELFT>::create(
      MemoryBufferRef(toStringRef(Data), "Test buffer"));
}

// A class to initialize a buffer to represent an ELF object file.
struct DataForTest {
  std::vector<uint8_t> Data;

  template <typename T>
  std::vector<uint8_t> makeElfData(uint8_t Class, uint8_t Encoding,
                                   uint16_t Machine) {
    T Ehdr{}; // Zero-initialise the header.
    Ehdr.e_ident[ELF::EI_MAG0] = 0x7f;
    Ehdr.e_ident[ELF::EI_MAG1] = 'E';
    Ehdr.e_ident[ELF::EI_MAG2] = 'L';
    Ehdr.e_ident[ELF::EI_MAG3] = 'F';
    Ehdr.e_ident[ELF::EI_CLASS] = Class;
    Ehdr.e_ident[ELF::EI_DATA] = Encoding;
    Ehdr.e_ident[ELF::EI_VERSION] = 1;
    Ehdr.e_type = ELF::ET_REL;
    Ehdr.e_machine = Machine;
    Ehdr.e_version = 1;
    Ehdr.e_ehsize = sizeof(T);

    bool IsLittleEndian = Encoding == ELF::ELFDATA2LSB;
    if (sys::IsLittleEndianHost != IsLittleEndian) {
      sys::swapByteOrder(Ehdr.e_type);
      sys::swapByteOrder(Ehdr.e_machine);
      sys::swapByteOrder(Ehdr.e_version);
      sys::swapByteOrder(Ehdr.e_ehsize);
    }

    uint8_t *EhdrBytes = reinterpret_cast<uint8_t *>(&Ehdr);
    std::vector<uint8_t> Bytes;
    std::copy(EhdrBytes, EhdrBytes + sizeof(Ehdr), std::back_inserter(Bytes));
    return Bytes;
  }

  DataForTest(uint8_t Class, uint8_t Encoding, uint16_t Machine) {
    if (Class == ELF::ELFCLASS64)
      Data = makeElfData<ELF::Elf64_Ehdr>(Class, Encoding, Machine);
    else {
      assert(Class == ELF::ELFCLASS32);
      Data = makeElfData<ELF::Elf64_Ehdr>(Class, Encoding, Machine);
    }
  }
};

TEST(ELFObjectFileTest, MachineTestForVE) {
  DataForTest Data(ELF::ELFCLASS64, ELF::ELFDATA2LSB, ELF::EM_VE);
  auto ExpectedFile = create<ELF64LE>(Data.Data);
  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  const ELFObjectFile<ELF64LE> &File = *ExpectedFile;
  EXPECT_EQ("elf64-ve", File.getFileFormatName());
  EXPECT_EQ(Triple::ve, File.getArch());
}

TEST(ELFObjectFileTest, MachineTestForX86_64) {
  DataForTest Data(ELF::ELFCLASS64, ELF::ELFDATA2LSB, ELF::EM_X86_64);
  auto ExpectedFile = create<ELF64LE>(Data.Data);
  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  const ELFObjectFile<ELF64LE> &File = *ExpectedFile;
  EXPECT_EQ("elf64-x86-64", File.getFileFormatName());
  EXPECT_EQ(Triple::x86_64, File.getArch());
}

TEST(ELFObjectFileTest, MachineTestFor386) {
  DataForTest Data(ELF::ELFCLASS32, ELF::ELFDATA2LSB, ELF::EM_386);
  auto ExpectedFile = create<ELF32LE>(Data.Data);
  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
  const ELFObjectFile<ELF32LE> &File = *ExpectedFile;
  EXPECT_EQ("elf32-i386", File.getFileFormatName());
  EXPECT_EQ(Triple::x86, File.getArch());
}

TEST(ELFObjectFileTest, MachineTestForMIPS) {
  {
    DataForTest Data(ELF::ELFCLASS64, ELF::ELFDATA2LSB, ELF::EM_MIPS);
    auto ExpectedFile = create<ELF64LE>(Data.Data);
    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
    const ELFObjectFile<ELF64LE> &File = *ExpectedFile;
    EXPECT_EQ("elf64-mips", File.getFileFormatName());
    EXPECT_EQ(Triple::mips64el, File.getArch());
  }
  {
    DataForTest Data(ELF::ELFCLASS64, ELF::ELFDATA2MSB, ELF::EM_MIPS);
    auto ExpectedFile = create<ELF64BE>(Data.Data);
    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
    const ELFObjectFile<ELF64BE> &File = *ExpectedFile;
    EXPECT_EQ("elf64-mips", File.getFileFormatName());
    EXPECT_EQ(Triple::mips64, File.getArch());
  }
  {
    DataForTest Data(ELF::ELFCLASS32, ELF::ELFDATA2LSB, ELF::EM_MIPS);
    auto ExpectedFile = create<ELF32LE>(Data.Data);
    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
    const ELFObjectFile<ELF32LE> &File = *ExpectedFile;
    EXPECT_EQ("elf32-mips", File.getFileFormatName());
    EXPECT_EQ(Triple::mipsel, File.getArch());
  }
  {
    DataForTest Data(ELF::ELFCLASS32, ELF::ELFDATA2MSB, ELF::EM_MIPS);
    auto ExpectedFile = create<ELF32BE>(Data.Data);
    ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
    const ELFObjectFile<ELF32BE> &File = *ExpectedFile;
    EXPECT_EQ("elf32-mips", File.getFileFormatName());
    EXPECT_EQ(Triple::mips, File.getArch());
  }
}