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/BlockFrequency.h"
13#include "llvm/Support/MemoryBuffer.h"
14#include "llvm/Support/YAMLTraits.h"
15#include "llvm/Testing/Support/Error.h"
16#include "gtest/gtest.h"
17
18#include "llvm/Support/thread.h"
19#include "llvm/TargetParser/Host.h"
20
21using namespace llvm;
22using namespace llvm::object;
23
24namespace {
25
26// A struct to initialize a buffer to represent an ELF object file.
27struct DataForTest {
28 std::vector<uint8_t> Data;
29
30 template <typename T>
31 std::vector<uint8_t> makeElfData(uint8_t Class, uint8_t Encoding,
32 uint16_t Machine, uint8_t OS,
33 uint16_t Flags) {
34 T Ehdr{}; // Zero-initialise the header.
35 Ehdr.e_ident[ELF::EI_MAG0] = 0x7f;
36 Ehdr.e_ident[ELF::EI_MAG1] = 'E';
37 Ehdr.e_ident[ELF::EI_MAG2] = 'L';
38 Ehdr.e_ident[ELF::EI_MAG3] = 'F';
39 Ehdr.e_ident[ELF::EI_CLASS] = Class;
40 Ehdr.e_ident[ELF::EI_DATA] = Encoding;
41 Ehdr.e_ident[ELF::EI_VERSION] = 1;
42 Ehdr.e_ident[ELF::EI_OSABI] = OS;
43 Ehdr.e_type = ELF::ET_REL;
44 Ehdr.e_machine = Machine;
45 Ehdr.e_version = 1;
46 Ehdr.e_flags = Flags;
47 Ehdr.e_ehsize = sizeof(T);
48
49 bool IsLittleEndian = Encoding == ELF::ELFDATA2LSB;
50 if (sys::IsLittleEndianHost != IsLittleEndian) {
51 sys::swapByteOrder(Ehdr.e_type);
52 sys::swapByteOrder(Ehdr.e_machine);
53 sys::swapByteOrder(Ehdr.e_version);
54 sys::swapByteOrder(Ehdr.e_ehsize);
55 }
56
57 uint8_t *EhdrBytes = reinterpret_cast<uint8_t *>(&Ehdr);
58 std::vector<uint8_t> Bytes;
59 std::copy(first: EhdrBytes, last: EhdrBytes + sizeof(Ehdr), result: std::back_inserter(x&: Bytes));
60 return Bytes;
61 }
62
63 DataForTest(uint8_t Class, uint8_t Encoding, uint16_t Machine,
64 uint8_t OS = ELF::ELFOSABI_NONE, uint16_t Flags = 0) {
65 if (Class == ELF::ELFCLASS64)
66 Data = makeElfData<ELF::Elf64_Ehdr>(Class, Encoding, Machine, OS, Flags);
67 else {
68 assert(Class == ELF::ELFCLASS32);
69 Data = makeElfData<ELF::Elf32_Ehdr>(Class, Encoding, Machine, OS, Flags);
70 }
71 }
72};
73
74void checkFormatAndArch(const DataForTest &D, StringRef Fmt,
75 Triple::ArchType Arch) {
76 Expected<std::unique_ptr<ObjectFile>> ELFObjOrErr =
77 object::ObjectFile::createELFObjectFile(
78 Object: MemoryBufferRef(toStringRef(Input: D.Data), "dummyELF"));
79 ASSERT_THAT_EXPECTED(ELFObjOrErr, Succeeded());
80
81 const ObjectFile &File = *(*ELFObjOrErr).get();
82 EXPECT_EQ(Fmt, File.getFileFormatName());
83 EXPECT_EQ(Arch, File.getArch());
84}
85
86std::array<DataForTest, 4> generateData(uint16_t Machine) {
87 return {DataForTest(ELF::ELFCLASS32, ELF::ELFDATA2LSB, Machine),
88 DataForTest(ELF::ELFCLASS32, ELF::ELFDATA2MSB, Machine),
89 DataForTest(ELF::ELFCLASS64, ELF::ELFDATA2LSB, Machine),
90 DataForTest(ELF::ELFCLASS64, ELF::ELFDATA2MSB, Machine)};
91}
92
93} // namespace
94
95TEST(ELFObjectFileTest, MachineTestForNoneOrUnused) {
96 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
97 "elf64-unknown", "elf64-unknown"};
98 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_NONE)))
99 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::UnknownArch);
100
101 // Test an arbitrary unused EM_* value (255).
102 for (auto [Idx, Data] : enumerate(First: generateData(Machine: 255)))
103 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::UnknownArch);
104}
105
106TEST(ELFObjectFileTest, MachineTestForVE) {
107 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
108 "elf64-ve", "elf64-ve"};
109 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_VE)))
110 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::ve);
111}
112
113TEST(ELFObjectFileTest, MachineTestForX86_64) {
114 std::array<StringRef, 4> Formats = {"elf32-x86-64", "elf32-x86-64",
115 "elf64-x86-64", "elf64-x86-64"};
116 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_X86_64)))
117 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::x86_64);
118}
119
120TEST(ELFObjectFileTest, MachineTestFor386) {
121 std::array<StringRef, 4> Formats = {"elf32-i386", "elf32-i386", "elf64-i386",
122 "elf64-i386"};
123 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_386)))
124 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::x86);
125}
126
127TEST(ELFObjectFileTest, MachineTestForMIPS) {
128 std::array<StringRef, 4> Formats = {"elf32-mips", "elf32-mips", "elf64-mips",
129 "elf64-mips"};
130 std::array<Triple::ArchType, 4> Archs = {Triple::mipsel, Triple::mips,
131 Triple::mips64el, Triple::mips64};
132 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_MIPS)))
133 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
134}
135
136TEST(ELFObjectFileTest, MachineTestForAMDGPU) {
137 std::array<StringRef, 4> Formats = {"elf32-amdgpu", "elf32-amdgpu",
138 "elf64-amdgpu", "elf64-amdgpu"};
139 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_AMDGPU)))
140 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::UnknownArch);
141}
142
143TEST(ELFObjectFileTest, MachineTestForIAMCU) {
144 std::array<StringRef, 4> Formats = {"elf32-iamcu", "elf32-iamcu",
145 "elf64-unknown", "elf64-unknown"};
146 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_IAMCU)))
147 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::x86);
148}
149
150TEST(ELFObjectFileTest, MachineTestForAARCH64) {
151 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
152 "elf64-littleaarch64",
153 "elf64-bigaarch64"};
154 std::array<Triple::ArchType, 4> Archs = {Triple::aarch64, Triple::aarch64_be,
155 Triple::aarch64, Triple::aarch64_be};
156 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_AARCH64)))
157 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
158}
159
160TEST(ELFObjectFileTest, MachineTestForPPC64) {
161 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
162 "elf64-powerpcle", "elf64-powerpc"};
163 std::array<Triple::ArchType, 4> Archs = {Triple::ppc64le, Triple::ppc64,
164 Triple::ppc64le, Triple::ppc64};
165 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_PPC64)))
166 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
167}
168
169TEST(ELFObjectFileTest, MachineTestForPPC) {
170 std::array<StringRef, 4> Formats = {"elf32-powerpcle", "elf32-powerpc",
171 "elf64-unknown", "elf64-unknown"};
172 std::array<Triple::ArchType, 4> Archs = {Triple::ppcle, Triple::ppc,
173 Triple::ppcle, Triple::ppc};
174 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_PPC)))
175 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
176}
177
178TEST(ELFObjectFileTest, MachineTestForRISCV) {
179 std::array<StringRef, 4> Formats = {"elf32-littleriscv", "elf32-littleriscv",
180 "elf64-littleriscv", "elf64-littleriscv"};
181 std::array<Triple::ArchType, 4> Archs = {Triple::riscv32, Triple::riscv32,
182 Triple::riscv64, Triple::riscv64};
183 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_RISCV)))
184 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
185}
186
187TEST(ELFObjectFileTest, MachineTestForARM) {
188 std::array<StringRef, 4> Formats = {"elf32-littlearm", "elf32-bigarm",
189 "elf64-unknown", "elf64-unknown"};
190 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_ARM)))
191 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::arm);
192}
193
194TEST(ELFObjectFileTest, MachineTestForS390) {
195 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
196 "elf64-s390", "elf64-s390"};
197 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_S390)))
198 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::systemz);
199}
200
201TEST(ELFObjectFileTest, MachineTestForSPARCV9) {
202 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
203 "elf64-sparc", "elf64-sparc"};
204 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_SPARCV9)))
205 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::sparcv9);
206}
207
208TEST(ELFObjectFileTest, MachineTestForSPARC) {
209 std::array<StringRef, 4> Formats = {"elf32-sparc", "elf32-sparc",
210 "elf64-unknown", "elf64-unknown"};
211 std::array<Triple::ArchType, 4> Archs = {Triple::sparcel, Triple::sparc,
212 Triple::sparcel, Triple::sparc};
213 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_SPARC)))
214 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
215}
216
217TEST(ELFObjectFileTest, MachineTestForSPARC32PLUS) {
218 std::array<StringRef, 4> Formats = {"elf32-sparc", "elf32-sparc",
219 "elf64-unknown", "elf64-unknown"};
220 std::array<Triple::ArchType, 4> Archs = {Triple::sparcel, Triple::sparc,
221 Triple::sparcel, Triple::sparc};
222 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_SPARC32PLUS)))
223 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
224}
225
226TEST(ELFObjectFileTest, MachineTestForBPF) {
227 std::array<StringRef, 4> Formats = {"elf32-unknown", "elf32-unknown",
228 "elf64-bpf", "elf64-bpf"};
229 std::array<Triple::ArchType, 4> Archs = {Triple::bpfel, Triple::bpfeb,
230 Triple::bpfel, Triple::bpfeb};
231 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_BPF)))
232 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
233}
234
235TEST(ELFObjectFileTest, MachineTestForAVR) {
236 std::array<StringRef, 4> Formats = {"elf32-avr", "elf32-avr", "elf64-unknown",
237 "elf64-unknown"};
238 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_AVR)))
239 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::avr);
240}
241
242TEST(ELFObjectFileTest, MachineTestForHEXAGON) {
243 std::array<StringRef, 4> Formats = {"elf32-hexagon", "elf32-hexagon",
244 "elf64-unknown", "elf64-unknown"};
245 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_HEXAGON)))
246 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::hexagon);
247}
248
249TEST(ELFObjectFileTest, MachineTestForLANAI) {
250 std::array<StringRef, 4> Formats = {"elf32-lanai", "elf32-lanai",
251 "elf64-unknown", "elf64-unknown"};
252 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_LANAI)))
253 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::lanai);
254}
255
256TEST(ELFObjectFileTest, MachineTestForMSP430) {
257 std::array<StringRef, 4> Formats = {"elf32-msp430", "elf32-msp430",
258 "elf64-unknown", "elf64-unknown"};
259 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_MSP430)))
260 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::msp430);
261}
262
263TEST(ELFObjectFileTest, MachineTestForLoongArch) {
264 std::array<StringRef, 4> Formats = {"elf32-loongarch", "elf32-loongarch",
265 "elf64-loongarch", "elf64-loongarch"};
266 std::array<Triple::ArchType, 4> Archs = {
267 Triple::loongarch32, Triple::loongarch32, Triple::loongarch64,
268 Triple::loongarch64};
269 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_LOONGARCH)))
270 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Archs[Idx]);
271}
272
273TEST(ELFObjectFileTest, MachineTestForCSKY) {
274 std::array<StringRef, 4> Formats = {"elf32-csky", "elf32-csky",
275 "elf64-unknown", "elf64-unknown"};
276 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_CSKY)))
277 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::csky);
278}
279
280TEST(ELFObjectFileTest, MachineTestForXtensa) {
281 std::array<StringRef, 4> Formats = {"elf32-xtensa", "elf32-xtensa",
282 "elf64-unknown", "elf64-unknown"};
283 for (auto [Idx, Data] : enumerate(First: generateData(Machine: ELF::EM_XTENSA)))
284 checkFormatAndArch(D: Data, Fmt: Formats[Idx], Arch: Triple::xtensa);
285}
286
287TEST(ELFObjectFileTest, CheckOSAndTriple) {
288 std::tuple<uint16_t, uint8_t, StringRef> Formats[] = {
289 {ELF::EM_AMDGPU, ELF::ELFOSABI_AMDGPU_HSA, "amdgcn-amd-amdhsa"},
290 {ELF::EM_X86_64, ELF::ELFOSABI_LINUX, "x86_64--linux"},
291 {ELF::EM_X86_64, ELF::ELFOSABI_NETBSD, "x86_64--netbsd"},
292 {ELF::EM_X86_64, ELF::ELFOSABI_HURD, "x86_64--hurd"},
293 {ELF::EM_X86_64, ELF::ELFOSABI_SOLARIS, "x86_64--solaris"},
294 {ELF::EM_X86_64, ELF::ELFOSABI_AIX, "x86_64--aix"},
295 {ELF::EM_X86_64, ELF::ELFOSABI_FREEBSD, "x86_64--freebsd"},
296 {ELF::EM_X86_64, ELF::ELFOSABI_OPENBSD, "x86_64--openbsd"},
297 {ELF::EM_CUDA, ELF::ELFOSABI_CUDA, "nvptx64-nvidia-cuda"}};
298 for (auto [Machine, OS, Triple] : Formats) {
299 const DataForTest D(ELF::ELFCLASS64, ELF::ELFDATA2LSB, Machine, OS,
300 ELF::EF_AMDGPU_MACH_AMDGCN_LAST);
301 Expected<ELF64LEObjectFile> ELFObjOrErr = ELF64LEObjectFile::create(
302 Object: MemoryBufferRef(toStringRef(Input: D.Data), "dummyELF"));
303 ASSERT_THAT_EXPECTED(ELFObjOrErr, Succeeded());
304
305 auto &ELFObj = *ELFObjOrErr;
306 llvm::Triple TheTriple = ELFObj.makeTriple();
307
308 // The AMDGPU architecture will be unknown on big-endian testers.
309 if (TheTriple.getArch() == Triple::UnknownArch)
310 continue;
311
312 EXPECT_EQ(Triple, TheTriple.getTriple());
313 }
314}
315
316// ELF relative relocation type test.
317TEST(ELFObjectFileTest, RelativeRelocationTypeTest) {
318 EXPECT_EQ(ELF::R_CKCORE_RELATIVE, getELFRelativeRelocationType(ELF::EM_CSKY));
319}
320
321template <class ELFT>
322static Expected<ELFObjectFile<ELFT>> toBinary(SmallVectorImpl<char> &Storage,
323 StringRef Yaml) {
324 raw_svector_ostream OS(Storage);
325 yaml::Input YIn(Yaml);
326 if (!yaml::convertYAML(YIn, Out&: OS, ErrHandler: [](const Twine &Msg) {}))
327 return createStringError(EC: std::errc::invalid_argument,
328 Fmt: "unable to convert YAML");
329 return ELFObjectFile<ELFT>::create(MemoryBufferRef(OS.str(), "dummyELF"));
330}
331
332// Check we are able to create an ELFObjectFile even when the content of the
333// SHT_SYMTAB_SHNDX section can't be read properly.
334TEST(ELFObjectFileTest, InvalidSymtabShndxTest) {
335 SmallString<0> Storage;
336 Expected<ELFObjectFile<ELF64LE>> ExpectedFile = toBinary<ELF64LE>(Storage, Yaml: R"(
337--- !ELF
338FileHeader:
339 Class: ELFCLASS64
340 Data: ELFDATA2LSB
341 Type: ET_REL
342Sections:
343 - Name: .symtab_shndx
344 Type: SHT_SYMTAB_SHNDX
345 Entries: [ 0 ]
346 ShSize: 0xFFFFFFFF
347)");
348
349 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
350}
351
352// Test that we are able to create an ELFObjectFile even when loadable segments
353// are unsorted by virtual address.
354// Test that ELFFile<ELFT>::toMappedAddr works properly in this case.
355
356TEST(ELFObjectFileTest, InvalidLoadSegmentsOrderTest) {
357 SmallString<0> Storage;
358 Expected<ELFObjectFile<ELF64LE>> ExpectedFile = toBinary<ELF64LE>(Storage, Yaml: R"(
359--- !ELF
360FileHeader:
361 Class: ELFCLASS64
362 Data: ELFDATA2LSB
363 Type: ET_EXEC
364Sections:
365 - Name: .foo
366 Type: SHT_PROGBITS
367 Address: 0x1000
368 Offset: 0x3000
369 ContentArray: [ 0x11 ]
370 - Name: .bar
371 Type: SHT_PROGBITS
372 Address: 0x2000
373 Offset: 0x4000
374 ContentArray: [ 0x99 ]
375ProgramHeaders:
376 - Type: PT_LOAD
377 VAddr: 0x2000
378 FirstSec: .bar
379 LastSec: .bar
380 - Type: PT_LOAD
381 VAddr: 0x1000
382 FirstSec: .foo
383 LastSec: .foo
384)");
385
386 ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
387
388 std::string WarnString;
389 auto ToMappedAddr = [&](uint64_t Addr) -> const uint8_t * {
390 Expected<const uint8_t *> DataOrErr =
391 ExpectedFile->getELFFile().toMappedAddr(VAddr: Addr, WarnHandler: [&](const Twine &Msg) {
392 EXPECT_TRUE(WarnString.empty());
393 WarnString = Msg.str();
394 return Error::success();
395 });
396
397 if (!DataOrErr) {
398 ADD_FAILURE() << toString(E: DataOrErr.takeError());
399 return nullptr;
400 }
401
402 EXPECT_TRUE(WarnString ==
403 "loadable segments are unsorted by virtual address");
404 WarnString = "";
405 return *DataOrErr;
406 };
407
408 const uint8_t *Data = ToMappedAddr(0x1000);
409 ASSERT_TRUE(Data);
410 MemoryBufferRef Buf = ExpectedFile->getMemoryBufferRef();
411 EXPECT_EQ((const char *)Data - Buf.getBufferStart(), 0x3000);
412 EXPECT_EQ(Data[0], 0x11);
413
414 Data = ToMappedAddr(0x2000);
415 ASSERT_TRUE(Data);
416 Buf = ExpectedFile->getMemoryBufferRef();
417 EXPECT_EQ((const char *)Data - Buf.getBufferStart(), 0x4000);
418 EXPECT_EQ(Data[0], 0x99);
419}
420
421// This is a test for API that is related to symbols.
422// We check that errors are properly reported here.
423TEST(ELFObjectFileTest, InvalidSymbolTest) {
424 SmallString<0> Storage;
425 Expected<ELFObjectFile<ELF64LE>> ElfOrErr = toBinary<ELF64LE>(Storage, Yaml: R"(
426--- !ELF
427FileHeader:
428 Class: ELFCLASS64
429 Data: ELFDATA2LSB
430 Type: ET_DYN
431 Machine: EM_X86_64
432Sections:
433 - Name: .symtab
434 Type: SHT_SYMTAB
435)");
436
437 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
438 const ELFFile<ELF64LE> &Elf = ElfOrErr->getELFFile();
439 const ELFObjectFile<ELF64LE> &Obj = *ElfOrErr;
440
441 Expected<const typename ELF64LE::Shdr *> SymtabSecOrErr = Elf.getSection(Index: 1);
442 ASSERT_THAT_EXPECTED(SymtabSecOrErr, Succeeded());
443 ASSERT_EQ((*SymtabSecOrErr)->sh_type, ELF::SHT_SYMTAB);
444
445 auto DoCheck = [&](unsigned BrokenSymIndex, const char *ErrMsg) {
446 ELFSymbolRef BrokenSym = Obj.toSymbolRef(SymTable: *SymtabSecOrErr, SymbolNum: BrokenSymIndex);
447
448 // 1) Check the behavior of ELFObjectFile<ELFT>::getSymbolName().
449 // SymbolRef::getName() calls it internally. We can't test it directly,
450 // because it is protected.
451 EXPECT_THAT_ERROR(BrokenSym.getName().takeError(),
452 FailedWithMessage(ErrMsg));
453
454 // 2) Check the behavior of ELFObjectFile<ELFT>::getSymbol().
455 EXPECT_THAT_ERROR(Obj.getSymbol(BrokenSym.getRawDataRefImpl()).takeError(),
456 FailedWithMessage(ErrMsg));
457
458 // 3) Check the behavior of ELFObjectFile<ELFT>::getSymbolSection().
459 // SymbolRef::getSection() calls it internally. We can't test it
460 // directly, because it is protected.
461 EXPECT_THAT_ERROR(BrokenSym.getSection().takeError(),
462 FailedWithMessage(ErrMsg));
463
464 // 4) Check the behavior of ELFObjectFile<ELFT>::getSymbolFlags().
465 // SymbolRef::getFlags() calls it internally. We can't test it directly,
466 // because it is protected.
467 EXPECT_THAT_ERROR(BrokenSym.getFlags().takeError(),
468 FailedWithMessage(ErrMsg));
469
470 // 5) Check the behavior of ELFObjectFile<ELFT>::getSymbolType().
471 // SymbolRef::getType() calls it internally. We can't test it directly,
472 // because it is protected.
473 EXPECT_THAT_ERROR(BrokenSym.getType().takeError(),
474 FailedWithMessage(ErrMsg));
475
476 // 6) Check the behavior of ELFObjectFile<ELFT>::getSymbolAddress().
477 // SymbolRef::getAddress() calls it internally. We can't test it
478 // directly, because it is protected.
479 EXPECT_THAT_ERROR(BrokenSym.getAddress().takeError(),
480 FailedWithMessage(ErrMsg));
481
482 // Finally, check the `ELFFile<ELFT>::getEntry` API. This is an underlying
483 // method that generates errors for all cases above.
484 EXPECT_THAT_EXPECTED(
485 Elf.getEntry<typename ELF64LE::Sym>(**SymtabSecOrErr, 0), Succeeded());
486 EXPECT_THAT_ERROR(
487 Elf.getEntry<typename ELF64LE::Sym>(**SymtabSecOrErr, BrokenSymIndex)
488 .takeError(),
489 FailedWithMessage(ErrMsg));
490 };
491
492 // We create a symbol with an index that is too large to exist in the symbol
493 // table.
494 DoCheck(0x1, "can't read an entry at 0x18: it goes past the end of the "
495 "section (0x18)");
496
497 // We create a symbol with an index that is too large to exist in the object.
498 DoCheck(0xFFFFFFFF, "can't read an entry at 0x17ffffffe8: it goes past the "
499 "end of the section (0x18)");
500}
501
502// Tests for error paths of the ELFFile::decodeBBAddrMap API.
503TEST(ELFObjectFileTest, InvalidDecodeBBAddrMap) {
504 StringRef CommonYamlString(R"(
505--- !ELF
506FileHeader:
507 Class: ELFCLASS64
508 Data: ELFDATA2LSB
509 Type: ET_EXEC
510Sections:
511 - Type: SHT_LLVM_BB_ADDR_MAP
512 Name: .llvm_bb_addr_map
513 Entries:
514)");
515
516 auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) {
517 SmallString<0> Storage;
518 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
519 toBinary<ELF64LE>(Storage, Yaml: YamlString);
520 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
521 const ELFFile<ELF64LE> &Elf = ElfOrErr->getELFFile();
522
523 Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
524 Elf.getSection(Index: 1);
525 ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
526 EXPECT_THAT_ERROR(Elf.decodeBBAddrMap(**BBAddrMapSecOrErr).takeError(),
527 FailedWithMessage(ErrMsg));
528 };
529
530 // Check that we can detect unsupported versions.
531 SmallString<128> UnsupportedVersionYamlString(CommonYamlString);
532 UnsupportedVersionYamlString += R"(
533 - Version: 3
534 BBRanges:
535 - BaseAddress: 0x11111
536 BBEntries:
537 - AddressOffset: 0x0
538 Size: 0x1
539 Metadata: 0x2
540)";
541
542 {
543 SCOPED_TRACE("unsupported version");
544 DoCheck(UnsupportedVersionYamlString,
545 "unsupported SHT_LLVM_BB_ADDR_MAP version: 3");
546 }
547
548 SmallString<128> ZeroBBRangesYamlString(CommonYamlString);
549 ZeroBBRangesYamlString += R"(
550 - Version: 2
551 Feature: 0x8
552 BBRanges: []
553)";
554 {
555 SCOPED_TRACE("zero bb ranges");
556 DoCheck(ZeroBBRangesYamlString,
557 "invalid zero number of BB ranges at offset 3 in "
558 "SHT_LLVM_BB_ADDR_MAP section with index 1");
559 }
560
561 SmallString<128> CommonVersionedYamlString(CommonYamlString);
562 CommonVersionedYamlString += R"(
563 - Version: 2
564 BBRanges:
565 - BaseAddress: 0x11111
566 BBEntries:
567 - AddressOffset: 0x0
568 Size: 0x1
569 Metadata: 0x2
570)";
571
572 // Check that we can detect the malformed encoding when the section is
573 // truncated.
574 SmallString<128> TruncatedYamlString(CommonVersionedYamlString);
575 TruncatedYamlString += R"(
576 ShSize: 0xb
577)";
578 {
579 SCOPED_TRACE("truncated section");
580 DoCheck(TruncatedYamlString,
581 "unable to decode LEB128 at offset 0x0000000b: "
582 "malformed uleb128, extends past end");
583 }
584
585 // Check that we can detect when the encoded BB entry fields exceed the UINT32
586 // limit.
587 SmallVector<SmallString<128>, 3> OverInt32LimitYamlStrings(
588 3, CommonVersionedYamlString);
589 OverInt32LimitYamlStrings[0] += R"(
590 - ID: 1
591 AddressOffset: 0x100000000
592 Size: 0xFFFFFFFF
593 Metadata: 0xFFFFFFFF
594)";
595
596 OverInt32LimitYamlStrings[1] += R"(
597 - ID: 2
598 AddressOffset: 0xFFFFFFFF
599 Size: 0x100000000
600 Metadata: 0xFFFFFFFF
601)";
602
603 OverInt32LimitYamlStrings[2] += R"(
604 - ID: 3
605 AddressOffset: 0xFFFFFFFF
606 Size: 0xFFFFFFFF
607 Metadata: 0x100000000
608)";
609
610 {
611 SCOPED_TRACE("overlimit fields");
612 DoCheck(OverInt32LimitYamlStrings[0],
613 "ULEB128 value at offset 0x10 exceeds UINT32_MAX (0x100000000)");
614 DoCheck(OverInt32LimitYamlStrings[1],
615 "ULEB128 value at offset 0x15 exceeds UINT32_MAX (0x100000000)");
616 DoCheck(OverInt32LimitYamlStrings[2],
617 "ULEB128 value at offset 0x1a exceeds UINT32_MAX (0x100000000)");
618 }
619
620 // Check the proper error handling when the section has fields exceeding
621 // UINT32 and is also truncated. This is for checking that we don't generate
622 // unhandled errors.
623 SmallVector<SmallString<128>, 3> OverInt32LimitAndTruncated(
624 3, OverInt32LimitYamlStrings[1]);
625 // Truncate before the end of the 5-byte field.
626 OverInt32LimitAndTruncated[0] += R"(
627 ShSize: 0x19
628)";
629 // Truncate at the end of the 5-byte field.
630 OverInt32LimitAndTruncated[1] += R"(
631 ShSize: 0x1a
632)";
633 // Truncate after the end of the 5-byte field.
634 OverInt32LimitAndTruncated[2] += R"(
635 ShSize: 0x1b
636)";
637
638 {
639 SCOPED_TRACE("overlimit fields, truncated section");
640 DoCheck(OverInt32LimitAndTruncated[0],
641 "unable to decode LEB128 at offset 0x00000015: malformed uleb128, "
642 "extends past end");
643 DoCheck(OverInt32LimitAndTruncated[1],
644 "ULEB128 value at offset 0x15 exceeds UINT32_MAX (0x100000000)");
645 DoCheck(OverInt32LimitAndTruncated[2],
646 "ULEB128 value at offset 0x15 exceeds UINT32_MAX (0x100000000)");
647 }
648
649 // Check for proper error handling when the 'NumBlocks' field is overridden
650 // with an out-of-range value.
651 SmallString<128> OverLimitNumBlocks(CommonVersionedYamlString);
652 OverLimitNumBlocks += R"(
653 NumBlocks: 0x100000000
654)";
655
656 {
657 SCOPED_TRACE("overlimit 'NumBlocks' field");
658 DoCheck(OverLimitNumBlocks,
659 "ULEB128 value at offset 0xa exceeds UINT32_MAX (0x100000000)");
660 }
661
662 // Check for proper error handling when the 'NumBBRanges' field is overridden
663 // with an out-of-range value.
664 SmallString<128> OverLimitNumBBRanges(CommonVersionedYamlString);
665 OverLimitNumBBRanges += R"(
666 NumBBRanges: 0x100000000
667 Feature: 0x8
668)";
669 DoCheck(OverLimitNumBBRanges,
670 "ULEB128 value at offset 0x2 exceeds UINT32_MAX (0x100000000)");
671}
672
673// Test for the ELFObjectFile::readBBAddrMap API.
674TEST(ELFObjectFileTest, ReadBBAddrMap) {
675 StringRef CommonYamlString(R"(
676--- !ELF
677FileHeader:
678 Class: ELFCLASS64
679 Data: ELFDATA2LSB
680 Type: ET_EXEC
681Sections:
682 - Name: .llvm_bb_addr_map_1
683 Type: SHT_LLVM_BB_ADDR_MAP
684 Link: 1
685 Entries:
686 - Version: 2
687 BBRanges:
688 - BaseAddress: 0x11111
689 BBEntries:
690 - ID: 1
691 AddressOffset: 0x0
692 Size: 0x1
693 Metadata: 0x2
694 - Name: .llvm_bb_addr_map_2
695 Type: SHT_LLVM_BB_ADDR_MAP
696 Link: 1
697 Entries:
698 - Version: 2
699 Feature: 0x8
700 BBRanges:
701 - BaseAddress: 0x22222
702 BBEntries:
703 - ID: 2
704 AddressOffset: 0x0
705 Size: 0x2
706 Metadata: 0x4
707 - BaseAddress: 0xFFFFF
708 BBEntries:
709 - ID: 15
710 AddressOffset: 0xF0
711 Size: 0xF1
712 Metadata: 0x1F
713 - Name: .llvm_bb_addr_map_3
714 Type: SHT_LLVM_BB_ADDR_MAP
715 Link: 2
716 Entries:
717 - Version: 1
718 BBRanges:
719 - BaseAddress: 0x33333
720 BBEntries:
721 - ID: 0
722 AddressOffset: 0x0
723 Size: 0x3
724 Metadata: 0x6
725 - Name: .llvm_bb_addr_map_4
726 Type: SHT_LLVM_BB_ADDR_MAP
727 # Link: 0 (by default, can be overriden)
728 Entries:
729 - Version: 2
730 BBRanges:
731 - BaseAddress: 0x44444
732 BBEntries:
733 - ID: 0
734 AddressOffset: 0x0
735 Size: 0x4
736 Metadata: 0x18
737)");
738
739 BBAddrMap E1 = {
740 .BBRanges: {{.BaseAddress: 0x11111, .BBEntries: {{1, 0x0, 0x1, {.HasReturn: false, .HasTailCall: true, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}}}}}};
741 BBAddrMap E2 = {
742 .BBRanges: {{.BaseAddress: 0x22222, .BBEntries: {{2, 0x0, 0x2, {.HasReturn: false, .HasTailCall: false, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}}}},
743 {.BaseAddress: 0xFFFFF, .BBEntries: {{15, 0xF0, 0xF1, {.HasReturn: true, .HasTailCall: true, .IsEHPad: true, .CanFallThrough: true, .HasIndirectBranch: true}}}}}};
744 BBAddrMap E3 = {
745 .BBRanges: {{.BaseAddress: 0x33333, .BBEntries: {{0, 0x0, 0x3, {.HasReturn: false, .HasTailCall: true, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}}}}}};
746 BBAddrMap E4 = {
747 .BBRanges: {{.BaseAddress: 0x44444, .BBEntries: {{0, 0x0, 0x4, {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: true, .HasIndirectBranch: true}}}}}};
748
749 std::vector<BBAddrMap> Section0BBAddrMaps = {E4};
750 std::vector<BBAddrMap> Section1BBAddrMaps = {E3};
751 std::vector<BBAddrMap> Section2BBAddrMaps = {E1, E2};
752 std::vector<BBAddrMap> AllBBAddrMaps = {E1, E2, E3, E4};
753
754 auto DoCheckSucceeds = [&](StringRef YamlString,
755 std::optional<unsigned> TextSectionIndex,
756 std::vector<BBAddrMap> ExpectedResult) {
757 SCOPED_TRACE("for TextSectionIndex: " +
758 (TextSectionIndex ? llvm::Twine(*TextSectionIndex) : "{}") +
759 " and object yaml:\n" + YamlString);
760 SmallString<0> Storage;
761 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
762 toBinary<ELF64LE>(Storage, Yaml: YamlString);
763 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
764
765 Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
766 ElfOrErr->getELFFile().getSection(Index: 1);
767 ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
768 auto BBAddrMaps = ElfOrErr->readBBAddrMap(TextSectionIndex);
769 ASSERT_THAT_EXPECTED(BBAddrMaps, Succeeded());
770 EXPECT_EQ(*BBAddrMaps, ExpectedResult);
771 };
772
773 auto DoCheckFails = [&](StringRef YamlString,
774 std::optional<unsigned> TextSectionIndex,
775 const char *ErrMsg) {
776 SCOPED_TRACE("for TextSectionIndex: " +
777 (TextSectionIndex ? llvm::Twine(*TextSectionIndex) : "{}") +
778 " and object yaml:\n" + YamlString);
779 SmallString<0> Storage;
780 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
781 toBinary<ELF64LE>(Storage, Yaml: YamlString);
782 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
783
784 Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
785 ElfOrErr->getELFFile().getSection(Index: 1);
786 ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
787 EXPECT_THAT_ERROR(ElfOrErr->readBBAddrMap(TextSectionIndex).takeError(),
788 FailedWithMessage(ErrMsg));
789 };
790
791 {
792 SCOPED_TRACE("normal sections");
793 // Check that we can retrieve the data in the normal case.
794 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/std::nullopt,
795 AllBBAddrMaps);
796 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/0,
797 Section0BBAddrMaps);
798 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/2,
799 Section1BBAddrMaps);
800 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/1,
801 Section2BBAddrMaps);
802 // Check that when no bb-address-map section is found for a text section,
803 // we return an empty result.
804 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/3, {});
805 }
806
807 // Check that we detect when a bb-addr-map section is linked to an invalid
808 // (not present) section.
809 SmallString<128> InvalidLinkedYamlString(CommonYamlString);
810 InvalidLinkedYamlString += R"(
811 Link: 121
812)";
813
814 DoCheckFails(InvalidLinkedYamlString, /*TextSectionIndex=*/4,
815 "unable to get the linked-to section for "
816 "SHT_LLVM_BB_ADDR_MAP section with index 4: invalid section "
817 "index: 121");
818 {
819 SCOPED_TRACE("invalid linked section");
820 // Linked sections are not checked when we don't target a specific text
821 // section.
822 DoCheckSucceeds(InvalidLinkedYamlString, /*TextSectionIndex=*/std::nullopt,
823 AllBBAddrMaps);
824 }
825
826 // Check that we can detect when bb-address-map decoding fails.
827 SmallString<128> TruncatedYamlString(CommonYamlString);
828 TruncatedYamlString += R"(
829 ShSize: 0xa
830)";
831
832 {
833 SCOPED_TRACE("truncated section");
834 DoCheckFails(TruncatedYamlString, /*TextSectionIndex=*/std::nullopt,
835 "unable to read SHT_LLVM_BB_ADDR_MAP section with index 4: "
836 "unable to decode LEB128 at offset 0x0000000a: malformed "
837 "uleb128, extends past end");
838
839 // Check that we can read the other section's bb-address-maps which are
840 // valid.
841 DoCheckSucceeds(TruncatedYamlString, /*TextSectionIndex=*/2,
842 Section1BBAddrMaps);
843 }
844}
845
846// Tests for error paths of the ELFFile::decodeBBAddrMap with PGOAnalysisMap
847// API.
848TEST(ELFObjectFileTest, InvalidDecodePGOAnalysisMap) {
849 StringRef CommonYamlString(R"(
850--- !ELF
851FileHeader:
852 Class: ELFCLASS64
853 Data: ELFDATA2LSB
854 Type: ET_EXEC
855Sections:
856 - Type: SHT_LLVM_BB_ADDR_MAP
857 Name: .llvm_bb_addr_map
858 Entries:
859)");
860
861 auto DoCheck = [&](StringRef YamlString, const char *ErrMsg) {
862 SmallString<0> Storage;
863 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
864 toBinary<ELF64LE>(Storage, Yaml: YamlString);
865 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
866 const ELFFile<ELF64LE> &Elf = ElfOrErr->getELFFile();
867
868 Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
869 Elf.getSection(Index: 1);
870 ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
871
872 std::vector<PGOAnalysisMap> PGOAnalyses;
873 EXPECT_THAT_ERROR(
874 Elf.decodeBBAddrMap(**BBAddrMapSecOrErr, nullptr, &PGOAnalyses)
875 .takeError(),
876 FailedWithMessage(ErrMsg));
877 };
878
879 // Check that we can detect unsupported versions that are too old.
880 SmallString<128> UnsupportedLowVersionYamlString(CommonYamlString);
881 UnsupportedLowVersionYamlString += R"(
882 - Version: 1
883 Feature: 0x4
884 BBRanges:
885 - BBEntries:
886 - AddressOffset: 0x0
887 Size: 0x1
888 Metadata: 0x2
889)";
890
891 {
892 SCOPED_TRACE("unsupported version");
893 DoCheck(UnsupportedLowVersionYamlString,
894 "version should be >= 2 for SHT_LLVM_BB_ADDR_MAP when PGO features "
895 "are enabled: version = 1 feature = 4");
896 }
897
898 SmallString<128> CommonVersionedYamlString(CommonYamlString);
899 CommonVersionedYamlString += R"(
900 - Version: 2
901 BBRanges:
902 - BBEntries:
903 - ID: 1
904 AddressOffset: 0x0
905 Size: 0x1
906 Metadata: 0x2
907)";
908
909 // Check that we fail when function entry count is enabled but not provided.
910 SmallString<128> MissingFuncEntryCount(CommonYamlString);
911 MissingFuncEntryCount += R"(
912 - Version: 2
913 Feature: 0x01
914)";
915
916 {
917 SCOPED_TRACE("missing function entry count");
918 DoCheck(MissingFuncEntryCount,
919 "unexpected end of data at offset 0x2 while reading [0x2, 0xa)");
920 }
921
922 // Check that we fail when basic block frequency is enabled but not provided.
923 SmallString<128> MissingBBFreq(CommonYamlString);
924 MissingBBFreq += R"(
925 - Version: 2
926 Feature: 0x02
927 BBRanges:
928 - BBEntries:
929 - ID: 1
930 AddressOffset: 0x0
931 Size: 0x1
932 Metadata: 0x2
933)";
934
935 {
936 SCOPED_TRACE("missing bb frequency");
937 DoCheck(MissingBBFreq, "unable to decode LEB128 at offset 0x0000000f: "
938 "malformed uleb128, extends past end");
939 }
940
941 // Check that we fail when branch probability is enabled but not provided.
942 SmallString<128> MissingBrProb(CommonYamlString);
943 MissingBrProb += R"(
944 - Version: 2
945 Feature: 0x04
946 BBRanges:
947 - BBEntries:
948 - ID: 1
949 AddressOffset: 0x0
950 Size: 0x1
951 Metadata: 0x6
952 - ID: 2
953 AddressOffset: 0x1
954 Size: 0x1
955 Metadata: 0x2
956 - ID: 3
957 AddressOffset: 0x2
958 Size: 0x1
959 Metadata: 0x2
960 PGOAnalyses:
961 - PGOBBEntries:
962 - Successors:
963 - ID: 2
964 BrProb: 0x80000000
965 - ID: 3
966 BrProb: 0x80000000
967 - Successors:
968 - ID: 3
969 BrProb: 0xF0000000
970)";
971
972 {
973 SCOPED_TRACE("missing branch probability");
974 DoCheck(MissingBrProb, "unable to decode LEB128 at offset 0x00000017: "
975 "malformed uleb128, extends past end");
976 }
977}
978
979// Test for the ELFObjectFile::readBBAddrMap API with PGOAnalysisMap.
980TEST(ELFObjectFileTest, ReadPGOAnalysisMap) {
981 StringRef CommonYamlString(R"(
982--- !ELF
983FileHeader:
984 Class: ELFCLASS64
985 Data: ELFDATA2LSB
986 Type: ET_EXEC
987Sections:
988 - Name: .llvm_bb_addr_map_1
989 Type: SHT_LLVM_BB_ADDR_MAP
990 Link: 1
991 Entries:
992 - Version: 2
993 Feature: 0x1
994 BBRanges:
995 - BaseAddress: 0x11111
996 BBEntries:
997 - ID: 1
998 AddressOffset: 0x0
999 Size: 0x1
1000 Metadata: 0x2
1001 PGOAnalyses:
1002 - FuncEntryCount: 892
1003 - Name: .llvm_bb_addr_map_2
1004 Type: SHT_LLVM_BB_ADDR_MAP
1005 Link: 1
1006 Entries:
1007 - Version: 2
1008 Feature: 0x2
1009 BBRanges:
1010 - BaseAddress: 0x22222
1011 BBEntries:
1012 - ID: 2
1013 AddressOffset: 0x0
1014 Size: 0x2
1015 Metadata: 0x4
1016 PGOAnalyses:
1017 - PGOBBEntries:
1018 - BBFreq: 343
1019 - Name: .llvm_bb_addr_map_3
1020 Type: SHT_LLVM_BB_ADDR_MAP
1021 Link: 2
1022 Entries:
1023 - Version: 2
1024 Feature: 0x4
1025 BBRanges:
1026 - BaseAddress: 0x33333
1027 BBEntries:
1028 - ID: 0
1029 AddressOffset: 0x0
1030 Size: 0x3
1031 Metadata: 0x6
1032 - ID: 1
1033 AddressOffset: 0x0
1034 Size: 0x3
1035 Metadata: 0x4
1036 - ID: 2
1037 AddressOffset: 0x0
1038 Size: 0x3
1039 Metadata: 0x0
1040 PGOAnalyses:
1041 - PGOBBEntries:
1042 - Successors:
1043 - ID: 1
1044 BrProb: 0x11111111
1045 - ID: 2
1046 BrProb: 0xeeeeeeee
1047 - Successors:
1048 - ID: 2
1049 BrProb: 0xffffffff
1050 - Successors: []
1051 - Name: .llvm_bb_addr_map_4
1052 Type: SHT_LLVM_BB_ADDR_MAP
1053 # Link: 0 (by default, can be overriden)
1054 Entries:
1055 - Version: 2
1056 Feature: 0x7
1057 BBRanges:
1058 - BaseAddress: 0x44444
1059 BBEntries:
1060 - ID: 0
1061 AddressOffset: 0x0
1062 Size: 0x4
1063 Metadata: 0x18
1064 - ID: 1
1065 AddressOffset: 0x0
1066 Size: 0x4
1067 Metadata: 0x0
1068 - ID: 2
1069 AddressOffset: 0x0
1070 Size: 0x4
1071 Metadata: 0x0
1072 - ID: 3
1073 AddressOffset: 0x0
1074 Size: 0x4
1075 Metadata: 0x0
1076 PGOAnalyses:
1077 - FuncEntryCount: 1000
1078 PGOBBEntries:
1079 - BBFreq: 1000
1080 Successors:
1081 - ID: 1
1082 BrProb: 0x22222222
1083 - ID: 2
1084 BrProb: 0x33333333
1085 - ID: 3
1086 BrProb: 0xaaaaaaaa
1087 - BBFreq: 133
1088 Successors:
1089 - ID: 2
1090 BrProb: 0x11111111
1091 - ID: 3
1092 BrProb: 0xeeeeeeee
1093 - BBFreq: 18
1094 Successors:
1095 - ID: 3
1096 BrProb: 0xffffffff
1097 - BBFreq: 1000
1098 Successors: []
1099 - Name: .llvm_bb_addr_map_5
1100 Type: SHT_LLVM_BB_ADDR_MAP
1101 # Link: 0 (by default, can be overriden)
1102 Entries:
1103 - Version: 2
1104 Feature: 0x0
1105 BBRanges:
1106 - BaseAddress: 0x55555
1107 BBEntries:
1108 - ID: 2
1109 AddressOffset: 0x0
1110 Size: 0x2
1111 Metadata: 0x4
1112 PGOAnalyses: [{}]
1113 - Name: .llvm_bb_addr_map_6
1114 Type: SHT_LLVM_BB_ADDR_MAP
1115 # Link: 0 (by default, can be overriden)
1116 Entries:
1117 - Version: 2
1118 Feature: 0xc
1119 BBRanges:
1120 - BaseAddress: 0x66666
1121 BBEntries:
1122 - ID: 0
1123 AddressOffset: 0x0
1124 Size: 0x6
1125 Metadata: 0x6
1126 - ID: 1
1127 AddressOffset: 0x0
1128 Size: 0x6
1129 Metadata: 0x4
1130 - BaseAddress: 0x666661
1131 BBEntries:
1132 - ID: 2
1133 AddressOffset: 0x0
1134 Size: 0x6
1135 Metadata: 0x0
1136 PGOAnalyses:
1137 - PGOBBEntries:
1138 - Successors:
1139 - ID: 1
1140 BrProb: 0x22222222
1141 - ID: 2
1142 BrProb: 0xcccccccc
1143 - Successors:
1144 - ID: 2
1145 BrProb: 0x88888888
1146 - Successors: []
1147)");
1148
1149 BBAddrMap E1 = {
1150 .BBRanges: {{.BaseAddress: 0x11111, .BBEntries: {{1, 0x0, 0x1, {.HasReturn: false, .HasTailCall: true, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}}}}}};
1151 PGOAnalysisMap P1 = {.FuncEntryCount: 892, .BBEntries: {}, .FeatEnable: {.FuncEntryCount: true, .BBFreq: false, .BrProb: false, .MultiBBRange: false}};
1152 BBAddrMap E2 = {
1153 .BBRanges: {{.BaseAddress: 0x22222, .BBEntries: {{2, 0x0, 0x2, {.HasReturn: false, .HasTailCall: false, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}}}}}};
1154 PGOAnalysisMap P2 = {
1155 .FuncEntryCount: {}, .BBEntries: {{.BlockFreq: BlockFrequency(343), .Successors: {}}}, .FeatEnable: {.FuncEntryCount: false, .BBFreq: true, .BrProb: false, .MultiBBRange: false}};
1156 BBAddrMap E3 = {.BBRanges: {{.BaseAddress: 0x33333,
1157 .BBEntries: {{0, 0x0, 0x3, {.HasReturn: false, .HasTailCall: true, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}},
1158 {1, 0x3, 0x3, {.HasReturn: false, .HasTailCall: false, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}},
1159 {2, 0x6, 0x3, {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}}}}}};
1160 PGOAnalysisMap P3 = {.FuncEntryCount: {},
1161 .BBEntries: {{.BlockFreq: {},
1162 .Successors: {{.ID: 1, .Prob: BranchProbability::getRaw(N: 0x1111'1111)},
1163 {.ID: 2, .Prob: BranchProbability::getRaw(N: 0xeeee'eeee)}}},
1164 {.BlockFreq: {}, .Successors: {{.ID: 2, .Prob: BranchProbability::getRaw(N: 0xffff'ffff)}}},
1165 {.BlockFreq: {}, .Successors: {}}},
1166 .FeatEnable: {.FuncEntryCount: false, .BBFreq: false, .BrProb: true, .MultiBBRange: false}};
1167 BBAddrMap E4 = {.BBRanges: {{.BaseAddress: 0x44444,
1168 .BBEntries: {{0, 0x0, 0x4, {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: true, .HasIndirectBranch: true}},
1169 {1, 0x4, 0x4, {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}},
1170 {2, 0x8, 0x4, {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}},
1171 {3, 0xc, 0x4, {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}}}}}};
1172 PGOAnalysisMap P4 = {
1173 .FuncEntryCount: 1000,
1174 .BBEntries: {{.BlockFreq: BlockFrequency(1000),
1175 .Successors: {{.ID: 1, .Prob: BranchProbability::getRaw(N: 0x2222'2222)},
1176 {.ID: 2, .Prob: BranchProbability::getRaw(N: 0x3333'3333)},
1177 {.ID: 3, .Prob: BranchProbability::getRaw(N: 0xaaaa'aaaa)}}},
1178 {.BlockFreq: BlockFrequency(133),
1179 .Successors: {{.ID: 2, .Prob: BranchProbability::getRaw(N: 0x1111'1111)},
1180 {.ID: 3, .Prob: BranchProbability::getRaw(N: 0xeeee'eeee)}}},
1181 {.BlockFreq: BlockFrequency(18), .Successors: {{.ID: 3, .Prob: BranchProbability::getRaw(N: 0xffff'ffff)}}},
1182 {.BlockFreq: BlockFrequency(1000), .Successors: {}}},
1183 .FeatEnable: {.FuncEntryCount: true, .BBFreq: true, .BrProb: true, .MultiBBRange: false}};
1184 BBAddrMap E5 = {
1185 .BBRanges: {{.BaseAddress: 0x55555, .BBEntries: {{2, 0x0, 0x2, {.HasReturn: false, .HasTailCall: false, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}}}}}};
1186 PGOAnalysisMap P5 = {.FuncEntryCount: {}, .BBEntries: {}, .FeatEnable: {.FuncEntryCount: false, .BBFreq: false, .BrProb: false, .MultiBBRange: false}};
1187 BBAddrMap E6 = {
1188 .BBRanges: {{.BaseAddress: 0x66666,
1189 .BBEntries: {{0, 0x0, 0x6, {.HasReturn: false, .HasTailCall: true, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}},
1190 {1, 0x6, 0x6, {.HasReturn: false, .HasTailCall: false, .IsEHPad: true, .CanFallThrough: false, .HasIndirectBranch: false}}}},
1191 {.BaseAddress: 0x666661, .BBEntries: {{2, 0x0, 0x6, {.HasReturn: false, .HasTailCall: false, .IsEHPad: false, .CanFallThrough: false, .HasIndirectBranch: false}}}}}};
1192 PGOAnalysisMap P6 = {.FuncEntryCount: {},
1193 .BBEntries: {{.BlockFreq: {},
1194 .Successors: {{.ID: 1, .Prob: BranchProbability::getRaw(N: 0x2222'2222)},
1195 {.ID: 2, .Prob: BranchProbability::getRaw(N: 0xcccc'cccc)}}},
1196 {.BlockFreq: {}, .Successors: {{.ID: 2, .Prob: BranchProbability::getRaw(N: 0x8888'8888)}}},
1197 {.BlockFreq: {}, .Successors: {}}},
1198 .FeatEnable: {.FuncEntryCount: false, .BBFreq: false, .BrProb: true, .MultiBBRange: true}};
1199
1200 std::vector<BBAddrMap> Section0BBAddrMaps = {E4, E5, E6};
1201 std::vector<BBAddrMap> Section1BBAddrMaps = {E3};
1202 std::vector<BBAddrMap> Section2BBAddrMaps = {E1, E2};
1203 std::vector<BBAddrMap> AllBBAddrMaps = {E1, E2, E3, E4, E5, E6};
1204
1205 std::vector<PGOAnalysisMap> Section0PGOAnalysisMaps = {P4, P5, P6};
1206 std::vector<PGOAnalysisMap> Section1PGOAnalysisMaps = {P3};
1207 std::vector<PGOAnalysisMap> Section2PGOAnalysisMaps = {P1, P2};
1208 std::vector<PGOAnalysisMap> AllPGOAnalysisMaps = {P1, P2, P3, P4, P5, P6};
1209
1210 auto DoCheckSucceeds =
1211 [&](StringRef YamlString, std::optional<unsigned> TextSectionIndex,
1212 std::vector<BBAddrMap> ExpectedResult,
1213 std::optional<std::vector<PGOAnalysisMap>> ExpectedPGO) {
1214 SCOPED_TRACE(
1215 "for TextSectionIndex: " +
1216 (TextSectionIndex ? llvm::Twine(*TextSectionIndex) : "{}") +
1217 " and object yaml:\n" + YamlString);
1218 SmallString<0> Storage;
1219 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
1220 toBinary<ELF64LE>(Storage, Yaml: YamlString);
1221 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
1222
1223 Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
1224 ElfOrErr->getELFFile().getSection(Index: 1);
1225 ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
1226
1227 std::vector<PGOAnalysisMap> PGOAnalyses;
1228 auto BBAddrMaps = ElfOrErr->readBBAddrMap(
1229 TextSectionIndex, PGOAnalyses: ExpectedPGO ? &PGOAnalyses : nullptr);
1230 ASSERT_THAT_EXPECTED(BBAddrMaps, Succeeded());
1231 EXPECT_EQ(*BBAddrMaps, ExpectedResult);
1232 if (ExpectedPGO) {
1233 EXPECT_EQ(BBAddrMaps->size(), PGOAnalyses.size());
1234 for (const auto &PGO : PGOAnalyses) {
1235 errs() << "FuncEntryCount: " << PGO.FuncEntryCount << "\n";
1236 for (const auto &PGOBB : PGO.BBEntries)
1237 errs() << "\tBB: " << PGOBB.BlockFreq.getFrequency() << "\n";
1238 }
1239 errs() << " To expected:\n";
1240 for (const auto &PGO : *ExpectedPGO) {
1241 errs() << "FuncEntryCount: " << PGO.FuncEntryCount << "\n";
1242 for (const auto &PGOBB : PGO.BBEntries)
1243 errs() << "\tBB: " << PGOBB.BlockFreq.getFrequency() << "\n";
1244 }
1245 EXPECT_EQ(PGOAnalyses, *ExpectedPGO);
1246 for (auto &&[BB, PGO] : llvm::zip(t&: *BBAddrMaps, u&: PGOAnalyses)) {
1247 if (PGO.FeatEnable.BBFreq || PGO.FeatEnable.BrProb)
1248 EXPECT_EQ(BB.getNumBBEntries(), PGO.BBEntries.size());
1249 }
1250 }
1251 };
1252
1253 auto DoCheckFails = [&](StringRef YamlString,
1254 std::optional<unsigned> TextSectionIndex,
1255 const char *ErrMsg) {
1256 SCOPED_TRACE("for TextSectionIndex: " +
1257 (TextSectionIndex ? llvm::Twine(*TextSectionIndex) : "{}") +
1258 " and object yaml:\n" + YamlString);
1259 SmallString<0> Storage;
1260 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
1261 toBinary<ELF64LE>(Storage, Yaml: YamlString);
1262 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
1263
1264 Expected<const typename ELF64LE::Shdr *> BBAddrMapSecOrErr =
1265 ElfOrErr->getELFFile().getSection(Index: 1);
1266 ASSERT_THAT_EXPECTED(BBAddrMapSecOrErr, Succeeded());
1267 std::vector<PGOAnalysisMap> PGOAnalyses;
1268 EXPECT_THAT_ERROR(
1269 ElfOrErr->readBBAddrMap(TextSectionIndex, &PGOAnalyses).takeError(),
1270 FailedWithMessage(ErrMsg));
1271 };
1272
1273 {
1274 SCOPED_TRACE("normal sections");
1275 // Check that we can retrieve the data in the normal case.
1276 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/std::nullopt,
1277 AllBBAddrMaps, std::nullopt);
1278 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/0,
1279 Section0BBAddrMaps, std::nullopt);
1280 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/2,
1281 Section1BBAddrMaps, std::nullopt);
1282 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/1,
1283 Section2BBAddrMaps, std::nullopt);
1284
1285 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/std::nullopt,
1286 AllBBAddrMaps, AllPGOAnalysisMaps);
1287 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/0,
1288 Section0BBAddrMaps, Section0PGOAnalysisMaps);
1289 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/2,
1290 Section1BBAddrMaps, Section1PGOAnalysisMaps);
1291 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/1,
1292 Section2BBAddrMaps, Section2PGOAnalysisMaps);
1293 // Check that when no bb-address-map section is found for a text section,
1294 // we return an empty result.
1295 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/3, {}, std::nullopt);
1296 DoCheckSucceeds(CommonYamlString, /*TextSectionIndex=*/3, {},
1297 std::vector<PGOAnalysisMap>{});
1298 }
1299
1300 // Check that we detect when a bb-addr-map section is linked to an invalid
1301 // (not present) section.
1302 SmallString<128> InvalidLinkedYamlString(CommonYamlString);
1303 InvalidLinkedYamlString += R"(
1304 Link: 121
1305)";
1306
1307 {
1308 SCOPED_TRACE("invalid linked section");
1309 DoCheckFails(InvalidLinkedYamlString, /*TextSectionIndex=*/5,
1310 "unable to get the linked-to section for "
1311 "SHT_LLVM_BB_ADDR_MAP section with index 6: invalid section "
1312 "index: 121");
1313
1314 // Linked sections are not checked when we don't target a specific text
1315 // section.
1316 DoCheckSucceeds(InvalidLinkedYamlString, /*TextSectionIndex=*/std::nullopt,
1317 AllBBAddrMaps, std::nullopt);
1318 DoCheckSucceeds(InvalidLinkedYamlString, /*TextSectionIndex=*/std::nullopt,
1319 AllBBAddrMaps, AllPGOAnalysisMaps);
1320 }
1321
1322 // Check that we can detect when bb-address-map decoding fails.
1323 SmallString<128> TruncatedYamlString(CommonYamlString);
1324 TruncatedYamlString += R"(
1325 ShSize: 0xa
1326)";
1327
1328 {
1329 SCOPED_TRACE("truncated section");
1330 DoCheckFails(
1331 TruncatedYamlString, /*TextSectionIndex=*/std::nullopt,
1332 "unable to read SHT_LLVM_BB_ADDR_MAP section with index 6: "
1333 "unexpected end of data at offset 0xa while reading [0x3, 0xb)");
1334 // Check that we can read the other section's bb-address-maps which are
1335 // valid.
1336 DoCheckSucceeds(TruncatedYamlString, /*TextSectionIndex=*/2,
1337 Section1BBAddrMaps, std::nullopt);
1338 DoCheckSucceeds(TruncatedYamlString, /*TextSectionIndex=*/2,
1339 Section1BBAddrMaps, Section1PGOAnalysisMaps);
1340 }
1341}
1342
1343// Test for ObjectFile::getRelocatedSection: check that it returns a relocated
1344// section for executable and relocatable files.
1345TEST(ELFObjectFileTest, ExecutableWithRelocs) {
1346 StringRef HeaderString(R"(
1347--- !ELF
1348FileHeader:
1349 Class: ELFCLASS64
1350 Data: ELFDATA2LSB
1351)");
1352 StringRef ContentsString(R"(
1353Sections:
1354 - Name: .text
1355 Type: SHT_PROGBITS
1356 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
1357 - Name: .rela.text
1358 Type: SHT_RELA
1359 Flags: [ SHF_INFO_LINK ]
1360 Info: .text
1361)");
1362
1363 auto DoCheck = [&](StringRef YamlString) {
1364 SmallString<0> Storage;
1365 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
1366 toBinary<ELF64LE>(Storage, Yaml: YamlString);
1367 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
1368 const ELFObjectFile<ELF64LE> &Obj = *ElfOrErr;
1369
1370 bool FoundRela;
1371
1372 for (SectionRef Sec : Obj.sections()) {
1373 Expected<StringRef> SecNameOrErr = Sec.getName();
1374 ASSERT_THAT_EXPECTED(SecNameOrErr, Succeeded());
1375 StringRef SecName = *SecNameOrErr;
1376 if (SecName != ".rela.text")
1377 continue;
1378 FoundRela = true;
1379 Expected<section_iterator> RelSecOrErr = Sec.getRelocatedSection();
1380 ASSERT_THAT_EXPECTED(RelSecOrErr, Succeeded());
1381 section_iterator RelSec = *RelSecOrErr;
1382 ASSERT_NE(RelSec, Obj.section_end());
1383 Expected<StringRef> TextSecNameOrErr = RelSec->getName();
1384 ASSERT_THAT_EXPECTED(TextSecNameOrErr, Succeeded());
1385 StringRef TextSecName = *TextSecNameOrErr;
1386 EXPECT_EQ(TextSecName, ".text");
1387 }
1388 ASSERT_TRUE(FoundRela);
1389 };
1390
1391 // Check ET_EXEC file (`ld --emit-relocs` use-case).
1392 SmallString<128> ExecFileYamlString(HeaderString);
1393 ExecFileYamlString += R"(
1394 Type: ET_EXEC
1395)";
1396 ExecFileYamlString += ContentsString;
1397 DoCheck(ExecFileYamlString);
1398
1399 // Check ET_REL file.
1400 SmallString<128> RelocatableFileYamlString(HeaderString);
1401 RelocatableFileYamlString += R"(
1402 Type: ET_REL
1403)";
1404 RelocatableFileYamlString += ContentsString;
1405 DoCheck(RelocatableFileYamlString);
1406}
1407
1408TEST(ELFObjectFileTest, GetSectionAndRelocations) {
1409 StringRef HeaderString(R"(
1410--- !ELF
1411FileHeader:
1412 Class: ELFCLASS64
1413 Data: ELFDATA2LSB
1414 Type: ET_EXEC
1415)");
1416
1417 using Elf_Shdr = Elf_Shdr_Impl<ELF64LE>;
1418
1419 auto DoCheckSucceeds = [&](StringRef ContentsString,
1420 std::function<Expected<bool>(const Elf_Shdr &)>
1421 Matcher) {
1422 SmallString<0> Storage;
1423 SmallString<128> FullYamlString(HeaderString);
1424 FullYamlString += ContentsString;
1425 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
1426 toBinary<ELF64LE>(Storage, Yaml: FullYamlString);
1427 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
1428
1429 Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
1430 ElfOrErr->getELFFile().getSectionAndRelocations(IsMatch: Matcher);
1431 ASSERT_THAT_EXPECTED(SecToRelocMapOrErr, Succeeded());
1432
1433 // Basic verification to make sure we have the correct section types.
1434 for (auto const &[Sec, RelaSec] : *SecToRelocMapOrErr) {
1435 ASSERT_EQ(Sec->sh_type, ELF::SHT_PROGBITS);
1436 ASSERT_EQ(RelaSec->sh_type, ELF::SHT_RELA);
1437 }
1438 };
1439
1440 auto DoCheckFails = [&](StringRef ContentsString,
1441 std::function<Expected<bool>(const Elf_Shdr &)>
1442 Matcher,
1443 const char *ErrorMessage) {
1444 SmallString<0> Storage;
1445 SmallString<128> FullYamlString(HeaderString);
1446 FullYamlString += ContentsString;
1447 Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
1448 toBinary<ELF64LE>(Storage, Yaml: FullYamlString);
1449 ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
1450
1451 Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
1452 ElfOrErr->getELFFile().getSectionAndRelocations(IsMatch: Matcher);
1453 ASSERT_THAT_ERROR(SecToRelocMapOrErr.takeError(),
1454 FailedWithMessage(ErrorMessage));
1455 };
1456
1457 auto DefaultMatcher = [](const Elf_Shdr &Sec) -> bool {
1458 return Sec.sh_type == ELF::SHT_PROGBITS;
1459 };
1460
1461 StringRef TwoTextSections = R"(
1462Sections:
1463 - Name: .text
1464 Type: SHT_PROGBITS
1465 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
1466 - Name: .rela.text
1467 Type: SHT_RELA
1468 Flags: [ SHF_INFO_LINK ]
1469 Info: .text
1470 - Name: .text2
1471 Type: SHT_PROGBITS
1472 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
1473 - Name: .rela.text2
1474 Type: SHT_RELA
1475 Flags: [ SHF_INFO_LINK ]
1476 Info: .text2
1477)";
1478 DoCheckSucceeds(TwoTextSections, DefaultMatcher);
1479
1480 StringRef OneTextSection = R"(
1481Sections:
1482 - Name: .text
1483 Type: SHT_PROGBITS
1484 Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
1485)";
1486
1487 auto ErroringMatcher = [](const Elf_Shdr &Sec) -> Expected<bool> {
1488 if (Sec.sh_type == ELF::SHT_PROGBITS)
1489 return createError(Err: "This was supposed to fail.");
1490 return false;
1491 };
1492
1493 DoCheckFails(OneTextSection, ErroringMatcher, "This was supposed to fail.");
1494
1495 StringRef MissingRelocatableContent = R"(
1496Sections:
1497 - Name: .rela.text
1498 Type: SHT_RELA
1499 Flags: [ SHF_INFO_LINK ]
1500 Info: 0xFF
1501)";
1502
1503 DoCheckFails(MissingRelocatableContent, DefaultMatcher,
1504 "SHT_RELA section with index 1: failed to get a "
1505 "relocated section: invalid section index: 255");
1506}
1507

source code of llvm/unittests/Object/ELFObjectFileTest.cpp