blob: 86dea5458580193034b299676afc3a3b65d12195 [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:
241 YAMLAtom( Definition d
242 , Combine c
243 , Scope s
244 , ContentType ct
245 , SectionChoice sc
246 , bool uvn
247 , bool dds
248 , bool tb
249 , bool al
250 , Alignment a
251 , YAMLFile *f
252 , const char *n)
253 : Atom(d, c, s, ct, sc, uvn, dds, tb, al, a)
254 , _file(f)
255 , _name(n)
256 , _size(0)
257 , _refStartIndex(f->_lastRefIndex)
258 , _refEndIndex(f->_references.size()) {
259 f->_lastRefIndex = _refEndIndex;
260 }
261
262 virtual const class File *file() const {
263 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:
286 YAMLFile *_file;
287 const char *_name;
288 unsigned long _size;
289 unsigned int _refStartIndex;
290 unsigned int _refEndIndex;
291};
292
293Reference::iterator YAMLAtom::referencesBegin() const {
294 if (_file->_references.size() < _refStartIndex)
295 return (Reference::iterator)&_file->_references[_refStartIndex];
296 return 0;
297}
298
299Reference::iterator YAMLAtom::referencesEnd() const {
300 if (_file->_references.size() < _refEndIndex)
301 return (Reference::iterator)&_file->_references[_refEndIndex];
302 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
320 void makeAtom(YAMLFile *);
321
322private:
323 const char *_name;
324 Atom::Alignment _align;
325 Atom::Combine _combine;
326 Atom::ContentType _type;
327 Atom::Scope _scope;
328 Atom::Definition _def;
329 Atom::SectionChoice _sectionChoice;
330 bool _userVisibleName;
331 bool _dontDeadStrip;
332 bool _thumb;
333 bool _alias;
334 Reference _ref;
335};
336
337YAMLAtomState::YAMLAtomState()
338 : _name(NULL)
339 , _align(0, 0)
340 , _combine(Atom::combineNever)
341 , _type(Atom::typeData)
342 , _scope(Atom::scopeGlobal)
343 , _userVisibleName(true)
344 , _dontDeadStrip(false)
345 , _thumb(false)
346 , _alias(false) {
347 _ref.target = NULL;
348 _ref.addend = 0;
349 _ref.offsetInAtom = 0;
350 _ref.kind = 0;
351 _ref.flags = 0;
352}
353
354void YAMLAtomState::makeAtom(YAMLFile *f) {
355 Atom *a = new YAMLAtom(_def, _combine, _scope, _type, _sectionChoice,
356 _userVisibleName, _dontDeadStrip, _thumb, _alias,
357 _align, f, _name);
358
359 f->_atoms.push_back(a);
360
361 // reset state for next atom
362 _name = NULL;
363 _align.powerOf2 = 0;
364 _align.modulus = 0;
365 _combine = Atom::combineNever;
366 _type = Atom::typeData;
367 _scope = Atom::scopeGlobal;
368 _def = Atom::definitionRegular;
369 _sectionChoice = Atom::sectionBasedOnContent;
370 _userVisibleName = true;
371 _dontDeadStrip = false;
372 _thumb = false;
373 _alias = false;
374 _ref.target = NULL;
375 _ref.addend = 0;
376 _ref.offsetInAtom = 0;
377 _ref.kind = 0;
378 _ref.flags = 0;
379}
380
381void YAMLAtomState::setName(const char *n) {
382 _name = n;
383}
384
385void YAMLAtomState::setScope(const char *s) {
386 if (strcmp(s, "global") == 0)
387 _scope = Atom::scopeGlobal;
388 else if (strcmp(s, "hidden") == 0)
389 _scope = Atom::scopeLinkageUnit;
390 else if (strcmp(s, "static") == 0)
391 _scope = Atom::scopeTranslationUnit;
392 else
393 llvm::report_fatal_error("bad scope value");
394}
395
396void YAMLAtomState::setType(const char *s) {
397 if (strcmp(s, "code") == 0)
398 _type = Atom::typeCode;
399 else if (strcmp(s, "c-string") == 0)
400 _type = Atom::typeCString;
401 else if (strcmp(s, "zero-fill") == 0)
402 _type = Atom::typeZeroFill;
403 else if (strcmp(s, "data") == 0)
404 _type = Atom::typeData;
405 else
406 llvm::report_fatal_error("bad type value");
407}
408
409void YAMLAtomState::setAlign2(const char *s) {
410 llvm::StringRef str(s);
411 uint32_t res;
412 str.getAsInteger(10, res);
413 _align.powerOf2 = static_cast<uint16_t>(res);
414}
415
416void YAMLAtomState::setDefinition(const char *s) {
417 if (strcmp(s, "regular") == 0)
418 _def = Atom::definitionRegular;
419 else if (strcmp(s, "tentative") == 0)
420 _def = Atom::definitionTentative;
421 else if (strcmp(s, "absolute") == 0)
422 _def = Atom::definitionAbsolute;
423 else
424 llvm::report_fatal_error("bad definition value");
425}
426
427void YAMLAtomState::setFixupKind(const char *s) {
428 if (strcmp(s, "pcrel32") == 0)
429 _ref.kind = 1;
430 else if (strcmp(s, "call32") == 0)
431 _ref.kind = 2;
432 else
433 llvm::report_fatal_error("bad fixup kind value");
434}
435
436void YAMLAtomState::setFixupOffset(const char *s) {
437 if ((s[0] == '0') && (s[1] == 'x'))
438 llvm::StringRef(s).getAsInteger(16, _ref.offsetInAtom);
439 else
440 llvm::StringRef(s).getAsInteger(10, _ref.offsetInAtom);
441}
442
443void YAMLAtomState::setFixupTarget(const char *s) {
444}
445
446void YAMLAtomState::addFixup(YAMLFile *f) {
447 f->_references.push_back(_ref);
448 // clear for next ref
449 _ref.target = NULL;
450 _ref.addend = 0;
451 _ref.offsetInAtom = 0;
452 _ref.kind = 0;
453 _ref.flags = 0;
454}
455
456llvm::error_code parseObjectText( llvm::MemoryBuffer *mb
457 , std::vector<File *> &result) {
458 std::vector<const YAML::Entry *> entries;
459 YAML::parse(mb, entries);
460
461 YAMLFile *file = NULL;
462 YAMLAtomState atomState;
463 bool inAtoms = false;
464 bool inFixups = false;
465 int depthForAtoms = -1;
466 int depthForFixups = -1;
467 int lastDepth = -1;
468 bool haveAtom = false;
469 bool haveFixup = false;
470
471 for (std::vector<const YAML::Entry *>::iterator it = entries.begin();
472 it != entries.end(); ++it) {
473 const YAML::Entry *entry = *it;
474
475 if (entry->beginDocument) {
476 if (file != NULL) {
477 if (haveAtom) {
478 atomState.makeAtom(file);
479 haveAtom = false;
480 }
481 result.push_back(file);
482 }
483 file = new YAMLFile();
484 inAtoms = false;
485 depthForAtoms = -1;
486 }
487 if (lastDepth > entry->depth) {
488 // end of fixup sequence
489 if (haveFixup) {
490 atomState.addFixup(file);
491 haveFixup = false;
492 }
493 }
494
495 if (inAtoms && (depthForAtoms == -1)) {
496 depthForAtoms = entry->depth;
497 }
498 if (inFixups && (depthForFixups == -1)) {
499 depthForFixups = entry->depth;
500 }
501 if (strcmp(entry->key, "atoms") == 0) {
502 inAtoms = true;
503 }
504 if (inAtoms) {
505 if (depthForAtoms == entry->depth) {
506 if (entry->beginSequence) {
507 if (haveAtom) {
508 atomState.makeAtom(file);
509 haveAtom = false;
510 }
511 }
512 if (strcmp(entry->key, "name") == 0) {
513 atomState.setName(entry->value);
514 haveAtom = true;
515 } else if (strcmp(entry->key, "scope") == 0) {
516 atomState.setScope(entry->value);
517 haveAtom = true;
518 } else if (strcmp(entry->key, "type") == 0) {
519 atomState.setType(entry->value);
520 haveAtom = true;
521 } else if (strcmp(entry->key, "align2") == 0) {
522 atomState.setAlign2(entry->value);
523 haveAtom = true;
524 } else if (strcmp(entry->key, "definition") == 0) {
525 atomState.setDefinition(entry->value);
526 haveAtom = true;
527 } else if (strcmp(entry->key, "fixups") == 0) {
528 inFixups = true;
529 }
530 } else if (depthForFixups == entry->depth) {
531 if (entry->beginSequence) {
532 if (haveFixup) {
533 atomState.addFixup(file);
534 haveFixup = false;
535 }
536 }
537 if (strcmp(entry->key, "kind") == 0) {
538 atomState.setFixupKind(entry->value);
539 haveFixup = true;
540 } else if (strcmp(entry->key, "offset") == 0) {
541 atomState.setFixupOffset(entry->value);
542 haveFixup = true;
543 } else if (strcmp(entry->key, "target") == 0) {
544 atomState.setFixupTarget(entry->value);
545 haveFixup = true;
546 }
547 }
548 }
549 lastDepth = entry->depth;
550 }
551 if (haveAtom) {
552 atomState.makeAtom(file);
553 }
554
555 result.push_back(file);
556 return success;
557}
558} // namespace yaml
559} // namespace lld