X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-readobj%2Fllvm-readobj.cpp;h=2e95b6b5518f97032ce07e87dec3b1f8243f2241;hb=4ff87aaf84f0fbc9dffa2757fd7a33c7ee9044ea;hp=40e3b8c933bd6f1429261fc1f099240942f5857f;hpb=f010c464a11444733ec67e31aace8bcebeaf2588;p=oota-llvm.git diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 40e3b8c933b..2e95b6b5518 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -7,212 +7,287 @@ // //===----------------------------------------------------------------------===// // -// This program is a utility that works like traditional Unix "readelf", -// except that it can handle any type of object file recognized by lib/Object. +// This is a tool similar to readelf, except it works on multiple object file +// formats. The main purpose of this tool is to provide detailed output suitable +// for FileCheck. // -// It makes use of the generic ObjectFile interface. +// Flags should be similar to readelf where supported, but the output format +// does not need to be identical. The point is to not make users learn yet +// another set of flags. // -// Caution: This utility is new, experimental, unsupported, and incomplete. +// Output should be specialized for each format where appropriate. // //===----------------------------------------------------------------------===// -#include "llvm/ADT/Triple.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Object/ELF.h" +#include "llvm-readobj.h" + +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/system_error.h" + +#include + using namespace llvm; using namespace llvm::object; -static cl::opt -InputFilename(cl::Positional, cl::desc(""), cl::init("")); +namespace opts { + cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::ZeroOrMore); -void DumpSymbolHeader() { - outs() << format(" %-32s", (const char*)"Name") - << format(" %-4s", (const char*)"Type") - << format(" %-16s", (const char*)"Address") - << format(" %-16s", (const char*)"Size") - << format(" %-16s", (const char*)"FileOffset") - << format(" %-26s", (const char*)"Flags") - << "\n"; + // -file-headers, -h + cl::opt FileHeaders("file-headers", + cl::desc("Display file headers ")); + cl::alias FileHeadersShort("h", + cl::desc("Alias for --file-headers"), + cl::aliasopt(FileHeaders)); + + // -sections, -s + cl::opt Sections("sections", + cl::desc("Display all sections.")); + cl::alias SectionsShort("s", + cl::desc("Alias for --sections"), + cl::aliasopt(Sections)); + + // -section-relocations, -sr + cl::opt SectionRelocations("section-relocations", + cl::desc("Display relocations for each section shown.")); + cl::alias SectionRelocationsShort("sr", + cl::desc("Alias for --section-relocations"), + cl::aliasopt(SectionRelocations)); + + // -section-symbols, -st + cl::opt SectionSymbols("section-symbols", + cl::desc("Display symbols for each section shown.")); + cl::alias SectionSymbolsShort("st", + cl::desc("Alias for --section-symbols"), + cl::aliasopt(SectionSymbols)); + + // -section-data, -sd + cl::opt SectionData("section-data", + cl::desc("Display section data for each section shown.")); + cl::alias SectionDataShort("sd", + cl::desc("Alias for --section-data"), + cl::aliasopt(SectionData)); + + // -relocations, -r + cl::opt Relocations("relocations", + cl::desc("Display the relocation entries in the file")); + cl::alias RelocationsShort("r", + cl::desc("Alias for --relocations"), + cl::aliasopt(Relocations)); + + // -symbols, -t + cl::opt Symbols("symbols", + cl::desc("Display the symbol table")); + cl::alias SymbolsShort("t", + cl::desc("Alias for --symbols"), + cl::aliasopt(Symbols)); + + // -dyn-symbols, -dt + cl::opt DynamicSymbols("dyn-symbols", + cl::desc("Display the dynamic symbol table")); + cl::alias DynamicSymbolsShort("dt", + cl::desc("Alias for --dyn-symbols"), + cl::aliasopt(DynamicSymbols)); + + // -unwind, -u + cl::opt UnwindInfo("unwind", + cl::desc("Display unwind information")); + cl::alias UnwindInfoShort("u", + cl::desc("Alias for --unwind"), + cl::aliasopt(UnwindInfo)); + + // -dynamic-table + cl::opt DynamicTable("dynamic-table", + cl::desc("Display the ELF .dynamic section table")); + + // -needed-libs + cl::opt NeededLibraries("needed-libs", + cl::desc("Display the needed libraries")); + + // -program-headers + cl::opt ProgramHeaders("program-headers", + cl::desc("Display ELF program headers")); + + // -expand-relocs + cl::opt ExpandRelocs("expand-relocs", + cl::desc("Expand each shown relocation to multiple lines")); +} // namespace opts + +namespace llvm { + +bool error(error_code EC) { + if (!EC) + return false; + + outs() << "\nError reading file: " << EC.message() << ".\n"; + outs().flush(); + return true; } -const char *GetTypeStr(SymbolRef::Type Type) { - switch (Type) { - case SymbolRef::ST_Unknown: return "?"; - case SymbolRef::ST_Data: return "DATA"; - case SymbolRef::ST_Debug: return "DBG"; - case SymbolRef::ST_File: return "FILE"; - case SymbolRef::ST_Function: return "FUNC"; - case SymbolRef::ST_Other: return "-"; - } - return "INV"; +bool relocAddressLess(RelocationRef a, RelocationRef b) { + uint64_t a_addr, b_addr; + if (error(a.getOffset(a_addr))) return false; + if (error(b.getOffset(b_addr))) return false; + return a_addr < b_addr; } -std::string GetFlagStr(uint32_t Flags) { - std::string result; - if (Flags & SymbolRef::SF_Undefined) - result += "undef,"; - if (Flags & SymbolRef::SF_Global) - result += "global,"; - if (Flags & SymbolRef::SF_Weak) - result += "weak,"; - if (Flags & SymbolRef::SF_Absolute) - result += "absolute,"; - if (Flags & SymbolRef::SF_ThreadLocal) - result += "threadlocal,"; - if (Flags & SymbolRef::SF_Common) - result += "common,"; - if (Flags & SymbolRef::SF_FormatSpecific) - result += "formatspecific,"; - - // Remove trailing comma - if (result.size() > 0) { - result.erase(result.size() - 1); - } - return result; +} // namespace llvm + + +static void reportError(StringRef Input, error_code EC) { + if (Input == "-") + Input = ""; + + errs() << Input << ": " << EC.message() << "\n"; + errs().flush(); } -void DumpSymbol(const SymbolRef &Sym, const ObjectFile *obj, bool IsDynamic) { - StringRef Name; - SymbolRef::Type Type; - uint32_t Flags; - uint64_t Address; - uint64_t Size; - uint64_t FileOffset; - Sym.getName(Name); - Sym.getAddress(Address); - Sym.getSize(Size); - Sym.getFileOffset(FileOffset); - Sym.getType(Type); - Sym.getFlags(Flags); - std::string FullName = Name; - - // If this is a dynamic symbol from an ELF object, append - // the symbol's version to the name. - if (IsDynamic && obj->isELF()) { - StringRef Version; - bool IsDefault; - GetELFSymbolVersion(obj, Sym, Version, IsDefault); - if (!Version.empty()) { - FullName += (IsDefault ? "@@" : "@"); - FullName += Version; - } - } +static void reportError(StringRef Input, StringRef Message) { + if (Input == "-") + Input = ""; - // format() can't handle StringRefs - outs() << format(" %-32s", FullName.c_str()) - << format(" %-4s", GetTypeStr(Type)) - << format(" %16" PRIx64, Address) - << format(" %16" PRIx64, Size) - << format(" %16" PRIx64, FileOffset) - << " " << GetFlagStr(Flags) - << "\n"; + errs() << Input << ": " << Message << "\n"; } +/// @brief Creates an format-specific object file dumper. +static error_code createDumper(const ObjectFile *Obj, + StreamWriter &Writer, + OwningPtr &Result) { + if (!Obj) + return readobj_error::unsupported_file_format; -// Iterate through the normal symbols in the ObjectFile -void DumpSymbols(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - outs() << "Symbols:\n"; - symbol_iterator it = obj->begin_symbols(); - symbol_iterator ie = obj->end_symbols(); - while (it != ie) { - DumpSymbol(*it, obj, false); - it.increment(ec); - if (ec) - report_fatal_error("Symbol iteration failed"); - ++count; - } - outs() << " Total: " << count << "\n\n"; + if (Obj->isCOFF()) + return createCOFFDumper(Obj, Writer, Result); + if (Obj->isELF()) + return createELFDumper(Obj, Writer, Result); + if (Obj->isMachO()) + return createMachODumper(Obj, Writer, Result); + + return readobj_error::unsupported_obj_file_format; } -// Iterate through the dynamic symbols in the ObjectFile. -void DumpDynamicSymbols(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - outs() << "Dynamic Symbols:\n"; - symbol_iterator it = obj->begin_dynamic_symbols(); - symbol_iterator ie = obj->end_dynamic_symbols(); - while (it != ie) { - DumpSymbol(*it, obj, true); - it.increment(ec); - if (ec) - report_fatal_error("Symbol iteration failed"); - ++count; + +/// @brief Dumps the specified object file. +static void dumpObject(const ObjectFile *Obj) { + StreamWriter Writer(outs()); + OwningPtr Dumper; + if (error_code EC = createDumper(Obj, Writer, Dumper)) { + reportError(Obj->getFileName(), EC); + return; } - outs() << " Total: " << count << "\n\n"; -} -void DumpLibrary(const LibraryRef &lib) { - StringRef path; - lib.getPath(path); - outs() << " " << path << "\n"; + outs() << '\n'; + outs() << "File: " << Obj->getFileName() << "\n"; + outs() << "Format: " << Obj->getFileFormatName() << "\n"; + outs() << "Arch: " + << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch()) + << "\n"; + outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n"; + if (Obj->isELF()) + outs() << "LoadName: " << Obj->getLoadName() << "\n"; + + if (opts::FileHeaders) + Dumper->printFileHeaders(); + if (opts::Sections) + Dumper->printSections(); + if (opts::Relocations) + Dumper->printRelocations(); + if (opts::Symbols) + Dumper->printSymbols(); + if (opts::DynamicSymbols) + Dumper->printDynamicSymbols(); + if (opts::UnwindInfo) + Dumper->printUnwindInfo(); + if (opts::DynamicTable) + Dumper->printDynamicTable(); + if (opts::NeededLibraries) + Dumper->printNeededLibraries(); + if (opts::ProgramHeaders) + Dumper->printProgramHeaders(); } -// Iterate through needed libraries -void DumpLibrariesNeeded(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - library_iterator it = obj->begin_libraries_needed(); - library_iterator ie = obj->end_libraries_needed(); - outs() << "Libraries needed:\n"; - while (it != ie) { - DumpLibrary(*it); - it.increment(ec); - if (ec) - report_fatal_error("Needed libraries iteration failed"); - ++count; + +/// @brief Dumps each object file in \a Arc; +static void dumpArchive(const Archive *Arc) { + for (Archive::child_iterator ArcI = Arc->begin_children(), + ArcE = Arc->end_children(); + ArcI != ArcE; ++ArcI) { + OwningPtr child; + if (error_code EC = ArcI->getAsBinary(child)) { + // Ignore non-object files. + if (EC != object_error::invalid_file_type) + reportError(Arc->getFileName(), EC.message()); + continue; + } + + if (ObjectFile *Obj = dyn_cast(child.get())) + dumpObject(Obj); + else + reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); } - outs() << " Total: " << count << "\n\n"; } -void DumpHeaders(const ObjectFile *obj) { - outs() << "File Format : " << obj->getFileFormatName() << "\n"; - outs() << "Arch : " - << Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch()) - << "\n"; - outs() << "Address Size: " << (8*obj->getBytesInAddress()) << " bits\n"; - outs() << "Load Name : " << obj->getLoadName() << "\n"; - outs() << "\n"; + +/// @brief Opens \a File and dumps it. +static void dumpInput(StringRef File) { + // If file isn't stdin, check that it exists. + if (File != "-" && !sys::fs::exists(File)) { + reportError(File, readobj_error::file_not_found); + return; + } + + // Attempt to open the binary. + OwningPtr Binary; + if (error_code EC = createBinary(File, Binary)) { + reportError(File, EC); + return; + } + + if (Archive *Arc = dyn_cast(Binary.get())) + dumpArchive(Arc); + else if (ObjectFile *Obj = dyn_cast(Binary.get())) + dumpObject(Obj); + else + reportError(File, readobj_error::unrecognized_file_format); } -int main(int argc, char** argv) { - error_code ec; + +int main(int argc, const char *argv[]) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; - cl::ParseCommandLineOptions(argc, argv, - "LLVM Object Reader\n"); + // Initialize targets. + llvm::InitializeAllTargetInfos(); - if (InputFilename.empty()) { - errs() << "Please specify an input filename\n"; - return 1; - } + // Register the target printer for --version. + cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); - // Open the object file - OwningPtr File; - if (MemoryBuffer::getFile(InputFilename, File)) { - errs() << InputFilename << ": Open failed\n"; - return 1; - } + cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n"); - ObjectFile *obj = ObjectFile::createObjectFile(File.take()); - if (!obj) { - errs() << InputFilename << ": Object type not recognized\n"; - } + // Default to stdin if no filename is specified. + if (opts::InputFilenames.size() == 0) + opts::InputFilenames.push_back("-"); + + std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), + dumpInput); - DumpHeaders(obj); - DumpSymbols(obj); - DumpDynamicSymbols(obj); - DumpLibrariesNeeded(obj); return 0; } -