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
19namespace llvm {
20
21class MemoryBuffer;
22class raw_ostream;
23
24namespace 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.
45class MachOObject {
46public:
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
55private:
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
78private:
79  MachOObject(MemoryBuffer *Buffer, bool IsLittleEndian, bool Is64Bit);
80
81public:
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 ReadDataInCodeTableEntry(
178    uint64_t TableOffset, unsigned Index,
179    InMemoryStruct<macho::DataInCodeTableEntry> &Res) const;
180  void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const;
181
182  /// @}
183
184  /// @name Object Dump Facilities
185  /// @{
186  /// dump - Support for debugging, callable in GDB: V->dump()
187  //
188  void dump() const;
189  void dumpHeader() const;
190
191  /// print - Implement operator<< on Value.
192  ///
193  void print(raw_ostream &O) const;
194  void printHeader(raw_ostream &O) const;
195
196  /// @}
197};
198
199inline raw_ostream &operator<<(raw_ostream &OS, const MachOObject &V) {
200  V.print(OS);
201  return OS;
202}
203
204} // end namespace object
205} // end namespace llvm
206
207#endif
208