diff --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp --- a/llvm/tools/llvm-objdump/COFFDump.cpp +++ b/llvm/tools/llvm-objdump/COFFDump.cpp @@ -37,13 +37,15 @@ StringRef Name; }; -class COFFDumper { +class COFFDumper : public Dumper { public: - explicit COFFDumper(const llvm::object::COFFObjectFile &Obj) : Obj(Obj) { + explicit COFFDumper(const llvm::object::COFFObjectFile &O) + : Dumper(O), Obj(O) { Is64 = !Obj.getPE32Header(); } template void printPEHeader(const PEHeader &Hdr) const; + void printPrivateHeaders(bool MachOOnlyFirst) override; private: template FormattedNumber formatAddr(T V) const { @@ -59,6 +61,11 @@ }; } // namespace +std::unique_ptr +objdump::createCOFFDumper(const object::COFFObjectFile &Obj) { + return std::make_unique(Obj); +} + constexpr EnumEntry PEHeaderMagic[] = { {uint16_t(COFF::PE32Header::PE32), "PE32"}, {uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"}, @@ -764,7 +771,7 @@ } } -void objdump::printCOFFFileHeader(const COFFObjectFile &Obj) { +void COFFDumper::printPrivateHeaders(bool MachOOnlyFirst) { COFFDumper CD(Obj); const uint16_t Cha = Obj.getCharacteristics(); outs() << "Characteristics 0x" << Twine::utohexstr(Cha) << '\n'; diff --git a/llvm/tools/llvm-objdump/ELFDump.h b/llvm/tools/llvm-objdump/ELFDump.h --- a/llvm/tools/llvm-objdump/ELFDump.h +++ b/llvm/tools/llvm-objdump/ELFDump.h @@ -30,8 +30,6 @@ uint64_t getELFSectionLMA(const object::ELFSectionRef &Sec); void printELFFileHeader(const object::ObjectFile *O); -void printELFDynamicSection(const object::ObjectFile *Obj); -void printELFSymbolVersionInfo(const object::ObjectFile *Obj); } // namespace objdump } // namespace llvm diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp --- a/llvm/tools/llvm-objdump/ELFDump.cpp +++ b/llvm/tools/llvm-objdump/ELFDump.cpp @@ -24,6 +24,38 @@ using namespace llvm::object; using namespace llvm::objdump; +namespace { +template class ELFDumper : public Dumper { +public: + ELFDumper(const ELFObjectFile &O) : Dumper(O), Obj(O) {} + void printPrivateHeaders(bool MachOOnlyFirst) override; + +private: + const ELFObjectFile &Obj; + + const ELFFile &getELFFile() const { return Obj.getELFFile(); } + void printDynamicSection(); + void printProgramHeaders(); + void printSymbolVersion(); +}; +} // namespace + +template +static std::unique_ptr createDumper(const ELFObjectFile &Obj) { + return std::make_unique>(Obj); +} + +std::unique_ptr +objdump::createELFDumper(const object::ELFObjectFileBase &Obj) { + if (const auto *O = dyn_cast(&Obj)) + return createDumper(*O); + if (const auto *O = dyn_cast(&Obj)) + return createDumper(*O); + if (const auto *O = dyn_cast(&Obj)) + return createDumper(*O); + return createDumper(cast(Obj)); +} + template static Expected getDynamicStrTab(const ELFFile &Elf) { auto DynamicEntriesOrError = Elf.dynamicEntries(); @@ -166,11 +198,11 @@ return getSectionLMA(ELFObj->getELFFile(), Sec); } -template -static void printDynamicSection(const ELFFile &Elf, StringRef Filename) { +template void ELFDumper::printDynamicSection() { + const ELFFile &Elf = getELFFile(); auto DynamicEntriesOrErr = Elf.dynamicEntries(); if (!DynamicEntriesOrErr) { - reportWarning(toString(DynamicEntriesOrErr.takeError()), Filename); + reportWarning(toString(DynamicEntriesOrErr.takeError()), Obj.getFileName()); return; } ArrayRef DynamicEntries = *DynamicEntriesOrErr; @@ -200,21 +232,20 @@ outs() << (Data + Dyn.d_un.d_val) << "\n"; continue; } - reportWarning(toString(StrTabOrErr.takeError()), Filename); + reportWarning(toString(StrTabOrErr.takeError()), Obj.getFileName()); consumeError(StrTabOrErr.takeError()); } outs() << format(Fmt, (uint64_t)Dyn.d_un.d_val); } } -template -static void printProgramHeaders(const ELFFile &Obj, StringRef FileName) { +template void ELFDumper::printProgramHeaders() { outs() << "\nProgram Header:\n"; - auto ProgramHeaderOrError = Obj.program_headers(); + auto ProgramHeaderOrError = getELFFile().program_headers(); if (!ProgramHeaderOrError) { reportWarning("unable to read program headers: " + toString(ProgramHeaderOrError.takeError()), - FileName); + Obj.getFileName()); return; } @@ -338,9 +369,9 @@ } } -template -static void printSymbolVersionInfo(const ELFFile &Elf, - StringRef FileName) { +template void ELFDumper::printSymbolVersion() { + const ELFFile &Elf = getELFFile(); + StringRef FileName = Obj.getFileName(); ArrayRef Sections = unwrapOrError(Elf.sections(), FileName); for (const typename ELFT::Shdr &Shdr : Sections) { @@ -361,35 +392,8 @@ } } -void objdump::printELFFileHeader(const object::ObjectFile *Obj) { - if (const auto *ELFObj = dyn_cast(Obj)) - printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName()); -} - -void objdump::printELFDynamicSection(const object::ObjectFile *Obj) { - if (const auto *ELFObj = dyn_cast(Obj)) - printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printDynamicSection(ELFObj->getELFFile(), Obj->getFileName()); -} - -void objdump::printELFSymbolVersionInfo(const object::ObjectFile *Obj) { - if (const auto *ELFObj = dyn_cast(Obj)) - printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); - else if (const auto *ELFObj = dyn_cast(Obj)) - printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName()); +template void ELFDumper::printPrivateHeaders(bool) { + printProgramHeaders(); + printDynamicSection(); + printSymbolVersion(); } diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -191,8 +191,21 @@ return AAddr < BAddr; } }; + +class MachODumper : public Dumper { + const object::MachOObjectFile &Obj; + +public: + MachODumper(const object::MachOObjectFile &O) : Dumper(O), Obj(O) {} + void printPrivateHeaders(bool OnlyFirst) override; +}; } // namespace +std::unique_ptr +objdump::createMachODumper(const object::MachOObjectFile &Obj) { + return std::make_unique(Obj); +} + // Types for the storted data in code table that is built before disassembly // and the predicate function to sort them. typedef std::pair DiceTableEntry; @@ -2142,7 +2155,8 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF, StringRef ArchiveMemberName = StringRef(), StringRef ArchitectureName = StringRef()) { - Dumper D(*MachOOF); + std::unique_ptr D = createMachODumper(*MachOOF); + // If we are doing some processing here on the Mach-O file print the header // info. And don't print it otherwise like in the case of printing the // UniversalHeaders or ArchiveHeaders. @@ -2228,7 +2242,7 @@ if (DylibId) PrintDylibs(MachOOF, true); if (SymbolTable) - D.printSymbolTable(ArchiveName, ArchitectureName); + D->printSymbolTable(ArchiveName, ArchitectureName); if (UnwindInfo) printMachOUnwindInfo(MachOOF); if (PrivateHeaders) { @@ -10540,6 +10554,12 @@ PrintMachHeader(file, Verbose); } +void MachODumper::printPrivateHeaders(bool OnlyFirst) { + printMachOFileHeader(&Obj); + if (!OnlyFirst) + printMachOLoadCommands(&Obj); +} + void objdump::printMachOLoadCommands(const object::ObjectFile *Obj) { const MachOObjectFile *file = cast(Obj); uint32_t filetype = 0; diff --git a/llvm/tools/llvm-objdump/WasmDump.cpp b/llvm/tools/llvm-objdump/WasmDump.cpp --- a/llvm/tools/llvm-objdump/WasmDump.cpp +++ b/llvm/tools/llvm-objdump/WasmDump.cpp @@ -19,12 +19,25 @@ using namespace llvm; using namespace llvm::object; -void objdump::printWasmFileHeader(const object::ObjectFile *Obj) { - const auto *File = cast(Obj); +namespace { +class WasmDumper : public objdump::Dumper { + const WasmObjectFile &Obj; +public: + WasmDumper(const WasmObjectFile &O) : Dumper(O), Obj(O) {} + void printPrivateHeaders(bool MachOOnlyFirst) override; +}; +} // namespace + +std::unique_ptr +objdump::createWasmDumper(const object::WasmObjectFile &Obj) { + return std::make_unique(Obj); +} + +void WasmDumper::printPrivateHeaders(bool) { outs() << "Program Header:\n"; outs() << "Version: 0x"; - outs().write_hex(File->getHeader().Version); + outs().write_hex(Obj.getHeader().Version); outs() << "\n"; } diff --git a/llvm/tools/llvm-objdump/XCOFFDump.cpp b/llvm/tools/llvm-objdump/XCOFFDump.cpp --- a/llvm/tools/llvm-objdump/XCOFFDump.cpp +++ b/llvm/tools/llvm-objdump/XCOFFDump.cpp @@ -28,6 +28,21 @@ using namespace llvm::XCOFF; using namespace llvm::support; +namespace { +class XCOFFDumper : public objdump::Dumper { +public: + XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O) {} + void printPrivateHeaders(bool MachOOnlyFirst) override; +}; +} // namespace + +std::unique_ptr +objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) { + return std::make_unique(Obj); +} + +void XCOFFDumper::printPrivateHeaders(bool) {} + Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj, const RelocationRef &Rel, SmallVectorImpl &Result) { diff --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h --- a/llvm/tools/llvm-objdump/llvm-objdump.h +++ b/llvm/tools/llvm-objdump/llvm-objdump.h @@ -18,6 +18,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/FormattedStream.h" +#include namespace llvm { class StringRef; @@ -30,6 +31,12 @@ namespace object { class RelocationRef; struct VersionEntry; + +class COFFObjectFile; +class ELFObjectFileBase; +class MachOObjectFile; +class WasmObjectFile; +class XCOFFObjectFile; } // namespace object namespace objdump { @@ -71,10 +78,12 @@ public: Dumper(const object::ObjectFile &O) : O(O) {} + virtual ~Dumper() {} void reportUniqueWarning(Error Err); void reportUniqueWarning(const Twine &Msg); + virtual void printPrivateHeaders(bool MachOOnlyFirst); void printSymbolTable(StringRef ArchiveName, StringRef ArchitectureName = StringRef(), bool DumpDynamic = false); @@ -85,6 +94,12 @@ void printRelocations(); }; +std::unique_ptr createCOFFDumper(const object::COFFObjectFile &Obj); +std::unique_ptr createELFDumper(const object::ELFObjectFileBase &Obj); +std::unique_ptr createMachODumper(const object::MachOObjectFile &Obj); +std::unique_ptr createWasmDumper(const object::WasmObjectFile &Obj); +std::unique_ptr createXCOFFDumper(const object::XCOFFObjectFile &Obj); + // Various helper functions. /// Creates a SectionFilter with a standard predicate that conditionally skips diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -256,6 +256,22 @@ reportWarning(Msg, O.getFileName()); } +static Expected> createDumper(const ObjectFile &Obj) { + if (const auto *O = dyn_cast(&Obj)) + return createCOFFDumper(*O); + if (const auto *O = dyn_cast(&Obj)) + return createELFDumper(*O); + if (const auto *O = dyn_cast(&Obj)) + return createMachODumper(*O); + if (const auto *O = dyn_cast(&Obj)) + return createWasmDumper(*O); + if (const auto *O = dyn_cast(&Obj)) + return createXCOFFDumper(*O); + + return createStringError(errc::invalid_argument, + "unsupported object file format"); +} + namespace { struct FilterResult { // True if the section should not be skipped. @@ -2697,24 +2713,8 @@ outs() << FMP; } -static void printPrivateFileHeaders(const ObjectFile *O, bool OnlyFirst) { - if (O->isELF()) { - printELFFileHeader(O); - printELFDynamicSection(O); - printELFSymbolVersionInfo(O); - return; - } - if (O->isCOFF()) - return printCOFFFileHeader(cast(*O)); - if (O->isWasm()) - return printWasmFileHeader(O); - if (O->isMachO()) { - printMachOFileHeader(O); - if (!OnlyFirst) - printMachOLoadCommands(O); - return; - } - reportError(O->getFileName(), "Invalid/Unsupported object file format"); +void Dumper::printPrivateHeaders(bool) { + reportError(O.getFileName(), "Invalid/Unsupported object file format"); } static void printFileHeaders(const ObjectFile *O) { @@ -2817,7 +2817,13 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr, const Archive::Child *C = nullptr) { - Dumper D(*O); + Expected> DumperOrErr = createDumper(*O); + if (!DumperOrErr) { + reportError(DumperOrErr.takeError(), O->getFileName(), + A ? A->getFileName() : ""); + return; + } + Dumper &D = **DumperOrErr; // Avoid other output when using a raw option. if (!RawClangAST) { @@ -2842,7 +2848,7 @@ if (FileHeaders) printFileHeaders(O); if (PrivateHeaders || FirstPrivateHeader) - printPrivateFileHeaders(O, FirstPrivateHeader); + D.printPrivateHeaders(FirstPrivateHeader); if (SectionHeaders) printSectionHeaders(*O); if (SymbolTable)