Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ELFYAML] Introduce the external interface CustomSection #115707

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions llvm/include/llvm/ObjectYAML/ELFYAML.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ struct Chunk {
Dynamic,
Group,
RawContent,
CustomContent,
Relocation,
Relr,
NoBits,
Expand Down Expand Up @@ -398,6 +399,26 @@ struct RawContentSection : Section {
std::optional<std::vector<uint8_t>> ContentBuf;
};

/// Abstract base class for non-blob contents.
struct CustomSection : Section {
std::optional<llvm::yaml::Hex64> Info;

CustomSection() : Section(ChunkKind::CustomContent) {}

/// 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::CustomContent;
}
};

struct NoBitsSection : Section {
NoBitsSection() : Section(ChunkKind::NoBits) {}

Expand Down Expand Up @@ -757,6 +778,52 @@ struct Object {
bool shouldAllocateFileSpace(ArrayRef<ProgramHeader> Phdrs,
const NoBitsSection &S);

/// ELFYAML::Opt -- Null 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::IO::OptBase {
public:
Opt() {
OptBaseClassID = &ID;
OptClassID = &ID;
}
~Opt();

/// Create an empty new object of CustomSection.
/// Its contents will be filled later.
/// This is called:
/// - Before preMapping for elf2yaml.
/// - After preMapping for yaml2elf.
/// Returns nullptr to delegate default actions.
virtual std::unique_ptr<CustomSection>
makeCustomSection(StringRef Name) const;

/// Called before mapping sections for prettyprinting yaml.
virtual void preMapping(const ELFYAML::Object &Object, bool IsOutputting);

/// Called after mapping sections to gather members for the file format.
virtual void postMapping(const ELFYAML::Object &Object, bool IsOutputting);

/// Tell IO::OptBase to be this and derivered classes.
static bool classof(const yaml::IO::OptBase *Obj) {
return (Obj->OptBaseClassID == &ID);
}

/// This will be not needed unless the pointer to ELFYAML::Opt would
/// be cast further.
static bool classof(const Opt *Obj) { return (Obj->OptClassID == &ID); }
const char *OptClassID;

private:
static const char ID;
};
} // end namespace ELFYAML
} // end namespace llvm

Expand Down
20 changes: 20 additions & 0 deletions llvm/include/llvm/Support/YAMLTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -962,8 +962,28 @@ class IO {
}
}

public:
/// The base class of options.
class OptBase {
public:
virtual ~OptBase();

static bool classof(const OptBase *Obj) {
return (Obj->OptBaseClassID == &ID);
}
const char *OptBaseClassID = &ID;

private:
static const char ID;
};

private:
void *Ctxt;
OptBase DefaultOpt;

public:
/// This may be overwritten in derivered classes.
OptBase *Opt = &DefaultOpt;
};

namespace detail {
Expand Down
23 changes: 22 additions & 1 deletion llvm/lib/ObjectYAML/ELFEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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::CustomSection &Section,
ContiguousBlobAccumulator &CBA);
void writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::RawContentSection &Section,
ContiguousBlobAccumulator &CBA);
Expand Down Expand Up @@ -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::CustomSection>(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);
Expand Down Expand Up @@ -1264,6 +1269,22 @@ void ELFState<ELFT>::writeSectionContent(
SHeader.sh_info = *Section.Info;
}

template <class ELFT>
void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::CustomSection &Section,
ContiguousBlobAccumulator &CBA) {
if (Section.Info)
SHeader.sh_info = *Section.Info;

// If Section has Content, emit it w/o encoding other fields.
if (Section.Content)
return;

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) &&
Expand Down
39 changes: 38 additions & 1 deletion llvm/lib/ObjectYAML/ELFYAML.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,22 @@ namespace llvm {

ELFYAML::Chunk::~Chunk() = default;

ELFYAML::Opt::~Opt() = default;
const char ELFYAML::Opt::ID = 'E';

std::unique_ptr<ELFYAML::CustomSection>
ELFYAML::Opt::makeCustomSection(StringRef Name) const {
return nullptr;
}

/// Called before mapping sections for prettyprinting yaml.
void ELFYAML::Opt::preMapping(const ELFYAML::Object &Object,
bool IsOutputting) {}

/// Called after mapping sections to gather members for the file format.
void ELFYAML::Opt::postMapping(const ELFYAML::Object &Object,
bool IsOutputting) {}

namespace ELFYAML {
ELF_ELFOSABI Object::getOSAbi() const { return Header.OSABI; }

Expand Down Expand Up @@ -1582,6 +1598,20 @@ 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 CustomSection by Name for ELFEmitter.
if (auto *Opt = dyn_cast<ELFYAML::Opt>(IO.Opt)) {
StringRef Name;
IO.mapOptional("Name", Name);
if (auto S = Opt->makeCustomSection(Name)) {
commonSectionMapping(IO, *S);
S->sectionMapping(IO);
Section = std::move(S);
return;
}
}
}

ELFYAML::ELF_SHT Type;
StringRef TypeStr;
if (IO.outputting()) {
Expand Down Expand Up @@ -1731,7 +1761,10 @@ 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::CustomSection>(Section.get())) {
commonSectionMapping(IO, *S);
S->sectionMapping(IO);
} else if (auto S = dyn_cast<ELFYAML::RawContentSection>(Section.get()))
sectionMapping(IO, *S);
else
sectionMapping(IO, *cast<ELFYAML::StackSizesSection>(Section.get()));
Expand Down Expand Up @@ -1981,6 +2014,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);
Expand All @@ -1994,6 +2029,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);
}

Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Support/YAMLTraits.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
using namespace llvm;
using namespace yaml;

//===----------------------------------------------------------------------===//
// IO::OptBase
//===----------------------------------------------------------------------===//

IO::OptBase::~OptBase() = default;

const char IO::OptBase::ID = '@';

//===----------------------------------------------------------------------===//
// IO
//===----------------------------------------------------------------------===//
Expand Down
49 changes: 49 additions & 0 deletions llvm/tools/obj2yaml/elf2yaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
using namespace llvm;

namespace {
struct DumperOpt : public ELFYAML::Opt {};

template <class ELFT>
class ELFDumper {
Expand Down Expand Up @@ -80,6 +81,7 @@ class ELFDumper {
Expected<ELFYAML::RelrSection *> dumpRelrSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::RawContentSection *>
dumpContentSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::CustomSection *> dumpCustomSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::SymtabShndxSection *>
dumpSymtabShndxSection(const Elf_Shdr *Shdr);
Expected<ELFYAML::NoBitsSection *> dumpNoBitsSection(const Elf_Shdr *Shdr);
Expand All @@ -104,6 +106,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();
};
Expand Down Expand Up @@ -657,6 +661,18 @@ ELFDumper<ELFT>::dumpSections() {
if (!NameOrErr)
return NameOrErr.takeError();

if (auto ResultOrErr = dumpCustomSection(&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);
Expand Down Expand Up @@ -1654,6 +1670,38 @@ ELFDumper<ELFT>::dumpMipsABIFlags(const Elf_Shdr *Shdr) {
return S.release();
}

template <class ELFT>
Expected<ELFYAML::CustomSection *>
ELFDumper<ELFT>::dumpCustomSection(const Elf_Shdr *Shdr) {
Expected<StringRef> NameOrErr = getUniquedSectionName(*Shdr);
if (Error E = NameOrErr.takeError())
return nullptr;
auto Name = std::move(*NameOrErr);

auto S = Opt.makeCustomSection(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;

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) {
Expand All @@ -1664,6 +1712,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();
Expand Down
4 changes: 4 additions & 0 deletions llvm/tools/yaml2obj/yaml2obj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ 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));

struct EmitterOpt : public ELFYAML::Opt {};
} // namespace

static std::optional<std::string> preprocess(StringRef Buf,
Expand Down Expand Up @@ -142,7 +144,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))
Expand Down
Loading