blob: 7d9766c251402048a8fbc0111f43c9c933e324fc [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/note.h>
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <type_traits>
#include <zxtest/zxtest.h>
namespace {
#if defined(__GLIBC__) || defined(__Fuchsia__)
#define HAVE_OPEN_MEMSTREAM 1
#else
#define HAVE_OPEN_MEMSTREAM 0
#endif
class StringFile {
public:
StringFile(const StringFile&) = delete;
StringFile()
#if HAVE_OPEN_MEMSTREAM
: file_(open_memstream(&buffer_, &buffer_size_))
#else
: file_(tmpfile())
#endif
{
ASSERT_NOT_NULL(file_);
}
FILE* file() { return file_; }
std::string contents() && {
#if HAVE_OPEN_MEMSTREAM
EXPECT_EQ(0, fflush(file_));
return std::string(buffer_, buffer_size_);
#endif
EXPECT_EQ(0, fseek(file_, 0, SEEK_END), "fseek: %s", strerror(errno));
std::string result(ftell(file_), 'x');
rewind(file_);
EXPECT_FALSE(ferror(file_));
EXPECT_EQ(1, fread(result.data(), result.size(), 1, file_), "fread of %zu: %s", result.size(),
strerror(errno));
return result;
}
~StringFile() {
if (file_) {
fclose(file_);
}
#if defined(__GLIBC__) || defined(__Fuchsia__)
free(buffer_);
#endif
}
private:
FILE* file_ = nullptr;
#if HAVE_OPEN_MEMSTREAM
char* buffer_ = nullptr;
size_t buffer_size_ = 0;
#endif
};
template <auto Class, auto Data>
constexpr bool kAliasCheck = std::conjunction_v<
std::is_same<typename elfldltl::Elf<Class, Data>::Note, elfldltl::ElfNote>,
std::is_same<typename elfldltl::Elf<Class, Data>::NoteSegment, elfldltl::ElfNoteSegment<Data>>>;
static_assert(kAliasCheck<elfldltl::ElfClass::k32, elfldltl::ElfData::k2Msb>);
static_assert(kAliasCheck<elfldltl::ElfClass::k64, elfldltl::ElfData::k2Msb>);
static_assert(kAliasCheck<elfldltl::ElfClass::k32, elfldltl::ElfData::k2Lsb>);
static_assert(kAliasCheck<elfldltl::ElfClass::k64, elfldltl::ElfData::k2Lsb>);
TEST(ElfldltlNoteTests, Empty) {
constexpr elfldltl::ElfNote::Bytes kData{};
elfldltl::ElfNoteSegment notes(kData);
for (auto note : notes) {
// This should never be reached, but these statements ensure that the
// intended API usages compile correctly.
EXPECT_TRUE(note.name.empty());
EXPECT_TRUE(note.desc.empty());
EXPECT_EQ(note.type, uint32_t{0});
FAIL("container should be empty");
}
}
TEST(ElfldltlNoteTests, BuildId) {
static constexpr std::byte kData[] = {
std::byte{0}, std::byte{0}, std::byte{0}, std::byte{4}, // namesz
std::byte{0}, std::byte{0}, std::byte{0}, std::byte{8}, // descsz
std::byte{0}, std::byte{0}, std::byte{0}, std::byte{3}, // type
std::byte{'G'}, std::byte{'N'}, std::byte{'U'}, std::byte{0}, // name[]
std::byte{1}, std::byte{2}, std::byte{3}, std::byte{4}, // desc[]
std::byte{5}, std::byte{6}, std::byte{7}, std::byte{8},
};
constexpr elfldltl::ElfNoteSegment<elfldltl::ElfData::k2Msb> notes({kData, sizeof(kData)});
size_t count = 0;
for (auto note : notes) {
++count;
EXPECT_TRUE(note.IsBuildId());
EXPECT_EQ(16, note.HexSize());
std::string str;
note.HexDump([&str](char c) { str += c; });
EXPECT_STREQ(str, "0102030405060708");
StringFile sf;
note.HexDump(sf.file());
EXPECT_STREQ(std::move(sf).contents(), "0102030405060708");
}
EXPECT_EQ(count, size_t{1});
}
} // namespace