Coverage Report

Created: 2017-10-03 07:32

/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/lld/lib/ReaderWriter/MachO/MachONormalizedFile.h
Line
Count
Source
1
//===- lib/ReaderWriter/MachO/MachONormalizedFile.h -----------------------===//
2
//
3
//                             The LLVM Linker
4
//
5
// This file is distributed under the University of Illinois Open Source
6
// License. See LICENSE.TXT for details.
7
//
8
//===----------------------------------------------------------------------===//
9
10
///
11
/// \file These data structures comprise the "normalized" view of
12
/// mach-o object files. The normalized view is an in-memory only data structure
13
/// which is always in native endianness and pointer size.
14
///
15
/// The normalized view easily converts to and from YAML using YAML I/O.
16
///
17
/// The normalized view converts to and from binary mach-o object files using
18
/// the writeBinary() and readBinary() functions.
19
///
20
/// The normalized view converts to and from lld::Atoms using the
21
/// normalizedToAtoms() and normalizedFromAtoms().
22
///
23
/// Overall, the conversion paths available look like:
24
///
25
///                 +---------------+
26
///                 | binary mach-o |
27
///                 +---------------+
28
///                        ^
29
///                        |
30
///                        v
31
///                  +------------+         +------+
32
///                  | normalized |   <->   | yaml |
33
///                  +------------+         +------+
34
///                        ^
35
///                        |
36
///                        v
37
///                    +-------+
38
///                    | Atoms |
39
///                    +-------+
40
///
41
42
#ifndef LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
43
#define LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H
44
45
#include "DebugInfo.h"
46
#include "lld/Core/Error.h"
47
#include "lld/Core/LLVM.h"
48
#include "lld/ReaderWriter/MachOLinkingContext.h"
49
#include "llvm/ADT/SmallString.h"
50
#include "llvm/ADT/StringRef.h"
51
#include "llvm/BinaryFormat/MachO.h"
52
#include "llvm/Support/Allocator.h"
53
#include "llvm/Support/Debug.h"
54
#include "llvm/Support/ErrorOr.h"
55
#include "llvm/Support/YAMLTraits.h"
56
57
using llvm::BumpPtrAllocator;
58
using llvm::yaml::Hex64;
59
using llvm::yaml::Hex32;
60
using llvm::yaml::Hex16;
61
using llvm::yaml::Hex8;
62
using llvm::yaml::SequenceTraits;
63
using llvm::MachO::HeaderFileType;
64
using llvm::MachO::BindType;
65
using llvm::MachO::RebaseType;
66
using llvm::MachO::NListType;
67
using llvm::MachO::RelocationInfoType;
68
using llvm::MachO::SectionType;
69
using llvm::MachO::LoadCommandType;
70
using llvm::MachO::ExportSymbolKind;
71
using llvm::MachO::DataRegionType;
72
73
namespace lld {
74
namespace mach_o {
75
namespace normalized {
76
77
78
/// The real mach-o relocation record is 8-bytes on disk and is
79
/// encoded in one of two different bit-field patterns.  This
80
/// normalized form has the union of all possible fields.
81
struct Relocation {
82
  Relocation() : offset(0), scattered(false),
83
                 type(llvm::MachO::GENERIC_RELOC_VANILLA),
84
                 length(0), pcRel(false), isExtern(false), value(0),
85
1.19k
                 symbol(0) { }
86
87
  Hex32               offset;
88
  bool                scattered;
89
  RelocationInfoType  type;
90
  uint8_t             length;
91
  bool                pcRel;
92
  bool                isExtern;
93
  Hex32               value;
94
  uint32_t            symbol;
95
};
96
97
/// A typedef so that YAML I/O can treat this vector as a sequence.
98
typedef std::vector<Relocation> Relocations;
99
100
/// A typedef so that YAML I/O can process the raw bytes in a section.
101
typedef std::vector<Hex8> ContentBytes;
102
103
/// A typedef so that YAML I/O can treat indirect symbols as a flow sequence.
104
typedef std::vector<uint32_t> IndirectSymbols;
105
106
/// A typedef so that YAML I/O can encode/decode section attributes.
107
LLVM_YAML_STRONG_TYPEDEF(uint32_t, SectionAttr)
108
109
/// A typedef so that YAML I/O can encode/decode section alignment.
110
LLVM_YAML_STRONG_TYPEDEF(uint16_t, SectionAlignment)
111
112
/// Mach-O has a 32-bit and 64-bit section record.  This normalized form
113
/// can support either kind.
114
struct Section {
115
  Section() : type(llvm::MachO::S_REGULAR),
116
739
              attributes(0), alignment(1), address(0) { }
117
118
  StringRef       segmentName;
119
  StringRef       sectionName;
120
  SectionType     type;
121
  SectionAttr     attributes;
122
  SectionAlignment        alignment;
123
  Hex64           address;
124
  ArrayRef<uint8_t> content;
125
  Relocations     relocations;
126
  IndirectSymbols indirectSymbols;
127
128
#ifndef NDEBUG
129
  raw_ostream& operator<<(raw_ostream &OS) const {
130
    dump(OS);
131
    return OS;
132
  }
133
134
  void dump(raw_ostream &OS = llvm::dbgs()) const;
135
#endif
136
};
137
138
139
/// A typedef so that YAML I/O can encode/decode the scope bits of an nlist.
140
LLVM_YAML_STRONG_TYPEDEF(uint8_t, SymbolScope)
141
142
/// A typedef so that YAML I/O can encode/decode the desc bits of an nlist.
143
LLVM_YAML_STRONG_TYPEDEF(uint16_t, SymbolDesc)
144
145
/// Mach-O has a 32-bit and 64-bit symbol table entry (nlist), and the symbol
146
/// type and scope and mixed in the same n_type field.  This normalized form
147
/// works for any pointer size and separates out the type and scope.
148
struct Symbol {
149
1.23k
  Symbol() : type(llvm::MachO::N_UNDF), scope(0), sect(0), desc(0), value(0) { }
150
151
  StringRef     name;
152
  NListType     type;
153
  SymbolScope   scope;
154
  uint8_t       sect;
155
  SymbolDesc    desc;
156
  Hex64         value;
157
};
158
159
/// Check whether the given section type indicates a zero-filled section.
160
// FIXME: Utility functions of this kind should probably be moved into
161
//        llvm/Support.
162
2.37k
inline bool isZeroFillSection(SectionType T) {
163
2.37k
  return (T == llvm::MachO::S_ZEROFILL ||
164
2.35k
          T == llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
165
2.37k
}
166
167
/// A typedef so that YAML I/O can (de/en)code the protection bits of a segment.
168
LLVM_YAML_STRONG_TYPEDEF(uint32_t, VMProtect)
169
170
/// A typedef to hold verions X.Y.X packed into 32-bit xxxx.yy.zz
171
LLVM_YAML_STRONG_TYPEDEF(uint32_t, PackedVersion)
172
173
/// Segments are only used in normalized final linked images (not in relocatable
174
/// object files). They specify how a range of the file is loaded.
175
struct Segment {
176
  StringRef     name;
177
  Hex64         address;
178
  Hex64         size;
179
  VMProtect     init_access;
180
  VMProtect     max_access;
181
};
182
183
/// Only used in normalized final linked images to specify on which dylibs
184
/// it depends.
185
struct DependentDylib {
186
  StringRef       path;
187
  LoadCommandType kind;
188
  PackedVersion   compatVersion;
189
  PackedVersion   currentVersion;
190
};
191
192
/// A normalized rebasing entry.  Only used in normalized final linked images.
193
struct RebaseLocation {
194
  Hex32         segOffset;
195
  uint8_t       segIndex;
196
  RebaseType    kind;
197
};
198
199
/// A normalized binding entry.  Only used in normalized final linked images.
200
struct BindLocation {
201
  Hex32           segOffset;
202
  uint8_t         segIndex;
203
  BindType        kind;
204
  bool            canBeNull;
205
  int             ordinal;
206
  StringRef       symbolName;
207
  Hex64           addend;
208
};
209
210
/// A typedef so that YAML I/O can encode/decode export flags.
211
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ExportFlags)
212
213
/// A normalized export entry.  Only used in normalized final linked images.
214
struct Export {
215
  StringRef         name;
216
  Hex64             offset;
217
  ExportSymbolKind  kind;
218
  ExportFlags       flags;
219
  Hex32             otherOffset;
220
  StringRef         otherName;
221
};
222
223
/// A normalized data-in-code entry.
224
struct DataInCode {
225
  Hex32           offset;
226
  Hex16           length;
227
  DataRegionType  kind;
228
};
229
230
/// A typedef so that YAML I/O can encode/decode mach_header.flags.
231
LLVM_YAML_STRONG_TYPEDEF(uint32_t, FileFlags)
232
233
///
234
struct NormalizedFile {
235
  MachOLinkingContext::Arch   arch = MachOLinkingContext::arch_unknown;
236
  HeaderFileType              fileType = llvm::MachO::MH_OBJECT;
237
  FileFlags                   flags = 0;
238
  std::vector<Segment>        segments; // Not used in object files.
239
  std::vector<Section>        sections;
240
241
  // Symbols sorted by kind.
242
  std::vector<Symbol>         localSymbols;
243
  std::vector<Symbol>         globalSymbols;
244
  std::vector<Symbol>         undefinedSymbols;
245
  std::vector<Symbol>         stabsSymbols;
246
247
  // Maps to load commands with no LINKEDIT content (final linked images only).
248
  std::vector<DependentDylib> dependentDylibs;
249
  StringRef                   installName;        // dylibs only
250
  PackedVersion               compatVersion = 0;  // dylibs only
251
  PackedVersion               currentVersion = 0; // dylibs only
252
  bool                        hasUUID = false;
253
  bool                        hasMinVersionLoadCommand = false;
254
  bool                        generateDataInCodeLoadCommand = false;
255
  std::vector<StringRef>      rpaths;
256
  Hex64                       entryAddress = 0;
257
  Hex64                       stackSize = 0;
258
  MachOLinkingContext::OS     os = MachOLinkingContext::OS::unknown;
259
  Hex64                       sourceVersion = 0;
260
  PackedVersion               minOSverson = 0;
261
  PackedVersion               sdkVersion = 0;
262
  LoadCommandType             minOSVersionKind = (LoadCommandType)0;
263
264
  // Maps to load commands with LINKEDIT content (final linked images only).
265
  Hex32                       pageSize = 0;
266
  std::vector<RebaseLocation> rebasingInfo;
267
  std::vector<BindLocation>   bindingInfo;
268
  std::vector<BindLocation>   weakBindingInfo;
269
  std::vector<BindLocation>   lazyBindingInfo;
270
  std::vector<Export>         exportInfo;
271
  std::vector<uint8_t>        functionStarts;
272
  std::vector<DataInCode>     dataInCode;
273
274
  // TODO:
275
  // code-signature
276
  // split-seg-info
277
  // function-starts
278
279
  // For any allocations in this struct which need to be owned by this struct.
280
  BumpPtrAllocator            ownedAllocations;
281
};
282
283
/// Tests if a file is a non-fat mach-o object file.
284
bool isThinObjectFile(StringRef path, MachOLinkingContext::Arch &arch);
285
286
/// If the buffer is a fat file with the request arch, then this function
287
/// returns true with 'offset' and 'size' set to location of the arch slice
288
/// within the buffer.  Otherwise returns false;
289
bool sliceFromFatFile(MemoryBufferRef mb, MachOLinkingContext::Arch arch,
290
                      uint32_t &offset, uint32_t &size);
291
292
/// Reads a mach-o file and produces an in-memory normalized view.
293
llvm::Expected<std::unique_ptr<NormalizedFile>>
294
readBinary(std::unique_ptr<MemoryBuffer> &mb,
295
           const MachOLinkingContext::Arch arch);
296
297
/// Takes in-memory normalized view and writes a mach-o object file.
298
llvm::Error writeBinary(const NormalizedFile &file, StringRef path);
299
300
size_t headerAndLoadCommandsSize(const NormalizedFile &file);
301
302
303
/// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
304
llvm::Expected<std::unique_ptr<NormalizedFile>>
305
readYaml(std::unique_ptr<MemoryBuffer> &mb);
306
307
/// Writes a yaml encoded mach-o files given an in-memory normalized view.
308
std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out);
309
310
llvm::Error
311
normalizedObjectToAtoms(MachOFile *file,
312
                        const NormalizedFile &normalizedFile,
313
                        bool copyRefs);
314
315
llvm::Error
316
normalizedDylibToAtoms(MachODylibFile *file,
317
                       const NormalizedFile &normalizedFile,
318
                       bool copyRefs);
319
320
/// Takes in-memory normalized dylib or object and parses it into lld::File
321
llvm::Expected<std::unique_ptr<lld::File>>
322
normalizedToAtoms(const NormalizedFile &normalizedFile, StringRef path,
323
                  bool copyRefs);
324
325
/// Takes atoms and generates a normalized macho-o view.
326
llvm::Expected<std::unique_ptr<NormalizedFile>>
327
normalizedFromAtoms(const lld::File &atomFile, const MachOLinkingContext &ctxt);
328
329
330
} // namespace normalized
331
332
/// Class for interfacing mach-o yaml files into generic yaml parsing
333
class MachOYamlIOTaggedDocumentHandler : public YamlIOTaggedDocumentHandler {
334
public:
335
  MachOYamlIOTaggedDocumentHandler(MachOLinkingContext::Arch arch)
336
223
    : _arch(arch) { }
337
  bool handledDocTag(llvm::yaml::IO &io, const lld::File *&file) const override;
338
private:
339
  const MachOLinkingContext::Arch _arch;
340
};
341
342
} // namespace mach_o
343
} // namespace lld
344
345
#endif // LLD_READER_WRITER_MACHO_NORMALIZE_FILE_H