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. */ 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}"]" { 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 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: 354