OSDN Git Service

Reworked from Andrew Chatham: report error locations.
authoriant <iant>
Fri, 2 Nov 2007 03:28:52 +0000 (03:28 +0000)
committeriant <iant>
Fri, 2 Nov 2007 03:28:52 +0000 (03:28 +0000)
elfcpp/elfcpp_file.h
gold/dynobj.h
gold/object.cc
gold/object.h

index 9adbb5f..7462bb8 100644 (file)
@@ -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<size, big_endian, File>::section_type(unsigned int shndx)
   return shdr.get_sh_type();
 }
 
+// Return the sh_link field of section SHNDX.
+
+template<int size, bool big_endian, typename File>
+Elf_Word
+Elf_file<size, big_endian, 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)
index a3d733d..aea004d 100644 (file)
@@ -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<size, big_endian> This;
index 9e4b58d..269acc5 100644 (file)
@@ -801,6 +801,62 @@ Sized_relobj<size, big_endian>::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<int size, bool big_endian>
+bool
+Sized_relobj<size, big_endian>::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<const char*>(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<size, big_endian> 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<off_t>(sym.get_st_value()) <= offset
+               && (static_cast<off_t>(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<int size, bool big_endian>
 std::string
-Relocate_info<size, big_endian>::location(size_t relnum, off_t) const
+Relocate_info<size, big_endian>::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<long>(offset));
   ret += buf;
-  ret += " (" + this->object->section_name(this->data_shndx) + ")";
   return ret;
 }
 
index 46e332f..9fdb9a3 100644 (file)
@@ -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<size, big_endian> This;