From Craig Silverstein: Use relocations in reporting error message
locations.
This commit is contained in:
parent
bbce853ae5
commit
4c50553d98
6 changed files with 182 additions and 25 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <byteswap.h>
|
||||
|
||||
#include "elfcpp.h"
|
||||
#include "workqueue.h"
|
||||
|
||||
namespace gold
|
||||
|
|
Loading…
Reference in a new issue