aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-readobj/llvm-readobj.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-02-16 20:13:02 +0000
commitb60736ec1405bb0a8dd40989f67ef4c93da068ab (patch)
tree5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /llvm/tools/llvm-readobj/llvm-readobj.cpp
parentcfca06d7963fa0909f90483b42a6d7d194d01e08 (diff)
Diffstat (limited to 'llvm/tools/llvm-readobj/llvm-readobj.cpp')
-rw-r--r--llvm/tools/llvm-readobj/llvm-readobj.cpp157
1 files changed, 101 insertions, 56 deletions
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index b9c6ad2256ae..41cd4414d051 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -19,20 +19,23 @@
//===----------------------------------------------------------------------===//
#include "llvm-readobj.h"
-#include "Error.h"
#include "ObjDumper.h"
#include "WindowsResourceDumper.h"
#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/Wasm.h"
#include "llvm/Object/WindowsResource.h"
+#include "llvm/Object/XCOFFObjectFile.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/InitLLVM.h"
@@ -63,7 +66,7 @@ namespace opts {
DependentLibraries("dependent-libraries",
cl::desc("Display the dependent libraries section"));
- // --headers -e
+ // --headers, -e
cl::opt<bool>
Headers("headers",
cl::desc("Equivalent to setting: --file-headers, --program-headers, "
@@ -134,6 +137,11 @@ namespace opts {
cl::opt<bool> DynRelocs("dyn-relocations",
cl::desc("Display the dynamic relocation entries in the file"));
+ // --section-details
+ // Also -t in llvm-readelf mode.
+ cl::opt<bool> SectionDetails("section-details",
+ cl::desc("Display the section details"));
+
// --symbols
// Also -s in llvm-readelf mode, or -t in llvm-readobj mode.
cl::opt<bool>
@@ -183,14 +191,18 @@ namespace opts {
cl::aliasopt(ProgramHeaders));
// --string-dump, -p
- cl::list<std::string> StringDump("string-dump", cl::desc("<number|name>"),
- cl::ZeroOrMore);
+ cl::list<std::string> StringDump(
+ "string-dump", cl::value_desc("number|name"),
+ cl::desc("Display the specified section(s) as a list of strings"),
+ cl::ZeroOrMore);
cl::alias StringDumpShort("p", cl::desc("Alias for --string-dump"),
cl::aliasopt(StringDump), cl::Prefix);
// --hex-dump, -x
- cl::list<std::string> HexDump("hex-dump", cl::desc("<number|name>"),
- cl::ZeroOrMore);
+ cl::list<std::string>
+ HexDump("hex-dump", cl::value_desc("number|name"),
+ cl::desc("Display the specified section(s) as hexadecimal bytes"),
+ cl::ZeroOrMore);
cl::alias HexDumpShort("x", cl::desc("Alias for --hex-dump"),
cl::aliasopt(HexDump), cl::Prefix);
@@ -265,6 +277,10 @@ namespace opts {
COFFDebugDirectory("coff-debug-directory",
cl::desc("Display the PE/COFF debug directory"));
+ // --coff-tls-directory
+ cl::opt<bool> COFFTLSDirectory("coff-tls-directory",
+ cl::desc("Display the PE/COFF TLS directory"));
+
// --coff-resources
cl::opt<bool> COFFResources("coff-resources",
cl::desc("Display the PE/COFF .rsrc section"));
@@ -420,55 +436,73 @@ struct ReadObjTypeTableBuilder {
static ReadObjTypeTableBuilder CVTypes;
/// Creates an format-specific object file dumper.
-static std::error_code createDumper(const ObjectFile *Obj,
- ScopedPrinter &Writer,
- std::unique_ptr<ObjDumper> &Result) {
- if (!Obj)
- return readobj_error::unsupported_file_format;
-
- if (Obj->isCOFF())
- return createCOFFDumper(Obj, Writer, Result);
- if (Obj->isELF())
- return createELFDumper(Obj, Writer, Result);
- if (Obj->isMachO())
- return createMachODumper(Obj, Writer, Result);
- if (Obj->isWasm())
- return createWasmDumper(Obj, Writer, Result);
- if (Obj->isXCOFF())
- return createXCOFFDumper(Obj, Writer, Result);
-
- return readobj_error::unsupported_obj_file_format;
+static Expected<std::unique_ptr<ObjDumper>>
+createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) {
+ if (const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(&Obj))
+ return createCOFFDumper(*COFFObj, Writer);
+
+ if (const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj))
+ return createELFDumper(*ELFObj, Writer);
+
+ if (const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(&Obj))
+ return createMachODumper(*MachOObj, Writer);
+
+ if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj))
+ return createWasmDumper(*WasmObj, Writer);
+
+ if (const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(&Obj))
+ return createXCOFFDumper(*XObj, Writer);
+
+ return createStringError(errc::invalid_argument,
+ "unsupported object file format");
}
/// Dumps the specified object file.
-static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
+static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer,
const Archive *A = nullptr) {
std::string FileStr =
- A ? Twine(A->getFileName() + "(" + Obj->getFileName() + ")").str()
- : Obj->getFileName().str();
+ A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str()
+ : Obj.getFileName().str();
- std::unique_ptr<ObjDumper> Dumper;
- if (std::error_code EC = createDumper(Obj, Writer, Dumper))
- reportError(errorCodeToError(EC), FileStr);
+ std::string ContentErrString;
+ if (Error ContentErr = Obj.initContent())
+ ContentErrString = "unable to continue dumping, the file is corrupt: " +
+ toString(std::move(ContentErr));
+
+ ObjDumper *Dumper;
+ Expected<std::unique_ptr<ObjDumper>> DumperOrErr = createDumper(Obj, Writer);
+ if (!DumperOrErr)
+ reportError(DumperOrErr.takeError(), FileStr);
+ Dumper = (*DumperOrErr).get();
if (opts::Output == opts::LLVM || opts::InputFilenames.size() > 1 || A) {
Writer.startLine() << "\n";
Writer.printString("File", FileStr);
}
if (opts::Output == opts::LLVM) {
- Writer.printString("Format", Obj->getFileFormatName());
- Writer.printString("Arch", Triple::getArchTypeName(
- (llvm::Triple::ArchType)Obj->getArch()));
+ Writer.printString("Format", Obj.getFileFormatName());
+ Writer.printString("Arch", Triple::getArchTypeName(Obj.getArch()));
Writer.printString(
"AddressSize",
- std::string(formatv("{0}bit", 8 * Obj->getBytesInAddress())));
+ std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress())));
Dumper->printLoadName();
}
if (opts::FileHeaders)
Dumper->printFileHeaders();
- if (opts::SectionHeaders)
- Dumper->printSectionHeaders();
+
+ // This is only used for ELF currently. In some cases, when an object is
+ // corrupt (e.g. truncated), we can't dump anything except the file header.
+ if (!ContentErrString.empty())
+ reportError(createError(ContentErrString), FileStr);
+
+ if (opts::SectionDetails || opts::SectionHeaders) {
+ if (opts::Output == opts::GNU && opts::SectionDetails)
+ Dumper->printSectionDetails();
+ else
+ Dumper->printSectionHeaders();
+ }
+
if (opts::HashSymbols)
Dumper->printHashSymbols();
if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
@@ -492,10 +526,10 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
if (opts::HashTable)
Dumper->printHashTable();
if (opts::GnuHashTable)
- Dumper->printGnuHashTable(Obj);
+ Dumper->printGnuHashTable();
if (opts::VersionInfo)
Dumper->printVersionInfo();
- if (Obj->isELF()) {
+ if (Obj.isELF()) {
if (opts::DependentLibraries)
Dumper->printDependentLibs();
if (opts::ELFLinkerOptions)
@@ -513,7 +547,7 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
if (opts::Notes)
Dumper->printNotes();
}
- if (Obj->isCOFF()) {
+ if (Obj.isCOFF()) {
if (opts::COFFImports)
Dumper->printCOFFImports();
if (opts::COFFExports)
@@ -524,6 +558,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
Dumper->printCOFFBaseReloc();
if (opts::COFFDebugDirectory)
Dumper->printCOFFDebugDirectory();
+ if (opts::COFFTLSDirectory)
+ Dumper->printCOFFTLSDirectory();
if (opts::COFFResources)
Dumper->printCOFFResources();
if (opts::COFFLoadConfig)
@@ -539,7 +575,7 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable,
opts::CodeViewEnableGHash);
}
- if (Obj->isMachO()) {
+ if (Obj.isMachO()) {
if (opts::MachODataInCode)
Dumper->printMachODataInCode();
if (opts::MachOIndirectSymbols)
@@ -569,13 +605,17 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {
reportError(std::move(E), Arc->getFileName());
continue;
}
- if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
- dumpObject(Obj, Writer, Arc);
- else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))
+
+ Binary *Bin = ChildOrErr->get();
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin))
+ dumpObject(*Obj, Writer, Arc);
+ else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(Bin))
dumpCOFFImportFile(Imp, Writer);
else
- reportError(errorCodeToError(readobj_error::unrecognized_file_format),
- Arc->getFileName());
+ reportWarning(createStringError(errc::invalid_argument,
+ Bin->getFileName() +
+ " has an unsupported file type"),
+ Arc->getFileName());
}
if (Err)
reportError(std::move(Err), Arc->getFileName());
@@ -587,7 +627,7 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,
for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
if (ObjOrErr)
- dumpObject(&*ObjOrErr.get(), Writer);
+ dumpObject(*ObjOrErr.get(), Writer);
else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError()))
reportError(ObjOrErr.takeError(), UBinary->getFileName());
else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
@@ -607,7 +647,8 @@ static void dumpWindowsResourceFile(WindowsResource *WinRes,
/// Opens \a File and dumps it.
static void dumpInput(StringRef File, ScopedPrinter &Writer) {
// Attempt to open the binary.
- Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
+ Expected<OwningBinary<Binary>> BinaryOrErr =
+ createBinary(File, /*Context=*/nullptr, /*InitContent=*/false);
if (!BinaryOrErr)
reportError(BinaryOrErr.takeError(), File);
Binary &Binary = *BinaryOrErr.get().getBinary();
@@ -618,14 +659,13 @@ static void dumpInput(StringRef File, ScopedPrinter &Writer) {
dyn_cast<MachOUniversalBinary>(&Binary))
dumpMachOUniversalBinary(UBinary, Writer);
else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
- dumpObject(Obj, Writer);
+ dumpObject(*Obj, Writer);
else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary))
dumpCOFFImportFile(Import, Writer);
else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary))
dumpWindowsResourceFile(WinRes, Writer);
else
- reportError(errorCodeToError(readobj_error::unrecognized_file_format),
- File);
+ llvm_unreachable("unrecognized file type");
CVTypes.Binaries.push_back(std::move(*BinaryOrErr));
}
@@ -638,8 +678,7 @@ static void registerReadobjAliases() {
cl::aliasopt(opts::SectionHeaders),
cl::NotHidden);
- // Only register -t in llvm-readobj, as readelf reserves it for
- // --section-details (not implemented yet).
+ // llvm-readelf reserves it for --section-details.
static cl::alias SymbolsShort("t", cl::desc("Alias for --symbols"),
cl::aliasopt(opts::Symbols), cl::NotHidden);
@@ -665,6 +704,11 @@ static void registerReadelfAliases() {
cl::aliasopt(opts::Symbols), cl::NotHidden,
cl::Grouping);
+ // -t is here because for readobj it is an alias for --symbols.
+ static cl::alias SectionDetailsShort(
+ "t", cl::desc("Alias for --section-details"),
+ cl::aliasopt(opts::SectionDetails), cl::NotHidden);
+
// Allow all single letter flags to be grouped together.
for (auto &OptEntry : cl::getRegisteredOptions()) {
StringRef ArgName = OptEntry.getKey();
@@ -690,6 +734,11 @@ int main(int argc, const char *argv[]) {
cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n");
+ // Default to print error if no filename is specified.
+ if (opts::InputFilenames.empty()) {
+ error("no input files specified");
+ }
+
if (opts::All) {
opts::FileHeaders = true;
opts::ProgramHeaders = true;
@@ -714,10 +763,6 @@ int main(int argc, const char *argv[]) {
opts::SectionHeaders = true;
}
- // Default to stdin if no filename is specified.
- if (opts::InputFilenames.empty())
- opts::InputFilenames.push_back("-");
-
ScopedPrinter Writer(fouts());
for (const std::string &I : opts::InputFilenames)
dumpInput(I, Writer);