blob: c3a7f235454de2af2a3bf6ecc087fc5cc505cab0 [file] [log] [blame]
Michael J. Spencer773a8fb2011-12-18 08:27:59 +00001//===- Core/YamlWriter.cpp - Writes YAML ----------------------------------===//
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
Nick Kledzik7735a7d2012-01-04 23:58:17 +000010#include "YamlKeyValues.h"
11
Michael J. Spencer773a8fb2011-12-18 08:27:59 +000012#include "lld/Core/YamlWriter.h"
13#include "lld/Core/Atom.h"
14#include "lld/Core/File.h"
15#include "lld/Core/Reference.h"
16
17#include "llvm/ADT/OwningPtr.h"
Nick Kledzik49d6cc82012-02-15 00:38:09 +000018#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/StringExtras.h"
Nick Kledzikbfedfc12012-01-09 20:18:15 +000020#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/StringExtras.h"
Michael J. Spencer773a8fb2011-12-18 08:27:59 +000022#include "llvm/Support/DataTypes.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/Support/system_error.h"
25
26#include <vector>
27
28namespace lld {
29namespace yaml {
30
Nick Kledzik49d6cc82012-02-15 00:38:09 +000031namespace {
32///
33/// In most cases, atoms names are unambiguous, so references can just
34/// use the atom name as the target (e.g. target: foo). But in a few
35/// cases that does not work, so ref-names are added. These are labels
36/// used only in yaml. The labels do not exist in the Atom model.
37///
38/// One need for ref-names are when atoms have no user supplied name
39/// (e.g. c-string literal). Another case is when two object files with
40/// identically named static functions are merged (ld -r) into one object file.
41/// In that case referencing the function by name is ambiguous, so a unique
42/// ref-name is added.
43///
44class RefNameBuilder : public File::AtomHandler,
45 public DefinedAtom::ReferenceHandler {
Michael J. Spencer773a8fb2011-12-18 08:27:59 +000046public:
Nick Kledzik49d6cc82012-02-15 00:38:09 +000047 RefNameBuilder() { }
48
49 virtual void doReference(const Reference& ref) {
50 // create refname for any unnamed reference target
51 if ( ref.target()->name().empty() ) {
52 char* buffer;
53 asprintf(&buffer, "L%03d", _unnamedCounter++);
54 _refNames[ref.target()] = buffer;
55 }
56 }
57
58 virtual void doFile(const File &) { }
59
60 virtual void doDefinedAtom(const DefinedAtom& atom) {
61 // Build map of atoms names to detect duplicates
62 if ( ! atom.name().empty() )
63 buildDuplicateNameMap(atom);
64
65 // Find references to unnamed atoms and create ref-names for them.
66 _unnamedCounter = 0;
67 atom.forEachReference(*this);
68 }
69
70 virtual void doUndefinedAtom(const UndefinedAtom& atom) {
71 buildDuplicateNameMap(atom);
72 }
73
Nick Kledzik6bc04c62012-02-22 21:56:59 +000074 virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
75 buildDuplicateNameMap(atom);
76 }
77
78 virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
79 buildDuplicateNameMap(atom);
80 }
81
Nick Kledzik49d6cc82012-02-15 00:38:09 +000082 void buildDuplicateNameMap(const Atom& atom) {
83 assert(!atom.name().empty());
84 NameToAtom::iterator pos = _nameMap.find(atom.name());
85 if ( pos != _nameMap.end() ) {
86 // Found name collision, give each a unique ref-name.
87 char* buffer;
88 asprintf(&buffer, "%s.%03d", atom.name().data(), ++_collisionCount);
89 _refNames[&atom] = buffer;
90 const Atom* prevAtom = pos->second;
91 AtomToRefName::iterator pos2 = _refNames.find(prevAtom);
92 if ( pos2 == _refNames.end() ) {
93 // only create ref-name for previous if none already created
94 asprintf(&buffer, "%s.%03d", prevAtom->name().data(), ++_collisionCount);
95 _refNames[prevAtom] = buffer;
96 }
97 }
98 else {
99 // First time we've seen this name, just add it to map.
100 _nameMap[atom.name()] = &atom;
101 }
102 }
103
104 bool hasRefName(const Atom* atom) {
105 return _refNames.count(atom);
106 }
107
108 const char* refName(const Atom* atom) {
109 return _refNames.find(atom)->second;
110 }
111
112private:
113 struct MyMappingInfo {
114 static llvm::StringRef getEmptyKey() { return llvm::StringRef(); }
115 static llvm::StringRef getTombstoneKey() { return llvm::StringRef(" ", 0); }
116 static unsigned getHashValue(llvm::StringRef const val) {
117 return llvm::HashString(val); }
118 static bool isEqual(llvm::StringRef const lhs,
119 llvm::StringRef const rhs) { return lhs.equals(rhs); }
120 };
121 typedef llvm::DenseMap<llvm::StringRef, const Atom*, MyMappingInfo> NameToAtom;
122 typedef llvm::DenseMap<const Atom*, const char*> AtomToRefName;
123
124 unsigned int _collisionCount;
125 unsigned int _unnamedCounter;
126 NameToAtom _nameMap;
127 AtomToRefName _refNames;
128};
129
130
131///
132/// Helper class for writeObjectText() to write out atoms in yaml format.
133///
134class AtomWriter : public File::AtomHandler,
135 public DefinedAtom::ReferenceHandler {
136public:
137 AtomWriter(RefNameBuilder& rnb, llvm::raw_ostream &out)
138 : _out(out), _rnb(rnb), _firstAtom(true) { }
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000139
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000140 virtual void doFile(const class File &) { _firstAtom = true; }
141
Nick Kledzikf4fb2c52012-01-11 01:06:19 +0000142 virtual void doDefinedAtom(const class DefinedAtom &atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000143 if ( _firstAtom ) {
144 _out << "atoms:\n";
145 _firstAtom = false;
146 }
147 else {
148 // add blank line between atoms for readability
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000149 _out << "\n";
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000150 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000151
152 bool hasDash = false;
153 if ( !atom.name().empty() ) {
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000154 _out << " - "
155 << KeyValues::nameKeyword
156 << ":"
157 << spacePadding(KeyValues::nameKeyword)
158 << atom.name()
159 << "\n";
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000160 hasDash = true;
161 }
162
163 if ( _rnb.hasRefName(&atom) ) {
164 _out << (hasDash ? " " : " - ")
165 << KeyValues::refNameKeyword
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000166 << ":"
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000167 << spacePadding(KeyValues::refNameKeyword)
168 << _rnb.refName(&atom)
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000169 << "\n";
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000170 hasDash = true;
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000171 }
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000172
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000173 if ( atom.definition() != KeyValues::definitionDefault ) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000174 _out << (hasDash ? " " : " - ")
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000175 << KeyValues::definitionKeyword
176 << ":"
177 << spacePadding(KeyValues::definitionKeyword)
178 << KeyValues::definition(atom.definition())
179 << "\n";
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000180 hasDash = true;
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000181 }
182
183 if ( atom.scope() != KeyValues::scopeDefault ) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000184 _out << (hasDash ? " " : " - ")
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000185 << KeyValues::scopeKeyword
186 << ":"
187 << spacePadding(KeyValues::scopeKeyword)
188 << KeyValues::scope(atom.scope())
189 << "\n";
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000190 hasDash = true;
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000191 }
192
Nick Kledzikf4fb2c52012-01-11 01:06:19 +0000193 if ( atom.interposable() != KeyValues::interposableDefault ) {
194 _out << " "
195 << KeyValues::interposableKeyword
196 << ":"
197 << spacePadding(KeyValues::interposableKeyword)
198 << KeyValues::interposable(atom.interposable())
199 << "\n";
200 }
201
Nick Kledzik23384e82012-02-07 02:59:54 +0000202 if ( atom.merge() != KeyValues::mergeDefault ) {
Nick Kledzikf4fb2c52012-01-11 01:06:19 +0000203 _out << " "
204 << KeyValues::mergeKeyword
205 << ":"
206 << spacePadding(KeyValues::mergeKeyword)
207 << KeyValues::merge(atom.merge())
208 << "\n";
209 }
210
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000211 if ( atom.contentType() != KeyValues::contentTypeDefault ) {
212 _out << " "
213 << KeyValues::contentTypeKeyword
214 << ":"
215 << spacePadding(KeyValues::contentTypeKeyword)
216 << KeyValues::contentType(atom.contentType())
217 << "\n";
218 }
219
220 if ( atom.deadStrip() != KeyValues::deadStripKindDefault ) {
221 _out << " "
222 << KeyValues::deadStripKindKeyword
223 << ":"
224 << spacePadding(KeyValues::deadStripKindKeyword)
225 << KeyValues::deadStripKind(atom.deadStrip())
226 << "\n";
227 }
228
229 if ( atom.sectionChoice() != KeyValues::sectionChoiceDefault ) {
230 _out << " "
231 << KeyValues::sectionChoiceKeyword
232 << ":"
233 << spacePadding(KeyValues::sectionChoiceKeyword)
234 << KeyValues::sectionChoice(atom.sectionChoice())
235 << "\n";
236 assert( ! atom.customSectionName().empty() );
237 _out << " "
238 << KeyValues::sectionNameKeyword
239 << ":"
240 << spacePadding(KeyValues::sectionNameKeyword)
241 << atom.customSectionName()
242 << "\n";
243 }
244
Nick Kledzik23384e82012-02-07 02:59:54 +0000245 if ( atom.isThumb() != KeyValues::isThumbDefault ) {
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000246 _out << " "
247 << KeyValues::isThumbKeyword
248 << ":"
249 << spacePadding(KeyValues::isThumbKeyword)
250 << KeyValues::isThumb(atom.isThumb())
251 << "\n";
252 }
253
254 if ( atom.isAlias() != KeyValues::isAliasDefault ) {
255 _out << " "
256 << KeyValues::isAliasKeyword
257 << ":"
258 << spacePadding(KeyValues::isAliasKeyword)
259 << KeyValues::isAlias(atom.isAlias())
260 << "\n";
261 }
262
Nick Kledzik23384e82012-02-07 02:59:54 +0000263 if ( (atom.contentType() != DefinedAtom::typeZeroFill)
264 && (atom.size() != 0) ) {
Nick Kledzikbfedfc12012-01-09 20:18:15 +0000265 _out << " "
266 << KeyValues::contentKeyword
267 << ":"
268 << spacePadding(KeyValues::contentKeyword)
269 << "[ ";
270 llvm::ArrayRef<uint8_t> arr = atom.rawContent();
271 bool needComma = false;
272 for (unsigned int i=0; i < arr.size(); ++i) {
273 if ( needComma )
274 _out << ", ";
275 _out << hexdigit(arr[i] >> 4);
276 _out << hexdigit(arr[i] & 0x0F);
277 needComma = true;
278 }
279 _out << " ]\n";
280 }
281
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000282 _wroteFirstFixup = false;
283 atom.forEachReference(*this);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000284 }
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000285
286 virtual void doReference(const Reference& ref) {
287 if ( !_wroteFirstFixup ) {
288 _out << " fixups:\n";
289 _wroteFirstFixup = true;
290 }
291 _out << " - "
292 << KeyValues::fixupsOffsetKeyword
293 << ":"
294 << spacePadding(KeyValues::fixupsOffsetKeyword)
295 << ref.offsetInAtom()
296 << "\n";
297 _out << " "
298 << KeyValues::fixupsKindKeyword
299 << ":"
300 << spacePadding(KeyValues::fixupsKindKeyword)
301 << ref.kind()
302 << "\n";
303 const Atom* target = ref.target();
304 if ( target != NULL ) {
305 llvm::StringRef refName = target->name();
306 if ( _rnb.hasRefName(target) )
307 refName = _rnb.refName(target);
308 assert(!refName.empty());
309 _out << " "
310 << KeyValues::fixupsTargetKeyword
311 << ":"
312 << spacePadding(KeyValues::fixupsTargetKeyword)
313 << refName
314 << "\n";
315 }
316 if ( ref.addend() != 0 ) {
317 _out << " "
318 << KeyValues::fixupsAddendKeyword
319 << ":"
320 << spacePadding(KeyValues::fixupsAddendKeyword)
321 << ref.addend()
322 << "\n";
323 }
324 }
325
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000326
Nick Kledzik23384e82012-02-07 02:59:54 +0000327 virtual void doUndefinedAtom(const class UndefinedAtom &atom) {
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000328 if ( _firstAtom ) {
329 _out << "atoms:\n";
Nick Kledzik23384e82012-02-07 02:59:54 +0000330 _firstAtom = false;
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000331 }
332 else {
333 // add blank line between atoms for readability
334 _out << "\n";
335 }
Nick Kledzik23384e82012-02-07 02:59:54 +0000336
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000337 _out << " - "
338 << KeyValues::nameKeyword
339 << ":"
340 << spacePadding(KeyValues::nameKeyword)
341 << atom.name()
342 << "\n";
Nick Kledzikf4fb2c52012-01-11 01:06:19 +0000343
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000344 _out << " "
345 << KeyValues::definitionKeyword
346 << ":"
347 << spacePadding(KeyValues::definitionKeyword)
348 << KeyValues::definition(atom.definition())
349 << "\n";
Nick Kledzik23384e82012-02-07 02:59:54 +0000350
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000351 if ( atom.canBeNull() != KeyValues::canBeNullDefault ) {
Nick Kledzik23384e82012-02-07 02:59:54 +0000352 _out << " "
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000353 << KeyValues::canBeNullKeyword
Nick Kledzik23384e82012-02-07 02:59:54 +0000354 << ":"
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000355 << spacePadding(KeyValues::canBeNullKeyword)
356 << KeyValues::canBeNull(atom.canBeNull())
Nick Kledzik23384e82012-02-07 02:59:54 +0000357 << "\n";
358 }
359 }
Nick Kledzikf4fb2c52012-01-11 01:06:19 +0000360
Nick Kledzik6bc04c62012-02-22 21:56:59 +0000361 virtual void doSharedLibraryAtom(const SharedLibraryAtom& atom) {
362 if ( _firstAtom ) {
363 _out << "atoms:\n";
364 _firstAtom = false;
365 }
366 else {
367 // add blank line between atoms for readability
368 _out << "\n";
369 }
370
371 _out << " - "
372 << KeyValues::nameKeyword
373 << ":"
374 << spacePadding(KeyValues::nameKeyword)
375 << atom.name()
376 << "\n";
377
378 _out << " "
379 << KeyValues::definitionKeyword
380 << ":"
381 << spacePadding(KeyValues::definitionKeyword)
382 << KeyValues::definition(atom.definition())
383 << "\n";
384
385 if ( !atom.loadName().empty() ) {
386 _out << " "
387 << KeyValues::loadNameKeyword
388 << ":"
389 << spacePadding(KeyValues::loadNameKeyword)
390 << atom.loadName()
391 << "\n";
392 }
393
394 if ( atom.canBeNullAtRuntime() ) {
395 _out << " "
396 << KeyValues::canBeNullKeyword
397 << ":"
398 << spacePadding(KeyValues::canBeNullKeyword)
399 << KeyValues::canBeNull(UndefinedAtom::canBeNullAtRuntime)
400 << "\n";
401 }
402 }
403
404 virtual void doAbsoluteAtom(const AbsoluteAtom& atom) {
405 if ( _firstAtom ) {
406 _out << "atoms:\n";
407 _firstAtom = false;
408 }
409 else {
410 // add blank line between atoms for readability
411 _out << "\n";
412 }
413
414 _out << " - "
415 << KeyValues::nameKeyword
416 << ":"
417 << spacePadding(KeyValues::nameKeyword)
418 << atom.name()
419 << "\n";
420
421 _out << " "
422 << KeyValues::definitionKeyword
423 << ":"
424 << spacePadding(KeyValues::definitionKeyword)
425 << KeyValues::definition(atom.definition())
426 << "\n";
427
428 _out << " "
429 << KeyValues::valueKeyword
430 << ":"
431 << spacePadding(KeyValues::valueKeyword)
432 << "0x";
433 _out.write_hex(atom.value());
434 _out << "\n";
435 }
436
Nick Kledzikf4fb2c52012-01-11 01:06:19 +0000437
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000438private:
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000439 // return a string of the correct number of spaces to align value
440 const char* spacePadding(const char* key) {
441 const char* spaces = " ";
442 assert(strlen(spaces) > strlen(key));
443 return &spaces[strlen(key)];
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000444 }
445
Nick Kledzikbfedfc12012-01-09 20:18:15 +0000446 char hexdigit(uint8_t nibble) {
447 if ( nibble < 0x0A )
448 return '0' + nibble;
449 else
450 return 'A' + nibble - 0x0A;
451 }
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000452
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000453 llvm::raw_ostream& _out;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000454 RefNameBuilder _rnb;
Nick Kledzik7735a7d2012-01-04 23:58:17 +0000455 bool _firstAtom;
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000456 bool _wroteFirstFixup;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000457};
458
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000459} // anonymous namespace
460
461
462
463///
464/// writeObjectText - writes the lld::File object as in YAML
465/// format to the specified stream.
466///
Nick Kledzik55fd6be2012-01-16 22:03:44 +0000467void writeObjectText(const File &file, llvm::raw_ostream &out) {
Nick Kledzik49d6cc82012-02-15 00:38:09 +0000468 // Figure what ref-name labels are needed
469 RefNameBuilder rnb;
470 file.forEachAtom(rnb);
471
472 // Write out all atoms
473 AtomWriter h(rnb, out);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000474 out << "---\n";
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000475 file.forEachAtom(h);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000476 out << "...\n";
477}
478
479} // namespace yaml
480} // namespace lld