| // errors.cc -- handle errors for gold |
| |
| // Copyright (C) 2006-2021 Free Software Foundation, Inc. |
| // Written by Ian Lance Taylor <iant@google.com>. |
| |
| // This file is part of gold. |
| |
| // This program is free software; you can redistribute it and/or modify |
| // it under the terms of the GNU General Public License as published by |
| // the Free Software Foundation; either version 3 of the License, or |
| // (at your option) any later version. |
| |
| // This program is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| |
| // You should have received a copy of the GNU General Public License |
| // along with this program; if not, write to the Free Software |
| // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
| // MA 02110-1301, USA. |
| |
| #include "gold.h" |
| |
| #include <cstdarg> |
| #include <cstdio> |
| |
| #include "gold-threads.h" |
| #include "parameters.h" |
| #include "object.h" |
| #include "symtab.h" |
| #include "errors.h" |
| |
| namespace gold |
| { |
| |
| // Class Errors. |
| |
| const int Errors::max_undefined_error_report; |
| |
| Errors::Errors(const char* program_name) |
| : program_name_(program_name), lock_(NULL), initialize_lock_(&this->lock_), |
| error_count_(0), warning_count_(0), undefined_symbols_() |
| { |
| } |
| |
| // 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. |
| |
| bool |
| Errors::initialize_lock() |
| { |
| return this->initialize_lock_.initialize(); |
| } |
| |
| // 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. |
| |
| void |
| Errors::fatal(const char* format, va_list args) |
| { |
| fprintf(stderr, _("%s: fatal error: "), this->program_name_); |
| vfprintf(stderr, format, args); |
| fputc('\n', stderr); |
| gold_exit(GOLD_ERR); |
| } |
| |
| // Report a fallback error. |
| |
| void |
| Errors::fallback(const char* format, va_list args) |
| { |
| fprintf(stderr, _("%s: fatal error: "), this->program_name_); |
| vfprintf(stderr, format, args); |
| fputc('\n', stderr); |
| gold_exit(GOLD_FALLBACK); |
| } |
| |
| // Report an error. |
| |
| void |
| Errors::error(const char* format, va_list args) |
| { |
| fprintf(stderr, _("%s: error: "), this->program_name_); |
| vfprintf(stderr, format, args); |
| fputc('\n', stderr); |
| |
| this->increment_counter(&this->error_count_); |
| } |
| |
| // Report a warning. |
| |
| void |
| Errors::warning(const char* format, va_list args) |
| { |
| fprintf(stderr, _("%s: warning: "), this->program_name_); |
| vfprintf(stderr, format, args); |
| fputc('\n', stderr); |
| |
| this->increment_counter(&this->warning_count_); |
| } |
| |
| // Print an informational message. |
| |
| void |
| Errors::info(const char* format, va_list args) |
| { |
| vfprintf(stderr, format, args); |
| fputc('\n', stderr); |
| } |
| |
| // Print a trace message. |
| |
| void |
| Errors::trace(const char* format, va_list args) |
| { |
| vfprintf(stdout, format, args); |
| fputc('\n', stdout); |
| } |
| |
| // Report an error at a reloc location. |
| |
| template<int size, bool big_endian> |
| void |
| Errors::error_at_location(const Relocate_info<size, big_endian>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, va_list args) |
| { |
| fprintf(stderr, _("%s: error: "), |
| relinfo->location(relnum, reloffset).c_str()); |
| vfprintf(stderr, format, args); |
| fputc('\n', stderr); |
| |
| this->increment_counter(&this->error_count_); |
| } |
| |
| // Report a warning at a reloc location. |
| |
| template<int size, bool big_endian> |
| void |
| Errors::warning_at_location(const Relocate_info<size, big_endian>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, va_list args) |
| { |
| fprintf(stderr, _("%s: warning: "), |
| relinfo->location(relnum, reloffset).c_str()); |
| vfprintf(stderr, format, args); |
| fputc('\n', stderr); |
| |
| this->increment_counter(&this->warning_count_); |
| } |
| |
| // Issue an undefined symbol error with a caller-supplied location string. |
| |
| void |
| Errors::undefined_symbol(const Symbol* sym, const std::string& location) |
| { |
| bool initialized = this->initialize_lock(); |
| gold_assert(initialized); |
| |
| const char* zmsg; |
| { |
| Hold_lock h(*this->lock_); |
| if (++this->undefined_symbols_[sym] >= max_undefined_error_report) |
| return; |
| if (parameters->options().warn_unresolved_symbols()) |
| { |
| ++this->warning_count_; |
| zmsg = _("warning"); |
| } |
| else |
| { |
| ++this->error_count_; |
| zmsg = _("error"); |
| } |
| } |
| |
| const char* const version = sym->version(); |
| if (version == NULL) |
| fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"), |
| location.c_str(), zmsg, sym->demangled_name().c_str()); |
| else |
| fprintf(stderr, |
| _("%s: %s: undefined reference to '%s', version '%s'\n"), |
| location.c_str(), zmsg, sym->demangled_name().c_str(), version); |
| |
| if (sym->is_cxx_vtable()) |
| gold_info(_("%s: the vtable symbol may be undefined because " |
| "the class is missing its key function"), |
| program_name); |
| if (sym->is_placeholder()) |
| gold_info(_("%s: the symbol should have been defined by a plugin"), |
| program_name); |
| } |
| |
| // Issue a debugging message. |
| |
| void |
| Errors::debug(const char* format, ...) |
| { |
| fprintf(stderr, _("%s: "), this->program_name_); |
| |
| va_list args; |
| va_start(args, format); |
| vfprintf(stderr, format, args); |
| va_end(args); |
| |
| fputc('\n', stderr); |
| } |
| |
| // The functions which the rest of the code actually calls. |
| |
| // Report a fatal error. |
| |
| void |
| gold_fatal(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| parameters->errors()->fatal(format, args); |
| va_end(args); |
| } |
| |
| // Report a fallback error. |
| |
| void |
| gold_fallback(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| parameters->errors()->fallback(format, args); |
| va_end(args); |
| } |
| |
| // Report an error. |
| |
| void |
| gold_error(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| parameters->errors()->error(format, args); |
| va_end(args); |
| } |
| |
| // Report a warning. |
| |
| void |
| gold_warning(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| parameters->errors()->warning(format, args); |
| va_end(args); |
| } |
| |
| // Print an informational message. |
| |
| void |
| gold_info(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| parameters->errors()->info(format, args); |
| va_end(args); |
| } |
| |
| // Print a trace message (to stdout). |
| |
| void |
| gold_trace(const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| parameters->errors()->trace(format, args); |
| va_end(args); |
| } |
| |
| // Report an error at a location. |
| |
| template<int size, bool big_endian> |
| void |
| gold_error_at_location(const Relocate_info<size, big_endian>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| parameters->errors()->error_at_location(relinfo, relnum, reloffset, |
| format, args); |
| va_end(args); |
| } |
| |
| // Report a warning at a location. |
| |
| template<int size, bool big_endian> |
| void |
| gold_warning_at_location(const Relocate_info<size, big_endian>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...) |
| { |
| va_list args; |
| va_start(args, format); |
| parameters->errors()->warning_at_location(relinfo, relnum, reloffset, |
| format, args); |
| va_end(args); |
| } |
| |
| // Report an undefined symbol. |
| |
| void |
| gold_undefined_symbol(const Symbol* sym) |
| { |
| parameters->errors()->undefined_symbol(sym, sym->object()->name().c_str()); |
| } |
| |
| // Report an undefined symbol at a reloc location |
| |
| template<int size, bool big_endian> |
| void |
| gold_undefined_symbol_at_location(const Symbol* sym, |
| const Relocate_info<size, big_endian>* relinfo, |
| size_t relnum, off_t reloffset) |
| { |
| parameters->errors()->undefined_symbol(sym, |
| relinfo->location(relnum, reloffset)); |
| } |
| |
| #ifdef HAVE_TARGET_32_LITTLE |
| template |
| void |
| gold_error_at_location<32, false>(const Relocate_info<32, false>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...); |
| #endif |
| |
| #ifdef HAVE_TARGET_32_BIG |
| template |
| void |
| gold_error_at_location<32, true>(const Relocate_info<32, true>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...); |
| #endif |
| |
| #ifdef HAVE_TARGET_64_LITTLE |
| template |
| void |
| gold_error_at_location<64, false>(const Relocate_info<64, false>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...); |
| #endif |
| |
| #ifdef HAVE_TARGET_64_BIG |
| template |
| void |
| gold_error_at_location<64, true>(const Relocate_info<64, true>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...); |
| #endif |
| |
| #ifdef HAVE_TARGET_32_LITTLE |
| template |
| void |
| gold_warning_at_location<32, false>(const Relocate_info<32, false>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...); |
| #endif |
| |
| #ifdef HAVE_TARGET_32_BIG |
| template |
| void |
| gold_warning_at_location<32, true>(const Relocate_info<32, true>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...); |
| #endif |
| |
| #ifdef HAVE_TARGET_64_LITTLE |
| template |
| void |
| gold_warning_at_location<64, false>(const Relocate_info<64, false>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...); |
| #endif |
| |
| #ifdef HAVE_TARGET_64_BIG |
| template |
| void |
| gold_warning_at_location<64, true>(const Relocate_info<64, true>* relinfo, |
| size_t relnum, off_t reloffset, |
| const char* format, ...); |
| #endif |
| |
| #ifdef HAVE_TARGET_32_LITTLE |
| template |
| void |
| gold_undefined_symbol_at_location<32, false>( |
| const Symbol* sym, |
| const Relocate_info<32, false>* relinfo, |
| size_t relnum, off_t reloffset); |
| #endif |
| |
| #ifdef HAVE_TARGET_32_BIG |
| template |
| void |
| gold_undefined_symbol_at_location<32, true>( |
| const Symbol* sym, |
| const Relocate_info<32, true>* relinfo, |
| size_t relnum, off_t reloffset); |
| #endif |
| |
| #ifdef HAVE_TARGET_64_LITTLE |
| template |
| void |
| gold_undefined_symbol_at_location<64, false>( |
| const Symbol* sym, |
| const Relocate_info<64, false>* relinfo, |
| size_t relnum, off_t reloffset); |
| #endif |
| |
| #ifdef HAVE_TARGET_64_BIG |
| template |
| void |
| gold_undefined_symbol_at_location<64, true>( |
| const Symbol* sym, |
| const Relocate_info<64, true>* relinfo, |
| size_t relnum, off_t reloffset); |
| #endif |
| |
| } // End namespace gold. |