summaryrefslogtreecommitdiff
path: root/include/llvm/Object/MachOObject.h
blob: 51be847858a1e23061116acd8358315814fcc9ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//===- 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 <string>
#include "llvm/ADT/InMemoryStruct.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/MachOFormat.h"

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<MemoryBuffer> 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
  /// @{

  /// \brief Retrieve the information for the given load command.
  const LoadCommandInfo &getLoadCommandInfo(unsigned Index) const;

  void ReadSegmentLoadCommand(
    const LoadCommandInfo &LCI,
    InMemoryStruct<macho::SegmentLoadCommand> &Res) const;
  void ReadSegment64LoadCommand(
    const LoadCommandInfo &LCI,
    InMemoryStruct<macho::Segment64LoadCommand> &Res) const;
  void ReadSymtabLoadCommand(
    const LoadCommandInfo &LCI,
    InMemoryStruct<macho::SymtabLoadCommand> &Res) const;
  void ReadDysymtabLoadCommand(
    const LoadCommandInfo &LCI,
    InMemoryStruct<macho::DysymtabLoadCommand> &Res) const;
  void ReadLinkeditDataLoadCommand(
    const LoadCommandInfo &LCI,
    InMemoryStruct<macho::LinkeditDataLoadCommand> &Res) const;
  void ReadIndirectSymbolTableEntry(
    const macho::DysymtabLoadCommand &DLC,
    unsigned Index,
    InMemoryStruct<macho::IndirectSymbolTableEntry> &Res) const;
  void ReadSection(
    const LoadCommandInfo &LCI,
    unsigned Index,
    InMemoryStruct<macho::Section> &Res) const;
  void ReadSection64(
    const LoadCommandInfo &LCI,
    unsigned Index,
    InMemoryStruct<macho::Section64> &Res) const;
  void ReadRelocationEntry(
    uint64_t RelocationTableOffset, unsigned Index,
    InMemoryStruct<macho::RelocationEntry> &Res) const;
  void ReadSymbolTableEntry(
    uint64_t SymbolTableOffset, unsigned Index,
    InMemoryStruct<macho::SymbolTableEntry> &Res) const;
  void ReadSymbol64TableEntry(
    uint64_t SymbolTableOffset, unsigned Index,
    InMemoryStruct<macho::Symbol64TableEntry> &Res) const;
  void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &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