aboutsummaryrefslogtreecommitdiff
path: root/tools/llvm-readobj/llvm-readobj.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-readobj/llvm-readobj.cpp')
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp231
1 files changed, 147 insertions, 84 deletions
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index 40e3b8c933..8f0917fc91 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -7,15 +7,20 @@
//
//===----------------------------------------------------------------------===//
//
-// 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-readobj.h"
+
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Object/ELF.h"
@@ -33,7 +38,7 @@ using namespace llvm::object;
static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input object>"), cl::init(""));
-void DumpSymbolHeader() {
+static void dumpSymbolHeader() {
outs() << format(" %-32s", (const char*)"Name")
<< format(" %-4s", (const char*)"Type")
<< format(" %-16s", (const char*)"Address")
@@ -43,7 +48,16 @@ void DumpSymbolHeader() {
<< "\n";
}
-const char *GetTypeStr(SymbolRef::Type Type) {
+static void dumpSectionHeader() {
+ outs() << format(" %-24s", (const char*)"Name")
+ << format(" %-16s", (const char*)"Address")
+ << format(" %-16s", (const char*)"Size")
+ << format(" %-8s", (const char*)"Align")
+ << format(" %-26s", (const char*)"Flags")
+ << "\n";
+}
+
+static const char *getTypeStr(SymbolRef::Type Type) {
switch (Type) {
case SymbolRef::ST_Unknown: return "?";
case SymbolRef::ST_Data: return "DATA";
@@ -55,7 +69,7 @@ const char *GetTypeStr(SymbolRef::Type Type) {
return "INV";
}
-std::string GetFlagStr(uint32_t Flags) {
+static std::string getSymbolFlagStr(uint32_t Flags) {
std::string result;
if (Flags & SymbolRef::SF_Undefined)
result += "undef,";
@@ -79,102 +93,126 @@ std::string GetFlagStr(uint32_t Flags) {
return result;
}
-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;
- }
- }
-
- // 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";
+static void checkError(error_code ec, const char *msg) {
+ if (ec)
+ report_fatal_error(std::string(msg) + ": " + ec.message());
}
+static std::string getSectionFlagStr(const SectionRef &Section) {
+ const struct {
+ error_code (SectionRef::*MemF)(bool &) const;
+ const char *FlagStr, *ErrorStr;
+ } Work[] =
+ {{ &SectionRef::isText, "text,", "Section.isText() failed" },
+ { &SectionRef::isData, "data,", "Section.isData() failed" },
+ { &SectionRef::isBSS, "bss,", "Section.isBSS() failed" },
+ { &SectionRef::isRequiredForExecution, "required,",
+ "Section.isRequiredForExecution() failed" },
+ { &SectionRef::isVirtual, "virtual,", "Section.isVirtual() failed" },
+ { &SectionRef::isZeroInit, "zeroinit,", "Section.isZeroInit() failed" },
+ { &SectionRef::isReadOnlyData, "rodata,",
+ "Section.isReadOnlyData() failed" }};
-// 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;
+ std::string result;
+ for (uint32_t I = 0; I < sizeof(Work)/sizeof(*Work); ++I) {
+ bool B;
+ checkError((Section.*Work[I].MemF)(B), Work[I].ErrorStr);
+ if (B)
+ result += Work[I].FlagStr;
}
- outs() << " Total: " << count << "\n\n";
+
+ // Remove trailing comma
+ if (result.size() > 0) {
+ result.erase(result.size() - 1);
+ }
+ return result;
}
-// 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;
+static 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;
+ checkError(Sym.getName(Name), "SymbolRef.getName() failed");
+ checkError(Sym.getAddress(Address), "SymbolRef.getAddress() failed");
+ checkError(Sym.getSize(Size), "SymbolRef.getSize() failed");
+ checkError(Sym.getFileOffset(FileOffset),
+ "SymbolRef.getFileOffset() failed");
+ checkError(Sym.getType(Type), "SymbolRef.getType() failed");
+ checkError(Sym.getFlags(Flags), "SymbolRef.getFlags() failed");
+ 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;
+ }
}
- outs() << " Total: " << count << "\n\n";
+
+ // 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)
+ << " " << getSymbolFlagStr(Flags)
+ << "\n";
+}
+
+static void dumpStaticSymbol(const SymbolRef &Sym, const ObjectFile *obj) {
+ return dumpSymbol(Sym, obj, false);
}
-void DumpLibrary(const LibraryRef &lib) {
+static void dumpDynamicSymbol(const SymbolRef &Sym, const ObjectFile *obj) {
+ return dumpSymbol(Sym, obj, true);
+}
+
+static void dumpSection(const SectionRef &Section, const ObjectFile *obj) {
+ StringRef Name;
+ checkError(Section.getName(Name), "SectionRef::getName() failed");
+ uint64_t Addr, Size, Align;
+ checkError(Section.getAddress(Addr), "SectionRef::getAddress() failed");
+ checkError(Section.getSize(Size), "SectionRef::getSize() failed");
+ checkError(Section.getAlignment(Align), "SectionRef::getAlignment() failed");
+ outs() << format(" %-24s", std::string(Name).c_str())
+ << format(" %16" PRIx64, Addr)
+ << format(" %16" PRIx64, Size)
+ << format(" %8" PRIx64, Align)
+ << " " << getSectionFlagStr(Section)
+ << "\n";
+}
+
+static void dumpLibrary(const LibraryRef &lib, const ObjectFile *obj) {
StringRef path;
lib.getPath(path);
outs() << " " << path << "\n";
}
-// Iterate through needed libraries
-void DumpLibrariesNeeded(const ObjectFile *obj) {
+template<typename Iterator, typename Func>
+static void dump(const ObjectFile *obj, Func f, Iterator begin, Iterator end,
+ const char *errStr) {
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";
+ Iterator it = begin, ie = end;
while (it != ie) {
- DumpLibrary(*it);
+ f(*it, obj);
it.increment(ec);
if (ec)
- report_fatal_error("Needed libraries iteration failed");
+ report_fatal_error(errStr);
++count;
}
outs() << " Total: " << count << "\n\n";
}
-void DumpHeaders(const ObjectFile *obj) {
+static void dumpHeaders(const ObjectFile *obj) {
outs() << "File Format : " << obj->getFileFormatName() << "\n";
outs() << "Arch : "
<< Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch())
@@ -204,15 +242,40 @@ int main(int argc, char** argv) {
return 1;
}
- ObjectFile *obj = ObjectFile::createObjectFile(File.take());
+ OwningPtr<ObjectFile> o(ObjectFile::createObjectFile(File.take()));
+ ObjectFile *obj = o.get();
if (!obj) {
errs() << InputFilename << ": Object type not recognized\n";
}
- DumpHeaders(obj);
- DumpSymbols(obj);
- DumpDynamicSymbols(obj);
- DumpLibrariesNeeded(obj);
+ dumpHeaders(obj);
+
+ outs() << "Symbols:\n";
+ dumpSymbolHeader();
+ dump(obj, dumpStaticSymbol, obj->begin_symbols(), obj->end_symbols(),
+ "Symbol iteration failed");
+
+ outs() << "Dynamic Symbols:\n";
+ dumpSymbolHeader();
+ dump(obj, dumpDynamicSymbol, obj->begin_dynamic_symbols(),
+ obj->end_dynamic_symbols(), "Symbol iteration failed");
+
+ outs() << "Sections:\n";
+ dumpSectionHeader();
+ dump(obj, &dumpSection, obj->begin_sections(), obj->end_sections(),
+ "Section iteration failed");
+
+ if (obj->isELF()) {
+ if (ErrorOr<void> e = dumpELFDynamicTable(obj, outs()))
+ ;
+ else
+ errs() << "InputFilename" << ": " << error_code(e).message() << "\n";
+ }
+
+ outs() << "Libraries needed:\n";
+ dump(obj, &dumpLibrary, obj->begin_libraries_needed(),
+ obj->end_libraries_needed(), "Needed libraries iteration failed");
+
return 0;
}