From 4c50553d987166e6f2ee3aa56e286dc4b9e82cbc Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 9 Nov 2007 23:16:54 +0000 Subject: [PATCH] From Craig Silverstein: Use relocations in reporting error message locations. --- gold/dwarf_reader.cc | 80 ++++++++++++++++++++++++++++++++++++++------ gold/dwarf_reader.h | 45 +++++++++++++++++++++++-- gold/dynobj.h | 5 +++ gold/object.cc | 62 +++++++++++++++++++++++++++------- gold/object.h | 14 ++++++++ gold/reloc.h | 1 + 6 files changed, 182 insertions(+), 25 deletions(-) diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc index 1873091b497..74e089f4f0e 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::process_one_opcode( return true; case elfcpp::DW_LNE_set_address: - // FIXME: modify the address based on the reloc - lsm->address = elfcpp::Swap::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::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(start); @@ -435,17 +449,55 @@ Dwarf_line_info::read_lines(unsigned const char* lineptr) return lengthstart + header_.total_length; } +// Looks in the symtab to see what section a symbol is in. + +template +unsigned int +Dwarf_line_info::symbol_section( + unsigned int sym, + typename elfcpp::Elf_types::Elf_Addr* value) +{ + const int symsize = elfcpp::Elf_sizes::sym_size; + gold_assert(this->symtab_buffer_ + sym * symsize < this->symtab_buffer_end_); + elfcpp::Sym elfsym(this->symtab_buffer_ + sym * symsize); + *value = elfsym.get_st_value(); + return elfsym.get_st_shndx(); +} + +// Read the relocations into a Reloc_map. + +template +void +Dwarf_line_info::read_relocs() +{ + if (this->symtab_buffer_ == NULL) + return; + + typename elfcpp::Elf_types::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 void Dwarf_line_info::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::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 std::string Dwarf_line_info::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& offsets = line_number_map_[shndx]; + std::vector& offsets = this->line_number_map_[shndx]; + if (offsets.empty()) + return ""; + typename std::vector::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 a01634238ab..1bb6ea32ef6 100644 --- a/gold/dwarf_reader.h +++ b/gold/dwarf_reader.h @@ -24,13 +24,17 @@ #define GOLD_DWARF_READER_H #include +#include +#include "elfcpp.h" #include "elfcpp_swap.h" #include "dwarf.h" namespace gold { +template +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* 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::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* 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 directories_; // The first part is an index into directories_, the second the filename. std::vector< std::pair > files_; + // A map from offset of the relocation target to the shndx and + // addend for the relocation. + typedef std::map::Elf_Addr, + std::pair::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 7895ddac72f..eb6eb5c1cf5 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 This; diff --git a/gold/object.cc b/gold/object.cc index d334b172d7d..44ebcaabb5c 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::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 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 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 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 8aa40a2e182..b8bc65c9098 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 This; diff --git a/gold/reloc.h b/gold/reloc.h index 5d2a160e41c..91b08199b98 100644 --- a/gold/reloc.h +++ b/gold/reloc.h @@ -25,6 +25,7 @@ #include +#include "elfcpp.h" #include "workqueue.h" namespace gold -- 2.30.2