blob: bfc8bbe53c2b8200055f5ea15a2751f9330bb2c5 [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001%{
2/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Red Hat, Inc.
Elliott Hughes03333822015-02-18 22:19:45 -08003 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004 Written by Ulrich Drepper <drepper@redhat.com>, 2001.
5
Elliott Hughes03333822015-02-18 22:19:45 -08006 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.
Ben Cheng25b3c042013-11-20 14:45:36 -080010
Elliott Hughes03333822015-02-18 22:19:45 -080011 elfutils is distributed in the hope that it will be useful, but
Ben Cheng25b3c042013-11-20 14:45:36 -080012 WITHOUT ANY WARRANTY; without even the implied warranty of
Elliott Hughes03333822015-02-18 22:19:45 -080013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
Ben Cheng25b3c042013-11-20 14:45:36 -080015
Elliott Hughes03333822015-02-18 22:19:45 -080016 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080018
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. */
54extern int ld_scan_version_script;
55
56#define MAX_PREPDEPTH 20
57static enum prepstate
58{
59 prep_normal,
60 skip_if,
61 skip_to_endif
62} prepstate[MAX_PREPDEPTH];
63static int prepdepth;
64
65static void eat_comment (void);
66static void eat_to_eol (bool empty);
67static int attrib_convert (int c);
68static void push_state (enum prepstate);
69static int pop_state (void);
70static int handle_ifdef (void);
71static void invalid_char (int ch);
72%}
73
74ID [a-zA-Z0-9_.*?][a-zA-Z0-9_.*?-]*
75FILENAMECHAR1 [a-zA-Z0-9_/.\\~]
76FILENAMECHAR [^][{}[:space:]():;]+
77HEX 0[xX][0-9a-fA-F]+[kKmM]?
78OCT 0[0-7]*[kKmM]?
79DEC [0-9]+[kKmM]?
80WHITE [[: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
130ALIGN { return kALIGN; }
131AS_NEEDED { return kAS_NEEDED; }
132ENTRY { return kENTRY; }
133EXCLUDE_FILE { return kEXCLUDE_FILE; }
134"global:" { return kGLOBAL; }
135GROUP { return kGROUP; }
136INPUT { return kINPUT; }
137INTERP { return kINTERP; }
138KEEP { return kKEEP; }
139"local:" { return kLOCAL; }
140OUTPUT_FORMAT { return kOUTPUT_FORMAT; }
141PAGESIZE { return kPAGESIZE; }
142PROVIDE { return kPROVIDE; }
143SEARCH_DIR { return kSEARCH_DIR; }
144SEGMENT { return kSEGMENT; }
145SIZEOF_HEADERS { return kSIZEOF_HEADERS; }
146SORT { return kSORT; }
147VERSION { return kVERSION; }
148
149"["([RWX]){0,3}"]" { 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
200static void
201eat_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
229static void
230eat_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
255static int
256attrib_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
267static void
268push_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
278static int
279pop_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
290static int
291handle_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
341static void
342invalid_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: