1 //===- ELFObjectFileTest.cpp - Tests for ELFObjectFile --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/Object/ELFObjectFile.h"
10 #include "llvm/Support/MemoryBuffer.h"
11 #include "llvm/ObjectYAML/yaml2obj.h"
12 #include "llvm/Support/YAMLTraits.h"
13 #include "llvm/Testing/Support/Error.h"
14 #include "gtest/gtest.h"
15
16 using namespace llvm;
17 using namespace llvm::object;
18
19 namespace {
20
21 // A struct to initialize a buffer to represent an ELF object file.
22 struct DataForTest {
23 std::vector<uint8_t> Data;
24
25 template <typename T>
makeElfData__anon3b7e07700111::DataForTest26 std::vector<uint8_t> makeElfData(uint8_t Class, uint8_t Encoding,
27 uint16_t Machine) {
28 T Ehdr{}; // Zero-initialise the header.
29 Ehdr.e_ident[ELF::EI_MAG0] = 0x7f;
30 Ehdr.e_ident[ELF::EI_MAG1] = 'E';
31 Ehdr.e_ident[ELF::EI_MAG2] = 'L';
32 Ehdr.e_ident[ELF::EI_MAG3] = 'F';
33 Ehdr.e_ident[ELF::EI_CLASS] = Class;
34 Ehdr.e_ident[ELF::EI_DATA] = Encoding;
35 Ehdr.e_ident[ELF::EI_VERSION] = 1;
36 Ehdr.e_type = ELF::ET_REL;
37 Ehdr.e_machine = Machine;
38 Ehdr.e_version = 1;
39 Ehdr.e_ehsize = sizeof(T);
40
41 bool IsLittleEndian = Encoding == ELF::ELFDATA2LSB;
42 if (sys::IsLittleEndianHost != IsLittleEndian) {
43 sys::swapByteOrder(Ehdr.e_type);
44 sys::swapByteOrder(Ehdr.e_machine);
45 sys::swapByteOrder(Ehdr.e_version);
46 sys::swapByteOrder(Ehdr.e_ehsize);
47 }
48
49 uint8_t *EhdrBytes = reinterpret_cast<uint8_t *>(&Ehdr);
50 std::vector<uint8_t> Bytes;
51 std::copy(EhdrBytes, EhdrBytes + sizeof(Ehdr), std::back_inserter(Bytes));
52 return Bytes;
53 }
54
DataForTest__anon3b7e07700111::DataForTest55 DataForTest(uint8_t Class, uint8_t Encoding, uint16_t Machine) {
56 if (Class == ELF::ELFCLASS64)
57 Data = makeElfData<ELF::Elf64_Ehdr>(Class, Encoding, Machine);
58 else {
59 assert(Class == ELF::ELFCLASS32);
60 Data = makeElfData<ELF::Elf32_Ehdr>(Class, Encoding, Machine);
61 }
62 }
63 };
64
checkFormatAndArch(const DataForTest & D,StringRef Fmt,Triple::ArchType Arch)65 void checkFormatAndArch(const DataForTest &D, StringRef Fmt,
66 Triple::ArchType Arch) {
67 Expected<std::unique_ptr<ObjectFile>> ELFObjOrErr =
68 object::ObjectFile::createELFObjectFile(
69 MemoryBufferRef(toStringRef(D.Data), "dummyELF"));
70 ASSERT_THAT_EXPECTED(ELFObjOrErr, Succeeded());
71
72 const ObjectFile &File = *(*ELFObjOrErr).get();
73 EXPECT_EQ(Fmt, File.getFileFormatName());
74 EXPECT_EQ(Arch, File.getArch());
75 }
76
generateData(uint16_t Machine)77 std::array<DataForTest, 4> generateData(uint16_t Machine) {
78 return {DataForTest(ELF::ELFCLASS32, ELF::ELFDATA2LSB, Machine),
79 DataForTest(ELF::ELFCLASS32, ELF::ELFDATA2MSB, Machine),
80 DataForTest(ELF::ELFCLASS64, ELF::ELFDATA2LSB, Machine),
81 DataForTest(ELF::ELFCLASS64, ELF::ELFDATA2MSB, Machine)};
82 }
83
84 } // namespace
85
TEST(ELFObjectFileTest,MachineTestForNoneOrUnused)86 TEST(ELFObjectFileTest, MachineTestForNoneOrUnused) {
87 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
88 "elf64-unknown", "elf64-unknown"};
89 size_t I = 0;
90 for (const DataForTest &D : generateData(ELF::EM_NONE))
91 checkFormatAndArch(D, Formats[I++], Triple::UnknownArch);
92
93 // Test an arbitrary unused EM_* value (255).
94 I = 0;
95 for (const DataForTest &D : generateData(255))
96 checkFormatAndArch(D, Formats[I++], Triple::UnknownArch);
97 }
98
TEST(ELFObjectFileTest,MachineTestForVE)99 TEST(ELFObjectFileTest, MachineTestForVE) {
100 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
101 "elf64-ve", "elf64-ve"};
102 size_t I = 0;
103 for (const DataForTest &D : generateData(ELF::EM_VE))
104 checkFormatAndArch(D, Formats[I++], Triple::ve);
105 }
106
TEST(ELFObjectFileTest,MachineTestForX86_64)107 TEST(ELFObjectFileTest, MachineTestForX86_64) {
108 std::array<StringRef, 4> Formats = {"elf32-x86-64", "elf32-x86-64",
109 "elf64-x86-64", "elf64-x86-64"};
110 size_t I = 0;
111 for (const DataForTest &D : generateData(ELF::EM_X86_64))
112 checkFormatAndArch(D, Formats[I++], Triple::x86_64);
113 }
114
TEST(ELFObjectFileTest,MachineTestFor386)115 TEST(ELFObjectFileTest, MachineTestFor386) {
116 std::array<StringRef, 4> Formats = {"elf32-i386", "elf32-i386", "elf64-i386",
117 "elf64-i386"};
118 size_t I = 0;
119 for (const DataForTest &D : generateData(ELF::EM_386))
120 checkFormatAndArch(D, Formats[I++], Triple::x86);
121 }
122
TEST(ELFObjectFileTest,MachineTestForMIPS)123 TEST(ELFObjectFileTest, MachineTestForMIPS) {
124 std::array<StringRef, 4> Formats = {"elf32-mips", "elf32-mips", "elf64-mips",
125 "elf64-mips"};
126 std::array<Triple::ArchType, 4> Archs = {Triple::mipsel, Triple::mips,
127 Triple::mips64el, Triple::mips64};
128 size_t I = 0;
129 for (const DataForTest &D : generateData(ELF::EM_MIPS)) {
130 checkFormatAndArch(D, Formats[I], Archs[I]);
131 ++I;
132 }
133 }
134
TEST(ELFObjectFileTest,MachineTestForAMDGPU)135 TEST(ELFObjectFileTest, MachineTestForAMDGPU) {
136 std::array<StringRef, 4> Formats = {"elf32-amdgpu", "elf32-amdgpu",
137 "elf64-amdgpu", "elf64-amdgpu"};
138 size_t I = 0;
139 for (const DataForTest &D : generateData(ELF::EM_AMDGPU))
140 checkFormatAndArch(D, Formats[I++], Triple::UnknownArch);
141 }
142
TEST(ELFObjectFileTest,MachineTestForIAMCU)143 TEST(ELFObjectFileTest, MachineTestForIAMCU) {
144 std::array<StringRef, 4> Formats = {"elf32-iamcu", "elf32-iamcu",
145 "elf64-unknown", "elf64-unknown"};
146 size_t I = 0;
147 for (const DataForTest &D : generateData(ELF::EM_IAMCU))
148 checkFormatAndArch(D, Formats[I++], Triple::x86);
149 }
150
TEST(ELFObjectFileTest,MachineTestForAARCH64)151 TEST(ELFObjectFileTest, MachineTestForAARCH64) {
152 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
153 "elf64-littleaarch64",
154 "elf64-bigaarch64"};
155 std::array<Triple::ArchType, 4> Archs = {Triple::aarch64, Triple::aarch64_be,
156 Triple::aarch64, Triple::aarch64_be};
157 size_t I = 0;
158 for (const DataForTest &D : generateData(ELF::EM_AARCH64)) {
159 checkFormatAndArch(D, Formats[I], Archs[I]);
160 ++I;
161 }
162 }
163
TEST(ELFObjectFileTest,MachineTestForPPC64)164 TEST(ELFObjectFileTest, MachineTestForPPC64) {
165 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
166 "elf64-powerpcle", "elf64-powerpc"};
167 std::array<Triple::ArchType, 4> Archs = {Triple::ppc64le, Triple::ppc64,
168 Triple::ppc64le, Triple::ppc64};
169 size_t I = 0;
170 for (const DataForTest &D : generateData(ELF::EM_PPC64)) {
171 checkFormatAndArch(D, Formats[I], Archs[I]);
172 ++I;
173 }
174 }
175
TEST(ELFObjectFileTest,MachineTestForPPC)176 TEST(ELFObjectFileTest, MachineTestForPPC) {
177 std::array<StringRef, 4> Formats = {"elf32-powerpc", "elf32-powerpc",
178 "elf64-unknown", "elf64-unknown"};
179 size_t I = 0;
180 for (const DataForTest &D : generateData(ELF::EM_PPC))
181 checkFormatAndArch(D, Formats[I++], Triple::ppc);
182 }
183
TEST(ELFObjectFileTest,MachineTestForRISCV)184 TEST(ELFObjectFileTest, MachineTestForRISCV) {
185 std::array<StringRef, 4> Formats = {"elf32-littleriscv", "elf32-littleriscv",
186 "elf64-littleriscv", "elf64-littleriscv"};
187 std::array<Triple::ArchType, 4> Archs = {Triple::riscv32, Triple::riscv32,
188 Triple::riscv64, Triple::riscv64};
189 size_t I = 0;
190 for (const DataForTest &D : generateData(ELF::EM_RISCV)) {
191 checkFormatAndArch(D, Formats[I], Archs[I]);
192 ++I;
193 }
194 }
195
TEST(ELFObjectFileTest,MachineTestForARM)196 TEST(ELFObjectFileTest, MachineTestForARM) {
197 std::array<StringRef, 4> Formats = {"elf32-littlearm", "elf32-bigarm",
198 "elf64-unknown", "elf64-unknown"};
199 size_t I = 0;
200 for (const DataForTest &D : generateData(ELF::EM_ARM))
201 checkFormatAndArch(D, Formats[I++], Triple::arm);
202 }
203
TEST(ELFObjectFileTest,MachineTestForS390)204 TEST(ELFObjectFileTest, MachineTestForS390) {
205 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
206 "elf64-s390", "elf64-s390"};
207 size_t I = 0;
208 for (const DataForTest &D : generateData(ELF::EM_S390))
209 checkFormatAndArch(D, Formats[I++], Triple::systemz);
210 }
211
TEST(ELFObjectFileTest,MachineTestForSPARCV9)212 TEST(ELFObjectFileTest, MachineTestForSPARCV9) {
213 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
214 "elf64-sparc", "elf64-sparc"};
215 size_t I = 0;
216 for (const DataForTest &D : generateData(ELF::EM_SPARCV9))
217 checkFormatAndArch(D, Formats[I++], Triple::sparcv9);
218 }
219
TEST(ELFObjectFileTest,MachineTestForSPARC)220 TEST(ELFObjectFileTest, MachineTestForSPARC) {
221 std::array<StringRef, 4> Formats = {"elf32-sparc", "elf32-sparc",
222 "elf64-unknown", "elf64-unknown"};
223 std::array<Triple::ArchType, 4> Archs = {Triple::sparcel, Triple::sparc,
224 Triple::sparcel, Triple::sparc};
225 size_t I = 0;
226 for (const DataForTest &D : generateData(ELF::EM_SPARC)) {
227 checkFormatAndArch(D, Formats[I], Archs[I]);
228 ++I;
229 }
230 }
231
TEST(ELFObjectFileTest,MachineTestForSPARC32PLUS)232 TEST(ELFObjectFileTest, MachineTestForSPARC32PLUS) {
233 std::array<StringRef, 4> Formats = {"elf32-sparc", "elf32-sparc",
234 "elf64-unknown", "elf64-unknown"};
235 std::array<Triple::ArchType, 4> Archs = {Triple::sparcel, Triple::sparc,
236 Triple::sparcel, Triple::sparc};
237 size_t I = 0;
238 for (const DataForTest &D : generateData(ELF::EM_SPARC32PLUS)) {
239 checkFormatAndArch(D, Formats[I], Archs[I]);
240 ++I;
241 }
242 }
243
TEST(ELFObjectFileTest,MachineTestForBPF)244 TEST(ELFObjectFileTest, MachineTestForBPF) {
245 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
246 "elf64-bpf", "elf64-bpf"};
247 std::array<Triple::ArchType, 4> Archs = {Triple::bpfel, Triple::bpfeb,
248 Triple::bpfel, Triple::bpfeb};
249 size_t I = 0;
250 for (const DataForTest &D : generateData(ELF::EM_BPF)) {
251 checkFormatAndArch(D, Formats[I], Archs[I]);
252 ++I;
253 }
254 }
255
TEST(ELFObjectFileTest,MachineTestForAVR)256 TEST(ELFObjectFileTest, MachineTestForAVR) {
257 std::array<StringRef, 4> Formats = {"elf32-avr", "elf32-avr", "elf64-unknown",
258 "elf64-unknown"};
259 size_t I = 0;
260 for (const DataForTest &D : generateData(ELF::EM_AVR))
261 checkFormatAndArch(D, Formats[I++], Triple::avr);
262 }
263
TEST(ELFObjectFileTest,MachineTestForHEXAGON)264 TEST(ELFObjectFileTest, MachineTestForHEXAGON) {
265 std::array<StringRef, 4> Formats = {"elf32-hexagon", "elf32-hexagon",
266 "elf64-unknown", "elf64-unknown"};
267 size_t I = 0;
268 for (const DataForTest &D : generateData(ELF::EM_HEXAGON))
269 checkFormatAndArch(D, Formats[I++], Triple::hexagon);
270 }
271
TEST(ELFObjectFileTest,MachineTestForLANAI)272 TEST(ELFObjectFileTest, MachineTestForLANAI) {
273 std::array<StringRef, 4> Formats = {"elf32-lanai", "elf32-lanai",
274 "elf64-unknown", "elf64-unknown"};
275 size_t I = 0;
276 for (const DataForTest &D : generateData(ELF::EM_LANAI))
277 checkFormatAndArch(D, Formats[I++], Triple::lanai);
278 }
279
TEST(ELFObjectFileTest,MachineTestForMSP430)280 TEST(ELFObjectFileTest, MachineTestForMSP430) {
281 std::array<StringRef, 4> Formats = {"elf32-msp430", "elf32-msp430",
282 "elf64-unknown", "elf64-unknown"};
283 size_t I = 0;
284 for (const DataForTest &D : generateData(ELF::EM_MSP430))
285 checkFormatAndArch(D, Formats[I++], Triple::msp430);
286 }
287
TEST(ELFObjectFileTest,MachineTestForCSKY)288 TEST(ELFObjectFileTest, MachineTestForCSKY) {
289 std::array<StringRef, 4> Formats = {"elf32-csky", "elf32-csky",
290 "elf64-unknown", "elf64-unknown"};
291 size_t I = 0;
292 for (const DataForTest &D : generateData(ELF::EM_CSKY))
293 checkFormatAndArch(D, Formats[I++], Triple::csky);
294 }
295
296 // ELF relative relocation type test.
TEST(ELFObjectFileTest,RelativeRelocationTypeTest)297 TEST(ELFObjectFileTest, RelativeRelocationTypeTest) {
298 EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY));
299 }
300
301 template <class ELFT>
toBinary(SmallVectorImpl<char> & Storage,StringRef Yaml)302 static Expected<ELFObjectFile<ELFT>> toBinary(SmallVectorImpl<char> &Storage,
303 StringRef Yaml) {
304 raw_svector_ostream OS(Storage);
305 yaml::Input YIn(Yaml);
306 if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {}))
307 return createStringError(std::errc::invalid_argument,
308 "unable to convert YAML");
309 return ELFObjectFile<ELFT>::create(MemoryBufferRef(OS.str(), "dummyELF"));
310 }
311
312 // Check we are able to create an ELFObjectFile even when the content of the
313 // SHT_SYMTAB_SHNDX section can't be read properly.
TEST(ELFObjectFileTest,InvalidSymtabShndxTest)314 TEST(ELFObjectFileTest, InvalidSymtabShndxTest) {
315 SmallString<0> Storage;
316 Expected<ELFObjectFile<ELF64LE>> ExpectedFile = toBinary<ELF64LE>(Storage, R"(
317 --- !ELF
318 FileHeader:
319 Class: ELFCLASS64
320 Data: ELFDATA2LSB
321 Type: ET_REL
322 Sections:
323 - Name: .symtab_shndx
324 Type: SHT_SYMTAB_SHNDX
325 Entries: [ 0 ]
326 ShSize: 0xFFFFFFFF
327 )");
328
329 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
330 }
331