[llvm] [ELFYAML] Introduce `CustomRawContent` (PR #115707)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 11 02:38:39 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-support
Author: NAKAMURA Takumi (chapuni)
<details>
<summary>Changes</summary>
`CustomRawContent` itself is an abstract class. Each of its derivables can have customized encoder and decoder. At the moment, their type assumes `SHT_PROGBITS`.
Introduce `ELFYAML::Opt` (and `yaml::Opt`) to define parameters, hooks, and contexts.
Since it is pluggable, the definition of `CustomRawContent` derivables can be located not in `LLVMObjectYAML` but in YAML tools like `obj2yaml` and `yaml2obj`. This commit shows also skeletons in YAML tools.
---
Full diff: https://github.com/llvm/llvm-project/pull/115707.diff
7 Files Affected:
- (modified) llvm/include/llvm/ObjectYAML/ELFYAML.h (+69-1)
- (modified) llvm/include/llvm/Support/YAMLTraits.h (+17)
- (modified) llvm/lib/ObjectYAML/ELFEmitter.cpp (+15-1)
- (modified) llvm/lib/ObjectYAML/ELFYAML.cpp (+23-1)
- (modified) llvm/lib/Support/YAMLTraits.cpp (+8)
- (modified) llvm/tools/obj2yaml/elf2yaml.cpp (+63)
- (modified) llvm/tools/yaml2obj/yaml2obj.cpp (+16)
``````````diff
diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 8f045d6383623b..ee8ca11aa2ee62 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -211,6 +211,7 @@ struct Chunk {
Dynamic,
Group,
RawContent,
+ CustomRawContent,
Relocation,
Relr,
NoBits,
@@ -388,7 +389,7 @@ struct DynamicSection : Section {
struct RawContentSection : Section {
std::optional<llvm::yaml::Hex64> Info;
- RawContentSection() : Section(ChunkKind::RawContent) {}
+ RawContentSection(ChunkKind Kind = ChunkKind::RawContent) : Section(Kind) {}
static bool classof(const Chunk *S) {
return S->Kind == ChunkKind::RawContent;
@@ -398,6 +399,29 @@ struct RawContentSection : Section {
std::optional<std::vector<uint8_t>> ContentBuf;
};
+/// Abstract base class for non-blob contents.
+struct CustomRawContentSection : RawContentSection {
+ CustomRawContentSection() : RawContentSection(ChunkKind::CustomRawContent) {
+ // Type assumes PROGBITS.
+ Type = ELF::SHT_PROGBITS;
+ Flags = ELF::SHF_GNU_RETAIN;
+ AddressAlign = 1;
+ }
+
+ /// Apply mappings.
+ virtual void sectionMapping(yaml::IO &IO) = 0;
+
+ /// Decode Content and store to members.
+ virtual Error decode(const ArrayRef<uint8_t> Content, bool isLE) = 0;
+
+ /// Encode members and returns Content.
+ virtual std::string encode() const = 0;
+
+ static bool classof(const Chunk *S) {
+ return S->Kind == ChunkKind::CustomRawContent;
+ }
+};
+
struct NoBitsSection : Section {
NoBitsSection() : Section(ChunkKind::NoBits) {}
@@ -757,6 +781,50 @@ struct Object {
bool shouldAllocateFileSpace(ArrayRef<ProgramHeader> Phdrs,
const NoBitsSection &S);
+/// ELFYAML::Opt -- Abstract base class for ELFYAML to provide
+/// the interface for handling CustomRawConetentSection.
+///
+/// Users in ELFYAML should obtain the pointer with
+/// dyn_cast<ELFYAML::Opt> if IO::Opt is the instance from yaml::Opt.
+///
+/// if (auto *Opt = dyn_cast<ELFYAML::Opt>(IO.Opt))
+///
+/// Derivered classes should not modify OptClassID to ensue that
+/// dyn_cast<ELFYAML::Opt> can find this interface.
+class Opt : public yaml::Opt {
+public:
+ Opt() {
+ OptClassID = &ID;
+ ELFOptClassID = &ID;
+ }
+ ~Opt();
+
+ /// Create an empty new object of CustomRawContentSection.
+ /// Its contents will be filled later.
+ /// This is called:
+ /// - Before preMapping for elf2yaml.
+ /// - After preMapping for yaml2elf.
+ virtual std::unique_ptr<CustomRawContentSection>
+ makeCustomRawContentSection(StringRef Name) const = 0;
+
+ /// Called before mapping sections for prettyprinting yaml.
+ virtual void preMapping(const ELFYAML::Object &Object, bool IsOutputting) = 0;
+
+ /// Called after mapping sections to gather members for the file format.
+ virtual void postMapping(const ELFYAML::Object &Object,
+ bool IsOutputting) = 0;
+
+ /// Tell IO::Opt to be this and derivered classes.
+ static bool classof(const yaml::Opt *Obj) { return (Obj->OptClassID == &ID); }
+
+ /// This will be not needed unless the pointer to ELFYAML::Opt would
+ /// be cast further.
+ static bool classof(const Opt *Obj) { return (Obj->ELFOptClassID == &ID); }
+ const char *ELFOptClassID;
+
+private:
+ static const char ID;
+};
} // end namespace ELFYAML
} // end namespace llvm
diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h
index 1d04783753d5cd..1f1e06a9e37735 100644
--- a/llvm/include/llvm/Support/YAMLTraits.h
+++ b/llvm/include/llvm/Support/YAMLTraits.h
@@ -39,6 +39,18 @@ class VersionTuple;
namespace yaml {
+/// The base class of options.
+class Opt {
+public:
+ virtual ~Opt();
+
+ static bool classof(const Opt *Obj) { return (Obj->OptClassID == &ID); }
+ const char *OptClassID = &ID;
+
+private:
+ static const char ID;
+};
+
enum class NodeKind : uint8_t {
Scalar,
Map,
@@ -964,6 +976,11 @@ class IO {
private:
void *Ctxt;
+ Opt DefaultOpt;
+
+public:
+ /// This may be overwritten in derivered classes.
+ Opt *Opt = &DefaultOpt;
};
namespace detail {
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index fc234581a45a70..09a540b0485176 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -251,6 +251,9 @@ template <class ELFT> class ELFState {
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::NoBitsSection &Section,
ContiguousBlobAccumulator &CBA);
+ void writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::CustomRawContentSection &Section,
+ ContiguousBlobAccumulator &CBA);
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::RawContentSection &Section,
ContiguousBlobAccumulator &CBA);
@@ -859,7 +862,9 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
if (!isa<ELFYAML::NoBitsSection>(Sec) && (Sec->Content || Sec->Size))
SHeader.sh_size = writeContent(CBA, Sec->Content, Sec->Size);
- if (auto S = dyn_cast<ELFYAML::RawContentSection>(Sec)) {
+ if (auto S = dyn_cast<ELFYAML::CustomRawContentSection>(Sec)) {
+ writeSectionContent(SHeader, *S, CBA);
+ } else if (auto S = dyn_cast<ELFYAML::RawContentSection>(Sec)) {
writeSectionContent(SHeader, *S, CBA);
} else if (auto S = dyn_cast<ELFYAML::SymtabShndxSection>(Sec)) {
writeSectionContent(SHeader, *S, CBA);
@@ -1264,6 +1269,15 @@ void ELFState<ELFT>::writeSectionContent(
SHeader.sh_info = *Section.Info;
}
+template <class ELFT>
+void ELFState<ELFT>::writeSectionContent(
+ Elf_Shdr &SHeader, const ELFYAML::CustomRawContentSection &Section,
+ ContiguousBlobAccumulator &CBA) {
+ std::string Storage = Section.encode();
+ SHeader.sh_size = Storage.size();
+ CBA.write(Storage.data(), Storage.size());
+}
+
static bool isMips64EL(const ELFYAML::Object &Obj) {
return Obj.getMachine() == llvm::ELF::EM_MIPS &&
Obj.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64) &&
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 89ffc383a4a6ec..7d06c2c32e23b8 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -29,6 +29,9 @@ namespace llvm {
ELFYAML::Chunk::~Chunk() = default;
+ELFYAML::Opt::~Opt() = default;
+const char ELFYAML::Opt::ID = 'E';
+
namespace ELFYAML {
ELF_ELFOSABI Object::getOSAbi() const { return Header.OSABI; }
@@ -1582,6 +1585,19 @@ static bool isInteger(StringRef Val) {
void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
IO &IO, std::unique_ptr<ELFYAML::Chunk> &Section) {
+ if (!IO.outputting()) {
+ /// Prepare CustomRawContentSection by Name for ELFEmitter.
+ if (auto *Opt = dyn_cast<ELFYAML::Opt>(IO.Opt)) {
+ StringRef Name;
+ IO.mapOptional("Name", Name);
+ if (auto S = Opt->makeCustomRawContentSection(Name)) {
+ S->sectionMapping(IO);
+ Section = std::move(S);
+ return;
+ }
+ }
+ }
+
ELFYAML::ELF_SHT Type;
StringRef TypeStr;
if (IO.outputting()) {
@@ -1731,7 +1747,9 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
Section = std::make_unique<ELFYAML::RawContentSection>();
}
- if (auto S = dyn_cast<ELFYAML::RawContentSection>(Section.get()))
+ if (auto S = dyn_cast<ELFYAML::CustomRawContentSection>(Section.get()))
+ S->sectionMapping(IO);
+ else if (auto S = dyn_cast<ELFYAML::RawContentSection>(Section.get()))
sectionMapping(IO, *S);
else
sectionMapping(IO, *cast<ELFYAML::StackSizesSection>(Section.get()));
@@ -1981,6 +1999,8 @@ void MappingTraits<ELFYAML::ARMIndexTableEntry>::mapping(
void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
assert(!IO.getContext() && "The IO context is initialized already");
IO.setContext(&Object);
+ if (auto *Opt = dyn_cast<ELFYAML::Opt>(IO.Opt))
+ Opt->preMapping(Object, IO.outputting());
IO.mapTag("!ELF", true);
IO.mapRequired("FileHeader", Object.Header);
IO.mapOptional("ProgramHeaders", Object.ProgramHeaders);
@@ -1994,6 +2014,8 @@ void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
Object.DWARF->Is64BitAddrSize =
Object.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64);
}
+ if (auto *Opt = dyn_cast<ELFYAML::Opt>(IO.Opt))
+ Opt->postMapping(Object, IO.outputting());
IO.setContext(nullptr);
}
diff --git a/llvm/lib/Support/YAMLTraits.cpp b/llvm/lib/Support/YAMLTraits.cpp
index 56b557646100b1..4c5d8d5a138aa4 100644
--- a/llvm/lib/Support/YAMLTraits.cpp
+++ b/llvm/lib/Support/YAMLTraits.cpp
@@ -31,6 +31,14 @@
using namespace llvm;
using namespace yaml;
+//===----------------------------------------------------------------------===//
+// Opt
+//===----------------------------------------------------------------------===//
+
+Opt::~Opt() = default;
+
+const char Opt::ID = '@';
+
//===----------------------------------------------------------------------===//
// IO
//===----------------------------------------------------------------------===//
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 9b4644bde36c0b..3b3fc0f9e8b3c1 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -22,6 +22,19 @@
using namespace llvm;
namespace {
+class DumperOpt : public ELFYAML::Opt {
+public:
+ std::unique_ptr<ELFYAML::CustomRawContentSection>
+ makeCustomRawContentSection(StringRef Name) const override {
+ return nullptr;
+ }
+ void preMapping(const ELFYAML::Object &Object, bool IsOutputting) override {
+ // Do nothing.
+ }
+ void postMapping(const ELFYAML::Object &Object, bool IsOutputting) override {
+ // Do nothing.
+ }
+};
template <class ELFT>
class ELFDumper {
@@ -80,6 +93,8 @@ class ELFDumper {
Expected<ELFYAML::RelrSection *> dumpRelrSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::RawContentSection *>
dumpContentSection(const Elf_Shdr *Shdr);
+ Expected<ELFYAML::CustomRawContentSection *>
+ dumpCustomRawContentSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::SymtabShndxSection *>
dumpSymtabShndxSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::NoBitsSection *> dumpNoBitsSection(const Elf_Shdr *Shdr);
@@ -104,6 +119,8 @@ class ELFDumper {
std::optional<DWARFYAML::Data> DWARF);
public:
+ DumperOpt Opt;
+
ELFDumper(const object::ELFFile<ELFT> &O, std::unique_ptr<DWARFContext> DCtx);
Expected<ELFYAML::Object *> dump();
};
@@ -657,6 +674,18 @@ ELFDumper<ELFT>::dumpSections() {
if (!NameOrErr)
return NameOrErr.takeError();
+ if (auto ResultOrErr = dumpCustomRawContentSection(&Sec)) {
+ auto *Ptr = *ResultOrErr;
+ if (Ptr) {
+ if (Error E = Add(Ptr))
+ return E;
+ continue;
+ } else {
+ // Do nothing -- nullptr
+ }
+ } else
+ return ResultOrErr.takeError();
+
if (ELFYAML::StackSizesSection::nameMatches(*NameOrErr)) {
if (Error E = Add(dumpStackSizesSection(&Sec)))
return std::move(E);
@@ -1654,6 +1683,39 @@ ELFDumper<ELFT>::dumpMipsABIFlags(const Elf_Shdr *Shdr) {
return S.release();
}
+template <class ELFT>
+Expected<ELFYAML::CustomRawContentSection *>
+ELFDumper<ELFT>::dumpCustomRawContentSection(const Elf_Shdr *Shdr) {
+ Expected<StringRef> NameOrErr = getUniquedSectionName(*Shdr);
+ if (Error E = NameOrErr.takeError())
+ return nullptr;
+ auto Name = std::move(*NameOrErr);
+
+ auto S = Opt.makeCustomRawContentSection(Name);
+ if (!S)
+ return nullptr;
+
+ if (Error E = dumpCommonSection(Shdr, *S))
+ return std::move(E);
+
+ unsigned SecIndex = Shdr - &Sections[0];
+ if (SecIndex == 0 && Shdr->sh_type == ELF::SHT_NULL)
+ return nullptr;
+
+ auto ContentOrErr = Obj.getSectionContents(*Shdr);
+ if (!ContentOrErr)
+ return ContentOrErr.takeError();
+
+ ArrayRef<uint8_t> Content = *ContentOrErr;
+ if (Content.empty())
+ return nullptr;
+
+ S->Content = yaml::BinaryRef(Content);
+ if (Error E = S->decode(Content, Obj.isLE()))
+ return E;
+ return S.release();
+}
+
template <class ELFT>
static Error elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj,
std::unique_ptr<DWARFContext> DWARFCtx) {
@@ -1664,6 +1726,7 @@ static Error elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj,
std::unique_ptr<ELFYAML::Object> YAML(YAMLOrErr.get());
yaml::Output Yout(Out);
+ Yout.Opt = &Dumper.Opt;
Yout << *YAML;
return Error::success();
diff --git a/llvm/tools/yaml2obj/yaml2obj.cpp b/llvm/tools/yaml2obj/yaml2obj.cpp
index 4a060e1aad427f..3d356dc7a006fc 100644
--- a/llvm/tools/yaml2obj/yaml2obj.cpp
+++ b/llvm/tools/yaml2obj/yaml2obj.cpp
@@ -58,6 +58,20 @@ static cl::opt<uint64_t> MaxSize(
cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
cl::value_desc("filename"), cl::init("-"),
cl::Prefix, cl::cat(Cat));
+
+class EmitterOpt : public ELFYAML::Opt {
+public:
+ std::unique_ptr<ELFYAML::CustomRawContentSection>
+ makeCustomRawContentSection(StringRef Name) const override {
+ return nullptr;
+ }
+ void preMapping(const ELFYAML::Object &Object, bool IsOutputting) override {
+ // Do nothing.
+ }
+ void postMapping(const ELFYAML::Object &Object, bool IsOutputting) override {
+ // Do nothing.
+ }
+};
} // namespace
static std::optional<std::string> preprocess(StringRef Buf,
@@ -142,7 +156,9 @@ int main(int argc, char **argv) {
if (PreprocessOnly) {
Out->os() << Buffer;
} else {
+ EmitterOpt Opt;
yaml::Input YIn(*Buffer);
+ YIn.Opt = &Opt;
if (!convertYAML(YIn, Out->os(), ErrHandler, DocNum,
MaxSize == 0 ? UINT64_MAX : MaxSize))
``````````
</details>
https://github.com/llvm/llvm-project/pull/115707
More information about the llvm-commits
mailing list