• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 %{
2 /* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 2001.
5 
6    This file is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    elfutils is distributed in the hope that it will be useful, but
12    WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22 
23 #include <assert.h>
24 #include <ctype.h>
25 #include <elf.h>
26 #include <error.h>
27 #include <inttypes.h>
28 #include <libintl.h>
29 #include <stdbool.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 #include <system.h>
34 #include <ld.h>
35 #include "ldscript.h"
36 
37 /* We sure use no threads to read the stream, so use the _unlocked
38    variants of the functions.  */
39 #undef getc
40 #define getc(s) getc_unlocked (s)
41 #undef ferror
42 #define ferror(s) ferror_unlocked (s)
43 #undef fread
44 #define fread(b, m, n, s) fread_unlocked (b, m, n, s)
45 #undef fwrite
46 #define fwrite(b, m, n, s) fwrite_unlocked (b, m, n, s)
47 
48 /* ECHO must be redefined since the default implementation ignores
49    the return value of fwrite_unlocked.  */
50 #define ECHO do { size_t n__ __attribute__ ((unused)) \
51 			   = fwrite (yytext, yyleng, 1, yyout); } while (0)
52 
53 /* Defined in ld.c.  */
54 extern int ld_scan_version_script;
55 
56 #define MAX_PREPDEPTH 20
57 static enum prepstate
58 {
59   prep_normal,
60   skip_if,
61   skip_to_endif
62 } prepstate[MAX_PREPDEPTH];
63 static int prepdepth;
64 
65 static void eat_comment (void);
66 static void eat_to_eol (bool empty);
67 static int attrib_convert (int c);
68 static void push_state (enum prepstate);
69 static int pop_state (void);
70 static int handle_ifdef (void);
71 static void invalid_char (int ch);
72 %}
73 
74 ID		[a-zA-Z0-9_.*?][a-zA-Z0-9_.*?-]*
75 FILENAMECHAR1	[a-zA-Z0-9_/.\\~]
76 FILENAMECHAR	[^][{}[:space:]():;]+
77 HEX		0[xX][0-9a-fA-F]+[kKmM]?
78 OCT		0[0-7]*[kKmM]?
79 DEC		[0-9]+[kKmM]?
80 WHITE		[[:space:]]+
81 
82 %option yylineno
83 %option never-interactive
84 %option noyywrap
85 
86 %x IGNORE
87 
88 %%
89 				if (unlikely (ld_scan_version_script))
90 				  {
91 				    ld_scan_version_script = -1;
92 				    return kVERSION_SCRIPT;
93 				  }
94 
95 ^"#"ifdef/[[:space:]]		{ BEGIN (handle_ifdef ()); }
96 ^"#"else/[[:space:]\n]		{ eat_to_eol (true);
97 				  push_state (skip_to_endif);
98 				  BEGIN (IGNORE); }
99 ^"#"elifdef/[[:space:]]		{ eat_to_eol (false);
100 				  push_state (skip_to_endif);
101 				  BEGIN (IGNORE); }
102 ^"#"endif/[[:space:]\n]		{ eat_to_eol (true) ; }
103 
104 <IGNORE>^"#"ifdef/[[:space:]\n] { eat_to_eol (false);
105 				  push_state (skip_to_endif); }
106 <IGNORE>^"#"else/[[:space:]\n]	{ eat_to_eol (true);
107 				  assert (prepdepth > 0);
108 				  if (prepstate[prepdepth - 1] == skip_if)
109 				    {
110 				      /* Back to normal processing.  */
111 				      assert (prepdepth == 1);
112 				      BEGIN (pop_state ());
113 				    }
114 				}
115 <IGNORE>^"#"elifdef/[[:space:]]	{ assert (prepdepth > 0);
116 				  if (prepstate[prepdepth - 1] == skip_if)
117 				    {
118 				      /* Maybe this symbol is defined.  */
119 				      pop_state ();
120 				      BEGIN (handle_ifdef ());
121 				    }
122 				}
123 <IGNORE>^"#"endif/[[:space:]\n] { eat_to_eol (true);
124 				  BEGIN (pop_state ()); }
125 <IGNORE>.|\n			{ /* nothing */ }
126 
127 
128 "/*"				{ eat_comment (); }
129 
130 ALIGN				{ return kALIGN; }
131 AS_NEEDED			{ return kAS_NEEDED; }
132 ENTRY				{ return kENTRY; }
133 EXCLUDE_FILE			{ return kEXCLUDE_FILE; }
134 "global:"			{ return kGLOBAL; }
135 GROUP				{ return kGROUP; }
136 INPUT				{ return kINPUT; }
137 INTERP				{ return kINTERP; }
138 KEEP				{ return kKEEP; }
139 "local:"			{ return kLOCAL; }
140 OUTPUT_FORMAT			{ return kOUTPUT_FORMAT; }
141 PAGESIZE			{ return kPAGESIZE; }
142 PROVIDE				{ return kPROVIDE; }
143 SEARCH_DIR			{ return kSEARCH_DIR; }
144 SEGMENT				{ return kSEGMENT; }
145 SIZEOF_HEADERS			{ return kSIZEOF_HEADERS; }
146 SORT				{ return kSORT; }
147 VERSION				{ return kVERSION; }
148 
149 "["([RWX]){0,3}"]"		{ unsigned int cnt = 1 ;
150 				  ldlval.num = 0;
151 				  while (cnt < yyleng - 1)
152 				    ldlval.num |= attrib_convert (yytext[cnt++]);
153 				  return kMODE; }
154 
155 "{"				{ return '{'; }
156 "}"				{ return '}'; }
157 "("				{ return '('; }
158 ")"				{ return ')'; }
159 ":"				{ return ':'; }
160 ";"				{ return ';'; }
161 "="				{ return '='; }
162 "+"				{ ldlval.op = exp_plus; return kADD_OP; }
163 "-"				{ ldlval.op = exp_minus; return kADD_OP; }
164 "*"				{ return '*'; }
165 "/"				{ ldlval.op = exp_div; return kMUL_OP; }
166 "%"				{ ldlval.op = exp_mod; return kMUL_OP; }
167 "&"				{ return '&'; }
168 "|"				{ return '|'; }
169 
170 ","				{ return ','; }
171 
172 {HEX}|{OCT}|{DEC}		{ char *endp;
173 				  ldlval.num = strtoumax (yytext, &endp, 0);
174 				  if (*endp != '\0')
175 				    {
176 				      if (tolower (*endp) == 'k')
177 					ldlval.num *= 1024;
178 				      else
179 					{
180 					  assert (tolower (*endp) == 'm');
181 					  ldlval.num *= 1024 * 1024;
182 					}
183 				    }
184 				  return kNUM; }
185 
186 {ID}				{ ldlval.str = obstack_strndup (&ld_state.smem,
187 								yytext, yyleng);
188 				  return kID; }
189 
190 {FILENAMECHAR1}{FILENAMECHAR}	{ ldlval.str = obstack_strndup (&ld_state.smem,
191 								yytext, yyleng);
192 				  return kFILENAME; }
193 
194 {WHITE}				{ /* IGNORE */ }
195 
196 .				{ invalid_char (*yytext); }
197 
198 %%
199 
200 static void
201 eat_comment (void)
202 {
203   while (1)
204     {
205       int c = input ();
206 
207       while (c != '*' && c != EOF)
208 	c = input ();
209 
210       if (c == '*')
211 	{
212 	  c = input ();
213 	  while (c == '*')
214 	    c = input ();
215 	  if (c == '/')
216 	    break;
217 	}
218 
219       if (c == EOF)
220 	{
221 	  /* XXX Use the setjmp buffer and signal EOF in comment */
222 	  error (0, 0, gettext ("EOF in comment"));
223 	  break;
224 	}
225     }
226 }
227 
228 
229 static void
eat_to_eol(bool empty)230 eat_to_eol (bool empty)
231 {
232   bool warned = false;
233 
234   while (1)
235     {
236       int c = input ();
237 
238       if (c == EOF)
239 	break;
240       if (c == '\n')
241 	{
242 	  ++yylineno;
243 	  break;
244 	}
245 
246       if (empty && ! isspace (c) && ! warned)
247 	{
248 	  error (0, 0, gettext ("%d: garbage at end of line"), yylineno);
249 	  warned = true;
250 	}
251     }
252 }
253 
254 
255 static int
attrib_convert(int c)256 attrib_convert (int c)
257 {
258   if (c == 'X')
259     return PF_X;
260   if (c == 'W')
261     return PF_W;
262   assert (c == 'R');
263   return PF_R;
264 }
265 
266 
267 static void
push_state(enum prepstate state)268 push_state (enum prepstate state)
269 {
270   if (prepdepth >= MAX_PREPDEPTH)
271     error (EXIT_FAILURE, 0, gettext ("%d: conditionals nested too deep"),
272 	   yylineno);
273 
274   prepstate[prepdepth++] = state;
275 }
276 
277 
278 static int
pop_state(void)279 pop_state (void)
280 {
281   if (prepdepth == 0)
282     error (0, 0, gettext ("%d: unexpected #endif"), yylineno);
283   else
284     --prepdepth;
285 
286   return prepdepth == 0 ? INITIAL : IGNORE;
287 }
288 
289 
290 static int
handle_ifdef(void)291 handle_ifdef (void)
292 {
293   char idbuf[50];
294   char *id = idbuf;
295   size_t idlen = 0;
296   size_t idmax = sizeof (idbuf);
297   bool ignore_ws = true;
298   bool defined = false;
299   int result;
300 
301   while (1)
302     {
303       int c = input ();
304 
305       if (isspace (c) && ignore_ws)
306 	continue;
307 
308       if (c != '_' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z')
309 	  && (idlen == 0 || c < '0' || c > '9'))
310 	{
311 	  unput (c);
312 	  break;
313 	}
314 
315       if (idlen == idmax)
316 	{
317 	  char *newp = (char *) alloca (idmax *= 2);
318 	  id = memcpy (newp, id, idlen);
319 	}
320 
321       id[idlen++] = c;
322       ignore_ws = false;
323     }
324 
325   /* XXX Compare in a better way.  */
326   if (idlen == 6 && strncmp (id, "SHARED", 6) == 0)
327     defined = ld_state.file_type == dso_file_type;
328 
329   if (defined)
330     result = INITIAL;
331   else
332     {
333       push_state (skip_if);
334       result = IGNORE;
335     }
336 
337   return result;
338 }
339 
340 
341 static void
invalid_char(int ch)342 invalid_char (int ch)
343 {
344   error (0, 0, (isascii (ch)
345 		? gettext ("invalid character '%c' at line %d; ignored")
346 		: gettext ("invalid character '\\%o' at line %d; ignored")),
347 	 ch, yylineno);
348 }
349 
350 
351 // Local Variables:
352 // mode: C
353 // End:
354