From Craig Silverstein: Use relocations in reporting error message

locations.
This commit is contained in:
Ian Lance Taylor 2007-11-09 23:16:54 +00:00
parent bbce853ae5
commit 4c50553d98
6 changed files with 182 additions and 25 deletions

View 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);

View file

@ -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

View 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;

View 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;

View 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;

View file

@ -25,6 +25,7 @@
#include <byteswap.h>
#include "elfcpp.h"
#include "workqueue.h"
namespace gold