Home | History | Annotate | Download | only in Object
      1 //===- MachOObject.h - Mach-O Object File Wrapper ---------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_OBJECT_MACHOOBJECT_H
     11 #define LLVM_OBJECT_MACHOOBJECT_H
     12 
     13 #include <string>
     14 #include "llvm/ADT/InMemoryStruct.h"
     15 #include "llvm/ADT/OwningPtr.h"
     16 #include "llvm/ADT/StringRef.h"
     17 #include "llvm/Object/MachOFormat.h"
     18 
     19 namespace llvm {
     20 
     21 class MemoryBuffer;
     22 class raw_ostream;
     23 
     24 namespace object {
     25 
     26 /// \brief Wrapper object for manipulating Mach-O object files.
     27 ///
     28 /// This class is designed to implement a full-featured, efficient, portable,
     29 /// and robust Mach-O interface to Mach-O object files. It does not attempt to
     30 /// smooth over rough edges in the Mach-O format or generalize access to object
     31 /// independent features.
     32 ///
     33 /// The class is designed around accessing the Mach-O object which is expected
     34 /// to be fully loaded into memory.
     35 ///
     36 /// This class is *not* suitable for concurrent use. For efficient operation,
     37 /// the class uses APIs which rely on the ability to cache the results of
     38 /// certain calls in internal objects which are not safe for concurrent
     39 /// access. This allows the API to be zero-copy on the common paths.
     40 //
     41 // FIXME: It would be cool if we supported a "paged" MemoryBuffer
     42 // implementation. This would allow us to implement a more sensible version of
     43 // MemoryObject which can work like a MemoryBuffer, but be more efficient for
     44 // objects which are in the current address space.
     45 class MachOObject {
     46 public:
     47   struct LoadCommandInfo {
     48     /// The load command information.
     49     macho::LoadCommand Command;
     50 
     51     /// The offset to the start of the load command in memory.
     52     uint64_t Offset;
     53   };
     54 
     55 private:
     56   OwningPtr<MemoryBuffer> Buffer;
     57 
     58   /// Whether the object is little endian.
     59   bool IsLittleEndian;
     60   /// Whether the object is 64-bit.
     61   bool Is64Bit;
     62   /// Whether the object is swapped endianness from the host.
     63   bool IsSwappedEndian;
     64   /// Whether the string table has been registered.
     65   bool HasStringTable;
     66 
     67   /// The cached information on the load commands.
     68   LoadCommandInfo *LoadCommands;
     69   mutable unsigned NumLoadedCommands;
     70 
     71   /// The cached copy of the header.
     72   macho::Header Header;
     73   macho::Header64Ext Header64Ext;
     74 
     75   /// Cache string table information.
     76   StringRef StringTable;
     77 
     78 private:
     79   MachOObject(MemoryBuffer *Buffer, bool IsLittleEndian, bool Is64Bit);
     80 
     81 public:
     82   ~MachOObject();
     83 
     84   /// \brief Load a Mach-O object from a MemoryBuffer object.
     85   ///
     86   /// \param Buffer - The buffer to load the object from. This routine takes
     87   /// exclusive ownership of the buffer (which is passed to the returned object
     88   /// on success).
     89   /// \param ErrorStr [out] - If given, will be set to a user readable error
     90   /// message on failure.
     91   /// \returns The loaded object, or null on error.
     92   static MachOObject *LoadFromBuffer(MemoryBuffer *Buffer,
     93                                      std::string *ErrorStr = 0);
     94 
     95   /// @name File Information
     96   /// @{
     97 
     98   bool isLittleEndian() const { return IsLittleEndian; }
     99   bool isSwappedEndian() const { return IsSwappedEndian; }
    100   bool is64Bit() const { return Is64Bit; }
    101 
    102   unsigned getHeaderSize() const {
    103     return Is64Bit ? macho::Header64Size : macho::Header32Size;
    104   }
    105 
    106   StringRef getData(size_t Offset, size_t Size) const;
    107 
    108   /// @}
    109   /// @name String Table Data
    110   /// @{
    111 
    112   StringRef getStringTableData() const {
    113     assert(HasStringTable && "String table has not been registered!");
    114     return StringTable;
    115   }
    116 
    117   StringRef getStringAtIndex(unsigned Index) const {
    118     size_t End = getStringTableData().find('\0', Index);
    119     return getStringTableData().slice(Index, End);
    120   }
    121 
    122   void RegisterStringTable(macho::SymtabLoadCommand &SLC);
    123 
    124   /// @}
    125   /// @name Object Header Access
    126   /// @{
    127 
    128   const macho::Header &getHeader() const { return Header; }
    129   const macho::Header64Ext &getHeader64Ext() const {
    130     assert(is64Bit() && "Invalid access!");
    131     return Header64Ext;
    132   }
    133 
    134   /// @}
    135   /// @name Object Structure Access
    136   /// @{
    137 
    138   /// \brief Retrieve the information for the given load command.
    139   const LoadCommandInfo &getLoadCommandInfo(unsigned Index) const;
    140 
    141   void ReadSegmentLoadCommand(
    142     const LoadCommandInfo &LCI,
    143     InMemoryStruct<macho::SegmentLoadCommand> &Res) const;
    144   void ReadSegment64LoadCommand(
    145     const LoadCommandInfo &LCI,
    146     InMemoryStruct<macho::Segment64LoadCommand> &Res) const;
    147   void ReadSymtabLoadCommand(
    148     const LoadCommandInfo &LCI,
    149     InMemoryStruct<macho::SymtabLoadCommand> &Res) const;
    150   void ReadDysymtabLoadCommand(
    151     const LoadCommandInfo &LCI,
    152     InMemoryStruct<macho::DysymtabLoadCommand> &Res) const;
    153   void ReadLinkeditDataLoadCommand(
    154     const LoadCommandInfo &LCI,
    155     InMemoryStruct<macho::LinkeditDataLoadCommand> &Res) const;
    156   void ReadIndirectSymbolTableEntry(
    157     const macho::DysymtabLoadCommand &DLC,
    158     unsigned Index,
    159     InMemoryStruct<macho::IndirectSymbolTableEntry> &Res) const;
    160   void ReadSection(
    161     const LoadCommandInfo &LCI,
    162     unsigned Index,
    163     InMemoryStruct<macho::Section> &Res) const;
    164   void ReadSection64(
    165     const LoadCommandInfo &LCI,
    166     unsigned Index,
    167     InMemoryStruct<macho::Section64> &Res) const;
    168   void ReadRelocationEntry(
    169     uint64_t RelocationTableOffset, unsigned Index,
    170     InMemoryStruct<macho::RelocationEntry> &Res) const;
    171   void ReadSymbolTableEntry(
    172     uint64_t SymbolTableOffset, unsigned Index,
    173     InMemoryStruct<macho::SymbolTableEntry> &Res) const;
    174   void ReadSymbol64TableEntry(
    175     uint64_t SymbolTableOffset, unsigned Index,
    176     InMemoryStruct<macho::Symbol64TableEntry> &Res) const;
    177   void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const;
    178 
    179   /// @}
    180 
    181   /// @name Object Dump Facilities
    182   /// @{
    183   /// dump - Support for debugging, callable in GDB: V->dump()
    184   //
    185   void dump() const;
    186   void dumpHeader() const;
    187 
    188   /// print - Implement operator<< on Value.
    189   ///
    190   void print(raw_ostream &O) const;
    191   void printHeader(raw_ostream &O) const;
    192 
    193   /// @}
    194 };
    195 
    196 inline raw_ostream &operator<<(raw_ostream &OS, const MachOObject &V) {
    197   V.print(OS);
    198   return OS;
    199 }
    200 
    201 } // end namespace object
    202 } // end namespace llvm
    203 
    204 #endif
    205