aboutsummaryrefslogtreecommitdiff
path: root/lib/ObjectYAML/ELFYAML.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ObjectYAML/ELFYAML.cpp')
-rw-r--r--lib/ObjectYAML/ELFYAML.cpp325
1 files changed, 272 insertions, 53 deletions
diff --git a/lib/ObjectYAML/ELFYAML.cpp b/lib/ObjectYAML/ELFYAML.cpp
index 7497154c757d..29585abe6e80 100644
--- a/lib/ObjectYAML/ELFYAML.cpp
+++ b/lib/ObjectYAML/ELFYAML.cpp
@@ -11,12 +11,14 @@
//===----------------------------------------------------------------------===//
#include "llvm/ObjectYAML/ELFYAML.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MipsABIFlags.h"
#include "llvm/Support/YAMLTraits.h"
+#include "llvm/Support/WithColor.h"
#include <cassert>
#include <cstdint>
@@ -50,6 +52,8 @@ void ScalarEnumerationTraits<ELFYAML::ELF_PT>::enumeration(
ECase(PT_PHDR);
ECase(PT_TLS);
ECase(PT_GNU_EH_FRAME);
+ ECase(PT_GNU_STACK);
+ ECase(PT_GNU_RELRO);
#undef ECase
IO.enumFallback<Hex32>(Value);
}
@@ -217,6 +221,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_EM>::enumeration(
ECase(EM_LANAI);
ECase(EM_BPF);
#undef ECase
+ IO.enumFallback<Hex16>(Value);
}
void ScalarEnumerationTraits<ELFYAML::ELF_ELFCLASS>::enumeration(
@@ -459,6 +464,9 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration(
ECase(SHT_LLVM_CALL_GRAPH_PROFILE);
ECase(SHT_LLVM_ADDRSIG);
ECase(SHT_LLVM_DEPENDENT_LIBRARIES);
+ ECase(SHT_LLVM_SYMPART);
+ ECase(SHT_LLVM_PART_EHDR);
+ ECase(SHT_LLVM_PART_PHDR);
ECase(SHT_GNU_ATTRIBUTES);
ECase(SHT_GNU_HASH);
ECase(SHT_GNU_verdef);
@@ -563,7 +571,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHN>::enumeration(
ECase(SHN_HEXAGON_SCOMMON_4);
ECase(SHN_HEXAGON_SCOMMON_8);
#undef ECase
- IO.enumFallback<Hex32>(Value);
+ IO.enumFallback<Hex16>(Value);
}
void ScalarEnumerationTraits<ELFYAML::ELF_STB>::enumeration(
@@ -592,34 +600,6 @@ void ScalarEnumerationTraits<ELFYAML::ELF_STT>::enumeration(
IO.enumFallback<Hex8>(Value);
}
-void ScalarEnumerationTraits<ELFYAML::ELF_STV>::enumeration(
- IO &IO, ELFYAML::ELF_STV &Value) {
-#define ECase(X) IO.enumCase(Value, #X, ELF::X)
- ECase(STV_DEFAULT);
- ECase(STV_INTERNAL);
- ECase(STV_HIDDEN);
- ECase(STV_PROTECTED);
-#undef ECase
-}
-
-void ScalarBitSetTraits<ELFYAML::ELF_STO>::bitset(IO &IO,
- ELFYAML::ELF_STO &Value) {
- const auto *Object = static_cast<ELFYAML::Object *>(IO.getContext());
- assert(Object && "The IO context is not initialized");
-#define BCase(X) IO.bitSetCase(Value, #X, ELF::X)
- switch (Object->Header.Machine) {
- case ELF::EM_MIPS:
- BCase(STO_MIPS_OPTIONAL);
- BCase(STO_MIPS_PLT);
- BCase(STO_MIPS_PIC);
- BCase(STO_MIPS_MICROMIPS);
- break;
- default:
- break; // Nothing to do
- }
-#undef BCase
-#undef BCaseMask
-}
void ScalarEnumerationTraits<ELFYAML::ELF_RSS>::enumeration(
IO &IO, ELFYAML::ELF_RSS &Value) {
@@ -671,8 +651,12 @@ void ScalarEnumerationTraits<ELFYAML::ELF_REL>::enumeration(
case ELF::EM_BPF:
#include "llvm/BinaryFormat/ELFRelocs/BPF.def"
break;
+ case ELF::EM_PPC64:
+#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"
+ break;
default:
- llvm_unreachable("Unsupported architecture");
+ // Nothing to do.
+ break;
}
#undef ELF_RELOC
IO.enumFallback<Hex32>(Value);
@@ -845,7 +829,7 @@ void MappingTraits<ELFYAML::FileHeader>::mapping(IO &IO,
IO.mapOptional("Entry", FileHdr.Entry, Hex64(0));
IO.mapOptional("SHEntSize", FileHdr.SHEntSize);
- IO.mapOptional("SHOffset", FileHdr.SHOffset);
+ IO.mapOptional("SHOff", FileHdr.SHOff);
IO.mapOptional("SHNum", FileHdr.SHNum);
IO.mapOptional("SHStrNdx", FileHdr.SHStrNdx);
}
@@ -863,18 +847,111 @@ void MappingTraits<ELFYAML::ProgramHeader>::mapping(
IO.mapOptional("Offset", Phdr.Offset);
}
+LLVM_YAML_STRONG_TYPEDEF(StringRef, StOtherPiece)
+
+template <> struct ScalarTraits<StOtherPiece> {
+ static void output(const StOtherPiece &Val, void *, raw_ostream &Out) {
+ Out << Val;
+ }
+ static StringRef input(StringRef Scalar, void *, StOtherPiece &Val) {
+ Val = Scalar;
+ return {};
+ }
+ static QuotingType mustQuote(StringRef) { return QuotingType::None; }
+};
+template <> struct SequenceElementTraits<StOtherPiece> {
+ static const bool flow = true;
+};
+
namespace {
struct NormalizedOther {
- NormalizedOther(IO &)
- : Visibility(ELFYAML::ELF_STV(0)), Other(ELFYAML::ELF_STO(0)) {}
- NormalizedOther(IO &, uint8_t Original)
- : Visibility(Original & 0x3), Other(Original & ~0x3) {}
+ NormalizedOther(IO &IO) : YamlIO(IO) {}
+ NormalizedOther(IO &IO, Optional<uint8_t> Original) : YamlIO(IO) {
+ assert(Original && "This constructor is only used for outputting YAML and "
+ "assumes a non-empty Original");
+ std::vector<StOtherPiece> Ret;
+ const auto *Object = static_cast<ELFYAML::Object *>(YamlIO.getContext());
+ for (std::pair<StringRef, uint8_t> &P :
+ getFlags(Object->Header.Machine).takeVector()) {
+ uint8_t FlagValue = P.second;
+ if ((*Original & FlagValue) != FlagValue)
+ continue;
+ *Original &= ~FlagValue;
+ Ret.push_back({P.first});
+ }
+
+ if (*Original != 0) {
+ UnknownFlagsHolder = std::to_string(*Original);
+ Ret.push_back({UnknownFlagsHolder});
+ }
+
+ if (!Ret.empty())
+ Other = std::move(Ret);
+ }
+
+ uint8_t toValue(StringRef Name) {
+ const auto *Object = static_cast<ELFYAML::Object *>(YamlIO.getContext());
+ MapVector<StringRef, uint8_t> Flags = getFlags(Object->Header.Machine);
- uint8_t denormalize(IO &) { return Visibility | Other; }
+ auto It = Flags.find(Name);
+ if (It != Flags.end())
+ return It->second;
+
+ uint8_t Val;
+ if (to_integer(Name, Val))
+ return Val;
+
+ YamlIO.setError("an unknown value is used for symbol's 'Other' field: " +
+ Name);
+ return 0;
+ }
- ELFYAML::ELF_STV Visibility;
- ELFYAML::ELF_STO Other;
+ Optional<uint8_t> denormalize(IO &) {
+ if (!Other)
+ return None;
+ uint8_t Ret = 0;
+ for (StOtherPiece &Val : *Other)
+ Ret |= toValue(Val);
+ return Ret;
+ }
+
+ // st_other field is used to encode symbol visibility and platform-dependent
+ // flags and values. This method returns a name to value map that is used for
+ // parsing and encoding this field.
+ MapVector<StringRef, uint8_t> getFlags(unsigned EMachine) {
+ MapVector<StringRef, uint8_t> Map;
+ // STV_* values are just enumeration values. We add them in a reversed order
+ // because when we convert the st_other to named constants when printing
+ // YAML we want to use a maximum number of bits on each step:
+ // when we have st_other == 3, we want to print it as STV_PROTECTED (3), but
+ // not as STV_HIDDEN (2) + STV_INTERNAL (1).
+ Map["STV_PROTECTED"] = ELF::STV_PROTECTED;
+ Map["STV_HIDDEN"] = ELF::STV_HIDDEN;
+ Map["STV_INTERNAL"] = ELF::STV_INTERNAL;
+ // STV_DEFAULT is used to represent the default visibility and has a value
+ // 0. We want to be able to read it from YAML documents, but there is no
+ // reason to print it.
+ if (!YamlIO.outputting())
+ Map["STV_DEFAULT"] = ELF::STV_DEFAULT;
+
+ // MIPS is not consistent. All of the STO_MIPS_* values are bit flags,
+ // except STO_MIPS_MIPS16 which overlaps them. It should be checked and
+ // consumed first when we print the output, because we do not want to print
+ // any other flags that have the same bits instead.
+ if (EMachine == ELF::EM_MIPS) {
+ Map["STO_MIPS_MIPS16"] = ELF::STO_MIPS_MIPS16;
+ Map["STO_MIPS_MICROMIPS"] = ELF::STO_MIPS_MICROMIPS;
+ Map["STO_MIPS_PIC"] = ELF::STO_MIPS_PIC;
+ Map["STO_MIPS_PLT"] = ELF::STO_MIPS_PLT;
+ Map["STO_MIPS_OPTIONAL"] = ELF::STO_MIPS_OPTIONAL;
+ }
+ return Map;
+ }
+
+ IO &YamlIO;
+ Optional<std::vector<StOtherPiece>> Other;
+ std::string UnknownFlagsHolder;
};
} // end anonymous namespace
@@ -888,17 +965,21 @@ void MappingTraits<ELFYAML::Symbol>::mapping(IO &IO, ELFYAML::Symbol &Symbol) {
IO.mapOptional("Binding", Symbol.Binding, ELFYAML::ELF_STB(0));
IO.mapOptional("Value", Symbol.Value, Hex64(0));
IO.mapOptional("Size", Symbol.Size, Hex64(0));
- MappingNormalization<NormalizedOther, uint8_t> Keys(IO, Symbol.Other);
- IO.mapOptional("Visibility", Keys->Visibility, ELFYAML::ELF_STV(0));
- IO.mapOptional("Other", Keys->Other, ELFYAML::ELF_STO(0));
+
+ // Symbol's Other field is a bit special. It is usually a field that
+ // represents st_other and holds the symbol visibility. However, on some
+ // platforms, it can contain bit fields and regular values, or even sometimes a
+ // crazy mix of them (see comments for NormalizedOther). Because of this, we
+ // need special handling.
+ MappingNormalization<NormalizedOther, Optional<uint8_t>> Keys(IO,
+ Symbol.Other);
+ IO.mapOptional("Other", Keys->Other);
}
StringRef MappingTraits<ELFYAML::Symbol>::validate(IO &IO,
ELFYAML::Symbol &Symbol) {
if (Symbol.Index && Symbol.Section.data())
return "Index and Section cannot both be specified for Symbol";
- if (Symbol.Index && *Symbol.Index == ELFYAML::ELF_SHN(ELF::SHN_XINDEX))
- return "Large indexes are not supported";
if (Symbol.NameIndex && !Symbol.Name.empty())
return "Name and NameIndex cannot both be specified for Symbol";
return StringRef();
@@ -914,10 +995,11 @@ static void commonSectionMapping(IO &IO, ELFYAML::Section &Section) {
IO.mapOptional("EntSize", Section.EntSize);
// obj2yaml does not dump these fields. They are expected to be empty when we
- // are producing YAML, because yaml2obj sets appropriate values for sh_offset
- // and sh_size automatically when they are not explicitly defined.
+ // are producing YAML, because yaml2obj sets appropriate values for them
+ // automatically when they are not explicitly defined.
assert(!IO.outputting() ||
(!Section.ShOffset.hasValue() && !Section.ShSize.hasValue()));
+ IO.mapOptional("ShName", Section.ShName);
IO.mapOptional("ShOffset", Section.ShOffset);
IO.mapOptional("ShSize", Section.ShSize);
}
@@ -935,6 +1017,21 @@ static void sectionMapping(IO &IO, ELFYAML::RawContentSection &Section) {
IO.mapOptional("Info", Section.Info);
}
+static void sectionMapping(IO &IO, ELFYAML::StackSizesSection &Section) {
+ commonSectionMapping(IO, Section);
+ IO.mapOptional("Content", Section.Content);
+ IO.mapOptional("Size", Section.Size);
+ IO.mapOptional("Entries", Section.Entries);
+}
+
+static void sectionMapping(IO &IO, ELFYAML::HashSection &Section) {
+ commonSectionMapping(IO, Section);
+ IO.mapOptional("Content", Section.Content);
+ IO.mapOptional("Bucket", Section.Bucket);
+ IO.mapOptional("Chain", Section.Chain);
+ IO.mapOptional("Size", Section.Size);
+}
+
static void sectionMapping(IO &IO, ELFYAML::NoBitsSection &Section) {
commonSectionMapping(IO, Section);
IO.mapOptional("Size", Section.Size, Hex64(0));
@@ -969,6 +1066,18 @@ static void groupSectionMapping(IO &IO, ELFYAML::Group &Group) {
IO.mapRequired("Members", Group.Members);
}
+static void sectionMapping(IO &IO, ELFYAML::SymtabShndxSection &Section) {
+ commonSectionMapping(IO, Section);
+ IO.mapRequired("Entries", Section.Entries);
+}
+
+static void sectionMapping(IO &IO, ELFYAML::AddrsigSection &Section) {
+ commonSectionMapping(IO, Section);
+ IO.mapOptional("Content", Section.Content);
+ IO.mapOptional("Size", Section.Size);
+ IO.mapOptional("Symbols", Section.Symbols);
+}
+
void MappingTraits<ELFYAML::SectionOrType>::mapping(
IO &IO, ELFYAML::SectionOrType &sectionOrType) {
IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
@@ -1029,6 +1138,11 @@ void MappingTraits<std::unique_ptr<ELFYAML::Section>>::mapping(
Section.reset(new ELFYAML::NoBitsSection());
sectionMapping(IO, *cast<ELFYAML::NoBitsSection>(Section.get()));
break;
+ case ELF::SHT_HASH:
+ if (!IO.outputting())
+ Section.reset(new ELFYAML::HashSection());
+ sectionMapping(IO, *cast<ELFYAML::HashSection>(Section.get()));
+ break;
case ELF::SHT_MIPS_ABIFLAGS:
if (!IO.outputting())
Section.reset(new ELFYAML::MipsABIFlags());
@@ -1049,21 +1163,113 @@ void MappingTraits<std::unique_ptr<ELFYAML::Section>>::mapping(
Section.reset(new ELFYAML::VerneedSection());
sectionMapping(IO, *cast<ELFYAML::VerneedSection>(Section.get()));
break;
- default:
+ case ELF::SHT_SYMTAB_SHNDX:
if (!IO.outputting())
- Section.reset(new ELFYAML::RawContentSection());
- sectionMapping(IO, *cast<ELFYAML::RawContentSection>(Section.get()));
+ Section.reset(new ELFYAML::SymtabShndxSection());
+ sectionMapping(IO, *cast<ELFYAML::SymtabShndxSection>(Section.get()));
+ break;
+ case ELF::SHT_LLVM_ADDRSIG:
+ if (!IO.outputting())
+ Section.reset(new ELFYAML::AddrsigSection());
+ sectionMapping(IO, *cast<ELFYAML::AddrsigSection>(Section.get()));
+ break;
+ default:
+ if (!IO.outputting()) {
+ StringRef Name;
+ IO.mapOptional("Name", Name, StringRef());
+ Name = ELFYAML::dropUniqueSuffix(Name);
+
+ if (ELFYAML::StackSizesSection::nameMatches(Name))
+ Section = std::make_unique<ELFYAML::StackSizesSection>();
+ else
+ Section = std::make_unique<ELFYAML::RawContentSection>();
+ }
+
+ if (auto S = dyn_cast<ELFYAML::RawContentSection>(Section.get()))
+ sectionMapping(IO, *S);
+ else
+ sectionMapping(IO, *cast<ELFYAML::StackSizesSection>(Section.get()));
}
}
StringRef MappingTraits<std::unique_ptr<ELFYAML::Section>>::validate(
IO &io, std::unique_ptr<ELFYAML::Section> &Section) {
- const auto *RawSection = dyn_cast<ELFYAML::RawContentSection>(Section.get());
- if (!RawSection)
+ if (const auto *RawSection =
+ dyn_cast<ELFYAML::RawContentSection>(Section.get())) {
+ if (RawSection->Size && RawSection->Content &&
+ (uint64_t)(*RawSection->Size) < RawSection->Content->binary_size())
+ return "Section size must be greater than or equal to the content size";
return {};
- if (RawSection->Size && RawSection->Content &&
- (uint64_t)(*RawSection->Size) < RawSection->Content->binary_size())
- return "Section size must be greater than or equal to the content size";
+ }
+
+ if (const auto *SS = dyn_cast<ELFYAML::StackSizesSection>(Section.get())) {
+ if (!SS->Entries && !SS->Content && !SS->Size)
+ return ".stack_sizes: one of Content, Entries and Size must be specified";
+
+ if (SS->Size && SS->Content &&
+ (uint64_t)(*SS->Size) < SS->Content->binary_size())
+ return ".stack_sizes: Size must be greater than or equal to the content "
+ "size";
+
+ // We accept Content, Size or both together when there are no Entries.
+ if (!SS->Entries)
+ return {};
+
+ if (SS->Size)
+ return ".stack_sizes: Size and Entries cannot be used together";
+ if (SS->Content)
+ return ".stack_sizes: Content and Entries cannot be used together";
+ return {};
+ }
+
+ if (const auto *HS = dyn_cast<ELFYAML::HashSection>(Section.get())) {
+ if (!HS->Content && !HS->Bucket && !HS->Chain && !HS->Size)
+ return "one of \"Content\", \"Size\", \"Bucket\" or \"Chain\" must be "
+ "specified";
+
+ if (HS->Content || HS->Size) {
+ if (HS->Size && HS->Content &&
+ (uint64_t)*HS->Size < HS->Content->binary_size())
+ return "\"Size\" must be greater than or equal to the content "
+ "size";
+
+ if (HS->Bucket)
+ return "\"Bucket\" cannot be used with \"Content\" or \"Size\"";
+ if (HS->Chain)
+ return "\"Chain\" cannot be used with \"Content\" or \"Size\"";
+ return {};
+ }
+
+ if ((HS->Bucket && !HS->Chain) || (!HS->Bucket && HS->Chain))
+ return "\"Bucket\" and \"Chain\" must be used together";
+ return {};
+ }
+
+ if (const auto *Sec = dyn_cast<ELFYAML::AddrsigSection>(Section.get())) {
+ if (!Sec->Symbols && !Sec->Content && !Sec->Size)
+ return "one of \"Content\", \"Size\" or \"Symbols\" must be specified";
+
+ if (Sec->Content || Sec->Size) {
+ if (Sec->Size && Sec->Content &&
+ (uint64_t)*Sec->Size < Sec->Content->binary_size())
+ return "\"Size\" must be greater than or equal to the content "
+ "size";
+
+ if (Sec->Symbols)
+ return "\"Symbols\" cannot be used with \"Content\" or \"Size\"";
+ return {};
+ }
+
+ if (!Sec->Symbols)
+ return {};
+
+ for (const ELFYAML::AddrsigSymbol &AS : *Sec->Symbols)
+ if (AS.Index && AS.Name)
+ return "\"Index\" and \"Name\" cannot be used together when defining a "
+ "symbol";
+ return {};
+ }
+
return {};
}
@@ -1092,6 +1298,13 @@ struct NormalizedMips64RelType {
} // end anonymous namespace
+void MappingTraits<ELFYAML::StackSizeEntry>::mapping(
+ IO &IO, ELFYAML::StackSizeEntry &E) {
+ assert(IO.getContext() && "The IO context is not initialized");
+ IO.mapOptional("Address", E.Address, Hex64(0));
+ IO.mapRequired("Size", E.Size);
+}
+
void MappingTraits<ELFYAML::DynamicEntry>::mapping(IO &IO,
ELFYAML::DynamicEntry &Rel) {
assert(IO.getContext() && "The IO context is not initialized");
@@ -1164,6 +1377,12 @@ void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
IO.setContext(nullptr);
}
+void MappingTraits<ELFYAML::AddrsigSymbol>::mapping(IO &IO, ELFYAML::AddrsigSymbol &Sym) {
+ assert(IO.getContext() && "The IO context is not initialized");
+ IO.mapOptional("Name", Sym.Name);
+ IO.mapOptional("Index", Sym.Index);
+}
+
LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_AFL_REG)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_ABI_FP)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, MIPS_AFL_EXT)