From 2dd3e587bdab39d73086c35be60399e096d48b46 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 7 Jan 2008 05:19:02 +0000 Subject: [PATCH] Report linker script errors with line numbers. Ignore OUTPUT_FORMAT with three arguments, and ignore OUTPUT_ARCH. --- gold/errors.cc | 55 ++++++++++++++++++++++++++++--------------------- gold/errors.h | 8 +++++-- gold/options.cc | 3 +-- gold/script.cc | 14 +++++++++++-- gold/yyscript.y | 14 +++++++++++-- 5 files changed, 62 insertions(+), 32 deletions(-) diff --git a/gold/errors.cc b/gold/errors.cc index c979463dfc2..85c5512c5d9 100644 --- a/gold/errors.cc +++ b/gold/errors.cc @@ -44,13 +44,35 @@ Errors::Errors(const char* program_name) { } -// Initialize the lock_ field. +// Initialize the lock_ field. If we have not yet processed the +// parameters, then we can't initialize, since we don't yet know +// whether we are using threads. That is OK, since if we haven't +// processed the parameters, we haven't created any threads, and we +// don't need a lock. Return true if the lock is now initialized. -void +bool Errors::initialize_lock() { - if (this->lock_ == NULL) + if (this->lock_ == NULL && parameters->options_valid()) this->lock_ = new Lock; + return this->lock_ != NULL; +} + +// Increment a counter, holding the lock if available. + +void +Errors::increment_counter(int *counter) +{ + if (!this->initialize_lock()) + { + // The lock does not exist, which means that we don't need it. + ++*counter; + } + else + { + Hold_lock h(*this->lock_); + ++*counter; + } } // Report a fatal error. @@ -73,11 +95,7 @@ Errors::error(const char* format, va_list args) vfprintf(stderr, format, args); fputc('\n', stderr); - this->initialize_lock(); - { - Hold_lock h(*this->lock_); - ++this->error_count_; - } + this->increment_counter(&this->error_count_); } // Report a warning. @@ -89,11 +107,7 @@ Errors::warning(const char* format, va_list args) vfprintf(stderr, format, args); fputc('\n', stderr); - this->initialize_lock(); - { - Hold_lock h(*this->lock_); - ++this->warning_count_; - } + this->increment_counter(&this->warning_count_); } // Report an error at a reloc location. @@ -109,11 +123,7 @@ Errors::error_at_location(const Relocate_info* relinfo, vfprintf(stderr, format, args); fputc('\n', stderr); - this->initialize_lock(); - { - Hold_lock h(*this->lock_); - ++this->error_count_; - } + this->increment_counter(&this->error_count_); } // Report a warning at a reloc location. @@ -129,11 +139,7 @@ Errors::warning_at_location(const Relocate_info* relinfo, vfprintf(stderr, format, args); fputc('\n', stderr); - this->initialize_lock(); - { - Hold_lock h(*this->lock_); - ++this->warning_count_; - } + this->increment_counter(&this->warning_count_); } // Issue an undefined symbol error. @@ -144,7 +150,8 @@ Errors::undefined_symbol(const Symbol* sym, const Relocate_info* relinfo, size_t relnum, off_t reloffset) { - this->initialize_lock(); + bool initialized = this->initialize_lock(); + gold_assert(initialized); { Hold_lock h(*this->lock_); if (++this->undefined_symbols_[sym] >= max_undefined_error_report) diff --git a/gold/errors.h b/gold/errors.h index 17b72e10b36..efc0d1ebe9f 100644 --- a/gold/errors.h +++ b/gold/errors.h @@ -95,10 +95,14 @@ class Errors // Initialize the lock. We don't do this in the constructor because // lock initialization wants to know whether we are using threads or - // not. - void + // not. This returns true if the lock is now initialized. + bool initialize_lock(); + // Increment a counter, holding the lock. + void + increment_counter(int*); + // The number of times we report an undefined symbol. static const int max_undefined_error_report = 5; diff --git a/gold/options.cc b/gold/options.cc index a26139bf425..2ba5414a43c 100644 --- a/gold/options.cc +++ b/gold/options.cc @@ -154,8 +154,7 @@ invoke_script(int argc, char** argv, char* arg, bool long_option, arg, long_option, &ret); if (!read_commandline_script(script_name, cmdline)) - gold::gold_error(_("%s: unable to parse script file %s\n"), - gold::program_name, arg); + gold::gold_error(_("unable to parse script file %s\n"), script_name); return ret; } diff --git a/gold/script.cc b/gold/script.cc index 775aedf6f21..2b14e3f15bc 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -881,7 +881,7 @@ class Parser_closure at_eof() const { return this->next_token_index_ >= this->tokens_->size(); } - // Return the next token. + // Return the next token, and advance. const Token* next_token() { @@ -890,6 +890,14 @@ class Parser_closure return ret; } + // Return the previous token. + const Token* + last_token() const + { + gold_assert(this->next_token_index_ > 0); + return &(*this->tokens_)[this->next_token_index_ - 1]; + } + // Return the list of input files, creating it if necessary. This // is a space leak--we never free the INPUTS_ pointer. Input_arguments* @@ -1240,7 +1248,9 @@ yyerror(void* closurev, const char* message) { Parser_closure* closure = static_cast(closurev); - gold_error(_("%s: %s"), closure->filename(), message); + const Token* token = closure->last_token(); + gold_error(_("%s:%d:%d: %s"), closure->filename(), token->lineno(), + token->charpos(), message); } // Called by the bison parser to add a file to the link. diff --git a/gold/yyscript.y b/gold/yyscript.y index 7cfe7247e78..513241b4857 100644 --- a/gold/yyscript.y +++ b/gold/yyscript.y @@ -168,14 +168,24 @@ file_list: /* A command which may appear at top level of a linker script. */ file_cmd: - OUTPUT_FORMAT '(' STRING ')' - | GROUP + GROUP { script_start_group(closure); } '(' input_list ')' { script_end_group(closure); } | OPTION '(' STRING ')' { script_parse_option(closure, $3); } | file_or_sections_cmd + | ignore_cmd + ; + +/* Top level commands which we ignore. The GNU linker uses these to + select the output format, but we don't offer a choice. Ignoring + 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 ')' ; /* A list of input file names. */ -- 2.30.2