+ std::vector<std::string> ret;
+ for (size_t j = 0; j < version_trees_.size(); ++j)
+ if (version_trees_[j]->tag == version)
+ {
+ const struct Version_dependency_list* deps =
+ version_trees_[j]->dependencies;
+ if (deps != NULL)
+ for (size_t k = 0; k < deps->dependencies.size(); ++k)
+ ret.push_back(deps->dependencies[k]);
+ return ret;
+ }
+ return ret;
+}
+
+const std::string&
+Version_script_info::get_symbol_version_helper(const char* symbol_name,
+ bool check_global) const
+{
+ for (size_t j = 0; j < version_trees_.size(); ++j)
+ {
+ // Is it a global symbol for this version?
+ const Version_expression_list* explist =
+ check_global ? version_trees_[j]->global : version_trees_[j]->local;
+ 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.language == "C++")
+ {
+ demangled_name = cplus_demangle(symbol_name,
+ DMGL_ANSI | DMGL_PARAMS);
+ // This isn't a C++ symbol.
+ if (demangled_name == NULL)
+ continue;
+ name_to_match = demangled_name;
+ }
+ else if (exp.language == "Java")
+ {
+ demangled_name = cplus_demangle(symbol_name,
+ (DMGL_ANSI | DMGL_PARAMS
+ | DMGL_JAVA));
+ // This isn't a Java symbol.
+ if (demangled_name == NULL)
+ continue;
+ name_to_match = demangled_name;
+ }
+ 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)
+ return version_trees_[j]->tag;
+ }
+ }
+ static const std::string empty = "";
+ return empty;
+}
+
+struct Version_dependency_list*
+Version_script_info::allocate_dependency_list()
+{
+ dependency_lists_.push_back(new Version_dependency_list);
+ return dependency_lists_.back();
+}
+
+struct Version_expression_list*
+Version_script_info::allocate_expression_list()
+{
+ expression_lists_.push_back(new Version_expression_list);
+ return expression_lists_.back();
+}
+
+struct Version_tree*
+Version_script_info::allocate_version_tree()
+{
+ version_trees_.push_back(new Version_tree);
+ return version_trees_.back();
+}
+
+// Print for debugging.
+
+void
+Version_script_info::print(FILE* f) const
+{
+ if (this->empty())
+ return;
+
+ fprintf(f, "VERSION {");
+
+ for (size_t i = 0; i < this->version_trees_.size(); ++i)
+ {
+ const Version_tree* vt = this->version_trees_[i];
+
+ if (vt->tag.empty())
+ fprintf(f, " {\n");
+ else
+ fprintf(f, " %s {\n", vt->tag.c_str());
+
+ if (vt->global != NULL)
+ {
+ fprintf(f, " global :\n");
+ this->print_expression_list(f, vt->global);
+ }
+
+ if (vt->local != NULL)
+ {
+ fprintf(f, " local :\n");
+ this->print_expression_list(f, vt->local);
+ }
+
+ fprintf(f, " }");
+ if (vt->dependencies != NULL)
+ {
+ const Version_dependency_list* deps = vt->dependencies;
+ for (size_t j = 0; j < deps->dependencies.size(); ++j)
+ {
+ if (j < deps->dependencies.size() - 1)
+ fprintf(f, "\n");
+ fprintf(f, " %s", deps->dependencies[j].c_str());
+ }
+ }
+ fprintf(f, ";\n");
+ }
+
+ fprintf(f, "}\n");
+}
+
+void
+Version_script_info::print_expression_list(
+ FILE* f,
+ const Version_expression_list* vel) const
+{
+ std::string current_language;
+ for (size_t i = 0; i < vel->expressions.size(); ++i)
+ {
+ const Version_expression& ve(vel->expressions[i]);
+
+ if (ve.language != current_language)
+ {
+ if (!current_language.empty())
+ fprintf(f, " }\n");
+ fprintf(f, " extern \"%s\" {\n", ve.language.c_str());
+ current_language = ve.language;
+ }
+
+ fprintf(f, " ");
+ if (!current_language.empty())
+ fprintf(f, " ");
+
+ if (ve.exact_match)
+ fprintf(f, "\"");
+ fprintf(f, "%s", ve.pattern.c_str());
+ if (ve.exact_match)
+ fprintf(f, "\"");
+
+ fprintf(f, "\n");
+ }
+
+ if (!current_language.empty())
+ fprintf(f, " }\n");
+}
+
+} // End namespace gold.
+
+// The remaining functions are extern "C", so it's clearer to not put
+// them in namespace gold.
+
+using namespace gold;
+
+// This function is called by the bison parser to return the next
+// token.
+
+extern "C" int
+yylex(YYSTYPE* lvalp, void* closurev)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ const Token* token = closure->next_token();
+ switch (token->classification())
+ {
+ default:
+ gold_unreachable();
+
+ case Token::TOKEN_INVALID:
+ yyerror(closurev, "invalid character");
+ return 0;
+
+ case Token::TOKEN_EOF:
+ return 0;
+
+ case Token::TOKEN_STRING:
+ {
+ // This is either a keyword or a STRING.
+ size_t len;
+ const char* str = token->string_value(&len);
+ int parsecode = 0;
+ switch (closure->lex_mode())
+ {
+ case Lex::LINKER_SCRIPT:
+ parsecode = script_keywords.keyword_to_parsecode(str, len);
+ break;
+ case Lex::VERSION_SCRIPT:
+ parsecode = version_script_keywords.keyword_to_parsecode(str, len);
+ break;
+ default:
+ break;
+ }
+ if (parsecode != 0)
+ return parsecode;
+ lvalp->string.value = str;
+ lvalp->string.length = len;
+ return STRING;
+ }
+
+ case Token::TOKEN_QUOTED_STRING:
+ lvalp->string.value = token->string_value(&lvalp->string.length);
+ return QUOTED_STRING;
+
+ case Token::TOKEN_OPERATOR:
+ return token->operator_value();
+
+ case Token::TOKEN_INTEGER:
+ lvalp->integer = token->integer_value();
+ return INTEGER;
+ }
+}
+
+// This function is called by the bison parser to report an error.
+
+extern "C" void
+yyerror(void* closurev, const char* message)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+ gold_error(_("%s:%d:%d: %s"), closure->filename(), closure->lineno(),
+ closure->charpos(), message);
+}
+
+// Called by the bison parser to add a file to the link.
+
+extern "C" void
+script_add_file(void* closurev, const char* name, size_t length)
+{
+ Parser_closure* closure = static_cast<Parser_closure*>(closurev);
+
+ // If this is an absolute path, and we found the script in the
+ // sysroot, then we want to prepend the sysroot to the file name.
+ // For example, this is how we handle a cross link to the x86_64
+ // libc.so, which refers to /lib/libc.so.6.
+ std::string name_string(name, length);
+ const char* extra_search_path = ".";
+ std::string script_directory;
+ if (IS_ABSOLUTE_PATH(name_string.c_str()))
+ {
+ if (closure->is_in_sysroot())
+ {
+ const std::string& sysroot(parameters->sysroot());
+ gold_assert(!sysroot.empty());
+ name_string = sysroot + name_string;
+ }
+ }
+ else
+ {
+ // In addition to checking the normal library search path, we
+ // also want to check in the script-directory.
+ const char *slash = strrchr(closure->filename(), '/');
+ if (slash != NULL)
+ {
+ script_directory.assign(closure->filename(),
+ slash - closure->filename() + 1);
+ extra_search_path = script_directory.c_str();
+ }
+ }
+
+ Input_file_argument file(name_string.c_str(), false, extra_search_path,
+ closure->position_dependent_options());
+ closure->inputs()->add_file(file);