Index: include/llvm/Object/ELFNoteDumper.h =================================================================== --- /dev/null +++ include/llvm/Object/ELFNoteDumper.h @@ -0,0 +1,48 @@ +//===- llvm/Object/ELFNoteDumper.h - ELFNoteDumper class --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the declaration of the ELFNoteDumper class, which is used +// to dump the contents of a note from the ELF .note section in readable form. +// ELFNoteDumper is subclassed by targets, and you create an ELFNoteDumper via +// the TargetRegistry. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ELFNOTEDUMPER_H +#define LLVM_OBJECT_ELFNOTEDUMPER_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +class Twine; + +class ELFNoteDumper { +public: + ELFNoteDumper() {} + + ELFNoteDumper(const ELFNoteDumper &) = delete; + ELFNoteDumper &operator=(const ELFNoteDumper &) = delete; + virtual ~ELFNoteDumper() {} + + // Dump the contents of one note from the ELF .note section in readable + // format. This returns false if the implementation does not understand the + // note. + // The .note descriptor (i.e. contents) is passed as an StringRef of bytes as + // found in the ELF file, together with an indication of the endianness of + // the ELF file. + virtual bool dumpNote(unsigned Type, StringRef Name, StringRef Desc, + support::endianness TargetEndianness, raw_ostream &OS) { + return false; + } +}; + +} // end namespace llvm + +#endif // LLVM_OBJECT_ELFNOTEDUMPER_H Index: include/llvm/Support/TargetRegistry.h =================================================================== --- include/llvm/Support/TargetRegistry.h +++ include/llvm/Support/TargetRegistry.h @@ -37,6 +37,7 @@ namespace llvm { class AsmPrinter; +class ELFNoteDumper; class MCAsmBackend; class MCAsmInfo; class MCAsmParser; @@ -190,6 +191,7 @@ const Triple &TT, LLVMOpInfoCallback GetOpInfo, LLVMSymbolLookupCallback SymbolLookUp, void *DisInfo, MCContext *Ctx, std::unique_ptr &&RelInfo); + using ELFNoteDumperCtorTy = ELFNoteDumper *(*)(const Target &T); private: /// Next - The next registered target in the linked list, maintained by the @@ -286,6 +288,10 @@ /// MCSymbolizer, if registered (default = llvm::createMCSymbolizer) MCSymbolizerCtorTy MCSymbolizerCtorFn = nullptr; + /// ELFNoteDumperCtorFn - Construction function for this target's + /// ELF note dumper, if registered. + ELFNoteDumperCtorTy ELFNoteDumperCtorFn = nullptr; + public: Target() = default; @@ -581,6 +587,13 @@ std::move(RelInfo)); } + /// createELFNoteDumper - Create a target specific ELFNoteDumper + ELFNoteDumper *createELFNoteDumper() const { + if (!ELFNoteDumperCtorFn) + return nullptr; + return ELFNoteDumperCtorFn(*this); + } + /// @} }; @@ -895,6 +908,19 @@ T.MCSymbolizerCtorFn = Fn; } + /// RegisterELFNoteDumper - Register an ELFNoteDumper + /// implementation for the given target. + /// + /// Clients are responsible for ensuring that registration doesn't occur + /// while another thread is attempting to access the registry. Typically + /// this is done by initializing all targets at program startup. + /// + /// @param T - The target being registered. + /// @param Fn - A function to construct an ELFNoteDumper for the target. + static void RegisterELFNoteDumper(Target &T, Target::ELFNoteDumperCtorTy Fn) { + T.ELFNoteDumperCtorFn = Fn; + } + /// @} }; Index: tools/llvm-readobj/CMakeLists.txt =================================================================== --- tools/llvm-readobj/CMakeLists.txt +++ tools/llvm-readobj/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + AllTargetsDisassemblers DebugInfoCodeView DebugInfoDWARF Object Index: tools/llvm-readobj/ELFDumper.cpp =================================================================== --- tools/llvm-readobj/ELFDumper.cpp +++ tools/llvm-readobj/ELFDumper.cpp @@ -30,6 +30,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELF.h" +#include "llvm/Object/ELFNoteDumper.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Object/Error.h" @@ -48,6 +49,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/MipsABIFlags.h" #include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -3771,6 +3773,12 @@ auto ProcessNote = [&](const Elf_Note &Note) { StringRef Name = Note.getName(); + // Elf_Note::getDesc erroneously returns an ArrayRef where the + // size is set to the number of bytes, not the number of Elf_Words. But + // fixing size to be the number of Elf_Words wouldn't work either, because + // n_descsz in the note header does not have to be a multiple of 4, so we + // would lose information in the case that the note actually contains + // bytes. The code here copes with what Elf_Note::getDesc returns. ArrayRef Descriptor = Note.getDesc(); Elf_Word Type = Note.getType(); @@ -3786,7 +3794,23 @@ OS << getAMDGPUNoteTypeName(Type) << '\n'; printAMDGPUNote(OS, Type, Descriptor, Descriptor.size()); } else { - OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; + // See if any compiled-in target knows how to dump this note record. A + // target's ELFNoteDumper takes the descriptor as a StringRef of bytes + // from the ELF file, and leaves it to the implementation to sort out + // endianness. + bool Dumped = false; + StringRef Bytes((const char *)Descriptor.data(), Descriptor.size()); + for (auto &T : TargetRegistry::targets()) { + auto Dumper = T.createELFNoteDumper(); + if (Dumper) { + Dumped = Dumper->dumpNote(Type, Name, Bytes, + ELFT::TargetEndianness, OS); + if (Dumped) + break; + } + } + if (!Dumped) + OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; } OS << '\n'; }; Index: tools/llvm-readobj/llvm-readobj.cpp =================================================================== --- tools/llvm-readobj/llvm-readobj.cpp +++ tools/llvm-readobj/llvm-readobj.cpp @@ -39,6 +39,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" using namespace llvm; using namespace llvm::object; @@ -590,6 +591,9 @@ int main(int argc, const char *argv[]) { InitLLVM X(argc, argv); + // For target-specific ELF .note dumping: + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllDisassemblers(); // Register the target printer for --version. cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);