1 %{ 2 /* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2008 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 Written by Ulrich Drepper <drepper (at) redhat.com>, 2001. 5 6 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. 9 10 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, 17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 18 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>. */ 26 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. */ 62 extern int ld_scan_version_script; 63 64 #define MAX_PREPDEPTH 20 65 static enum prepstate 66 { 67 prep_normal, 68 skip_if, 69 skip_to_endif 70 } prepstate[MAX_PREPDEPTH]; 71 static int prepdepth; 72 73 static void eat_comment (void); 74 static void eat_to_eol (bool empty); 75 static int attrib_convert (int c); 76 static void push_state (enum prepstate); 77 static int pop_state (void); 78 static int handle_ifdef (void); 79 static void invalid_char (int ch); 80 %} 81 82 ID [a-zA-Z0-9_.*?][a-zA-Z0-9_.*?-]* 83 FILENAMECHAR1 [a-zA-Z0-9_/.\\~] 84 FILENAMECHAR [^][{}[:space:]():;]+ 85 HEX 0[xX][0-9a-fA-F]+[kKmM]? 86 OCT 0[0-7]*[kKmM]? 87 DEC [0-9]+[kKmM]? 88 WHITE [[: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 138 ALIGN { return kALIGN; } 139 AS_NEEDED { return kAS_NEEDED; } 140 ENTRY { return kENTRY; } 141 EXCLUDE_FILE { return kEXCLUDE_FILE; } 142 "global:" { return kGLOBAL; } 143 GROUP { return kGROUP; } 144 INPUT { return kINPUT; } 145 INTERP { return kINTERP; } 146 KEEP { return kKEEP; } 147 "local:" { return kLOCAL; } 148 OUTPUT_FORMAT { return kOUTPUT_FORMAT; } 149 PAGESIZE { return kPAGESIZE; } 150 PROVIDE { return kPROVIDE; } 151 SEARCH_DIR { return kSEARCH_DIR; } 152 SEGMENT { return kSEGMENT; } 153 SIZEOF_HEADERS { return kSIZEOF_HEADERS; } 154 SORT { return kSORT; } 155 VERSION { 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 208 static void 209 eat_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 237 static void 238 eat_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 263 static int 264 attrib_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 275 static void 276 push_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 286 static int 287 pop_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 298 static int 299 handle_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 349 static void 350 invalid_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: 362