case Token::TOKEN_QUOTED_STRING:
lvalp->string.value = token->string_value(&lvalp->string.length);
- return STRING;
+ return QUOTED_STRING;
case Token::TOKEN_OPERATOR:
return token->operator_value();
// pattern and language should be from the stringpool
struct Version_expression {
Version_expression(const std::string& pattern,
- const std::string& language)
- : pattern(pattern), language(language) {}
+ const std::string& language,
+ bool exact_match)
+ : pattern(pattern), language(language), exact_match(exact_match) {}
std::string pattern;
std::string language;
+ // If false, we use glob() to match pattern. If true, we use strcmp().
+ bool exact_match;
};
for (size_t j = 0; j < version_trees_.size(); ++j)
{
// Is it a global symbol for this version?
- const Version_expression_list* exp =
+ const Version_expression_list* explist =
check_global ? version_trees_[j]->global : version_trees_[j]->local;
- if (exp != NULL)
- for (size_t k = 0; k < exp->expressions.size(); ++k)
+ if (explist != NULL)
+ for (size_t k = 0; k < explist->expressions.size(); ++k)
{
const char* name_to_match = symbol_name;
+ const struct Version_expression& exp = explist->expressions[k];
char* demangled_name = NULL;
- if (exp->expressions[k].language == "C++")
+ if (exp.language == "C++")
{
demangled_name = cplus_demangle(symbol_name,
DMGL_ANSI | DMGL_PARAMS);
continue;
name_to_match = demangled_name;
}
- else if (exp->expressions[k].language == "Java")
+ else if (exp.language == "Java")
{
demangled_name = cplus_demangle(symbol_name,
(DMGL_ANSI | DMGL_PARAMS
continue;
name_to_match = demangled_name;
}
- bool matched = fnmatch(exp->expressions[k].pattern.c_str(),
- name_to_match, FNM_NOESCAPE) == 0;
+ bool matched;
+ if (exp.exact_match)
+ matched = strcmp(exp.pattern.c_str(), name_to_match) == 0;
+ else
+ matched = fnmatch(exp.pattern.c_str(), name_to_match,
+ FNM_NOESCAPE) == 0;
if (demangled_name != NULL)
free(demangled_name);
if (matched)
extern "C" struct Version_expression_list *
script_new_vers_pattern(void* closurev,
struct Version_expression_list *expressions,
- const char *pattern, int patlen)
+ const char *pattern, int patlen, int exact_match)
{
Parser_closure* closure = static_cast<Parser_closure*>(closurev);
if (expressions == NULL)
expressions = closure->version_script()->allocate_expression_list();
expressions->expressions.push_back(
Version_expression(std::string(pattern, patlen),
- closure->get_current_language()));
+ closure->get_current_language(),
+ static_cast<bool>(exact_match)));
return expressions;
}
+// Attaches b to the end of a, and clears b. So a = a + b and b = {}.
+
+extern "C" struct Version_expression_list*
+script_merge_expressions(struct Version_expression_list *a,
+ struct Version_expression_list *b)
+{
+ a->expressions.insert(a->expressions.end(),
+ b->expressions.begin(), b->expressions.end());
+ // We could delete b and remove it from expressions_lists_, but
+ // that's a lot of work. This works just as well.
+ b->expressions.clear();
+ return a;
+}
+
// Combine the global and local expressions into a a Version_tree.
extern "C" struct Version_tree *
return tree;
}
-// Handle a transition in language, such as at the
+// Handle a transition in language, such as at the
// start or end of 'extern "C++"'
extern "C" void
/* Constants. */
%token <string> STRING
+%token <string> QUOTED_STRING
%token <integer> INTEGER
/* Keywords. This list is taken from ldgram.y and ldlex.l in the old
%type <versyms> vers_defns
%type <versnode> vers_tag
%type <deplist> verdep
+%type <string> string
%%
{ script_start_group(closure); }
'(' input_list ')'
{ script_end_group(closure); }
- | OPTION '(' STRING ')'
+ | OPTION '(' string ')'
{ script_parse_option(closure, $3.value, $3.length); }
| VERSIONK '{'
{ script_push_lex_into_version_mode(closure); }
these is more-or-less OK since most scripts simply explicitly
choose the default. */
ignore_cmd:
- OUTPUT_FORMAT '(' STRING ')'
- | OUTPUT_FORMAT '(' STRING ',' STRING ',' STRING ')'
- | OUTPUT_ARCH '(' STRING ')'
+ OUTPUT_FORMAT '(' string ')'
+ | OUTPUT_FORMAT '(' string ',' string ',' string ')'
+ | OUTPUT_ARCH '(' string ')'
;
/* A list of input file names. */
/* An input file name. */
input_list_element:
- STRING
+ string
{ script_add_file(closure, $1.value, $1.length); }
| AS_NEEDED
{ script_start_as_needed(closure); }
/* A command which may appear at the top level of a linker script, or
within a SECTIONS block. */
file_or_sections_cmd:
- ENTRY '(' STRING ')'
+ ENTRY '(' string ')'
{ script_set_entry(closure, $3.value, $3.length); }
| assignment end
;
/* Set a symbol to a value. */
assignment:
- STRING '=' parse_exp
+ string '=' parse_exp
{ script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
- | STRING PLUSEQ parse_exp
+ | string PLUSEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_add(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
- | STRING MINUSEQ parse_exp
+ | string MINUSEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_sub(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
- | STRING MULTEQ parse_exp
+ | string MULTEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_mult(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
- | STRING DIVEQ parse_exp
+ | string DIVEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_div(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
- | STRING LSHIFTEQ parse_exp
+ | string LSHIFTEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_lshift(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
- | STRING RSHIFTEQ parse_exp
+ | string RSHIFTEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_rshift(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
- | STRING ANDEQ parse_exp
+ | string ANDEQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_bitwise_and(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
- | STRING OREQ parse_exp
+ | string OREQ parse_exp
{
Expression_ptr s = script_exp_string($1.value, $1.length);
Expression_ptr e = script_exp_binary_bitwise_or(s, $3);
script_set_symbol(closure, $1.value, $1.length, e, 0, 0);
}
- | PROVIDE '(' STRING '=' parse_exp ')'
+ | PROVIDE '(' string '=' parse_exp ')'
{ script_set_symbol(closure, $3.value, $3.length, $5, 1, 0); }
- | PROVIDE_HIDDEN '(' STRING '=' parse_exp ')'
+ | PROVIDE_HIDDEN '(' string '=' parse_exp ')'
{ script_set_symbol(closure, $3.value, $3.length, $5, 1, 1); }
;
{ $$ = script_exp_integer($1); }
| STRING
{ $$ = script_exp_string($1.value, $1.length); }
+ | QUOTED_STRING
+ { $$ = script_exp_string($1.value, $1.length); }
| MAX_K '(' exp ',' exp ')'
{ $$ = script_exp_function_max($3, $5); }
| MIN_K '(' exp ',' exp ')'
{ $$ = script_exp_function_min($3, $5); }
- | DEFINED '(' STRING ')'
+ | DEFINED '(' string ')'
{ $$ = script_exp_function_defined($3.value, $3.length); }
| SIZEOF_HEADERS
{ $$ = script_exp_function_sizeof_headers(); }
- | ALIGNOF '(' STRING ')'
+ | ALIGNOF '(' string ')'
{ $$ = script_exp_function_alignof($3.value, $3.length); }
- | SIZEOF '(' STRING ')'
+ | SIZEOF '(' string ')'
{ $$ = script_exp_function_sizeof($3.value, $3.length); }
- | ADDR '(' STRING ')'
+ | ADDR '(' string ')'
{ $$ = script_exp_function_addr($3.value, $3.length); }
- | LOADADDR '(' STRING ')'
+ | LOADADDR '(' string ')'
{ $$ = script_exp_function_loadaddr($3.value, $3.length); }
- | ORIGIN '(' STRING ')'
+ | ORIGIN '(' string ')'
{ $$ = script_exp_function_origin($3.value, $3.length); }
- | LENGTH '(' STRING ')'
+ | LENGTH '(' string ')'
{ $$ = script_exp_function_length($3.value, $3.length); }
- | CONSTANT '(' STRING ')'
+ | CONSTANT '(' string ')'
{ $$ = script_exp_function_constant($3.value, $3.length); }
| ABSOLUTE '(' exp ')'
{ $$ = script_exp_function_absolute($3); }
{ $$ = script_exp_function_data_segment_relro_end($3, $5); }
| DATA_SEGMENT_END '(' exp ')'
{ $$ = script_exp_function_data_segment_end($3); }
- | SEGMENT_START '(' STRING ',' exp ')'
+ | SEGMENT_START '(' string ',' exp ')'
{
$$ = script_exp_function_segment_start($3.value, $3.length, $5);
}
- | ASSERT_K '(' exp ',' STRING ')'
+ | ASSERT_K '(' exp ',' string ')'
{ $$ = script_exp_function_assert($3, $5.value, $5.length); }
;
/* Handle the --defsym option. */
defsym_expr:
- STRING '=' parse_exp
+ string '=' parse_exp
{ script_set_symbol(closure, $1.value, $1.length, $3, 0, 0); }
;
{
script_register_vers_node (closure, NULL, 0, $2, NULL);
}
- | STRING '{' vers_tag '}' ';'
+ | string '{' vers_tag '}' ';'
{
script_register_vers_node (closure, $1.value, $1.length, $3,
NULL);
}
- | STRING '{' vers_tag '}' verdep ';'
+ | string '{' vers_tag '}' verdep ';'
{
script_register_vers_node (closure, $1.value, $1.length, $3, $5);
}
;
verdep:
- STRING
+ string
{
$$ = script_add_vers_depend (closure, NULL, $1.value, $1.length);
}
- | verdep STRING
+ | verdep string
{
$$ = script_add_vers_depend (closure, $1, $2.value, $2.length);
}
{ $$ = script_new_vers_node (closure, $3, $7); }
;
+/* Here is one of the rare places we care about the distinction
+ between STRING and QUOTED_STRING. For QUOTED_STRING, we do exact
+ matching on the pattern, so we pass in true for the exact_match
+ parameter. For STRING, we do glob matching and pass in false. */
vers_defns:
STRING
{
$$ = script_new_vers_pattern (closure, NULL, $1.value,
- $1.length);
+ $1.length, 0);
+ }
+ | QUOTED_STRING
+ {
+ $$ = script_new_vers_pattern (closure, NULL, $1.value,
+ $1.length, 1);
}
| vers_defns ';' STRING
{
- $$ = script_new_vers_pattern (closure, $1, $3.value, $3.length);
+ $$ = script_new_vers_pattern (closure, $1, $3.value,
+ $3.length, 0);
+ }
+ | vers_defns ';' QUOTED_STRING
+ {
+ $$ = script_new_vers_pattern (closure, $1, $3.value,
+ $3.length, 1);
}
- | /* Push STRING on the language stack. */
- EXTERN STRING '{'
- { version_script_push_lang(closure, $2.value, $2.length); }
+ | /* Push string on the language stack. */
+ EXTERN string '{'
+ { version_script_push_lang (closure, $2.value, $2.length); }
vers_defns opt_semicolon '}'
{
$$ = $5;
version_script_pop_lang(closure);
}
+ | /* Push string on the language stack. This is more complicated
+ than the other cases because we need to merge the linked-list
+ state from the pre-EXTERN defns and the post-EXTERN defns. */
+ vers_defns ';' EXTERN string '{'
+ { version_script_push_lang (closure, $4.value, $4.length); }
+ vers_defns opt_semicolon '}'
+ {
+ $$ = script_merge_expressions ($1, $7);
+ version_script_pop_lang(closure);
+ }
| EXTERN // "extern" as a symbol name
{
$$ = script_new_vers_pattern (closure, NULL, "extern",
- sizeof("extern") - 1);
+ sizeof("extern") - 1, 1);
}
| vers_defns ';' EXTERN
{
$$ = script_new_vers_pattern (closure, $1, "extern",
- sizeof("extern") - 1);
+ sizeof("extern") - 1, 1);
}
;
+/* A string can be either a STRING or a QUOTED_STRING. Almost all the
+ time we don't care, and we use this rule. */
+string:
+ STRING
+ { $$ = $1; }
+ | QUOTED_STRING
+ { $$ = $1; }
+ ;
+
/* Some statements require a terminator, which may be a semicolon or a
comma. */
end: