blob: 6b4631e3b8519c0876d3d446241e55d5483f3615 [file] [log] [blame]
// Copyright 2018 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 "garnet/lib/elflib/elflib.h"
#include <algorithm>
#include <iterator>
#include "gtest/gtest.h"
namespace elflib {
namespace {
constexpr uint64_t kAddrPoison = 0xdeadb33ff00db4b3;
constexpr uint64_t kSymbolPoison = 0xb0bab0ba;
constexpr uint64_t kNoteGnuBuildId = 3;
constexpr uint64_t kMeaninglessNoteType = 42;
class TestMemoryAccessor : public ElfLib::MemoryAccessor {
public:
TestMemoryAccessor() {
PushData(Elf64_Ehdr{
.e_ident = {EI_MAG0, EI_MAG1, EI_MAG2, EI_MAG3},
.e_version = 1,
.e_shoff = sizeof(Elf64_Ehdr),
.e_ehsize = sizeof(Elf64_Ehdr),
.e_shentsize = sizeof(Elf64_Shdr),
.e_phentsize = sizeof(Elf64_Phdr),
.e_shnum = 4,
.e_phnum = 2,
.e_shstrndx = 0,
});
size_t shstrtab_hdr = PushData(Elf64_Shdr{
.sh_name = 1,
.sh_type = SHT_STRTAB,
.sh_size = 34,
.sh_addr = kAddrPoison,
});
size_t stuff_hdr = PushData(Elf64_Shdr{
.sh_name = 2,
.sh_type = SHT_LOUSER,
.sh_size = 15,
.sh_addr = kAddrPoison,
});
size_t strtab_hdr = PushData(Elf64_Shdr{
.sh_name = 3,
.sh_type = SHT_STRTAB,
.sh_size = 16,
.sh_addr = kAddrPoison,
});
size_t symtab_hdr = PushData(Elf64_Shdr{
.sh_name = 4,
.sh_type = SHT_SYMTAB,
.sh_size = sizeof(Elf64_Sym),
.sh_addr = kAddrPoison,
});
size_t phnote_hdr = PushData(Elf64_Phdr{
.p_type = PT_NOTE,
.p_vaddr = kAddrPoison,
});
DataAt<Elf64_Ehdr>(0)->e_phoff = phnote_hdr;
DataAt<Elf64_Shdr>(shstrtab_hdr)->sh_offset =
PushData("\0.shstrtab\0.stuff\0.strtab\0.symtab\0", 34);
DataAt<Elf64_Shdr>(stuff_hdr)->sh_offset = PushData("This is a test.", 15);
DataAt<Elf64_Shdr>(strtab_hdr)->sh_offset =
PushData("\0zx_frob_handle\0", 16);
DataAt<Elf64_Shdr>(symtab_hdr)->sh_offset = PushData(Elf64_Sym{
.st_name = 1,
.st_shndx = SHN_COMMON,
.st_value = kSymbolPoison,
.st_size = 0,
});
size_t buildid_nhdr = PushData(
Elf64_Nhdr{.n_namesz = 4, .n_descsz = 32, .n_type = kNoteGnuBuildId});
DataAt<Elf64_Phdr>(phnote_hdr)->p_offset = buildid_nhdr;
PushData("GNU\0", 4);
uint8_t desc_data[32] = {
0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
};
PushData(desc_data, 32);
PushData(Elf64_Nhdr{
.n_namesz = 6,
.n_descsz = 3,
.n_type = kMeaninglessNoteType,
});
PushData("seven\0\0\0", 8);
PushData("foo\0", 4);
DataAt<Elf64_Phdr>(phnote_hdr)->p_filesz = Pos() - buildid_nhdr;
DataAt<Elf64_Phdr>(phnote_hdr)->p_memsz = Pos() - buildid_nhdr;
}
template <typename T>
T* DataAt(size_t offset) {
return reinterpret_cast<T*>(content_.data() + offset);
}
template <typename T>
size_t PushData(T data) {
return PushData(reinterpret_cast<uint8_t*>(&data), sizeof(data));
}
size_t PushData(const char* bytes, size_t size) {
return PushData(reinterpret_cast<const uint8_t*>(bytes), size);
}
size_t PushData(const uint8_t* bytes, size_t size) {
size_t offset = Pos();
std::copy(bytes, bytes + size, std::back_inserter(content_));
return offset;
}
size_t Pos() { return content_.size(); }
std::optional<std::vector<uint8_t>> GetMemory(uint64_t offset, size_t size) {
const auto& start_iter = content_.begin() + offset;
std::vector<uint8_t> out;
out.clear();
out.resize(size);
if (content_.size() < offset + out.size()) {
return std::nullopt;
}
std::copy(start_iter, start_iter + out.size(), out.begin());
return out;
}
std::optional<std::vector<uint8_t>> GetMappedMemory(uint64_t offset,
uint64_t address,
size_t size,
size_t map_size) {
if (address != kAddrPoison) {
return std::nullopt;
}
return GetMemory(offset, size);
}
private:
std::vector<uint8_t> content_;
};
} // namespace
TEST(ElfLib, Create) {
std::unique_ptr<ElfLib> got;
EXPECT_NE(ElfLib::Create(std::make_unique<TestMemoryAccessor>()).get(),
nullptr);
}
TEST(ElfLib, GetSection) {
std::unique_ptr<ElfLib> elf =
ElfLib::Create(std::make_unique<TestMemoryAccessor>());
ASSERT_NE(elf.get(), nullptr);
auto data = elf->GetSectionData(".stuff");
const uint8_t* expected_content =
reinterpret_cast<const uint8_t*>("This is a test.");
auto test = std::vector<uint8_t>(expected_content, expected_content + 15);
ASSERT_NE(data, nullptr);
EXPECT_EQ(test, *data);
}
TEST(ElfLib, GetSymbolValue) {
std::unique_ptr<ElfLib> elf =
ElfLib::Create(std::make_unique<TestMemoryAccessor>());
ASSERT_NE(elf.get(), nullptr);
auto data = elf->GetSymbolValue("zx_frob_handle");
ASSERT_TRUE(data);
EXPECT_EQ(kSymbolPoison, *data);
}
TEST(ElfLib, GetAllSymbols) {
std::unique_ptr<ElfLib> elf =
ElfLib::Create(std::make_unique<TestMemoryAccessor>());
ASSERT_NE(elf.get(), nullptr);
auto syms = elf->GetAllSymbols();
ASSERT_TRUE(syms);
EXPECT_EQ(1U, syms->size());
Elf64_Sym sym = (*syms)["zx_frob_handle"];
EXPECT_EQ(1U, sym.st_name);
EXPECT_EQ(0U, sym.st_size);
EXPECT_EQ(SHN_COMMON, sym.st_shndx);
EXPECT_EQ(kSymbolPoison, sym.st_value);
}
TEST(ElfLib, GetNote) {
std::unique_ptr<ElfLib> elf =
ElfLib::Create(std::make_unique<TestMemoryAccessor>());
ASSERT_NE(elf.get(), nullptr);
auto got = elf->GetNote("GNU", kNoteGnuBuildId);
EXPECT_TRUE(got);
auto data = *got;
EXPECT_EQ(32U, data.size());
for (size_t i = 0; i < 32; i++) {
EXPECT_EQ(i % 8, data[i]);
}
}
TEST(ElfLib, GetIrregularNote) {
std::unique_ptr<ElfLib> elf =
ElfLib::Create(std::make_unique<TestMemoryAccessor>());
ASSERT_NE(elf.get(), nullptr);
auto got = elf->GetNote("seven", kMeaninglessNoteType);
EXPECT_TRUE(got);
auto data = *got;
EXPECT_EQ(3U, data.size());
EXPECT_EQ("foo", std::string(data.data(), data.data() + 3));
}
} // namespace elflib