blob: 310e8b41654927c71f678671de79a8a36837154d [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
Nick Kledzikbd491982013-01-08 23:51:03 +0000262
Nick Kledzik6b079f52013-01-05 02:22:35 +0000263// The content bytes in a DefinedAtom are just uint8_t but we want
264// special formatting, so define a strong type.
Nick Kledzikbd491982013-01-08 23:51:03 +0000265LLVM_YAML_STRONG_TYPEDEF(uint8_t, ImplicitHex8)
Nick Kledzik6b079f52013-01-05 02:22:35 +0000266
267// SharedLibraryAtoms have a bool canBeNull() method which we'd like to be
268// more readable than just true/false.
Nick Kledzikbd491982013-01-08 23:51:03 +0000269LLVM_YAML_STRONG_TYPEDEF(bool, ShlibCanBeNull)
Nick Kledzik6b079f52013-01-05 02:22:35 +0000270
271// lld::Reference::Kind is a typedef of int32. We need a stronger
272// type to make template matching work, so invent RefKind.
Nick Kledzikbd491982013-01-08 23:51:03 +0000273LLVM_YAML_STRONG_TYPEDEF(lld::Reference::Kind, RefKind)
Nick Kledzik6b079f52013-01-05 02:22:35 +0000274
275
276} // namespace anon
277
278
Nick Kledzikbd491982013-01-08 23:51:03 +0000279LLVM_YAML_IS_SEQUENCE_VECTOR(ArchMember);
280LLVM_YAML_IS_SEQUENCE_VECTOR(const lld::Reference*)
281
282// Always write DefinedAtoms content bytes as a flow sequence.
283LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(ImplicitHex8);
284
285// for compatibility with gcc-4.7 in C++11 mode, add extra namespace
286namespace llvm {
287namespace yaml {
288
Nick Kledzik6b079f52013-01-05 02:22:35 +0000289// This is a custom formatter for RefKind
290template<>
291struct ScalarTraits<RefKind> {
292 static void output(const RefKind &value, void *ctxt,
293 llvm::raw_ostream &out) {
294 assert(ctxt != nullptr);
295 ContextInfo *info = reinterpret_cast<ContextInfo*>(ctxt);
296 out << info->_writerOptions->kindToString(value);
297 }
298
299 static StringRef input(StringRef scalar, void *ctxt, RefKind &value) {
300 assert(ctxt != nullptr);
301 ContextInfo *info = reinterpret_cast<ContextInfo*>(ctxt);
302 value = info->_readerOptions->kindFromString(scalar);
303 return StringRef();
304 }
305};
306
307
308template <>
309struct ScalarEnumerationTraits<lld::File::Kind> {
310 static void enumeration(IO &io, lld::File::Kind &value) {
311 io.enumCase(value, "object", lld::File::kindObject);
312 io.enumCase(value, "shared-library", lld::File::kindSharedLibrary);
313 io.enumCase(value, "static-library", lld::File::kindArchiveLibrary);
314 }
315};
316
317template <>
318struct ScalarEnumerationTraits<lld::Atom::Scope> {
319 static void enumeration(IO &io, lld::Atom::Scope &value) {
320 io.enumCase(value, "global", lld::Atom::scopeGlobal);
321 io.enumCase(value, "hidden", lld::Atom::scopeLinkageUnit);
322 io.enumCase(value, "static", lld::Atom::scopeTranslationUnit);
323 }
324};
325
326template <>
327struct ScalarEnumerationTraits<lld::DefinedAtom::SectionChoice> {
328 static void enumeration(IO &io, lld::DefinedAtom::SectionChoice &value) {
329 io.enumCase(value, "content", lld::DefinedAtom::sectionBasedOnContent);
330 io.enumCase(value, "custom", lld::DefinedAtom::sectionCustomPreferred);
331 io.enumCase(value, "custom-required",
332 lld::DefinedAtom::sectionCustomRequired);
333 }
334};
335
336template <>
337struct ScalarEnumerationTraits<lld::DefinedAtom::Interposable> {
338 static void enumeration(IO &io, lld::DefinedAtom::Interposable &value) {
339 io.enumCase(value, "no", lld::DefinedAtom::interposeNo);
340 io.enumCase(value, "yes", lld::DefinedAtom::interposeYes);
341 io.enumCase(value, "yes-and-weak",
342 lld::DefinedAtom::interposeYesAndRuntimeWeak);
343 }
344};
345
346template <>
347struct ScalarEnumerationTraits<lld::DefinedAtom::Merge> {
348 static void enumeration(IO &io, lld::DefinedAtom::Merge &value) {
349 io.enumCase(value, "no", lld::DefinedAtom::mergeNo);
350 io.enumCase(value, "as-tentative", lld::DefinedAtom::mergeAsTentative);
351 io.enumCase(value, "as-weak", lld::DefinedAtom::mergeAsWeak);
352 io.enumCase(value, "as-addressed-weak",
353 lld::DefinedAtom::mergeAsWeakAndAddressUsed);
Nick Kledzik233f5372013-01-15 00:17:57 +0000354 io.enumCase(value, "by-content", lld::DefinedAtom::mergeByContent);
Nick Kledzik6b079f52013-01-05 02:22:35 +0000355 }
356};
357
358template <>
359struct ScalarEnumerationTraits<lld::DefinedAtom::DeadStripKind> {
360 static void enumeration(IO &io, lld::DefinedAtom::DeadStripKind &value) {
361 io.enumCase(value, "normal", lld::DefinedAtom::deadStripNormal);
362 io.enumCase(value, "never", lld::DefinedAtom::deadStripNever);
363 io.enumCase(value, "always", lld::DefinedAtom::deadStripAlways);
364 }
365};
366
367template <>
368struct ScalarEnumerationTraits<lld::DefinedAtom::ContentPermissions> {
369 static void enumeration(IO &io, lld::DefinedAtom::ContentPermissions &value) {
Nick Kledzikcc3d2dc2013-01-09 01:17:12 +0000370 io.enumCase(value, "---", lld::DefinedAtom::perm___);
371 io.enumCase(value, "r--", lld::DefinedAtom::permR__);
372 io.enumCase(value, "r-x", lld::DefinedAtom::permR_X);
373 io.enumCase(value, "rw-", lld::DefinedAtom::permRW_);
374 io.enumCase(value, "rwx", lld::DefinedAtom::permRWX);
375 io.enumCase(value, "rw-l", lld::DefinedAtom::permRW_L);
376 io.enumCase(value, "unknown", lld::DefinedAtom::permUnknown);
Nick Kledzik6b079f52013-01-05 02:22:35 +0000377 }
378};
379
380template <>
381struct ScalarEnumerationTraits<lld::DefinedAtom::ContentType> {
382 static void enumeration(IO &io, lld::DefinedAtom::ContentType &value) {
383 io.enumCase(value, "unknown",
384 lld::DefinedAtom::typeUnknown);
385 io.enumCase(value, "code",
386 lld::DefinedAtom::typeCode);
387 io.enumCase(value, "stub",
388 lld::DefinedAtom::typeStub);
389 io.enumCase(value, "constant",
390 lld::DefinedAtom::typeConstant);
391 io.enumCase(value, "data",
392 lld::DefinedAtom::typeData);
393 io.enumCase(value, "zero-fill",
394 lld::DefinedAtom::typeZeroFill);
Nick Kledzikcc3d2dc2013-01-09 01:17:12 +0000395 io.enumCase(value, "const-data",
396 lld::DefinedAtom::typeConstData);
Nick Kledzik6b079f52013-01-05 02:22:35 +0000397 io.enumCase(value, "got",
398 lld::DefinedAtom::typeGOT);
399 io.enumCase(value, "resolver",
400 lld::DefinedAtom::typeResolver);
401 io.enumCase(value, "branch-island",
402 lld::DefinedAtom::typeBranchIsland);
403 io.enumCase(value, "branch-shim",
404 lld::DefinedAtom::typeBranchShim);
405 io.enumCase(value, "stub-helper",
406 lld::DefinedAtom::typeStubHelper);
407 io.enumCase(value, "c-string",
408 lld::DefinedAtom::typeCString);
409 io.enumCase(value, "utf16-string",
410 lld::DefinedAtom::typeUTF16String);
411 io.enumCase(value, "unwind-cfi",
412 lld::DefinedAtom::typeCFI);
413 io.enumCase(value, "unwind-lsda",
414 lld::DefinedAtom::typeLSDA);
415 io.enumCase(value, "const-4-byte",
416 lld::DefinedAtom::typeLiteral4);
417 io.enumCase(value, "const-8-byte",
418 lld::DefinedAtom::typeLiteral8);
419 io.enumCase(value, "const-16-byte",
420 lld::DefinedAtom::typeLiteral16);
421 io.enumCase(value, "lazy-pointer",
422 lld::DefinedAtom::typeLazyPointer);
423 io.enumCase(value, "lazy-dylib-pointer",
424 lld::DefinedAtom::typeLazyDylibPointer);
425 io.enumCase(value, "cfstring",
426 lld::DefinedAtom::typeCFString);
427 io.enumCase(value, "initializer-pointer",
428 lld::DefinedAtom::typeInitializerPtr);
429 io.enumCase(value, "terminator-pointer",
430 lld::DefinedAtom::typeTerminatorPtr);
431 io.enumCase(value, "c-string-pointer",
432 lld::DefinedAtom::typeCStringPtr);
433 io.enumCase(value, "objc-class-pointer",
434 lld::DefinedAtom::typeObjCClassPtr);
435 io.enumCase(value, "objc-category-list",
436 lld::DefinedAtom::typeObjC2CategoryList);
437 io.enumCase(value, "objc-class1",
438 lld::DefinedAtom::typeObjC1Class);
439 io.enumCase(value, "dtraceDOF",
440 lld::DefinedAtom::typeDTraceDOF);
441 io.enumCase(value, "lto-temp",
442 lld::DefinedAtom::typeTempLTO);
443 io.enumCase(value, "compact-unwind",
444 lld::DefinedAtom::typeCompactUnwindInfo);
445 io.enumCase(value, "tlv-thunk",
446 lld::DefinedAtom::typeThunkTLV);
447 io.enumCase(value, "tlv-data",
448 lld::DefinedAtom::typeTLVInitialData);
449 io.enumCase(value, "tlv-zero-fill",
450 lld::DefinedAtom::typeTLVInitialZeroFill);
451 io.enumCase(value, "tlv-initializer-ptr",
452 lld::DefinedAtom::typeTLVInitializerPtr);
453 io.enumCase(value, "first-in-section",
454 lld::DefinedAtom::typeFirstInSection);
455 io.enumCase(value, "last-in-section",
456 lld::DefinedAtom::typeLastInSection);
457 }
458};
459
460template <>
461struct ScalarEnumerationTraits<lld::UndefinedAtom::CanBeNull> {
462 static void enumeration(IO &io, lld::UndefinedAtom::CanBeNull &value) {
463 io.enumCase(value, "never", lld::UndefinedAtom::canBeNullNever);
464 io.enumCase(value, "at-runtime", lld::UndefinedAtom::canBeNullAtRuntime);
465 io.enumCase(value, "at-buildtime", lld::UndefinedAtom::canBeNullAtBuildtime);
466 }
467};
468
469
470template <>
471struct ScalarEnumerationTraits<ShlibCanBeNull> {
472 static void enumeration(IO &io, ShlibCanBeNull &value) {
473 io.enumCase(value, "never", false);
474 io.enumCase(value, "at-runtime", true);
475 }
476};
477
478
479
480/// This is a custom formatter for lld::DefinedAtom::Alignment. Values look
481/// like:
482/// 2^3 # 8-byte aligned
483/// 7 mod 2^4 # 16-byte aligned plus 7 bytes
484template<>
485struct ScalarTraits<lld::DefinedAtom::Alignment> {
486 static void output(const lld::DefinedAtom::Alignment &value, void *ctxt,
487 llvm::raw_ostream &out) {
488 if (value.modulus == 0) {
489 out << llvm::format("2^%d", value.powerOf2);
490 }
491 else {
492 out << llvm::format("%d mod 2^%d", value.modulus, value.powerOf2);
493 }
494 }
495
496 static StringRef input(StringRef scalar, void *ctxt,
497 lld::DefinedAtom::Alignment &value) {
498 value.modulus = 0;
499 size_t modStart = scalar.find("mod");
500 if (modStart != StringRef::npos) {
501 StringRef modStr = scalar.slice(0, modStart);
502 modStr = modStr.rtrim();
503 unsigned int modulus;
504 if (modStr.getAsInteger(0, modulus)) {
505 return "malformed alignment modulus";
506 }
507 value.modulus = modulus;
508 scalar = scalar.drop_front(modStart+3);
509 scalar = scalar.ltrim();
510 }
511 if (!scalar.startswith("2^")) {
512 return "malformed alignment";
513 }
514 StringRef powerStr = scalar.drop_front(2);
515 unsigned int power;
516 if (powerStr.getAsInteger(0, power)) {
517 return "malformed alignment power";
518 }
519 value.powerOf2 = power;
520 if (value.modulus > (1<<value.powerOf2)) {
521 return "malformed alignment, modulus too large for power";
522 }
523 return StringRef(); // returning empty string means success
524 }
525};
526
527
528
529
530template <>
531struct ScalarEnumerationTraits<FileKinds> {
532 static void enumeration(IO &io, FileKinds &value) {
533 io.enumCase(value, "object", fileKindObjectAtoms);
534 io.enumCase(value, "archive", fileKindArchive);
535 io.enumCase(value, "object-elf", fileKindObjectELF);
536 io.enumCase(value, "object-mach-o", fileKindObjectMachO);
537 }
538};
539
540template <>
541struct MappingTraits<ArchMember> {
542 static void mapping(IO &io, ArchMember &member) {
543 io.mapOptional("kind", member._kind, fileKindObjectAtoms);
544 io.mapOptional("name", member._name);
545 io.mapRequired("content", member._content);
546 }
547};
548
Nick Kledzik6b079f52013-01-05 02:22:35 +0000549
550
551// Declare that an AtomList is a yaml sequence.
552template<typename T>
553struct SequenceTraits<AtomList<T>> {
554 static size_t size(IO &io, AtomList<T> &seq) {
555 return seq._atoms.size();
556 }
557 static const T *&element(IO &io, AtomList<T> &seq, size_t index) {
558 if (index >= seq._atoms.size())
559 seq._atoms.resize(index+1);
560 return seq._atoms[index];
561 }
562};
563
564// Used to allow DefinedAtom content bytes to be a flow sequence of
565// two-digit hex numbers without the leading 0x (e.g. FF, 04, 0A)
566template<>
567struct ScalarTraits<ImplicitHex8> {
568 static void output(const ImplicitHex8 &val, void*, llvm::raw_ostream &out) {
569 uint8_t num = val;
570 out << llvm::format("%02X", num);
571 }
572
573 static llvm::StringRef input(llvm::StringRef str, void*, ImplicitHex8 &val) {
574 unsigned long long n;
575 if (getAsUnsignedInteger(str, 16, n))
576 return "invalid two-digit-hex number";
577 if (n > 0xFF)
578 return "out of range two-digit-hex number";
579 val = n;
580 return StringRef(); // returning empty string means success
581 }
582};
583
Nick Kledzik6b079f52013-01-05 02:22:35 +0000584
585// YAML conversion for std::vector<const lld::File*>
586template<>
587struct DocumentListTraits< std::vector<const lld::File*> > {
588 static size_t size(IO &io, std::vector<const lld::File*> &seq) {
589 return seq.size();
590 }
591 static const lld::File *&element(IO &io, std::vector<const lld::File*> &seq,
592 size_t index) {
593 if (index >= seq.size())
594 seq.resize(index+1);
595 return seq[index];
596 }
597};
598
599
600// YAML conversion for const lld::File*
601template <>
602struct MappingTraits<const lld::File*> {
603
604 class NormArchiveFile : public lld::ArchiveLibraryFile {
605 public:
606 NormArchiveFile(IO &io) : ArchiveLibraryFile(""), _path() {
607 }
608 NormArchiveFile(IO &io, const lld::File *file)
609 : ArchiveLibraryFile(file->path()),
610 _path(file->path()) {
611 // If we want to support writing archives, this constructor would
612 // need to populate _members.
613 }
614
615 const lld::File *denormalize(IO &io) {
616 return this;
617 }
Michael J. Spencer57752dc2013-01-12 02:45:54 +0000618
Nick Kledzik6b079f52013-01-05 02:22:35 +0000619 virtual const atom_collection<lld::DefinedAtom> &defined() const {
620 return _noDefinedAtoms;
621 }
622 virtual const atom_collection<lld::UndefinedAtom> &undefined() const {
623 return _noUndefinedAtoms;
624 }
625 virtual const atom_collection<lld::SharedLibraryAtom> &sharedLibrary()const{
626 return _noSharedLibaryAtoms;
627 }
628 virtual const atom_collection<lld::AbsoluteAtom> &absolute() const {
629 return _noAbsoluteAtoms;
630 }
631 virtual const File *find(StringRef name, bool dataSymbolOnly) const {
632 for (const ArchMember &member : _members) {
633 for (const lld::DefinedAtom *atom : member._content->defined() ) {
634 if (name == atom->name()) {
635 if (!dataSymbolOnly)
636 return member._content;
637 switch (atom->contentType()) {
638 case lld::DefinedAtom::typeData:
639 case lld::DefinedAtom::typeZeroFill:
640 return member._content;
641 default:
642 break;
643 }
644 }
645 }
646 }
647 return nullptr;
648 }
649
650 StringRef _path;
651 std::vector<ArchMember> _members;
652 };
653
654
655 class NormalizedFile : public lld::File {
656 public:
657 NormalizedFile(IO &io) : File(""), _rnb(nullptr) {
658 }
659 NormalizedFile(IO &io, const lld::File *file)
660 : File(file->path()),
661 _rnb(new RefNameBuilder(*file)),
662 _path(file->path()) {
663 for (const lld::DefinedAtom *a : file->defined())
664 _definedAtoms.push_back(a);
665 for (const lld::UndefinedAtom *a : file->undefined())
666 _undefinedAtoms.push_back(a);
667 for (const lld::SharedLibraryAtom *a : file->sharedLibrary())
668 _sharedLibraryAtoms.push_back(a);
669 for (const lld::AbsoluteAtom *a : file->absolute())
670 _absoluteAtoms.push_back(a);
671 }
672 const lld::File *denormalize(IO &io);
Michael J. Spencer57752dc2013-01-12 02:45:54 +0000673
Nick Kledzik6b079f52013-01-05 02:22:35 +0000674 virtual const atom_collection<lld::DefinedAtom> &defined() const {
675 return _definedAtoms;
676 }
677 virtual const atom_collection<lld::UndefinedAtom> &undefined() const {
678 return _undefinedAtoms;
679 }
680 virtual const atom_collection<lld::SharedLibraryAtom> &sharedLibrary()const{
681 return _sharedLibraryAtoms;
682 }
683 virtual const atom_collection<lld::AbsoluteAtom> &absolute() const {
684 return _absoluteAtoms;
685 }
686
687 // Allocate a new copy of this string and keep track of allocations
688 // in _stringCopies, so they can be freed when File is destroyed.
689 StringRef copyString(StringRef str) {
690 // We want _stringCopies to own the string memory so it is deallocated
691 // when the File object is destroyed. But we need a StringRef that
692 // points into that memory.
693 std::unique_ptr<char> s = std::unique_ptr<char>(new char[str.size()]);
694 memcpy(s.get(), str.data(), str.size());
695 llvm::StringRef r = llvm::StringRef(s.get(), str.size());
696 _stringCopies.push_back(std::move(s));
697 return r;
698 }
699
700 RefNameBuilder *_rnb;
701 StringRef _path;
702 AtomList<lld::DefinedAtom> _definedAtoms;
703 AtomList<lld::UndefinedAtom> _undefinedAtoms;
704 AtomList<lld::SharedLibraryAtom> _sharedLibraryAtoms;
705 AtomList<lld::AbsoluteAtom> _absoluteAtoms;
706 std::vector<std::unique_ptr<char>> _stringCopies;
707 };
708
709
710 static void mapping(IO &io, const lld::File *&file) {
711 // We only support writing atom based YAML
712 FileKinds kind = fileKindObjectAtoms;
713 // If reading, peek ahead to see what kind of file this is.
714 io.mapOptional("kind", kind, fileKindObjectAtoms);
715 //
716 switch (kind) {
717 case fileKindObjectAtoms:
718 mappingAtoms(io, file);
719 break;
720 case fileKindArchive:
721 mappingArchive(io, file);
722 break;
723 case fileKindObjectELF:
724 case fileKindObjectMachO:
725 // Eventually we will have an external function to call, similar
726 // to mappingAtoms() and mappingArchive() but implememented
727 // with coresponding file format code.
Nick Kledzik6b079f52013-01-05 02:22:35 +0000728 llvm_unreachable("section based YAML not supported yet");
729 }
730 }
731
732 static void mappingAtoms(IO &io, const lld::File *&file) {
733 MappingNormalizationHeap<NormalizedFile, const lld::File*> keys(io, file);
734 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
735 assert(info != nullptr);
736 info->_currentFile = keys.operator->();
737
738 io.mapOptional("path", keys->_path);
739 io.mapOptional("defined-atoms", keys->_definedAtoms);
740 io.mapOptional("undefined-atoms", keys->_undefinedAtoms);
741 io.mapOptional("shared-library-atoms", keys->_sharedLibraryAtoms);
742 io.mapOptional("absolute-atoms", keys->_absoluteAtoms);
743 }
744
745 static void mappingArchive(IO &io, const lld::File *&file) {
746 MappingNormalizationHeap<NormArchiveFile, const lld::File*> keys(io, file);
747
748 io.mapOptional("path", keys->_path);
749 io.mapOptional("members", keys->_members);
750 }
751
752};
753
754
755
756// YAML conversion for const lld::Reference*
757template <>
758struct MappingTraits<const lld::Reference*> {
759
760 class NormalizedReference : public lld::Reference {
761 public:
762 NormalizedReference(IO &io)
763 : _target(nullptr), _targetName(), _offset(0), _addend(0) , _kind(0) {
764 }
765 NormalizedReference(IO &io, const lld::Reference *ref)
766 : _target(nullptr),
767 _targetName(targetName(io, ref)),
768 _offset(ref->offsetInAtom()),
769 _addend(ref->addend()),
770 _kind(ref->kind()) {
771 }
772 const lld::Reference *denormalize(IO &io) {
773 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
774 assert(info != nullptr);
775 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
776 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
777 if (!_targetName.empty())
778 _targetName = f->copyString(_targetName);
779 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
780 << "created Reference to name: '" << _targetName
781 << "' (" << (void*)_targetName.data() << ", "
782 << _targetName.size() << ")\n");
783 return this;
784 }
785 void bind(const RefNameResolver&);
786 static StringRef targetName(IO &io, const lld::Reference *ref);
787
788 virtual uint64_t offsetInAtom() const { return _offset; }
789 virtual Kind kind() const { return _kind; }
790 virtual const lld::Atom *target() const { return _target; }
791 virtual Addend addend() const { return _addend; }
792 virtual void setKind(Kind k) { _kind = k; }
793 virtual void setAddend(Addend a) { _addend = a; }
794 virtual void setTarget(const lld::Atom *a) { _target = a; }
795
796 const lld::Atom *_target;
797 StringRef _targetName;
798 uint32_t _offset;
799 Addend _addend;
800 RefKind _kind;
801 };
802
803
804 static void mapping(IO &io, const lld::Reference *&ref) {
805 MappingNormalizationHeap<NormalizedReference,
806 const lld::Reference*> keys(io, ref);
807
808 io.mapRequired("kind", keys->_kind);
809 io.mapOptional("offset", keys->_offset);
810 io.mapOptional("target", keys->_targetName);
811 io.mapOptional("addend", keys->_addend, (lld::Reference::Addend)0);
812 }
813};
814
Nick Kledzik6b079f52013-01-05 02:22:35 +0000815
816
817// YAML conversion for const lld::DefinedAtom*
818template <>
819struct MappingTraits<const lld::DefinedAtom*> {
820
821 class NormalizedAtom : public lld::DefinedAtom {
822 public:
823 NormalizedAtom(IO &io)
824 : _file(fileFromContext(io)), _name(), _refName(),
825 _alignment(0), _content(), _references() {
826 }
827 NormalizedAtom(IO &io, const lld::DefinedAtom *atom)
828 : _file(fileFromContext(io)),
829 _name(atom->name()),
830 _refName(),
831 _scope(atom->scope()),
832 _interpose(atom->interposable()),
833 _merge(atom->merge()),
834 _contentType(atom->contentType()),
835 _alignment(atom->alignment()),
836 _sectionChoice(atom->sectionChoice()),
837 _deadStrip(atom->deadStrip()),
838 _permissions(atom->permissions()),
839 _size(atom->size()),
840 _sectionName(atom->customSectionName()) {
841 for ( const lld::Reference *r : *atom )
842 _references.push_back(r);
843 ArrayRef<uint8_t> cont = atom->rawContent();
844 _content.reserve(cont.size());
845 for (uint8_t x : cont)
846 _content.push_back(x);
847 }
848 const lld::DefinedAtom *denormalize(IO &io) {
849 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
850 assert(info != nullptr);
851 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
852 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
853 if ( !_name.empty() )
854 _name = f->copyString(_name);
855 if ( !_refName.empty() )
856 _refName = f->copyString(_refName);
857 if ( !_sectionName.empty() )
858 _sectionName = f->copyString(_sectionName);
859 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
860 << "created DefinedAtom named: '" << _name
861 << "' (" << (void*)_name.data() << ", "
862 << _name.size() << ")\n");
863 return this;
864 }
865 void bind(const RefNameResolver&);
866 // Extract current File object from YAML I/O parsing context
867 const lld::File &fileFromContext(IO &io) {
868 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
869 assert(info != nullptr);
870 assert(info->_currentFile != nullptr);
871 return *info->_currentFile;
872 }
873
874 virtual const lld::File &file() const { return _file; }
875 virtual StringRef name() const { return _name; }
876 virtual uint64_t size() const { return _size; }
877 virtual Scope scope() const { return _scope; }
878 virtual Interposable interposable() const { return _interpose; }
879 virtual Merge merge() const { return _merge; }
880 virtual ContentType contentType() const { return _contentType; }
881 virtual Alignment alignment() const { return _alignment; }
882 virtual SectionChoice sectionChoice() const { return _sectionChoice; }
883 virtual StringRef customSectionName() const { return _sectionName;}
884 virtual DeadStripKind deadStrip() const { return _deadStrip; }
885 virtual ContentPermissions permissions() const { return _permissions; }
886 virtual bool isThumb() const { return false; }
887 virtual bool isAlias() const { return false; }
Michael J. Spencer74ba7222013-01-13 01:09:39 +0000888 ArrayRef<uint8_t> rawContent() const {
889 return ArrayRef<uint8_t>(
890 reinterpret_cast<const uint8_t *>(_content.data()), _content.size());
891 }
892
Nick Kledzik6b079f52013-01-05 02:22:35 +0000893 virtual uint64_t ordinal() const { return 0; }
894
895 reference_iterator begin() const {
896 uintptr_t index = 0;
897 const void *it = reinterpret_cast<const void*>(index);
898 return reference_iterator(*this, it);
899 }
900 reference_iterator end() const {
901 uintptr_t index = _references.size();
902 const void *it = reinterpret_cast<const void*>(index);
903 return reference_iterator(*this, it);
904 }
905 const lld::Reference *derefIterator(const void *it) const {
906 uintptr_t index = reinterpret_cast<uintptr_t>(it);
907 assert(index < _references.size());
908 return _references[index];
909 }
910 void incrementIterator(const void *&it) const {
911 uintptr_t index = reinterpret_cast<uintptr_t>(it);
912 ++index;
913 it = reinterpret_cast<const void*>(index);
914 }
915
916 const lld::File &_file;
917 StringRef _name;
918 StringRef _refName;
919 Scope _scope;
920 Interposable _interpose;
921 Merge _merge;
922 ContentType _contentType;
923 Alignment _alignment;
924 SectionChoice _sectionChoice;
925 DeadStripKind _deadStrip;
926 ContentPermissions _permissions;
927 std::vector<ImplicitHex8> _content;
928 uint64_t _size;
929 StringRef _sectionName;
930 std::vector<const lld::Reference*> _references;
931 };
932
933 static void mapping(IO &io, const lld::DefinedAtom *&atom) {
934 MappingNormalizationHeap<NormalizedAtom,
935 const lld::DefinedAtom*> keys(io, atom);
936 if ( io.outputting() ) {
937 // If writing YAML, check if atom needs a ref-name.
938 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
939 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
940 assert(info != nullptr);
941 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
942 assert(f);
943 assert(f->_rnb);
944 if ( f->_rnb->hasRefName(atom) ) {
945 keys->_refName = f->_rnb->refName(atom);
946 }
947 }
948
949 io.mapOptional("name", keys->_name,
950 StringRef());
951 io.mapOptional("ref-name", keys->_refName,
952 StringRef());
953 io.mapOptional("scope", keys->_scope,
954 lld::DefinedAtom::scopeTranslationUnit);
955 io.mapOptional("type", keys->_contentType,
956 lld::DefinedAtom::typeCode);
957 io.mapOptional("content", keys->_content);
958 io.mapOptional("size", keys->_size,
959 (uint64_t)keys->_content.size());
960 io.mapOptional("interposable", keys->_interpose,
961 lld::DefinedAtom::interposeNo);
962 io.mapOptional("merge", keys->_merge,
963 lld::DefinedAtom::mergeNo);
964 io.mapOptional("alignment", keys->_alignment,
965 lld::DefinedAtom::Alignment(0));
966 io.mapOptional("section-choice", keys->_sectionChoice,
967 lld::DefinedAtom::sectionBasedOnContent);
968 io.mapOptional("section-name", keys->_sectionName,
969 StringRef());
970 io.mapOptional("dead-strip", keys->_deadStrip,
971 lld::DefinedAtom::deadStripNormal);
Nick Kledzikcc3d2dc2013-01-09 01:17:12 +0000972 // default permissions based on content type
973 io.mapOptional("permissions", keys->_permissions,
974 lld::DefinedAtom::permissions(
975 keys->_contentType));
Nick Kledzik8a3052e2013-01-08 21:12:13 +0000976 io.mapOptional("references", keys->_references);
Nick Kledzik6b079f52013-01-05 02:22:35 +0000977 }
978};
979
980
981
982
Nick Kledzik6b079f52013-01-05 02:22:35 +0000983// YAML conversion for const lld::UndefinedAtom*
984template <>
985struct MappingTraits<const lld::UndefinedAtom*> {
986
987 class NormalizedAtom : public lld::UndefinedAtom {
988 public:
989 NormalizedAtom(IO &io)
990 : _file(fileFromContext(io)), _name(), _canBeNull(canBeNullNever) {
991 }
992 NormalizedAtom(IO &io, const lld::UndefinedAtom *atom)
993 : _file(fileFromContext(io)),
994 _name(atom->name()),
995 _canBeNull(atom->canBeNull()) {
996 }
997 const lld::UndefinedAtom *denormalize(IO &io) {
998 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
999 assert(info != nullptr);
1000 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1001 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1002 if ( !_name.empty() )
1003 _name = f->copyString(_name);
1004
1005 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
1006 << "created UndefinedAtom named: '" << _name
1007 << "' (" << (void*)_name.data() << ", "
1008 << _name.size() << ")\n");
1009 return this;
1010 }
1011 // Extract current File object from YAML I/O parsing context
1012 const lld::File &fileFromContext(IO &io) {
1013 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1014 assert(info != nullptr);
1015 assert(info->_currentFile != nullptr);
1016 return *info->_currentFile;
1017 }
1018
1019 virtual const lld::File &file() const { return _file; }
1020 virtual StringRef name() const { return _name; }
1021 virtual CanBeNull canBeNull() const { return _canBeNull; }
1022
1023 const lld::File &_file;
1024 StringRef _name;
1025 CanBeNull _canBeNull;
1026 };
1027
1028
1029 static void mapping(IO &io, const lld::UndefinedAtom* &atom) {
1030 MappingNormalizationHeap<NormalizedAtom,
1031 const lld::UndefinedAtom*> keys(io, atom);
1032
1033 io.mapRequired("name", keys->_name);
1034 io.mapOptional("can-be-null", keys->_canBeNull,
1035 lld::UndefinedAtom::canBeNullNever);
1036 }
1037};
1038
1039
1040// YAML conversion for const lld::SharedLibraryAtom*
1041template <>
1042struct MappingTraits<const lld::SharedLibraryAtom*> {
1043
1044 class NormalizedAtom : public lld::SharedLibraryAtom {
1045 public:
1046 NormalizedAtom(IO &io)
1047 : _file(fileFromContext(io)), _name(), _loadName(), _canBeNull(false) {
1048 }
1049 NormalizedAtom(IO &io, const lld::SharedLibraryAtom *atom)
1050 : _file(fileFromContext(io)),
1051 _name(atom->name()),
1052 _loadName(atom->loadName()),
1053 _canBeNull(atom->canBeNullAtRuntime()) {
1054 }
1055 const lld::SharedLibraryAtom *denormalize(IO &io) {
1056 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1057 assert(info != nullptr);
1058 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1059 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1060 if ( !_name.empty() )
1061 _name = f->copyString(_name);
1062 if ( !_loadName.empty() )
1063 _loadName = f->copyString(_loadName);
1064
1065 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
1066 << "created SharedLibraryAtom named: '" << _name
1067 << "' (" << (void*)_name.data() << ", "
1068 << _name.size() << ")\n");
1069 return this;
1070 }
1071 // Extract current File object from YAML I/O parsing context
1072 const lld::File &fileFromContext(IO &io) {
1073 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1074 assert(info != nullptr);
1075 assert(info->_currentFile != nullptr);
1076 return *info->_currentFile;
1077 }
1078
1079 virtual const lld::File &file() const { return _file; }
1080 virtual StringRef name() const { return _name; }
1081 virtual StringRef loadName() const { return _loadName;}
1082 virtual bool canBeNullAtRuntime() const { return _canBeNull; }
1083
1084 const lld::File &_file;
1085 StringRef _name;
1086 StringRef _loadName;
1087 ShlibCanBeNull _canBeNull;
1088 };
1089
1090
1091 static void mapping(IO &io, const lld::SharedLibraryAtom *&atom) {
1092
1093 MappingNormalizationHeap<NormalizedAtom,
1094 const lld::SharedLibraryAtom*> keys(io, atom);
1095
1096 io.mapRequired("name", keys->_name);
1097 io.mapOptional("load-name", keys->_loadName);
1098 io.mapOptional("can-be-null", keys->_canBeNull,
1099 (ShlibCanBeNull)false);
1100 }
1101};
1102
1103
1104// YAML conversion for const lld::AbsoluteAtom*
1105template <>
1106struct MappingTraits<const lld::AbsoluteAtom*> {
1107
1108 class NormalizedAtom : public lld::AbsoluteAtom {
1109 public:
1110 NormalizedAtom(IO &io)
1111 : _file(fileFromContext(io)), _name(), _scope(), _value(0) {
1112 }
1113 NormalizedAtom(IO &io, const lld::AbsoluteAtom *atom)
1114 : _file(fileFromContext(io)),
1115 _name(atom->name()),
1116 _scope(atom->scope()),
1117 _value(atom->value()) {
1118 }
1119 const lld::AbsoluteAtom *denormalize(IO &io) {
1120 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1121 assert(info != nullptr);
1122 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1123 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1124 if ( !_name.empty() )
1125 _name = f->copyString(_name);
1126
1127 DEBUG_WITH_TYPE("WriterYAML", llvm::dbgs()
1128 << "created AbsoluteAtom named: '" << _name
1129 << "' (" << (void*)_name.data() << ", "
1130 << _name.size() << ")\n");
1131 return this;
1132 }
1133 // Extract current File object from YAML I/O parsing context
1134 const lld::File &fileFromContext(IO &io) {
1135 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1136 assert(info != nullptr);
1137 assert(info->_currentFile != nullptr);
1138 return *info->_currentFile;
1139 }
1140
1141 virtual const lld::File &file() const { return _file; }
1142 virtual StringRef name() const { return _name; }
1143 virtual uint64_t value() const { return _value; }
1144 virtual Scope scope() const { return _scope; }
1145
1146 const lld::File &_file;
1147 StringRef _name;
1148 StringRef _refName;
1149 Scope _scope;
1150 Hex64 _value;
1151 };
1152
1153
1154 static void mapping(IO &io, const lld::AbsoluteAtom *&atom) {
1155 MappingNormalizationHeap<NormalizedAtom,
1156 const lld::AbsoluteAtom*> keys(io, atom);
1157
1158 if ( io.outputting() ) {
1159 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1160 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1161 assert(info != nullptr);
1162 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1163 assert(f);
1164 assert(f->_rnb);
1165 if ( f->_rnb->hasRefName(atom) ) {
1166 keys->_refName = f->_rnb->refName(atom);
1167 }
1168 }
1169
1170 io.mapRequired("name", keys->_name);
1171 io.mapOptional("ref-name", keys->_refName, StringRef());
1172 io.mapOptional("scope", keys->_scope);
1173 io.mapRequired("value", keys->_value);
1174 }
1175};
1176
Nick Kledzikbd491982013-01-08 23:51:03 +00001177} // namespace llvm
1178} // namespace yaml
1179
Nick Kledzik6b079f52013-01-05 02:22:35 +00001180
1181RefNameResolver::RefNameResolver(const lld::File *file, IO &io) : _io(io) {
1182 typedef MappingTraits<const lld::DefinedAtom*>::NormalizedAtom NormalizedAtom;
1183 for (const lld::DefinedAtom *a : file->defined() ) {
1184 NormalizedAtom *na = (NormalizedAtom*)a;
1185 if ( na->_refName.empty() )
1186 add(na->_name, a);
1187 else
1188 add(na->_refName, a);
1189 }
1190
1191 for (const lld::UndefinedAtom *a : file->undefined() )
1192 add(a->name(), a);
1193
1194 for (const lld::SharedLibraryAtom *a : file->sharedLibrary() )
1195 add(a->name(), a);
1196
1197 typedef MappingTraits<const lld::AbsoluteAtom*>::NormalizedAtom NormAbsAtom;
1198 for (const lld::AbsoluteAtom *a : file->absolute() ) {
1199 NormAbsAtom *na = (NormAbsAtom*)a;
1200 if ( na->_refName.empty() )
1201 add(na->_name, a);
1202 else
1203 add(na->_refName, a);
1204 }
1205}
1206
1207
Nick Kledzikbd491982013-01-08 23:51:03 +00001208
1209inline
1210const lld::File*
1211MappingTraits<const lld::File*>::NormalizedFile::denormalize(IO &io) {
1212 typedef MappingTraits<const lld::DefinedAtom*>::NormalizedAtom NormalizedAtom;
1213
1214 RefNameResolver nameResolver(this, io);
1215 // Now that all atoms are parsed, references can be bound.
1216 for (const lld::DefinedAtom *a : this->defined() ) {
1217 NormalizedAtom *normAtom = (NormalizedAtom*)a;
1218 normAtom->bind(nameResolver);
1219 }
1220 return this;
1221}
1222
1223inline
1224void MappingTraits<const lld::DefinedAtom*>::
1225 NormalizedAtom::bind(const RefNameResolver &resolver) {
1226 typedef MappingTraits<const lld::Reference*>::NormalizedReference
1227 NormalizedReference;
1228 for (const lld::Reference *ref : _references) {
1229 NormalizedReference *normRef = (NormalizedReference*)ref;
1230 normRef->bind(resolver);
1231 }
1232}
1233
1234inline
1235void MappingTraits<const lld::Reference*>::
1236 NormalizedReference::bind(const RefNameResolver &resolver) {
1237 _target = resolver.lookup(_targetName);
1238}
1239
1240
Nick Kledzik6b079f52013-01-05 02:22:35 +00001241inline
1242llvm::StringRef MappingTraits<const lld::Reference*>::NormalizedReference::
1243 targetName(IO &io, const lld::Reference *ref) {
1244 if ( ref->target() == nullptr )
1245 return llvm::StringRef();
1246 ContextInfo *info = reinterpret_cast<ContextInfo*>(io.getContext());
1247 assert(info != nullptr);
1248 typedef MappingTraits<const lld::File*>::NormalizedFile NormalizedFile;
1249 NormalizedFile *f = reinterpret_cast<NormalizedFile*>(info->_currentFile);
1250 RefNameBuilder *rnb = f->_rnb;
1251 if ( rnb->hasRefName(ref->target()) )
1252 return rnb->refName(ref->target());
1253 return ref->target()->name();
1254}
1255
1256
1257
1258namespace lld {
1259namespace yaml {
1260
1261class Writer : public lld::Writer {
1262public:
1263 Writer(const WriterOptionsYAML &options) : _options(options) {
1264 }
1265
1266 virtual error_code writeFile(const lld::File &file, StringRef outPath) {
1267 // Create stream to path.
1268 std::string errorInfo;
1269 llvm::raw_fd_ostream out(outPath.data(), errorInfo);
1270 if (!errorInfo.empty())
1271 return llvm::make_error_code(llvm::errc::no_such_file_or_directory);
1272
1273 // Create yaml Output writer, using yaml options for context.
1274 ContextInfo context(_options);
1275 llvm::yaml::Output yout(out, &context);
1276
1277 // Write yaml output.
1278 const lld::File *fileRef = &file;
1279 yout << fileRef;
1280
1281 return error_code::success();
1282 }
1283
1284 virtual StubsPass *stubPass() {
1285 return _options.stubPass();
1286 }
1287
1288 virtual GOTPass *gotPass() {
1289 return _options.gotPass();
1290 }
1291
1292
1293private:
1294 const WriterOptionsYAML &_options;
1295};
1296
1297
1298
1299class ReaderYAML : public Reader {
1300public:
1301 ReaderYAML(const ReaderOptionsYAML &options) : _options(options) {
1302 }
1303
1304 error_code parseFile(std::unique_ptr<MemoryBuffer> mb,
1305 std::vector<std::unique_ptr<File>> &result) {
1306 // Note: we do not take ownership of the MemoryBuffer. That is
1307 // because yaml may produce multiple File objects, so there is no
1308 // *one* File to take ownership. Therefore, the yaml File objects
1309 // produced must make copies of all strings that come from YAML I/O.
1310 // Otherwise the strings will become invalid when this MemoryBuffer
1311 // is deallocated.
1312
1313 // Create YAML Input parser.
1314 ContextInfo context(_options);
1315 llvm::yaml::Input yin(mb->getBuffer(), &context);
1316
1317 // Fill vector with File objects created by parsing yaml.
1318 std::vector<const lld::File*> createdFiles;
1319 yin >> createdFiles;
1320
1321 // Quit now if there were parsing errors.
1322 if ( yin.error() )
1323 return make_error_code(lld::yaml_reader_error::illegal_value);
1324
1325 for (const File *file : createdFiles) {
1326 // Note: parseFile() should return vector of *const* File
1327 File *f = const_cast<File*>(file);
1328 result.emplace_back(f);
1329 }
1330 return make_error_code(lld::yaml_reader_error::success);
1331 }
1332
1333private:
1334 const ReaderOptionsYAML &_options;
1335};
1336
1337
1338
1339} // namespace yaml
1340
1341
1342Writer *createWriterYAML(const WriterOptionsYAML &options) {
1343 return new lld::yaml::Writer(options);
1344}
1345
1346WriterOptionsYAML::WriterOptionsYAML() {
1347}
1348
1349WriterOptionsYAML::~WriterOptionsYAML() {
1350}
1351
1352
1353
1354Reader *createReaderYAML(const ReaderOptionsYAML &options) {
1355 return new lld::yaml::ReaderYAML(options);
1356}
1357
1358ReaderOptionsYAML::ReaderOptionsYAML() {
1359}
1360
1361ReaderOptionsYAML::~ReaderOptionsYAML() {
1362}
1363
1364
1365} // namespace lld
1366