{
}
-// 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.
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.
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.
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.
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.
const Relocate_info<size, big_endian>* 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)
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()
{
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*
{
Parser_closure* closure = static_cast<Parser_closure*>(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.
/* 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. */