blob: c35664e028031c0e3016c2b9f7181a381c2ab11d [file] [log] [blame]
Michael J. Spencer773a8fb2011-12-18 08:27:59 +00001//===- Core/YamlReader.cpp - Reads 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
10#include "lld/Core/YamlReader.h"
11#include "lld/Core/Atom.h"
12#include "lld/Core/File.h"
13#include "lld/Core/Reference.h"
14
15#include "llvm/ADT/OwningPtr.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/Support/DataTypes.h"
18#include "llvm/Support/ErrorHandling.h"
19#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/system_error.h"
21
22#include <vector>
23
24namespace { const llvm::error_code success; }
25
26namespace lld {
27namespace yaml {
28class YAML {
29public:
30 struct Entry {
31 Entry(const char *k, const char *v, int d, bool bd, bool bs)
32 : key(strdup(k))
33 , value(strdup(v))
34 , depth(d)
35 , beginSequence(bs)
36 , beginDocument(bd) {}
37
38 const char *key;
39 const char *value;
40 int depth;
41 bool beginSequence;
42 bool beginDocument;
43 };
44
45 static void parse(llvm::MemoryBuffer *mb, std::vector<const Entry *>&);
46
47private:
48 enum State {
49 start,
50 inHeaderComment,
51 inTripleDash,
52 inTriplePeriod,
53 inDocument,
54 inKey,
55 inSpaceBeforeValue,
56 inValue,
57 inValueSequence,
58 inValueSequenceEnd
59 };
60};
61
62
63void YAML::parse(llvm::MemoryBuffer *mb, std::vector<const Entry *> &entries) {
64 State state = start;
65 char key[64];
66 char value[64];
67 char *p = NULL;
68 unsigned int lineNumber = 1;
69 int depth = 0;
70 bool nextKeyIsStartOfDocument = false;
71 bool nextKeyIsStartOfSequence = false;
72 for (const char *s = mb->getBufferStart(); s < mb->getBufferEnd(); ++s) {
73 char c = *s;
74 if (c == '\n')
75 ++lineNumber;
76 switch (state) {
77 case start:
78 if (c == '#')
79 state = inHeaderComment;
80 else if (c == '-') {
81 p = &key[0];
82 *p++ = c;
83 state = inTripleDash;
84 }
85 break;
86 case inHeaderComment:
87 if (c == '\n') {
88 state = start;
89 }
90 break;
91 case inTripleDash:
92 if (c == '-') {
93 *p++ = c;
94 } else if (c == '\n') {
95 *p = '\0';
96 if (strcmp(key, "---") != 0)
97 return;
98 depth = 0;
99 state = inDocument;
100 nextKeyIsStartOfDocument = true;
101 } else {
102 return;
103 }
104 break;
105 case inTriplePeriod:
106 if (c == '.') {
107 *p++ = c;
108 } else if (c == '\n') {
109 *p = '\0';
110 if (strcmp(key, "...") != 0)
111 return;
112 depth = 0;
113 state = inHeaderComment;
114 } else {
115 return;
116 }
117 break;
118 case inDocument:
119 if (isalnum(c)) {
120 state = inKey;
121 p = &key[0];
122 *p++ = c;
123 } else if (c == '-') {
124 if (depth == 0) {
125 p = &key[0];
126 *p++ = c;
127 state = inTripleDash;
128 } else {
129 nextKeyIsStartOfSequence = true;
130 ++depth;
131 }
132 } else if (c == ' ') {
133 ++depth;
134 } else if (c == '.') {
135 p = &key[0];
136 *p++ = c;
137 state = inTriplePeriod;
138 } else if (c == '\n') {
139 // ignore empty lines
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000140 } else if (c == '\t') {
141 llvm::report_fatal_error("TAB character found in yaml file");
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000142 } else {
143 return;
144 }
145 break;
146 case inKey:
147 if (isalnum(c) || (c == '-')) {
148 *p++ = c;
149 } else if (c == ':') {
150 *p = '\0';
151 state = inSpaceBeforeValue;
152 } else if (c == '\n') {
153 *p = '\0';
154 if (strcmp(key, "---") == 0)
155 state = inDocument;
156 else
157 return;
158 } else {
159 return;
160 }
161 break;
162 case inSpaceBeforeValue:
163 if (isalnum(c) || (c == '-') || (c == '_')) {
164 p = &value[0];
165 *p++ = c;
166 state = inValue;
167 } else if (c == '\n') {
168 entries.push_back(new Entry(key, "", depth,
169 nextKeyIsStartOfDocument,
170 nextKeyIsStartOfSequence));
171 nextKeyIsStartOfSequence = false;
172 nextKeyIsStartOfDocument = false;
173 state = inDocument;
174 depth = 0;
175 } else if (c == '[') {
176 state = inValueSequence;
177 } else if (c == ' ') {
178 // eat space
179 } else {
180 return;
181 }
182 break;
183 case inValue:
184 if (isalnum(c) || (c == '-') || (c == '_')) {
185 *p++ = c;
186 } else if (c == '\n') {
187 *p = '\0';
188 entries.push_back(new Entry(key, value, depth,
189 nextKeyIsStartOfDocument,
190 nextKeyIsStartOfSequence));
191 nextKeyIsStartOfSequence = false;
192 nextKeyIsStartOfDocument = false;
193 state = inDocument;
194 depth = 0;
195 }
196 break;
197 case inValueSequence:
198 if (c == ']')
199 state = inValueSequenceEnd;
200 break;
201 case inValueSequenceEnd:
202 if (c == '\n') {
203 state = inDocument;
204 depth = 0;
205 }
206 break;
207 }
208 }
209}
210
211class YAMLFile : public File {
212public:
213 YAMLFile()
214 : File("path")
215 , _lastRefIndex(0) {}
216
217 virtual bool forEachAtom(File::AtomHandler &) const;
218 virtual bool justInTimeforEachAtom(llvm::StringRef name,
219 File::AtomHandler &) const;
220
221 std::vector<Atom *> _atoms;
222 std::vector<Reference> _references;
223 unsigned int _lastRefIndex;
224};
225
226bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
227 handler.doFile(*this);
228 for (std::vector<Atom *>::const_iterator it = _atoms.begin();
229 it != _atoms.end(); ++it) {
230 handler.doAtom(**it);
231 }
232 return true;
233}
234
235bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name,
236 File::AtomHandler &handler) const {
237 return false;
238}
239
240
241class YAMLAtom : public Atom {
242public:
Nick Kledzikf46669c2011-12-21 23:29:36 +0000243 YAMLAtom( uint64_t ord
244 , Definition d
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000245 , Scope s
246 , ContentType ct
247 , SectionChoice sc
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000248 , bool intn
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000249 , bool md
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000250 , DeadStripKind dsk
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000251 , bool tb
252 , bool al
253 , Alignment a
Nick Kledzikf46669c2011-12-21 23:29:36 +0000254 , YAMLFile& f
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000255 , const char *n)
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000256 : Atom(ord, d, s, ct, sc, intn, md, dsk, tb, al, a)
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000257 , _file(f)
258 , _name(n)
259 , _size(0)
Nick Kledzikf46669c2011-12-21 23:29:36 +0000260 , _refStartIndex(f._lastRefIndex)
261 , _refEndIndex(f._references.size()) {
262 f._lastRefIndex = _refEndIndex;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000263 }
264
Nick Kledzikf46669c2011-12-21 23:29:36 +0000265 virtual const class File& file() const {
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000266 return _file;
267 }
268
269 virtual bool translationUnitSource(const char* *dir, const char* *name) const{
270 return false;
271 }
272
273 virtual llvm::StringRef name() const {
274 return _name;
275 }
276
277 virtual uint64_t objectAddress() const {
278 return 0;
279 }
280
281 virtual uint64_t size() const {
282 return _size;
283 }
284
285 virtual void copyRawContent(uint8_t buffer[]) const { }
286 virtual Reference::iterator referencesBegin() const;
287 virtual Reference::iterator referencesEnd() const;
288private:
Nick Kledzikf46669c2011-12-21 23:29:36 +0000289 YAMLFile& _file;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000290 const char *_name;
291 unsigned long _size;
292 unsigned int _refStartIndex;
293 unsigned int _refEndIndex;
294};
295
296Reference::iterator YAMLAtom::referencesBegin() const {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000297 if (_file._references.size() < _refStartIndex)
298 return (Reference::iterator)&_file._references[_refStartIndex];
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000299 return 0;
300}
301
302Reference::iterator YAMLAtom::referencesEnd() const {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000303 if (_file._references.size() < _refEndIndex)
304 return (Reference::iterator)&_file._references[_refEndIndex];
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000305 return 0;
306}
307
308class YAMLAtomState {
309public:
310 YAMLAtomState();
311
312 void setName(const char *n);
313 void setScope(const char *n);
314 void setType(const char *n);
315 void setAlign2(const char *n);
316 void setDefinition(const char *n);
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000317 void setMergeDuplicates(const char *n);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000318
319 void setFixupKind(const char *n);
320 void setFixupOffset(const char *n);
321 void setFixupTarget(const char *n);
322 void addFixup(YAMLFile *f);
323
Nick Kledzikf46669c2011-12-21 23:29:36 +0000324 void makeAtom(YAMLFile&);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000325
326private:
Nick Kledzikf46669c2011-12-21 23:29:36 +0000327 uint64_t _ordinal;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000328 const char *_name;
329 Atom::Alignment _align;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000330 Atom::ContentType _type;
331 Atom::Scope _scope;
332 Atom::Definition _def;
333 Atom::SectionChoice _sectionChoice;
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000334 bool _internalName;
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000335 bool _mergeDuplicates;
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000336 Atom::DeadStripKind _dontDeadStrip;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000337 bool _thumb;
338 bool _alias;
339 Reference _ref;
340};
341
342YAMLAtomState::YAMLAtomState()
Nick Kledzikf46669c2011-12-21 23:29:36 +0000343 : _ordinal(0)
344 , _name(NULL)
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000345 , _align(0, 0)
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000346 , _type(Atom::typeData)
347 , _scope(Atom::scopeGlobal)
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000348 , _internalName(false)
349 , _mergeDuplicates(false)
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000350 , _dontDeadStrip(Atom::deadStripNormal)
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000351 , _thumb(false)
352 , _alias(false) {
353 _ref.target = NULL;
354 _ref.addend = 0;
355 _ref.offsetInAtom = 0;
356 _ref.kind = 0;
357 _ref.flags = 0;
358}
359
Nick Kledzikf46669c2011-12-21 23:29:36 +0000360void YAMLAtomState::makeAtom(YAMLFile& f) {
361 Atom *a = new YAMLAtom(_ordinal, _def, _scope, _type, _sectionChoice,
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000362 _internalName, _mergeDuplicates, _dontDeadStrip,
363 _thumb, _alias, _align, f, _name);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000364
Nick Kledzikf46669c2011-12-21 23:29:36 +0000365 f._atoms.push_back(a);
366 ++_ordinal;
367
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000368 // reset state for next atom
369 _name = NULL;
370 _align.powerOf2 = 0;
371 _align.modulus = 0;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000372 _type = Atom::typeData;
373 _scope = Atom::scopeGlobal;
374 _def = Atom::definitionRegular;
375 _sectionChoice = Atom::sectionBasedOnContent;
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000376 _internalName = false;
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000377 _mergeDuplicates = false;
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000378 _dontDeadStrip = Atom::deadStripNormal;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000379 _thumb = false;
380 _alias = false;
381 _ref.target = NULL;
382 _ref.addend = 0;
383 _ref.offsetInAtom = 0;
384 _ref.kind = 0;
385 _ref.flags = 0;
386}
387
388void YAMLAtomState::setName(const char *n) {
389 _name = n;
390}
391
392void YAMLAtomState::setScope(const char *s) {
393 if (strcmp(s, "global") == 0)
394 _scope = Atom::scopeGlobal;
395 else if (strcmp(s, "hidden") == 0)
396 _scope = Atom::scopeLinkageUnit;
397 else if (strcmp(s, "static") == 0)
398 _scope = Atom::scopeTranslationUnit;
399 else
400 llvm::report_fatal_error("bad scope value");
401}
402
403void YAMLAtomState::setType(const char *s) {
404 if (strcmp(s, "code") == 0)
405 _type = Atom::typeCode;
406 else if (strcmp(s, "c-string") == 0)
407 _type = Atom::typeCString;
408 else if (strcmp(s, "zero-fill") == 0)
409 _type = Atom::typeZeroFill;
410 else if (strcmp(s, "data") == 0)
411 _type = Atom::typeData;
412 else
413 llvm::report_fatal_error("bad type value");
414}
415
416void YAMLAtomState::setAlign2(const char *s) {
417 llvm::StringRef str(s);
418 uint32_t res;
419 str.getAsInteger(10, res);
420 _align.powerOf2 = static_cast<uint16_t>(res);
421}
422
423void YAMLAtomState::setDefinition(const char *s) {
424 if (strcmp(s, "regular") == 0)
425 _def = Atom::definitionRegular;
426 else if (strcmp(s, "tentative") == 0)
427 _def = Atom::definitionTentative;
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000428 else if (strcmp(s, "weak") == 0)
429 _def = Atom::definitionWeak;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000430 else if (strcmp(s, "absolute") == 0)
431 _def = Atom::definitionAbsolute;
432 else
433 llvm::report_fatal_error("bad definition value");
434}
435
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000436void YAMLAtomState::setMergeDuplicates(const char *s) {
437 if (strcmp(s, "true") == 0)
438 _mergeDuplicates = true;
439 else if (strcmp(s, "false") == 0)
440 _mergeDuplicates = false;
441 else
442 llvm::report_fatal_error("bad merge-duplicates value");
443}
444
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000445void YAMLAtomState::setFixupKind(const char *s) {
446 if (strcmp(s, "pcrel32") == 0)
447 _ref.kind = 1;
448 else if (strcmp(s, "call32") == 0)
449 _ref.kind = 2;
450 else
451 llvm::report_fatal_error("bad fixup kind value");
452}
453
454void YAMLAtomState::setFixupOffset(const char *s) {
455 if ((s[0] == '0') && (s[1] == 'x'))
456 llvm::StringRef(s).getAsInteger(16, _ref.offsetInAtom);
457 else
458 llvm::StringRef(s).getAsInteger(10, _ref.offsetInAtom);
459}
460
461void YAMLAtomState::setFixupTarget(const char *s) {
462}
463
464void YAMLAtomState::addFixup(YAMLFile *f) {
465 f->_references.push_back(_ref);
466 // clear for next ref
467 _ref.target = NULL;
468 _ref.addend = 0;
469 _ref.offsetInAtom = 0;
470 _ref.kind = 0;
471 _ref.flags = 0;
472}
473
474llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
475 , std::vector<File *> &result) {
476 std::vector<const YAML::Entry *> entries;
477 YAML::parse(mb, entries);
478
479 YAMLFile *file = NULL;
480 YAMLAtomState atomState;
481 bool inAtoms = false;
482 bool inFixups = false;
483 int depthForAtoms = -1;
484 int depthForFixups = -1;
485 int lastDepth = -1;
486 bool haveAtom = false;
487 bool haveFixup = false;
488
489 for (std::vector<const YAML::Entry *>::iterator it = entries.begin();
490 it != entries.end(); ++it) {
491 const YAML::Entry *entry = *it;
492
493 if (entry->beginDocument) {
494 if (file != NULL) {
495 if (haveAtom) {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000496 atomState.makeAtom(*file);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000497 haveAtom = false;
498 }
499 result.push_back(file);
500 }
501 file = new YAMLFile();
502 inAtoms = false;
503 depthForAtoms = -1;
504 }
505 if (lastDepth > entry->depth) {
506 // end of fixup sequence
507 if (haveFixup) {
508 atomState.addFixup(file);
509 haveFixup = false;
510 }
511 }
512
513 if (inAtoms && (depthForAtoms == -1)) {
514 depthForAtoms = entry->depth;
515 }
516 if (inFixups && (depthForFixups == -1)) {
517 depthForFixups = entry->depth;
518 }
519 if (strcmp(entry->key, "atoms") == 0) {
520 inAtoms = true;
521 }
522 if (inAtoms) {
523 if (depthForAtoms == entry->depth) {
524 if (entry->beginSequence) {
525 if (haveAtom) {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000526 atomState.makeAtom(*file);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000527 haveAtom = false;
528 }
529 }
530 if (strcmp(entry->key, "name") == 0) {
531 atomState.setName(entry->value);
532 haveAtom = true;
533 } else if (strcmp(entry->key, "scope") == 0) {
534 atomState.setScope(entry->value);
535 haveAtom = true;
536 } else if (strcmp(entry->key, "type") == 0) {
537 atomState.setType(entry->value);
538 haveAtom = true;
539 } else if (strcmp(entry->key, "align2") == 0) {
540 atomState.setAlign2(entry->value);
541 haveAtom = true;
542 } else if (strcmp(entry->key, "definition") == 0) {
543 atomState.setDefinition(entry->value);
544 haveAtom = true;
Nick Kledzik38eec3d2011-12-22 02:38:01 +0000545 } else if (strcmp(entry->key, "merge-duplicates") == 0) {
546 atomState.setMergeDuplicates(entry->value);
547 haveAtom = true;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000548 } else if (strcmp(entry->key, "fixups") == 0) {
549 inFixups = true;
550 }
551 } else if (depthForFixups == entry->depth) {
552 if (entry->beginSequence) {
553 if (haveFixup) {
554 atomState.addFixup(file);
555 haveFixup = false;
556 }
557 }
558 if (strcmp(entry->key, "kind") == 0) {
559 atomState.setFixupKind(entry->value);
560 haveFixup = true;
561 } else if (strcmp(entry->key, "offset") == 0) {
562 atomState.setFixupOffset(entry->value);
563 haveFixup = true;
564 } else if (strcmp(entry->key, "target") == 0) {
565 atomState.setFixupTarget(entry->value);
566 haveFixup = true;
567 }
568 }
569 }
570 lastDepth = entry->depth;
571 }
572 if (haveAtom) {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000573 atomState.makeAtom(*file);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000574 }
575
576 result.push_back(file);
577 return success;
578}
Nick Kledzik070e1a72011-12-20 00:07:11 +0000579
580//
581// Fill in vector<File*> from path to input text file.
582//
583llvm::error_code parseObjectTextFileOrSTDIN(llvm::StringRef path
584 , std::vector<File*>& result) {
585 llvm::OwningPtr<llvm::MemoryBuffer> mb;
586 llvm::error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb);
587 if ( ec )
588 return ec;
589
590 return parseObjectText(mb.get(), result);
591}
592
593
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000594} // namespace yaml
595} // namespace lld