diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2021-02-16 20:13:02 +0000 |
commit | b60736ec1405bb0a8dd40989f67ef4c93da068ab (patch) | |
tree | 5c43fbb7c9fc45f0f87e0e6795a86267dbd12f9d /llvm/tools/llvm-readobj/llvm-readobj.cpp | |
parent | cfca06d7963fa0909f90483b42a6d7d194d01e08 (diff) |
Diffstat (limited to 'llvm/tools/llvm-readobj/llvm-readobj.cpp')
-rw-r--r-- | llvm/tools/llvm-readobj/llvm-readobj.cpp | 157 |
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); |