Home | History | Annotate | Download | only in src
      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 (at) 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
    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
    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
    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
    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
    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
    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