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 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