blob: 6250939b8a737ad8bcdeff7207bf806dc9e3bb5b [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
140 } else {
141 return;
142 }
143 break;
144 case inKey:
145 if (isalnum(c) || (c == '-')) {
146 *p++ = c;
147 } else if (c == ':') {
148 *p = '\0';
149 state = inSpaceBeforeValue;
150 } else if (c == '\n') {
151 *p = '\0';
152 if (strcmp(key, "---") == 0)
153 state = inDocument;
154 else
155 return;
156 } else {
157 return;
158 }
159 break;
160 case inSpaceBeforeValue:
161 if (isalnum(c) || (c == '-') || (c == '_')) {
162 p = &value[0];
163 *p++ = c;
164 state = inValue;
165 } else if (c == '\n') {
166 entries.push_back(new Entry(key, "", depth,
167 nextKeyIsStartOfDocument,
168 nextKeyIsStartOfSequence));
169 nextKeyIsStartOfSequence = false;
170 nextKeyIsStartOfDocument = false;
171 state = inDocument;
172 depth = 0;
173 } else if (c == '[') {
174 state = inValueSequence;
175 } else if (c == ' ') {
176 // eat space
177 } else {
178 return;
179 }
180 break;
181 case inValue:
182 if (isalnum(c) || (c == '-') || (c == '_')) {
183 *p++ = c;
184 } else if (c == '\n') {
185 *p = '\0';
186 entries.push_back(new Entry(key, value, depth,
187 nextKeyIsStartOfDocument,
188 nextKeyIsStartOfSequence));
189 nextKeyIsStartOfSequence = false;
190 nextKeyIsStartOfDocument = false;
191 state = inDocument;
192 depth = 0;
193 }
194 break;
195 case inValueSequence:
196 if (c == ']')
197 state = inValueSequenceEnd;
198 break;
199 case inValueSequenceEnd:
200 if (c == '\n') {
201 state = inDocument;
202 depth = 0;
203 }
204 break;
205 }
206 }
207}
208
209class YAMLFile : public File {
210public:
211 YAMLFile()
212 : File("path")
213 , _lastRefIndex(0) {}
214
215 virtual bool forEachAtom(File::AtomHandler &) const;
216 virtual bool justInTimeforEachAtom(llvm::StringRef name,
217 File::AtomHandler &) const;
218
219 std::vector<Atom *> _atoms;
220 std::vector<Reference> _references;
221 unsigned int _lastRefIndex;
222};
223
224bool YAMLFile::forEachAtom(File::AtomHandler &handler) const {
225 handler.doFile(*this);
226 for (std::vector<Atom *>::const_iterator it = _atoms.begin();
227 it != _atoms.end(); ++it) {
228 handler.doAtom(**it);
229 }
230 return true;
231}
232
233bool YAMLFile::justInTimeforEachAtom(llvm::StringRef name,
234 File::AtomHandler &handler) const {
235 return false;
236}
237
238
239class YAMLAtom : public Atom {
240public:
Nick Kledzikf46669c2011-12-21 23:29:36 +0000241 YAMLAtom( uint64_t ord
242 , Definition d
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000243 , Scope s
244 , ContentType ct
245 , SectionChoice sc
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000246 , bool intn
247 , DeadStripKind dsk
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000248 , bool tb
249 , bool al
250 , Alignment a
Nick Kledzikf46669c2011-12-21 23:29:36 +0000251 , YAMLFile& f
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000252 , const char *n)
Nick Kledzikf46669c2011-12-21 23:29:36 +0000253 : Atom(ord, d, s, ct, sc, intn, dsk, tb, al, a)
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000254 , _file(f)
255 , _name(n)
256 , _size(0)
Nick Kledzikf46669c2011-12-21 23:29:36 +0000257 , _refStartIndex(f._lastRefIndex)
258 , _refEndIndex(f._references.size()) {
259 f._lastRefIndex = _refEndIndex;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000260 }
261
Nick Kledzikf46669c2011-12-21 23:29:36 +0000262 virtual const class File& file() const {
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000263 return _file;
264 }
265
266 virtual bool translationUnitSource(const char* *dir, const char* *name) const{
267 return false;
268 }
269
270 virtual llvm::StringRef name() const {
271 return _name;
272 }
273
274 virtual uint64_t objectAddress() const {
275 return 0;
276 }
277
278 virtual uint64_t size() const {
279 return _size;
280 }
281
282 virtual void copyRawContent(uint8_t buffer[]) const { }
283 virtual Reference::iterator referencesBegin() const;
284 virtual Reference::iterator referencesEnd() const;
285private:
Nick Kledzikf46669c2011-12-21 23:29:36 +0000286 YAMLFile& _file;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000287 const char *_name;
288 unsigned long _size;
289 unsigned int _refStartIndex;
290 unsigned int _refEndIndex;
291};
292
293Reference::iterator YAMLAtom::referencesBegin() const {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000294 if (_file._references.size() < _refStartIndex)
295 return (Reference::iterator)&_file._references[_refStartIndex];
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000296 return 0;
297}
298
299Reference::iterator YAMLAtom::referencesEnd() const {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000300 if (_file._references.size() < _refEndIndex)
301 return (Reference::iterator)&_file._references[_refEndIndex];
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000302 return 0;
303}
304
305class YAMLAtomState {
306public:
307 YAMLAtomState();
308
309 void setName(const char *n);
310 void setScope(const char *n);
311 void setType(const char *n);
312 void setAlign2(const char *n);
313 void setDefinition(const char *n);
314
315 void setFixupKind(const char *n);
316 void setFixupOffset(const char *n);
317 void setFixupTarget(const char *n);
318 void addFixup(YAMLFile *f);
319
Nick Kledzikf46669c2011-12-21 23:29:36 +0000320 void makeAtom(YAMLFile&);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000321
322private:
Nick Kledzikf46669c2011-12-21 23:29:36 +0000323 uint64_t _ordinal;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000324 const char *_name;
325 Atom::Alignment _align;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000326 Atom::ContentType _type;
327 Atom::Scope _scope;
328 Atom::Definition _def;
329 Atom::SectionChoice _sectionChoice;
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000330 bool _internalName;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000331 bool _userVisibleName;
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000332 Atom::DeadStripKind _dontDeadStrip;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000333 bool _thumb;
334 bool _alias;
335 Reference _ref;
336};
337
338YAMLAtomState::YAMLAtomState()
Nick Kledzikf46669c2011-12-21 23:29:36 +0000339 : _ordinal(0)
340 , _name(NULL)
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000341 , _align(0, 0)
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000342 , _type(Atom::typeData)
343 , _scope(Atom::scopeGlobal)
344 , _userVisibleName(true)
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000345 , _dontDeadStrip(Atom::deadStripNormal)
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000346 , _thumb(false)
347 , _alias(false) {
348 _ref.target = NULL;
349 _ref.addend = 0;
350 _ref.offsetInAtom = 0;
351 _ref.kind = 0;
352 _ref.flags = 0;
353}
354
Nick Kledzikf46669c2011-12-21 23:29:36 +0000355void YAMLAtomState::makeAtom(YAMLFile& f) {
356 Atom *a = new YAMLAtom(_ordinal, _def, _scope, _type, _sectionChoice,
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000357 _internalName, _dontDeadStrip, _thumb, _alias,
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000358 _align, f, _name);
359
Nick Kledzikf46669c2011-12-21 23:29:36 +0000360 f._atoms.push_back(a);
361 ++_ordinal;
362
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000363 // reset state for next atom
364 _name = NULL;
365 _align.powerOf2 = 0;
366 _align.modulus = 0;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000367 _type = Atom::typeData;
368 _scope = Atom::scopeGlobal;
369 _def = Atom::definitionRegular;
370 _sectionChoice = Atom::sectionBasedOnContent;
Nick Kledzikf96d0ad2011-12-20 02:18:44 +0000371 _internalName = false;
372 _dontDeadStrip = Atom::deadStripNormal;
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000373 _thumb = false;
374 _alias = false;
375 _ref.target = NULL;
376 _ref.addend = 0;
377 _ref.offsetInAtom = 0;
378 _ref.kind = 0;
379 _ref.flags = 0;
380}
381
382void YAMLAtomState::setName(const char *n) {
383 _name = n;
384}
385
386void YAMLAtomState::setScope(const char *s) {
387 if (strcmp(s, "global") == 0)
388 _scope = Atom::scopeGlobal;
389 else if (strcmp(s, "hidden") == 0)
390 _scope = Atom::scopeLinkageUnit;
391 else if (strcmp(s, "static") == 0)
392 _scope = Atom::scopeTranslationUnit;
393 else
394 llvm::report_fatal_error("bad scope value");
395}
396
397void YAMLAtomState::setType(const char *s) {
398 if (strcmp(s, "code") == 0)
399 _type = Atom::typeCode;
400 else if (strcmp(s, "c-string") == 0)
401 _type = Atom::typeCString;
402 else if (strcmp(s, "zero-fill") == 0)
403 _type = Atom::typeZeroFill;
404 else if (strcmp(s, "data") == 0)
405 _type = Atom::typeData;
406 else
407 llvm::report_fatal_error("bad type value");
408}
409
410void YAMLAtomState::setAlign2(const char *s) {
411 llvm::StringRef str(s);
412 uint32_t res;
413 str.getAsInteger(10, res);
414 _align.powerOf2 = static_cast<uint16_t>(res);
415}
416
417void YAMLAtomState::setDefinition(const char *s) {
418 if (strcmp(s, "regular") == 0)
419 _def = Atom::definitionRegular;
420 else if (strcmp(s, "tentative") == 0)
421 _def = Atom::definitionTentative;
422 else if (strcmp(s, "absolute") == 0)
423 _def = Atom::definitionAbsolute;
424 else
425 llvm::report_fatal_error("bad definition value");
426}
427
428void YAMLAtomState::setFixupKind(const char *s) {
429 if (strcmp(s, "pcrel32") == 0)
430 _ref.kind = 1;
431 else if (strcmp(s, "call32") == 0)
432 _ref.kind = 2;
433 else
434 llvm::report_fatal_error("bad fixup kind value");
435}
436
437void YAMLAtomState::setFixupOffset(const char *s) {
438 if ((s[0] == '0') && (s[1] == 'x'))
439 llvm::StringRef(s).getAsInteger(16, _ref.offsetInAtom);
440 else
441 llvm::StringRef(s).getAsInteger(10, _ref.offsetInAtom);
442}
443
444void YAMLAtomState::setFixupTarget(const char *s) {
445}
446
447void YAMLAtomState::addFixup(YAMLFile *f) {
448 f->_references.push_back(_ref);
449 // clear for next ref
450 _ref.target = NULL;
451 _ref.addend = 0;
452 _ref.offsetInAtom = 0;
453 _ref.kind = 0;
454 _ref.flags = 0;
455}
456
457llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
458 , std::vector<File *> &result) {
459 std::vector<const YAML::Entry *> entries;
460 YAML::parse(mb, entries);
461
462 YAMLFile *file = NULL;
463 YAMLAtomState atomState;
464 bool inAtoms = false;
465 bool inFixups = false;
466 int depthForAtoms = -1;
467 int depthForFixups = -1;
468 int lastDepth = -1;
469 bool haveAtom = false;
470 bool haveFixup = false;
471
472 for (std::vector<const YAML::Entry *>::iterator it = entries.begin();
473 it != entries.end(); ++it) {
474 const YAML::Entry *entry = *it;
475
476 if (entry->beginDocument) {
477 if (file != NULL) {
478 if (haveAtom) {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000479 atomState.makeAtom(*file);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000480 haveAtom = false;
481 }
482 result.push_back(file);
483 }
484 file = new YAMLFile();
485 inAtoms = false;
486 depthForAtoms = -1;
487 }
488 if (lastDepth > entry->depth) {
489 // end of fixup sequence
490 if (haveFixup) {
491 atomState.addFixup(file);
492 haveFixup = false;
493 }
494 }
495
496 if (inAtoms && (depthForAtoms == -1)) {
497 depthForAtoms = entry->depth;
498 }
499 if (inFixups && (depthForFixups == -1)) {
500 depthForFixups = entry->depth;
501 }
502 if (strcmp(entry->key, "atoms") == 0) {
503 inAtoms = true;
504 }
505 if (inAtoms) {
506 if (depthForAtoms == entry->depth) {
507 if (entry->beginSequence) {
508 if (haveAtom) {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000509 atomState.makeAtom(*file);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000510 haveAtom = false;
511 }
512 }
513 if (strcmp(entry->key, "name") == 0) {
514 atomState.setName(entry->value);
515 haveAtom = true;
516 } else if (strcmp(entry->key, "scope") == 0) {
517 atomState.setScope(entry->value);
518 haveAtom = true;
519 } else if (strcmp(entry->key, "type") == 0) {
520 atomState.setType(entry->value);
521 haveAtom = true;
522 } else if (strcmp(entry->key, "align2") == 0) {
523 atomState.setAlign2(entry->value);
524 haveAtom = true;
525 } else if (strcmp(entry->key, "definition") == 0) {
526 atomState.setDefinition(entry->value);
527 haveAtom = true;
528 } else if (strcmp(entry->key, "fixups") == 0) {
529 inFixups = true;
530 }
531 } else if (depthForFixups == entry->depth) {
532 if (entry->beginSequence) {
533 if (haveFixup) {
534 atomState.addFixup(file);
535 haveFixup = false;
536 }
537 }
538 if (strcmp(entry->key, "kind") == 0) {
539 atomState.setFixupKind(entry->value);
540 haveFixup = true;
541 } else if (strcmp(entry->key, "offset") == 0) {
542 atomState.setFixupOffset(entry->value);
543 haveFixup = true;
544 } else if (strcmp(entry->key, "target") == 0) {
545 atomState.setFixupTarget(entry->value);
546 haveFixup = true;
547 }
548 }
549 }
550 lastDepth = entry->depth;
551 }
552 if (haveAtom) {
Nick Kledzikf46669c2011-12-21 23:29:36 +0000553 atomState.makeAtom(*file);
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000554 }
555
556 result.push_back(file);
557 return success;
558}
Nick Kledzik070e1a72011-12-20 00:07:11 +0000559
560//
561// Fill in vector<File*> from path to input text file.
562//
563llvm::error_code parseObjectTextFileOrSTDIN(llvm::StringRef path
564 , std::vector<File*>& result) {
565 llvm::OwningPtr<llvm::MemoryBuffer> mb;
566 llvm::error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(path, mb);
567 if ( ec )
568 return ec;
569
570 return parseObjectText(mb.get(), result);
571}
572
573
Michael J. Spencer773a8fb2011-12-18 08:27:59 +0000574} // namespace yaml
575} // namespace lld