xref: /Universal-ctags/parsers/ldscript.c (revision d69940b7160d084b07ccb9a66639454bdd4b5043)
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