1 /*
2 * Copyright (c) 2016, Masatake YAMATO
3 * Copyright (c) 2016, Red Hat, Inc.
4 *
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License version 2 or (at your option) any later version.
7 *
8 * This module contains functions for generating tags for GNU linker script
9 * files.
10 */
11
12 #include "general.h"
13 #include "tokeninfo.h"
14
15 #include "entry.h"
16 #include "cpreprocessor.h"
17 #include "keyword.h"
18 #include "parse.h"
19 #include "ptrarray.h"
20 #include "read.h"
21 #include "trace.h"
22 #include "xtag.h"
23
24 #include <string.h>
25
26 /*
27 * DATA DEFINITIONS
28 */
29
30 typedef enum {
31 LD_SCRIPT_SYMBOL_ENTRYPOINT,
32 } ldScriptSymbolRole;
33
34 static roleDefinition LdScriptSymbolRoles [] = {
35 { true, "entrypoint", "entry points" },
36 };
37
38 typedef enum {
39 LD_SCRIPT_INPUT_SECTION_MAPPED,
40 LD_SCRIPT_INPUT_SECTION_DISCARDED,
41 } ldScriptInputSectionRole;
42
43 static roleDefinition LdScriptInputSectionRoles [] = {
44 { true, "mapped", "mapped to output section" },
45 { true, "discarded", "discarded when linking" },
46 };
47
48 typedef enum {
49 K_SECTION,
50 K_SYMBOL,
51 K_VERSION,
52 K_INPUT_SECTION,
53 } ldScriptKind;
54
55 static kindDefinition LdScriptKinds [] = {
56 { true, 'S', "section", "sections" },
57 { true, 's', "symbol", "symbols",
58 .referenceOnly = false, ATTACH_ROLES(LdScriptSymbolRoles)},
59 { true, 'v', "version", "versions" },
60 { true, 'i', "inputSection", "input sections",
61 .referenceOnly = true, ATTACH_ROLES(LdScriptInputSectionRoles)},
62 };
63
64 enum {
65 KEYWORD_ENTRY,
66 KEYWORD_SECTIONS,
67 KEYWORD_LOC,
68 KEYWORD_AT,
69 KEYWORD_VERSION,
70 KEYWORD_PROVIDE,
71 KEYWORD_PROVIDE_HIDDEN,
72 KEYWORD_HIDDEN,
73 KEYWORD_EXCLUDE_FILE,
74 KEYWORD_INPUT_SECTION_FLAGS,
75 KEYWORD_COMMON,
76 KEYWORD_KEEP,
77 KEYWORD_DATA,
78 };
79 typedef int keywordId; /* to allow KEYWORD_NONE */
80
81
82 static const keywordTable LdScriptKeywordTable[] = {
83 /* keyword keyword ID */
84 { "ENTRY", KEYWORD_ENTRY },
85 { "SECTIONS", KEYWORD_SECTIONS },
86 { ".", KEYWORD_LOC },
87 { "AT", KEYWORD_AT },
88 { "VERSION", KEYWORD_VERSION },
89 { "PROVIDE", KEYWORD_PROVIDE },
90 { "PROVIDE_HIDDEN", KEYWORD_PROVIDE_HIDDEN },
91 { "HIDDEN", KEYWORD_HIDDEN },
92 { "EXCLUDE_FILE", KEYWORD_EXCLUDE_FILE },
93 { "INPUT_SECTION_FLAGS", KEYWORD_INPUT_SECTION_FLAGS },
94 { "COMMON", KEYWORD_COMMON },
95 { "KEEP", KEYWORD_KEEP },
96 { "BYTE", KEYWORD_DATA },
97 { "SHORT", KEYWORD_DATA },
98 { "LONG", KEYWORD_DATA },
99 { "QUAD", KEYWORD_DATA },
100 { "SQUAD", KEYWORD_DATA },
101 { "FILL", KEYWORD_DATA },
102 };
103
104 enum eTokenType {
105 /* 0..255 are the byte's value */
106 TOKEN_EOF = 256,
107 TOKEN_UNDEFINED,
108 TOKEN_KEYWORD,
109 TOKEN_IDENTIFIER,
110 TOKEN_NUMBER,
111 TOKEN_ASSIGNMENT_OP,
112 TOKEN_OP,
113 TOKEN_PHDIR,
114 TOKEN_REGION,
115 TOKEN_FILLEXP,
116 TOKEN_DISCARD,
117 };
118
119 static void readToken (tokenInfo *const token, void *data CTAGS_ATTR_UNUSED);
120 static void clearToken (tokenInfo *token);
121 static void copyToken (tokenInfo *dest, tokenInfo *src, void *data CTAGS_ATTR_UNUSED);
122
123 typedef struct sLdScriptToken {
124 tokenInfo base;
125 int scopeIndex;
126 tokenKeyword assignment;
127 bool whitespacePrefixed;
128 } ldScriptToken;
129
130 #define LDSCRIPT(TOKEN) ((ldScriptToken *)TOKEN)
131
132 static struct tokenTypePair ldScriptTypePairs [] = {
133 { '{', '}' },
134 };
135
136 static struct tokenInfoClass ldScriptTokenInfoClass = {
137 .nPreAlloc = 4,
138 .typeForUndefined = TOKEN_UNDEFINED,
139 .keywordNone = KEYWORD_NONE,
140 .typeForKeyword = TOKEN_KEYWORD,
141 .typeForEOF = TOKEN_EOF,
142 .extraSpace = sizeof (ldScriptToken) - sizeof (tokenInfo),
143 .pairs = ldScriptTypePairs,
144 .pairCount = ARRAY_SIZE (ldScriptTypePairs),
145 .read = readToken,
146 .clear = clearToken,
147 .copy = copyToken,
148 };
149
150 typedef enum {
151 F_ASSIGNMENT,
152 COUNT_FIELD
153 } ldScriptField;
154
155 static fieldDefinition LdScriptFields[COUNT_FIELD] = {
156 { .name = "assignment",
157 .description = "how a value is assigned to the symbol",
158 .enabled = true },
159 };
160
161 static langType Lang_ldscript;
162
163 /*
164 * FUNCTION DEFINITIONS
165 */
166
newLdScriptToken(void)167 static tokenInfo *newLdScriptToken (void)
168 {
169 return newToken (&ldScriptTokenInfoClass);
170 }
171
clearToken(tokenInfo * token)172 static void clearToken (tokenInfo *token)
173 {
174 LDSCRIPT(token)->scopeIndex = CORK_NIL;
175 LDSCRIPT(token)->assignment = KEYWORD_NONE;
176 }
177
copyToken(tokenInfo * dest,tokenInfo * src,void * data CTAGS_ATTR_UNUSED)178 static void copyToken (tokenInfo *dest, tokenInfo *src, void *data CTAGS_ATTR_UNUSED)
179 {
180 LDSCRIPT (dest)->scopeIndex =
181 LDSCRIPT (src)->scopeIndex;
182 LDSCRIPT (dest)->assignment =
183 LDSCRIPT (src)->assignment;
184 LDSCRIPT (dest)->whitespacePrefixed =
185 LDSCRIPT (src)->whitespacePrefixed;
186 }
187
makeLdScriptTagMaybe(tagEntryInfo * const e,tokenInfo * const token,int kind,int role)188 static int makeLdScriptTagMaybe (tagEntryInfo *const e, tokenInfo *const token,
189 int kind, int role)
190 {
191 if (role == ROLE_DEFINITION_INDEX)
192 {
193 if (! LdScriptKinds[kind].enabled)
194 return CORK_NIL;
195 }
196 else if (! (isXtagEnabled (XTAG_REFERENCE_TAGS)
197 && LdScriptKinds[kind].roles[role].enabled))
198 return CORK_NIL;
199
200 initRefTagEntry (e, tokenString (token),
201 kind,
202 role);
203 e->lineNumber = token->lineNumber;
204 e->filePosition = token->filePosition;
205 e->extensionFields.scopeIndex = LDSCRIPT (token)->scopeIndex;
206
207 /* TODO: implement file: field. */
208 if ((kind == K_SYMBOL)
209 && LdScriptFields[F_ASSIGNMENT].enabled)
210 {
211 const char *assignment = NULL;
212
213 switch (LDSCRIPT (token)->assignment)
214 {
215 case KEYWORD_PROVIDE:
216 assignment = "provide";
217 break;
218 case KEYWORD_PROVIDE_HIDDEN:
219 assignment = "provide_hidden";
220 break;
221 case KEYWORD_HIDDEN:
222 assignment = "hidden";
223 break;
224 }
225
226 if (assignment)
227 attachParserField (e, false, LdScriptFields[F_ASSIGNMENT].ftype,
228 assignment);
229 }
230
231 return makeTagEntry (e);
232 }
233
234 #define isIdentifierChar(c) \
235 (cppIsalnum (c) || (c) == '_' || (c) == '.' || (c) == '-' || (c) >= 0x80)
236
readPrefixedToken(tokenInfo * const token,int type)237 static int readPrefixedToken (tokenInfo *const token, int type)
238 {
239 int n = 0;
240 int c;
241
242 while ((c = cppGetc()) != EOF)
243 {
244 if (isIdentifierChar (c))
245 {
246 n++;
247 tokenPutc (token, c);
248 }
249 else
250 {
251 cppUngetc (c);
252 break;
253 }
254 }
255
256 if (n)
257 token->type = type;
258 return n;
259 }
260
261 // We stop applying macro replacements if a macro is used so many
262 // times in a recursive macro expansion.
263 #define LD_SCRIPT_PARSER_MAXIMUM_MACRO_USE_COUNT 8
264
collectMacroArguments(ptrArray * args)265 static bool collectMacroArguments (ptrArray *args)
266 {
267 vString *s = vStringNew ();
268 tokenInfo *const t = newLdScriptToken ();
269 int depth = 1;
270
271 do
272 {
273 tokenRead (t);
274
275 if (tokenIsType (t, EOF))
276 break;
277 else if (tokenIsTypeVal (t, ')'))
278 {
279 depth--;
280 if (depth == 0)
281 {
282 char *cstr = vStringDeleteUnwrap (s);
283 ptrArrayAdd (args, cstr);
284 s = NULL;
285 }
286 else
287 vStringCat (s, t->string);
288 }
289 else if (tokenIsTypeVal (t, '('))
290 {
291 depth++;
292 vStringCat (s, t->string);
293 }
294 else if (tokenIsTypeVal (t, ','))
295 {
296 char *cstr = vStringDeleteUnwrap (s);
297 ptrArrayAdd (args, cstr);
298 s = vStringNew ();
299 }
300 else
301 {
302 if (LDSCRIPT(t)->whitespacePrefixed)
303 vStringPut(s, ' ');
304 vStringCat (s, t->string);
305 }
306 }
307 while (depth > 0);
308
309 vStringDelete (s); /* NULL is acceptable. */
310
311 tokenDelete (t);
312
313 if (depth > 0)
314 TRACE_PRINT("unbalanced argument list");
315
316 return (depth > 0)? false: true;
317 }
318
expandCppMacro(cppMacroInfo * macroInfo)319 static bool expandCppMacro (cppMacroInfo *macroInfo)
320 {
321 ptrArray *args = NULL;
322
323 if (macroInfo->hasParameterList)
324 {
325 tokenInfo *const t = newLdScriptToken ();
326
327 /* Though macro arguments are expected, they are not found. */
328 tokenRead (t);
329 if (!tokenIsTypeVal (t, '('))
330 {
331 tokenUnread (t);
332 tokenDelete (t);
333 TRACE_PRINT("no argument for the %s<%p>", macroInfo->name, macroInfo);
334 return false;
335 }
336
337 args = ptrArrayNew (eFree);
338 if (!collectMacroArguments (args))
339 {
340 ptrArrayDelete (args);
341 tokenUnread (t);
342 tokenDelete (t);
343 return false;
344 }
345 tokenDelete (t);
346 }
347
348 #ifdef DO_TRACING
349 for (int i = 0; i < ptrArrayCount(args); i++)
350 TRACE_PRINT("[%d] %s", i, (const char *)ptrArrayItem (args, i));
351 #endif
352
353 cppBuildMacroReplacementWithPtrArrayAndUngetResult (macroInfo, args);
354
355 ptrArrayDelete (args); /* NULL is acceptable. */
356 return true;
357 }
358
readToken(tokenInfo * const token,void * data CTAGS_ATTR_UNUSED)359 static void readToken (tokenInfo *const token, void *data CTAGS_ATTR_UNUSED)
360 {
361 int c, c0, c1;
362
363 token->type = TOKEN_UNDEFINED;
364 token->keyword = KEYWORD_NONE;
365 vStringClear (token->string);
366
367 int prefix_count = -1;
368 LDSCRIPT (token)->whitespacePrefixed = false;
369 do {
370 c = cppGetc();
371 prefix_count++;
372 if (prefix_count > 0)
373 LDSCRIPT (token)->whitespacePrefixed = true;
374 } while (c == ' ' || c== '\t' || c == '\f' || c == '\r' || c == '\n'
375 || c == STRING_SYMBOL || c == CHAR_SYMBOL);
376
377 token->lineNumber = getInputLineNumber ();
378 token->filePosition = getInputFilePosition ();
379
380 switch (c)
381 {
382 case EOF:
383 token->type = TOKEN_EOF;
384 break;
385 case ';':
386 case '(':
387 case ')':
388 case '{':
389 case '}':
390 case '[':
391 case ']':
392 tokenPutc(token, c);
393 token->type = c;
394 break;
395 case '~':
396 case '%':
397 case '?':
398 tokenPutc(token, c);
399 token->type = TOKEN_OP;
400 break;
401 case '-':
402 case '+':
403 case '*':
404 case '/': /* -,+,*,/,-=,+=,*=,/= */
405 tokenPutc(token, c);
406 c0 = cppGetc ();
407 token->type = TOKEN_OP;
408 if (c0 == '=')
409 {
410 tokenPutc(token, c0);
411 token->type = TOKEN_ASSIGNMENT_OP;
412 }
413 else if (c == '/' && c0 == 'D')
414 {
415 tokenInfo *const discard = newLdScriptToken ();
416
417 cppUngetc (c0);
418 tokenRead (discard);
419 if (tokenIsType(discard, IDENTIFIER) &&
420 (strcmp(tokenString(discard), "DISCARD")) == 0)
421 {
422 c1 = cppGetc ();
423 if (c1 == '/')
424 token->type = TOKEN_DISCARD;
425 else
426 {
427 cppUngetc (c1);
428 tokenUnread (discard);
429 }
430 }
431 else
432 tokenUnread (discard);
433 tokenDelete (discard);
434 }
435 else
436 cppUngetc (c0);
437 break;
438 case '!': /* !, != */
439 tokenPutc(token, c);
440 token->type = TOKEN_OP;
441 c0 = cppGetc ();
442 if (c0 == '=')
443 tokenPutc(token, c0);
444 else
445 cppUngetc (c0);
446 case '<': /* <,<=,<<,<<= */
447 tokenPutc(token, c);
448 token->type = TOKEN_OP;
449 c0 = cppGetc ();
450 if (c0 == c || c0 == '=')
451 {
452 tokenPutc(token, c0);
453 if (c0 == c)
454 {
455 c1 = cppGetc ();
456 if (c1 == '=')
457 {
458 tokenPutc(token, c1);
459 token->type = TOKEN_ASSIGNMENT_OP;
460 }
461 else
462 cppUngetc (c1);
463 }
464 }
465 else
466 cppUngetc (c0);
467 case '|': /* |,||,|= */
468 case '&': /* &,&&,&= */
469 tokenPutc(token, c);
470 token->type = TOKEN_OP;
471 c0 = cppGetc ();
472 if (c0 == c)
473 tokenPutc(token, c0);
474 else if (c0 == '=')
475 {
476 tokenPutc(token, c0);
477 token->type = TOKEN_ASSIGNMENT_OP;
478 }
479 else
480 cppUngetc (c0);
481 break;
482 case '=': /* =,== */
483 tokenPutc(token, c);
484 if (!readPrefixedToken (token, TOKEN_FILLEXP))
485 {
486 c0 = cppGetc ();
487 if (c0 == '=')
488 {
489 tokenPutc(token, c0);
490 token->type = TOKEN_OP;
491 }
492 else
493 {
494 cppUngetc (c0);
495 token->type = TOKEN_ASSIGNMENT_OP;
496 }
497 }
498 break;
499 case '>': /* >,>>,>>= */
500 tokenPutc(token, c);
501 if (!readPrefixedToken (token, TOKEN_REGION))
502 {
503 token->type = TOKEN_OP;
504 c0 = cppGetc ();
505 if (c0 == c || c0 == '=')
506 {
507 tokenPutc(token, c0);
508 c1 = cppGetc();
509 if (c1 == '=')
510 {
511 tokenPutc(token, c1);
512 token->type = TOKEN_ASSIGNMENT_OP;
513 }
514 else
515 cppUngetc (c1);
516 }
517 else
518 cppUngetc (c0);
519 }
520 break;
521 case ':':
522 tokenPutc(token, c);
523 if (!readPrefixedToken (token, TOKEN_PHDIR))
524 token->type = c;
525 break;
526 default:
527 if (cppIsdigit (c))
528 {
529 /* Using cppIsdigit here is redundant.
530 *
531 * `c' never takes STRING_SYMBOL or CHAR_SYMBOL as
532 * its value here.
533 * However, the practice using cppIs... macros for the value
534 * returned from cppGetc() may avoid unexpected programming
535 * mistakes I took repeatedly.
536 */
537 token->type = TOKEN_NUMBER;
538 tokenPutc(token, c);
539 while ((c = cppGetc()))
540 {
541 if (isIdentifierChar (c))
542 tokenPutc(token, c);
543 else
544 {
545 cppUngetc (c);
546 break;
547 }
548 }
549 }
550 else if (isIdentifierChar(c))
551 {
552 tokenPutc(token, c);
553 while ((c = cppGetc()))
554 {
555 if (isIdentifierChar(c))
556 tokenPutc(token, c);
557 else
558 {
559 cppUngetc (c);
560 break;
561 }
562 }
563 token->keyword = lookupKeyword (vStringValue (token->string), Lang_ldscript);
564 if (token->keyword == KEYWORD_NONE)
565 {
566 token->type = TOKEN_IDENTIFIER;
567
568 cppMacroInfo *macroInfo = cppFindMacro (vStringValue (token->string));
569 if (macroInfo)
570 {
571 TRACE_PRINT("Macro expansion: %s<%p>%s", vStringValue (token->string),
572 macroInfo, macroInfo->hasParameterList? "(...)": "");
573 if (!(macroInfo->useCount < LD_SCRIPT_PARSER_MAXIMUM_MACRO_USE_COUNT))
574 TRACE_PRINT ("Overly uesd macro %s<%p> useCount: %d (> %d)",
575 vStringValue (token->string), macroInfo, macroInfo->useCount,
576 LD_SCRIPT_PARSER_MAXIMUM_MACRO_USE_COUNT);
577 else if (expandCppMacro (macroInfo))
578 readToken (token, NULL);
579 }
580 }
581 else
582 token->type = TOKEN_KEYWORD;
583 }
584 else
585 {
586 tokenPutc(token, c);
587 token->type = c;
588 }
589 break;
590 }
591 }
592
parseEntry(tokenInfo * const token)593 static void parseEntry (tokenInfo *const token)
594 {
595 tokenRead (token);
596 if (token->type == '(')
597 {
598 tokenInfo *const name = newLdScriptToken ();
599
600 tokenRead (name);
601 if (tokenIsType(name, IDENTIFIER))
602 {
603 tagEntryInfo e;
604
605 makeLdScriptTagMaybe (&e, name, K_SYMBOL, LD_SCRIPT_SYMBOL_ENTRYPOINT);
606 tokenRead (token);
607 tokenSkipToType (token, ')');
608 }
609 tokenDelete (name);
610 }
611 }
612
parseProvide(tokenInfo * token)613 static void parseProvide (tokenInfo * token)
614 {
615 tokenKeyword p = token->keyword;
616
617 if (tokenSkipToType (token, '('))
618 {
619 tagEntryInfo e;
620 tokenRead (token);
621 if (tokenIsType(token, IDENTIFIER))
622 {
623 LDSCRIPT (token)->assignment = p;
624
625 makeLdScriptTagMaybe (&e, token,
626 K_SYMBOL, ROLE_DEFINITION_INDEX);
627 LDSCRIPT (token)->assignment = KEYWORD_NONE;
628 }
629 tokenSkipToType (token, ')');
630 }
631 }
632
633 /* An example of input sections:
634
635 (.text .rdata)
636
637 .text and .rtada are input sections. */
parseInputSections(tokenInfo * const token)638 static void parseInputSections (tokenInfo *const token)
639 {
640 tagEntryInfo e;
641 do {
642 tokenRead (token);
643 if (token->type == ')')
644 break;
645 else if (tokenIsType (token, IDENTIFIER))
646 makeLdScriptTagMaybe (&e, token,
647 K_INPUT_SECTION,
648 LDSCRIPT(token)->scopeIndex == CORK_NIL
649 ? LD_SCRIPT_INPUT_SECTION_DISCARDED
650 : LD_SCRIPT_INPUT_SECTION_MAPPED);
651 else if (tokenIsKeyword (token, EXCLUDE_FILE))
652 tokenSkipToType (token, ')');
653 } while (!tokenIsEOF (token));
654 }
655
656 /* Symbols and input sections are captured here.
657 An example of output sections:
658
659 __brk_base = .;
660 . += 64 * 1024;
661 *(.brk_reservation)
662 __brk_limit = .;
663
664 __brk_base and __brk_limit should be recorded as a symbol.
665 .brk_reservationshould be recorded as an input section. */
666
parseOutputSectionCommands(tokenInfo * const token,int terminator)667 static void parseOutputSectionCommands (tokenInfo *const token, int terminator)
668 {
669 tokenInfo *const tmp = newLdScriptToken ();
670 int scope_index = LDSCRIPT (token)->scopeIndex;
671
672 do {
673 tokenRead (token);
674 LDSCRIPT (token)->scopeIndex = scope_index;
675
676 if (tokenIsKeyword (token, INPUT_SECTION_FLAGS))
677 {
678 tokenSkipToType (token, '(');
679 tokenSkipToType (token, ')');
680 }
681 else if (tokenIsKeyword (token, KEEP))
682 {
683 tokenSkipToType (token, '(');
684 parseOutputSectionCommands (token, ')');
685 }
686 else if (tokenIsType (token,IDENTIFIER)
687 || tokenIsKeyword (token, LOC))
688 {
689 tagEntryInfo e;
690
691 tokenRead (tmp);
692 if (tokenIsType (tmp, ASSIGNMENT_OP))
693 {
694 if (! tokenIsKeyword (token, LOC))
695 makeLdScriptTagMaybe (&e, token,
696 K_SYMBOL, ROLE_DEFINITION_INDEX);
697 tokenSkipToType (token, ';');
698 }
699 else if (tmp->type == '(')
700 parseInputSections (token);
701 else
702 tokenUnread (tmp);
703 }
704 /* `*',`?', `[', `]' can be part of a pattern of input object file names
705 as a meta character.
706 `[' can enumerated here because it cannot be at the end of pattern. */
707 else if ((token->type == TOKEN_OP
708 && ((tokenString(token)[0] == '*')
709 || (tokenString(token)[0] == '?'))
710 && (tokenString(token)[1] == '\0'))
711 || token->type == ']')
712 {
713 tokenRead (tmp);
714 if (tmp->type == '(')
715 parseInputSections (token);
716 else
717 tokenUnread (tmp);
718 }
719 else if (tokenIsKeyword (token, PROVIDE)
720 || tokenIsKeyword (token, PROVIDE_HIDDEN)
721 || tokenIsKeyword (token, HIDDEN))
722 parseProvide (token);
723 } while (! (tokenIsEOF (token) || token->type == terminator));
724
725 tokenDelete (tmp);
726 }
727
parseSection(tokenInfo * name)728 static void parseSection (tokenInfo * name)
729 {
730 tokenInfo *const token = newLdScriptToken ();
731 tagEntryInfo e;
732
733 tokenRead (token);
734
735 if (tokenIsType (token, ASSIGNMENT_OP))
736 {
737 if (!tokenIsKeyword (name, LOC))
738 makeLdScriptTagMaybe (&e, name,
739 K_SYMBOL, ROLE_DEFINITION_INDEX);
740 tokenSkipToType (token, ';');
741 }
742 else
743 {
744 retry:
745 if (tokenIsType (token, NUMBER))
746 tokenSkipToType (token, ':');
747 else if (tokenIsType (token, IDENTIFIER))
748 {
749 tokenCopy (name, token);
750 tokenRead (token);
751 goto retry;
752 }
753 else if (token->type == '(')
754 tokenSkipToType (token, ')');
755
756 if (token->type == ':')
757 {
758 int scope_index;
759
760 if (tokenIsType (name, DISCARD))
761 scope_index = CORK_NIL;
762 else
763 scope_index = makeLdScriptTagMaybe (&e, name,
764 K_SECTION, ROLE_DEFINITION_INDEX);
765
766 if (tokenSkipToType (token, '{'))
767 {
768 LDSCRIPT (token)->scopeIndex = scope_index;
769 parseOutputSectionCommands (token, '}');
770 }
771 }
772 }
773 tokenDelete (token);
774 }
775
parseSections(tokenInfo * const token)776 static void parseSections (tokenInfo *const token)
777 {
778 tokenRead (token);
779 if (token->type == '{')
780 {
781 do {
782 tokenRead (token);
783 if (tokenIsKeyword (token, ENTRY))
784 parseEntry (token);
785 else if (tokenIsType(token, IDENTIFIER)
786 || tokenIsKeyword (token, LOC)
787 || tokenIsType (token, DISCARD))
788 parseSection (token);
789 else if (tokenIsKeyword (token, PROVIDE)
790 || tokenIsKeyword (token, PROVIDE_HIDDEN)
791 || tokenIsKeyword (token, HIDDEN))
792 parseProvide (token);
793 } while (! (tokenIsEOF (token) || token->type == '}'));
794 }
795 }
796
parseVersion(tokenInfo * const token)797 static void parseVersion (tokenInfo *const token)
798 {
799 tagEntryInfo e;
800 makeLdScriptTagMaybe (&e, token,
801 K_VERSION, ROLE_DEFINITION_INDEX);
802
803 if (tokenSkipToType (token, '{'))
804 tokenSkipOverPair (token);
805 }
806
parseVersions(tokenInfo * const token)807 static void parseVersions (tokenInfo *const token)
808 {
809 tokenRead (token);
810 if (token->type == '{')
811 {
812 do {
813 tokenRead (token);
814 if (tokenIsType(token, IDENTIFIER))
815 parseVersion (token);
816 } while (! (tokenIsEOF (token) || token->type == '}'));
817 tokenSkipToType (token, ';');
818 }
819 }
820
findLdScriptTags(void)821 static void findLdScriptTags (void)
822 {
823 tokenInfo *const token = newLdScriptToken ();
824 tokenInfo *const tmp = newLdScriptToken ();
825
826 cppInit (false, false, false, false,
827 KIND_GHOST_INDEX, 0, 0,
828 KIND_GHOST_INDEX,
829 KIND_GHOST_INDEX, 0, 0,
830 FIELD_UNKNOWN);
831
832 do {
833 tokenRead (token);
834 if (tokenIsKeyword (token, ENTRY))
835 parseEntry (token);
836 else if (tokenIsKeyword (token, SECTIONS))
837 parseSections (token);
838 else if (tokenIsType(token, IDENTIFIER))
839 {
840 tagEntryInfo e;
841 tokenRead (tmp);
842 if (tokenIsType(tmp, ASSIGNMENT_OP))
843 {
844 makeLdScriptTagMaybe (&e, token,
845 K_SYMBOL, ROLE_DEFINITION_INDEX);
846 tokenSkipToType (tmp, ';');
847 }
848 }
849 else if (tokenIsKeyword (token, VERSION))
850 parseVersions(token);
851 } while (!tokenIsEOF (token));
852
853 cppTerminate ();
854
855 tokenDelete (tmp);
856 tokenDelete (token);
857
858 flashTokenBacklog (&ldScriptTokenInfoClass);
859 }
860
initialize(const langType language)861 static void initialize (const langType language)
862 {
863 Lang_ldscript = language;
864 }
865
LdScriptParser(void)866 extern parserDefinition* LdScriptParser (void)
867 {
868 parserDefinition* def = parserNew ("LdScript");
869
870 /* File name patters are picked from Linux kernel and ecos. */
871 static const char *const extensions [] = { "lds", "scr", "ld", "ldi", NULL };
872
873 /* lds.S must be here because Asm parser registers .S as an extension.
874 * ld.script is used in linux/arch/mips/boot/compressed/ld.script. */
875 static const char *const patterns [] = { "*.lds.S", "ld.script", NULL };
876
877 /* Emacs's mode */
878 static const char *const aliases [] = { "ld-script", NULL };
879
880 def->initialize = initialize;
881 def->parser = findLdScriptTags;
882
883 def->kindTable = LdScriptKinds;
884 def->kindCount = ARRAY_SIZE (LdScriptKinds);
885 def->extensions = extensions;
886 def->patterns = patterns;
887 def->aliases = aliases;
888 def->keywordTable = LdScriptKeywordTable;
889 def->keywordCount = ARRAY_SIZE (LdScriptKeywordTable);
890 def->fieldTable = LdScriptFields;
891 def->fieldCount = ARRAY_SIZE (LdScriptFields);
892
893 def->useCork = CORK_QUEUE|CORK_SYMTAB;
894
895 return def;
896 }
897