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