1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_elf/reader.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/array.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/endian.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_bytes/suffix.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/memory_stream.h"
21*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/std_file_stream.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
23*61c4878aSAndroid Build Coastguard Worker
24*61c4878aSAndroid Build Coastguard Worker namespace pw::elf {
25*61c4878aSAndroid Build Coastguard Worker namespace {
26*61c4878aSAndroid Build Coastguard Worker
27*61c4878aSAndroid Build Coastguard Worker constexpr Status kEndOfFileStatus = Status::OutOfRange();
28*61c4878aSAndroid Build Coastguard Worker
TestInitialize(ConstByteSpan data)29*61c4878aSAndroid Build Coastguard Worker Status TestInitialize(ConstByteSpan data) {
30*61c4878aSAndroid Build Coastguard Worker stream::MemoryReader stream(data);
31*61c4878aSAndroid Build Coastguard Worker return ElfReader::FromStream(stream).status();
32*61c4878aSAndroid Build Coastguard Worker }
33*61c4878aSAndroid Build Coastguard Worker
TEST(Reader,HandlesEmptyStream)34*61c4878aSAndroid Build Coastguard Worker TEST(Reader, HandlesEmptyStream) {
35*61c4878aSAndroid Build Coastguard Worker constexpr auto kData = bytes::Array<>();
36*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(TestInitialize(kData), kEndOfFileStatus);
37*61c4878aSAndroid Build Coastguard Worker }
38*61c4878aSAndroid Build Coastguard Worker
TEST(Reader,HandlesInvalidMagic)39*61c4878aSAndroid Build Coastguard Worker TEST(Reader, HandlesInvalidMagic) {
40*61c4878aSAndroid Build Coastguard Worker constexpr std::array<std::byte, EI_NIDENT> kData = {
41*61c4878aSAndroid Build Coastguard Worker std::byte{0x7F},
42*61c4878aSAndroid Build Coastguard Worker std::byte{'B'},
43*61c4878aSAndroid Build Coastguard Worker std::byte{'A'},
44*61c4878aSAndroid Build Coastguard Worker std::byte{'D'},
45*61c4878aSAndroid Build Coastguard Worker };
46*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(TestInitialize(kData), Status::DataLoss());
47*61c4878aSAndroid Build Coastguard Worker }
48*61c4878aSAndroid Build Coastguard Worker
TEST(Reader,HandlesTruncatedAfterMagic)49*61c4878aSAndroid Build Coastguard Worker TEST(Reader, HandlesTruncatedAfterMagic) {
50*61c4878aSAndroid Build Coastguard Worker constexpr auto kData = bytes::Array<0x7F, 'E', 'L', 'F'>();
51*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(TestInitialize(kData), kEndOfFileStatus);
52*61c4878aSAndroid Build Coastguard Worker }
53*61c4878aSAndroid Build Coastguard Worker
TEST(Reader,HandlesInvalidClass)54*61c4878aSAndroid Build Coastguard Worker TEST(Reader, HandlesInvalidClass) {
55*61c4878aSAndroid Build Coastguard Worker constexpr std::array<std::byte, EI_NIDENT> kData = {
56*61c4878aSAndroid Build Coastguard Worker std::byte{0x7F},
57*61c4878aSAndroid Build Coastguard Worker std::byte{'E'},
58*61c4878aSAndroid Build Coastguard Worker std::byte{'L'},
59*61c4878aSAndroid Build Coastguard Worker std::byte{'F'},
60*61c4878aSAndroid Build Coastguard Worker std::byte{0x66}, // EI_CLASS
61*61c4878aSAndroid Build Coastguard Worker std::byte{pw::endian::native == pw::endian::little
62*61c4878aSAndroid Build Coastguard Worker ? ELFDATA2LSB
63*61c4878aSAndroid Build Coastguard Worker : ELFDATA2MSB}, // EI_DATA
64*61c4878aSAndroid Build Coastguard Worker };
65*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(TestInitialize(kData), Status::DataLoss());
66*61c4878aSAndroid Build Coastguard Worker }
67*61c4878aSAndroid Build Coastguard Worker
TEST(Reader,HandlesUnsupportedEndian)68*61c4878aSAndroid Build Coastguard Worker TEST(Reader, HandlesUnsupportedEndian) {
69*61c4878aSAndroid Build Coastguard Worker constexpr std::array<std::byte, EI_NIDENT> kData = {
70*61c4878aSAndroid Build Coastguard Worker std::byte{0x7F},
71*61c4878aSAndroid Build Coastguard Worker std::byte{'E'},
72*61c4878aSAndroid Build Coastguard Worker std::byte{'L'},
73*61c4878aSAndroid Build Coastguard Worker std::byte{'F'},
74*61c4878aSAndroid Build Coastguard Worker std::byte{0x66}, // EI_CLASS
75*61c4878aSAndroid Build Coastguard Worker std::byte{pw::endian::native == pw::endian::little
76*61c4878aSAndroid Build Coastguard Worker ? ELFDATA2MSB
77*61c4878aSAndroid Build Coastguard Worker : ELFDATA2LSB}, // EI_DATA (opposite)
78*61c4878aSAndroid Build Coastguard Worker };
79*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(TestInitialize(kData), Status::Unimplemented());
80*61c4878aSAndroid Build Coastguard Worker }
81*61c4878aSAndroid Build Coastguard Worker
TEST(Reader,SeekToSectionWorksOnRealFile)82*61c4878aSAndroid Build Coastguard Worker TEST(Reader, SeekToSectionWorksOnRealFile) {
83*61c4878aSAndroid Build Coastguard Worker pw::stream::StdFileReader stream(TEST_ELF_FILE_PATH);
84*61c4878aSAndroid Build Coastguard Worker PW_TEST_ASSERT_OK_AND_ASSIGN(auto reader,
85*61c4878aSAndroid Build Coastguard Worker pw::elf::ElfReader::FromStream(stream));
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard Worker auto section_size = reader.SeekToSection(".test_section_1");
88*61c4878aSAndroid Build Coastguard Worker PW_TEST_ASSERT_OK(section_size);
89*61c4878aSAndroid Build Coastguard Worker
90*61c4878aSAndroid Build Coastguard Worker std::vector<std::byte> section_data;
91*61c4878aSAndroid Build Coastguard Worker section_data.resize(section_size.size());
92*61c4878aSAndroid Build Coastguard Worker PW_TEST_ASSERT_OK(stream.ReadExact(section_data));
93*61c4878aSAndroid Build Coastguard Worker
94*61c4878aSAndroid Build Coastguard Worker constexpr auto kExpectedData = bytes::String("You cannot pass\0");
95*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(section_data.size(), kExpectedData.size());
96*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(std::equal(
97*61c4878aSAndroid Build Coastguard Worker section_data.begin(), section_data.end(), kExpectedData.begin()));
98*61c4878aSAndroid Build Coastguard Worker }
99*61c4878aSAndroid Build Coastguard Worker
TEST(Reader,ReadSectionWorksOnRealFile)100*61c4878aSAndroid Build Coastguard Worker TEST(Reader, ReadSectionWorksOnRealFile) {
101*61c4878aSAndroid Build Coastguard Worker pw::stream::StdFileReader stream(TEST_ELF_FILE_PATH);
102*61c4878aSAndroid Build Coastguard Worker PW_TEST_ASSERT_OK_AND_ASSIGN(auto reader,
103*61c4878aSAndroid Build Coastguard Worker pw::elf::ElfReader::FromStream(stream));
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker PW_TEST_ASSERT_OK_AND_ASSIGN(auto section_data,
106*61c4878aSAndroid Build Coastguard Worker reader.ReadSection(".test_section_2"));
107*61c4878aSAndroid Build Coastguard Worker
108*61c4878aSAndroid Build Coastguard Worker constexpr auto kExpectedData = bytes::Array<0xEF, 0xBE, 0xED, 0xFE>();
109*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(section_data.size(), kExpectedData.size());
110*61c4878aSAndroid Build Coastguard Worker EXPECT_TRUE(std::equal(
111*61c4878aSAndroid Build Coastguard Worker section_data.begin(), section_data.end(), kExpectedData.begin()));
112*61c4878aSAndroid Build Coastguard Worker }
113*61c4878aSAndroid Build Coastguard Worker
114*61c4878aSAndroid Build Coastguard Worker } // namespace
115*61c4878aSAndroid Build Coastguard Worker } // namespace pw::elf
116