diff options
Diffstat (limited to 'contrib/llvm/tools/llvm-readobj')
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/COFFDumper.cpp | 1014 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ELFDumper.cpp | 800 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/Error.cpp | 62 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/Error.h | 48 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/MachODumper.cpp | 438 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ObjDumper.cpp | 33 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ObjDumper.h | 60 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/StreamWriter.cpp | 79 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/StreamWriter.h | 282 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp | 395 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/llvm-readobj.h | 45 |
11 files changed, 3091 insertions, 165 deletions
diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp new file mode 100644 index 0000000..be4e76c --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -0,0 +1,1014 @@ +//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the COFF-specific dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "ObjDumper.h" + +#include "Error.h" +#include "StreamWriter.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/Win64EH.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +#include <algorithm> +#include <cstring> +#include <time.h> + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::Win64EH; + +namespace { + +class COFFDumper : public ObjDumper { +public: + COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer) + : ObjDumper(Writer) + , Obj(Obj) { + cacheRelocations(); + } + + virtual void printFileHeaders() LLVM_OVERRIDE; + virtual void printSections() LLVM_OVERRIDE; + virtual void printRelocations() LLVM_OVERRIDE; + virtual void printSymbols() LLVM_OVERRIDE; + virtual void printDynamicSymbols() LLVM_OVERRIDE; + virtual void printUnwindInfo() LLVM_OVERRIDE; + +private: + void printSymbol(symbol_iterator SymI); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + void printX64UnwindInfo(); + + void printRuntimeFunction( + const RuntimeFunction& RTF, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels); + + void printUnwindInfo( + const Win64EH::UnwindInfo& UI, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels); + + void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs); + + void cacheRelocations(); + + error_code getSectionContents( + const std::vector<RelocationRef> &Rels, + uint64_t Offset, + ArrayRef<uint8_t> &Contents, + uint64_t &Addr); + + error_code getSection( + const std::vector<RelocationRef> &Rels, + uint64_t Offset, + const coff_section **Section, + uint64_t *AddrPtr); + + typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy; + + const llvm::object::COFFObjectFile *Obj; + RelocMapTy RelocMap; + std::vector<RelocationRef> EmptyRelocs; +}; + +} // namespace + + +namespace llvm { + +error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result) { + const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj); + if (!COFFObj) + return readobj_error::unsupported_obj_file_format; + + Result.reset(new COFFDumper(COFFObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm + + +// Returns the name of the unwind code. +static StringRef getUnwindCodeTypeName(uint8_t Code) { + switch(Code) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: return "PUSH_NONVOL"; + case UOP_AllocLarge: return "ALLOC_LARGE"; + case UOP_AllocSmall: return "ALLOC_SMALL"; + case UOP_SetFPReg: return "SET_FPREG"; + case UOP_SaveNonVol: return "SAVE_NONVOL"; + case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; + case UOP_SaveXMM128: return "SAVE_XMM128"; + case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; + case UOP_PushMachFrame: return "PUSH_MACHFRAME"; + } +} + +// Returns the name of a referenced register. +static StringRef getUnwindRegisterName(uint8_t Reg) { + switch(Reg) { + default: llvm_unreachable("Invalid register"); + case 0: return "RAX"; + case 1: return "RCX"; + case 2: return "RDX"; + case 3: return "RBX"; + case 4: return "RSP"; + case 5: return "RBP"; + case 6: return "RSI"; + case 7: return "RDI"; + case 8: return "R8"; + case 9: return "R9"; + case 10: return "R10"; + case 11: return "R11"; + case 12: return "R12"; + case 13: return "R13"; + case 14: return "R14"; + case 15: return "R15"; + } +} + +// Calculates the number of array slots required for the unwind code. +static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { + switch (UnwindCode.getUnwindOp()) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: + case UOP_AllocSmall: + case UOP_SetFPReg: + case UOP_PushMachFrame: + return 1; + case UOP_SaveNonVol: + case UOP_SaveXMM128: + return 2; + case UOP_SaveNonVolBig: + case UOP_SaveXMM128Big: + return 3; + case UOP_AllocLarge: + return (UnwindCode.getOpInfo() == 0) ? 2 : 3; + } +} + +// Given a symbol sym this functions returns the address and section of it. +static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, + const SymbolRef &Sym, + const coff_section *&ResolvedSection, + uint64_t &ResolvedAddr) { + if (error_code EC = Sym.getAddress(ResolvedAddr)) + return EC; + + section_iterator iter(Obj->begin_sections()); + if (error_code EC = Sym.getSection(iter)) + return EC; + + ResolvedSection = Obj->getCOFFSection(iter); + return object_error::success; +} + +// Given a vector of relocations for a section and an offset into this section +// the function returns the symbol used for the relocation at the offset. +static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, + uint64_t Offset, SymbolRef &Sym) { + for (std::vector<RelocationRef>::const_iterator RelI = Rels.begin(), + RelE = Rels.end(); + RelI != RelE; ++RelI) { + uint64_t Ofs; + if (error_code EC = RelI->getOffset(Ofs)) + return EC; + + if (Ofs == Offset) { + if (error_code EC = RelI->getSymbol(Sym)) + return EC; + return readobj_error::success; + } + } + + return readobj_error::unknown_symbol; +} + +// Given a vector of relocations for a section and an offset into this section +// the function returns the name of the symbol used for the relocation at the +// offset. +static error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, + uint64_t Offset, StringRef &Name) { + SymbolRef Sym; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; + if (error_code EC = Sym.getName(Name)) return EC; + return object_error::success; +} + +static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMV7 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2) +}; + +static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI ) +}; + +static const EnumEntry<COFF::SectionCharacteristics> +ImageSectionCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE ) +}; + +static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = { + { "Null" , COFF::IMAGE_SYM_TYPE_NULL }, + { "Void" , COFF::IMAGE_SYM_TYPE_VOID }, + { "Char" , COFF::IMAGE_SYM_TYPE_CHAR }, + { "Short" , COFF::IMAGE_SYM_TYPE_SHORT }, + { "Int" , COFF::IMAGE_SYM_TYPE_INT }, + { "Long" , COFF::IMAGE_SYM_TYPE_LONG }, + { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT }, + { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE }, + { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT }, + { "Union" , COFF::IMAGE_SYM_TYPE_UNION }, + { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM }, + { "MOE" , COFF::IMAGE_SYM_TYPE_MOE }, + { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE }, + { "Word" , COFF::IMAGE_SYM_TYPE_WORD }, + { "UInt" , COFF::IMAGE_SYM_TYPE_UINT }, + { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD } +}; + +static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = { + { "Null" , COFF::IMAGE_SYM_DTYPE_NULL }, + { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER }, + { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION }, + { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY } +}; + +static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = { + { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION }, + { "Null" , COFF::IMAGE_SYM_CLASS_NULL }, + { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC }, + { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL }, + { "Static" , COFF::IMAGE_SYM_CLASS_STATIC }, + { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER }, + { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF }, + { "Label" , COFF::IMAGE_SYM_CLASS_LABEL }, + { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL }, + { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT }, + { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT }, + { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG }, + { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION }, + { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG }, + { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION }, + { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC }, + { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG }, + { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM }, + { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM }, + { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD }, + { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK }, + { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION }, + { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT }, + { "File" , COFF::IMAGE_SYM_CLASS_FILE }, + { "Section" , COFF::IMAGE_SYM_CLASS_SECTION }, + { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL }, + { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN } +}; + +static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = { + { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES }, + { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY }, + { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE }, + { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH }, + { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE }, + { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST }, + { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST } +}; + +static const EnumEntry<COFF::WeakExternalCharacteristics> +WeakExternalCharacteristics[] = { + { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY }, + { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY }, + { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } +}; + +static const EnumEntry<unsigned> UnwindFlags[] = { + { "ExceptionHandler", Win64EH::UNW_ExceptionHandler }, + { "TerminateHandler", Win64EH::UNW_TerminateHandler }, + { "ChainInfo" , Win64EH::UNW_ChainInfo } +}; + +static const EnumEntry<unsigned> UnwindOpInfo[] = { + { "RAX", 0 }, + { "RCX", 1 }, + { "RDX", 2 }, + { "RBX", 3 }, + { "RSP", 4 }, + { "RBP", 5 }, + { "RSI", 6 }, + { "RDI", 7 }, + { "R8", 8 }, + { "R9", 9 }, + { "R10", 10 }, + { "R11", 11 }, + { "R12", 12 }, + { "R13", 13 }, + { "R14", 14 }, + { "R15", 15 } +}; + +// Some additional COFF structures not defined by llvm::object. +namespace { + struct coff_aux_function_definition { + support::ulittle32_t TagIndex; + support::ulittle32_t TotalSize; + support::ulittle32_t PointerToLineNumber; + support::ulittle32_t PointerToNextFunction; + uint8_t Unused[2]; + }; + + struct coff_aux_weak_external_definition { + support::ulittle32_t TagIndex; + support::ulittle32_t Characteristics; + uint8_t Unused[10]; + }; + + struct coff_aux_file_record { + char FileName[18]; + }; + + struct coff_aux_clr_token { + support::ulittle8_t AuxType; + support::ulittle8_t Reserved; + support::ulittle32_t SymbolTableIndex; + uint8_t Unused[12]; + }; +} // namespace + +static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) { + return static_cast<const char*>(UI.getLanguageSpecificData()) + - reinterpret_cast<const char*>(&UI); +} + +static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UCs) { + if (UCs.size() < 3) + return 0; + + return UCs[1].FrameOffset + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16); +} + +template<typename T> +static error_code getSymbolAuxData(const COFFObjectFile *Obj, + const coff_symbol *Symbol, const T* &Aux) { + ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); + Aux = reinterpret_cast<const T*>(AuxData.data()); + return readobj_error::success; +} + +static std::string formatSymbol(const std::vector<RelocationRef> &Rels, + uint64_t Offset, uint32_t Disp) { + std::string Buffer; + raw_string_ostream Str(Buffer); + + StringRef Sym; + if (resolveSymbolName(Rels, Offset, Sym)) { + Str << format(" (0x%X)", Offset); + return Str.str(); + } + + Str << Sym; + if (Disp > 0) { + Str << format(" +0x%X (0x%X)", Disp, Offset); + } else { + Str << format(" (0x%X)", Offset); + } + + return Str.str(); +} + +// Given a vector of relocations for a section and an offset into this section +// the function resolves the symbol used for the relocation at the offset and +// returns the section content and the address inside the content pointed to +// by the symbol. +error_code COFFDumper::getSectionContents( + const std::vector<RelocationRef> &Rels, uint64_t Offset, + ArrayRef<uint8_t> &Contents, uint64_t &Addr) { + + SymbolRef Sym; + const coff_section *Section; + + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; + if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + return EC; + if (error_code EC = Obj->getSectionContents(Section, Contents)) + return EC; + + return object_error::success; +} + +error_code COFFDumper::getSection( + const std::vector<RelocationRef> &Rels, uint64_t Offset, + const coff_section **SectionPtr, uint64_t *AddrPtr) { + + SymbolRef Sym; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; + + const coff_section *Section; + uint64_t Addr; + if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + return EC; + + if (SectionPtr) + *SectionPtr = Section; + if (AddrPtr) + *AddrPtr = Addr; + + return object_error::success; +} + +void COFFDumper::cacheRelocations() { + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) + break; + + const coff_section *Section = Obj->getCOFFSection(SecI); + + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) + break; + + RelocMap[Section].push_back(*RelI); + } + + // Sort relocations by address. + std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), + relocAddressLess); + } +} + +void COFFDumper::printFileHeaders() { + const coff_file_header *Header = 0; + if (error(Obj->getHeader(Header))) + return; + + time_t TDS = Header->TimeDateStamp; + char FormattedTime[20] = { }; + strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); + + { + DictScope D(W, "ImageFileHeader"); + W.printEnum ("Machine", Header->Machine, + makeArrayRef(ImageFileMachineType)); + W.printNumber("SectionCount", Header->NumberOfSections); + W.printHex ("TimeDateStamp", FormattedTime, Header->TimeDateStamp); + W.printHex ("PointerToSymbolTable", Header->PointerToSymbolTable); + W.printNumber("SymbolCount", Header->NumberOfSymbols); + W.printNumber("OptionalHeaderSize", Header->SizeOfOptionalHeader); + W.printFlags ("Characteristics", Header->Characteristics, + makeArrayRef(ImageFileCharacteristics)); + } +} + +void COFFDumper::printSections() { + error_code EC; + + ListScope SectionsD(W, "Sections"); + int SectionNumber = 0; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) + break; + + ++SectionNumber; + const coff_section *Section = Obj->getCOFFSection(SecI); + + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + DictScope D(W, "Section"); + W.printNumber("Number", SectionNumber); + W.printBinary("Name", Name, Section->Name); + W.printHex ("VirtualSize", Section->VirtualSize); + W.printHex ("VirtualAddress", Section->VirtualAddress); + W.printNumber("RawDataSize", Section->SizeOfRawData); + W.printHex ("PointerToRawData", Section->PointerToRawData); + W.printHex ("PointerToRelocations", Section->PointerToRelocations); + W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers); + W.printNumber("RelocationCount", Section->NumberOfRelocations); + W.printNumber("LineNumberCount", Section->NumberOfLinenumbers); + W.printFlags ("Characteristics", Section->Characteristics, + makeArrayRef(ImageSectionCharacteristics), + COFF::SectionCharacteristics(0x00F00000)); + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + printRelocation(SecI, RelI); + } + } + + if (opts::SectionSymbols) { + ListScope D(W, "Symbols"); + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +void COFFDumper::printRelocations() { + ListScope D(W, "Relocations"); + + error_code EC; + int SectionNumber = 0; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + ++SectionNumber; + if (error(EC)) + break; + + StringRef Name; + if (error(SecI->getName(Name))) + continue; + + bool PrintedGroup = false; + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + if (!PrintedGroup) { + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +void COFFDumper::printRelocation(section_iterator SecI, + relocation_iterator RelI) { + uint64_t Offset; + uint64_t RelocType; + SmallString<32> RelocName; + SymbolRef Symbol; + StringRef SymbolName; + StringRef Contents; + if (error(RelI->getOffset(Offset))) return; + if (error(RelI->getType(RelocType))) return; + if (error(RelI->getTypeName(RelocName))) return; + if (error(RelI->getSymbol(Symbol))) return; + if (error(Symbol.getName(SymbolName))) return; + if (error(SecI->getContents(Contents))) return; + + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << RelocName + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << "\n"; +} + +void COFFDumper::printSymbols() { + ListScope Group(W, "Symbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI); + } +} + +void COFFDumper::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); +} + +void COFFDumper::printSymbol(symbol_iterator SymI) { + DictScope D(W, "Symbol"); + + const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI); + const coff_section *Section; + if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { + W.startLine() << "Invalid section number: " << EC.message() << "\n"; + W.flush(); + return; + } + + StringRef SymbolName; + if (Obj->getSymbolName(Symbol, SymbolName)) + SymbolName = ""; + + StringRef SectionName; + if (Section && Obj->getSectionName(Section, SectionName)) + SectionName = ""; + + W.printString("Name", SymbolName); + W.printNumber("Value", Symbol->Value); + W.printNumber("Section", SectionName, Symbol->SectionNumber); + W.printEnum ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType)); + W.printEnum ("ComplexType", Symbol->getComplexType(), + makeArrayRef(ImageSymDType)); + W.printEnum ("StorageClass", Symbol->StorageClass, + makeArrayRef(ImageSymClass)); + W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols); + + for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) { + if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && + Symbol->getBaseType() == COFF::IMAGE_SYM_TYPE_NULL && + Symbol->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION && + Symbol->SectionNumber > 0) { + const coff_aux_function_definition *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxFunctionDef"); + W.printNumber("TagIndex", Aux->TagIndex); + W.printNumber("TotalSize", Aux->TotalSize); + W.printHex("PointerToLineNumber", Aux->PointerToLineNumber); + W.printHex("PointerToNextFunction", Aux->PointerToNextFunction); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); + + } else if ( + Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL || + (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && + Symbol->SectionNumber == 0 && + Symbol->Value == 0)) { + const coff_aux_weak_external_definition *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + const coff_symbol *Linked; + StringRef LinkedName; + error_code EC; + if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) || + (EC = Obj->getSymbolName(Linked, LinkedName))) { + LinkedName = ""; + error(EC); + } + + DictScope AS(W, "AuxWeakExternal"); + W.printNumber("Linked", LinkedName, Aux->TagIndex); + W.printEnum ("Search", Aux->Characteristics, + makeArrayRef(WeakExternalCharacteristics)); + W.printBinary("Unused", Aux->Unused); + + } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) { + const coff_aux_file_record *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC) { + const coff_aux_section_definition *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxSectionDef"); + W.printNumber("Length", Aux->Length); + W.printNumber("RelocationCount", Aux->NumberOfRelocations); + W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers); + W.printHex("Checksum", Aux->CheckSum); + W.printNumber("Number", Aux->Number); + W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect)); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); + + if (Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT + && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + const coff_section *Assoc; + StringRef AssocName; + error_code EC; + if ((EC = Obj->getSection(Aux->Number, Assoc)) || + (EC = Obj->getSectionName(Assoc, AssocName))) { + AssocName = ""; + error(EC); + } + + W.printNumber("AssocSection", AssocName, Aux->Number); + } + } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) { + const coff_aux_clr_token *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxCLRToken"); + W.printNumber("AuxType", Aux->AuxType); + W.printNumber("Reserved", Aux->Reserved); + W.printNumber("SymbolTableIndex", Aux->SymbolTableIndex); + W.printBinary("Unused", Aux->Unused); + + } else { + W.startLine() << "<unhandled auxiliary record>\n"; + } + } +} + +void COFFDumper::printUnwindInfo() { + const coff_file_header *Header; + if (error(Obj->getHeader(Header))) + return; + + ListScope D(W, "UnwindInformation"); + if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { + W.startLine() << "Unsupported image machine type " + "(currently only AMD64 is supported).\n"; + return; + } + + printX64UnwindInfo(); +} + +void COFFDumper::printX64UnwindInfo() { + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + StringRef Name; + if (error(SecI->getName(Name))) + continue; + if (Name != ".pdata" && !Name.startswith(".pdata$")) + continue; + + const coff_section *PData = Obj->getCOFFSection(SecI); + + ArrayRef<uint8_t> Contents; + if (error(Obj->getSectionContents(PData, Contents)) || + Contents.empty()) + continue; + + ArrayRef<RuntimeFunction> RFs( + reinterpret_cast<const RuntimeFunction *>(Contents.data()), + Contents.size() / sizeof(RuntimeFunction)); + + for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) { + const uint64_t OffsetInSection = std::distance(RFs.begin(), I) + * sizeof(RuntimeFunction); + + printRuntimeFunction(*I, OffsetInSection, RelocMap[PData]); + } + } +} + +void COFFDumper::printRuntimeFunction( + const RuntimeFunction& RTF, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels) { + + DictScope D(W, "RuntimeFunction"); + W.printString("StartAddress", + formatSymbol(Rels, OffsetInSection + 0, RTF.StartAddress)); + W.printString("EndAddress", + formatSymbol(Rels, OffsetInSection + 4, RTF.EndAddress)); + W.printString("UnwindInfoAddress", + formatSymbol(Rels, OffsetInSection + 8, RTF.UnwindInfoOffset)); + + const coff_section* XData = 0; + uint64_t UnwindInfoOffset = 0; + if (error(getSection(Rels, OffsetInSection + 8, &XData, &UnwindInfoOffset))) + return; + + ArrayRef<uint8_t> XContents; + if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty()) + return; + + UnwindInfoOffset += RTF.UnwindInfoOffset; + if (UnwindInfoOffset > XContents.size()) + return; + + const Win64EH::UnwindInfo *UI = + reinterpret_cast<const Win64EH::UnwindInfo *>( + XContents.data() + UnwindInfoOffset); + + printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]); +} + +void COFFDumper::printUnwindInfo( + const Win64EH::UnwindInfo& UI, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels) { + DictScope D(W, "UnwindInfo"); + W.printNumber("Version", UI.getVersion()); + W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); + W.printNumber("PrologSize", UI.PrologSize); + if (UI.getFrameRegister() != 0) { + W.printEnum("FrameRegister", UI.getFrameRegister(), + makeArrayRef(UnwindOpInfo)); + W.printHex("FrameOffset", UI.getFrameOffset()); + } else { + W.printString("FrameRegister", StringRef("-")); + W.printString("FrameOffset", StringRef("-")); + } + + W.printNumber("UnwindCodeCount", UI.NumCodes); + { + ListScope CodesD(W, "UnwindCodes"); + ArrayRef<UnwindCode> UCs(&UI.UnwindCodes[0], UI.NumCodes); + for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) { + unsigned UsedSlots = getNumUsedSlots(*I); + if (UsedSlots > UCs.size()) { + errs() << "Corrupt unwind data"; + return; + } + printUnwindCode(UI, ArrayRef<UnwindCode>(I, E)); + I += UsedSlots - 1; + } + } + + uint64_t LSDAOffset = OffsetInSection + getOffsetOfLSDA(UI); + if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { + W.printString("Handler", formatSymbol(Rels, LSDAOffset, + UI.getLanguageSpecificHandlerOffset())); + } else if (UI.getFlags() & UNW_ChainInfo) { + const RuntimeFunction *Chained = UI.getChainedFunctionEntry(); + if (Chained) { + DictScope D(W, "Chained"); + W.printString("StartAddress", formatSymbol(Rels, LSDAOffset + 0, + Chained->StartAddress)); + W.printString("EndAddress", formatSymbol(Rels, LSDAOffset + 4, + Chained->EndAddress)); + W.printString("UnwindInfoAddress", formatSymbol(Rels, LSDAOffset + 8, + Chained->UnwindInfoOffset)); + } + } +} + +// Prints one unwind code. Because an unwind code can occupy up to 3 slots in +// the unwind codes array, this function requires that the correct number of +// slots is provided. +void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI, + ArrayRef<UnwindCode> UCs) { + assert(UCs.size() >= getNumUsedSlots(UCs[0])); + + W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset)) + << getUnwindCodeTypeName(UCs[0].getUnwindOp()); + + uint32_t AllocSize = 0; + + switch (UCs[0].getUnwindOp()) { + case UOP_PushNonVol: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()); + break; + + case UOP_AllocLarge: + if (UCs[0].getOpInfo() == 0) { + AllocSize = UCs[1].FrameOffset * 8; + } else { + AllocSize = getLargeSlotValue(UCs); + } + outs() << " size=" << AllocSize; + break; + case UOP_AllocSmall: + outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8); + break; + case UOP_SetFPReg: + if (UI.getFrameRegister() == 0) { + outs() << " reg=<invalid>"; + } else { + outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) + << format(", offset=0x%X", UI.getFrameOffset() * 16); + } + break; + case UOP_SaveNonVol: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) + << format(", offset=0x%X", UCs[1].FrameOffset * 8); + break; + case UOP_SaveNonVolBig: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UCs)); + break; + case UOP_SaveXMM128: + outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) + << format(", offset=0x%X", UCs[1].FrameOffset * 16); + break; + case UOP_SaveXMM128Big: + outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UCs)); + break; + case UOP_PushMachFrame: + outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes"); + break; + } + + outs() << "\n"; +} diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp new file mode 100644 index 0000000..9e111dd --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -0,0 +1,800 @@ +//===-- ELFDumper.cpp - ELF-specific dumper ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the ELF-specific dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; +using namespace ELF; + + +#define LLVM_READOBJ_ENUM_CASE(ns, enum) \ + case ns::enum: return #enum; + +namespace { + +template<typename ELFT> +class ELFDumper : public ObjDumper { +public: + ELFDumper(const ELFObjectFile<ELFT> *Obj, StreamWriter& Writer) + : ObjDumper(Writer) + , Obj(Obj) { } + + virtual void printFileHeaders() LLVM_OVERRIDE; + virtual void printSections() LLVM_OVERRIDE; + virtual void printRelocations() LLVM_OVERRIDE; + virtual void printSymbols() LLVM_OVERRIDE; + virtual void printDynamicSymbols() LLVM_OVERRIDE; + virtual void printUnwindInfo() LLVM_OVERRIDE; + + virtual void printDynamicTable() LLVM_OVERRIDE; + virtual void printNeededLibraries() LLVM_OVERRIDE; + +private: + typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + + void printSymbol(symbol_iterator SymI, bool IsDynamic = false); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + const ELFObjectFile<ELFT> *Obj; +}; + +} // namespace + + +namespace llvm { + +error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result) { + typedef ELFType<support::little, 4, false> Little32ELF; + typedef ELFType<support::big, 4, false> Big32ELF; + typedef ELFType<support::little, 4, true > Little64ELF; + typedef ELFType<support::big, 8, true > Big64ELF; + + typedef ELFObjectFile<Little32ELF> LittleELF32Obj; + typedef ELFObjectFile<Big32ELF > BigELF32Obj; + typedef ELFObjectFile<Little64ELF> LittleELF64Obj; + typedef ELFObjectFile<Big64ELF > BigELF64Obj; + + // Little-endian 32-bit + if (const LittleELF32Obj *ELFObj = dyn_cast<LittleELF32Obj>(Obj)) { + Result.reset(new ELFDumper<Little32ELF>(ELFObj, Writer)); + return readobj_error::success; + } + + // Big-endian 32-bit + if (const BigELF32Obj *ELFObj = dyn_cast<BigELF32Obj>(Obj)) { + Result.reset(new ELFDumper<Big32ELF>(ELFObj, Writer)); + return readobj_error::success; + } + + // Little-endian 64-bit + if (const LittleELF64Obj *ELFObj = dyn_cast<LittleELF64Obj>(Obj)) { + Result.reset(new ELFDumper<Little64ELF>(ELFObj, Writer)); + return readobj_error::success; + } + + // Big-endian 64-bit + if (const BigELF64Obj *ELFObj = dyn_cast<BigELF64Obj>(Obj)) { + Result.reset(new ELFDumper<Big64ELF>(ELFObj, Writer)); + return readobj_error::success; + } + + return readobj_error::unsupported_obj_file_format; +} + +} // namespace llvm + + +static const EnumEntry<unsigned> ElfClass[] = { + { "None", ELF::ELFCLASSNONE }, + { "32-bit", ELF::ELFCLASS32 }, + { "64-bit", ELF::ELFCLASS64 }, +}; + +static const EnumEntry<unsigned> ElfDataEncoding[] = { + { "None", ELF::ELFDATANONE }, + { "LittleEndian", ELF::ELFDATA2LSB }, + { "BigEndian", ELF::ELFDATA2MSB }, +}; + +static const EnumEntry<unsigned> ElfObjectFileType[] = { + { "None", ELF::ET_NONE }, + { "Relocatable", ELF::ET_REL }, + { "Executable", ELF::ET_EXEC }, + { "SharedObject", ELF::ET_DYN }, + { "Core", ELF::ET_CORE }, +}; + +static const EnumEntry<unsigned> ElfOSABI[] = { + { "SystemV", ELF::ELFOSABI_NONE }, + { "HPUX", ELF::ELFOSABI_HPUX }, + { "NetBSD", ELF::ELFOSABI_NETBSD }, + { "GNU/Linux", ELF::ELFOSABI_LINUX }, + { "GNU/Hurd", ELF::ELFOSABI_HURD }, + { "Solaris", ELF::ELFOSABI_SOLARIS }, + { "AIX", ELF::ELFOSABI_AIX }, + { "IRIX", ELF::ELFOSABI_IRIX }, + { "FreeBSD", ELF::ELFOSABI_FREEBSD }, + { "TRU64", ELF::ELFOSABI_TRU64 }, + { "Modesto", ELF::ELFOSABI_MODESTO }, + { "OpenBSD", ELF::ELFOSABI_OPENBSD }, + { "OpenVMS", ELF::ELFOSABI_OPENVMS }, + { "NSK", ELF::ELFOSABI_NSK }, + { "AROS", ELF::ELFOSABI_AROS }, + { "FenixOS", ELF::ELFOSABI_FENIXOS }, + { "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI }, + { "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX }, + { "ARM", ELF::ELFOSABI_ARM }, + { "Standalone" , ELF::ELFOSABI_STANDALONE } +}; + +static const EnumEntry<unsigned> ElfMachineType[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EM_NONE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_386 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_88K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_486 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_860 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_S370 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_RS3_LE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PARISC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VPP500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC32PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_960 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_S390 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_V800 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FR20 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RH32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RCE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARM ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ALPHA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SH ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARCV9 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TRICORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300H ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8S ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_IA_64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COLDFIRE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC12 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PCP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NCPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NDR1 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STARCORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ME16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST100 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TINYJ ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_X86_64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDSP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP10 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP11 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FX66 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST9PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST7 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC11 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC08 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC05 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SVX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST19 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VAX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRIS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_JAVELIN ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FIREPATH ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ZSP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMIX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_HUANY ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PRISM ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FR30 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_D10V ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_D30V ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_V850 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32R ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10300 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10200 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PJ ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_OPENRISC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XTENSA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TMM_GPP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NS32K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TPC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SNP1K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST200 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_IP2K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MAX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_F2MC16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MSP430 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_BLACKFIN ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C33 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SEP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARCA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_UNICORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_EXCESS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DXP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ALTERA_NIOS2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XGATE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_C166 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M16C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DSPIC30F ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TSK3000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RS08 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SHARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SCORE7 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DSP24 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE3 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_LATTICEMICO32), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C17 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C6000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C2000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C5500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMDSP_PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CYPRESS_M8C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_R32C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TRIMEDIA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_HEXAGON ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_8051 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STXP7X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NDS32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MAXQ30 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XIMO16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MANIK ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRAYNV2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_METAG ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MCST_ELBRUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CR16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ETPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SLE9X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_L10M ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_K10M ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AARCH64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STM8 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILE64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEPRO ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MICROBLAZE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_1ST ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_2ND ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_OPEN8 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RL78 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE5 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_78KOR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MBLAZE ) +}; + +static const EnumEntry<unsigned> ElfSymbolBindings[] = { + { "Local", ELF::STB_LOCAL }, + { "Global", ELF::STB_GLOBAL }, + { "Weak", ELF::STB_WEAK } +}; + +static const EnumEntry<unsigned> ElfSymbolTypes[] = { + { "None", ELF::STT_NOTYPE }, + { "Object", ELF::STT_OBJECT }, + { "Function", ELF::STT_FUNC }, + { "Section", ELF::STT_SECTION }, + { "File", ELF::STT_FILE }, + { "Common", ELF::STT_COMMON }, + { "TLS", ELF::STT_TLS }, + { "GNU_IFunc", ELF::STT_GNU_IFUNC } +}; + +static const char *getElfSectionType(unsigned Arch, unsigned Type) { + switch (Arch) { + case Triple::arm: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION); + } + case Triple::hexagon: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); + } + case Triple::x86_64: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); + } + case Triple::mips: + case Triple::mipsel: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); + } + } + + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym ); + default: return ""; + } +} + +static const EnumEntry<unsigned> ElfSectionFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, SHF_WRITE ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_ALLOC ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_INFO_LINK ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_LINK_ORDER ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_OS_NONCONFORMING), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_GROUP ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ), + LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), + LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) +}; + + +template<class ELFT> +void ELFDumper<ELFT>::printFileHeaders() { + error_code EC; + typedef ELFObjectFile<ELFT> ELFO; + + const typename ELFO::Elf_Ehdr *Header = Obj->getElfHeader(); + + { + DictScope D(W, "ElfHeader"); + { + DictScope D(W, "Ident"); + W.printBinary("Magic", makeArrayRef(Header->e_ident).slice(ELF::EI_MAG0, + 4)); + W.printEnum ("Class", Header->e_ident[ELF::EI_CLASS], + makeArrayRef(ElfClass)); + W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA], + makeArrayRef(ElfDataEncoding)); + W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]); + W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI], + makeArrayRef(ElfOSABI)); + W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]); + W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD)); + } + + W.printEnum ("Type", Header->e_type, makeArrayRef(ElfObjectFileType)); + W.printEnum ("Machine", Header->e_machine, makeArrayRef(ElfMachineType)); + W.printNumber("Version", Header->e_version); + W.printHex ("Entry", Header->e_entry); + W.printHex ("ProgramHeaderOffset", Header->e_phoff); + W.printHex ("SectionHeaderOffset", Header->e_shoff); + W.printFlags ("Flags", Header->e_flags); + W.printNumber("HeaderSize", Header->e_ehsize); + W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize); + W.printNumber("ProgramHeaderCount", Header->e_phnum); + W.printNumber("SectionHeaderEntrySize", Header->e_shentsize); + W.printNumber("SectionHeaderCount", Header->e_shnum); + W.printNumber("StringTableSectionIndex", Header->e_shstrndx); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printSections() { + ListScope SectionsD(W, "Sections"); + + int SectionIndex = -1; + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + ++SectionIndex; + + const Elf_Shdr *Section = Obj->getElfSection(SecI); + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + DictScope SectionD(W, "Section"); + W.printNumber("Index", SectionIndex); + W.printNumber("Name", Name, Section->sh_name); + W.printHex ("Type", getElfSectionType(Obj->getArch(), Section->sh_type), + Section->sh_type); + W.printFlags ("Flags", Section->sh_flags, makeArrayRef(ElfSectionFlags)); + W.printHex ("Address", Section->sh_addr); + W.printHex ("Offset", Section->sh_offset); + W.printNumber("Size", Section->sh_size); + W.printNumber("Link", Section->sh_link); + W.printNumber("Info", Section->sh_info); + W.printNumber("AddressAlignment", Section->sh_addralign); + W.printNumber("EntrySize", Section->sh_entsize); + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + printRelocation(SecI, RelI); + } + } + + if (opts::SectionSymbols) { + ListScope D(W, "Symbols"); + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printRelocations() { + ListScope D(W, "Relocations"); + + error_code EC; + int SectionNumber = -1; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + ++SectionNumber; + StringRef Name; + if (error(SecI->getName(Name))) + continue; + + bool PrintedGroup = false; + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + if (!PrintedGroup) { + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printRelocation(section_iterator Sec, + relocation_iterator RelI) { + uint64_t Offset; + SmallString<32> RelocName; + int64_t Info; + StringRef SymbolName; + SymbolRef Symbol; + if (error(RelI->getOffset(Offset))) return; + if (error(RelI->getTypeName(RelocName))) return; + if (error(RelI->getAdditionalInfo(Info))) return; + if (error(RelI->getSymbol(Symbol))) return; + if (error(Symbol.getName(SymbolName))) return; + + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << RelocName + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << " " << W.hex(Info) + << "\n"; +} + +template<class ELFT> +void ELFDumper<ELFT>::printSymbols() { + ListScope Group(W, "Symbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_symbols(), SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_dynamic_symbols(), + SymE = Obj->end_dynamic_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI, true); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printSymbol(symbol_iterator SymI, bool IsDynamic) { + error_code EC; + + const Elf_Sym *Symbol = Obj->getElfSymbol(SymI); + const Elf_Shdr *Section = Obj->getSection(Symbol); + + StringRef SymbolName; + if (SymI->getName(SymbolName)) + SymbolName = ""; + + StringRef SectionName; + if (Section && Obj->getSectionName(Section, SectionName)) + SectionName = ""; + + std::string FullSymbolName(SymbolName); + if (IsDynamic) { + StringRef Version; + bool IsDefault; + if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault))) + return; + if (!Version.empty()) { + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += Version; + } + } + + DictScope D(W, "Symbol"); + W.printNumber("Name", FullSymbolName, Symbol->st_name); + W.printHex ("Value", Symbol->st_value); + W.printNumber("Size", Symbol->st_size); + W.printEnum ("Binding", Symbol->getBinding(), + makeArrayRef(ElfSymbolBindings)); + W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); + W.printNumber("Other", Symbol->st_other); + W.printHex ("Section", SectionName, Symbol->st_shndx); +} + +#define LLVM_READOBJ_TYPE_CASE(name) \ + case DT_##name: return #name + +static const char *getTypeString(uint64_t Type) { + switch (Type) { + LLVM_READOBJ_TYPE_CASE(BIND_NOW); + LLVM_READOBJ_TYPE_CASE(DEBUG); + LLVM_READOBJ_TYPE_CASE(FINI); + LLVM_READOBJ_TYPE_CASE(FINI_ARRAY); + LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(FLAGS); + LLVM_READOBJ_TYPE_CASE(HASH); + LLVM_READOBJ_TYPE_CASE(INIT); + LLVM_READOBJ_TYPE_CASE(INIT_ARRAY); + LLVM_READOBJ_TYPE_CASE(INIT_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAY); + LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(JMPREL); + LLVM_READOBJ_TYPE_CASE(NEEDED); + LLVM_READOBJ_TYPE_CASE(NULL); + LLVM_READOBJ_TYPE_CASE(PLTGOT); + LLVM_READOBJ_TYPE_CASE(PLTREL); + LLVM_READOBJ_TYPE_CASE(PLTRELSZ); + LLVM_READOBJ_TYPE_CASE(REL); + LLVM_READOBJ_TYPE_CASE(RELA); + LLVM_READOBJ_TYPE_CASE(RELENT); + LLVM_READOBJ_TYPE_CASE(RELSZ); + LLVM_READOBJ_TYPE_CASE(RELAENT); + LLVM_READOBJ_TYPE_CASE(RELASZ); + LLVM_READOBJ_TYPE_CASE(RPATH); + LLVM_READOBJ_TYPE_CASE(RUNPATH); + LLVM_READOBJ_TYPE_CASE(SONAME); + LLVM_READOBJ_TYPE_CASE(STRSZ); + LLVM_READOBJ_TYPE_CASE(STRTAB); + LLVM_READOBJ_TYPE_CASE(SYMBOLIC); + LLVM_READOBJ_TYPE_CASE(SYMENT); + LLVM_READOBJ_TYPE_CASE(SYMTAB); + LLVM_READOBJ_TYPE_CASE(TEXTREL); + default: return "unknown"; + } +} + +#undef LLVM_READOBJ_TYPE_CASE + +template<class ELFT> +static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, + uint64_t Value, bool Is64, raw_ostream &OS) { + switch (Type) { + case DT_PLTREL: + if (Value == DT_REL) { + OS << "REL"; + break; + } else if (Value == DT_RELA) { + OS << "RELA"; + break; + } + // Fallthrough. + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + case DT_DEBUG: + case DT_NULL: + OS << format("0x%" PRIX64, Value); + break; + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_RELSZ: + case DT_RELENT: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_PREINIT_ARRAYSZ: + OS << Value << " (bytes)"; + break; + case DT_NEEDED: + OS << "SharedLibrary (" + << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + break; + case DT_SONAME: + OS << "LibrarySoname (" + << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + break; + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printUnwindInfo() { + W.startLine() << "UnwindInfo not implemented.\n"; +} + +template<class ELFT> +void ELFDumper<ELFT>::printDynamicTable() { + typedef ELFObjectFile<ELFT> ELFO; + typedef typename ELFO::Elf_Dyn_iterator EDI; + EDI Start = Obj->begin_dynamic_table(), + End = Obj->end_dynamic_table(true); + + if (Start == End) + return; + + ptrdiff_t Total = std::distance(Start, End); + raw_ostream &OS = W.getOStream(); + W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; + + bool Is64 = Obj->getBytesInAddress() == 8; + + W.startLine() + << " Tag" << (Is64 ? " " : " ") << "Type" + << " " << "Name/Value\n"; + for (; Start != End; ++Start) { + W.startLine() + << " " + << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag()) + << " " << format("%-21s", getTypeString(Start->getTag())); + printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS); + OS << "\n"; + } + + W.startLine() << "]\n"; +} + +static bool compareLibraryName(const LibraryRef &L, const LibraryRef &R) { + StringRef LPath, RPath; + L.getPath(LPath); + R.getPath(RPath); + return LPath < RPath; +} + +template<class ELFT> +void ELFDumper<ELFT>::printNeededLibraries() { + ListScope D(W, "NeededLibraries"); + + error_code EC; + + typedef std::vector<LibraryRef> LibsTy; + LibsTy Libs; + + for (library_iterator I = Obj->begin_libraries_needed(), + E = Obj->end_libraries_needed(); + I != E; I.increment(EC)) { + if (EC) + report_fatal_error("Needed libraries iteration failed"); + + Libs.push_back(*I); + } + + std::sort(Libs.begin(), Libs.end(), &compareLibraryName); + + for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); + I != E; ++I) { + StringRef Path; + I->getPath(Path); + outs() << " " << Path << "\n"; + } +} diff --git a/contrib/llvm/tools/llvm-readobj/Error.cpp b/contrib/llvm/tools/llvm-readobj/Error.cpp new file mode 100644 index 0000000..a6c6132 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/Error.cpp @@ -0,0 +1,62 @@ +//===- Error.cpp - system_error extensions for llvm-readobj -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines a new error_category for the llvm-readobj tool. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { +class _readobj_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; +} // namespace + +const char *_readobj_error_category::name() const { + return "llvm.readobj"; +} + +std::string _readobj_error_category::message(int ev) const { + switch (ev) { + case readobj_error::success: return "Success"; + case readobj_error::file_not_found: + return "No such file."; + case readobj_error::unsupported_file_format: + return "The file was not recognized as a valid object file."; + case readobj_error::unrecognized_file_format: + return "Unrecognized file type."; + case readobj_error::unsupported_obj_file_format: + return "Unsupported object file format."; + case readobj_error::unknown_symbol: + return "Unknown symbol."; + default: + llvm_unreachable("An enumerator of readobj_error does not have a message " + "defined."); + } +} + +error_condition _readobj_error_category::default_error_condition(int ev) const { + if (ev == readobj_error::success) + return errc::success; + return errc::invalid_argument; +} + +namespace llvm { +const error_category &readobj_category() { + static _readobj_error_category o; + return o; +} +} // namespace llvm diff --git a/contrib/llvm/tools/llvm-readobj/Error.h b/contrib/llvm/tools/llvm-readobj/Error.h new file mode 100644 index 0000000..cf68da8 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/Error.h @@ -0,0 +1,48 @@ +//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This declares a new error_category for the llvm-readobj tool. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ERROR_H +#define LLVM_READOBJ_ERROR_H + +#include "llvm/Support/system_error.h" + +namespace llvm { + +const error_category &readobj_category(); + +struct readobj_error { + enum _ { + success = 0, + file_not_found, + unsupported_file_format, + unrecognized_file_format, + unsupported_obj_file_format, + unknown_symbol + }; + _ v_; + + readobj_error(_ v) : v_(v) {} + explicit readobj_error(int v) : v_(_(v)) {} + operator int() const {return v_;} +}; + +inline error_code make_error_code(readobj_error e) { + return error_code(static_cast<int>(e), readobj_category()); +} + +template <> struct is_error_code_enum<readobj_error> : true_type { }; +template <> struct is_error_code_enum<readobj_error::_> : true_type { }; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp new file mode 100644 index 0000000..798c941 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp @@ -0,0 +1,438 @@ +//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MachO-specific dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; +using namespace object; + +namespace { + +class MachODumper : public ObjDumper { +public: + MachODumper(const llvm::object::MachOObjectFile *Obj, StreamWriter& Writer) + : ObjDumper(Writer) + , Obj(Obj) { } + + virtual void printFileHeaders() LLVM_OVERRIDE; + virtual void printSections() LLVM_OVERRIDE; + virtual void printRelocations() LLVM_OVERRIDE; + virtual void printSymbols() LLVM_OVERRIDE; + virtual void printDynamicSymbols() LLVM_OVERRIDE; + virtual void printUnwindInfo() LLVM_OVERRIDE; + +private: + void printSymbol(symbol_iterator SymI); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + const llvm::object::MachOObjectFile *Obj; +}; + +} // namespace + + +namespace llvm { + +error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result) { + const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); + if (!MachOObj) + return readobj_error::unsupported_obj_file_format; + + Result.reset(new MachODumper(MachOObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm + + +static const EnumEntry<unsigned> MachOSectionTypes[] = { + { "Regular" , 0x00 }, + { "ZeroFill" , 0x01 }, + { "CStringLiterals" , 0x02 }, + { "4ByteLiterals" , 0x03 }, + { "8ByteLiterals" , 0x04 }, + { "LiteralPointers" , 0x05 }, + { "NonLazySymbolPointers" , 0x06 }, + { "LazySymbolPointers" , 0x07 }, + { "SymbolStubs" , 0x08 }, + { "ModInitFuncs" , 0x09 }, + { "ModTermFuncs" , 0x0A }, + { "Coalesced" , 0x0B }, + { "GBZeroFill" , 0x0C }, + { "Interposing" , 0x0D }, + { "16ByteLiterals" , 0x0E }, + { "DTraceDOF" , 0x0F }, + { "LazyDylibSymbolPoints" , 0x10 }, + { "ThreadLocalRegular" , 0x11 }, + { "ThreadLocalZerofill" , 0x12 }, + { "ThreadLocalVariables" , 0x13 }, + { "ThreadLocalVariablePointers" , 0x14 }, + { "ThreadLocalInitFunctionPointers", 0x15 } +}; + +static const EnumEntry<unsigned> MachOSectionAttributes[] = { + { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ }, + { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ }, + { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ }, + { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ }, + { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ }, + { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ }, + { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ }, + { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ }, + { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ }, + { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ }, +}; + +static const EnumEntry<unsigned> MachOSymbolRefTypes[] = { + { "UndefinedNonLazy", 0 }, + { "ReferenceFlagUndefinedLazy", 1 }, + { "ReferenceFlagDefined", 2 }, + { "ReferenceFlagPrivateDefined", 3 }, + { "ReferenceFlagPrivateUndefinedNonLazy", 4 }, + { "ReferenceFlagPrivateUndefinedLazy", 5 } +}; + +static const EnumEntry<unsigned> MachOSymbolFlags[] = { + { "ReferencedDynamically", 0x10 }, + { "NoDeadStrip", 0x20 }, + { "WeakRef", 0x40 }, + { "WeakDef", 0x80 } +}; + +static const EnumEntry<unsigned> MachOSymbolTypes[] = { + { "Undef", 0x0 }, + { "External", 0x1 }, + { "Abs", 0x2 }, + { "Indirect", 0xA }, + { "PreboundUndef", 0xC }, + { "Section", 0xE }, + { "PrivateExternal", 0x10 } +}; + +namespace { + enum { + N_STAB = 0xE0 + }; + + struct MachOSection { + ArrayRef<char> Name; + ArrayRef<char> SegmentName; + uint64_t Address; + uint64_t Size; + uint32_t Offset; + uint32_t Alignment; + uint32_t RelocationTableOffset; + uint32_t NumRelocationTableEntries; + uint32_t Flags; + uint32_t Reserved1; + uint32_t Reserved2; + }; + + struct MachOSymbol { + uint32_t StringIndex; + uint8_t Type; + uint8_t SectionIndex; + uint16_t Flags; + uint64_t Value; + }; +} + +static StringRef parseSegmentOrSectionName(ArrayRef<char> P) { + if (P[15] == 0) + // Null terminated. + return StringRef(P.data()); + // Not null terminated, so this is a 16 char string. + return StringRef(P.data(), 16); +} + +static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) { + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + if (LCI.Command.Type == macho::LCT_Segment64) + return true; + assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type."); + return false; +} + +static void getSection(const MachOObject *MachOObj, + DataRefImpl DRI, + MachOSection &Section) { + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + if (is64BitLoadCommand(MachOObj, DRI)) { + InMemoryStruct<macho::Section64> Sect; + MachOObj->ReadSection64(LCI, DRI.d.b, Sect); + + Section.Name = ArrayRef<char>(Sect->Name); + Section.SegmentName = ArrayRef<char>(Sect->SegmentName); + Section.Address = Sect->Address; + Section.Size = Sect->Size; + Section.Offset = Sect->Offset; + Section.Alignment = Sect->Align; + Section.RelocationTableOffset = Sect->RelocationTableOffset; + Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries; + Section.Flags = Sect->Flags; + Section.Reserved1 = Sect->Reserved1; + Section.Reserved2 = Sect->Reserved2; + } else { + InMemoryStruct<macho::Section> Sect; + MachOObj->ReadSection(LCI, DRI.d.b, Sect); + + Section.Name = Sect->Name; + Section.SegmentName = Sect->SegmentName; + Section.Address = Sect->Address; + Section.Size = Sect->Size; + Section.Offset = Sect->Offset; + Section.Alignment = Sect->Align; + Section.RelocationTableOffset = Sect->RelocationTableOffset; + Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries; + Section.Flags = Sect->Flags; + Section.Reserved1 = Sect->Reserved1; + Section.Reserved2 = Sect->Reserved2; + } +} + +static void getSymbolTableEntry(const MachOObject *MachO, + DataRefImpl DRI, + InMemoryStruct<macho::SymbolTableEntry> &Res) { + InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; + LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a); + MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); + MachO->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res); +} + +static void getSymbol64TableEntry(const MachOObject *MachO, + DataRefImpl DRI, + InMemoryStruct<macho::Symbol64TableEntry> &Res) { + InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; + LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a); + MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); + MachO->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res); +} + +static void getSymbol(const MachOObject *MachOObj, + DataRefImpl DRI, + MachOSymbol &Symbol) { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(MachOObj, DRI, Entry); + Symbol.StringIndex = Entry->StringIndex; + Symbol.Type = Entry->Type; + Symbol.SectionIndex = Entry->SectionIndex; + Symbol.Flags = Entry->Flags; + Symbol.Value = Entry->Value; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(MachOObj, DRI, Entry); + Symbol.StringIndex = Entry->StringIndex; + Symbol.Type = Entry->Type; + Symbol.SectionIndex = Entry->SectionIndex; + Symbol.Flags = Entry->Flags; + Symbol.Value = Entry->Value; + } +} + +void MachODumper::printFileHeaders() { + W.startLine() << "FileHeaders not implemented.\n"; +} + +void MachODumper::printSections() { + ListScope Group(W, "Sections"); + + int SectionIndex = -1; + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + ++SectionIndex; + + const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject(); + + MachOSection Section; + getSection(MachO, SecI->getRawDataRefImpl(), Section); + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + DictScope SectionD(W, "Section"); + W.printNumber("Index", SectionIndex); + W.printBinary("Name", Name, Section.Name); + W.printBinary("Segment", parseSegmentOrSectionName(Section.SegmentName), + Section.SegmentName); + W.printHex ("Address", Section.Address); + W.printHex ("Size", Section.Size); + W.printNumber("Offset", Section.Offset); + W.printNumber("Alignment", Section.Alignment); + W.printHex ("RelocationOffset", Section.RelocationTableOffset); + W.printNumber("RelocationCount", Section.NumRelocationTableEntries); + W.printEnum ("Type", Section.Flags & 0xFF, + makeArrayRef(MachOSectionAttributes)); + W.printFlags ("Attributes", Section.Flags >> 8, + makeArrayRef(MachOSectionAttributes)); + W.printHex ("Reserved1", Section.Reserved1); + W.printHex ("Reserved2", Section.Reserved2); + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + printRelocation(SecI, RelI); + } + } + + if (opts::SectionSymbols) { + ListScope D(W, "Symbols"); + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +void MachODumper::printRelocations() { + ListScope D(W, "Relocations"); + + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + StringRef Name; + if (error(SecI->getName(Name))) + continue; + + bool PrintedGroup = false; + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + if (!PrintedGroup) { + W.startLine() << "Section " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +void MachODumper::printRelocation(section_iterator SecI, + relocation_iterator RelI) { + uint64_t Offset; + SmallString<32> RelocName; + int64_t Info; + StringRef SymbolName; + SymbolRef Symbol; + if (error(RelI->getOffset(Offset))) return; + if (error(RelI->getTypeName(RelocName))) return; + if (error(RelI->getAdditionalInfo(Info))) return; + if (error(RelI->getSymbol(Symbol))) return; + if (error(Symbol.getName(SymbolName))) return; + + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << RelocName + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << " " << W.hex(Info) + << "\n"; +} + +void MachODumper::printSymbols() { + ListScope Group(W, "Symbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI); + } +} + +void MachODumper::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); +} + +void MachODumper::printSymbol(symbol_iterator SymI) { + error_code EC; + + StringRef SymbolName; + if (SymI->getName(SymbolName)) + SymbolName = ""; + + const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject(); + + MachOSymbol Symbol; + getSymbol(MachO, SymI->getRawDataRefImpl(), Symbol); + + StringRef SectionName; + section_iterator SecI(Obj->end_sections()); + if (error(SymI->getSection(SecI)) || + error(SecI->getName(SectionName))) + SectionName = ""; + + DictScope D(W, "Symbol"); + W.printNumber("Name", SymbolName, Symbol.StringIndex); + if (Symbol.Type & N_STAB) { + W.printHex ("Type", "SymDebugTable", Symbol.Type); + } else { + W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes)); + } + W.printHex ("Section", SectionName, Symbol.SectionIndex); + W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF), + makeArrayRef(MachOSymbolRefTypes)); + W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF), + makeArrayRef(MachOSymbolFlags)); + W.printHex ("Value", Symbol.Value); +} + +void MachODumper::printUnwindInfo() { + W.startLine() << "UnwindInfo not implemented.\n"; +} diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp new file mode 100644 index 0000000..61f5117 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp @@ -0,0 +1,33 @@ +//===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements ObjDumper. +/// +//===----------------------------------------------------------------------===// + +#include "ObjDumper.h" + +#include "Error.h" +#include "StreamWriter.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +ObjDumper::ObjDumper(StreamWriter& Writer) + : W(Writer) { +} + +ObjDumper::~ObjDumper() { +} + +} // namespace llvm diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h new file mode 100644 index 0000000..8d191cb --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h @@ -0,0 +1,60 @@ +//===-- ObjDumper.h -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_OBJDUMPER_H +#define LLVM_READOBJ_OBJDUMPER_H + +namespace llvm { + +namespace object { + class ObjectFile; +} + +class error_code; + +template<typename T> +class OwningPtr; + +class StreamWriter; + +class ObjDumper { +public: + ObjDumper(StreamWriter& Writer); + virtual ~ObjDumper(); + + virtual void printFileHeaders() = 0; + virtual void printSections() = 0; + virtual void printRelocations() = 0; + virtual void printSymbols() = 0; + virtual void printDynamicSymbols() = 0; + virtual void printUnwindInfo() = 0; + + // Only implemented for ELF at this time. + virtual void printDynamicTable() { } + virtual void printNeededLibraries() { } + +protected: + StreamWriter& W; +}; + +error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +} // namespace llvm + +#endif diff --git a/contrib/llvm/tools/llvm-readobj/StreamWriter.cpp b/contrib/llvm/tools/llvm-readobj/StreamWriter.cpp new file mode 100644 index 0000000..8718112 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/StreamWriter.cpp @@ -0,0 +1,79 @@ +#include "StreamWriter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" +#include <cctype> + +using namespace llvm::support; + +namespace llvm { + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value) { + uint64_t N = Value.Value; + // Zero is a special case. + if (N == 0) + return OS << "0x0"; + + char NumberBuffer[20]; + char *EndPtr = NumberBuffer + sizeof(NumberBuffer); + char *CurPtr = EndPtr; + + while (N) { + uintptr_t X = N % 16; + *--CurPtr = (X < 10 ? '0' + X : 'A' + X - 10); + N /= 16; + } + + OS << "0x"; + return OS.write(CurPtr, EndPtr - CurPtr); +} + +void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str, + ArrayRef<uint8_t> Data, bool Block) { + if (Data.size() > 16) + Block = true; + + if (Block) { + startLine() << Label; + if (Str.size() > 0) + OS << ": " << Str; + OS << " (\n"; + for (size_t addr = 0, end = Data.size(); addr < end; addr += 16) { + startLine() << format(" %04" PRIX64 ": ", uint64_t(addr)); + // Dump line of hex. + for (size_t i = 0; i < 16; ++i) { + if (i != 0 && i % 4 == 0) + OS << ' '; + if (addr + i < end) + OS << hexdigit((Data[addr + i] >> 4) & 0xF, false) + << hexdigit(Data[addr + i] & 0xF, false); + else + OS << " "; + } + // Print ascii. + OS << " |"; + for (std::size_t i = 0; i < 16 && addr + i < end; ++i) { + if (std::isprint(Data[addr + i] & 0xFF)) + OS << Data[addr + i]; + else + OS << "."; + } + OS << "|\n"; + } + + startLine() << ")\n"; + } else { + startLine() << Label << ":"; + if (Str.size() > 0) + OS << " " << Str; + OS << " ("; + for (size_t i = 0; i < Data.size(); ++i) { + if (i > 0) + OS << " "; + + OS << format("%02X", static_cast<int>(Data[i])); + } + OS << ")\n"; + } +} + +} // namespace llvm diff --git a/contrib/llvm/tools/llvm-readobj/StreamWriter.h b/contrib/llvm/tools/llvm-readobj/StreamWriter.h new file mode 100644 index 0000000..129f6e7 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/StreamWriter.h @@ -0,0 +1,282 @@ +//===-- StreamWriter.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_STREAMWRITER_H +#define LLVM_READOBJ_STREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +using namespace llvm; +using namespace llvm::support; + +namespace llvm { + +template<typename T> +struct EnumEntry { + StringRef Name; + T Value; +}; + +struct HexNumber { + // To avoid sign-extension we have to explicitly cast to the appropriate + // unsigned type. The overloads are here so that every type that is implicitly + // convertible to an integer (including enums and endian helpers) can be used + // without requiring type traits or call-site changes. + HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { } + HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { } + HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { } + HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { } + HexNumber(uint8_t Value) : Value(Value) { } + HexNumber(uint16_t Value) : Value(Value) { } + HexNumber(uint32_t Value) : Value(Value) { } + HexNumber(uint64_t Value) : Value(Value) { } + uint64_t Value; +}; + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value); + +class StreamWriter { +public: + StreamWriter(raw_ostream &OS) + : OS(OS) + , IndentLevel(0) { + } + + void flush() { + OS.flush(); + } + + void indent(int Levels = 1) { + IndentLevel += Levels; + } + + void unindent(int Levels = 1) { + IndentLevel = std::max(0, IndentLevel - Levels); + } + + void printIndent() { + for (int i = 0; i < IndentLevel; ++i) + OS << " "; + } + + template<typename T> + HexNumber hex(T Value) { + return HexNumber(Value); + } + + template<typename T, typename TEnum> + void printEnum(StringRef Label, T Value, + ArrayRef<EnumEntry<TEnum> > EnumValues) { + StringRef Name; + bool Found = false; + for (size_t i = 0; i < EnumValues.size(); ++i) { + if (EnumValues[i].Value == Value) { + Name = EnumValues[i].Name; + Found = true; + break; + } + } + + if (Found) { + startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n"; + } else { + startLine() << Label << ": " << hex(Value) << "\n"; + } + } + + template<typename T, typename TFlag> + void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag> > Flags, + TFlag EnumMask = TFlag(0)) { + typedef EnumEntry<TFlag> FlagEntry; + typedef SmallVector<FlagEntry, 10> FlagVector; + FlagVector SetFlags; + + for (typename ArrayRef<FlagEntry>::const_iterator I = Flags.begin(), + E = Flags.end(); I != E; ++I) { + if (I->Value == 0) + continue; + + bool IsEnum = (I->Value & EnumMask) != 0; + if ((!IsEnum && (Value & I->Value) == I->Value) || + (IsEnum && (Value & EnumMask) == I->Value)) { + SetFlags.push_back(*I); + } + } + + std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>); + + startLine() << Label << " [ (" << hex(Value) << ")\n"; + for (typename FlagVector::const_iterator I = SetFlags.begin(), + E = SetFlags.end(); + I != E; ++I) { + startLine() << " " << I->Name << " (" << hex(I->Value) << ")\n"; + } + startLine() << "]\n"; + } + + template<typename T> + void printFlags(StringRef Label, T Value) { + startLine() << Label << " [ (" << hex(Value) << ")\n"; + uint64_t Flag = 1; + uint64_t Curr = Value; + while (Curr > 0) { + if (Curr & 1) + startLine() << " " << hex(Flag) << "\n"; + Curr >>= 1; + Flag <<= 1; + } + startLine() << "]\n"; + } + + void printNumber(StringRef Label, uint64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint8_t Value) { + startLine() << Label << ": " << unsigned(Value) << "\n"; + } + + void printNumber(StringRef Label, int64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int8_t Value) { + startLine() << Label << ": " << int(Value) << "\n"; + } + + template<typename T> + void printHex(StringRef Label, T Value) { + startLine() << Label << ": " << hex(Value) << "\n"; + } + + template<typename T> + void printHex(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n"; + } + + void printString(StringRef Label, StringRef Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printString(StringRef Label, const std::string &Value) { + startLine() << Label << ": " << Value << "\n"; + } + + template<typename T> + void printNumber(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << Value << ")\n"; + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, Str, Value, false); + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, Str, V, false); + } + + void printBinary(StringRef Label, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, StringRef(), Value, false); + } + + void printBinary(StringRef Label, ArrayRef<char> Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinary(StringRef Label, StringRef Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinaryBlock(StringRef Label, StringRef Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, true); + } + + raw_ostream& startLine() { + printIndent(); + return OS; + } + + raw_ostream& getOStream() { + return OS; + } + +private: + template<typename T> + static bool flagName(const EnumEntry<T>& lhs, const EnumEntry<T>& rhs) { + return lhs.Name < rhs.Name; + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value, + bool Block); + + raw_ostream &OS; + int IndentLevel; +}; + +struct DictScope { + DictScope(StreamWriter& W, StringRef N) : W(W) { + W.startLine() << N << " {\n"; + W.indent(); + } + + ~DictScope() { + W.unindent(); + W.startLine() << "}\n"; + } + + StreamWriter& W; +}; + +struct ListScope { + ListScope(StreamWriter& W, StringRef N) : W(W) { + W.startLine() << N << " [\n"; + W.indent(); + } + + ~ListScope() { + W.unindent(); + W.startLine() << "]\n"; + } + + StreamWriter& W; +}; + +} // namespace llvm + +#endif diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp index 3be1289..67c9a98 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -7,212 +7,277 @@ // //===----------------------------------------------------------------------===// // -// 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 "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/ELF.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Support/Format.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/system_error.h" + +#include <string> + using namespace llvm; using namespace llvm::object; -static cl::opt<std::string> -InputFilename(cl::Positional, cl::desc("<input object>"), cl::init("")); +namespace opts { + cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<input object files>"), + 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<bool> 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<bool> Sections("sections", + cl::desc("Display all sections.")); + cl::alias SectionsShort("s", + cl::desc("Alias for --sections"), + cl::aliasopt(Sections)); + + // -section-relocations, -sr + cl::opt<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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<bool> 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<bool> UnwindInfo("unwind", + cl::desc("Display unwind information")); + cl::alias UnwindInfoShort("u", + cl::desc("Alias for --unwind"), + cl::aliasopt(UnwindInfo)); + + // -dynamic-table + cl::opt<bool> DynamicTable("dynamic-table", + cl::desc("Display the ELF .dynamic section table")); + + // -needed-libs + cl::opt<bool> NeededLibraries("needed-libs", + cl::desc("Display the needed libraries")); +} // 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.getAddress(a_addr))) return false; + if (error(b.getAddress(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 = "<stdin>"; + + 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 = "<stdin>"; - // 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<ObjDumper> &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<ObjDumper> 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(); } -// 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<Binary> 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<ObjectFile>(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> Binary; + if (error_code EC = createBinary(File, Binary)) { + reportError(File, EC); + return; + } + + if (Archive *Arc = dyn_cast<Archive>(Binary.get())) + dumpArchive(Arc); + else if (ObjectFile *Obj = dyn_cast<ObjectFile>(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<MemoryBuffer> 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; } - diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h new file mode 100644 index 0000000..be18268 --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h @@ -0,0 +1,45 @@ +//===-- llvm-readobj.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_READ_OBJ_H +#define LLVM_TOOLS_READ_OBJ_H + +#include "llvm/Support/CommandLine.h" +#include <string> + +namespace llvm { + namespace object { + class RelocationRef; + } + + class error_code; + + // Various helper functions. + bool error(error_code ec); + bool relocAddressLess(object::RelocationRef A, + object::RelocationRef B); +} // namespace llvm + +namespace opts { + extern llvm::cl::list<std::string> InputFilenames; + extern llvm::cl::opt<bool> FileHeaders; + extern llvm::cl::opt<bool> Sections; + extern llvm::cl::opt<bool> SectionRelocations; + extern llvm::cl::opt<bool> SectionSymbols; + extern llvm::cl::opt<bool> SectionData; + extern llvm::cl::opt<bool> Relocations; + extern llvm::cl::opt<bool> Symbols; + extern llvm::cl::opt<bool> DynamicSymbols; + extern llvm::cl::opt<bool> UnwindInfo; +} // namespace opts + +#define LLVM_READOBJ_ENUM_ENT(ns, enum) \ + { #enum, ns::enum } + +#endif |