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