From Craig Silverstein: Use relocations in reporting error message
authorIan Lance Taylor <iant@google.com>
Fri, 9 Nov 2007 23:16:54 +0000 (23:16 +0000)
committerIan Lance Taylor <iant@google.com>
Fri, 9 Nov 2007 23:16:54 +0000 (23:16 +0000)
locations.

gold/dwarf_reader.cc
gold/dwarf_reader.h
gold/dynobj.h
gold/object.cc
gold/object.h
gold/reloc.h

index 1873091b4973ab2ba0d45b89bdb33d083dfc72f5..74e089f4f0e63456963b136ebd0afe71727a461a 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "elfcpp_swap.h"
 #include "dwarf.h"
+#include "reloc.h"
 #include "dwarf_reader.h"
 
 namespace {
@@ -347,12 +348,25 @@ Dwarf_line_info<size, big_endian>::process_one_opcode(
             return true;
 
           case elfcpp::DW_LNE_set_address:
-            // FIXME: modify the address based on the reloc
-            lsm->address = elfcpp::Swap<size, big_endian>::readval(start);
-            // FIXME: set lsm->shndx from the reloc
-            lsm->shndx = 1;
-            break;
-
+            {
+              typename Reloc_map::const_iterator it
+                  = reloc_map_.find(start - this->buffer_);
+              if (it != reloc_map_.end())
+                {
+                  // value + addend.
+                  lsm->address =
+                   (elfcpp::Swap<size, big_endian>::readval(start)
+                    + it->second.second);
+                  lsm->shndx = it->second.first;
+                }
+              else
+                {
+                  // Every set_address should have an associated
+                  // relocation.
+                  this->data_valid_ = false;
+                }
+              break;
+            }                
           case elfcpp::DW_LNE_define_file:
             {
               const char* filename  = reinterpret_cast<const char*>(start);
@@ -435,17 +449,55 @@ Dwarf_line_info<size, big_endian>::read_lines(unsigned const char* lineptr)
   return lengthstart + header_.total_length;
 }
 
+// Looks in the symtab to see what section a symbol is in.
+
+template<int size, bool big_endian>
+unsigned int
+Dwarf_line_info<size, big_endian>::symbol_section(
+    unsigned int sym,
+    typename elfcpp::Elf_types<size>::Elf_Addr* value)
+{
+  const int symsize = elfcpp::Elf_sizes<size>::sym_size;
+  gold_assert(this->symtab_buffer_ + sym * symsize < this->symtab_buffer_end_);
+  elfcpp::Sym<size, big_endian> elfsym(this->symtab_buffer_ + sym * symsize);
+  *value = elfsym.get_st_value();
+  return elfsym.get_st_shndx();
+}
+
+// Read the relocations into a Reloc_map.
+
+template<int size, bool big_endian>
+void
+Dwarf_line_info<size, big_endian>::read_relocs()
+{
+  if (this->symtab_buffer_ == NULL)
+    return;
+
+  typename elfcpp::Elf_types<size>::Elf_Addr value;
+  off_t reloc_offset;
+  while ((reloc_offset = this->track_relocs_->next_offset()) != -1)
+    {
+      const unsigned int sym = this->track_relocs_->next_symndx();
+      const unsigned int shndx = this->symbol_section(sym, &value);
+      this->reloc_map_[reloc_offset] = std::make_pair(shndx, value);
+      this->track_relocs_->advance(reloc_offset + 1);
+    }
+}
+
+// Read the line number info.
+
 template<int size, bool big_endian>
 void
 Dwarf_line_info<size, big_endian>::read_line_mappings()
 {
-  while (buffer_ < buffer_end_)
+  read_relocs();
+  while (this->buffer_ < this->buffer_end_)
     {
-      const unsigned char* lineptr = buffer_;
+      const unsigned char* lineptr = this->buffer_;
       lineptr = this->read_header_prolog(lineptr);
       lineptr = this->read_header_tables(lineptr);
       lineptr = this->read_lines(lineptr);
-      buffer_ = lineptr;
+      this->buffer_ = lineptr;
     }
 
   // Sort the lines numbers, so addr2line can use binary search.
@@ -453,7 +505,7 @@ Dwarf_line_info<size, big_endian>::read_line_mappings()
        it != line_number_map_.end();
        ++it)
     // Each vector needs to be sorted by offset.
-    sort(it->second.begin(), it->second.end());
+    std::sort(it->second.begin(), it->second.end());
 }
 
 // Return a string for a file name and line number.
@@ -462,8 +514,14 @@ template<int size, bool big_endian>
 std::string
 Dwarf_line_info<size, big_endian>::addr2line(unsigned int shndx, off_t offset)
 {
+  if (this->data_valid_ == false)
+    return "";
+
   const Offset_to_lineno_entry lookup_key = { offset, 0, 0 };
-  std::vector<Offset_to_lineno_entry>& offsets = line_number_map_[shndx];
+  std::vector<Offset_to_lineno_entry>& offsets = this->line_number_map_[shndx];
+  if (offsets.empty())
+    return "";
+
   typename std::vector<Offset_to_lineno_entry>::const_iterator it
       = std::lower_bound(offsets.begin(), offsets.end(), lookup_key);
 
index a01634238ab50f76ad72f601a20f7f9be2483c25..1bb6ea32ef6f6bbe5e6562f7fd975493af579391 100644 (file)
 #define GOLD_DWARF_READER_H
 
 #include <vector>
+#include <map>
 
+#include "elfcpp.h"
 #include "elfcpp_swap.h"
 #include "dwarf.h"
 
 namespace gold
 {
 
+template<int size, bool big_endian>
+class Track_relocs;
 struct LineStateMachine;
 
 // This class is used to read the line information from the debugging
@@ -44,8 +48,15 @@ class Dwarf_line_info
   // to the beginning and length of the line information to read.
   // Reader is a ByteReader class that has the endianness set
   // properly.
-  Dwarf_line_info(const unsigned char* buffer, off_t buffer_length)
-    : buffer_(buffer), buffer_end_(buffer + buffer_length),
+  Dwarf_line_info(const unsigned char* buffer, off_t buffer_length,
+                 Track_relocs<size, big_endian>* track_relocs,
+                  const unsigned char* symtab_buffer,
+                  off_t symtab_buffer_length)
+    : data_valid_(true),
+      buffer_(buffer), buffer_end_(buffer + buffer_length),
+      track_relocs_(track_relocs),
+      symtab_buffer_(symtab_buffer),
+      symtab_buffer_end_(symtab_buffer + symtab_buffer_length),
       directories_(1), files_(1)
   { }
 
@@ -61,6 +72,16 @@ class Dwarf_line_info
   addr2line(unsigned int shndx, off_t offset);
 
  private:
+  // Reads the relocation section associated with .debug_line and
+  // stores relocation information in reloc_map_.
+  void
+  read_relocs();
+
+  // Looks in the symtab to see what section a symbol is in.
+  unsigned int
+  symbol_section(unsigned int sym,
+                 typename elfcpp::Elf_types<size>::Elf_Addr* value);
+
   // Reads the DWARF2/3 header for this line info.  Each takes as input
   // a starting buffer position, and returns the ending position.
   const unsigned char*
@@ -81,6 +102,11 @@ class Dwarf_line_info
   process_one_opcode(const unsigned char* start,
                      struct LineStateMachine* lsm, size_t* len);
 
+  // If we saw anything amiss while parsing, we set this to false.
+  // Then addr2line will always fail (rather than return possibly-
+  // corrupt data).
+  bool data_valid_;
+
   // A DWARF2/3 line info header.  This is not the same size as in the
   // actual file, as the one in the file may have a 32 bit or 64 bit
   // lengths.
@@ -104,11 +130,26 @@ class Dwarf_line_info
   const unsigned char* buffer_;
   const unsigned char* const buffer_end_;
 
+  // This has relocations that point into buffer.
+  Track_relocs<size, big_endian>* track_relocs_;
+
+  // This is used to figure out what section to apply a relocation to.
+  const unsigned char* const symtab_buffer_;
+  const unsigned char* const symtab_buffer_end_;
+
   // Holds the directories and files as we see them.
   std::vector<std::string> directories_;
   // The first part is an index into directories_, the second the filename.
   std::vector< std::pair<int, std::string> > files_;
 
+  // A map from offset of the relocation target to the shndx and
+  // addend for the relocation.
+  typedef std::map<typename elfcpp::Elf_types<size>::Elf_Addr,
+                   std::pair<unsigned int,
+                             typename elfcpp::Elf_types<size>::Elf_Swxword> >
+  Reloc_map;
+  Reloc_map reloc_map_;
+
   // We can't do better than to keep the offsets in a sorted vector.
   // Here, offset is the key, and file_num/line_num is the value.
   struct Offset_to_lineno_entry
index 7895ddac72f0d335cb2d8a2e30684e3aa3f2aeb8..eb6eb5c1cf5dadd01169cce5cdb50db64f09d1d8 100644 (file)
@@ -156,6 +156,11 @@ class Sized_dynobj : public Dynobj
   do_section_link(unsigned int shndx)
   { return this->elf_file_.section_link(shndx); }
 
+  // Return the section link field.
+  unsigned int
+  do_section_info(unsigned int shndx)
+  { return this->elf_file_.section_info(shndx); }
+
  private:
   // For convenience.
   typedef Sized_dynobj<size, big_endian> This;
index d334b172d7d841f26df44358a5bb9bfca05134e4..44ebcaabb5cce04d526363e00065914659ecc34a 100644 (file)
@@ -31,6 +31,7 @@
 #include "layout.h"
 #include "output.h"
 #include "symtab.h"
+#include "reloc.h"
 #include "object.h"
 #include "dynobj.h"
 
@@ -1091,22 +1092,59 @@ Relocate_info<size, big_endian>::location(size_t, off_t offset) const
   // See if we can get line-number information from debugging sections.
   std::string filename;
   std::string file_and_lineno;   // Better than filename-only, if available.
-  for (unsigned int shndx = 0; shndx < this->object->shnum(); ++shndx)
-    if (this->object->section_name(shndx) == ".debug_line")
+
+  // The line-number information is in the ".debug_line" section.
+  unsigned int debug_shndx;
+  off_t debuglines_size;
+  const unsigned char* debuglines = NULL;
+  for (debug_shndx = 0; debug_shndx < this->object->shnum(); ++debug_shndx)
+    if (this->object->section_name(debug_shndx) == ".debug_line")
       {
-        off_t debuglines_size;
-        const unsigned char* debuglines = this->object->section_contents(
-            shndx, &debuglines_size, false);
-        if (debuglines)
-          {
-            Dwarf_line_info<size, big_endian> line_info(debuglines,
-                                                       debuglines_size);
-            line_info.read_line_mappings();
-            file_and_lineno = line_info.addr2line(this->data_shndx, offset);
-          }
+        debuglines = this->object->section_contents(
+            debug_shndx, &debuglines_size, false);
         break;
       }
 
+  // Find the relocation section for ".debug_line".
+  Track_relocs<size, big_endian> track_relocs;
+  bool got_relocs;
+  for (unsigned int reloc_shndx = 0;
+       reloc_shndx < this->object->shnum();
+       ++reloc_shndx)
+    {
+      unsigned int reloc_sh_type = this->object->section_type(reloc_shndx);
+      if ((reloc_sh_type == elfcpp::SHT_REL
+          || reloc_sh_type == elfcpp::SHT_RELA)
+         && this->object->section_info(reloc_shndx) == debug_shndx)
+       {
+         got_relocs = track_relocs.initialize(this->object, reloc_shndx,
+                                              reloc_sh_type);
+         break;
+       }
+    }
+
+  // Finally, we need the symtab section to interpret the relocs.
+  unsigned int symtab_shndx;
+  off_t symtab_size;
+  const unsigned char* symtab = NULL;
+  for (symtab_shndx = 0; symtab_shndx < this->object->shnum(); ++symtab_shndx)
+    if (this->object->section_type(symtab_shndx) == elfcpp::SHT_SYMTAB)
+      {
+        symtab = this->object->section_contents(
+            symtab_shndx, &symtab_size, false);
+        break;
+      }
+
+  // If we got all three sections we need, we can try to read debug info.
+  if (debuglines != NULL && got_relocs && symtab != NULL)
+    {
+      Dwarf_line_info<size, big_endian> line_info(debuglines, debuglines_size,
+                                                 &track_relocs,
+                                                  symtab, symtab_size);
+      line_info.read_line_mappings();
+      file_and_lineno = line_info.addr2line(this->data_shndx, offset);
+    }
+
   std::string ret(this->object->name());
   ret += ':';
   Symbol_location_info info;
index 8aa40a2e182850a1ad8d5565045f9bae2744222f..b8bc65c90980f213646b1295252095294f9e58b5 100644 (file)
@@ -215,6 +215,11 @@ class Object
   section_link(unsigned int shndx)
   { return this->do_section_link(shndx); }
 
+  // Return the section info field given a section index.
+  unsigned int
+  section_info(unsigned int shndx)
+  { return this->do_section_info(shndx); }
+
   // Read the symbol information.
   void
   read_symbols(Read_symbols_data* sd)
@@ -312,6 +317,10 @@ class Object
   virtual unsigned int
   do_section_link(unsigned int shndx) = 0;
 
+  // Get section info field--implemented by child class.
+  virtual unsigned int
+  do_section_info(unsigned int shndx) = 0;
+
   // Get the file.
   Input_file*
   input_file() const
@@ -826,6 +835,11 @@ class Sized_relobj : public Relobj
   do_section_link(unsigned int shndx)
   { return this->elf_file_.section_link(shndx); }
 
+  // Return the section info field.
+  unsigned int
+  do_section_info(unsigned int shndx)
+  { return this->elf_file_.section_info(shndx); }
+
  private:
   // For convenience.
   typedef Sized_relobj<size, big_endian> This;
index 5d2a160e41c1d2410b6fd0815837d95d8a9ab240..91b08199b9874fb7f08b43eb914e1d8d80209cfb 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <byteswap.h>
 
+#include "elfcpp.h"
 #include "workqueue.h"
 
 namespace gold