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/endian.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_log/log.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_status/try.h"
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker namespace pw::elf {
22*61c4878aSAndroid Build Coastguard Worker namespace {
23*61c4878aSAndroid Build Coastguard Worker
24*61c4878aSAndroid Build Coastguard Worker using ElfIdent = std::array<unsigned char, EI_NIDENT>;
25*61c4878aSAndroid Build Coastguard Worker
ElfIdentGetEndian(const ElfIdent & e_ident)26*61c4878aSAndroid Build Coastguard Worker Result<pw::endian> ElfIdentGetEndian(const ElfIdent& e_ident) {
27*61c4878aSAndroid Build Coastguard Worker switch (e_ident[EI_DATA]) {
28*61c4878aSAndroid Build Coastguard Worker case ELFDATA2LSB:
29*61c4878aSAndroid Build Coastguard Worker // Encoding ELFDATA2LSB specifies 2's complement values, with the least
30*61c4878aSAndroid Build Coastguard Worker // significant byte occupying the lowest address.
31*61c4878aSAndroid Build Coastguard Worker return pw::endian::little;
32*61c4878aSAndroid Build Coastguard Worker case ELFDATA2MSB:
33*61c4878aSAndroid Build Coastguard Worker // Encoding ELFDATA2MSB specifies 2's complement values, with the most
34*61c4878aSAndroid Build Coastguard Worker // significant byte occupying the lowest address.
35*61c4878aSAndroid Build Coastguard Worker return pw::endian::big;
36*61c4878aSAndroid Build Coastguard Worker default:
37*61c4878aSAndroid Build Coastguard Worker return Status::OutOfRange();
38*61c4878aSAndroid Build Coastguard Worker }
39*61c4878aSAndroid Build Coastguard Worker }
40*61c4878aSAndroid Build Coastguard Worker
41*61c4878aSAndroid Build Coastguard Worker enum class ElfClass {
42*61c4878aSAndroid Build Coastguard Worker kElf32,
43*61c4878aSAndroid Build Coastguard Worker kElf64,
44*61c4878aSAndroid Build Coastguard Worker };
45*61c4878aSAndroid Build Coastguard Worker
ElfIdentGetElfClass(const ElfIdent & e_ident)46*61c4878aSAndroid Build Coastguard Worker Result<ElfClass> ElfIdentGetElfClass(const ElfIdent& e_ident) {
47*61c4878aSAndroid Build Coastguard Worker switch (e_ident[EI_CLASS]) {
48*61c4878aSAndroid Build Coastguard Worker case ELFCLASS32:
49*61c4878aSAndroid Build Coastguard Worker return ElfClass::kElf32;
50*61c4878aSAndroid Build Coastguard Worker case ELFCLASS64:
51*61c4878aSAndroid Build Coastguard Worker return ElfClass::kElf64;
52*61c4878aSAndroid Build Coastguard Worker default:
53*61c4878aSAndroid Build Coastguard Worker return Status::OutOfRange();
54*61c4878aSAndroid Build Coastguard Worker }
55*61c4878aSAndroid Build Coastguard Worker }
56*61c4878aSAndroid Build Coastguard Worker
MakeReaderImpl(ElfClass elf_class,stream::SeekableReader & stream)57*61c4878aSAndroid Build Coastguard Worker Result<internal::ElfReaderImpls> MakeReaderImpl(
58*61c4878aSAndroid Build Coastguard Worker ElfClass elf_class, stream::SeekableReader& stream) {
59*61c4878aSAndroid Build Coastguard Worker switch (elf_class) {
60*61c4878aSAndroid Build Coastguard Worker case ElfClass::kElf32:
61*61c4878aSAndroid Build Coastguard Worker return internal::ElfReaderImpl32::FromStream(stream);
62*61c4878aSAndroid Build Coastguard Worker #if UINTPTR_MAX == UINT64_MAX
63*61c4878aSAndroid Build Coastguard Worker case ElfClass::kElf64:
64*61c4878aSAndroid Build Coastguard Worker return internal::ElfReaderImpl64::FromStream(stream);
65*61c4878aSAndroid Build Coastguard Worker #endif
66*61c4878aSAndroid Build Coastguard Worker default:
67*61c4878aSAndroid Build Coastguard Worker return Status::Unimplemented();
68*61c4878aSAndroid Build Coastguard Worker }
69*61c4878aSAndroid Build Coastguard Worker }
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard Worker } // namespace
72*61c4878aSAndroid Build Coastguard Worker
FromStream(stream::SeekableReader & stream)73*61c4878aSAndroid Build Coastguard Worker Result<ElfReader> ElfReader::FromStream(stream::SeekableReader& stream) {
74*61c4878aSAndroid Build Coastguard Worker PW_TRY(stream.Seek(0));
75*61c4878aSAndroid Build Coastguard Worker
76*61c4878aSAndroid Build Coastguard Worker // Read the e_ident field of the ELF header.
77*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(ElfIdent e_ident, internal::ReadObject<ElfIdent>(stream));
78*61c4878aSAndroid Build Coastguard Worker PW_TRY(stream.Seek(0));
79*61c4878aSAndroid Build Coastguard Worker
80*61c4878aSAndroid Build Coastguard Worker // Validate e_ident.
81*61c4878aSAndroid Build Coastguard Worker if (!(e_ident[EI_MAG0] == ELFMAG0 && e_ident[EI_MAG1] == ELFMAG1 &&
82*61c4878aSAndroid Build Coastguard Worker e_ident[EI_MAG2] == ELFMAG2 && e_ident[EI_MAG3] == ELFMAG3)) {
83*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR("Invalid ELF magic bytes");
84*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
85*61c4878aSAndroid Build Coastguard Worker }
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard Worker auto endian = ElfIdentGetEndian(e_ident);
88*61c4878aSAndroid Build Coastguard Worker if (!endian.ok()) {
89*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
90*61c4878aSAndroid Build Coastguard Worker }
91*61c4878aSAndroid Build Coastguard Worker if (endian.value() != pw::endian::native) {
92*61c4878aSAndroid Build Coastguard Worker // Only native endian is supported.
93*61c4878aSAndroid Build Coastguard Worker PW_LOG_ERROR("Non-native ELF endian not supported");
94*61c4878aSAndroid Build Coastguard Worker return Status::Unimplemented();
95*61c4878aSAndroid Build Coastguard Worker }
96*61c4878aSAndroid Build Coastguard Worker
97*61c4878aSAndroid Build Coastguard Worker auto elf_class = ElfIdentGetElfClass(e_ident);
98*61c4878aSAndroid Build Coastguard Worker if (!elf_class.ok()) {
99*61c4878aSAndroid Build Coastguard Worker return Status::DataLoss();
100*61c4878aSAndroid Build Coastguard Worker }
101*61c4878aSAndroid Build Coastguard Worker
102*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(auto impl, MakeReaderImpl(elf_class.value(), stream));
103*61c4878aSAndroid Build Coastguard Worker return ElfReader(std::move(impl));
104*61c4878aSAndroid Build Coastguard Worker }
105*61c4878aSAndroid Build Coastguard Worker
ReadSection(std::string_view name)106*61c4878aSAndroid Build Coastguard Worker Result<std::vector<std::byte>> ElfReader::ReadSection(std::string_view name) {
107*61c4878aSAndroid Build Coastguard Worker StatusWithSize size = SeekToSection(name);
108*61c4878aSAndroid Build Coastguard Worker if (!size.ok()) {
109*61c4878aSAndroid Build Coastguard Worker return size.status();
110*61c4878aSAndroid Build Coastguard Worker }
111*61c4878aSAndroid Build Coastguard Worker
112*61c4878aSAndroid Build Coastguard Worker std::vector<std::byte> data;
113*61c4878aSAndroid Build Coastguard Worker data.resize(size.size());
114*61c4878aSAndroid Build Coastguard Worker PW_TRY(stream().ReadExact(data));
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard Worker return data;
117*61c4878aSAndroid Build Coastguard Worker }
118*61c4878aSAndroid Build Coastguard Worker
119*61c4878aSAndroid Build Coastguard Worker namespace internal {
120*61c4878aSAndroid Build Coastguard Worker
121*61c4878aSAndroid Build Coastguard Worker // TODO(jrreinhart): Move to pw_stream
ReadNullTermString(stream::Reader & stream)122*61c4878aSAndroid Build Coastguard Worker Result<std::string> ReadNullTermString(stream::Reader& stream) {
123*61c4878aSAndroid Build Coastguard Worker std::string result;
124*61c4878aSAndroid Build Coastguard Worker while (true) {
125*61c4878aSAndroid Build Coastguard Worker PW_TRY_ASSIGN(char c, ReadObject<char>(stream));
126*61c4878aSAndroid Build Coastguard Worker if (c == '\0') {
127*61c4878aSAndroid Build Coastguard Worker break;
128*61c4878aSAndroid Build Coastguard Worker }
129*61c4878aSAndroid Build Coastguard Worker result += c;
130*61c4878aSAndroid Build Coastguard Worker }
131*61c4878aSAndroid Build Coastguard Worker return result;
132*61c4878aSAndroid Build Coastguard Worker }
133*61c4878aSAndroid Build Coastguard Worker
134*61c4878aSAndroid Build Coastguard Worker } // namespace internal
135*61c4878aSAndroid Build Coastguard Worker } // namespace pw::elf
136