xref: /llvm-project/llvm/unittests/Object/ELFObjectFileTest.cpp (revision 8a0e0c226018a77ea148e128c97c2592e6f25416)
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/ADT/STLExtras.h"
11 #include "llvm/ObjectYAML/yaml2obj.h"
12 #include "llvm/Support/MemoryBuffer.h"
13 #include "llvm/Support/YAMLTraits.h"
14 #include "llvm/Testing/Support/Error.h"
15 #include "gtest/gtest.h"
16 
17 using namespace llvm;
18 using namespace llvm::object;
19 
20 namespace {
21 
22 // A struct to initialize a buffer to represent an ELF object file.
23 struct DataForTest {
24   std::vector<uint8_t> Data;
25 
26   template <typename T>
27   std::vector<uint8_t> makeElfData(uint8_t Class, uint8_t Encoding,
28                                    uint16_t Machine) {
29     T Ehdr{}; // Zero-initialise the header.
30     Ehdr.e_ident[ELF::EI_MAG0] = 0x7f;
31     Ehdr.e_ident[ELF::EI_MAG1] = 'E';
32     Ehdr.e_ident[ELF::EI_MAG2] = 'L';
33     Ehdr.e_ident[ELF::EI_MAG3] = 'F';
34     Ehdr.e_ident[ELF::EI_CLASS] = Class;
35     Ehdr.e_ident[ELF::EI_DATA] = Encoding;
36     Ehdr.e_ident[ELF::EI_VERSION] = 1;
37     Ehdr.e_type = ELF::ET_REL;
38     Ehdr.e_machine = Machine;
39     Ehdr.e_version = 1;
40     Ehdr.e_ehsize = sizeof(T);
41 
42     bool IsLittleEndian = Encoding == ELF::ELFDATA2LSB;
43     if (sys::IsLittleEndianHost != IsLittleEndian) {
44       sys::swapByteOrder(Ehdr.e_type);
45       sys::swapByteOrder(Ehdr.e_machine);
46       sys::swapByteOrder(Ehdr.e_version);
47       sys::swapByteOrder(Ehdr.e_ehsize);
48     }
49 
50     uint8_t *EhdrBytes = reinterpret_cast<uint8_t *>(&Ehdr);
51     std::vector<uint8_t> Bytes;
52     std::copy(EhdrBytes, EhdrBytes + sizeof(Ehdr), std::back_inserter(Bytes));
53     return Bytes;
54   }
55 
56   DataForTest(uint8_t Class, uint8_t Encoding, uint16_t Machine) {
57     if (Class == ELF::ELFCLASS64)
58       Data = makeElfData<ELF::Elf64_Ehdr>(Class, Encoding, Machine);
59     else {
60       assert(Class == ELF::ELFCLASS32);
61       Data = makeElfData<ELF::Elf32_Ehdr>(Class, Encoding, Machine);
62     }
63   }
64 };
65 
66 void checkFormatAndArch(const DataForTest &D, StringRef Fmt,
67                         Triple::ArchType Arch) {
68   Expected<std::unique_ptr<ObjectFile>> ELFObjOrErr =
69       object::ObjectFile::createELFObjectFile(
70           MemoryBufferRef(toStringRef(D.Data), "dummyELF"));
71   ASSERT_THAT_EXPECTED(ELFObjOrErr, Succeeded());
72 
73   const ObjectFile &File = *(*ELFObjOrErr).get();
74   EXPECT_EQ(Fmt, File.getFileFormatName());
75   EXPECT_EQ(Arch, File.getArch());
76 }
77 
78 std::array<DataForTest, 4> generateData(uint16_t Machine) {
79   return {DataForTest(ELF::ELFCLASS32, ELF::ELFDATA2LSB, Machine),
80           DataForTest(ELF::ELFCLASS32, ELF::ELFDATA2MSB, Machine),
81           DataForTest(ELF::ELFCLASS64, ELF::ELFDATA2LSB, Machine),
82           DataForTest(ELF::ELFCLASS64, ELF::ELFDATA2MSB, Machine)};
83 }
84 
85 } // namespace
86 
87 TEST(ELFObjectFileTest, MachineTestForNoneOrUnused) {
88   std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
89                                       "elf64-unknown", "elf64-unknown"};
90   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_NONE)))
91     checkFormatAndArch(Data, Formats[Idx], Triple::UnknownArch);
92 
93   // Test an arbitrary unused EM_* value (255).
94   for (auto [Idx, Data] : enumerate(generateData(255)))
95     checkFormatAndArch(Data, Formats[Idx], Triple::UnknownArch);
96 }
97 
98 TEST(ELFObjectFileTest, MachineTestForVE) {
99   std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
100                                       "elf64-ve", "elf64-ve"};
101   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_VE)))
102     checkFormatAndArch(Data, Formats[Idx], Triple::ve);
103 }
104 
105 TEST(ELFObjectFileTest, MachineTestForX86_64) {
106   std::array<StringRef, 4> Formats = {"elf32-x86-64", "elf32-x86-64",
107                                       "elf64-x86-64", "elf64-x86-64"};
108   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_X86_64)))
109     checkFormatAndArch(Data, Formats[Idx], Triple::x86_64);
110 }
111 
112 TEST(ELFObjectFileTest, MachineTestFor386) {
113   std::array<StringRef, 4> Formats = {"elf32-i386", "elf32-i386", "elf64-i386",
114                                       "elf64-i386"};
115   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_386)))
116     checkFormatAndArch(Data, Formats[Idx], Triple::x86);
117 }
118 
119 TEST(ELFObjectFileTest, MachineTestForMIPS) {
120   std::array<StringRef, 4> Formats = {"elf32-mips", "elf32-mips", "elf64-mips",
121                                       "elf64-mips"};
122   std::array<Triple::ArchType, 4> Archs = {Triple::mipsel, Triple::mips,
123                                            Triple::mips64el, Triple::mips64};
124   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_MIPS)))
125     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
126 }
127 
128 TEST(ELFObjectFileTest, MachineTestForAMDGPU) {
129   std::array<StringRef, 4> Formats = {"elf32-amdgpu", "elf32-amdgpu",
130                                       "elf64-amdgpu", "elf64-amdgpu"};
131   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_AMDGPU)))
132     checkFormatAndArch(Data, Formats[Idx], Triple::UnknownArch);
133 }
134 
135 TEST(ELFObjectFileTest, MachineTestForIAMCU) {
136   std::array<StringRef, 4> Formats = {"elf32-iamcu", "elf32-iamcu",
137                                       "elf64-unknown", "elf64-unknown"};
138   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_IAMCU)))
139     checkFormatAndArch(Data, Formats[Idx], Triple::x86);
140 }
141 
142 TEST(ELFObjectFileTest, MachineTestForAARCH64) {
143   std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
144                                       "elf64-littleaarch64",
145                                       "elf64-bigaarch64"};
146   std::array<Triple::ArchType, 4> Archs = {Triple::aarch64, Triple::aarch64_be,
147                                            Triple::aarch64, Triple::aarch64_be};
148   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_AARCH64)))
149     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
150 }
151 
152 TEST(ELFObjectFileTest, MachineTestForPPC64) {
153   std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
154                                       "elf64-powerpcle", "elf64-powerpc"};
155   std::array<Triple::ArchType, 4> Archs = {Triple::ppc64le, Triple::ppc64,
156                                            Triple::ppc64le, Triple::ppc64};
157   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_PPC64)))
158     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
159 }
160 
161 TEST(ELFObjectFileTest, MachineTestForPPC) {
162   std::array<StringRef, 4> Formats = {"elf32-powerpcle", "elf32-powerpc",
163                                       "elf64-unknown", "elf64-unknown"};
164   std::array<Triple::ArchType, 4> Archs = {Triple::ppcle, Triple::ppc,
165                                            Triple::ppcle, Triple::ppc};
166   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_PPC)))
167     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
168 }
169 
170 TEST(ELFObjectFileTest, MachineTestForRISCV) {
171   std::array<StringRef, 4> Formats = {"elf32-littleriscv", "elf32-littleriscv",
172                                       "elf64-littleriscv", "elf64-littleriscv"};
173   std::array<Triple::ArchType, 4> Archs = {Triple::riscv32, Triple::riscv32,
174                                            Triple::riscv64, Triple::riscv64};
175   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_RISCV)))
176     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
177 }
178 
179 TEST(ELFObjectFileTest, MachineTestForARM) {
180   std::array<StringRef, 4> Formats = {"elf32-littlearm", "elf32-bigarm",
181                                       "elf64-unknown", "elf64-unknown"};
182   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_ARM)))
183     checkFormatAndArch(Data, Formats[Idx], Triple::arm);
184 }
185 
186 TEST(ELFObjectFileTest, MachineTestForS390) {
187   std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
188                                       "elf64-s390", "elf64-s390"};
189   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_S390)))
190     checkFormatAndArch(Data, Formats[Idx], Triple::systemz);
191 }
192 
193 TEST(ELFObjectFileTest, MachineTestForSPARCV9) {
194   std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
195                                       "elf64-sparc", "elf64-sparc"};
196   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_SPARCV9)))
197     checkFormatAndArch(Data, Formats[Idx], Triple::sparcv9);
198 }
199 
200 TEST(ELFObjectFileTest, MachineTestForSPARC) {
201   std::array<StringRef, 4> Formats = {"elf32-sparc", "elf32-sparc",
202                                       "elf64-unknown", "elf64-unknown"};
203   std::array<Triple::ArchType, 4> Archs = {Triple::sparcel, Triple::sparc,
204                                            Triple::sparcel, Triple::sparc};
205   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_SPARC)))
206     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
207 }
208 
209 TEST(ELFObjectFileTest, MachineTestForSPARC32PLUS) {
210   std::array<StringRef, 4> Formats = {"elf32-sparc", "elf32-sparc",
211                                       "elf64-unknown", "elf64-unknown"};
212   std::array<Triple::ArchType, 4> Archs = {Triple::sparcel, Triple::sparc,
213                                            Triple::sparcel, Triple::sparc};
214   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_SPARC32PLUS)))
215     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
216 }
217 
218 TEST(ELFObjectFileTest, MachineTestForBPF) {
219   std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
220                                       "elf64-bpf", "elf64-bpf"};
221   std::array<Triple::ArchType, 4> Archs = {Triple::bpfel, Triple::bpfeb,
222                                            Triple::bpfel, Triple::bpfeb};
223   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_BPF)))
224     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
225 }
226 
227 TEST(ELFObjectFileTest, MachineTestForAVR) {
228   std::array<StringRef, 4> Formats = {"elf32-avr", "elf32-avr", "elf64-unknown",
229                                       "elf64-unknown"};
230   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_AVR)))
231     checkFormatAndArch(Data, Formats[Idx], Triple::avr);
232 }
233 
234 TEST(ELFObjectFileTest, MachineTestForHEXAGON) {
235   std::array<StringRef, 4> Formats = {"elf32-hexagon", "elf32-hexagon",
236                                       "elf64-unknown", "elf64-unknown"};
237   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_HEXAGON)))
238     checkFormatAndArch(Data, Formats[Idx], Triple::hexagon);
239 }
240 
241 TEST(ELFObjectFileTest, MachineTestForLANAI) {
242   std::array<StringRef, 4> Formats = {"elf32-lanai", "elf32-lanai",
243                                       "elf64-unknown", "elf64-unknown"};
244   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_LANAI)))
245     checkFormatAndArch(Data, Formats[Idx], Triple::lanai);
246 }
247 
248 TEST(ELFObjectFileTest, MachineTestForMSP430) {
249   std::array<StringRef, 4> Formats = {"elf32-msp430", "elf32-msp430",
250                                       "elf64-unknown", "elf64-unknown"};
251   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_MSP430)))
252     checkFormatAndArch(Data, Formats[Idx], Triple::msp430);
253 }
254 
255 TEST(ELFObjectFileTest, MachineTestForLoongArch) {
256   std::array<StringRef, 4> Formats = {"elf32-loongarch", "elf32-loongarch",
257                                       "elf64-loongarch", "elf64-loongarch"};
258   std::array<Triple::ArchType, 4> Archs = {
259       Triple::loongarch32, Triple::loongarch32, Triple::loongarch64,
260       Triple::loongarch64};
261   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_LOONGARCH)))
262     checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
263 }
264 
265 TEST(ELFObjectFileTest, MachineTestForCSKY) {
266   std::array<StringRef, 4> Formats = {"elf32-csky", "elf32-csky",
267                                       "elf64-unknown", "elf64-unknown"};
268   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_CSKY)))
269     checkFormatAndArch(Data, Formats[Idx], Triple::csky);
270 }
271 
272 TEST(ELFObjectFileTest, MachineTestForXtensa) {
273   std::array<StringRef, 4> Formats = {"elf32-xtensa", "elf32-xtensa",
274                                       "elf64-unknown", "elf64-unknown"};
275   for (auto [Idx, Data] : enumerate(generateData(ELF::EM_XTENSA)))
276     checkFormatAndArch(Data, Formats[Idx], Triple::xtensa);
277 }
278 
279 // ELF relative relocation type test.
280 TEST(ELFObjectFileTest, RelativeRelocationTypeTest) {
281   EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY));
282 }
283 
284 template <class ELFT>
285 static Expected<ELFObjectFile<ELFT>> toBinary(SmallVectorImpl<char> &Storage,
286                                               StringRef Yaml) {
287   raw_svector_ostream OS(Storage);
288   yaml::Input YIn(Yaml);
289   if (!yaml::convertYAML(YIn, OS, [](const Twine &Msg) {}))
290     return createStringError(std::errc::invalid_argument,
291                              "unable to convert YAML");
292   return ELFObjectFile<ELFT>::create(MemoryBufferRef(OS.str(), "dummyELF"));
293 }
294 
295 // Check we are able to create an ELFObjectFile even when the content of the
296 // SHT_SYMTAB_SHNDX section can't be read properly.
297 TEST(ELFObjectFileTest, InvalidSymtabShndxTest) {
298   SmallString<0> Storage;
299   Expected<ELFObjectFile<ELF64LE>> ExpectedFile = toBinary<ELF64LE>(Storage, R"(
300 --- !ELF
301 FileHeader:
302   Class: ELFCLASS64
303   Data:  ELFDATA2LSB
304   Type:  ET_REL
305 Sections:
306   - Name:    .symtab_shndx
307     Type:    SHT_SYMTAB_SHNDX
308     Entries: [ 0 ]
309     ShSize: 0xFFFFFFFF
310 )");
311 
312   ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
313 }
314 
315 // Test that we are able to create an ELFObjectFile even when loadable segments
316 // are unsorted by virtual address.
317 // Test that ELFFile<ELFT>::toMappedAddr works properly in this case.
318 
319 TEST(ELFObjectFileTest, InvalidLoadSegmentsOrderTest) {
320   SmallString<0> Storage;
321   Expected<ELFObjectFile<ELF64LE>> ExpectedFile = toBinary<ELF64LE>(Storage, R"(
322 --- !ELF
323 FileHeader:
324   Class: ELFCLASS64
325   Data:  ELFDATA2LSB
326   Type:  ET_EXEC
327 Sections:
328   - Name:         .foo
329     Type:         SHT_PROGBITS
330     Address:      0x1000
331     Offset:       0x3000
332     ContentArray: [ 0x11 ]
333   - Name:         .bar
334     Type:         SHT_PROGBITS
335     Address:      0x2000
336     Offset:       0x4000
337     ContentArray: [ 0x99 ]
338 ProgramHeaders:
339   - Type:     PT_LOAD
340     VAddr:    0x2000
341     FirstSec: .bar
342     LastSec:  .bar
343   - Type:     PT_LOAD
344     VAddr:    0x1000
345     FirstSec: .foo
346     LastSec:  .foo
347 )");
348 
349   ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
350 
351   std::string WarnString;
352   auto ToMappedAddr = [&](uint64_t Addr) -> const uint8_t * {
353     Expected<const uint8_t *> DataOrErr =
354         ExpectedFile->getELFFile().toMappedAddr(Addr, [&](const Twine &Msg) {
355           EXPECT_TRUE(WarnString.empty());
356           WarnString = Msg.str();
357           return Error::success();
358         });
359 
360     if (!DataOrErr) {
361       ADD_FAILURE() << toString(DataOrErr.takeError());
362       return nullptr;
363     }
364 
365     EXPECT_TRUE(WarnString ==
366                 "loadable segments are unsorted by virtual address");
367     WarnString = "";
368     return *DataOrErr;
369   };
370 
371   const uint8_t *Data = ToMappedAddr(0x1000);
372   ASSERT_TRUE(Data);
373   MemoryBufferRef Buf = ExpectedFile->getMemoryBufferRef();
374   EXPECT_EQ((const char *)Data - Buf.getBufferStart(), 0x3000);
375   EXPECT_EQ(Data[0], 0x11);
376 
377   Data = ToMappedAddr(0x2000);
378   ASSERT_TRUE(Data);
379   Buf = ExpectedFile->getMemoryBufferRef();
380   EXPECT_EQ((const char *)Data - Buf.getBufferStart(), 0x4000);
381   EXPECT_EQ(Data[0], 0x99);
382 }
383 
384 // This is a test for API that is related to symbols.
385 // We check that errors are properly reported here.
386 TEST(ELFObjectFileTest, InvalidSymbolTest) {
387   SmallString<0> Storage;
388   Expected<ELFObjectFile<ELF64LE>> ElfOrErr = toBinary<ELF64LE>(Storage, R"(
389 --- !ELF
390 FileHeader:
391   Class:   ELFCLASS64
392   Data:    ELFDATA2LSB
393   Type:    ET_DYN
394   Machine: EM_X86_64
395 Sections:
396   - Name: .symtab
397     Type: SHT_SYMTAB
398 )");
399 
400   ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
401   const ELFFile<ELF64LE> &Elf = ElfOrErr->getELFFile();
402   const ELFObjectFile<ELF64LE> &Obj = *ElfOrErr;
403 
404   Expected<const typename ELF64LE::Shdr *> SymtabSecOrErr = Elf.getSection(1);
405   ASSERT_THAT_EXPECTED(SymtabSecOrErr, Succeeded());
406   ASSERT_EQ((*SymtabSecOrErr)->sh_type, ELF::SHT_SYMTAB);
407 
408   auto DoCheck = [&](unsigned BrokenSymIndex, const char *ErrMsg) {
409     ELFSymbolRef BrokenSym = Obj.toSymbolRef(*SymtabSecOrErr, BrokenSymIndex);
410 
411     // 1) Check the behavior of ELFObjectFile<ELFT>::getSymbolName().
412     //    SymbolRef::getName() calls it internally. We can't test it directly,
413     //    because it is protected.
414     EXPECT_THAT_ERROR(BrokenSym.getName().takeError(),
415                       FailedWithMessage(ErrMsg));
416 
417     // 2) Check the behavior of ELFObjectFile<ELFT>::getSymbol().
418     EXPECT_THAT_ERROR(Obj.getSymbol(BrokenSym.getRawDataRefImpl()).takeError(),
419                       FailedWithMessage(ErrMsg));
420 
421     // 3) Check the behavior of ELFObjectFile<ELFT>::getSymbolSection().
422     //    SymbolRef::getSection() calls it internally. We can't test it
423     //    directly, because it is protected.
424     EXPECT_THAT_ERROR(BrokenSym.getSection().takeError(),
425                       FailedWithMessage(ErrMsg));
426 
427     // 4) Check the behavior of ELFObjectFile<ELFT>::getSymbolFlags().
428     //    SymbolRef::getFlags() calls it internally. We can't test it directly,
429     //    because it is protected.
430     EXPECT_THAT_ERROR(BrokenSym.getFlags().takeError(),
431                       FailedWithMessage(ErrMsg));
432 
433     // 5) Check the behavior of ELFObjectFile<ELFT>::getSymbolType().
434     //    SymbolRef::getType() calls it internally. We can't test it directly,
435     //    because it is protected.
436     EXPECT_THAT_ERROR(BrokenSym.getType().takeError(),
437                       FailedWithMessage(ErrMsg));
438 
439     // 6) Check the behavior of ELFObjectFile<ELFT>::getSymbolAddress().
440     //    SymbolRef::getAddress() calls it internally. We can't test it
441     //    directly, because it is protected.
442     EXPECT_THAT_ERROR(BrokenSym.getAddress().takeError(),
443                       FailedWithMessage(ErrMsg));
444 
445     // Finally, check the `ELFFile<ELFT>::getEntry` API. This is an underlying
446     // method that generates errors for all cases above.
447     EXPECT_THAT_EXPECTED(
448         Elf.getEntry<typename ELF64LE::Sym>(**SymtabSecOrErr, 0), Succeeded());
449     EXPECT_THAT_ERROR(
450         Elf.getEntry<typename ELF64LE::Sym>(**SymtabSecOrErr, BrokenSymIndex)
451             .takeError(),
452         FailedWithMessage(ErrMsg));
453   };
454 
455   // We create a symbol with an index that is too large to exist in the symbol
456   // table.
457   DoCheck(0x1, "can't read an entry at 0x18: it goes past the end of the "
458                "section (0x18)");
459 
460   // We create a symbol with an index that is too large to exist in the object.
461   DoCheck(0xFFFFFFFF, "can't read an entry at 0x17ffffffe8: it goes past the "
462                       "end of the section (0x18)");
463 }
464 
465 // Tests for error paths of the ELFFile::decodeBBAddrMap API.
466 TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
467   StringRef CommonYamlString(R"(
468 --- !ELF
469 FileHeader:
470   Class: ELFCLASS64
471   Data:  ELFDATA2LSB
472   Type:  ET_EXEC
473 Sections:
474   - Type: SHT_LLVM_BB_ADDR_MAP
475     Name: .llvm_bb_addr_map
476     Entries:
477       - Address: 0x11111
478 )");
479 
480   auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) {
481     SmallString<0> Storage;
482     Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
483         toBinary<ELF64LE>(Storage, YamlString);
484     ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
485     const ELFFile<ELF64LE> &Elf = ElfOrErr->getELFFile();
486 
487     Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
488         Elf.getSection(1);
489     ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
490     EXPECT_THAT_ERROR(Elf.decodeBBAddrMap(**BBAddrMapSecOrErr).takeError(),
491                       FailedWithMessage(ErrMsg));
492   };
493 
494   // Check that we can detect unsupported versions.
495   SmallString<128> UnsupportedVersionYamlString(CommonYamlString);
496   UnsupportedVersionYamlString += R"(
497         Version: 2
498         BBEntries:
499           - AddressOffset: 0x0
500             Size:          0x1
501             Metadata:      0x2
502 )";
503 
504   DoCheck(UnsupportedVersionYamlString,
505           "unsupported SHT_LLVM_BB_ADDR_MAP version: 2");
506 
507   SmallString<128> CommonVersionedYamlString(CommonYamlString);
508   CommonVersionedYamlString += R"(
509         Version: 1
510         BBEntries:
511           - AddressOffset: 0x0
512             Size:          0x1
513             Metadata:      0x2
514 )";
515 
516   // Check that we can detect the malformed encoding when the section is
517   // truncated.
518   SmallString<128> TruncatedYamlString(CommonVersionedYamlString);
519   TruncatedYamlString += R"(
520     ShSize: 0xa
521 )";
522   DoCheck(TruncatedYamlString, "unable to decode LEB128 at offset 0x0000000a: "
523                                "malformed uleb128, extends past end");
524 
525   // Check that we can detect when the encoded BB entry fields exceed the UINT32
526   // limit.
527   SmallVector<SmallString<128>, 3> OverInt32LimitYamlStrings(
528       3, CommonVersionedYamlString);
529   OverInt32LimitYamlStrings[0] += R"(
530           - AddressOffset: 0x100000000
531             Size:          0xFFFFFFFF
532             Metadata:      0xFFFFFFFF
533 )";
534 
535   OverInt32LimitYamlStrings[1] += R"(
536           - AddressOffset: 0xFFFFFFFF
537             Size:          0x100000000
538             Metadata:      0xFFFFFFFF
539 )";
540 
541   OverInt32LimitYamlStrings[2] += R"(
542           - AddressOffset: 0xFFFFFFFF
543             Size:          0xFFFFFFFF
544             Metadata:      0x100000000
545 )";
546 
547   DoCheck(OverInt32LimitYamlStrings[0],
548           "ULEB128 value at offset 0xe exceeds UINT32_MAX (0x100000000)");
549   DoCheck(OverInt32LimitYamlStrings[1],
550           "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)");
551   DoCheck(OverInt32LimitYamlStrings[2],
552           "ULEB128 value at offset 0x18 exceeds UINT32_MAX (0x100000000)");
553 
554   // Check the proper error handling when the section has fields exceeding
555   // UINT32 and is also truncated. This is for checking that we don't generate
556   // unhandled errors.
557   SmallVector<SmallString<128>, 3> OverInt32LimitAndTruncated(
558       3, OverInt32LimitYamlStrings[1]);
559   // Truncate before the end of the 5-byte field.
560   OverInt32LimitAndTruncated[0] += R"(
561     ShSize: 0x17
562 )";
563   // Truncate at the end of the 5-byte field.
564   OverInt32LimitAndTruncated[1] += R"(
565     ShSize: 0x18
566 )";
567   // Truncate after the end of the 5-byte field.
568   OverInt32LimitAndTruncated[2] += R"(
569     ShSize: 0x19
570 )";
571 
572   DoCheck(OverInt32LimitAndTruncated[0],
573           "unable to decode LEB128 at offset 0x00000013: malformed uleb128, "
574           "extends past end");
575   DoCheck(OverInt32LimitAndTruncated[1],
576           "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)");
577   DoCheck(OverInt32LimitAndTruncated[2],
578           "ULEB128 value at offset 0x13 exceeds UINT32_MAX (0x100000000)");
579 
580   // Check for proper error handling when the 'NumBlocks' field is overridden
581   // with an out-of-range value.
582   SmallString<128> OverLimitNumBlocks(CommonVersionedYamlString);
583   OverLimitNumBlocks += R"(
584         NumBlocks: 0x100000000
585 )";
586 
587   DoCheck(OverLimitNumBlocks,
588           "ULEB128 value at offset 0xa exceeds UINT32_MAX (0x100000000)");
589 }
590 
591 // Test for the ELFObjectFile::readBBAddrMap API.
592 TEST(ELFObjectFileTest, ReadBBAddrMap) {
593   StringRef CommonYamlString(R"(
594 --- !ELF
595 FileHeader:
596   Class: ELFCLASS64
597   Data:  ELFDATA2LSB
598   Type:  ET_EXEC
599 Sections:
600   - Name: .llvm_bb_addr_map_1
601     Type: SHT_LLVM_BB_ADDR_MAP
602     Link: 1
603     Entries:
604       - Version: 1
605         Address: 0x11111
606         BBEntries:
607           - AddressOffset: 0x0
608             Size:          0x1
609             Metadata:      0x2
610   - Name: .llvm_bb_addr_map_2
611     Type: SHT_LLVM_BB_ADDR_MAP
612     Link: 1
613     Entries:
614       - Version: 1
615         Address: 0x22222
616         BBEntries:
617           - AddressOffset: 0x0
618             Size:          0x2
619             Metadata:      0x4
620   - Name: .llvm_bb_addr_map
621     Type: SHT_LLVM_BB_ADDR_MAP_V0
622   # Link: 0 (by default)
623     Entries:
624       - Version: 0
625         Address: 0x33333
626         BBEntries:
627           - AddressOffset: 0x0
628             Size:          0x3
629             Metadata:      0x6
630 )");
631 
632   BBAddrMap E1 = {0x11111, {{0x0, 0x1, 0x2}}};
633   BBAddrMap E2 = {0x22222, {{0x0, 0x2, 0x4}}};
634   BBAddrMap E3 = {0x33333, {{0x0, 0x3, 0x6}}};
635 
636   std::vector<BBAddrMap> Section0BBAddrMaps = {E3};
637   std::vector<BBAddrMap> Section1BBAddrMaps = {E1, E2};
638   std::vector<BBAddrMap> AllBBAddrMaps = {E1, E2, E3};
639 
640   auto DoCheckSucceeds = [&](StringRef YamlString,
641                              std::optional<unsigned> TextSectionIndex,
642                              std::vector<BBAddrMap> ExpectedResult) {
643     SmallString<0> Storage;
644     Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
645         toBinary<ELF64LE>(Storage, YamlString);
646     ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
647 
648     Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
649         ElfOrErr->getELFFile().getSection(1);
650     ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
651     auto BBAddrMaps = ElfOrErr->readBBAddrMap(TextSectionIndex);
652     EXPECT_THAT_EXPECTED(BBAddrMaps, Succeeded());
653     EXPECT_EQ(*BBAddrMaps, ExpectedResult);
654   };
655 
656   auto DoCheckFails = [&](StringRef YamlString,
657                           std::optional<unsigned> TextSectionIndex,
658                           const char *ErrMsg) {
659     SmallString<0> Storage;
660     Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
661         toBinary<ELF64LE>(Storage, YamlString);
662     ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
663 
664     Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
665         ElfOrErr->getELFFile().getSection(1);
666     ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
667     EXPECT_THAT_ERROR(ElfOrErr->readBBAddrMap(TextSectionIndex).takeError(),
668                       FailedWithMessage(ErrMsg));
669   };
670 
671   // Check that we can retrieve the data in the normal case.
672   DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/std::nullopt,
673                   AllBBAddrMaps);
674   DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/0, Section0BBAddrMaps);
675   DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/1, Section1BBAddrMaps);
676   // Check that when no bb-address-map section is found for a text section,
677   // we return an empty result.
678   DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/2, {});
679 
680   // Check that we detect when a bb-addr-map section is linked to an invalid
681   // (not present) section.
682   SmallString<128> InvalidLinkedYamlString(CommonYamlString);
683   InvalidLinkedYamlString += R"(
684     Link: 10
685 )";
686 
687   DoCheckFails(InvalidLinkedYamlString, /*TextSectionIndex=*/1,
688                "unable to get the linked-to section for "
689                "SHT_LLVM_BB_ADDR_MAP_V0 section with index 3: invalid section "
690                "index: 10");
691   // Linked sections are not checked when we don't target a specific text
692   // section.
693   DoCheckSucceeds(InvalidLinkedYamlString, /*TextSectionIndex=*/std::nullopt,
694                   AllBBAddrMaps);
695 
696   // Check that we can detect when bb-address-map decoding fails.
697   SmallString<128> TruncatedYamlString(CommonYamlString);
698   TruncatedYamlString += R"(
699     ShSize: 0x8
700 )";
701 
702   DoCheckFails(TruncatedYamlString, /*TextSectionIndex=*/std::nullopt,
703                "unable to read SHT_LLVM_BB_ADDR_MAP_V0 section with index 3: "
704                "unable to decode LEB128 at offset 0x00000008: malformed "
705                "uleb128, extends past end");
706   // Check that we can read the other section's bb-address-maps which are
707   // valid.
708   DoCheckSucceeds(TruncatedYamlString, /*TextSectionIndex=*/1,
709                   Section1BBAddrMaps);
710 }
711 
712 // Test for ObjectFile::getRelocatedSection: check that it returns a relocated
713 // section for executable and relocatable files.
714 TEST(ELFObjectFileTest, ExecutableWithRelocs) {
715   StringRef HeaderString(R"(
716 --- !ELF
717 FileHeader:
718   Class: ELFCLASS64
719   Data:  ELFDATA2LSB
720 )");
721   StringRef ContentsString(R"(
722 Sections:
723   - Name:  .text
724     Type:  SHT_PROGBITS
725     Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
726   - Name:  .rela.text
727     Type:  SHT_RELA
728     Flags: [ SHF_INFO_LINK ]
729     Info:  .text
730 )");
731 
732   auto DoCheck = [&](StringRef YamlString) {
733     SmallString<0> Storage;
734     Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
735         toBinary<ELF64LE>(Storage, YamlString);
736     ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
737     const ELFObjectFile<ELF64LE> &Obj = *ElfOrErr;
738 
739     bool FoundRela;
740 
741     for (SectionRef Sec : Obj.sections()) {
742       Expected<StringRef> SecNameOrErr = Sec.getName();
743       ASSERT_THAT_EXPECTED(SecNameOrErr, Succeeded());
744       StringRef SecName = *SecNameOrErr;
745       if (SecName != ".rela.text")
746         continue;
747       FoundRela = true;
748       Expected<section_iterator> RelSecOrErr = Sec.getRelocatedSection();
749       ASSERT_THAT_EXPECTED(RelSecOrErr, Succeeded());
750       section_iterator RelSec = *RelSecOrErr;
751       ASSERT_NE(RelSec, Obj.section_end());
752       Expected<StringRef> TextSecNameOrErr = RelSec->getName();
753       ASSERT_THAT_EXPECTED(TextSecNameOrErr, Succeeded());
754       StringRef TextSecName = *TextSecNameOrErr;
755       EXPECT_EQ(TextSecName, ".text");
756     }
757     ASSERT_TRUE(FoundRela);
758   };
759 
760   // Check ET_EXEC file (`ld --emit-relocs` use-case).
761   SmallString<128> ExecFileYamlString(HeaderString);
762   ExecFileYamlString += R"(
763   Type:  ET_EXEC
764 )";
765   ExecFileYamlString += ContentsString;
766   DoCheck(ExecFileYamlString);
767 
768   // Check ET_REL file.
769   SmallString<128> RelocatableFileYamlString(HeaderString);
770   RelocatableFileYamlString += R"(
771   Type:  ET_REL
772 )";
773   RelocatableFileYamlString += ContentsString;
774   DoCheck(RelocatableFileYamlString);
775 }
776