blob: 845d6bf45ac5a31a16dceb0f517ad8969bda2886 [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
10#include <vector>
11
12#include <assert.h>
13
14#include "llvm/ADT/ArrayRef.h"
15#include "llvm/ADT/OwningPtr.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/Support/ErrorHandling.h"
18#include "llvm/Support/MemoryBuffer.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000019
Michael J. Spencer7aba8952012-01-31 21:47:13 +000020#include "lld/Core/Error.h"
Nick Kledzik55fd6be2012-01-16 22:03:44 +000021#include "lld/Core/File.h"
22#include "lld/Core/Atom.h"
23
24#include "NativeFileFormat.h"
25
26namespace lld {
27
28// forward reference
29class NativeFile;
30
Nick Kledzik55fd6be2012-01-16 22:03:44 +000031//
32// An object of this class is instantied for each NativeDefinedAtomIvarsV1
33// struct in the NCS_DefinedAtomsV1 chunk.
34//
35class NativeDefinedAtomV1 : public DefinedAtom {
36public:
37 NativeDefinedAtomV1(const NativeFile& f,
38 const NativeDefinedAtomIvarsV1* ivarData)
39 : _file(&f), _ivarData(ivarData) { }
40
41 virtual const class File& file() const;
42
43 virtual uint64_t ordinal() const;
44
45 virtual llvm::StringRef name() const;
46
47 virtual bool internalName() const {
48 return attributes().internalName;
49 }
50
51 virtual uint64_t size() const {
52 return _ivarData->contentSize;
53 }
54
55 virtual DefinedAtom::Scope scope() const {
56 return (DefinedAtom::Scope)(attributes().scope);
57 }
58
59 virtual DefinedAtom::Interposable interposable() const {
60 return (DefinedAtom::Interposable)(attributes().interposable);
61 }
62
63 virtual DefinedAtom::Merge merge() const {
64 return (DefinedAtom::Merge)(attributes().merge);
65 }
66
67 virtual DefinedAtom::ContentType contentType() const {
68 return (DefinedAtom::ContentType)(attributes().contentType);
69 }
70
71 virtual DefinedAtom::Alignment alignment() const {
72 return DefinedAtom::Alignment(attributes().align2, attributes().alignModulus);
73 }
74
75 virtual DefinedAtom::SectionChoice sectionChoice() const {
76 return (DefinedAtom::SectionChoice)(attributes().sectionChoice);
77 }
78
79 virtual llvm::StringRef customSectionName() const;
80
81 virtual DefinedAtom::DeadStripKind deadStrip() const {
82 return (DefinedAtom::DeadStripKind)(attributes().deadStrip);
83 }
84
85 virtual DefinedAtom::ContentPermissions permissions() const {
86 return (DefinedAtom::ContentPermissions)(attributes().permissions);
87 }
88
89 virtual bool isThumb() const {
90 return (attributes().thumb != 0);
91 }
92
93 virtual bool isAlias() const {
94 return (attributes().alias != 0);
95 }
96
97 llvm::ArrayRef<uint8_t> rawContent() const;
98
99 virtual Reference::iterator referencesBegin() const {
100 return 0;
101 }
102
103 virtual Reference::iterator referencesEnd() const {
104 return 0;
105 }
106
107private:
108 const NativeAtomAttributesV1& attributes() const;
109
110 const NativeFile* _file;
111 const NativeDefinedAtomIvarsV1* _ivarData;
112};
113
114
115
116
117//
118// lld::File object for native llvm object file
119//
120class NativeFile : public File {
121public:
122
123 /// Instantiates a File object from a native object file. Ownership
124 /// of the MemoryBuffer is transfered to the resulting File object.
125 static llvm::error_code make(llvm::MemoryBuffer* mb, llvm::StringRef path,
126 File*& result) {
127 const uint8_t* const base =
128 reinterpret_cast<const uint8_t*>(mb->getBufferStart());
129 const NativeFileHeader* const header =
130 reinterpret_cast<const NativeFileHeader*>(base);
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000131 const NativeChunk *const chunks =
132 reinterpret_cast<const NativeChunk*>(base + sizeof(NativeFileHeader));
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000133 // make sure magic matches
134 if ( memcmp(header->magic, NATIVE_FILE_HEADER_MAGIC, 16) != 0 )
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000135 return make_error_code(native_reader_error::unknown_file_format);
136
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000137 // make sure mapped file contains all needed data
138 const size_t fileSize = mb->getBufferSize();
139 if ( header->fileSize > fileSize )
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000140 return make_error_code(native_reader_error::file_too_short);
141
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000142 // instantiate NativeFile object and add values to it as found
143 NativeFile* file = new NativeFile(mb, path);
144
145 // process each chunk
146 for(uint32_t i=0; i < header->chunkCount; ++i) {
147 llvm::error_code ec;
Michael J. Spencerb2bd7332012-01-31 21:45:53 +0000148 const NativeChunk* chunk = &chunks[i];
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000149 // sanity check chunk is within file
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000150 if ( chunk->fileOffset > fileSize )
151 return make_error_code(native_reader_error::file_malformed);
152 if ( (chunk->fileOffset + chunk->fileSize) > fileSize)
153 return make_error_code(native_reader_error::file_malformed);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000154 // process chunk, based on signature
155 switch ( chunk->signature ) {
156 case NCS_DefinedAtomsV1:
157 ec = file->processDefinedAtomsV1(base, chunk);
158 break;
159 case NCS_AttributesArrayV1:
160 ec = file->processAttributesV1(base, chunk);
161 break;
162 case NCS_Content:
163 ec = file->processContent(base, chunk);
164 break;
165 case NCS_Strings:
166 ec = file->processStrings(base, chunk);
167 break;
168 default:
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000169 return make_error_code(native_reader_error::unknown_chunk_type);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000170 }
171 if ( ec ) {
172 delete file;
173 return ec;
174 }
175
176 // TO DO: validate enough chunks were used
177
178 result = file;
179 }
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000180
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000181
182 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000183 }
184
185 virtual ~NativeFile() {
186 // The NativeFile owns the MemoryBuffer and must not delete it.
187 delete _buffer;
188 // All other ivar pointers are pointers into the MemoryBuffer, except
189 // the _definedAtoms array which was allocated to contain an array
190 // of Atom objects. The atoms have empty destructors, so it is ok
191 // to just delete the memory.
192 delete _definedAtoms.arrayStart;
193 }
194
195 // visits each atom in the file
196 virtual bool forEachAtom(AtomHandler& handler) const {
197 for(const uint8_t* p=_definedAtoms.arrayStart; p != _definedAtoms.arrayEnd;
198 p += _definedAtoms.elementSize) {
199 const DefinedAtom* atom = reinterpret_cast<const DefinedAtom*>(p);
200 handler.doDefinedAtom(*atom);
201 }
202 return (_definedAtoms.arrayStart != _definedAtoms.arrayEnd);
203 }
204
205 // not used
206 virtual bool justInTimeforEachAtom(llvm::StringRef name,
207 AtomHandler &) const {
208 return false;
209 }
210
211private:
212 friend class NativeDefinedAtomV1;
213
214 // instantiate array of DefinedAtoms from v1 ivar data in file
215 llvm::error_code processDefinedAtomsV1(const uint8_t* base,
216 const NativeChunk* chunk) {
217 const size_t atomSize = sizeof(NativeDefinedAtomV1);
218 size_t atomsArraySize = chunk->elementCount * atomSize;
219 uint8_t* atomsStart = reinterpret_cast<uint8_t*>
220 (operator new(atomsArraySize, std::nothrow));
221 if (atomsStart == NULL )
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000222 return make_error_code(native_reader_error::memory_error);
223 const size_t ivarElementSize = chunk->fileSize
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000224 / chunk->elementCount;
225 if ( ivarElementSize != sizeof(NativeDefinedAtomIvarsV1) )
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000226 return make_error_code(native_reader_error::file_malformed);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000227 uint8_t* atomsEnd = atomsStart + atomsArraySize;
228 const NativeDefinedAtomIvarsV1* ivarData =
229 reinterpret_cast<const NativeDefinedAtomIvarsV1*>
230 (base + chunk->fileOffset);
231 for(uint8_t* s = atomsStart; s != atomsEnd; s += atomSize) {
232 NativeDefinedAtomV1* atomAllocSpace =
233 reinterpret_cast<NativeDefinedAtomV1*>(s);
234 new (atomAllocSpace) NativeDefinedAtomV1(*this, ivarData);
235 ++ivarData;
236 }
237 this->_definedAtoms.arrayStart = atomsStart;
238 this->_definedAtoms.arrayEnd = atomsEnd;
239 this->_definedAtoms.elementSize = atomSize;
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000240 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000241 }
242
243 // set up pointers to attributes array
244 llvm::error_code processAttributesV1(const uint8_t* base, const NativeChunk* chunk) {
245 this->_attributes = base + chunk->fileOffset;
246 this->_attributesMaxOffset = chunk->fileSize;
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000247 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000248 }
249
250 // set up pointers to string pool in file
251 llvm::error_code processStrings(const uint8_t* base,
252 const NativeChunk* chunk) {
253 this->_strings = reinterpret_cast<const char*>(base + chunk->fileOffset);
254 this->_stringsMaxOffset = chunk->fileSize;
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000255 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000256 }
257
258 // set up pointers to content area in file
259 llvm::error_code processContent(const uint8_t* base,
260 const NativeChunk* chunk) {
261 this->_contentStart = base + chunk->fileOffset;
262 this->_contentEnd = base + chunk->fileOffset + chunk->fileSize;
Michael J. Spencer7aba8952012-01-31 21:47:13 +0000263 return make_error_code(native_reader_error::success);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000264 }
265
266 llvm::StringRef string(uint32_t offset) const {
267 assert(offset < _stringsMaxOffset);
268 return llvm::StringRef(&_strings[offset]);
269 }
270
271 const NativeAtomAttributesV1& attribute(uint32_t offset) const {
272 assert(offset < _attributesMaxOffset);
273 return *reinterpret_cast<const NativeAtomAttributesV1*>(_attributes + offset);
274 }
275
276 const uint8_t* content(uint32_t offset, uint32_t size) const {
277 const uint8_t* result = _contentStart + offset;
278 assert((result+size) <= _contentEnd);
279 return result;
280 }
281
282
283 // private constructor, only called by make()
284 NativeFile(llvm::MemoryBuffer* mb, llvm::StringRef path) :
285 lld::File(path), _buffer(mb), _header(NULL),
286 _strings(NULL), _stringsMaxOffset(0),
287 _contentStart(NULL), _contentEnd(NULL)
288 {
289 _header = reinterpret_cast<const NativeFileHeader*>(mb->getBufferStart());
290 }
291
292 struct AtomArray {
293 AtomArray() : arrayStart(NULL), arrayEnd(NULL),
294 elementSize(0) { }
295 const uint8_t* arrayStart;
296 const uint8_t* arrayEnd;
297 uint32_t elementSize;
298 };
299
300 llvm::MemoryBuffer* _buffer;
301 const NativeFileHeader* _header;
302 AtomArray _definedAtoms;
303 const uint8_t* _attributes;
304 uint32_t _attributesMaxOffset;
305 const char* _strings;
306 uint32_t _stringsMaxOffset;
307 const uint8_t* _contentStart;
308 const uint8_t* _contentEnd;
309};
310
311
312
313inline const class File& NativeDefinedAtomV1::file() const {
314 return *_file;
315}
316
317inline uint64_t NativeDefinedAtomV1:: ordinal() const {
318 const uint8_t* p = reinterpret_cast<const uint8_t*>(_ivarData);
319 return p - _file->_definedAtoms.arrayStart;
320}
321
322inline llvm::StringRef NativeDefinedAtomV1::name() const {
323 return _file->string(_ivarData->nameOffset);
324}
325
326inline const NativeAtomAttributesV1& NativeDefinedAtomV1::attributes() const {
327 return _file->attribute(_ivarData->attributesOffset);
328}
329
330inline llvm::ArrayRef<uint8_t> NativeDefinedAtomV1::rawContent() const {
331 if ( this->contentType() == DefinedAtom::typeZeroFill )
332 return llvm::ArrayRef<uint8_t>();
333 const uint8_t* p = _file->content(_ivarData->contentOffset,
334 _ivarData->contentSize);
335 return llvm::ArrayRef<uint8_t>(p, _ivarData->contentSize);
336}
337
338inline llvm::StringRef NativeDefinedAtomV1::customSectionName() const {
339 uint32_t offset = attributes().sectionNameOffset;
340 return _file->string(offset);
341}
342
343
344
345//
346// Instantiate an lld::File from the given native object file buffer
347//
348llvm::error_code parseNativeObjectFile(llvm::MemoryBuffer* mb,
349 llvm::StringRef path, File*& result) {
350 return NativeFile::make(mb, path, result);
351}
352
353
354
355//
356// Instantiate an lld::File from the given native object file path
357//
358llvm::error_code parseNativeObjectFileOrSTDIN(llvm::StringRef path,
359 File*& result) {
360 llvm::OwningPtr<llvm::MemoryBuffer> mb;
361 llvm::error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb);
362 if ( ec )
363 return ec;
364
Michael J. Spencer4e45ebb2012-01-31 21:46:29 +0000365 return parseNativeObjectFile(mb.take(), path, result);
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000366}
367
368
369
370} // namespace lld