[llvm] 0af663f - [llvm-objdump] Create ObjectFile specific dumpers

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 14 12:44:45 PDT 2023


Author: Fangrui Song
Date: 2023-07-14T12:44:41-07:00
New Revision: 0af663f80da0009f6fd879cf4d41743d4c88a2db

URL: https://github.com/llvm/llvm-project/commit/0af663f80da0009f6fd879cf4d41743d4c88a2db
DIFF: https://github.com/llvm/llvm-project/commit/0af663f80da0009f6fd879cf4d41743d4c88a2db.diff

LOG: [llvm-objdump] Create ObjectFile specific dumpers

We pay the one-off boilerplate overhead to create `*Dumper` classes that derive
from objdump::Dumper a la llvm-readobj. This has two primary advantages.

First, a lot object file format specific code can be moved from
llvm-objdump.cpp to *Dump.cpp files. Refactor `printPrivateHeaders` as
an example.

Second, with the introduction of ELFDumper<ELFT>, we can simplify
a few dispatch functions in ELFDump.cpp.

In addition, the ObjectFile specific dumpers contains a ObjectFile specific
reference so that we can remove a lot of `cast<*ObjectFile>(Obj)`.

Reviewed By: mtrofin

Differential Revision: https://reviews.llvm.org/D155045

Added: 
    

Modified: 
    llvm/tools/llvm-objdump/COFFDump.cpp
    llvm/tools/llvm-objdump/ELFDump.cpp
    llvm/tools/llvm-objdump/ELFDump.h
    llvm/tools/llvm-objdump/MachODump.cpp
    llvm/tools/llvm-objdump/WasmDump.cpp
    llvm/tools/llvm-objdump/XCOFFDump.cpp
    llvm/tools/llvm-objdump/llvm-objdump.cpp
    llvm/tools/llvm-objdump/llvm-objdump.h

Removed: 
    


################################################################################
diff  --git a/llvm/tools/llvm-objdump/COFFDump.cpp b/llvm/tools/llvm-objdump/COFFDump.cpp
index b1beedcc324ce1..e1b38471c77fbf 100644
--- a/llvm/tools/llvm-objdump/COFFDump.cpp
+++ b/llvm/tools/llvm-objdump/COFFDump.cpp
@@ -37,13 +37,15 @@ template <typename T> struct EnumEntry {
   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 <class PEHeader> void printPEHeader(const PEHeader &Hdr) const;
+  void printPrivateHeaders(bool MachOOnlyFirst) override;
 
 private:
   template <typename T> FormattedNumber formatAddr(T V) const {
@@ -59,6 +61,11 @@ class COFFDumper {
 };
 } // namespace
 
+std::unique_ptr<Dumper>
+objdump::createCOFFDumper(const object::COFFObjectFile &Obj) {
+  return std::make_unique<COFFDumper>(Obj);
+}
+
 constexpr EnumEntry<uint16_t> PEHeaderMagic[] = {
     {uint16_t(COFF::PE32Header::PE32), "PE32"},
     {uint16_t(COFF::PE32Header::PE32_PLUS), "PE32+"},
@@ -764,7 +771,7 @@ void objdump::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
   }
 }
 
-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.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp
index 6e422042c982af..43ab30991115e9 100644
--- a/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -24,6 +24,38 @@ using namespace llvm;
 using namespace llvm::object;
 using namespace llvm::objdump;
 
+namespace {
+template <typename ELFT> class ELFDumper : public Dumper {
+public:
+  ELFDumper(const ELFObjectFile<ELFT> &O) : Dumper(O), Obj(O) {}
+  void printPrivateHeaders(bool MachOOnlyFirst) override;
+
+private:
+  const ELFObjectFile<ELFT> &Obj;
+
+  const ELFFile<ELFT> &getELFFile() const { return Obj.getELFFile(); }
+  void printDynamicSection();
+  void printProgramHeaders();
+  void printSymbolVersion();
+};
+} // namespace
+
+template <class ELFT>
+static std::unique_ptr<Dumper> createDumper(const ELFObjectFile<ELFT> &Obj) {
+  return std::make_unique<ELFDumper<ELFT>>(Obj);
+}
+
+std::unique_ptr<Dumper>
+objdump::createELFDumper(const object::ELFObjectFileBase &Obj) {
+  if (const auto *O = dyn_cast<ELF32LEObjectFile>(&Obj))
+    return createDumper(*O);
+  if (const auto *O = dyn_cast<ELF32BEObjectFile>(&Obj))
+    return createDumper(*O);
+  if (const auto *O = dyn_cast<ELF64LEObjectFile>(&Obj))
+    return createDumper(*O);
+  return createDumper(cast<ELF64BEObjectFile>(Obj));
+}
+
 template <class ELFT>
 static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> &Elf) {
   auto DynamicEntriesOrError = Elf.dynamicEntries();
@@ -166,11 +198,11 @@ uint64_t objdump::getELFSectionLMA(const object::ELFSectionRef &Sec) {
   return getSectionLMA(ELFObj->getELFFile(), Sec);
 }
 
-template <class ELFT>
-static void printDynamicSection(const ELFFile<ELFT> &Elf, StringRef Filename) {
+template <class ELFT> void ELFDumper<ELFT>::printDynamicSection() {
+  const ELFFile<ELFT> &Elf = getELFFile();
   auto DynamicEntriesOrErr = Elf.dynamicEntries();
   if (!DynamicEntriesOrErr) {
-    reportWarning(toString(DynamicEntriesOrErr.takeError()), Filename);
+    reportWarning(toString(DynamicEntriesOrErr.takeError()), Obj.getFileName());
     return;
   }
   ArrayRef<typename ELFT::Dyn> DynamicEntries = *DynamicEntriesOrErr;
@@ -200,21 +232,20 @@ static void printDynamicSection(const ELFFile<ELFT> &Elf, StringRef Filename) {
         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 <class ELFT>
-static void printProgramHeaders(const ELFFile<ELFT> &Obj, StringRef FileName) {
+template <class ELFT> void ELFDumper<ELFT>::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 @@ static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
   }
 }
 
-template <class ELFT>
-static void printSymbolVersionInfo(const ELFFile<ELFT> &Elf,
-                                   StringRef FileName) {
+template <class ELFT> void ELFDumper<ELFT>::printSymbolVersion() {
+  const ELFFile<ELFT> &Elf = getELFFile();
+  StringRef FileName = Obj.getFileName();
   ArrayRef<typename ELFT::Shdr> Sections =
       unwrapOrError(Elf.sections(), FileName);
   for (const typename ELFT::Shdr &Shdr : Sections) {
@@ -361,35 +392,8 @@ static void printSymbolVersionInfo(const ELFFile<ELFT> &Elf,
   }
 }
 
-void objdump::printELFFileHeader(const object::ObjectFile *Obj) {
-  if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
-    printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
-    printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
-    printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
-    printProgramHeaders(ELFObj->getELFFile(), Obj->getFileName());
-}
-
-void objdump::printELFDynamicSection(const object::ObjectFile *Obj) {
-  if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
-    printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
-    printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
-    printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
-    printDynamicSection(ELFObj->getELFFile(), Obj->getFileName());
-}
-
-void objdump::printELFSymbolVersionInfo(const object::ObjectFile *Obj) {
-  if (const auto *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj))
-    printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj))
-    printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj))
-    printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
-  else if (const auto *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj))
-    printSymbolVersionInfo(ELFObj->getELFFile(), Obj->getFileName());
+template <class ELFT> void ELFDumper<ELFT>::printPrivateHeaders(bool) {
+  printProgramHeaders();
+  printDynamicSection();
+  printSymbolVersion();
 }

diff  --git a/llvm/tools/llvm-objdump/ELFDump.h b/llvm/tools/llvm-objdump/ELFDump.h
index 9b6b1f341cf3a8..205c3d256e2b39 100644
--- a/llvm/tools/llvm-objdump/ELFDump.h
+++ b/llvm/tools/llvm-objdump/ELFDump.h
@@ -30,8 +30,6 @@ Error getELFRelocationValueString(const object::ELFObjectFileBase *Obj,
 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/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index 0e10403ef2d70a..11fb1cb41a9fbd 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -191,8 +191,21 @@ struct SymbolSorter {
     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<Dumper>
+objdump::createMachODumper(const object::MachOObjectFile &Obj) {
+  return std::make_unique<MachODumper>(Obj);
+}
+
 // Types for the storted data in code table that is built before disassembly
 // and the predicate function to sort them.
 typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
@@ -2142,7 +2155,8 @@ static void printObjcMetaData(MachOObjectFile *O, bool verbose);
 static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
                          StringRef ArchiveMemberName = StringRef(),
                          StringRef ArchitectureName = StringRef()) {
-  Dumper D(*MachOOF);
+  std::unique_ptr<Dumper> 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 @@ static void ProcessMachO(StringRef Name, MachOObjectFile *MachOOF,
   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 @@ void objdump::printMachOFileHeader(const object::ObjectFile *Obj) {
   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<const MachOObjectFile>(Obj);
   uint32_t filetype = 0;

diff  --git a/llvm/tools/llvm-objdump/WasmDump.cpp b/llvm/tools/llvm-objdump/WasmDump.cpp
index df0a08e5b1dd05..a1d767d81003f4 100644
--- 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<const WasmObjectFile>(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::Dumper>
+objdump::createWasmDumper(const object::WasmObjectFile &Obj) {
+  return std::make_unique<WasmDumper>(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
index 44ee180e598d5f..87b1679a79692c 100644
--- a/llvm/tools/llvm-objdump/XCOFFDump.cpp
+++ b/llvm/tools/llvm-objdump/XCOFFDump.cpp
@@ -28,6 +28,21 @@ using namespace llvm::object;
 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::Dumper>
+objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) {
+  return std::make_unique<XCOFFDumper>(Obj);
+}
+
+void XCOFFDumper::printPrivateHeaders(bool) {}
+
 Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj,
                                              const RelocationRef &Rel,
                                              SmallVectorImpl<char> &Result) {

diff  --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 052b7f1472e61e..4d2e59d7ddfe0f 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -256,6 +256,22 @@ void Dumper::reportUniqueWarning(const Twine &Msg) {
     reportWarning(Msg, O.getFileName());
 }
 
+static Expected<std::unique_ptr<Dumper>> createDumper(const ObjectFile &Obj) {
+  if (const auto *O = dyn_cast<COFFObjectFile>(&Obj))
+    return createCOFFDumper(*O);
+  if (const auto *O = dyn_cast<ELFObjectFileBase>(&Obj))
+    return createELFDumper(*O);
+  if (const auto *O = dyn_cast<MachOObjectFile>(&Obj))
+    return createMachODumper(*O);
+  if (const auto *O = dyn_cast<WasmObjectFile>(&Obj))
+    return createWasmDumper(*O);
+  if (const auto *O = dyn_cast<XCOFFObjectFile>(&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 @@ static void printFaultMaps(const ObjectFile *Obj) {
   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<object::COFFObjectFile>(*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 checkForInvalidStartStopAddress(ObjectFile *Obj,
 
 static void dumpObject(ObjectFile *O, const Archive *A = nullptr,
                        const Archive::Child *C = nullptr) {
-  Dumper D(*O);
+  Expected<std::unique_ptr<Dumper>> 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 @@ static void dumpObject(ObjectFile *O, const Archive *A = nullptr,
   if (FileHeaders)
     printFileHeaders(O);
   if (PrivateHeaders || FirstPrivateHeader)
-    printPrivateFileHeaders(O, FirstPrivateHeader);
+    D.printPrivateHeaders(FirstPrivateHeader);
   if (SectionHeaders)
     printSectionHeaders(*O);
   if (SymbolTable)

diff  --git a/llvm/tools/llvm-objdump/llvm-objdump.h b/llvm/tools/llvm-objdump/llvm-objdump.h
index ffc13611daf9a2..fd75f552e50b4d 100644
--- 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 <memory>
 
 namespace llvm {
 class StringRef;
@@ -30,6 +31,12 @@ class Arg;
 namespace object {
 class RelocationRef;
 struct VersionEntry;
+
+class COFFObjectFile;
+class ELFObjectFileBase;
+class MachOObjectFile;
+class WasmObjectFile;
+class XCOFFObjectFile;
 } // namespace object
 
 namespace objdump {
@@ -71,10 +78,12 @@ class Dumper {
 
 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 @@ class Dumper {
   void printRelocations();
 };
 
+std::unique_ptr<Dumper> createCOFFDumper(const object::COFFObjectFile &Obj);
+std::unique_ptr<Dumper> createELFDumper(const object::ELFObjectFileBase &Obj);
+std::unique_ptr<Dumper> createMachODumper(const object::MachOObjectFile &Obj);
+std::unique_ptr<Dumper> createWasmDumper(const object::WasmObjectFile &Obj);
+std::unique_ptr<Dumper> createXCOFFDumper(const object::XCOFFObjectFile &Obj);
+
 // Various helper functions.
 
 /// Creates a SectionFilter with a standard predicate that conditionally skips


        


More information about the llvm-commits mailing list