[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