blob: cc1c12ea0ceca7fcc00dfd7e7324d09ebdfa4062 [file] [log] [blame]
Nick Kledzik6b079f52013-01-05 02:22:35 +00001//===- lib/ReaderWriter/YAML/ReaderWriterYAML.cpp -------------------------===//
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#include "lld/Core/ArchiveLibraryFile.h"
12#include "lld/Core/DefinedAtom.h"
13#include "lld/Core/Error.h"
14#include "lld/Core/File.h"
15#include "lld/Core/LLVM.h"
16#include "lld/Core/Reference.h"
17#include "lld/ReaderWriter/ReaderYAML.h"
18#include "lld/ReaderWriter/WriterYAML.h"
19
20#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/OwningPtr.h"
22#include "llvm/ADT/StringMap.h"
23#include "llvm/ADT/Twine.h"
24#include "llvm/Support/Debug.h"
25#include "llvm/Support/ErrorHandling.h"
26#include "llvm/Support/Format.h"
27#include "llvm/Support/MemoryBuffer.h"
28#include "llvm/Support/raw_ostream.h"
29#include "llvm/Support/system_error.h"
30#include "llvm/Support/YAMLTraits.h"
31
32#include <string>
33
34using llvm::yaml::MappingTraits;
35using llvm::yaml::ScalarEnumerationTraits;
36using llvm::yaml::ScalarTraits;
37using llvm::yaml::IO;
38using llvm::yaml::SequenceTraits;
39using llvm::yaml::DocumentListTraits;
40
41
42/// The conversion of Atoms to and from YAML uses LLVM's YAML I/O. This
43/// file just defines template specializations on the lld types which control
44/// how the mapping is done to and from YAML.
45
46
47namespace {
48/// Most of the traits are context-free and always do the same transformation.
49/// But, there are some traits that need some contextual information to properly
50/// do their transform. This struct is available via io.getContext() and
51/// supplies contextual information.
52class ContextInfo {
53public:
54 ContextInfo(const lld::ReaderOptionsYAML &ro)
55 : _currentFile(nullptr), _readerOptions(&ro), _writerOptions(nullptr) { }
56 ContextInfo(const lld::WriterOptionsYAML &wo)
57 : _currentFile(nullptr), _readerOptions(nullptr), _writerOptions(&wo) { }
58
59 lld::File *_currentFile;
60 const lld::ReaderOptionsYAML *_readerOptions;
61 const lld::WriterOptionsYAML *_writerOptions;
62};
63
64
65/// Used when writing yaml files.
66/// In most cases, atoms names are unambiguous, so references can just
67/// use the atom name as the target (e.g. target: foo). But in a few
68/// cases that does not work, so ref-names are added. These are labels
69/// used only in yaml. The labels do not exist in the Atom model.
70///
71/// One need for ref-names are when atoms have no user supplied name
72/// (e.g. c-string literal). Another case is when two object files with
73/// identically named static functions are merged (ld -r) into one object file.
74/// In that case referencing the function by name is ambiguous, so a unique
75/// ref-name is added.
76class RefNameBuilder {
77public:
78 RefNameBuilder(const lld::File &file)
79 : _collisionCount(0), _unnamedCounter(0) {
80 if (&file == nullptr)
81 return;
82 // visit all atoms
83 for (const lld::DefinedAtom *atom : file.defined()) {
84 // Build map of atoms names to detect duplicates
85 if (!atom->name().empty())
86 buildDuplicateNameMap(*atom);
87
88 // Find references to unnamed atoms and create ref-names for them.
89 for (const lld::Reference *ref : *atom) {
90 // create refname for any unnamed reference target
91 const lld::Atom *target = ref->target();
92 if ((target != nullptr) && target->name().empty()) {
93 std::string storage;
94 llvm::raw_string_ostream buffer(storage);
95 buffer << llvm::format("L%03d", _unnamedCounter++);
96 llvm::StringRef newName = copyString(buffer.str());
97 _refNames[target] = newName;
98 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
99 << "unnamed atom: creating ref-name: '" << newName
100 << "' (" << (void*)newName.data() << ", "
101 << newName.size() << ")\n");
102 }
103 }
104 }
105 for (const lld::UndefinedAtom *undefAtom : file.undefined()) {
106 buildDuplicateNameMap(*undefAtom);
107 }
108 for (const lld::SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
109 buildDuplicateNameMap(*shlibAtom);
110 }
111 for (const lld::AbsoluteAtom *absAtom : file.absolute()) {
112 buildDuplicateNameMap(*absAtom);
113 }
114 }
115
116 void buildDuplicateNameMap(const lld::Atom &atom) {
117 assert(!atom.name().empty());
118 NameToAtom::iterator pos = _nameMap.find(atom.name());
119 if ( pos != _nameMap.end() ) {
120 // Found name collision, give each a unique ref-name.
121 std::string Storage;
122 llvm::raw_string_ostream buffer(Storage);
123 buffer << atom.name() << llvm::format(".%03d", ++_collisionCount);
124 llvm::StringRef newName = copyString(buffer.str());
125 _refNames[&atom] = newName;
126 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
127 << "name collsion: creating ref-name: '" << newName
128 << "' (" << (void*)newName.data() << ", "
129 << newName.size() << ")\n");
130 const lld::Atom *prevAtom = pos->second;
131 AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
132 if ( pos2 == _refNames.end() ) {
133 // Only create ref-name for previous if none already created.
134 std::string Storage2;
135 llvm::raw_string_ostream buffer2(Storage2);
136 buffer2 << prevAtom->name() << llvm::format(".%03d", ++_collisionCount);
137 llvm::StringRef newName2 = copyString(buffer2.str());
138 _refNames[prevAtom] = newName2;
139 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
140 << "name collsion: creating ref-name: '" << newName2
141 << "' (" << (void*)newName2.data() << ", "
142 << newName2.size() << ")\n");
143 }
144 }
145 else {
146 // First time we've seen this name, just add it to map.
147 _nameMap[atom.name()] = &atom;
148 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
149 << "atom name seen for first time: '" << atom.name()
150 << "' (" << (void*)atom.name().data() << ", "
151 << atom.name().size() << ")\n");
152 }
153 }
154
155 bool hasRefName(const lld::Atom *atom) {
156 return _refNames.count(atom);
157 }
158
159 llvm::StringRef refName(const lld::Atom *atom) {
160 return _refNames.find(atom)->second;
161 }
162
163private:
164 typedef llvm::StringMap<const lld::Atom*> NameToAtom;
165 typedef llvm::DenseMap<const lld::Atom*, std::string> AtomToRefName;
166
167 // Allocate a new copy of this string and keep track of allocations
168 // in _stringCopies, so they can be freed when RefNameBuilder is destroyed.
169 llvm::StringRef copyString(llvm::StringRef str) {
170 // We want _stringCopies to own the string memory so it is deallocated
171 // when the File object is destroyed. But we need a StringRef that
172 // points into that memory.
173 std::unique_ptr<char> s = std::unique_ptr<char>(new char[str.size()]);
174 memcpy(s.get(), str.data(), str.size());
175 llvm::StringRef r = llvm::StringRef(s.get(), str.size());
176 _stringCopies.push_back(std::move(s));
177 return r;
178 }
179
180 unsigned int _collisionCount;
181 unsigned int _unnamedCounter;
182 NameToAtom _nameMap;
183 AtomToRefName _refNames;
184 std::vector<std::unique_ptr<char>> _stringCopies;
185};
186
187
188/// Used when reading yaml files to find the target of a reference
189/// that could be a name or ref-name.
190class RefNameResolver {
191public:
192 RefNameResolver(const lld::File *file, IO &io);
193
194 const lld::Atom *lookup(llvm::StringRef name) const {
195 NameToAtom::const_iterator pos = _nameMap.find(name);
196 if (pos != _nameMap.end()) {
197 return pos->second;
198 }
199 else {
200 _io.setError(llvm::Twine("no such atom name: ") + name);
201 return nullptr;
202 }
203 }
204
205private:
206 typedef llvm::StringMap<const lld::Atom*> NameToAtom;
207
208 void add(llvm::StringRef name, const lld::Atom *atom) {
209 if (_nameMap.count(name)) {
210 _io.setError(llvm::Twine("duplicate atom name: ") + name);
211 }
212 else {
213 _nameMap[name] = atom;
214 }
215 }
216
217 IO &_io;
218 NameToAtom _nameMap;
219};
220
221
222// Used in NormalizedFile to hold the atoms lists.
223template <typename T>
224class AtomList : public lld::File::atom_collection<T> {
225public:
226 virtual lld::File::atom_iterator<T> begin() const {
227 return lld::File::atom_iterator<T>(*this, reinterpret_cast<const void*>
228 (_atoms.data()));
229 }
230 virtual lld::File::atom_iterator<T> end() const{
231 return lld::File::atom_iterator<T>(*this, reinterpret_cast<const void*>
232 (_atoms.data() + _atoms.size()));
233 }
234 virtual const T *deref(const void *it) const {
235 return *reinterpret_cast<const T *const*>(it);
236 }
237 virtual void next(const void *&it) const {
238 const T *const *p = reinterpret_cast<const T *const *>(it);
239 ++p;
240 it = reinterpret_cast<const void*>(p);
241 }
242 virtual void push_back(const T *element) {
243 _atoms.push_back(element);
244 }
245 std::vector<const T*> _atoms;
246};
247
248/// Mapping of kind: field in yaml files.
249enum FileKinds {
250 fileKindObjectAtoms, // atom based object file encoded in yaml
251 fileKindArchive, // static archive library encoded in yaml
252 fileKindObjectELF, // ELF object files encoded in yaml
253 fileKindObjectMachO // mach-o object files encoded in yaml
254};
255
256struct ArchMember {
257 FileKinds _kind;
258 llvm::StringRef _name;
259 const lld::File *_content;
260};
261
262// The content bytes in a DefinedAtom are just uint8_t but we want
263// special formatting, so define a strong type.
264LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8);
265
266// SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
267// more readable than just true/false.
268LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull);
269
270// lld::Reference::Kind is a typedef of int32. We need a stronger
271// type to make template matching work, so invent RefKind.
272LLVM_YAML_STRONG_TYPEDEF(lld::Reference::Kind, RefKind);
273
274
275} // namespace anon
276
277
278// This is a custom formatter for RefKind
279template<>
280struct ScalarTraits<RefKind> {
281 static void output(const RefKind &value, void *ctxt,
282 llvm::raw_ostream &out) {
283 assert(ctxt != nullptr);
284 ContextInfo *info = reinterpret_cast<ContextInfo*>(ctxt);
285 out << info->_writerOptions->kindToString(value);
286 }
287
288 static StringRef input(StringRef scalar, void *ctxt, RefKind &value) {
289 assert(ctxt != nullptr);
290 ContextInfo *info = reinterpret_cast<ContextInfo*>(ctxt);
291 value = info->_readerOptions->kindFromString(scalar);
292 return StringRef();
293 }
294};
295
296
297template <>
298struct ScalarEnumerationTraits<lld::File::Kind> {
299 static void enumeration(IO &io, lld::File::Kind &value) {
300 io.enumCase(value, "object", lld::File::kindObject);
301 io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
302 io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
303 }
304};
305
306template <>
307struct ScalarEnumerationTraits<lld::Atom::Scope> {
308 static void enumeration(IO &io, lld::Atom::Scope &value) {
309 io.enumCase(value, "global", lld::Atom::scopeGlobal);
310 io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
311 io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
312 }
313};
314
315template <>
316struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
317 static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
318 io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
319 io.enumCase(value, "custom", lld::DefinedAtom::sectionCustomPreferred);
320 io.enumCase(value, "custom-required",
321 lld::DefinedAtom::sectionCustomRequired);
322 }
323};
324
325template <>
326struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
327 static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
328 io.enumCase(value, "no", lld::DefinedAtom::interposeNo);
329 io.enumCase(value, "yes", lld::DefinedAtom::interposeYes);
330 io.enumCase(value, "yes-and-weak",
331 lld::DefinedAtom::interposeYesAndRuntimeWeak);
332 }
333};
334
335template <>
336struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
337 static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
338 io.enumCase(value, "no", lld::DefinedAtom::mergeNo);
339 io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
340 io.enumCase(value, "as-weak", lld::DefinedAtom::mergeAsWeak);
341 io.enumCase(value, "as-addressed-weak",
342 lld::DefinedAtom::mergeAsWeakAndAddressUsed);
343 }
344};
345
346template <>
347struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
348 static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
349 io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
350 io.enumCase(value, "never", lld::DefinedAtom::deadStripNever);
351 io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
352 }
353};
354
355template <>
356struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
357 static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
358 io.enumCase(value, "---", lld::DefinedAtom::perm___);
359 io.enumCase(value, "r--", lld::DefinedAtom::permR__);
360 io.enumCase(value, "r-x", lld::DefinedAtom::permR_X);
361 io.enumCase(value, "rw-", lld::DefinedAtom::permRW_);
362 io.enumCase(value, "rwx", lld::DefinedAtom::permRWX);
363 io.enumCase(value, "rw-l", lld::DefinedAtom::permRW_L);
364 }
365};
366
367template <>
368struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
369 static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
370 io.enumCase(value, "unknown",
371 lld::DefinedAtom::typeUnknown);
372 io.enumCase(value, "code",
373 lld::DefinedAtom::typeCode);
374 io.enumCase(value, "stub",
375 lld::DefinedAtom::typeStub);
376 io.enumCase(value, "constant",
377 lld::DefinedAtom::typeConstant);
378 io.enumCase(value, "data",
379 lld::DefinedAtom::typeData);
380 io.enumCase(value, "zero-fill",
381 lld::DefinedAtom::typeZeroFill);
382 io.enumCase(value, "got",
383 lld::DefinedAtom::typeGOT);
384 io.enumCase(value, "resolver",
385 lld::DefinedAtom::typeResolver);
386 io.enumCase(value, "branch-island",
387 lld::DefinedAtom::typeBranchIsland);
388 io.enumCase(value, "branch-shim",
389 lld::DefinedAtom::typeBranchShim);
390 io.enumCase(value, "stub-helper",
391 lld::DefinedAtom::typeStubHelper);
392 io.enumCase(value, "c-string",
393 lld::DefinedAtom::typeCString);
394 io.enumCase(value, "utf16-string",
395 lld::DefinedAtom::typeUTF16String);
396 io.enumCase(value, "unwind-cfi",
397 lld::DefinedAtom::typeCFI);
398 io.enumCase(value, "unwind-lsda",
399 lld::DefinedAtom::typeLSDA);
400 io.enumCase(value, "const-4-byte",
401 lld::DefinedAtom::typeLiteral4);
402 io.enumCase(value, "const-8-byte",
403 lld::DefinedAtom::typeLiteral8);
404 io.enumCase(value, "const-16-byte",
405 lld::DefinedAtom::typeLiteral16);
406 io.enumCase(value, "lazy-pointer",
407 lld::DefinedAtom::typeLazyPointer);
408 io.enumCase(value, "lazy-dylib-pointer",
409 lld::DefinedAtom::typeLazyDylibPointer);
410 io.enumCase(value, "cfstring",
411 lld::DefinedAtom::typeCFString);
412 io.enumCase(value, "initializer-pointer",
413 lld::DefinedAtom::typeInitializerPtr);
414 io.enumCase(value, "terminator-pointer",
415 lld::DefinedAtom::typeTerminatorPtr);
416 io.enumCase(value, "c-string-pointer",
417 lld::DefinedAtom::typeCStringPtr);
418 io.enumCase(value, "objc-class-pointer",
419 lld::DefinedAtom::typeObjCClassPtr);
420 io.enumCase(value, "objc-category-list",
421 lld::DefinedAtom::typeObjC2CategoryList);
422 io.enumCase(value, "objc-class1",
423 lld::DefinedAtom::typeObjC1Class);
424 io.enumCase(value, "dtraceDOF",
425 lld::DefinedAtom::typeDTraceDOF);
426 io.enumCase(value, "lto-temp",
427 lld::DefinedAtom::typeTempLTO);
428 io.enumCase(value, "compact-unwind",
429 lld::DefinedAtom::typeCompactUnwindInfo);
430 io.enumCase(value, "tlv-thunk",
431 lld::DefinedAtom::typeThunkTLV);
432 io.enumCase(value, "tlv-data",
433 lld::DefinedAtom::typeTLVInitialData);
434 io.enumCase(value, "tlv-zero-fill",
435 lld::DefinedAtom::typeTLVInitialZeroFill);
436 io.enumCase(value, "tlv-initializer-ptr",
437 lld::DefinedAtom::typeTLVInitializerPtr);
438 io.enumCase(value, "first-in-section",
439 lld::DefinedAtom::typeFirstInSection);
440 io.enumCase(value, "last-in-section",
441 lld::DefinedAtom::typeLastInSection);
442 }
443};
444
445template <>
446struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
447 static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
448 io.enumCase(value, "never", lld::UndefinedAtom::canBeNullNever);
449 io.enumCase(value, "at-runtime", lld::UndefinedAtom::canBeNullAtRuntime);
450 io.enumCase(value, "at-buildtime", lld::UndefinedAtom::canBeNullAtBuildtime);
451 }
452};
453
454
455template <>
456struct ScalarEnumerationTraits<ShlibCanBeNull> {
457 static void enumeration(IO &io, ShlibCanBeNull &value) {
458 io.enumCase(value, "never", false);
459 io.enumCase(value, "at-runtime", true);
460 }
461};
462
463
464
465/// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
466/// like:
467/// 2^3 # 8-byte aligned
468/// 7 mod 2^4 # 16-byte aligned plus 7 bytes
469template<>
470struct ScalarTraits<lld::DefinedAtom::Alignment> {
471 static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
472 llvm::raw_ostream &out) {
473 if (value.modulus == 0) {
474 out << llvm::format("2^%d", value.powerOf2);
475 }
476 else {
477 out << llvm::format("%d mod 2^%d", value.modulus, value.powerOf2);
478 }
479 }
480
481 static StringRef input(StringRef scalar, void *ctxt,
482 lld::DefinedAtom::Alignment &value) {
483 value.modulus = 0;
484 size_t modStart = scalar.find("mod");
485 if (modStart != StringRef::npos) {
486 StringRef modStr = scalar.slice(0, modStart);
487 modStr = modStr.rtrim();
488 unsigned int modulus;
489 if (modStr.getAsInteger(0, modulus)) {
490 return "malformed alignment modulus";
491 }
492 value.modulus = modulus;
493 scalar = scalar.drop_front(modStart+3);
494 scalar = scalar.ltrim();
495 }
496 if (!scalar.startswith("2^")) {
497 return "malformed alignment";
498 }
499 StringRef powerStr = scalar.drop_front(2);
500 unsigned int power;
501 if (powerStr.getAsInteger(0, power)) {
502 return "malformed alignment power";
503 }
504 value.powerOf2 = power;
505 if (value.modulus > (1<<value.powerOf2)) {
506 return "malformed alignment, modulus too large for power";
507 }
508 return StringRef(); // returning empty string means success
509 }
510};
511
512
513
514
515template <>
516struct ScalarEnumerationTraits<FileKinds> {
517 static void enumeration(IO &io, FileKinds &value) {
518 io.enumCase(value, "object", fileKindObjectAtoms);
519 io.enumCase(value, "archive", fileKindArchive);
520 io.enumCase(value, "object-elf", fileKindObjectELF);
521 io.enumCase(value, "object-mach-o", fileKindObjectMachO);
522 }
523};
524
525template <>
526struct MappingTraits<ArchMember> {
527 static void mapping(IO &io, ArchMember &member) {
528 io.mapOptional("kind", member._kind, fileKindObjectAtoms);
529 io.mapOptional("name", member._name);
530 io.mapRequired("content", member._content);
531 }
532};
533
534LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember);
535
536
537// Declare that an AtomList is a yaml sequence.
538template<typename T>
539struct SequenceTraits<AtomList<T>> {
540 static size_t size(IO &io, AtomList<T> &seq) {
541 return seq._atoms.size();
542 }
543 static const T *&element(IO &io, AtomList<T> &seq, size_t index) {
544 if (index >= seq._atoms.size())
545 seq._atoms.resize(index+1);
546 return seq._atoms[index];
547 }
548};
549
550// Used to allow DefinedAtom content bytes to be a flow sequence of
551// two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
552template<>
553struct ScalarTraits<ImplicitHex8> {
554 static void output(const ImplicitHex8 &val, void*, llvm::raw_ostream &out) {
555 uint8_t num = val;
556 out << llvm::format("%02X", num);
557 }
558
559 static llvm::StringRef input(llvm::StringRef str, void*, ImplicitHex8 &val) {
560 unsigned long long n;
561 if (getAsUnsignedInteger(str, 16, n))
562 return "invalid two-digit-hex number";
563 if (n > 0xFF)
564 return "out of range two-digit-hex number";
565 val = n;
566 return StringRef(); // returning empty string means success
567 }
568};
569
570// Always write DefinedAtoms content bytes as a flow sequence.
571LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8);
572
573
574// YAML conversion for std::vector<const lld::File*>
575template<>
576struct DocumentListTraits< std::vector<const lld::File*> > {
577 static size_t size(IO &io, std::vector<const lld::File*> &seq) {
578 return seq.size();
579 }
580 static const lld::File *&element(IO &io, std::vector<const lld::File*> &seq,
581 size_t index) {
582 if (index >= seq.size())
583 seq.resize(index+1);
584 return seq[index];
585 }
586};
587
588
589// YAML conversion for const lld::File*
590template <>
591struct MappingTraits<const lld::File*> {
592
593 class NormArchiveFile : public lld::ArchiveLibraryFile {
594 public:
595 NormArchiveFile(IO &io) : ArchiveLibraryFile(""), _path() {
596 }
597 NormArchiveFile(IO &io, const lld::File *file)
598 : ArchiveLibraryFile(file->path()),
599 _path(file->path()) {
600 // If we want to support writing archives, this constructor would
601 // need to populate _members.
602 }
603
604 const lld::File *denormalize(IO &io) {
605 return this;
606 }
607
608 virtual void addAtom(const lld::Atom&) {
609 llvm_unreachable("cannot add atoms to yaml .o files");
610 }
611 virtual const atom_collection<lld::DefinedAtom> &defined() const {
612 return _noDefinedAtoms;
613 }
614 virtual const atom_collection<lld::UndefinedAtom> &undefined() const {
615 return _noUndefinedAtoms;
616 }
617 virtual const atom_collection<lld::SharedLibraryAtom> &sharedLibrary()const{
618 return _noSharedLibaryAtoms;
619 }
620 virtual const atom_collection<lld::AbsoluteAtom> &absolute() const {
621 return _noAbsoluteAtoms;
622 }
623 virtual const File *find(StringRef name, bool dataSymbolOnly) const {
624 for (const ArchMember &member : _members) {
625 for (const lld::DefinedAtom *atom : member._content->defined() ) {
626 if (name == atom->name()) {
627 if (!dataSymbolOnly)
628 return member._content;
629 switch (atom->contentType()) {
630 case lld::DefinedAtom::typeData:
631 case lld::DefinedAtom::typeZeroFill:
632 return member._content;
633 default:
634 break;
635 }
636 }
637 }
638 }
639 return nullptr;
640 }
641
642 StringRef _path;
643 std::vector<ArchMember> _members;
644 };
645
646
647 class NormalizedFile : public lld::File {
648 public:
649 NormalizedFile(IO &io) : File(""), _rnb(nullptr) {
650 }
651 NormalizedFile(IO &io, const lld::File *file)
652 : File(file->path()),
653 _rnb(new RefNameBuilder(*file)),
654 _path(file->path()) {
655 for (const lld::DefinedAtom *a : file->defined())
656 _definedAtoms.push_back(a);
657 for (const lld::UndefinedAtom *a : file->undefined())
658 _undefinedAtoms.push_back(a);
659 for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
660 _sharedLibraryAtoms.push_back(a);
661 for (const lld::AbsoluteAtom *a : file->absolute())
662 _absoluteAtoms.push_back(a);
663 }
664 const lld::File *denormalize(IO &io);
665
666
667 virtual void addAtom(const lld::Atom&) {
668 llvm_unreachable("cannot add atoms to yaml .o files");
669 }
670 virtual const atom_collection<lld::DefinedAtom> &defined() const {
671 return _definedAtoms;
672 }
673 virtual const atom_collection<lld::UndefinedAtom> &undefined() const {
674 return _undefinedAtoms;
675 }
676 virtual const atom_collection<lld::SharedLibraryAtom> &sharedLibrary()const{
677 return _sharedLibraryAtoms;
678 }
679 virtual const atom_collection<lld::AbsoluteAtom> &absolute() const {
680 return _absoluteAtoms;
681 }
682
683 // Allocate a new copy of this string and keep track of allocations
684 // in _stringCopies, so they can be freed when File is destroyed.
685 StringRef copyString(StringRef str) {
686 // We want _stringCopies to own the string memory so it is deallocated
687 // when the File object is destroyed. But we need a StringRef that
688 // points into that memory.
689 std::unique_ptr<char> s = std::unique_ptr<char>(new char[str.size()]);
690 memcpy(s.get(), str.data(), str.size());
691 llvm::StringRef r = llvm::StringRef(s.get(), str.size());
692 _stringCopies.push_back(std::move(s));
693 return r;
694 }
695
696 RefNameBuilder *_rnb;
697 StringRef _path;
698 AtomList<lld::DefinedAtom> _definedAtoms;
699 AtomList<lld::UndefinedAtom> _undefinedAtoms;
700 AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms;
701 AtomList<lld::AbsoluteAtom> _absoluteAtoms;
702 std::vector<std::unique_ptr<char>> _stringCopies;
703 };
704
705
706 static void mapping(IO &io, const lld::File *&file) {
707 // We only support writing atom based YAML
708 FileKinds kind = fileKindObjectAtoms;
709 // If reading, peek ahead to see what kind of file this is.
710 io.mapOptional("kind", kind, fileKindObjectAtoms);
711 //
712 switch (kind) {
713 case fileKindObjectAtoms:
714 mappingAtoms(io, file);
715 break;
716 case fileKindArchive:
717 mappingArchive(io, file);
718 break;
719 case fileKindObjectELF:
720 case fileKindObjectMachO:
721 // Eventually we will have an external function to call, similar
722 // to mappingAtoms() and mappingArchive() but implememented
723 // with coresponding file format code.
Nick Kledzik6b079f52013-01-05 02:22:35 +0000724 llvm_unreachable("section based YAML not supported yet");
725 }
726 }
727
728 static void mappingAtoms(IO &io, const lld::File *&file) {
729 MappingNormalizationHeap<NormalizedFile, const lld::File*> keys(io, file);
730 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
731 assert(info != nullptr);
732 info->_currentFile = keys.operator->();
733
734 io.mapOptional("path", keys->_path);
735 io.mapOptional("defined-atoms", keys->_definedAtoms);
736 io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
737 io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
738 io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
739 }
740
741 static void mappingArchive(IO &io, const lld::File *&file) {
742 MappingNormalizationHeap<NormArchiveFile, const lld::File*> keys(io, file);
743
744 io.mapOptional("path", keys->_path);
745 io.mapOptional("members", keys->_members);
746 }
747
748};
749
750
751
752// YAML conversion for const lld::Reference*
753template <>
754struct MappingTraits<const lld::Reference*> {
755
756 class NormalizedReference : public lld::Reference {
757 public:
758 NormalizedReference(IO &io)
759 : _target(nullptr), _targetName(), _offset(0), _addend(0) , _kind(0) {
760 }
761 NormalizedReference(IO &io, const lld::Reference *ref)
762 : _target(nullptr),
763 _targetName(targetName(io, ref)),
764 _offset(ref->offsetInAtom()),
765 _addend(ref->addend()),
766 _kind(ref->kind()) {
767 }
768 const lld::Reference *denormalize(IO &io) {
769 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
770 assert(info != nullptr);
771 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
772 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
773 if (!_targetName.empty())
774 _targetName = f->copyString(_targetName);
775 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
776 << "created Reference to name: '" << _targetName
777 << "' (" << (void*)_targetName.data() << ", "
778 << _targetName.size() << ")\n");
779 return this;
780 }
781 void bind(const RefNameResolver&);
782 static StringRef targetName(IO &io, const lld::Reference *ref);
783
784 virtual uint64_t offsetInAtom() const { return _offset; }
785 virtual Kind kind() const { return _kind; }
786 virtual const lld::Atom *target() const { return _target; }
787 virtual Addend addend() const { return _addend; }
788 virtual void setKind(Kind k) { _kind = k; }
789 virtual void setAddend(Addend a) { _addend = a; }
790 virtual void setTarget(const lld::Atom *a) { _target = a; }
791
792 const lld::Atom *_target;
793 StringRef _targetName;
794 uint32_t _offset;
795 Addend _addend;
796 RefKind _kind;
797 };
798
799
800 static void mapping(IO &io, const lld::Reference *&ref) {
801 MappingNormalizationHeap<NormalizedReference,
802 const lld::Reference*> keys(io, ref);
803
804 io.mapRequired("kind", keys->_kind);
805 io.mapOptional("offset", keys->_offset);
806 io.mapOptional("target", keys->_targetName);
807 io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
808 }
809};
810
811LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference*)
812
813
814// YAML conversion for const lld::DefinedAtom*
815template <>
816struct MappingTraits<const lld::DefinedAtom*> {
817
818 class NormalizedAtom : public lld::DefinedAtom {
819 public:
820 NormalizedAtom(IO &io)
821 : _file(fileFromContext(io)), _name(), _refName(),
822 _alignment(0), _content(), _references() {
823 }
824 NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
825 : _file(fileFromContext(io)),
826 _name(atom->name()),
827 _refName(),
828 _scope(atom->scope()),
829 _interpose(atom->interposable()),
830 _merge(atom->merge()),
831 _contentType(atom->contentType()),
832 _alignment(atom->alignment()),
833 _sectionChoice(atom->sectionChoice()),
834 _deadStrip(atom->deadStrip()),
835 _permissions(atom->permissions()),
836 _size(atom->size()),
837 _sectionName(atom->customSectionName()) {
838 for ( const lld::Reference *r : *atom )
839 _references.push_back(r);
840 ArrayRef<uint8_t> cont = atom->rawContent();
841 _content.reserve(cont.size());
842 for (uint8_t x : cont)
843 _content.push_back(x);
844 }
845 const lld::DefinedAtom *denormalize(IO &io) {
846 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
847 assert(info != nullptr);
848 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
849 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
850 if ( !_name.empty() )
851 _name = f->copyString(_name);
852 if ( !_refName.empty() )
853 _refName = f->copyString(_refName);
854 if ( !_sectionName.empty() )
855 _sectionName = f->copyString(_sectionName);
856 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
857 << "created DefinedAtom named: '" << _name
858 << "' (" << (void*)_name.data() << ", "
859 << _name.size() << ")\n");
860 return this;
861 }
862 void bind(const RefNameResolver&);
863 // Extract current File object from YAML I/O parsing context
864 const lld::File &fileFromContext(IO &io) {
865 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
866 assert(info != nullptr);
867 assert(info->_currentFile != nullptr);
868 return *info->_currentFile;
869 }
870
871 virtual const lld::File &file() const { return _file; }
872 virtual StringRef name() const { return _name; }
873 virtual uint64_t size() const { return _size; }
874 virtual Scope scope() const { return _scope; }
875 virtual Interposable interposable() const { return _interpose; }
876 virtual Merge merge() const { return _merge; }
877 virtual ContentType contentType() const { return _contentType; }
878 virtual Alignment alignment() const { return _alignment; }
879 virtual SectionChoice sectionChoice() const { return _sectionChoice; }
880 virtual StringRef customSectionName() const { return _sectionName;}
881 virtual DeadStripKind deadStrip() const { return _deadStrip; }
882 virtual ContentPermissions permissions() const { return _permissions; }
883 virtual bool isThumb() const { return false; }
884 virtual bool isAlias() const { return false; }
885 ArrayRef<uint8_t> rawContent() const {
886 return ArrayRef<uint8_t>((uint8_t*)&_content.operator[](0),
887 _content.size()); }
888 virtual uint64_t ordinal() const { return 0; }
889
890 reference_iterator begin() const {
891 uintptr_t index = 0;
892 const void *it = reinterpret_cast<const void*>(index);
893 return reference_iterator(*this, it);
894 }
895 reference_iterator end() const {
896 uintptr_t index = _references.size();
897 const void *it = reinterpret_cast<const void*>(index);
898 return reference_iterator(*this, it);
899 }
900 const lld::Reference *derefIterator(const void *it) const {
901 uintptr_t index = reinterpret_cast<uintptr_t>(it);
902 assert(index < _references.size());
903 return _references[index];
904 }
905 void incrementIterator(const void *&it) const {
906 uintptr_t index = reinterpret_cast<uintptr_t>(it);
907 ++index;
908 it = reinterpret_cast<const void*>(index);
909 }
910
911 const lld::File &_file;
912 StringRef _name;
913 StringRef _refName;
914 Scope _scope;
915 Interposable _interpose;
916 Merge _merge;
917 ContentType _contentType;
918 Alignment _alignment;
919 SectionChoice _sectionChoice;
920 DeadStripKind _deadStrip;
921 ContentPermissions _permissions;
922 std::vector<ImplicitHex8> _content;
923 uint64_t _size;
924 StringRef _sectionName;
925 std::vector<const lld::Reference*> _references;
926 };
927
928 static void mapping(IO &io, const lld::DefinedAtom *&atom) {
929 MappingNormalizationHeap<NormalizedAtom,
930 const lld::DefinedAtom*> keys(io, atom);
931 if ( io.outputting() ) {
932 // If writing YAML, check if atom needs a ref-name.
933 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
934 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
935 assert(info != nullptr);
936 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
937 assert(f);
938 assert(f->_rnb);
939 if ( f->_rnb->hasRefName(atom) ) {
940 keys->_refName = f->_rnb->refName(atom);
941 }
942 }
943
944 io.mapOptional("name", keys->_name,
945 StringRef());
946 io.mapOptional("ref-name", keys->_refName,
947 StringRef());
948 io.mapOptional("scope", keys->_scope,
949 lld::DefinedAtom::scopeTranslationUnit);
950 io.mapOptional("type", keys->_contentType,
951 lld::DefinedAtom::typeCode);
952 io.mapOptional("content", keys->_content);
953 io.mapOptional("size", keys->_size,
954 (uint64_t)keys->_content.size());
955 io.mapOptional("interposable", keys->_interpose,
956 lld::DefinedAtom::interposeNo);
957 io.mapOptional("merge", keys->_merge,
958 lld::DefinedAtom::mergeNo);
959 io.mapOptional("alignment", keys->_alignment,
960 lld::DefinedAtom::Alignment(0));
961 io.mapOptional("section-choice", keys->_sectionChoice,
962 lld::DefinedAtom::sectionBasedOnContent);
963 io.mapOptional("section-name", keys->_sectionName,
964 StringRef());
965 io.mapOptional("dead-strip", keys->_deadStrip,
966 lld::DefinedAtom::deadStripNormal);
967 io.mapOptional("permissions", keys->_permissions,
968 lld::DefinedAtom::permR_X);
Nick Kledzik8a3052e2013-01-08 21:12:13 +0000969 io.mapOptional("references", keys->_references);
Nick Kledzik6b079f52013-01-05 02:22:35 +0000970 }
971};
972
973
974
975
976inline
977const lld::File*
978MappingTraits<const lld::File*>::NormalizedFile::denormalize(IO &io) {
979 typedef MappingTraits<const lld::DefinedAtom*>::NormalizedAtom NormalizedAtom;
980
981 RefNameResolver nameResolver(this, io);
982 // Now that all atoms are parsed, references can be bound.
983 for (const lld::DefinedAtom *a : this->defined() ) {
984 NormalizedAtom *normAtom = (NormalizedAtom*)a;
985 normAtom->bind(nameResolver);
986 }
987 return this;
988}
989
990inline
991void MappingTraits<const lld::DefinedAtom*>::
992 NormalizedAtom::bind(const RefNameResolver &resolver) {
993 typedef MappingTraits<const lld::Reference*>::NormalizedReference
994 NormalizedReference;
995 for (const lld::Reference *ref : _references) {
996 NormalizedReference *normRef = (NormalizedReference*)ref;
997 normRef->bind(resolver);
998 }
999}
1000
1001inline
1002void MappingTraits<const lld::Reference*>::
1003 NormalizedReference::bind(const RefNameResolver &resolver) {
1004 _target = resolver.lookup(_targetName);
1005}
1006
1007
1008
1009// YAML conversion for const lld::UndefinedAtom*
1010template <>
1011struct MappingTraits<const lld::UndefinedAtom*> {
1012
1013 class NormalizedAtom : public lld::UndefinedAtom {
1014 public:
1015 NormalizedAtom(IO &io)
1016 : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {
1017 }
1018 NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
1019 : _file(fileFromContext(io)),
1020 _name(atom->name()),
1021 _canBeNull(atom->canBeNull()) {
1022 }
1023 const lld::UndefinedAtom *denormalize(IO &io) {
1024 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1025 assert(info != nullptr);
1026 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1027 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1028 if ( !_name.empty() )
1029 _name = f->copyString(_name);
1030
1031 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
1032 << "created UndefinedAtom named: '" << _name
1033 << "' (" << (void*)_name.data() << ", "
1034 << _name.size() << ")\n");
1035 return this;
1036 }
1037 // Extract current File object from YAML I/O parsing context
1038 const lld::File &fileFromContext(IO &io) {
1039 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1040 assert(info != nullptr);
1041 assert(info->_currentFile != nullptr);
1042 return *info->_currentFile;
1043 }
1044
1045 virtual const lld::File &file() const { return _file; }
1046 virtual StringRef name() const { return _name; }
1047 virtual CanBeNull canBeNull() const { return _canBeNull; }
1048
1049 const lld::File &_file;
1050 StringRef _name;
1051 CanBeNull _canBeNull;
1052 };
1053
1054
1055 static void mapping(IO &io, const lld::UndefinedAtom* &atom) {
1056 MappingNormalizationHeap<NormalizedAtom,
1057 const lld::UndefinedAtom*> keys(io, atom);
1058
1059 io.mapRequired("name", keys->_name);
1060 io.mapOptional("can-be-null", keys->_canBeNull,
1061 lld::UndefinedAtom::canBeNullNever);
1062 }
1063};
1064
1065
1066// YAML conversion for const lld::SharedLibraryAtom*
1067template <>
1068struct MappingTraits<const lld::SharedLibraryAtom*> {
1069
1070 class NormalizedAtom : public lld::SharedLibraryAtom {
1071 public:
1072 NormalizedAtom(IO &io)
1073 : _file(fileFromContext(io)), _name(), _loadName(), _canBeNull(false) {
1074 }
1075 NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
1076 : _file(fileFromContext(io)),
1077 _name(atom->name()),
1078 _loadName(atom->loadName()),
1079 _canBeNull(atom->canBeNullAtRuntime()) {
1080 }
1081 const lld::SharedLibraryAtom *denormalize(IO &io) {
1082 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1083 assert(info != nullptr);
1084 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1085 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1086 if ( !_name.empty() )
1087 _name = f->copyString(_name);
1088 if ( !_loadName.empty() )
1089 _loadName = f->copyString(_loadName);
1090
1091 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
1092 << "created SharedLibraryAtom named: '" << _name
1093 << "' (" << (void*)_name.data() << ", "
1094 << _name.size() << ")\n");
1095 return this;
1096 }
1097 // Extract current File object from YAML I/O parsing context
1098 const lld::File &fileFromContext(IO &io) {
1099 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1100 assert(info != nullptr);
1101 assert(info->_currentFile != nullptr);
1102 return *info->_currentFile;
1103 }
1104
1105 virtual const lld::File &file() const { return _file; }
1106 virtual StringRef name() const { return _name; }
1107 virtual StringRef loadName() const { return _loadName;}
1108 virtual bool canBeNullAtRuntime() const { return _canBeNull; }
1109
1110 const lld::File &_file;
1111 StringRef _name;
1112 StringRef _loadName;
1113 ShlibCanBeNull _canBeNull;
1114 };
1115
1116
1117 static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
1118
1119 MappingNormalizationHeap<NormalizedAtom,
1120 const lld::SharedLibraryAtom*> keys(io, atom);
1121
1122 io.mapRequired("name", keys->_name);
1123 io.mapOptional("load-name", keys->_loadName);
1124 io.mapOptional("can-be-null", keys->_canBeNull,
1125 (ShlibCanBeNull)false);
1126 }
1127};
1128
1129
1130// YAML conversion for const lld::AbsoluteAtom*
1131template <>
1132struct MappingTraits<const lld::AbsoluteAtom*> {
1133
1134 class NormalizedAtom : public lld::AbsoluteAtom {
1135 public:
1136 NormalizedAtom(IO &io)
1137 : _file(fileFromContext(io)), _name(), _scope(), _value(0) {
1138 }
1139 NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
1140 : _file(fileFromContext(io)),
1141 _name(atom->name()),
1142 _scope(atom->scope()),
1143 _value(atom->value()) {
1144 }
1145 const lld::AbsoluteAtom *denormalize(IO &io) {
1146 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1147 assert(info != nullptr);
1148 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1149 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1150 if ( !_name.empty() )
1151 _name = f->copyString(_name);
1152
1153 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
1154 << "created AbsoluteAtom named: '" << _name
1155 << "' (" << (void*)_name.data() << ", "
1156 << _name.size() << ")\n");
1157 return this;
1158 }
1159 // Extract current File object from YAML I/O parsing context
1160 const lld::File &fileFromContext(IO &io) {
1161 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1162 assert(info != nullptr);
1163 assert(info->_currentFile != nullptr);
1164 return *info->_currentFile;
1165 }
1166
1167 virtual const lld::File &file() const { return _file; }
1168 virtual StringRef name() const { return _name; }
1169 virtual uint64_t value() const { return _value; }
1170 virtual Scope scope() const { return _scope; }
1171
1172 const lld::File &_file;
1173 StringRef _name;
1174 StringRef _refName;
1175 Scope _scope;
1176 Hex64 _value;
1177 };
1178
1179
1180 static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
1181 MappingNormalizationHeap<NormalizedAtom,
1182 const lld::AbsoluteAtom*> keys(io, atom);
1183
1184 if ( io.outputting() ) {
1185 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1186 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1187 assert(info != nullptr);
1188 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1189 assert(f);
1190 assert(f->_rnb);
1191 if ( f->_rnb->hasRefName(atom) ) {
1192 keys->_refName = f->_rnb->refName(atom);
1193 }
1194 }
1195
1196 io.mapRequired("name", keys->_name);
1197 io.mapOptional("ref-name", keys->_refName, StringRef());
1198 io.mapOptional("scope", keys->_scope);
1199 io.mapRequired("value", keys->_value);
1200 }
1201};
1202
1203
1204RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
1205 typedef MappingTraits<const lld::DefinedAtom*>::NormalizedAtom NormalizedAtom;
1206 for (const lld::DefinedAtom *a : file->defined() ) {
1207 NormalizedAtom *na = (NormalizedAtom*)a;
1208 if ( na->_refName.empty() )
1209 add(na->_name, a);
1210 else
1211 add(na->_refName, a);
1212 }
1213
1214 for (const lld::UndefinedAtom *a : file->undefined() )
1215 add(a->name(), a);
1216
1217 for (const lld::SharedLibraryAtom *a : file->sharedLibrary() )
1218 add(a->name(), a);
1219
1220 typedef MappingTraits<const lld::AbsoluteAtom*>::NormalizedAtom NormAbsAtom;
1221 for (const lld::AbsoluteAtom *a : file->absolute() ) {
1222 NormAbsAtom *na = (NormAbsAtom*)a;
1223 if ( na->_refName.empty() )
1224 add(na->_name, a);
1225 else
1226 add(na->_refName, a);
1227 }
1228}
1229
1230
1231inline
1232llvm::StringRef MappingTraits<const lld::Reference*>::NormalizedReference::
1233 targetName(IO &io, const lld::Reference *ref) {
1234 if ( ref->target() == nullptr )
1235 return llvm::StringRef();
1236 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1237 assert(info != nullptr);
1238 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1239 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1240 RefNameBuilder *rnb = f->_rnb;
1241 if ( rnb->hasRefName(ref->target()) )
1242 return rnb->refName(ref->target());
1243 return ref->target()->name();
1244}
1245
1246
1247
1248namespace lld {
1249namespace yaml {
1250
1251class Writer : public lld::Writer {
1252public:
1253 Writer(const WriterOptionsYAML &options) : _options(options) {
1254 }
1255
1256 virtual error_code writeFile(const lld::File &file, StringRef outPath) {
1257 // Create stream to path.
1258 std::string errorInfo;
1259 llvm::raw_fd_ostream out(outPath.data(), errorInfo);
1260 if (!errorInfo.empty())
1261 return llvm::make_error_code(llvm::errc::no_such_file_or_directory);
1262
1263 // Create yaml Output writer, using yaml options for context.
1264 ContextInfo context(_options);
1265 llvm::yaml::Output yout(out, &context);
1266
1267 // Write yaml output.
1268 const lld::File *fileRef = &file;
1269 yout << fileRef;
1270
1271 return error_code::success();
1272 }
1273
1274 virtual StubsPass *stubPass() {
1275 return _options.stubPass();
1276 }
1277
1278 virtual GOTPass *gotPass() {
1279 return _options.gotPass();
1280 }
1281
1282
1283private:
1284 const WriterOptionsYAML &_options;
1285};
1286
1287
1288
1289class ReaderYAML : public Reader {
1290public:
1291 ReaderYAML(const ReaderOptionsYAML &options) : _options(options) {
1292 }
1293
1294 error_code parseFile(std::unique_ptr<MemoryBuffer> mb,
1295 std::vector<std::unique_ptr<File>> &result) {
1296 // Note: we do not take ownership of the MemoryBuffer. That is
1297 // because yaml may produce multiple File objects, so there is no
1298 // *one* File to take ownership. Therefore, the yaml File objects
1299 // produced must make copies of all strings that come from YAML I/O.
1300 // Otherwise the strings will become invalid when this MemoryBuffer
1301 // is deallocated.
1302
1303 // Create YAML Input parser.
1304 ContextInfo context(_options);
1305 llvm::yaml::Input yin(mb->getBuffer(), &context);
1306
1307 // Fill vector with File objects created by parsing yaml.
1308 std::vector<const lld::File*> createdFiles;
1309 yin >> createdFiles;
1310
1311 // Quit now if there were parsing errors.
1312 if ( yin.error() )
1313 return make_error_code(lld::yaml_reader_error::illegal_value);
1314
1315 for (const File *file : createdFiles) {
1316 // Note: parseFile() should return vector of *const* File
1317 File *f = const_cast<File*>(file);
1318 result.emplace_back(f);
1319 }
1320 return make_error_code(lld::yaml_reader_error::success);
1321 }
1322
1323private:
1324 const ReaderOptionsYAML &_options;
1325};
1326
1327
1328
1329} // namespace yaml
1330
1331
1332Writer *createWriterYAML(const WriterOptionsYAML &options) {
1333 return new lld::yaml::Writer(options);
1334}
1335
1336WriterOptionsYAML::WriterOptionsYAML() {
1337}
1338
1339WriterOptionsYAML::~WriterOptionsYAML() {
1340}
1341
1342
1343
1344Reader *createReaderYAML(const ReaderOptionsYAML &options) {
1345 return new lld::yaml::ReaderYAML(options);
1346}
1347
1348ReaderOptionsYAML::ReaderOptionsYAML() {
1349}
1350
1351ReaderOptionsYAML::~ReaderOptionsYAML() {
1352}
1353
1354
1355} // namespace lld
1356