summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/dwarf_reader.cc80
-rw-r--r--gold/dwarf_reader.h45
-rw-r--r--gold/dynobj.h5
-rw-r--r--gold/object.cc62
-rw-r--r--gold/object.h14
-rw-r--r--gold/reloc.h1
6 files changed, 182 insertions, 25 deletions
diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc
index 1873091b49..74e089f4f0 100644
--- a/gold/dwarf_reader.cc
+++ b/gold/dwarf_reader.cc
@@ -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);
diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h
index a01634238a..1bb6ea32ef 100644
--- a/gold/dwarf_reader.h
+++ b/gold/dwarf_reader.h
@@ -24,13 +24,17 @@
#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
diff --git a/gold/dynobj.h b/gold/dynobj.h
index 7895ddac72..eb6eb5c1cf 100644
--- a/gold/dynobj.h
+++ b/gold/dynobj.h
@@ -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;
diff --git a/gold/object.cc b/gold/object.cc
index d334b172d7..44ebcaabb5 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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;
diff --git a/gold/object.h b/gold/object.h
index 8aa40a2e18..b8bc65c909 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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;
diff --git a/gold/reloc.h b/gold/reloc.h
index 5d2a160e41..91b08199b9 100644
--- a/gold/reloc.h
+++ b/gold/reloc.h
@@ -25,6 +25,7 @@
#include <byteswap.h>
+#include "elfcpp.h"
#include "workqueue.h"
namespace gold