#define LLVM_OBJECT_ELF_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) const;
Expected<std::vector<BBAddrMap>> decodeBBAddrMap(const Elf_Shdr &Sec) const;
+ /// Returns a map from every section matching \p IsMatch to its relocation
+ /// section, or \p nullptr if it has no relocation section. This function
+ /// returns an error if any of the \p IsMatch calls fail or if it fails to
+ /// retrieve the content section of any relocation section.
+ Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>>
+ getSectionAndRelocations(
+ std::function<Expected<bool>(const Elf_Shdr &)> IsMatch) const;
+
void createFakeSections();
};
return FunctionEntries;
}
+template <class ELFT>
+Expected<
+ MapVector<const typename ELFT::Shdr *, const typename ELFT::Shdr *>>
+ELFFile<ELFT>::getSectionAndRelocations(
+ std::function<Expected<bool>(const Elf_Shdr &)> IsMatch) const {
+ MapVector<const Elf_Shdr *, const Elf_Shdr *> SecToRelocMap;
+ Error Errors = Error::success();
+ for (const Elf_Shdr &Sec : cantFail(this->sections())) {
+ Expected<bool> DoesSectionMatch = IsMatch(Sec);
+ if (!DoesSectionMatch) {
+ Errors = joinErrors(std::move(Errors), DoesSectionMatch.takeError());
+ continue;
+ }
+ if (*DoesSectionMatch) {
+ if (SecToRelocMap.insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr))
+ .second)
+ continue;
+ }
+
+ if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL)
+ continue;
+
+ Expected<const Elf_Shdr *> RelSecOrErr = this->getSection(Sec.sh_info);
+ if (!RelSecOrErr) {
+ Errors = joinErrors(std::move(Errors),
+ createError(describe(*this, Sec) +
+ ": failed to get a relocated section: " +
+ toString(RelSecOrErr.takeError())));
+ continue;
+ }
+ const Elf_Shdr *ContentsSec = *RelSecOrErr;
+ Expected<bool> DoesRelTargetMatch = IsMatch(*ContentsSec);
+ if (!DoesRelTargetMatch) {
+ Errors = joinErrors(std::move(Errors), DoesRelTargetMatch.takeError());
+ continue;
+ }
+ if (*DoesRelTargetMatch)
+ SecToRelocMap[ContentsSec] = &Sec;
+ }
+ if(Errors)
+ return Errors;
+ return SecToRelocMap;
+}
+
template class llvm::object::ELFFile<ELF32LE>;
template class llvm::object::ELFFile<ELF32BE>;
template class llvm::object::ELFFile<ELF64LE>;
Symbols:
- Name: foo
- Name: bar
+
+## Check that we report a warning when we fail to get a section associated with
+## a relocation section.
+
+# RUN: yaml2obj %s --docnum=8 -o %t9.o
+# RUN: llvm-readobj %t9.o --cg-profile 2>&1 | FileCheck %s -DFILE=%t9.o --check-prefix=LLVM-RELOC-NO-SECTIONS
+# RUN: llvm-readobj %t9.o --elf-cg-profile 2>&1 | FileCheck %s -DFILE=%t9.o --check-prefix=LLVM-RELOC-NO-SECTIONS
+
+# LLVM-RELOC-NO-SECTIONS: warning: '[[FILE]]': unable to get CG Profile section(s): SHT_RELA section with index 1: failed to get a relocated section: invalid section index: 255
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_DYN
+ Machine: EM_X86_64
+Sections:
+ - Name: .rela.llvm.call-graph-profile
+ Type: SHT_RELA
+ Info: 0xFF
# RUN: llvm-readobj --stack-sizes %t18 2>&1 | \
# RUN: FileCheck %s --implicit-check-not="warning:" -DFILE=%t18 --check-prefix=INVALID-TARGET
-# INVALID-TARGET: warning: '[[FILE]]': SHT_RELA section with index 1: failed to get a relocated section: invalid section index: 255
-# INVALID-TARGET: warning: '[[FILE]]': SHT_RELA section with index 2: failed to get a relocated section: invalid section index: 255
+# INVALID-TARGET: warning: '[[FILE]]': unable to get stack size map section(s): SHT_RELA section with index 1: failed to get a relocated section: invalid section index: 255
+# INVALID-TARGET: SHT_RELA section with index 2: failed to get a relocated section: invalid section index: 255
--- !ELF
FileHeader:
void printRelocatableStackSizes(std::function<void()> PrintHeader);
void printNonRelocatableStackSizes(std::function<void()> PrintHeader);
- /// Retrieves sections with corresponding relocation sections based on
- /// IsMatch.
- void getSectionAndRelocations(
- std::function<bool(const Elf_Shdr &)> IsMatch,
- llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> &SecToRelocMap);
-
const object::ELFObjectFile<ELFT> &ObjF;
const ELFFile<ELFT> &Obj;
StringRef FileName;
}
}
-template <class ELFT>
-void ELFDumper<ELFT>::getSectionAndRelocations(
- std::function<bool(const Elf_Shdr &)> IsMatch,
- llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> &SecToRelocMap) {
- for (const Elf_Shdr &Sec : cantFail(Obj.sections())) {
- if (IsMatch(Sec))
- if (SecToRelocMap.insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr))
- .second)
- continue;
-
- if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL)
- continue;
-
- Expected<const Elf_Shdr *> RelSecOrErr = Obj.getSection(Sec.sh_info);
- if (!RelSecOrErr) {
- reportUniqueWarning(describe(Sec) +
- ": failed to get a relocated section: " +
- toString(RelSecOrErr.takeError()));
- continue;
- }
- const Elf_Shdr *ContentsSec = *RelSecOrErr;
- if (IsMatch(*ContentsSec))
- SecToRelocMap[ContentsSec] = &Sec;
- }
-}
-
template <class ELFT>
void ELFDumper<ELFT>::printRelocatableStackSizes(
std::function<void()> PrintHeader) {
// Build a map between stack size sections and their corresponding relocation
// sections.
- llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> StackSizeRelocMap;
auto IsMatch = [&](const Elf_Shdr &Sec) -> bool {
StringRef SectionName;
if (Expected<StringRef> NameOrErr = Obj.getSectionName(Sec))
return SectionName == ".stack_sizes";
};
- getSectionAndRelocations(IsMatch, StackSizeRelocMap);
- for (const auto &StackSizeMapEntry : StackSizeRelocMap) {
+ Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>>
+ StackSizeRelocMapOrErr = Obj.getSectionAndRelocations(IsMatch);
+ if (!StackSizeRelocMapOrErr) {
+ reportUniqueWarning("unable to get stack size map section(s): " +
+ toString(StackSizeRelocMapOrErr.takeError()));
+ return;
+ }
+
+ for (const auto &StackSizeMapEntry : *StackSizeRelocMapOrErr) {
PrintHeader();
const Elf_Shdr *StackSizesELFSec = StackSizeMapEntry.first;
const Elf_Shdr *RelocSec = StackSizeMapEntry.second;
}
template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() {
- llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> SecToRelocMap;
-
auto IsMatch = [](const Elf_Shdr &Sec) -> bool {
return Sec.sh_type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE;
};
- this->getSectionAndRelocations(IsMatch, SecToRelocMap);
- for (const auto &CGMapEntry : SecToRelocMap) {
+ Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
+ this->Obj.getSectionAndRelocations(IsMatch);
+ if (!SecToRelocMapOrErr) {
+ this->reportUniqueWarning("unable to get CG Profile section(s): " +
+ toString(SecToRelocMapOrErr.takeError()));
+ return;
+ }
+
+ for (const auto &CGMapEntry : *SecToRelocMapOrErr) {
const Elf_Shdr *CGSection = CGMapEntry.first;
const Elf_Shdr *CGRelSection = CGMapEntry.second;
RelocatableFileYamlString += ContentsString;
DoCheck(RelocatableFileYamlString);
}
+
+TEST(ELFObjectFileTest, GetSectionAndRelocations) {
+ StringRef HeaderString(R"(
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+)");
+
+ using Elf_Shdr = Elf_Shdr_Impl<ELF64LE>;
+
+ auto DoCheckSucceeds = [&](StringRef ContentsString,
+ std::function<Expected<bool>(const Elf_Shdr &)>
+ Matcher) {
+ SmallString<0> Storage;
+ SmallString<128> FullYamlString(HeaderString);
+ FullYamlString += ContentsString;
+ Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
+ toBinary<ELF64LE>(Storage, FullYamlString);
+ ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+
+ Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
+ ElfOrErr->getELFFile().getSectionAndRelocations(Matcher);
+ ASSERT_THAT_EXPECTED(SecToRelocMapOrErr, Succeeded());
+
+ // Basic verification to make sure we have the correct section types.
+ for (auto const &[Sec, RelaSec] : *SecToRelocMapOrErr) {
+ ASSERT_EQ(Sec->sh_type, ELF::SHT_PROGBITS);
+ ASSERT_EQ(RelaSec->sh_type, ELF::SHT_RELA);
+ }
+ };
+
+ auto DoCheckFails = [&](StringRef ContentsString,
+ std::function<Expected<bool>(const Elf_Shdr &)>
+ Matcher,
+ const char *ErrorMessage) {
+ SmallString<0> Storage;
+ SmallString<128> FullYamlString(HeaderString);
+ FullYamlString += ContentsString;
+ Expected<ELFObjectFile<ELF64LE>> ElfOrErr =
+ toBinary<ELF64LE>(Storage, FullYamlString);
+ ASSERT_THAT_EXPECTED(ElfOrErr, Succeeded());
+
+ Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SecToRelocMapOrErr =
+ ElfOrErr->getELFFile().getSectionAndRelocations(Matcher);
+ ASSERT_THAT_ERROR(SecToRelocMapOrErr.takeError(),
+ FailedWithMessage(ErrorMessage));
+ };
+
+ auto DefaultMatcher = [](const Elf_Shdr &Sec) -> bool {
+ return Sec.sh_type == ELF::SHT_PROGBITS;
+ };
+
+ StringRef TwoTextSections = R"(
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Info: .text
+ - Name: .text2
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ - Name: .rela.text2
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Info: .text2
+)";
+ DoCheckSucceeds(TwoTextSections, DefaultMatcher);
+
+ StringRef OneTextSection = R"(
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+)";
+
+ auto ErroringMatcher = [](const Elf_Shdr &Sec) -> Expected<bool> {
+ if(Sec.sh_type == ELF::SHT_PROGBITS)
+ return createError("This was supposed to fail.");
+ return false;
+ };
+
+ DoCheckFails(OneTextSection, ErroringMatcher,
+ "This was supposed to fail.");
+
+ StringRef MissingRelocatableContent = R"(
+Sections:
+ - Name: .rela.text
+ Type: SHT_RELA
+ Flags: [ SHF_INFO_LINK ]
+ Info: 0xFF
+)";
+
+ DoCheckFails(MissingRelocatableContent, DefaultMatcher,
+ "SHT_RELA section with index 1: failed to get a "
+ "relocated section: invalid section index: 255");
+}