blob: 999760caab206257ce82874858b4dcb4b158e065 [file] [log] [blame] [edit]
// Copyright 2024 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_elf/reader.h"
#include "pw_bytes/array.h"
#include "pw_bytes/endian.h"
#include "pw_bytes/suffix.h"
#include "pw_stream/memory_stream.h"
#include "pw_stream/std_file_stream.h"
#include "pw_unit_test/framework.h"
namespace pw::elf {
namespace {
constexpr Status kEndOfFileStatus = Status::OutOfRange();
Status TestInitialize(ConstByteSpan data) {
stream::MemoryReader stream(data);
return ElfReader::FromStream(stream).status();
}
TEST(Reader, HandlesEmptyStream) {
constexpr auto kData = bytes::Array<>();
EXPECT_EQ(TestInitialize(kData), kEndOfFileStatus);
}
TEST(Reader, HandlesInvalidMagic) {
constexpr std::array<std::byte, EI_NIDENT> kData = {
std::byte{0x7F},
std::byte{'B'},
std::byte{'A'},
std::byte{'D'},
};
EXPECT_EQ(TestInitialize(kData), Status::DataLoss());
}
TEST(Reader, HandlesTruncatedAfterMagic) {
constexpr auto kData = bytes::Array<0x7F, 'E', 'L', 'F'>();
EXPECT_EQ(TestInitialize(kData), kEndOfFileStatus);
}
TEST(Reader, HandlesInvalidClass) {
constexpr std::array<std::byte, EI_NIDENT> kData = {
std::byte{0x7F},
std::byte{'E'},
std::byte{'L'},
std::byte{'F'},
std::byte{0x66}, // EI_CLASS
std::byte{pw::endian::native == pw::endian::little
? ELFDATA2LSB
: ELFDATA2MSB}, // EI_DATA
};
EXPECT_EQ(TestInitialize(kData), Status::DataLoss());
}
TEST(Reader, HandlesUnsupportedEndian) {
constexpr std::array<std::byte, EI_NIDENT> kData = {
std::byte{0x7F},
std::byte{'E'},
std::byte{'L'},
std::byte{'F'},
std::byte{0x66}, // EI_CLASS
std::byte{pw::endian::native == pw::endian::little
? ELFDATA2MSB
: ELFDATA2LSB}, // EI_DATA (opposite)
};
EXPECT_EQ(TestInitialize(kData), Status::Unimplemented());
}
TEST(Reader, SeekToSectionWorksOnRealFile) {
pw::stream::StdFileReader stream(TEST_ELF_FILE_PATH);
PW_TEST_ASSERT_OK_AND_ASSIGN(auto reader,
pw::elf::ElfReader::FromStream(stream));
auto section_size = reader.SeekToSection(".test_section_1");
PW_TEST_ASSERT_OK(section_size);
std::vector<std::byte> section_data;
section_data.resize(section_size.size());
PW_TEST_ASSERT_OK(stream.ReadExact(section_data));
constexpr auto kExpectedData = bytes::String("You cannot pass\0");
EXPECT_EQ(section_data.size(), kExpectedData.size());
EXPECT_TRUE(std::equal(
section_data.begin(), section_data.end(), kExpectedData.begin()));
}
TEST(Reader, ReadSectionWorksOnRealFile) {
pw::stream::StdFileReader stream(TEST_ELF_FILE_PATH);
PW_TEST_ASSERT_OK_AND_ASSIGN(auto reader,
pw::elf::ElfReader::FromStream(stream));
PW_TEST_ASSERT_OK_AND_ASSIGN(auto section_data,
reader.ReadSection(".test_section_2"));
constexpr auto kExpectedData = bytes::Array<0xEF, 0xBE, 0xED, 0xFE>();
EXPECT_EQ(section_data.size(), kExpectedData.size());
EXPECT_TRUE(std::equal(
section_data.begin(), section_data.end(), kExpectedData.begin()));
}
} // namespace
} // namespace pw::elf