From f7e2ee482013bd5df3e3726305eab7c5ed5ce020 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 2 Nov 2007 03:28:52 +0000 Subject: Reworked from Andrew Chatham: report error locations. --- elfcpp/elfcpp_file.h | 23 ++++++++++++++ gold/dynobj.h | 5 ++++ gold/object.cc | 84 +++++++++++++++++++++++++++++++++++++++++++++------- gold/object.h | 30 +++++++++++++++++++ 4 files changed, 131 insertions(+), 11 deletions(-) diff --git a/elfcpp/elfcpp_file.h b/elfcpp/elfcpp_file.h index 9adbb5f..7462bb8 100644 --- a/elfcpp/elfcpp_file.h +++ b/elfcpp/elfcpp_file.h @@ -139,6 +139,10 @@ class Elf_file Elf_Word section_type(unsigned int shndx); + // Return the link field of section SHNDX. + Elf_Word + section_link(unsigned int shndx); + private: // Shared constructor code. void @@ -325,6 +329,25 @@ Elf_file::section_type(unsigned int shndx) return shdr.get_sh_type(); } +// Return the sh_link field of section SHNDX. + +template +Elf_Word +Elf_file::section_link(unsigned int shndx) +{ + File* const file = this->file_; + + if (shndx >= this->shnum()) + file->error(_("section_link: bad shndx %u >= %u"), + shndx, this->shnum()); + + typename File::View v(file->view(this->section_header_offset(shndx), + This::shdr_size)); + + Ef_shdr shdr(v.data()); + return shdr.get_sh_link(); +} + } // End namespace elfcpp. #endif // !defined(ELFCPP_FILE_H) diff --git a/gold/dynobj.h b/gold/dynobj.h index a3d733d..aea004d 100644 --- a/gold/dynobj.h +++ b/gold/dynobj.h @@ -148,6 +148,11 @@ class Sized_dynobj : public Dynobj do_section_flags(unsigned int shndx) { return this->elf_file_.section_flags(shndx); } + // Return the section link field. + unsigned int + do_section_link(unsigned int shndx) + { return this->elf_file_.section_link(shndx); } + private: // For convenience. typedef Sized_dynobj This; diff --git a/gold/object.cc b/gold/object.cc index 9e4b58d..269acc5 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -801,6 +801,62 @@ Sized_relobj::write_local_symbols(Output_file* of, of->write_output_view(this->local_symbol_offset_, output_size, oview); } +// Set *INFO to symbolic information about the offset OFFSET in the +// section SHNDX. Return true if we found something, false if we +// found nothing. + +template +bool +Sized_relobj::get_symbol_location_info( + unsigned int shndx, + off_t offset, + Symbol_location_info* info) +{ + if (this->symtab_shndx_ == 0) + return false; + + off_t symbols_size; + const unsigned char* symbols = this->section_contents(this->symtab_shndx_, + &symbols_size, + false); + + unsigned int symbol_names_shndx = this->section_link(this->symtab_shndx_); + off_t names_size; + const unsigned char* symbol_names_u = + this->section_contents(symbol_names_shndx, &names_size, false); + const char* symbol_names = reinterpret_cast(symbol_names_u); + + const int sym_size = This::sym_size; + const size_t count = symbols_size / sym_size; + + const unsigned char* p = symbols; + for (size_t i = 0; i < count; ++i, p += sym_size) + { + elfcpp::Sym sym(p); + + if (sym.get_st_type() == elfcpp::STT_FILE) + { + if (sym.get_st_name() >= names_size) + info->source_file = "(invalid)"; + else + info->source_file = symbol_names + sym.get_st_name(); + } + else if (sym.get_st_shndx() == shndx + && static_cast(sym.get_st_value()) <= offset + && (static_cast(sym.get_st_value() + sym.get_st_size()) + >= offset)) + { + if (sym.get_st_name() > names_size) + info->enclosing_symbol_name = "(invalid)"; + else + info->enclosing_symbol_name = symbol_names + sym.get_st_name(); + return true; + } + } + + return false; +} + // Input_objects methods. // Add a regular relocatable object to the list. Return false if this @@ -849,21 +905,27 @@ Input_objects::add_object(Object* obj) template std::string -Relocate_info::location(size_t relnum, off_t) const +Relocate_info::location(size_t, off_t offset) const { + // FIXME: We would like to print the following: + // /tmp/foo.o: in function 'fn':foo.c:12: undefined reference to 'xxx' + // We're missing line numbers. std::string ret(this->object->name()); - ret += ": reloc "; + ret += ':'; + Symbol_location_info info; + if (this->object->get_symbol_location_info(this->data_shndx, offset, &info)) + { + ret += " in function "; + ret += info.enclosing_symbol_name; + ret += ":"; + ret += info.source_file; + } + ret += "("; + ret += this->object->section_name(this->data_shndx); char buf[100]; - snprintf(buf, sizeof buf, "%zu", relnum); - ret += buf; - ret += " in reloc section "; - snprintf(buf, sizeof buf, "%u", this->reloc_shndx); - ret += buf; - ret += " (" + this->object->section_name(this->reloc_shndx); - ret += ") for section "; - snprintf(buf, sizeof buf, "%u", this->data_shndx); + // Offsets into sections have to be positive. + snprintf(buf, sizeof(buf), "+0x%lx)", static_cast(offset)); ret += buf; - ret += " (" + this->object->section_name(this->data_shndx) + ")"; return ret; } diff --git a/gold/object.h b/gold/object.h index 46e332f..9fdb9a3 100644 --- a/gold/object.h +++ b/gold/object.h @@ -76,6 +76,15 @@ struct Read_symbols_data unsigned int verneed_info; }; +// Information used to print error messages. + +struct Symbol_location_info +{ + std::string source_file; + std::string enclosing_symbol_name; + int line_number; +}; + // Data about a single relocation section. This is read in // read_relocs and processed in scan_relocs. @@ -188,6 +197,11 @@ class Object section_flags(unsigned int shndx) { return this->do_section_flags(shndx); } + // Return the section link field given a section index. + unsigned int + section_link(unsigned int shndx) + { return this->do_section_link(shndx); } + // Read the symbol information. void read_symbols(Read_symbols_data* sd) @@ -277,6 +291,10 @@ class Object virtual uint64_t do_section_flags(unsigned int shndx) = 0; + // Get section link field--implemented by child class. + virtual unsigned int + do_section_link(unsigned int shndx) = 0; + // Get the file. Input_file* input_file() const @@ -660,6 +678,13 @@ class Sized_relobj : public Relobj gold_assert(ins.second); } + // Return the name of the symbol that spans the given offset in the + // specified section in this object. This is used only for error + // messages and is not particularly efficient. + bool + get_symbol_location_info(unsigned int shndx, off_t offset, + Symbol_location_info* info); + // Read the symbols. void do_read_symbols(Read_symbols_data*); @@ -706,6 +731,11 @@ class Sized_relobj : public Relobj do_section_flags(unsigned int shndx) { return this->elf_file_.section_flags(shndx); } + // Return the section link field. + unsigned int + do_section_link(unsigned int shndx) + { return this->elf_file_.section_link(shndx); } + private: // For convenience. typedef Sized_relobj This; -- cgit v1.1