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