blob: 2f92626a860f78c0cfff11d3e64371e72462882e [file] [log] [blame]
Nick Kledzik55fd6be2012-01-16 22:03:44 +00001//===- Core/NativeReader.cpp - reads native object file ------------------===//
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
Michael J. Spencercfd029f2012-03-28 19:04:02 +000010#include "NativeFileFormat.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000011
Michael J. Spencercfd029f2012-03-28 19:04:02 +000012#include "lld/Core/Atom.h"
13#include "lld/Core/Error.h"
14#include "lld/Core/File.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000015
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/OwningPtr.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/Support/ErrorHandling.h"
20#include "llvm/Support/MemoryBuffer.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000021
Michael J. Spencercfd029f2012-03-28 19:04:02 +000022#include <vector>
Nick Kledzik55fd6be2012-01-16 22:03:44 +000023
24namespace lld {
25
26// forward reference
27class NativeFile;
28
Nick Kledzik55fd6be2012-01-16 22:03:44 +000029//
30// An object of this class is instantied for each NativeDefinedAtomIvarsV1
31// struct in the NCS_DefinedAtomsV1 chunk.
32//
33class NativeDefinedAtomV1 : public DefinedAtom {
34public:
35 NativeDefinedAtomV1(const NativeFile& f,
36 const NativeDefinedAtomIvarsV1* ivarData)
37 : _file(&f), _ivarData(ivarData) { }
38
39 virtual const class File& file() const;
40
41 virtual uint64_t ordinal() const;
42
Nick Kledzik55fd6be2012-01-16 22:03:44 +000043
Michael J. Spencere6203a52012-04-03 18:39:40 +000044 virtual StringRef name() const;
Nick Kledzik55fd6be2012-01-16 22:03:44 +000045 virtual uint64_t size() const {
46 return _ivarData->contentSize;
47 }
48
49 virtual DefinedAtom::Scope scope() const {
50 return (DefinedAtom::Scope)(attributes().scope);
51 }
52
53 virtual DefinedAtom::Interposable interposable() const {
54 return (DefinedAtom::Interposable)(attributes().interposable);
55 }
56
57 virtual DefinedAtom::Merge merge() const {
58 return (DefinedAtom::Merge)(attributes().merge);
59 }
60
61 virtual DefinedAtom::ContentType contentType() const {
Nick Kledzik23384e82012-02-07 02:59:54 +000062 const NativeAtomAttributesV1& attr = attributes();
63 return (DefinedAtom::ContentType)(attr.contentType);
Nick Kledzik55fd6be2012-01-16 22:03:44 +000064 }
65
66 virtual DefinedAtom::Alignment alignment() const {
67 return DefinedAtom::Alignment(attributes().align2, attributes().alignModulus);
68 }
69
70 virtual DefinedAtom::SectionChoice sectionChoice() const {
71 return (DefinedAtom::SectionChoice)(attributes().sectionChoice);
72 }
73
Michael J. Spencere6203a52012-04-03 18:39:40 +000074 virtual StringRef customSectionName() const;
Nick Kledzik55fd6be2012-01-16 22:03:44 +000075
76 virtual DefinedAtom::DeadStripKind deadStrip() const {
77 return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
Nick Kledzik6bc04c62012-02-22 21:56:59 +000078 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +000079
80 virtual DefinedAtom::ContentPermissions permissions() const {
81 return (DefinedAtom::ContentPermissions)(attributes().permissions);
82 }
83
84 virtual bool isThumb() const {
Nick Kledzik49d6cc82012-02-15 00:38:09 +000085 return false; //(attributes().thumb != 0);
Nick Kledzik55fd6be2012-01-16 22:03:44 +000086 }
87
88 virtual bool isAlias() const {
89 return (attributes().alias != 0);
90 }
91
Nick Kledzik1a6615d2012-03-08 00:18:30 +000092
Michael J. Spencere6203a52012-04-03 18:39:40 +000093 virtual ArrayRef<uint8_t> rawContent() const;
Nick Kledzik1a6615d2012-03-08 00:18:30 +000094 virtual reference_iterator referencesBegin() const;
95
96 virtual reference_iterator referencesEnd() const;
97
98 virtual const Reference* derefIterator(const void*) const;
99
100 virtual void incrementIterator(const void*& it) const;
101
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000102private:
103 const NativeAtomAttributesV1& attributes() const;
104
105 const NativeFile* _file;
106 const NativeDefinedAtomIvarsV1* _ivarData;
107};
108
109
110
Nick Kledzik23384e82012-02-07 02:59:54 +0000111//
112// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
113// struct in the NCS_UndefinedAtomsV1 chunk.
114//
115class NativeUndefinedAtomV1 : public UndefinedAtom {
116public:
117 NativeUndefinedAtomV1(const NativeFile& f,
118 const NativeUndefinedAtomIvarsV1* ivarData)
119 : _file(&f), _ivarData(ivarData) { }
120
121 virtual const File& file() const;
Michael J. Spencere6203a52012-04-03 18:39:40 +0000122 virtual StringRef name() const;
Nick Kledzik23384e82012-02-07 02:59:54 +0000123
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000124 virtual CanBeNull canBeNull() const {
125 return (CanBeNull)(_ivarData->flags & 0x3);
Nick Kledzik23384e82012-02-07 02:59:54 +0000126 }
127
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000128
Nick Kledzik23384e82012-02-07 02:59:54 +0000129private:
130 const NativeFile* _file;
131 const NativeUndefinedAtomIvarsV1* _ivarData;
132};
133
134
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000135//
136// An object of this class is instantied for each NativeUndefinedAtomIvarsV1
137// struct in the NCS_SharedLibraryAtomsV1 chunk.
138//
139class NativeSharedLibraryAtomV1 : public SharedLibraryAtom {
140public:
141 NativeSharedLibraryAtomV1(const NativeFile& f,
142 const NativeSharedLibraryAtomIvarsV1* ivarData)
143 : _file(&f), _ivarData(ivarData) { }
144
145 virtual const File& file() const;
Michael J. Spencere6203a52012-04-03 18:39:40 +0000146 virtual StringRef name() const;
147 virtual StringRef loadName() const;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000148
149 virtual bool canBeNullAtRuntime() const {
150 return (_ivarData->flags & 0x1);
151 }
152
153private:
154 const NativeFile* _file;
155 const NativeSharedLibraryAtomIvarsV1* _ivarData;
156};
157
158
159//
160// An object of this class is instantied for each NativeAbsoluteAtomIvarsV1
161// struct in the NCS_AbsoluteAtomsV1 chunk.
162//
163class NativeAbsoluteAtomV1 : public AbsoluteAtom {
164public:
165 NativeAbsoluteAtomV1(const NativeFile& f,
166 const NativeAbsoluteAtomIvarsV1* ivarData)
167 : _file(&f), _ivarData(ivarData) { }
168
169 virtual const File& file() const;
Michael J. Spencere6203a52012-04-03 18:39:40 +0000170 virtual StringRef name() const;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000171
172 virtual uint64_t value() const {
173 return _ivarData->value;
174 }
175
176private:
177 const NativeFile* _file;
178 const NativeAbsoluteAtomIvarsV1* _ivarData;
179};
180
181
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000182
183//
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000184// An object of this class is instantied for each NativeReferenceIvarsV1
185// struct in the NCS_ReferencesArrayV1 chunk.
186//
187class NativeReferenceV1 : public Reference {
188public:
189 NativeReferenceV1(const NativeFile& f,
190 const NativeReferenceIvarsV1* ivarData)
191 : _file(&f), _ivarData(ivarData) { }
192
193 virtual uint64_t offsetInAtom() const {
194 return _ivarData->offsetInAtom;
195 }
196
197 virtual Kind kind() const {
198 return _ivarData->kind;
199 }
200
Nick Kledzikf4e2c732012-03-15 23:36:24 +0000201 virtual void setKind(Kind);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000202 virtual const Atom* target() const;
203 virtual Addend addend() const;
204 virtual void setTarget(const Atom* newAtom);
Nick Kledzikf4e2c732012-03-15 23:36:24 +0000205
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000206private:
Nick Kledzikf4e2c732012-03-15 23:36:24 +0000207 // Used in rare cases when Reference is modified,
208 // since ivar data is mapped read-only.
209 void cloneIvarData() {
210 // TODO: do nothing on second call
211 NativeReferenceIvarsV1* niv = reinterpret_cast<NativeReferenceIvarsV1*>
212 (operator new(sizeof(NativeReferenceIvarsV1),
213 std::nothrow));
214 memcpy(niv, _ivarData, sizeof(NativeReferenceIvarsV1));
215 }
216
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000217 const NativeFile* _file;
218 const NativeReferenceIvarsV1* _ivarData;
219};
220
221
222
223//
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000224// lld::File object for native llvm object file
225//
226class NativeFile : public File {
227public:
228
229 /// Instantiates a File object from a native object file. Ownership
230 /// of the MemoryBuffer is transfered to the resulting File object.
Michael J. Spencere6203a52012-04-03 18:39:40 +0000231 static error_code make(std::unique_ptr<llvm::MemoryBuffer> mb,
232 StringRef path,
233 std::unique_ptr<File> &result) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000234 const uint8_t* const base =
235 reinterpret_cast<const uint8_t*>(mb->getBufferStart());
236 const NativeFileHeader* const header =
237 reinterpret_cast<const NativeFileHeader*>(base);
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000238 const NativeChunk *const chunks =
239 reinterpret_cast<const NativeChunk*>(base + sizeof(NativeFileHeader));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000240 // make sure magic matches
241 if ( memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC, 16) != 0 )
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000242 return make_error_code(native_reader_error::unknown_file_format);
243
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000244 // make sure mapped file contains all needed data
245 const size_t fileSize = mb->getBufferSize();
246 if ( header->fileSize > fileSize )
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000247 return make_error_code(native_reader_error::file_too_short);
248
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000249 // instantiate NativeFile object and add values to it as found
Michael J. Spencerd58cf032012-03-29 00:49:50 +0000250 std::unique_ptr<NativeFile> file(new NativeFile(std::move(mb), path));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000251
252 // process each chunk
253 for(uint32_t i=0; i < header->chunkCount; ++i) {
Michael J. Spencere6203a52012-04-03 18:39:40 +0000254 error_code ec;
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000255 const NativeChunk* chunk = &chunks[i];
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000256 // sanity check chunk is within file
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000257 if ( chunk->fileOffset > fileSize )
258 return make_error_code(native_reader_error::file_malformed);
259 if ( (chunk->fileOffset + chunk->fileSize) > fileSize)
260 return make_error_code(native_reader_error::file_malformed);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000261 // process chunk, based on signature
262 switch ( chunk->signature ) {
263 case NCS_DefinedAtomsV1:
264 ec = file->processDefinedAtomsV1(base, chunk);
265 break;
266 case NCS_AttributesArrayV1:
267 ec = file->processAttributesV1(base, chunk);
268 break;
Nick Kledzik23384e82012-02-07 02:59:54 +0000269 case NCS_UndefinedAtomsV1:
270 ec = file->processUndefinedAtomsV1(base, chunk);
271 break;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000272 case NCS_SharedLibraryAtomsV1:
273 ec = file->processSharedLibraryAtomsV1(base, chunk);
274 break;
275 case NCS_AbsoluteAtomsV1:
276 ec = file->processAbsoluteAtomsV1(base, chunk);
277 break;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000278 case NCS_ReferencesArrayV1:
279 ec = file->processReferencesV1(base, chunk);
280 break;
281 case NCS_TargetsTable:
282 ec = file->processTargetsTable(base, chunk);
283 break;
284 case NCS_AddendsTable:
285 ec = file->processAddendsTable(base, chunk);
286 break;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000287 case NCS_Content:
288 ec = file->processContent(base, chunk);
289 break;
290 case NCS_Strings:
291 ec = file->processStrings(base, chunk);
292 break;
293 default:
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000294 return make_error_code(native_reader_error::unknown_chunk_type);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000295 }
296 if ( ec ) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000297 return ec;
298 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000299 // TO DO: validate enough chunks were used
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000300 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000301
Michael J. Spencerd58cf032012-03-29 00:49:50 +0000302 result.reset(file.release());
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000303 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000304 }
305
306 virtual ~NativeFile() {
Nick Kledzik23384e82012-02-07 02:59:54 +0000307 // _buffer is automatically deleted because of OwningPtr<>
308
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000309 // All other ivar pointers are pointers into the MemoryBuffer, except
310 // the _definedAtoms array which was allocated to contain an array
311 // of Atom objects. The atoms have empty destructors, so it is ok
312 // to just delete the memory.
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000313 delete _definedAtoms._arrayStart;
314 delete _undefinedAtoms._arrayStart;
315 delete _sharedLibraryAtoms._arrayStart;
316 delete _absoluteAtoms._arrayStart;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000317 delete _references.arrayStart;
318 delete _targetsTable;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000319 }
320
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000321 virtual const atom_collection<DefinedAtom>& defined() const {
322 return _definedAtoms;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000323 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000324 virtual const atom_collection<UndefinedAtom>& undefined() const {
325 return _undefinedAtoms;
326 }
327 virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
328 return _sharedLibraryAtoms;
329 }
330 virtual const atom_collection<AbsoluteAtom>& absolute() const {
331 return _absoluteAtoms;
332 }
333
334 virtual void addAtom(const Atom&) {
335 assert(0 && "cannot add atoms to native .o files");
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000336 }
337
338private:
339 friend class NativeDefinedAtomV1;
Nick Kledzik23384e82012-02-07 02:59:54 +0000340 friend class NativeUndefinedAtomV1;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000341 friend class NativeSharedLibraryAtomV1;
342 friend class NativeAbsoluteAtomV1;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000343 friend class NativeReferenceV1;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000344
345 // instantiate array of DefinedAtoms from v1 ivar data in file
Michael J. Spencere6203a52012-04-03 18:39:40 +0000346 error_code processDefinedAtomsV1(const uint8_t *base,
347 const NativeChunk *chunk) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000348 const size_t atomSize = sizeof(NativeDefinedAtomV1);
349 size_t atomsArraySize = chunk->elementCount * atomSize;
350 uint8_t* atomsStart = reinterpret_cast<uint8_t*>
351 (operator new(atomsArraySize, std::nothrow));
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000352 if (atomsStart == nullptr)
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000353 return make_error_code(native_reader_error::memory_error);
354 const size_t ivarElementSize = chunk->fileSize
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000355 / chunk->elementCount;
356 if ( ivarElementSize != sizeof(NativeDefinedAtomIvarsV1) )
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000357 return make_error_code(native_reader_error::file_malformed);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000358 uint8_t* atomsEnd = atomsStart + atomsArraySize;
359 const NativeDefinedAtomIvarsV1* ivarData =
360 reinterpret_cast<const NativeDefinedAtomIvarsV1*>
361 (base + chunk->fileOffset);
362 for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
363 NativeDefinedAtomV1* atomAllocSpace =
364 reinterpret_cast<NativeDefinedAtomV1*>(s);
365 new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData);
366 ++ivarData;
367 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000368 this->_definedAtoms._arrayStart = atomsStart;
369 this->_definedAtoms._arrayEnd = atomsEnd;
370 this->_definedAtoms._elementSize = atomSize;
371 this->_definedAtoms._elementCount = chunk->elementCount;
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000372 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000373 }
374
375 // set up pointers to attributes array
Michael J. Spencere6203a52012-04-03 18:39:40 +0000376 error_code processAttributesV1(const uint8_t *base,
377 const NativeChunk *chunk) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000378 this->_attributes = base + chunk->fileOffset;
379 this->_attributesMaxOffset = chunk->fileSize;
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000380 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000381 }
382
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000383 // instantiate array of UndefinedAtoms from v1 ivar data in file
Michael J. Spencere6203a52012-04-03 18:39:40 +0000384 error_code processUndefinedAtomsV1(const uint8_t *base,
385 const NativeChunk *chunk) {
Nick Kledzik23384e82012-02-07 02:59:54 +0000386 const size_t atomSize = sizeof(NativeUndefinedAtomV1);
387 size_t atomsArraySize = chunk->elementCount * atomSize;
388 uint8_t* atomsStart = reinterpret_cast<uint8_t*>
389 (operator new(atomsArraySize, std::nothrow));
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000390 if (atomsStart == nullptr)
Nick Kledzik23384e82012-02-07 02:59:54 +0000391 return make_error_code(native_reader_error::memory_error);
392 const size_t ivarElementSize = chunk->fileSize
393 / chunk->elementCount;
394 if ( ivarElementSize != sizeof(NativeUndefinedAtomIvarsV1) )
395 return make_error_code(native_reader_error::file_malformed);
396 uint8_t* atomsEnd = atomsStart + atomsArraySize;
397 const NativeUndefinedAtomIvarsV1* ivarData =
398 reinterpret_cast<const NativeUndefinedAtomIvarsV1*>
399 (base + chunk->fileOffset);
400 for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
401 NativeUndefinedAtomV1* atomAllocSpace =
402 reinterpret_cast<NativeUndefinedAtomV1*>(s);
403 new (atomAllocSpace) NativeUndefinedAtomV1(*this, ivarData);
404 ++ivarData;
405 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000406 this->_undefinedAtoms._arrayStart = atomsStart;
407 this->_undefinedAtoms._arrayEnd = atomsEnd;
408 this->_undefinedAtoms._elementSize = atomSize;
409 this->_undefinedAtoms._elementCount = chunk->elementCount;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000410 return make_error_code(native_reader_error::success);
411 }
412
413
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000414 // instantiate array of ShareLibraryAtoms from v1 ivar data in file
Michael J. Spencere6203a52012-04-03 18:39:40 +0000415 error_code processSharedLibraryAtomsV1(const uint8_t *base,
416 const NativeChunk *chunk) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000417 const size_t atomSize = sizeof(NativeSharedLibraryAtomV1);
418 size_t atomsArraySize = chunk->elementCount * atomSize;
419 uint8_t* atomsStart = reinterpret_cast<uint8_t*>
420 (operator new(atomsArraySize, std::nothrow));
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000421 if (atomsStart == nullptr)
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000422 return make_error_code(native_reader_error::memory_error);
423 const size_t ivarElementSize = chunk->fileSize
424 / chunk->elementCount;
425 if ( ivarElementSize != sizeof(NativeSharedLibraryAtomIvarsV1) )
426 return make_error_code(native_reader_error::file_malformed);
427 uint8_t* atomsEnd = atomsStart + atomsArraySize;
428 const NativeSharedLibraryAtomIvarsV1* ivarData =
429 reinterpret_cast<const NativeSharedLibraryAtomIvarsV1*>
430 (base + chunk->fileOffset);
431 for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
432 NativeSharedLibraryAtomV1* atomAllocSpace =
433 reinterpret_cast<NativeSharedLibraryAtomV1*>(s);
434 new (atomAllocSpace) NativeSharedLibraryAtomV1(*this, ivarData);
435 ++ivarData;
436 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000437 this->_sharedLibraryAtoms._arrayStart = atomsStart;
438 this->_sharedLibraryAtoms._arrayEnd = atomsEnd;
439 this->_sharedLibraryAtoms._elementSize = atomSize;
440 this->_sharedLibraryAtoms._elementCount = chunk->elementCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000441 return make_error_code(native_reader_error::success);
442 }
443
444
445 // instantiate array of AbsoluteAtoms from v1 ivar data in file
Michael J. Spencere6203a52012-04-03 18:39:40 +0000446 error_code processAbsoluteAtomsV1(const uint8_t *base,
447 const NativeChunk *chunk) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000448 const size_t atomSize = sizeof(NativeAbsoluteAtomV1);
449 size_t atomsArraySize = chunk->elementCount * atomSize;
450 uint8_t* atomsStart = reinterpret_cast<uint8_t*>
451 (operator new(atomsArraySize, std::nothrow));
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000452 if (atomsStart == nullptr)
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000453 return make_error_code(native_reader_error::memory_error);
454 const size_t ivarElementSize = chunk->fileSize
455 / chunk->elementCount;
456 if ( ivarElementSize != sizeof(NativeAbsoluteAtomIvarsV1) )
457 return make_error_code(native_reader_error::file_malformed);
458 uint8_t* atomsEnd = atomsStart + atomsArraySize;
459 const NativeAbsoluteAtomIvarsV1* ivarData =
460 reinterpret_cast<const NativeAbsoluteAtomIvarsV1*>
461 (base + chunk->fileOffset);
462 for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
463 NativeAbsoluteAtomV1* atomAllocSpace =
464 reinterpret_cast<NativeAbsoluteAtomV1*>(s);
465 new (atomAllocSpace) NativeAbsoluteAtomV1(*this, ivarData);
466 ++ivarData;
467 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000468 this->_absoluteAtoms._arrayStart = atomsStart;
469 this->_absoluteAtoms._arrayEnd = atomsEnd;
470 this->_absoluteAtoms._elementSize = atomSize;
471 this->_absoluteAtoms._elementCount = chunk->elementCount;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000472 return make_error_code(native_reader_error::success);
473 }
474
475
476
477
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000478 // instantiate array of Referemces from v1 ivar data in file
Michael J. Spencere6203a52012-04-03 18:39:40 +0000479 error_code processReferencesV1(const uint8_t *base,
480 const NativeChunk *chunk) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000481 if ( chunk->elementCount == 0 )
482 return make_error_code(native_reader_error::success);
483 const size_t refSize = sizeof(NativeReferenceV1);
484 size_t refsArraySize = chunk->elementCount * refSize;
485 uint8_t* refsStart = reinterpret_cast<uint8_t*>
486 (operator new(refsArraySize, std::nothrow));
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000487 if (refsStart == nullptr)
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000488 return make_error_code(native_reader_error::memory_error);
489 const size_t ivarElementSize = chunk->fileSize
490 / chunk->elementCount;
491 if ( ivarElementSize != sizeof(NativeReferenceIvarsV1) )
492 return make_error_code(native_reader_error::file_malformed);
493 uint8_t* refsEnd = refsStart + refsArraySize;
494 const NativeReferenceIvarsV1* ivarData =
495 reinterpret_cast<const NativeReferenceIvarsV1*>
496 (base + chunk->fileOffset);
497 for(uint8_t* s = refsStart; s != refsEnd; s += refSize) {
498 NativeReferenceV1* atomAllocSpace =
499 reinterpret_cast<NativeReferenceV1*>(s);
500 new (atomAllocSpace) NativeReferenceV1(*this, ivarData);
501 ++ivarData;
502 }
503 this->_references.arrayStart = refsStart;
504 this->_references.arrayEnd = refsEnd;
505 this->_references.elementSize = refSize;
506 this->_references.elementCount = chunk->elementCount;
507 return make_error_code(native_reader_error::success);
508 }
509
510 // set up pointers to target table
Michael J. Spencere6203a52012-04-03 18:39:40 +0000511 error_code processTargetsTable(const uint8_t *base,
512 const NativeChunk *chunk) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000513 const uint32_t* targetIndexes = reinterpret_cast<const uint32_t*>
514 (base + chunk->fileOffset);
515 this->_targetsTableCount = chunk->elementCount;
516 this->_targetsTable = new const Atom*[chunk->elementCount];
517 for (uint32_t i=0; i < chunk->elementCount; ++i) {
518 const uint32_t index = targetIndexes[i];
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000519 if ( index < _definedAtoms._elementCount ) {
520 const uint8_t* p = _definedAtoms._arrayStart
521 + index * _definedAtoms._elementSize;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000522 this->_targetsTable[i] = reinterpret_cast<const DefinedAtom*>(p);
523 continue;
524 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000525 const uint32_t undefIndex = index - _definedAtoms._elementCount;
526 if ( undefIndex < _undefinedAtoms._elementCount ) {
527 const uint8_t* p = _undefinedAtoms._arrayStart
528 + undefIndex * _undefinedAtoms._elementSize;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000529 this->_targetsTable[i] = reinterpret_cast<const UndefinedAtom*>(p);
530 continue;
531 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000532 const uint32_t slIndex = index - _definedAtoms._elementCount
533 - _undefinedAtoms._elementCount;
534 if ( slIndex < _sharedLibraryAtoms._elementCount ) {
535 const uint8_t* p = _sharedLibraryAtoms._arrayStart
536 + slIndex * _sharedLibraryAtoms._elementSize;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000537 this->_targetsTable[i] = reinterpret_cast<const SharedLibraryAtom*>(p);
538 continue;
539 }
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000540 const uint32_t abIndex = index - _definedAtoms._elementCount
541 - _undefinedAtoms._elementCount
542 - _sharedLibraryAtoms._elementCount;
543 if ( abIndex < _absoluteAtoms._elementCount ) {
544 const uint8_t* p = _absoluteAtoms._arrayStart
545 + slIndex * _absoluteAtoms._elementSize;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000546 this->_targetsTable[i] = reinterpret_cast<const AbsoluteAtom*>(p);
547 continue;
548 }
549 return make_error_code(native_reader_error::file_malformed);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000550 }
551 return make_error_code(native_reader_error::success);
552 }
553
554
555 // set up pointers to addend pool in file
Michael J. Spencere6203a52012-04-03 18:39:40 +0000556 error_code processAddendsTable(const uint8_t *base,
557 const NativeChunk *chunk) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000558 this->_addends = reinterpret_cast<const Reference::Addend*>
559 (base + chunk->fileOffset);
560 this->_addendsMaxIndex = chunk->elementCount;
Nick Kledzik23384e82012-02-07 02:59:54 +0000561 return make_error_code(native_reader_error::success);
562 }
563
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000564 // set up pointers to string pool in file
Michael J. Spencere6203a52012-04-03 18:39:40 +0000565 error_code processStrings(const uint8_t *base,
566 const NativeChunk *chunk) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000567 this->_strings = reinterpret_cast<const char*>(base + chunk->fileOffset);
568 this->_stringsMaxOffset = chunk->fileSize;
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000569 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000570 }
571
572 // set up pointers to content area in file
Michael J. Spencere6203a52012-04-03 18:39:40 +0000573 error_code processContent(const uint8_t *base,
574 const NativeChunk *chunk) {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000575 this->_contentStart = base + chunk->fileOffset;
576 this->_contentEnd = base + chunk->fileOffset + chunk->fileSize;
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000577 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000578 }
579
Michael J. Spencere6203a52012-04-03 18:39:40 +0000580 StringRef string(uint32_t offset) const {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000581 assert(offset < _stringsMaxOffset);
Michael J. Spencere6203a52012-04-03 18:39:40 +0000582 return StringRef(&_strings[offset]);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000583 }
584
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000585 Reference::Addend addend(uint32_t index) const {
586 if ( index == 0 )
587 return 0; // addend index zero is used to mean "no addend"
588 assert(index <= _addendsMaxIndex);
589 return _addends[index-1]; // one-based indexing
590 }
591
592 const NativeAtomAttributesV1& attribute(uint32_t off) const {
593 assert(off < _attributesMaxOffset);
594 return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + off);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000595 }
596
597 const uint8_t* content(uint32_t offset, uint32_t size) const {
598 const uint8_t* result = _contentStart + offset;
599 assert((result+size) <= _contentEnd);
600 return result;
601 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000602
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000603 const Reference* referenceByIndex(uintptr_t index) const {
604 assert(index < _references.elementCount);
605 const uint8_t* p = _references.arrayStart + index * _references.elementSize;
606 return reinterpret_cast<const NativeReferenceV1*>(p);
607 }
608
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000609 const Atom* target(uint32_t index) const {
610 assert(index < _targetsTableCount);
611 return _targetsTable[index];
612 }
613
614 void setTarget(uint32_t index, const Atom* newAtom) const {
615 assert(index > _targetsTableCount);
616 _targetsTable[index] = newAtom;
617 }
618
619
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000620 // private constructor, only called by make()
Michael J. Spencere6203a52012-04-03 18:39:40 +0000621 NativeFile(std::unique_ptr<llvm::MemoryBuffer> mb, StringRef path) :
622 File(path),
Michael J. Spencerd58cf032012-03-29 00:49:50 +0000623 _buffer(std::move(mb)), // NativeFile now takes ownership of buffer
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000624 _header(nullptr),
625 _targetsTable(nullptr),
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000626 _targetsTableCount(0),
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000627 _strings(nullptr),
Nick Kledzik23384e82012-02-07 02:59:54 +0000628 _stringsMaxOffset(0),
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000629 _addends(nullptr),
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000630 _addendsMaxIndex(0),
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000631 _contentStart(nullptr),
632 _contentEnd(nullptr)
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000633 {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000634 _header = reinterpret_cast<const NativeFileHeader*>
635 (_buffer->getBufferStart());
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000636 }
637
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000638 template <typename T>
639 class AtomArray : public File::atom_collection<T> {
640 public:
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000641 AtomArray() : _arrayStart(nullptr), _arrayEnd(nullptr),
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000642 _elementSize(0), _elementCount(0) { }
643
644 virtual atom_iterator<T> begin() const {
645 return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayStart));
646 }
647 virtual atom_iterator<T> end() const{
648 return atom_iterator<T>(*this, reinterpret_cast<const void*>(_arrayEnd));
649 }
650 virtual const T* deref(const void* it) const {
651 return reinterpret_cast<const T*>(it);
652 }
653 virtual void next(const void*& it) const {
654 const uint8_t* p = reinterpret_cast<const uint8_t*>(it);
655 p += _elementSize;
656 it = reinterpret_cast<const void*>(p);
657 }
658 const uint8_t* _arrayStart;
659 const uint8_t* _arrayEnd;
660 uint32_t _elementSize;
661 uint32_t _elementCount;
662 };
663
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000664 struct IvarArray {
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000665 IvarArray() :
Michael J. Spencerc9d25062012-03-29 19:39:14 +0000666 arrayStart(nullptr),
667 arrayEnd(nullptr),
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000668 elementSize(0),
669 elementCount(0) { }
670
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000671 const uint8_t* arrayStart;
672 const uint8_t* arrayEnd;
673 uint32_t elementSize;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000674 uint32_t elementCount;
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000675 };
676
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000677
Michael J. Spencerd58cf032012-03-29 00:49:50 +0000678 std::unique_ptr<llvm::MemoryBuffer> _buffer;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000679 const NativeFileHeader* _header;
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000680 AtomArray<DefinedAtom> _definedAtoms;
681 AtomArray<UndefinedAtom> _undefinedAtoms;
682 AtomArray<SharedLibraryAtom> _sharedLibraryAtoms;
683 AtomArray<AbsoluteAtom> _absoluteAtoms;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000684 const uint8_t* _attributes;
685 uint32_t _attributesMaxOffset;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000686 IvarArray _references;
687 const Atom** _targetsTable;
688 uint32_t _targetsTableCount;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000689 const char* _strings;
690 uint32_t _stringsMaxOffset;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000691 const Reference::Addend* _addends;
692 uint32_t _addendsMaxIndex;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000693 const uint8_t* _contentStart;
694 const uint8_t* _contentEnd;
695};
696
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000697
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000698inline const class File& NativeDefinedAtomV1::file() const {
699 return *_file;
700}
701
702inline uint64_t NativeDefinedAtomV1:: ordinal() const {
703 const uint8_t* p = reinterpret_cast<const uint8_t*>(_ivarData);
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000704 return p - _file->_definedAtoms._arrayStart;
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000705}
706
Michael J. Spencere6203a52012-04-03 18:39:40 +0000707inline StringRef NativeDefinedAtomV1::name() const {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000708 return _file->string(_ivarData->nameOffset);
709}
710
711inline const NativeAtomAttributesV1& NativeDefinedAtomV1::attributes() const {
712 return _file->attribute(_ivarData->attributesOffset);
713}
714
Michael J. Spencere6203a52012-04-03 18:39:40 +0000715inline ArrayRef<uint8_t> NativeDefinedAtomV1::rawContent() const {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000716 if ( this->contentType() == DefinedAtom::typeZeroFill )
Michael J. Spencere6203a52012-04-03 18:39:40 +0000717 return ArrayRef<uint8_t>();
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000718 const uint8_t* p = _file->content(_ivarData->contentOffset,
719 _ivarData->contentSize);
Michael J. Spencere6203a52012-04-03 18:39:40 +0000720 return ArrayRef<uint8_t>(p, _ivarData->contentSize);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000721}
722
Michael J. Spencere6203a52012-04-03 18:39:40 +0000723inline StringRef NativeDefinedAtomV1::customSectionName() const {
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000724 uint32_t offset = attributes().sectionNameOffset;
725 return _file->string(offset);
726}
727
Nick Kledzik1a6615d2012-03-08 00:18:30 +0000728DefinedAtom::reference_iterator NativeDefinedAtomV1::referencesBegin() const {
729 uintptr_t index = _ivarData->referencesStartIndex;
730 const void* it = reinterpret_cast<const void*>(index);
731 return reference_iterator(*this, it);
732}
733
734DefinedAtom::reference_iterator NativeDefinedAtomV1::referencesEnd() const {
735 uintptr_t index = _ivarData->referencesStartIndex+_ivarData->referencesCount;
736 const void* it = reinterpret_cast<const void*>(index);
737 return reference_iterator(*this, it);
738}
739
740const Reference* NativeDefinedAtomV1::derefIterator(const void* it) const {
741 uintptr_t index = reinterpret_cast<uintptr_t>(it);
742 return _file->referenceByIndex(index);
743}
744
745void NativeDefinedAtomV1::incrementIterator(const void*& it) const {
746 uintptr_t index = reinterpret_cast<uintptr_t>(it);
747 ++index;
748 it = reinterpret_cast<const void*>(index);
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000749}
Nick Kledzik23384e82012-02-07 02:59:54 +0000750
751inline const class File& NativeUndefinedAtomV1::file() const {
752 return *_file;
753}
754
Michael J. Spencere6203a52012-04-03 18:39:40 +0000755inline StringRef NativeUndefinedAtomV1::name() const {
Nick Kledzik23384e82012-02-07 02:59:54 +0000756 return _file->string(_ivarData->nameOffset);
757}
758
759
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000760
761
762inline const class File& NativeSharedLibraryAtomV1::file() const {
763 return *_file;
764}
765
Michael J. Spencere6203a52012-04-03 18:39:40 +0000766inline StringRef NativeSharedLibraryAtomV1::name() const {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000767 return _file->string(_ivarData->nameOffset);
768}
769
Michael J. Spencere6203a52012-04-03 18:39:40 +0000770inline StringRef NativeSharedLibraryAtomV1::loadName() const {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000771 return _file->string(_ivarData->loadNameOffset);
772}
773
774
775
776inline const class File& NativeAbsoluteAtomV1::file() const {
777 return *_file;
778}
779
Michael J. Spencere6203a52012-04-03 18:39:40 +0000780inline StringRef NativeAbsoluteAtomV1::name() const {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000781 return _file->string(_ivarData->nameOffset);
782}
783
784
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000785inline const Atom* NativeReferenceV1::target() const {
786 return _file->target(_ivarData->targetIndex);
787}
788
789inline Reference::Addend NativeReferenceV1::addend() const {
790 return _file->addend(_ivarData->addendIndex);
791}
792
Nick Kledzikf4e2c732012-03-15 23:36:24 +0000793inline void NativeReferenceV1::setKind(Kind k) {
794 this->cloneIvarData();
795 const_cast<NativeReferenceIvarsV1*>(_ivarData)->kind = k;
796}
797
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000798inline void NativeReferenceV1::setTarget(const Atom* newAtom) {
799 return _file->setTarget(_ivarData->targetIndex, newAtom);
800}
Nick Kledzik23384e82012-02-07 02:59:54 +0000801
802
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000803//
804// Instantiate an lld::File from the given native object file buffer
805//
Michael J. Spencere6203a52012-04-03 18:39:40 +0000806error_code parseNativeObjectFile(std::unique_ptr<llvm::MemoryBuffer> mb,
807 StringRef path,
808 std::unique_ptr<File> &result) {
Michael J. Spencerd58cf032012-03-29 00:49:50 +0000809 return NativeFile::make(std::move(mb), path, result);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000810}
811
812
813
814//
815// Instantiate an lld::File from the given native object file path
816//
Michael J. Spencere6203a52012-04-03 18:39:40 +0000817error_code parseNativeObjectFileOrSTDIN(StringRef path,
818 std::unique_ptr<File>& result) {
819 OwningPtr<llvm::MemoryBuffer> mb;
820 error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb);
821 if ( ec )
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000822 return ec;
823
Michael J. Spencerd58cf032012-03-29 00:49:50 +0000824 return parseNativeObjectFile( std::unique_ptr<llvm::MemoryBuffer>(mb.take())
825 , path
826 , result);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000827}
828
829
830
831} // namespace lld