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