From 2173e1839c2d00f7f980450dd537047b7b376e6b Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 26 Apr 2013 20:07:33 +0000 Subject: [PATCH] Use llvm/Object/MachO.h in macho-dumper. Drop the old macho parser. For Mach-O there were 2 implementations for parsing object files. A standalone llvm/Object/MachOObject.h and llvm/Object/MachO.h which implements the generic interface in llvm/Object/ObjectFile.h. This patch adds the missing features to MachO.h, moves macho-dump to use MachO.h and removes ObjectFile.h. In addition to making sure that check-all is clean, I checked that the new version produces exactly the same output in all Mach-O files in a llvm+clang build directory (including executables and shared libraries). To test the performance, I ran macho-dump over all the files in a llvm+clang build directory again, but this time redirecting the output to /dev/null. Both the old and new versions take about 4.6 seconds (2.5 user) to finish. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@180624 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/ADT/InMemoryStruct.h | 77 ---- include/llvm/Object/MachO.h | 22 + include/llvm/Object/MachOObject.h | 212 --------- .../RuntimeDyld/RuntimeDyldMachO.h | 2 +- lib/Object/CMakeLists.txt | 1 - lib/Object/MachOObject.cpp | 422 ------------------ lib/Object/MachOObjectFile.cpp | 161 +++++-- tools/llvm-rtdyld/llvm-rtdyld.cpp | 2 +- tools/macho-dump/macho-dump.cpp | 418 ++++++++--------- 9 files changed, 344 insertions(+), 973 deletions(-) delete mode 100644 include/llvm/ADT/InMemoryStruct.h delete mode 100644 include/llvm/Object/MachOObject.h delete mode 100644 lib/Object/MachOObject.cpp diff --git a/include/llvm/ADT/InMemoryStruct.h b/include/llvm/ADT/InMemoryStruct.h deleted file mode 100644 index a56084501a6..00000000000 --- a/include/llvm/ADT/InMemoryStruct.h +++ /dev/null @@ -1,77 +0,0 @@ -//===- InMemoryStruct.h - Indirect Struct Access Smart Pointer --*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ADT_INMEMORYSTRUCT_H -#define LLVM_ADT_INMEMORYSTRUCT_H - -#include - -namespace llvm { - -/// \brief Helper object for abstracting access to an in-memory structure which -/// may require some kind of temporary storage. -/// -/// This class is designed to be used for accessing file data structures which -/// in the common case can be accessed from a direct pointer to a memory mapped -/// object, but which in some cases may require indirect access to a temporary -/// structure (which, for example, may have undergone endianness translation). -template -class InMemoryStruct { - typedef T value_type; - typedef value_type &reference; - typedef value_type *pointer; - typedef const value_type &const_reference; - typedef const value_type *const_pointer; - - /// \brief The smart pointer target. - value_type *Target; - - /// \brief A temporary object which can be used as a target of the smart - /// pointer. - value_type Contents; - -private: - -public: - InMemoryStruct() : Target(0) {} - InMemoryStruct(reference Value) : Target(&Contents), Contents(Value) {} - InMemoryStruct(pointer Value) : Target(Value) {} - InMemoryStruct(const InMemoryStruct &Value) { *this = Value; } - - void operator=(const InMemoryStruct &Value) { - if (Value.Target != &Value.Contents) { - Target = Value.Target; - } else { - Target = &Contents; - Contents = Value.Contents; - } - } - - const_reference operator*() const { - assert(Target && "Cannot dereference null pointer"); - return *Target; - } - reference operator*() { - assert(Target && "Cannot dereference null pointer"); - return *Target; - } - - const_pointer operator->() const { - return Target; - } - pointer operator->() { - return Target; - } - - operator bool() const { return Target != 0; } -}; - -} - -#endif diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index d8598ebdcf0..98d3788e44c 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -106,6 +106,9 @@ public: virtual StringRef getLoadName() const; + relocation_iterator getSectionRelBegin(unsigned Index) const; + relocation_iterator getSectionRelEnd(unsigned Index) const; + // In a MachO file, sections have a segment name. This is used in the .o // files. They have a single segment, but this field specifies which segment // a section should be put in in the final object. @@ -134,14 +137,32 @@ public: // MachO specific structures. macho::Section getSection(DataRefImpl DRI) const; macho::Section64 getSection64(DataRefImpl DRI) const; + macho::Section getSection(const LoadCommandInfo &L, unsigned Index) const; + macho::Section64 getSection64(const LoadCommandInfo &L, unsigned Index) const; macho::SymbolTableEntry getSymbolTableEntry(DataRefImpl DRI) const; macho::Symbol64TableEntry getSymbol64TableEntry(DataRefImpl DRI) const; + macho::LinkeditDataLoadCommand getLinkeditDataLoadCommand(const LoadCommandInfo &L) const; + macho::SegmentLoadCommand + getSegmentLoadCommand(const LoadCommandInfo &L) const; + macho::Segment64LoadCommand + getSegment64LoadCommand(const LoadCommandInfo &L) const; + macho::LinkerOptionsLoadCommand + getLinkerOptionsLoadCommand(const LoadCommandInfo &L) const; + macho::RelocationEntry getRelocation(DataRefImpl Rel) const; macho::Header getHeader() const; + macho::Header64Ext getHeader64Ext() const; + macho::IndirectSymbolTableEntry + getIndirectSymbolTableEntry(const macho::DysymtabLoadCommand &DLC, + unsigned Index) const; + macho::DataInCodeTableEntry getDataInCodeTableEntry(uint32_t DataOffset, + unsigned Index) const; macho::SymtabLoadCommand getSymtabLoadCommand() const; + macho::DysymtabLoadCommand getDysymtabLoadCommand() const; + StringRef getStringTableData() const; bool is64Bit() const; void ReadULEB128s(uint64_t Index, SmallVectorImpl &Out) const; @@ -153,6 +174,7 @@ private: typedef SmallVector SectionList; SectionList Sections; const char *SymtabLoadCmd; + const char *DysymtabLoadCmd; }; } diff --git a/include/llvm/Object/MachOObject.h b/include/llvm/Object/MachOObject.h deleted file mode 100644 index 50ee25b4639..00000000000 --- a/include/llvm/Object/MachOObject.h +++ /dev/null @@ -1,212 +0,0 @@ -//===- MachOObject.h - Mach-O Object File Wrapper ---------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_OBJECT_MACHOOBJECT_H -#define LLVM_OBJECT_MACHOOBJECT_H - -#include "llvm/ADT/InMemoryStruct.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Object/MachOFormat.h" -#include - -namespace llvm { - -class MemoryBuffer; -class raw_ostream; - -namespace object { - -/// \brief Wrapper object for manipulating Mach-O object files. -/// -/// This class is designed to implement a full-featured, efficient, portable, -/// and robust Mach-O interface to Mach-O object files. It does not attempt to -/// smooth over rough edges in the Mach-O format or generalize access to object -/// independent features. -/// -/// The class is designed around accessing the Mach-O object which is expected -/// to be fully loaded into memory. -/// -/// This class is *not* suitable for concurrent use. For efficient operation, -/// the class uses APIs which rely on the ability to cache the results of -/// certain calls in internal objects which are not safe for concurrent -/// access. This allows the API to be zero-copy on the common paths. -// -// FIXME: It would be cool if we supported a "paged" MemoryBuffer -// implementation. This would allow us to implement a more sensible version of -// MemoryObject which can work like a MemoryBuffer, but be more efficient for -// objects which are in the current address space. -class MachOObject { -public: - struct LoadCommandInfo { - /// The load command information. - macho::LoadCommand Command; - - /// The offset to the start of the load command in memory. - uint64_t Offset; - }; - -private: - OwningPtr Buffer; - - /// Whether the object is little endian. - bool IsLittleEndian; - /// Whether the object is 64-bit. - bool Is64Bit; - /// Whether the object is swapped endianness from the host. - bool IsSwappedEndian; - /// Whether the string table has been registered. - bool HasStringTable; - - /// The cached information on the load commands. - LoadCommandInfo *LoadCommands; - mutable unsigned NumLoadedCommands; - - /// The cached copy of the header. - macho::Header Header; - macho::Header64Ext Header64Ext; - - /// Cache string table information. - StringRef StringTable; - -private: - MachOObject(MemoryBuffer *Buffer, bool IsLittleEndian, bool Is64Bit); - -public: - ~MachOObject(); - - /// \brief Load a Mach-O object from a MemoryBuffer object. - /// - /// \param Buffer - The buffer to load the object from. This routine takes - /// exclusive ownership of the buffer (which is passed to the returned object - /// on success). - /// \param ErrorStr [out] - If given, will be set to a user readable error - /// message on failure. - /// \returns The loaded object, or null on error. - static MachOObject *LoadFromBuffer(MemoryBuffer *Buffer, - std::string *ErrorStr = 0); - - /// @name File Information - /// @{ - - bool isLittleEndian() const { return IsLittleEndian; } - bool isSwappedEndian() const { return IsSwappedEndian; } - bool is64Bit() const { return Is64Bit; } - - unsigned getHeaderSize() const { - return Is64Bit ? macho::Header64Size : macho::Header32Size; - } - - StringRef getData(size_t Offset, size_t Size) const; - - /// @} - /// @name String Table Data - /// @{ - - StringRef getStringTableData() const { - assert(HasStringTable && "String table has not been registered!"); - return StringTable; - } - - StringRef getStringAtIndex(unsigned Index) const { - size_t End = getStringTableData().find('\0', Index); - return getStringTableData().slice(Index, End); - } - - void RegisterStringTable(macho::SymtabLoadCommand &SLC); - - /// @} - /// @name Object Header Access - /// @{ - - const macho::Header &getHeader() const { return Header; } - const macho::Header64Ext &getHeader64Ext() const { - assert(is64Bit() && "Invalid access!"); - return Header64Ext; - } - - /// @} - /// @name Object Structure Access - /// @{ - - // TODO: Would be useful to have an iterator based version - // of this. - /// \brief Retrieve the information for the given load command. - const LoadCommandInfo &getLoadCommandInfo(unsigned Index) const; - - void ReadSegmentLoadCommand( - const LoadCommandInfo &LCI, - InMemoryStruct &Res) const; - void ReadSegment64LoadCommand( - const LoadCommandInfo &LCI, - InMemoryStruct &Res) const; - void ReadSymtabLoadCommand( - const LoadCommandInfo &LCI, - InMemoryStruct &Res) const; - void ReadDysymtabLoadCommand( - const LoadCommandInfo &LCI, - InMemoryStruct &Res) const; - void ReadLinkeditDataLoadCommand( - const LoadCommandInfo &LCI, - InMemoryStruct &Res) const; - void ReadLinkerOptionsLoadCommand( - const LoadCommandInfo &LCI, - InMemoryStruct &Res) const; - void ReadIndirectSymbolTableEntry( - const macho::DysymtabLoadCommand &DLC, - unsigned Index, - InMemoryStruct &Res) const; - void ReadSection( - const LoadCommandInfo &LCI, - unsigned Index, - InMemoryStruct &Res) const; - void ReadSection64( - const LoadCommandInfo &LCI, - unsigned Index, - InMemoryStruct &Res) const; - void ReadRelocationEntry( - uint64_t RelocationTableOffset, unsigned Index, - InMemoryStruct &Res) const; - void ReadSymbolTableEntry( - uint64_t SymbolTableOffset, unsigned Index, - InMemoryStruct &Res) const; - void ReadSymbol64TableEntry( - uint64_t SymbolTableOffset, unsigned Index, - InMemoryStruct &Res) const; - void ReadDataInCodeTableEntry( - uint64_t TableOffset, unsigned Index, - InMemoryStruct &Res) const; - void ReadULEB128s(uint64_t Index, SmallVectorImpl &Out) const; - - /// @} - - /// @name Object Dump Facilities - /// @{ - /// dump - Support for debugging, callable in GDB: V->dump() - // - void dump() const; - void dumpHeader() const; - - /// print - Implement operator<< on Value. - /// - void print(raw_ostream &O) const; - void printHeader(raw_ostream &O) const; - - /// @} -}; - -inline raw_ostream &operator<<(raw_ostream &OS, const MachOObject &V) { - V.print(OS); - return OS; -} - -} // end namespace object -} // end namespace llvm - -#endif diff --git a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h index 62d84870780..f581b3f8248 100644 --- a/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h +++ b/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldMachO.h @@ -16,7 +16,7 @@ #include "RuntimeDyldImpl.h" #include "llvm/ADT/IndexedMap.h" -#include "llvm/Object/MachOObject.h" +#include "llvm/Object/MachO.h" #include "llvm/Support/Format.h" using namespace llvm; diff --git a/lib/Object/CMakeLists.txt b/lib/Object/CMakeLists.txt index c20fc0cc399..4ed129f467e 100644 --- a/lib/Object/CMakeLists.txt +++ b/lib/Object/CMakeLists.txt @@ -4,7 +4,6 @@ add_llvm_library(LLVMObject COFFObjectFile.cpp ELFObjectFile.cpp Error.cpp - MachOObject.cpp MachOObjectFile.cpp Object.cpp ObjectFile.cpp diff --git a/lib/Object/MachOObject.cpp b/lib/Object/MachOObject.cpp deleted file mode 100644 index d88f96f298c..00000000000 --- a/lib/Object/MachOObject.cpp +++ /dev/null @@ -1,422 +0,0 @@ -//===- MachOObject.cpp - Mach-O Object File Wrapper -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Object/MachOObject.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/DataExtractor.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SwapByteOrder.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; -using namespace llvm::object; - -/* Translation Utilities */ - -template -static void SwapValue(T &Value) { - Value = sys::SwapByteOrder(Value); -} - -template -static void SwapStruct(T &Value); - -template -static void ReadInMemoryStruct(const MachOObject &MOO, - StringRef Buffer, uint64_t Base, - InMemoryStruct &Res) { - typedef T struct_type; - uint64_t Size = sizeof(struct_type); - - // Check that the buffer contains the expected data. - if (Base + Size > Buffer.size()) { - Res = 0; - return; - } - - // Check whether we can return a direct pointer. - struct_type *Ptr = reinterpret_cast( - const_cast(Buffer.data() + Base)); - if (!MOO.isSwappedEndian()) { - Res = Ptr; - return; - } - - // Otherwise, copy the struct and translate the values. - Res = *Ptr; - SwapStruct(*Res); -} - -/* *** */ - -MachOObject::MachOObject(MemoryBuffer *Buffer_, bool IsLittleEndian_, - bool Is64Bit_) - : Buffer(Buffer_), IsLittleEndian(IsLittleEndian_), Is64Bit(Is64Bit_), - IsSwappedEndian(IsLittleEndian != sys::IsLittleEndianHost), - HasStringTable(false), LoadCommands(0), NumLoadedCommands(0) { - // Load the common header. - memcpy(&Header, Buffer->getBuffer().data(), sizeof(Header)); - if (IsSwappedEndian) { - SwapValue(Header.Magic); - SwapValue(Header.CPUType); - SwapValue(Header.CPUSubtype); - SwapValue(Header.FileType); - SwapValue(Header.NumLoadCommands); - SwapValue(Header.SizeOfLoadCommands); - SwapValue(Header.Flags); - } - - if (is64Bit()) { - memcpy(&Header64Ext, Buffer->getBuffer().data() + sizeof(Header), - sizeof(Header64Ext)); - if (IsSwappedEndian) { - SwapValue(Header64Ext.Reserved); - } - } - - // Create the load command array if sane. - if (getHeader().NumLoadCommands < (1 << 20)) - LoadCommands = new LoadCommandInfo[getHeader().NumLoadCommands]; -} - -MachOObject::~MachOObject() { - delete [] LoadCommands; -} - -MachOObject *MachOObject::LoadFromBuffer(MemoryBuffer *Buffer, - std::string *ErrorStr) { - // First, check the magic value and initialize the basic object info. - bool IsLittleEndian = false, Is64Bit = false; - StringRef Magic = Buffer->getBuffer().slice(0, 4); - if (Magic == "\xFE\xED\xFA\xCE") { - } else if (Magic == "\xCE\xFA\xED\xFE") { - IsLittleEndian = true; - } else if (Magic == "\xFE\xED\xFA\xCF") { - Is64Bit = true; - } else if (Magic == "\xCF\xFA\xED\xFE") { - IsLittleEndian = true; - Is64Bit = true; - } else { - if (ErrorStr) *ErrorStr = "not a Mach object file (invalid magic)"; - return 0; - } - - // Ensure that the at least the full header is present. - unsigned HeaderSize = Is64Bit ? macho::Header64Size : macho::Header32Size; - if (Buffer->getBufferSize() < HeaderSize) { - if (ErrorStr) *ErrorStr = "not a Mach object file (invalid header)"; - return 0; - } - - OwningPtr Object(new MachOObject(Buffer, IsLittleEndian, - Is64Bit)); - - // Check for bogus number of load commands. - if (Object->getHeader().NumLoadCommands >= (1 << 20)) { - if (ErrorStr) *ErrorStr = "not a Mach object file (unreasonable header)"; - return 0; - } - - if (ErrorStr) *ErrorStr = ""; - return Object.take(); -} - -StringRef MachOObject::getData(size_t Offset, size_t Size) const { - return Buffer->getBuffer().substr(Offset,Size); -} - -void MachOObject::RegisterStringTable(macho::SymtabLoadCommand &SLC) { - HasStringTable = true; - StringTable = Buffer->getBuffer().substr(SLC.StringTableOffset, - SLC.StringTableSize); -} - -const MachOObject::LoadCommandInfo & -MachOObject::getLoadCommandInfo(unsigned Index) const { - assert(Index < getHeader().NumLoadCommands && "Invalid index!"); - - // Load the command, if necessary. - if (Index >= NumLoadedCommands) { - uint64_t Offset; - if (Index == 0) { - Offset = getHeaderSize(); - } else { - const LoadCommandInfo &Prev = getLoadCommandInfo(Index - 1); - Offset = Prev.Offset + Prev.Command.Size; - } - - LoadCommandInfo &Info = LoadCommands[Index]; - memcpy(&Info.Command, Buffer->getBuffer().data() + Offset, - sizeof(macho::LoadCommand)); - if (IsSwappedEndian) { - SwapValue(Info.Command.Type); - SwapValue(Info.Command.Size); - } - Info.Offset = Offset; - NumLoadedCommands = Index + 1; - } - - return LoadCommands[Index]; -} - -template<> -void SwapStruct(macho::SegmentLoadCommand &Value) { - SwapValue(Value.Type); - SwapValue(Value.Size); - SwapValue(Value.VMAddress); - SwapValue(Value.VMSize); - SwapValue(Value.FileOffset); - SwapValue(Value.FileSize); - SwapValue(Value.MaxVMProtection); - SwapValue(Value.InitialVMProtection); - SwapValue(Value.NumSections); - SwapValue(Value.Flags); -} -void MachOObject::ReadSegmentLoadCommand(const LoadCommandInfo &LCI, - InMemoryStruct &Res) const { - ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); -} - -template<> -void SwapStruct(macho::Segment64LoadCommand &Value) { - SwapValue(Value.Type); - SwapValue(Value.Size); - SwapValue(Value.VMAddress); - SwapValue(Value.VMSize); - SwapValue(Value.FileOffset); - SwapValue(Value.FileSize); - SwapValue(Value.MaxVMProtection); - SwapValue(Value.InitialVMProtection); - SwapValue(Value.NumSections); - SwapValue(Value.Flags); -} -void MachOObject::ReadSegment64LoadCommand(const LoadCommandInfo &LCI, - InMemoryStruct &Res) const { - ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); -} - -template<> -void SwapStruct(macho::SymtabLoadCommand &Value) { - SwapValue(Value.Type); - SwapValue(Value.Size); - SwapValue(Value.SymbolTableOffset); - SwapValue(Value.NumSymbolTableEntries); - SwapValue(Value.StringTableOffset); - SwapValue(Value.StringTableSize); -} -void MachOObject::ReadSymtabLoadCommand(const LoadCommandInfo &LCI, - InMemoryStruct &Res) const { - ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); -} - -template<> -void SwapStruct(macho::DysymtabLoadCommand &Value) { - SwapValue(Value.Type); - SwapValue(Value.Size); - SwapValue(Value.LocalSymbolsIndex); - SwapValue(Value.NumLocalSymbols); - SwapValue(Value.ExternalSymbolsIndex); - SwapValue(Value.NumExternalSymbols); - SwapValue(Value.UndefinedSymbolsIndex); - SwapValue(Value.NumUndefinedSymbols); - SwapValue(Value.TOCOffset); - SwapValue(Value.NumTOCEntries); - SwapValue(Value.ModuleTableOffset); - SwapValue(Value.NumModuleTableEntries); - SwapValue(Value.ReferenceSymbolTableOffset); - SwapValue(Value.NumReferencedSymbolTableEntries); - SwapValue(Value.IndirectSymbolTableOffset); - SwapValue(Value.NumIndirectSymbolTableEntries); - SwapValue(Value.ExternalRelocationTableOffset); - SwapValue(Value.NumExternalRelocationTableEntries); - SwapValue(Value.LocalRelocationTableOffset); - SwapValue(Value.NumLocalRelocationTableEntries); -} -void MachOObject::ReadDysymtabLoadCommand(const LoadCommandInfo &LCI, - InMemoryStruct &Res) const { - ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); -} - -template<> -void SwapStruct(macho::LinkeditDataLoadCommand &Value) { - SwapValue(Value.Type); - SwapValue(Value.Size); - SwapValue(Value.DataOffset); - SwapValue(Value.DataSize); -} -void MachOObject::ReadLinkeditDataLoadCommand(const LoadCommandInfo &LCI, - InMemoryStruct &Res) const { - ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); -} - -template<> -void SwapStruct(macho::LinkerOptionsLoadCommand &Value) { - SwapValue(Value.Type); - SwapValue(Value.Size); - SwapValue(Value.Count); -} -void MachOObject::ReadLinkerOptionsLoadCommand(const LoadCommandInfo &LCI, - InMemoryStruct &Res) const { - ReadInMemoryStruct(*this, Buffer->getBuffer(), LCI.Offset, Res); -} - -template<> -void SwapStruct(macho::IndirectSymbolTableEntry &Value) { - SwapValue(Value.Index); -} -void -MachOObject::ReadIndirectSymbolTableEntry(const macho::DysymtabLoadCommand &DLC, - unsigned Index, - InMemoryStruct &Res) const { - uint64_t Offset = (DLC.IndirectSymbolTableOffset + - Index * sizeof(macho::IndirectSymbolTableEntry)); - ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); -} - - -template<> -void SwapStruct(macho::Section &Value) { - SwapValue(Value.Address); - SwapValue(Value.Size); - SwapValue(Value.Offset); - SwapValue(Value.Align); - SwapValue(Value.RelocationTableOffset); - SwapValue(Value.NumRelocationTableEntries); - SwapValue(Value.Flags); - SwapValue(Value.Reserved1); - SwapValue(Value.Reserved2); -} -void MachOObject::ReadSection(const LoadCommandInfo &LCI, - unsigned Index, - InMemoryStruct &Res) const { - assert(LCI.Command.Type == macho::LCT_Segment && - "Unexpected load command info!"); - uint64_t Offset = (LCI.Offset + sizeof(macho::SegmentLoadCommand) + - Index * sizeof(macho::Section)); - ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); -} - -template<> -void SwapStruct(macho::Section64 &Value) { - SwapValue(Value.Address); - SwapValue(Value.Size); - SwapValue(Value.Offset); - SwapValue(Value.Align); - SwapValue(Value.RelocationTableOffset); - SwapValue(Value.NumRelocationTableEntries); - SwapValue(Value.Flags); - SwapValue(Value.Reserved1); - SwapValue(Value.Reserved2); - SwapValue(Value.Reserved3); -} -void MachOObject::ReadSection64(const LoadCommandInfo &LCI, - unsigned Index, - InMemoryStruct &Res) const { - assert(LCI.Command.Type == macho::LCT_Segment64 && - "Unexpected load command info!"); - uint64_t Offset = (LCI.Offset + sizeof(macho::Segment64LoadCommand) + - Index * sizeof(macho::Section64)); - ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); -} - -template<> -void SwapStruct(macho::RelocationEntry &Value) { - SwapValue(Value.Word0); - SwapValue(Value.Word1); -} -void MachOObject::ReadRelocationEntry(uint64_t RelocationTableOffset, - unsigned Index, - InMemoryStruct &Res) const { - uint64_t Offset = (RelocationTableOffset + - Index * sizeof(macho::RelocationEntry)); - ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); -} - -template<> -void SwapStruct(macho::SymbolTableEntry &Value) { - SwapValue(Value.StringIndex); - SwapValue(Value.Flags); - SwapValue(Value.Value); -} -void MachOObject::ReadSymbolTableEntry(uint64_t SymbolTableOffset, - unsigned Index, - InMemoryStruct &Res) const { - uint64_t Offset = (SymbolTableOffset + - Index * sizeof(macho::SymbolTableEntry)); - ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); -} - -template<> -void SwapStruct(macho::Symbol64TableEntry &Value) { - SwapValue(Value.StringIndex); - SwapValue(Value.Flags); - SwapValue(Value.Value); -} -void MachOObject::ReadSymbol64TableEntry(uint64_t SymbolTableOffset, - unsigned Index, - InMemoryStruct &Res) const { - uint64_t Offset = (SymbolTableOffset + - Index * sizeof(macho::Symbol64TableEntry)); - ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); -} - -template<> -void SwapStruct(macho::DataInCodeTableEntry &Value) { - SwapValue(Value.Offset); - SwapValue(Value.Length); - SwapValue(Value.Kind); -} -void MachOObject::ReadDataInCodeTableEntry(uint64_t TableOffset, - unsigned Index, - InMemoryStruct &Res) const { - uint64_t Offset = (TableOffset + - Index * sizeof(macho::DataInCodeTableEntry)); - ReadInMemoryStruct(*this, Buffer->getBuffer(), Offset, Res); -} - -void MachOObject::ReadULEB128s(uint64_t Index, - SmallVectorImpl &Out) const { - DataExtractor extractor(Buffer->getBuffer(), true, 0); - - uint32_t offset = Index; - uint64_t data = 0; - while (uint64_t delta = extractor.getULEB128(&offset)) { - data += delta; - Out.push_back(data); - } -} - -/* ** */ -// Object Dumping Facilities -void MachOObject::dump() const { print(dbgs()); dbgs() << '\n'; } -void MachOObject::dumpHeader() const { printHeader(dbgs()); dbgs() << '\n'; } - -void MachOObject::printHeader(raw_ostream &O) const { - O << "('cputype', " << Header.CPUType << ")\n"; - O << "('cpusubtype', " << Header.CPUSubtype << ")\n"; - O << "('filetype', " << Header.FileType << ")\n"; - O << "('num_load_commands', " << Header.NumLoadCommands << ")\n"; - O << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n"; - O << "('flag', " << Header.Flags << ")\n"; - - // Print extended header if 64-bit. - if (is64Bit()) - O << "('reserved', " << Header64Ext.Reserved << ")\n"; -} - -void MachOObject::print(raw_ostream &O) const { - O << "Header:\n"; - printHeader(O); - O << "Load Commands:\n"; - - O << "Buffer:\n"; -} diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 38198b17938..bb6ca93176d 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -119,6 +119,11 @@ void SwapStruct(macho::Header &H) { SwapValue(H.Flags); } +template<> +void SwapStruct(macho::Header64Ext &E) { + SwapValue(E.Reserved); +} + template<> void SwapStruct(macho::SymtabLoadCommand &C) { SwapValue(C.Type); @@ -129,6 +134,30 @@ void SwapStruct(macho::SymtabLoadCommand &C) { SwapValue(C.StringTableSize); } +template<> +void SwapStruct(macho::DysymtabLoadCommand &C) { + SwapValue(C.Type); + SwapValue(C.Size); + SwapValue(C.LocalSymbolsIndex); + SwapValue(C.NumLocalSymbols); + SwapValue(C.ExternalSymbolsIndex); + SwapValue(C.NumExternalSymbols); + SwapValue(C.UndefinedSymbolsIndex); + SwapValue(C.NumUndefinedSymbols); + SwapValue(C.TOCOffset); + SwapValue(C.NumTOCEntries); + SwapValue(C.ModuleTableOffset); + SwapValue(C.NumModuleTableEntries); + SwapValue(C.ReferenceSymbolTableOffset); + SwapValue(C.NumReferencedSymbolTableEntries); + SwapValue(C.IndirectSymbolTableOffset); + SwapValue(C.NumIndirectSymbolTableEntries); + SwapValue(C.ExternalRelocationTableOffset); + SwapValue(C.NumExternalRelocationTableEntries); + SwapValue(C.LocalRelocationTableOffset); + SwapValue(C.NumLocalRelocationTableEntries); +} + template<> void SwapStruct(macho::LinkeditDataLoadCommand &C) { SwapValue(C.Type); @@ -165,6 +194,25 @@ void SwapStruct(macho::Segment64LoadCommand &C) { SwapValue(C.Flags); } +template<> +void SwapStruct(macho::IndirectSymbolTableEntry &C) { + SwapValue(C.Index); +} + +template<> +void SwapStruct(macho::LinkerOptionsLoadCommand &C) { + SwapValue(C.Type); + SwapValue(C.Size); + SwapValue(C.Count); +} + +template<> +void SwapStruct(macho::DataInCodeTableEntry &C) { + SwapValue(C.Offset); + SwapValue(C.Length); + SwapValue(C.Kind); +} + template T getStruct(const MachOObjectFile *O, const char *P) { T Cmd; @@ -174,32 +222,20 @@ T getStruct(const MachOObjectFile *O, const char *P) { return Cmd; } -static macho::SegmentLoadCommand -getSegmentLoadCommand(const MachOObjectFile *O, - const MachOObjectFile::LoadCommandInfo &L) { - return getStruct(O, L.Ptr); -} - -static macho::Segment64LoadCommand -getSegment64LoadCommand(const MachOObjectFile *O, - const MachOObjectFile::LoadCommandInfo &L) { - return getStruct(O, L.Ptr); -} - static uint32_t getSegmentLoadCommandNumSections(const MachOObjectFile *O, const MachOObjectFile::LoadCommandInfo &L) { if (O->is64Bit()) { - macho::Segment64LoadCommand S = getSegment64LoadCommand(O, L); + macho::Segment64LoadCommand S = O->getSegment64LoadCommand(L); return S.NumSections; } - macho::SegmentLoadCommand S = getSegmentLoadCommand(O, L); + macho::SegmentLoadCommand S = O->getSegmentLoadCommand(L); return S.NumSections; } -static const SectionBase * -getSectionBase(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L, - unsigned Sec) { +static const char * +getSectionPtr(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L, + unsigned Sec) { uintptr_t CommandAddr = reinterpret_cast(L.Ptr); bool Is64 = O->is64Bit(); @@ -209,7 +245,7 @@ getSectionBase(const MachOObjectFile *O, MachOObjectFile::LoadCommandInfo L, sizeof(macho::Section); uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize; - return reinterpret_cast(SectionAddr); + return reinterpret_cast(SectionAddr); } static const char *getPtr(const MachOObjectFile *O, size_t Offset) { @@ -377,7 +413,7 @@ MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, bool IsLittleEndian, bool Is64bits, error_code &ec) : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), - SymtabLoadCmd(NULL) { + SymtabLoadCmd(NULL), DysymtabLoadCmd(NULL) { uint32_t LoadCommandCount = this->getHeader().NumLoadCommands; macho::LoadCommandType SegmentLoadType = is64Bit() ? macho::LCT_Segment64 : macho::LCT_Segment; @@ -387,13 +423,14 @@ MachOObjectFile::MachOObjectFile(MemoryBuffer *Object, if (Load.C.Type == macho::LCT_Symtab) { assert(!SymtabLoadCmd && "Multiple symbol tables"); SymtabLoadCmd = Load.Ptr; - } - - if (Load.C.Type == SegmentLoadType) { + } else if (Load.C.Type == macho::LCT_Dysymtab) { + assert(!DysymtabLoadCmd && "Multiple dynamic symbol tables"); + DysymtabLoadCmd = Load.Ptr; + } else if (Load.C.Type == SegmentLoadType) { uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load); for (unsigned J = 0; J < NumSections; ++J) { - const SectionBase *Sec = getSectionBase(this, Load, J); - Sections.push_back(reinterpret_cast(Sec)); + const char *Sec = getSectionPtr(this, Load, J); + Sections.push_back(Sec); } } @@ -416,10 +453,9 @@ error_code MachOObjectFile::getSymbolNext(DataRefImpl Symb, error_code MachOObjectFile::getSymbolName(DataRefImpl Symb, StringRef &Res) const { - macho::SymtabLoadCommand S = getSymtabLoadCommand(); - const char *StringTable = getPtr(this, S.StringTableOffset); + StringRef StringTable = getStringTableData(); SymbolTableEntryBase Entry = getSymbolTableEntryBase(this, Symb); - const char *Start = &StringTable[Entry.StringIndex]; + const char *Start = &StringTable.data()[Entry.StringIndex]; Res = StringRef(Start); return object_error::success; } @@ -1271,6 +1307,18 @@ StringRef MachOObjectFile::getLoadName() const { report_fatal_error("get_load_name() unimplemented in MachOObjectFile"); } +relocation_iterator MachOObjectFile::getSectionRelBegin(unsigned Index) const { + DataRefImpl DRI; + DRI.d.a = Index; + return getSectionRelBegin(DRI); +} + +relocation_iterator MachOObjectFile::getSectionRelEnd(unsigned Index) const { + DataRefImpl DRI; + DRI.d.a = Index; + return getSectionRelEnd(DRI); +} + StringRef MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const { ArrayRef Raw = getSectionRawFinalSegmentName(Sec); @@ -1375,6 +1423,18 @@ macho::Section64 MachOObjectFile::getSection64(DataRefImpl DRI) const { return getStruct(this, Sections[DRI.d.a]); } +macho::Section MachOObjectFile::getSection(const LoadCommandInfo &L, + unsigned Index) const { + const char *Sec = getSectionPtr(this, L, Index); + return getStruct(this, Sec); +} + +macho::Section64 MachOObjectFile::getSection64(const LoadCommandInfo &L, + unsigned Index) const { + const char *Sec = getSectionPtr(this, L, Index); + return getStruct(this, Sec); +} + macho::SymbolTableEntry MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const { const char *P = reinterpret_cast(DRI.p); @@ -1392,6 +1452,21 @@ MachOObjectFile::getLinkeditDataLoadCommand(const MachOObjectFile::LoadCommandIn return getStruct(this, L.Ptr); } +macho::SegmentLoadCommand +MachOObjectFile::getSegmentLoadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +macho::Segment64LoadCommand +MachOObjectFile::getSegment64LoadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + +macho::LinkerOptionsLoadCommand +MachOObjectFile::getLinkerOptionsLoadCommand(const LoadCommandInfo &L) const { + return getStruct(this, L.Ptr); +} + macho::RelocationEntry MachOObjectFile::getRelocation(DataRefImpl Rel) const { const char *P = reinterpret_cast(Rel.p); @@ -1402,11 +1477,39 @@ macho::Header MachOObjectFile::getHeader() const { return getStruct(this, getPtr(this, 0)); } -macho::SymtabLoadCommand -MachOObjectFile::getSymtabLoadCommand() const { +macho::Header64Ext MachOObjectFile::getHeader64Ext() const { + return + getStruct(this, getPtr(this, sizeof(macho::Header))); +} + +macho::IndirectSymbolTableEntry MachOObjectFile::getIndirectSymbolTableEntry( + const macho::DysymtabLoadCommand &DLC, + unsigned Index) const { + uint64_t Offset = DLC.IndirectSymbolTableOffset + + Index * sizeof(macho::IndirectSymbolTableEntry); + return getStruct(this, getPtr(this, Offset)); +} + +macho::DataInCodeTableEntry +MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset, + unsigned Index) const { + uint64_t Offset = DataOffset + Index * sizeof(macho::DataInCodeTableEntry); + return getStruct(this, getPtr(this, Offset)); +} + +macho::SymtabLoadCommand MachOObjectFile::getSymtabLoadCommand() const { return getStruct(this, SymtabLoadCmd); } +macho::DysymtabLoadCommand MachOObjectFile::getDysymtabLoadCommand() const { + return getStruct(this, DysymtabLoadCmd); +} + +StringRef MachOObjectFile::getStringTableData() const { + macho::SymtabLoadCommand S = getSymtabLoadCommand(); + return getData().substr(S.StringTableOffset, S.StringTableSize); +} + bool MachOObjectFile::is64Bit() const { return getType() == getMachOType(false, true) || getType() == getMachOType(true, true); diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 4d8d345894d..ead541a5b80 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -17,7 +17,7 @@ #include "llvm/ExecutionEngine/ObjectBuffer.h" #include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/Object/MachOObject.h" +#include "llvm/Object/MachO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Memory.h" diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index 3bd3ecc8fde..88fd4529ab4 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -11,9 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Object/MachOObject.h" +#include "llvm/Object/MachO.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" @@ -66,7 +67,8 @@ static void DumpSegmentCommandData(StringRef Name, outs() << " ('flags', " << Flags << ")\n"; } -static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name, +static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index, + StringRef Name, StringRef SegmentName, uint64_t Address, uint64_t Size, uint32_t Offset, uint32_t Align, uint32_t RelocationTableOffset, @@ -92,26 +94,22 @@ static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name, outs() << " ),\n"; // Dump the relocation entries. - int Res = 0; outs() << " ('_relocations', [\n"; - for (unsigned i = 0; i != NumRelocationTableEntries; ++i) { - InMemoryStruct RE; - Obj.ReadRelocationEntry(RelocationTableOffset, i, RE); - if (!RE) { - Res = Error("unable to read relocation table entry '" + Twine(i) + "'"); - break; - } - - outs() << " # Relocation " << i << "\n"; - outs() << " (('word-0', " << format("0x%x", RE->Word0) << "),\n"; - outs() << " ('word-1', " << format("0x%x", RE->Word1) << ")),\n"; + unsigned RelNum = 0; + error_code EC; + for (relocation_iterator I = Obj.getSectionRelBegin(Index), + E = Obj.getSectionRelEnd(Index); I != E; I.increment(EC), ++RelNum) { + macho::RelocationEntry RE = Obj.getRelocation(I->getRawDataRefImpl()); + outs() << " # Relocation " << RelNum << "\n"; + outs() << " (('word-0', " << format("0x%x", RE.Word0) << "),\n"; + outs() << " ('word-1', " << format("0x%x", RE.Word1) << ")),\n"; } outs() << " ])\n"; // Dump the section data, if requested. if (ShowSectionData) { outs() << " ('_section_data', '"; - StringRef Data = Obj.getData(Offset, Size); + StringRef Data = Obj.getData().substr(Offset, Size); for (unsigned i = 0; i != Data.size(); ++i) { if (i && (i % 4) == 0) outs() << ' '; @@ -121,208 +119,162 @@ static int DumpSectionData(MachOObject &Obj, unsigned Index, StringRef Name, outs() << "')\n"; } - return Res; + return 0; } -static int DumpSegmentCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct SLC; - Obj.ReadSegmentLoadCommand(LCI, SLC); - if (!SLC) - return Error("unable to read segment load command"); +static int DumpSegmentCommand(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::SegmentLoadCommand SLC = Obj.getSegmentLoadCommand(LCI); - DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress, - SLC->VMSize, SLC->FileOffset, SLC->FileSize, - SLC->MaxVMProtection, SLC->InitialVMProtection, - SLC->NumSections, SLC->Flags); + DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress, + SLC.VMSize, SLC.FileOffset, SLC.FileSize, + SLC.MaxVMProtection, SLC.InitialVMProtection, + SLC.NumSections, SLC.Flags); // Dump the sections. - int Res = 0; outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC->NumSections; ++i) { - InMemoryStruct Sect; - Obj.ReadSection(LCI, i, Sect); - if (!SLC) { - Res = Error("unable to read section '" + Twine(i) + "'"); - break; - } - - if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16), - StringRef(Sect->SegmentName, 16), Sect->Address, - Sect->Size, Sect->Offset, Sect->Align, - Sect->RelocationTableOffset, - Sect->NumRelocationTableEntries, Sect->Flags, - Sect->Reserved1, Sect->Reserved2))) - break; + for (unsigned i = 0; i != SLC.NumSections; ++i) { + macho::Section Sect = Obj.getSection(LCI, i); + DumpSectionData(Obj, i, StringRef(Sect.Name, 16), + StringRef(Sect.SegmentName, 16), Sect.Address, + Sect.Size, Sect.Offset, Sect.Align, + Sect.RelocationTableOffset, + Sect.NumRelocationTableEntries, Sect.Flags, + Sect.Reserved1, Sect.Reserved2); } outs() << " ])\n"; - return Res; + return 0; } -static int DumpSegment64Command(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct SLC; - Obj.ReadSegment64LoadCommand(LCI, SLC); - if (!SLC) - return Error("unable to read segment load command"); - - DumpSegmentCommandData(StringRef(SLC->Name, 16), SLC->VMAddress, - SLC->VMSize, SLC->FileOffset, SLC->FileSize, - SLC->MaxVMProtection, SLC->InitialVMProtection, - SLC->NumSections, SLC->Flags); +static int DumpSegment64Command(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::Segment64LoadCommand SLC = Obj.getSegment64LoadCommand(LCI); + DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress, + SLC.VMSize, SLC.FileOffset, SLC.FileSize, + SLC.MaxVMProtection, SLC.InitialVMProtection, + SLC.NumSections, SLC.Flags); // Dump the sections. - int Res = 0; outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC->NumSections; ++i) { - InMemoryStruct Sect; - Obj.ReadSection64(LCI, i, Sect); - if (!SLC) { - Res = Error("unable to read section '" + Twine(i) + "'"); - break; - } + for (unsigned i = 0; i != SLC.NumSections; ++i) { + macho::Section64 Sect = Obj.getSection64(LCI, i); - if ((Res = DumpSectionData(Obj, i, StringRef(Sect->Name, 16), - StringRef(Sect->SegmentName, 16), Sect->Address, - Sect->Size, Sect->Offset, Sect->Align, - Sect->RelocationTableOffset, - Sect->NumRelocationTableEntries, Sect->Flags, - Sect->Reserved1, Sect->Reserved2, - Sect->Reserved3))) - break; + DumpSectionData(Obj, i, StringRef(Sect.Name, 16), + StringRef(Sect.SegmentName, 16), Sect.Address, + Sect.Size, Sect.Offset, Sect.Align, + Sect.RelocationTableOffset, + Sect.NumRelocationTableEntries, Sect.Flags, + Sect.Reserved1, Sect.Reserved2, + Sect.Reserved3); } outs() << " ])\n"; - return Res; + return 0; } -static void DumpSymbolTableEntryData(MachOObject &Obj, +static void DumpSymbolTableEntryData(const MachOObjectFile &Obj, unsigned Index, uint32_t StringIndex, uint8_t Type, uint8_t SectionIndex, - uint16_t Flags, uint64_t Value) { + uint16_t Flags, uint64_t Value, + StringRef StringTable) { + const char *Name = &StringTable.data()[StringIndex]; outs() << " # Symbol " << Index << "\n"; outs() << " (('n_strx', " << StringIndex << ")\n"; outs() << " ('n_type', " << format("0x%x", Type) << ")\n"; outs() << " ('n_sect', " << uint32_t(SectionIndex) << ")\n"; outs() << " ('n_desc', " << Flags << ")\n"; outs() << " ('n_value', " << Value << ")\n"; - outs() << " ('_string', '" << Obj.getStringAtIndex(StringIndex) << "')\n"; + outs() << " ('_string', '" << Name << "')\n"; outs() << " ),\n"; } -static int DumpSymtabCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct SLC; - Obj.ReadSymtabLoadCommand(LCI, SLC); - if (!SLC) - return Error("unable to read segment load command"); +static int DumpSymtabCommand(const MachOObjectFile &Obj) { + macho::SymtabLoadCommand SLC = Obj.getSymtabLoadCommand(); - outs() << " ('symoff', " << SLC->SymbolTableOffset << ")\n"; - outs() << " ('nsyms', " << SLC->NumSymbolTableEntries << ")\n"; - outs() << " ('stroff', " << SLC->StringTableOffset << ")\n"; - outs() << " ('strsize', " << SLC->StringTableSize << ")\n"; - - // Cache the string table data. - Obj.RegisterStringTable(*SLC); + outs() << " ('symoff', " << SLC.SymbolTableOffset << ")\n"; + outs() << " ('nsyms', " << SLC.NumSymbolTableEntries << ")\n"; + outs() << " ('stroff', " << SLC.StringTableOffset << ")\n"; + outs() << " ('strsize', " << SLC.StringTableSize << ")\n"; // Dump the string data. outs() << " ('_string_data', '"; - outs().write_escaped(Obj.getStringTableData(), + StringRef StringTable = Obj.getStringTableData(); + outs().write_escaped(StringTable, /*UseHexEscapes=*/true) << "')\n"; // Dump the symbol table. - int Res = 0; outs() << " ('_symbols', [\n"; - for (unsigned i = 0; i != SLC->NumSymbolTableEntries; ++i) { + error_code EC; + unsigned SymNum = 0; + for (symbol_iterator I = Obj.begin_symbols(), E = Obj.end_symbols(); I != E; + I.increment(EC), ++SymNum) { + DataRefImpl DRI = I->getRawDataRefImpl(); if (Obj.is64Bit()) { - InMemoryStruct STE; - Obj.ReadSymbol64TableEntry(SLC->SymbolTableOffset, i, STE); - if (!STE) { - Res = Error("unable to read symbol: '" + Twine(i) + "'"); - break; - } - - DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type, - STE->SectionIndex, STE->Flags, STE->Value); + macho::Symbol64TableEntry STE = Obj.getSymbol64TableEntry(DRI); + DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type, + STE.SectionIndex, STE.Flags, STE.Value, + StringTable); } else { - InMemoryStruct STE; - Obj.ReadSymbolTableEntry(SLC->SymbolTableOffset, i, STE); - if (!SLC) { - Res = Error("unable to read symbol: '" + Twine(i) + "'"); - break; - } - - DumpSymbolTableEntryData(Obj, i, STE->StringIndex, STE->Type, - STE->SectionIndex, STE->Flags, STE->Value); + macho::SymbolTableEntry STE = Obj.getSymbolTableEntry(DRI); + DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type, + STE.SectionIndex, STE.Flags, STE.Value, + StringTable); } } outs() << " ])\n"; - return Res; + return 0; } -static int DumpDysymtabCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct DLC; - Obj.ReadDysymtabLoadCommand(LCI, DLC); - if (!DLC) - return Error("unable to read segment load command"); +static int DumpDysymtabCommand(const MachOObjectFile &Obj) { + macho::DysymtabLoadCommand DLC = Obj.getDysymtabLoadCommand(); - outs() << " ('ilocalsym', " << DLC->LocalSymbolsIndex << ")\n"; - outs() << " ('nlocalsym', " << DLC->NumLocalSymbols << ")\n"; - outs() << " ('iextdefsym', " << DLC->ExternalSymbolsIndex << ")\n"; - outs() << " ('nextdefsym', " << DLC->NumExternalSymbols << ")\n"; - outs() << " ('iundefsym', " << DLC->UndefinedSymbolsIndex << ")\n"; - outs() << " ('nundefsym', " << DLC->NumUndefinedSymbols << ")\n"; - outs() << " ('tocoff', " << DLC->TOCOffset << ")\n"; - outs() << " ('ntoc', " << DLC->NumTOCEntries << ")\n"; - outs() << " ('modtaboff', " << DLC->ModuleTableOffset << ")\n"; - outs() << " ('nmodtab', " << DLC->NumModuleTableEntries << ")\n"; - outs() << " ('extrefsymoff', " << DLC->ReferenceSymbolTableOffset << ")\n"; + outs() << " ('ilocalsym', " << DLC.LocalSymbolsIndex << ")\n"; + outs() << " ('nlocalsym', " << DLC.NumLocalSymbols << ")\n"; + outs() << " ('iextdefsym', " << DLC.ExternalSymbolsIndex << ")\n"; + outs() << " ('nextdefsym', " << DLC.NumExternalSymbols << ")\n"; + outs() << " ('iundefsym', " << DLC.UndefinedSymbolsIndex << ")\n"; + outs() << " ('nundefsym', " << DLC.NumUndefinedSymbols << ")\n"; + outs() << " ('tocoff', " << DLC.TOCOffset << ")\n"; + outs() << " ('ntoc', " << DLC.NumTOCEntries << ")\n"; + outs() << " ('modtaboff', " << DLC.ModuleTableOffset << ")\n"; + outs() << " ('nmodtab', " << DLC.NumModuleTableEntries << ")\n"; + outs() << " ('extrefsymoff', " << DLC.ReferenceSymbolTableOffset << ")\n"; outs() << " ('nextrefsyms', " - << DLC->NumReferencedSymbolTableEntries << ")\n"; - outs() << " ('indirectsymoff', " << DLC->IndirectSymbolTableOffset << ")\n"; + << DLC.NumReferencedSymbolTableEntries << ")\n"; + outs() << " ('indirectsymoff', " << DLC.IndirectSymbolTableOffset << ")\n"; outs() << " ('nindirectsyms', " - << DLC->NumIndirectSymbolTableEntries << ")\n"; - outs() << " ('extreloff', " << DLC->ExternalRelocationTableOffset << ")\n"; - outs() << " ('nextrel', " << DLC->NumExternalRelocationTableEntries << ")\n"; - outs() << " ('locreloff', " << DLC->LocalRelocationTableOffset << ")\n"; - outs() << " ('nlocrel', " << DLC->NumLocalRelocationTableEntries << ")\n"; + << DLC.NumIndirectSymbolTableEntries << ")\n"; + outs() << " ('extreloff', " << DLC.ExternalRelocationTableOffset << ")\n"; + outs() << " ('nextrel', " << DLC.NumExternalRelocationTableEntries << ")\n"; + outs() << " ('locreloff', " << DLC.LocalRelocationTableOffset << ")\n"; + outs() << " ('nlocrel', " << DLC.NumLocalRelocationTableEntries << ")\n"; // Dump the indirect symbol table. - int Res = 0; outs() << " ('_indirect_symbols', [\n"; - for (unsigned i = 0; i != DLC->NumIndirectSymbolTableEntries; ++i) { - InMemoryStruct ISTE; - Obj.ReadIndirectSymbolTableEntry(*DLC, i, ISTE); - if (!ISTE) { - Res = Error("unable to read segment load command"); - break; - } - + for (unsigned i = 0; i != DLC.NumIndirectSymbolTableEntries; ++i) { + macho::IndirectSymbolTableEntry ISTE = + Obj.getIndirectSymbolTableEntry(DLC, i); outs() << " # Indirect Symbol " << i << "\n"; outs() << " (('symbol_index', " - << format("0x%x", ISTE->Index) << "),),\n"; + << format("0x%x", ISTE.Index) << "),),\n"; } outs() << " ])\n"; - return Res; + return 0; } -static int DumpLinkeditDataCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct LLC; - Obj.ReadLinkeditDataLoadCommand(LCI, LLC); - if (!LLC) - return Error("unable to read segment load command"); - - outs() << " ('dataoff', " << LLC->DataOffset << ")\n" - << " ('datasize', " << LLC->DataSize << ")\n" +static int +DumpLinkeditDataCommand(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI); + outs() << " ('dataoff', " << LLC.DataOffset << ")\n" + << " ('datasize', " << LLC.DataSize << ")\n" << " ('_addresses', [\n"; SmallVector Addresses; - Obj.ReadULEB128s(LLC->DataOffset, Addresses); + Obj.ReadULEB128s(LLC.DataOffset, Addresses); for (unsigned i = 0, e = Addresses.size(); i != e; ++i) outs() << " # Address " << i << '\n' << " ('address', " << format("0x%x", Addresses[i]) << "),\n"; @@ -332,28 +284,22 @@ static int DumpLinkeditDataCommand(MachOObject &Obj, return 0; } -static int DumpDataInCodeDataCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct LLC; - Obj.ReadLinkeditDataLoadCommand(LCI, LLC); - if (!LLC) - return Error("unable to read data-in-code load command"); - - outs() << " ('dataoff', " << LLC->DataOffset << ")\n" - << " ('datasize', " << LLC->DataSize << ")\n" +static int +DumpDataInCodeDataCommand(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI); + outs() << " ('dataoff', " << LLC.DataOffset << ")\n" + << " ('datasize', " << LLC.DataSize << ")\n" << " ('_data_regions', [\n"; - - unsigned NumRegions = LLC->DataSize / 8; + unsigned NumRegions = LLC.DataSize / 8; for (unsigned i = 0; i < NumRegions; ++i) { - InMemoryStruct DICE; - Obj.ReadDataInCodeTableEntry(LLC->DataOffset, i, DICE); - if (!DICE) - return Error("unable to read DataInCodeTableEntry"); + macho::DataInCodeTableEntry DICE = + Obj.getDataInCodeTableEntry(LLC.DataOffset, i); outs() << " # DICE " << i << "\n" - << " ('offset', " << DICE->Offset << ")\n" - << " ('length', " << DICE->Length << ")\n" - << " ('kind', " << DICE->Kind << ")\n"; + << " ('offset', " << DICE.Offset << ")\n" + << " ('length', " << DICE.Length << ")\n" + << " ('kind', " << DICE.Kind << ")\n"; } outs() <<" ])\n"; @@ -361,99 +307,111 @@ static int DumpDataInCodeDataCommand(MachOObject &Obj, return 0; } -static int DumpLinkerOptionsCommand(MachOObject &Obj, - const MachOObject::LoadCommandInfo &LCI) { - InMemoryStruct LOLC; - Obj.ReadLinkerOptionsLoadCommand(LCI, LOLC); - if (!LOLC) - return Error("unable to read linker options load command"); +static int +DumpLinkerOptionsCommand(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + macho::LinkerOptionsLoadCommand LOLC = Obj.getLinkerOptionsLoadCommand(LCI); + outs() << " ('count', " << LOLC.Count << ")\n" + << " ('_strings', [\n"; - outs() << " ('count', " << LOLC->Count << ")\n" - << " ('_strings', [\n"; - - uint64_t DataSize = LOLC->Size - sizeof(macho::LinkerOptionsLoadCommand); - StringRef Data = Obj.getData( - LCI.Offset + sizeof(macho::LinkerOptionsLoadCommand), DataSize); - for (unsigned i = 0; i != LOLC->Count; ++i) { - std::pair Split = Data.split('\0'); - outs() << "\t\""; - outs().write_escaped(Split.first); - outs() << "\",\n"; - Data = Split.second; - } - outs() <<" ])\n"; + uint64_t DataSize = LOLC.Size - sizeof(macho::LinkerOptionsLoadCommand); + const char *P = LCI.Ptr + sizeof(macho::LinkerOptionsLoadCommand); + StringRef Data(P, DataSize); + for (unsigned i = 0; i != LOLC.Count; ++i) { + std::pair Split = Data.split('\0'); + outs() << "\t\""; + outs().write_escaped(Split.first); + outs() << "\",\n"; + Data = Split.second; + } + outs() <<" ])\n"; return 0; } - -static int DumpLoadCommand(MachOObject &Obj, unsigned Index) { - const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index); - int Res = 0; - - outs() << " # Load Command " << Index << "\n" - << " (('command', " << LCI.Command.Type << ")\n" - << " ('size', " << LCI.Command.Size << ")\n"; - switch (LCI.Command.Type) { +static int DumpLoadCommand(const MachOObjectFile &Obj, + MachOObjectFile::LoadCommandInfo &LCI) { + switch (LCI.C.Type) { case macho::LCT_Segment: - Res = DumpSegmentCommand(Obj, LCI); - break; + return DumpSegmentCommand(Obj, LCI); case macho::LCT_Segment64: - Res = DumpSegment64Command(Obj, LCI); - break; + return DumpSegment64Command(Obj, LCI); case macho::LCT_Symtab: - Res = DumpSymtabCommand(Obj, LCI); - break; + return DumpSymtabCommand(Obj); case macho::LCT_Dysymtab: - Res = DumpDysymtabCommand(Obj, LCI); - break; + return DumpDysymtabCommand(Obj); case macho::LCT_CodeSignature: case macho::LCT_SegmentSplitInfo: case macho::LCT_FunctionStarts: - Res = DumpLinkeditDataCommand(Obj, LCI); - break; + return DumpLinkeditDataCommand(Obj, LCI); case macho::LCT_DataInCode: - Res = DumpDataInCodeDataCommand(Obj, LCI); - break; + return DumpDataInCodeDataCommand(Obj, LCI); case macho::LCT_LinkerOptions: - Res = DumpLinkerOptionsCommand(Obj, LCI); - break; + return DumpLinkerOptionsCommand(Obj, LCI); default: - Warning("unknown load command: " + Twine(LCI.Command.Type)); - break; + Warning("unknown load command: " + Twine(LCI.C.Type)); + return 0; } - outs() << " ),\n"; +} + +static int DumpLoadCommand(const MachOObjectFile &Obj, unsigned Index, + MachOObjectFile::LoadCommandInfo &LCI) { + outs() << " # Load Command " << Index << "\n" + << " (('command', " << LCI.C.Type << ")\n" + << " ('size', " << LCI.C.Size << ")\n"; + int Res = DumpLoadCommand(Obj, LCI); + outs() << " ),\n"; return Res; } +static void printHeader(const MachOObjectFile *Obj, + const macho::Header &Header) { + outs() << "('cputype', " << Header.CPUType << ")\n"; + outs() << "('cpusubtype', " << Header.CPUSubtype << ")\n"; + outs() << "('filetype', " << Header.FileType << ")\n"; + outs() << "('num_load_commands', " << Header.NumLoadCommands << ")\n"; + outs() << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n"; + outs() << "('flag', " << Header.Flags << ")\n"; + + // Print extended header if 64-bit. + if (Obj->is64Bit()) { + macho::Header64Ext Header64Ext = Obj->getHeader64Ext(); + outs() << "('reserved', " << Header64Ext.Reserved << ")\n"; + } +} + int main(int argc, char **argv) { ProgramName = argv[0]; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n"); - // Load the input file. - std::string ErrorStr; - OwningPtr InputBuffer; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFile, InputBuffer)) - return Error("unable to read input: '" + ec.message() + "'"); + OwningPtr Binary; + if (error_code EC = createBinary(InputFile, Binary)) + return Error("unable to read input: '" + EC.message() + "'"); - // Construct the Mach-O wrapper object. - OwningPtr InputObject( - MachOObject::LoadFromBuffer(InputBuffer.take(), &ErrorStr)); + const MachOObjectFile *InputObject = dyn_cast(Binary.get()); if (!InputObject) - return Error("unable to load object: '" + ErrorStr + "'"); + return Error("Not a MachO object"); // Print the header - InputObject->printHeader(outs()); + macho::Header Header = InputObject->getHeader(); + printHeader(InputObject, Header); // Print the load commands. int Res = 0; + MachOObjectFile::LoadCommandInfo Command = + InputObject->getFirstLoadCommandInfo(); outs() << "('load_commands', [\n"; - for (unsigned i = 0; i != InputObject->getHeader().NumLoadCommands; ++i) - if ((Res = DumpLoadCommand(*InputObject, i))) + for (unsigned i = 0; ; ++i) { + if (DumpLoadCommand(*InputObject, i, Command)) break; + + if (i == Header.NumLoadCommands - 1) + break; + Command = InputObject->getNextLoadCommandInfo(Command); + } outs() << "])\n"; return Res;