From 5c2c6c957be387f3649b143508a2b5c730c0b6f5 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 2 Nov 2007 23:02:44 +0000 Subject: [PATCH] From Craig Silverstein: Add first version of generating error messages with file name and line number. --- elfcpp/dwarf.h | 10 - gold/Makefile.am | 2 + gold/Makefile.in | 19 +- gold/dwarf_reader.cc | 529 +++++++++++++++++++++++++++++++++++++++++++ gold/dwarf_reader.h | 150 ++++++++++++ gold/object.cc | 52 ++++- gold/po/POTFILES.in | 2 + gold/po/gold.pot | 458 +++++++++++++++++++++++-------------- 8 files changed, 1022 insertions(+), 200 deletions(-) create mode 100644 gold/dwarf_reader.cc create mode 100644 gold/dwarf_reader.h diff --git a/elfcpp/dwarf.h b/elfcpp/dwarf.h index 0b98bccc1e8..b60bdbd6011 100644 --- a/elfcpp/dwarf.h +++ b/elfcpp/dwarf.h @@ -35,16 +35,6 @@ namespace elfcpp { -typedef unsigned char Dwarf_uint8; -typedef signed char Dwarf_int8; -typedef uint16_t Dwarf_uint16; -typedef int16_t Dwarf_int16; -typedef uint32_t Dwarf_uint32; -typedef int32_t Dwarf_int32; -typedef uint64_t Dwarf_uint64; -typedef int64_t Dwarf_int64; - - // DWARF2 codes. enum DW_TAG diff --git a/gold/Makefile.am b/gold/Makefile.am index c9cde9ca977..a91a1c80cc8 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -33,6 +33,7 @@ CCFILES = \ defstd.cc \ dirsearch.cc \ dynobj.cc \ + dwarf_reader.cc \ ehframe.cc \ errors.cc \ fileread.cc \ @@ -60,6 +61,7 @@ HFILES = \ defstd.h \ dirsearch.h \ dynobj.h \ + dwarf_reader.h \ ehframe.h \ errors.h \ fileread.h \ diff --git a/gold/Makefile.in b/gold/Makefile.in index a7e3f73893f..9ca37010131 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -71,14 +71,14 @@ ARFLAGS = cru libgold_a_AR = $(AR) $(ARFLAGS) libgold_a_LIBADD = am__objects_1 = archive.$(OBJEXT) common.$(OBJEXT) defstd.$(OBJEXT) \ - dirsearch.$(OBJEXT) dynobj.$(OBJEXT) ehframe.$(OBJEXT) \ - errors.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \ - gold-threads.$(OBJEXT) layout.$(OBJEXT) merge.$(OBJEXT) \ - object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \ - parameters.$(OBJEXT) readsyms.$(OBJEXT) reloc.$(OBJEXT) \ - resolve.$(OBJEXT) script.$(OBJEXT) symtab.$(OBJEXT) \ - stringpool.$(OBJEXT) target-select.$(OBJEXT) version.$(OBJEXT) \ - workqueue.$(OBJEXT) + dirsearch.$(OBJEXT) dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) \ + ehframe.$(OBJEXT) errors.$(OBJEXT) fileread.$(OBJEXT) \ + gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \ + merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \ + output.$(OBJEXT) parameters.$(OBJEXT) readsyms.$(OBJEXT) \ + reloc.$(OBJEXT) resolve.$(OBJEXT) script.$(OBJEXT) \ + symtab.$(OBJEXT) stringpool.$(OBJEXT) target-select.$(OBJEXT) \ + version.$(OBJEXT) workqueue.$(OBJEXT) am__objects_2 = am__objects_3 = yyscript.$(OBJEXT) am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \ @@ -287,6 +287,7 @@ CCFILES = \ defstd.cc \ dirsearch.cc \ dynobj.cc \ + dwarf_reader.cc \ ehframe.cc \ errors.cc \ fileread.cc \ @@ -314,6 +315,7 @@ HFILES = \ defstd.h \ dirsearch.h \ dynobj.h \ + dwarf_reader.h \ ehframe.h \ errors.h \ fileread.h \ @@ -462,6 +464,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_reader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynobj.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ehframe.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Po@am__quote@ diff --git a/gold/dwarf_reader.cc b/gold/dwarf_reader.cc new file mode 100644 index 00000000000..05809a7d913 --- /dev/null +++ b/gold/dwarf_reader.cc @@ -0,0 +1,529 @@ +// dwarf_reader.cc -- parse dwarf2/3 debug information + +// Copyright 2007 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +#include "gold.h" + +#include "elfcpp_swap.h" +#include "dwarf.h" +#include "dwarf_reader.h" + +namespace { + +// Read an unsigned LEB128 number. Each byte contains 7 bits of +// information, plus one bit saying whether the number continues or +// not. + +uint64_t +read_unsigned_LEB_128(const unsigned char* buffer, size_t* len) +{ + uint64_t result = 0; + size_t num_read = 0; + unsigned int shift = 0; + unsigned char byte; + + do + { + byte = *buffer++; + num_read++; + result |= (static_cast(byte & 0x7f)) << shift; + shift += 7; + } + while (byte & 0x80); + + *len = num_read; + + return result; +} + +// Read a signed LEB128 number. These are like regular LEB128 +// numbers, except the last byte may have a sign bit set. + +int64_t +read_signed_LEB_128(const unsigned char* buffer, size_t* len) +{ + int64_t result = 0; + int shift = 0; + size_t num_read = 0; + unsigned char byte; + + do + { + byte = *buffer++; + num_read++; + result |= (static_cast(byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + + if ((shift < 8 * static_cast(sizeof(result))) && (byte & 0x40)) + result |= -((static_cast(1)) << shift); + *len = num_read; + return result; +} + +} // End anonymous namespace. + + +namespace gold { + +// This is the format of a DWARF2/3 line state machine that we process +// opcodes using. There is no need for anything outside the lineinfo +// processor to know how this works. + +struct LineStateMachine +{ + int file_num; + uint64_t address; + int line_num; + int column_num; + unsigned int shndx; // the section address refers to + bool is_stmt; // stmt means statement. + bool basic_block; + bool end_sequence; +}; + +static void +ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt) +{ + lsm->file_num = 1; + lsm->address = 0; + lsm->line_num = 1; + lsm->column_num = 0; + lsm->shndx = -1; + lsm->is_stmt = default_is_stmt; + lsm->basic_block = false; + lsm->end_sequence = false; +} + +// Read the DWARF header. + +template +const unsigned char* +Dwarf_line_info::read_header_prolog(const unsigned char* lineptr) +{ + uint32_t initial_length = elfcpp::Swap<32, big_endian>::readval(lineptr); + lineptr += 4; + + // In DWARF2/3, if the initial length is all 1 bits, then the offset + // size is 8 and we need to read the next 8 bytes for the real length. + if (initial_length == 0xffffffff) + { + header_.offset_size = 8; + initial_length = elfcpp::Swap<64, big_endian>::readval(lineptr); + lineptr += 8; + } + else + header_.offset_size = 4; + + header_.total_length = initial_length; + + gold_assert(lineptr + header_.total_length <= buffer_end_); + + header_.version = elfcpp::Swap<16, big_endian>::readval(lineptr); + lineptr += 2; + + if (header_.offset_size == 4) + header_.prologue_length = elfcpp::Swap<32, big_endian>::readval(lineptr); + else + header_.prologue_length = elfcpp::Swap<64, big_endian>::readval(lineptr); + lineptr += header_.offset_size; + + header_.min_insn_length = *lineptr; + lineptr += 1; + + header_.default_is_stmt = *lineptr; + lineptr += 1; + + header_.line_base = *reinterpret_cast(lineptr); + lineptr += 1; + + header_.line_range = *lineptr; + lineptr += 1; + + header_.opcode_base = *lineptr; + lineptr += 1; + + header_.std_opcode_lengths.reserve(header_.opcode_base + 1); + header_.std_opcode_lengths[0] = 0; + for (int i = 1; i < header_.opcode_base; i++) + { + header_.std_opcode_lengths[i] = *lineptr; + lineptr += 1; + } + + return lineptr; +} + +// The header for a debug_line section is mildly complicated, because +// the line info is very tightly encoded. + +const unsigned char* +Dwarf_line_info::read_header_tables(const unsigned char* lineptr) +{ + // It is legal for the directory entry table to be empty. + if (*lineptr) + { + int dirindex = 1; + while (*lineptr) + { + const unsigned char* dirname = lineptr; + gold_assert(dirindex == static_cast(directories_.size())); + directories_.push_back(reinterpret_cast(dirname)); + lineptr += directories_.back().size() + 1; + dirindex++; + } + } + lineptr++; + + // It is also legal for the file entry table to be empty. + if (*lineptr) + { + int fileindex = 1; + size_t len; + while (*lineptr) + { + const char* filename = reinterpret_cast(lineptr); + lineptr += strlen(filename) + 1; + + uint64_t dirindex = read_unsigned_LEB_128(lineptr, &len); + if (dirindex >= directories_.size()) + dirindex = 0; + lineptr += len; + + read_unsigned_LEB_128(lineptr, &len); // mod_time + lineptr += len; + + read_unsigned_LEB_128(lineptr, &len); // filelength + lineptr += len; + + gold_assert(fileindex == static_cast(files_.size())); + files_.push_back(std::pair(dirindex, filename)); + fileindex++; + } + } + lineptr++; + + return lineptr; +} + +// Process a single opcode in the .debug.line structure. + +// Templating on size and big_endian would yield more efficient (and +// simpler) code, but would bloat the binary. Speed isn't important +// here. + +bool +Dwarf_line_info::process_one_opcode(int size, bool big_endian, + const unsigned char* start, + struct LineStateMachine* lsm, + size_t* len) +{ + size_t oplen = 0; + size_t templen; + unsigned char opcode = *start; + oplen++; + start++; + + // If the opcode is great than the opcode_base, it is a special + // opcode. Most line programs consist mainly of special opcodes. + if (opcode >= header_.opcode_base) + { + opcode -= header_.opcode_base; + const int advance_address = ((opcode / header_.line_range) + * header_.min_insn_length); + lsm->address += advance_address; + + const int advance_line = ((opcode % header_.line_range) + + header_.line_base); + lsm->line_num += advance_line; + lsm->basic_block = true; + *len = oplen; + return true; + } + + // Otherwise, we have the regular opcodes + switch (opcode) + { + case elfcpp::DW_LNS_copy: + lsm->basic_block = false; + *len = oplen; + return true; + + case elfcpp::DW_LNS_advance_pc: + { + const uint64_t advance_address + = read_unsigned_LEB_128(start, &templen); + oplen += templen; + lsm->address += header_.min_insn_length * advance_address; + } + break; + + case elfcpp::DW_LNS_advance_line: + { + const uint64_t advance_line = read_signed_LEB_128(start, &templen); + oplen += templen; + lsm->line_num += advance_line; + } + break; + + case elfcpp::DW_LNS_set_file: + { + const uint64_t fileno = read_unsigned_LEB_128(start, &templen); + oplen += templen; + lsm->file_num = fileno; + } + break; + + case elfcpp::DW_LNS_set_column: + { + const uint64_t colno = read_unsigned_LEB_128(start, &templen); + oplen += templen; + lsm->column_num = colno; + } + break; + + case elfcpp::DW_LNS_negate_stmt: + lsm->is_stmt = !lsm->is_stmt; + break; + + case elfcpp::DW_LNS_set_basic_block: + lsm->basic_block = true; + break; + + case elfcpp::DW_LNS_fixed_advance_pc: + { + int advance_address; + if (big_endian) + advance_address = elfcpp::Swap<16, true>::readval(start); + else + advance_address = elfcpp::Swap<16, false>::readval(start); + oplen += 2; + lsm->address += advance_address; + } + break; + + case elfcpp::DW_LNS_const_add_pc: + { + const int advance_address = (header_.min_insn_length + * ((255 - header_.opcode_base) + / header_.line_range)); + lsm->address += advance_address; + } + break; + + case elfcpp::DW_LNS_extended_op: + { + const uint64_t extended_op_len + = read_unsigned_LEB_128(start, &templen); + start += templen; + oplen += templen + extended_op_len; + + const unsigned char extended_op = *start; + start++; + + switch (extended_op) + { + case elfcpp::DW_LNE_end_sequence: + lsm->end_sequence = true; + *len = oplen; + return true; + + case elfcpp::DW_LNE_set_address: + // FIXME: modify the address based on the reloc + if (size == 32 && big_endian == false) + lsm->address = elfcpp::Swap<32, false>::readval(start); + else if (size == 32 && big_endian == true) + lsm->address = elfcpp::Swap<32, true>::readval(start); + else if (size == 64 && big_endian == false) + lsm->address = elfcpp::Swap<64, false>::readval(start); + else if (size == 64 && big_endian == true) + lsm->address = elfcpp::Swap<64, true>::readval(start); + else + gold_assert(false); // We need to implement more cases, then. + // FIXME: set lsm->shndx from the reloc + lsm->shndx = 1; + break; + + case elfcpp::DW_LNE_define_file: + { + const char* filename = reinterpret_cast(start); + templen = strlen(filename) + 1; + start += templen; + + uint64_t dirindex = read_unsigned_LEB_128(start, &templen); + if (dirindex >= directories_.size()) + dirindex = 0; + oplen += templen; + + read_unsigned_LEB_128(start, &templen); // mod_time + oplen += templen; + + read_unsigned_LEB_128(start, &templen); // filelength + oplen += templen; + + files_.push_back(std::pair(dirindex, + filename)); + } + break; + } + } + break; + + default: + { + // Ignore unknown opcode silently + for (int i = 0; i < header_.std_opcode_lengths[opcode]; i++) + { + size_t templen; + read_unsigned_LEB_128(start, &templen); + start += templen; + oplen += templen; + } + } + break; + } + *len = oplen; + return false; +} + +// Read the debug information at LINEPTR and store it in the line +// number map. + +unsigned const char* +Dwarf_line_info::read_lines(int size, bool big_endian, + unsigned const char* lineptr) +{ + struct LineStateMachine lsm; + + // LENGTHSTART is the place the length field is based on. It is the + // point in the header after the initial length field. + const unsigned char* lengthstart = buffer_; + + // In 64 bit dwarf, the initial length is 12 bytes, because of the + // 0xffffffff at the start. + if (header_.offset_size == 8) + lengthstart += 12; + else + lengthstart += 4; + + while (lineptr < lengthstart + header_.total_length) + { + ResetLineStateMachine(&lsm, header_.default_is_stmt); + while (!lsm.end_sequence) + { + size_t oplength; + bool add_line = this->process_one_opcode(size, big_endian, + lineptr, &lsm, &oplength); + if (add_line) + { + Offset_to_lineno_entry entry + = { lsm.address, lsm.file_num, lsm.line_num }; + line_number_map_[lsm.shndx].push_back(entry); + } + lineptr += oplength; + } + } + + return lengthstart + header_.total_length; +} + +// Called after all line numbers have been read. + +void +Dwarf_line_info::finalize_line_number_map() +{ + for (Lineno_map::iterator it = line_number_map_.begin(); + it != line_number_map_.end(); + ++it) + // Each vector needs to be sorted by offset. + sort(it->second.begin(), it->second.end()); +} + +// Return a string for a file name and line number. + +std::string +Dwarf_line_info::addr2line(unsigned int shndx, off_t offset) +{ + const Offset_to_lineno_entry lookup_key = { offset, 0, 0 }; + std::vector& offsets = line_number_map_[shndx]; + std::vector::const_iterator it + = std::lower_bound(offsets.begin(), offsets.end(), lookup_key); + + // If we found an exact match, great, otherwise find the last entry + // before the passed-in offset. + if (it->offset > offset) + { + if (it == offsets.begin()) + return ""; + --it; + gold_assert(it->offset < offset); + } + + // Convert the file_num + line_num into a string. + std::string ret; + gold_assert(it->file_num < static_cast(files_.size())); + const std::pair& filename_pair = files_[it->file_num]; + gold_assert(filename_pair.first < static_cast(directories_.size())); + const std::string& dirname = directories_[filename_pair.first]; + const std::string& filename = filename_pair.second; + if (!dirname.empty()) + { + ret += dirname; + ret += "/"; + } + ret += filename; + if (ret.empty()) + ret = "(unknown)"; + + char buffer[64]; // enough to hold a line number + snprintf(buffer, sizeof(buffer), "%d", it->line_num); + ret += ":"; + ret += buffer; + + return ret; +} + +#ifdef HAVE_TARGET_32_LITTLE +template +const unsigned char* +Dwarf_line_info::read_header_prolog<32, false>(const unsigned char* lineptr); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +const unsigned char* +Dwarf_line_info::read_header_prolog<32, true>(const unsigned char* lineptr); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +const unsigned char* +Dwarf_line_info::read_header_prolog<64, false>(const unsigned char* lineptr); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +const unsigned char* +Dwarf_line_info::read_header_prolog<64, true>(const unsigned char* lineptr); +#endif + +} // End namespace gold. diff --git a/gold/dwarf_reader.h b/gold/dwarf_reader.h new file mode 100644 index 00000000000..a36771554a7 --- /dev/null +++ b/gold/dwarf_reader.h @@ -0,0 +1,150 @@ +// dwarf_reader.h -- parse dwarf2/3 debug information for gold -*- C++ -*- + +// Copyright 2007 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +#ifndef GOLD_DWARF_READER_H +#define GOLD_DWARF_READER_H + +#include + +#include "elfcpp_swap.h" +#include "dwarf.h" + +namespace gold +{ + +struct LineStateMachine; + +// This class is used to read the line information from the debugging +// section of an object file. + +class Dwarf_line_info +{ + public: + // Initializes a .debug_line reader. Buffer and buffer length point + // 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), + directories_(1), files_(1) + { } + + // Start processing line info, and populates the offset_map_. + template + void + read_line_mappings() + { + while (buffer_ < buffer_end_) + { + const unsigned char* lineptr = buffer_; + lineptr = this->read_header_prolog(lineptr); + lineptr = this->read_header_tables(lineptr); + lineptr = this->read_lines(size, big_endian, lineptr); + buffer_ = lineptr; + } + finalize_line_number_map(); + } + + // Given a section number and an offset, returns the associated + // file and line-number, as a string: "file:lineno". If unable + // to do the mapping, returns the empty string. You must call + // read_line_mappings() before calling this function. + std::string + addr2line(unsigned int shndx, off_t offset); + + private: + // Reads the DWARF2/3 header for this line info. Each takes as input + // a starting buffer position, and returns the ending position. + template + const unsigned char* + read_header_prolog(const unsigned char* lineptr); + + const unsigned char* + read_header_tables(const unsigned char* lineptr); + + // Reads the DWARF2/3 line information. + const unsigned char* + read_lines(int size, bool big_endian, const unsigned char* lineptr); + + // Process a single line info opcode at START using the state + // machine at LSM. Return true if we should define a line using the + // current state of the line state machine. Place the length of the + // opcode in LEN. + bool + process_one_opcode(int size, bool big_endian, + const unsigned char* start, + struct LineStateMachine* lsm, size_t* len); + + // Called after all line number have been read, to ready + // line_number_map_ for calls to addr2line(). + void + finalize_line_number_map(); + + // 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. + + struct Dwarf_line_infoHeader + { + off_t total_length; + int version; + off_t prologue_length; + int min_insn_length; // insn stands for instructin + bool default_is_stmt; // stmt stands for statement + signed char line_base; + int line_range; + unsigned char opcode_base; + std::vector std_opcode_lengths; + int offset_size; + } header_; + + // buffer is the buffer for our line info, starting at exactly where + // the line info to read is. + const unsigned char* buffer_; + const unsigned char* const 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_; + + // 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 + { + off_t offset; + int file_num; // a pointer into files_ + int line_num; + // Offsets are unique within a section, so that's a sufficient sort key. + bool operator<(const Offset_to_lineno_entry& that) const + { return this->offset < that.offset; } + }; + // We have a vector of offset->lineno entries for every input section. + typedef Unordered_map > + Lineno_map; + + Lineno_map line_number_map_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_DWARF_READER_H) diff --git a/gold/object.cc b/gold/object.cc index 269acc5e2a7..58f0db08242 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -27,6 +27,7 @@ #include #include "target-select.h" +#include "dwarf_reader.h" #include "layout.h" #include "output.h" #include "symtab.h" @@ -844,7 +845,7 @@ Sized_relobj::get_symbol_location_info( else if (sym.get_st_shndx() == shndx && static_cast(sym.get_st_value()) <= offset && (static_cast(sym.get_st_value() + sym.get_st_size()) - >= offset)) + > offset)) { if (sym.get_st_name() > names_size) info->enclosing_symbol_name = "(invalid)"; @@ -907,25 +908,54 @@ template std::string Relocate_info::location(size_t, off_t offset) const { - // FIXME: We would like to print the following: - // /tmp/foo.o: in function 'fn':foo.c:12: undefined reference to 'xxx' - // We're missing line numbers. + // 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") + { + 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); + } + break; + } + std::string ret(this->object->name()); ret += ':'; Symbol_location_info info; if (this->object->get_symbol_location_info(this->data_shndx, offset, &info)) { ret += " in function "; + // We could demangle this name before printing, but we don't + // bother because gcc runs linker output through a demangle + // filter itself. The only advantage to demangling here is if + // someone might call ld directly, rather than via gcc. If we + // did want to demangle, cplus_demangle() is in libiberty. ret += info.enclosing_symbol_name; ret += ":"; - ret += info.source_file; + filename = info.source_file; + } + + if (!file_and_lineno.empty()) + ret += file_and_lineno; + else + { + if (!filename.empty()) + ret += filename; + ret += "("; + ret += this->object->section_name(this->data_shndx); + char buf[100]; + // Offsets into sections have to be positive. + snprintf(buf, sizeof(buf), "+0x%lx", static_cast(offset)); + ret += buf; + ret += ")"; } - ret += "("; - ret += this->object->section_name(this->data_shndx); - char buf[100]; - // Offsets into sections have to be positive. - snprintf(buf, sizeof(buf), "+0x%lx)", static_cast(offset)); - ret += buf; return ret; } diff --git a/gold/po/POTFILES.in b/gold/po/POTFILES.in index bb32fdf9d99..a78d65d0650 100644 --- a/gold/po/POTFILES.in +++ b/gold/po/POTFILES.in @@ -6,6 +6,8 @@ defstd.cc defstd.h dirsearch.cc dirsearch.h +dwarf_reader.cc +dwarf_reader.h dynobj.cc dynobj.h ehframe.cc diff --git a/gold/po/gold.pot b/gold/po/gold.pot index 12770a64822..d79701c3363 100644 --- a/gold/po/gold.pot +++ b/gold/po/gold.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2007-10-13 23:40-0700\n" +"POT-Creation-Date: 2007-11-02 16:01-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -38,7 +38,7 @@ msgstr "" #: archive.cc:199 #, c-format -msgid "%s: malformed archive header name at %zu\n" +msgid "%s: malformed archive header name at %zu" msgstr "" #: archive.cc:224 @@ -105,7 +105,7 @@ msgstr "" msgid "dynamic symbol table name section has wrong type: %u" msgstr "" -#: dynobj.cc:365 object.cc:428 +#: dynobj.cc:365 object.cc:447 #, c-format msgid "bad section name offset for section %u: %lu" msgstr "" @@ -169,7 +169,7 @@ msgstr "" msgid "size of dynamic symbols is not multiple of symbol size" msgstr "" -#: dynobj.cc:1253 +#: dynobj.cc:1265 #, c-format msgid "symbol %s has undefined version %s" msgstr "" @@ -229,19 +229,19 @@ msgstr "" msgid "%s: maximum bytes mapped for read at one time: %llu\n" msgstr "" -#: fileread.cc:441 +#: fileread.cc:442 #, c-format -msgid "cannot find -l%s\n" +msgid "cannot find -l%s" msgstr "" -#: fileread.cc:468 +#: fileread.cc:469 #, c-format -msgid "cannot find %s\n" +msgid "cannot find %s" msgstr "" -#: fileread.cc:479 +#: fileread.cc:480 #, c-format -msgid "cannot open %s: %s\n" +msgid "cannot open %s: %s" msgstr "" #: gold.cc:72 @@ -249,468 +249,576 @@ msgstr "" msgid "%s: internal error in %s, at %s:%d\n" msgstr "" -#: gold.cc:118 +#. We had some input files, but we weren't able to open any of +#. them. +#: gold.cc:118 gold.cc:164 msgid "no input files" msgstr "" #. We print out just the first .so we see; there may be others. -#: gold.cc:161 +#: gold.cc:179 #, c-format msgid "cannot mix -static with dynamic object %s" msgstr "" -#: gold-threads.cc:66 -msgid "pthead_mutextattr_init failed" -msgstr "" - #: gold-threads.cc:69 -msgid "pthread_mutextattr_settype failed" +#, c-format +msgid "pthead_mutextattr_init failed: %s" msgstr "" -#: gold-threads.cc:73 -msgid "pthread_mutex_init failed" +#: gold-threads.cc:72 +#, c-format +msgid "pthread_mutextattr_settype failed: %s" msgstr "" #: gold-threads.cc:76 -msgid "pthread_mutexattr_destroy failed" +#, c-format +msgid "pthread_mutex_init failed: %s" msgstr "" -#: gold-threads.cc:82 -msgid "pthread_mutex_destroy failed" +#: gold-threads.cc:79 +#, c-format +msgid "pthread_mutexattr_destroy failed: %s" msgstr "" -#: gold-threads.cc:89 -msgid "pthread_mutex_lock failed" +#: gold-threads.cc:85 +#, c-format +msgid "pthread_mutex_destroy failed: %s" msgstr "" -#: gold-threads.cc:96 -msgid "pthread_mutex_unlock failed" +#: gold-threads.cc:92 +#, c-format +msgid "pthread_mutex_lock failed: %s" msgstr "" -#: gold-threads.cc:177 -msgid "pthread_cond_init failed" +#: gold-threads.cc:99 +#, c-format +msgid "pthread_mutex_unlock failed: %s" msgstr "" -#: gold-threads.cc:183 -msgid "pthread_cond_destroy failed" +#: gold-threads.cc:180 +#, c-format +msgid "pthread_cond_init failed: %s" +msgstr "" + +#: gold-threads.cc:186 +#, c-format +msgid "pthread_cond_destroy failed: %s" msgstr "" -#: gold-threads.cc:190 -msgid "pthread_cond_wait failed" +#: gold-threads.cc:193 +#, c-format +msgid "pthread_cond_wait failed: %s" msgstr "" -#: gold-threads.cc:197 -msgid "pthread_cond_signal failed" +#: gold-threads.cc:200 +#, c-format +msgid "pthread_cond_signal failed: %s" msgstr "" #. FIXME: This needs to specify the location somehow. -#: i386.cc:142 i386.cc:1160 x86_64.cc:1138 +#: i386.cc:150 i386.cc:1296 x86_64.cc:162 x86_64.cc:1228 msgid "missing expected TLS relocation" msgstr "" -#: i386.cc:728 x86_64.cc:700 x86_64.cc:840 +#: i386.cc:746 x86_64.cc:709 x86_64.cc:876 #, c-format msgid "%s: unsupported reloc %u against local symbol" msgstr "" -#: i386.cc:782 +#: i386.cc:840 i386.cc:1070 x86_64.cc:817 x86_64.cc:1055 #, c-format -msgid "%s: unexpected reloc %u in object file\n" +msgid "%s: unexpected reloc %u in object file" msgstr "" -#: i386.cc:870 x86_64.cc:854 x86_64.cc:1024 +#: i386.cc:926 x86_64.cc:890 x86_64.cc:1114 #, c-format msgid "%s: unsupported reloc %u against global symbol %s" msgstr "" -#: i386.cc:974 x86_64.cc:778 x86_64.cc:965 -#, c-format -msgid "%s: unexpected reloc %u in object file" -msgstr "" - -#: i386.cc:1070 +#: i386.cc:1166 #, c-format msgid "%s: unsupported RELA reloc section" msgstr "" -#: i386.cc:1252 x86_64.cc:1315 +#: i386.cc:1423 x86_64.cc:1426 #, c-format msgid "unexpected reloc %u in object file" msgstr "" -#: i386.cc:1284 i386.cc:1343 i386.cc:1356 i386.cc:1376 i386.cc:1397 -#: x86_64.cc:1337 x86_64.cc:1404 x86_64.cc:1413 +#: i386.cc:1455 i386.cc:1502 i386.cc:1509 i386.cc:1529 i386.cc:1558 +#: x86_64.cc:1447 x86_64.cc:1496 x86_64.cc:1507 #, c-format msgid "unsupported reloc %u" msgstr "" -#: i386.cc:1309 x86_64.cc:1362 +#: i386.cc:1480 x86_64.cc:1472 msgid "TLS reloc but no TLS segment" msgstr "" -#: i386.cc:1364 +#: i386.cc:1517 msgid "both SUN and GNU model TLS relocations" msgstr "" -#: merge.cc:254 +#: merge.cc:258 msgid "mergeable string section length not multiple of character size" msgstr "" -#: merge.cc:269 +#: merge.cc:274 msgid "entry in mergeable string section not null terminated" msgstr "" -#: object.cc:49 +#: object.cc:50 #, c-format msgid "%s: unsupported ELF machine number %d" msgstr "" -#: object.cc:67 +#: object.cc:68 script.cc:1222 #, c-format msgid "%s: %s" msgstr "" -#: object.cc:102 +#: object.cc:103 #, c-format msgid "section name section has wrong type: %u" msgstr "" -#: object.cc:243 +#: object.cc:244 #, c-format msgid "invalid symbol table name index: %u" msgstr "" -#: object.cc:249 +#: object.cc:250 #, c-format msgid "symbol table name section has wrong type: %u" msgstr "" -#: object.cc:304 +#: object.cc:305 #, c-format msgid "section group %u info %u out of range" msgstr "" -#: object.cc:322 +#: object.cc:323 #, c-format msgid "symbol %u name offset %u out of range" msgstr "" -#: object.cc:354 +#: object.cc:355 #, c-format msgid "section %u in section group %u out of range" msgstr "" -#: object.cc:494 +#: object.cc:525 msgid "size of symbols is not multiple of symbol size" msgstr "" #. FIXME: Handle SHN_XINDEX. -#: object.cc:584 +#: object.cc:615 #, c-format msgid "unknown section index %u for local symbol %u" msgstr "" -#: object.cc:593 +#: object.cc:624 #, c-format msgid "local symbol %u section index %u out of range" msgstr "" -#: object.cc:625 +#: object.cc:656 #, c-format msgid "local symbol %u section name out of range: %u >= %u" msgstr "" -#: object.cc:805 +#: object.cc:892 #, c-format msgid "%s: incompatible target" msgstr "" -#: object.cc:872 +#: object.cc:994 #, c-format msgid "%s: unsupported ELF file type %d" msgstr "" -#: object.cc:891 object.cc:937 object.cc:971 +#: object.cc:1013 object.cc:1059 object.cc:1093 #, c-format msgid "%s: ELF file too short" msgstr "" -#: object.cc:899 +#: object.cc:1021 #, c-format msgid "%s: invalid ELF version 0" msgstr "" -#: object.cc:901 +#: object.cc:1023 #, c-format msgid "%s: unsupported ELF version %d" msgstr "" -#: object.cc:908 +#: object.cc:1030 #, c-format msgid "%s: invalid ELF class 0" msgstr "" -#: object.cc:914 +#: object.cc:1036 #, c-format msgid "%s: unsupported ELF class %d" msgstr "" -#: object.cc:921 +#: object.cc:1043 #, c-format msgid "%s: invalid ELF data encoding" msgstr "" -#: object.cc:927 +#: object.cc:1049 #, c-format msgid "%s: unsupported ELF data encoding %d" msgstr "" -#: object.cc:947 +#: object.cc:1069 #, c-format msgid "%s: not configured to support 32-bit big-endian object" msgstr "" -#: object.cc:960 +#: object.cc:1082 #, c-format msgid "%s: not configured to support 32-bit little-endian object" msgstr "" -#: object.cc:981 +#: object.cc:1103 #, c-format msgid "%s: not configured to support 64-bit big-endian object" msgstr "" -#: object.cc:994 +#: object.cc:1116 #, c-format msgid "%s: not configured to support 64-bit little-endian object" msgstr "" -#: options.cc:139 +#: options.cc:142 +#, c-format +msgid "%s: unable to parse script file %s\n" +msgstr "" + +#: options.cc:170 #, c-format msgid "" "Usage: %s [options] file...\n" "Options:\n" msgstr "" -#: options.cc:309 -msgid "Search for library LIBNAME" +#: options.cc:341 +msgid "Only set DT_NEEDED for dynamic libs if used" msgstr "" -#: options.cc:310 -msgid "-lLIBNAME, --library LIBNAME" +#: options.cc:344 +msgid "Always DT_NEEDED for dynamic libs (default)" msgstr "" -#: options.cc:312 -msgid "Start a library search group" +#: options.cc:347 +msgid "-l searches for shared libraries" msgstr "" -#: options.cc:314 -msgid "End a library search group" +#: options.cc:351 +msgid "-l does not search for shared libraries" msgstr "" -#: options.cc:316 +#: options.cc:354 +msgid "Bind defined symbols locally" +msgstr "" + +#: options.cc:356 msgid "Export all dynamic symbols" msgstr "" -#: options.cc:318 +#: options.cc:358 +msgid "Create exception frame header" +msgstr "" + +#: options.cc:360 msgid "Set dynamic linker path" msgstr "" -#: options.cc:319 +#: options.cc:361 msgid "-I PROGRAM, --dynamic-linker PROGRAM" msgstr "" -#: options.cc:321 +#: options.cc:363 +msgid "Search for library LIBNAME" +msgstr "" + +#: options.cc:364 +msgid "-lLIBNAME, --library LIBNAME" +msgstr "" + +#: options.cc:366 msgid "Add directory to search path" msgstr "" -#: options.cc:322 +#: options.cc:367 msgid "-L DIR, --library-path DIR" msgstr "" -#: options.cc:324 +#: options.cc:369 msgid "Ignored for compatibility" msgstr "" -#: options.cc:326 -msgid "Optimize output file size" +#: options.cc:371 +msgid "Set output file name" msgstr "" -#: options.cc:327 -msgid "-O level" +#: options.cc:372 +msgid "-o FILE, --output FILE" msgstr "" -#: options.cc:329 -msgid "Set output file name" +#: options.cc:374 +msgid "Optimize output file size" msgstr "" -#: options.cc:330 -msgid "-o FILE, --output FILE" +#: options.cc:375 +msgid "-O level" msgstr "" -#: options.cc:332 +#: options.cc:377 msgid "Generate relocatable output" msgstr "" -#: options.cc:334 +#: options.cc:379 msgid "Add DIR to runtime search path" msgstr "" -#: options.cc:335 +#: options.cc:380 msgid "-R DIR, -rpath DIR" msgstr "" -#: options.cc:337 -msgid "Strip all symbols" -msgstr "" - -#: options.cc:339 -msgid "Strip debugging information" +#: options.cc:383 +msgid "Add DIR to link time shared library search path" msgstr "" -#: options.cc:341 -msgid "Create exception frame header" +#: options.cc:384 +msgid "--rpath-link DIR" msgstr "" -#: options.cc:344 -msgid "Add DIR to link time shared library search path" +#: options.cc:386 +msgid "Strip all symbols" msgstr "" -#: options.cc:345 -msgid "--rpath-link DIR" +#: options.cc:388 +msgid "Strip debugging information" msgstr "" -#: options.cc:347 +#: options.cc:390 msgid "Generate shared library" msgstr "" -#: options.cc:349 +#: options.cc:392 msgid "Do not link against shared libraries" msgstr "" -#: options.cc:351 +#: options.cc:394 msgid "Print resource usage statistics" msgstr "" -#: options.cc:353 +#: options.cc:396 msgid "Set target system root directory" msgstr "" -#: options.cc:354 +#: options.cc:397 msgid "--sysroot DIR" msgstr "" -#: options.cc:356 -msgid "Only set DT_NEEDED for dynamic libs if used" +#: options.cc:398 +msgid "Set the address of the .text section" msgstr "" -#: options.cc:359 -msgid "Always DT_NEEDED for dynamic libs (default)" +#: options.cc:399 +msgid "-Ttext ADDRESS" +msgstr "" + +#. This must come after -Ttext since it's a prefix of it. +#: options.cc:402 +msgid "Read linker script" +msgstr "" + +#: options.cc:403 +msgid "-T FILE, --script FILE" +msgstr "" + +#: options.cc:405 +msgid "Run the linker multi-threaded" +msgstr "" + +#: options.cc:407 +msgid "Do not run the linker multi-threaded" +msgstr "" + +#: options.cc:409 +msgid "Number of threads to use" +msgstr "" + +#: options.cc:410 +msgid "--thread-count COUNT" +msgstr "" + +#: options.cc:413 +msgid "Number of threads to use in initial pass" +msgstr "" + +#: options.cc:414 +msgid "--thread-count-initial COUNT" +msgstr "" + +#: options.cc:417 +msgid "Number of threads to use in middle pass" +msgstr "" + +#: options.cc:418 +msgid "--thread-count-middle COUNT" +msgstr "" + +#: options.cc:421 +msgid "Number of threads to use in final pass" +msgstr "" + +#: options.cc:422 +msgid "--thread-count-final COUNT" msgstr "" -#: options.cc:362 +#: options.cc:425 msgid "Include all archive contents" msgstr "" -#: options.cc:366 +#: options.cc:429 msgid "Include only needed archive contents" msgstr "" -#: options.cc:369 +#: options.cc:434 +msgid "" +"Subcommands as follows:\n" +" -z execstack Mark output as requiring executable stack\n" +" -z noexecstack Mark output as not requiring executable stack" +msgstr "" + +#: options.cc:437 +msgid "-z SUBCOMMAND" +msgstr "" + +#: options.cc:440 +msgid "Start a library search group" +msgstr "" + +#: options.cc:442 +msgid "End a library search group" +msgstr "" + +#: options.cc:444 msgid "Report usage information" msgstr "" -#: options.cc:371 +#: options.cc:446 msgid "Report version information" msgstr "" -#: options.cc:576 +#: options.cc:518 +#, c-format +msgid "%s: unrecognized -z subcommand: %s\n" +msgstr "" + +#: options.cc:698 msgid "unexpected argument" msgstr "" -#: options.cc:583 options.cc:634 options.cc:735 +#: options.cc:705 options.cc:757 options.cc:838 msgid "missing argument" msgstr "" -#: options.cc:596 options.cc:643 +#: options.cc:718 options.cc:766 msgid "unknown option" msgstr "" -#: options.cc:651 +#: options.cc:784 #, c-format -msgid "%s: missing group end" +msgid "%s: missing group end\n" msgstr "" -#: options.cc:748 +#: options.cc:912 msgid "may not nest groups" msgstr "" -#: options.cc:758 +#: options.cc:922 msgid "group end without group start" msgstr "" -#: options.cc:768 +#: options.cc:932 #, c-format msgid "%s: use the --help option for usage information\n" msgstr "" -#: options.cc:777 +#: options.cc:941 #, c-format msgid "%s: %s: %s\n" msgstr "" -#: options.cc:786 +#: options.cc:950 #, c-format msgid "%s: -%c: %s\n" msgstr "" -#: output.cc:1031 +#: options.h:338 +#, c-format +msgid "%s: invalid argument to -Ttext: %s\n" +msgstr "" + +#: options.h:351 +#, c-format +msgid "%s: invalid thread count: %s\n" +msgstr "" + +#: output.cc:1038 #, c-format msgid "invalid alignment %lu for section \"%s\"" msgstr "" -#: output.cc:1697 +#: output.cc:1703 #, c-format msgid "%s: open: %s" msgstr "" -#: output.cc:1702 +#: output.cc:1708 #, c-format msgid "%s: lseek: %s" msgstr "" -#: output.cc:1705 +#: output.cc:1711 #, c-format msgid "%s: write: %s" msgstr "" -#: output.cc:1711 +#: output.cc:1717 #, c-format msgid "%s: mmap: %s" msgstr "" -#: output.cc:1721 +#: output.cc:1727 #, c-format -msgid "%s: munmap: %s\n" +msgid "%s: munmap: %s" msgstr "" -#: output.cc:1725 +#: output.cc:1731 #, c-format msgid "%s: close: %s" msgstr "" -#: readsyms.cc:94 +#: readsyms.cc:147 #, c-format msgid "%s: file is empty" msgstr "" -#: readsyms.cc:129 +#: readsyms.cc:182 #, c-format msgid "%s: ordinary object found in input group" msgstr "" #. Here we have to handle any other input file types we need. -#: readsyms.cc:177 +#: readsyms.cc:230 #, c-format msgid "%s: not an object or archive" msgstr "" @@ -735,53 +843,66 @@ msgstr "" msgid "reloc section %u size %lu uneven" msgstr "" -#: resolve.cc:136 +#: resolve.cc:165 #, c-format msgid "%s: invalid STB_LOCAL symbol %s in external symbols" msgstr "" -#: resolve.cc:142 +#: resolve.cc:171 #, c-format msgid "%s: unsupported symbol binding %d for symbol %s" msgstr "" #. Two definitions of the same symbol. -#. FIXME: Report locations. -#: resolve.cc:280 +#. FIXME: Do a better job of reporting locations. +#: resolve.cc:310 #, c-format -msgid "multiple definition of %s\n" +msgid "%s: multiple definition of %s" msgstr "" -#: script.cc:1169 +#: resolve.cc:311 resolve.cc:316 +msgid "command line" +msgstr "" + +#: resolve.cc:313 +#, c-format +msgid "%s: previous definition here" +msgstr "" + +#. There are some options that we could handle here--e.g., +#. -lLIBRARY. Should we bother? +#: script.cc:1326 #, c-format -msgid "%s: %s\n" +msgid "" +"%s: Ignoring command OPTION; OPTION is only valid for scripts specified via -" +"T" msgstr "" -#: symtab.cc:517 +#: symtab.cc:540 #, c-format msgid "bad global symbol name offset %u at %zu" msgstr "" -#: symtab.cc:595 +#: symtab.cc:618 msgid "too few symbol versions" msgstr "" -#: symtab.cc:614 +#: symtab.cc:647 #, c-format msgid "bad symbol name offset %u at %zu" msgstr "" -#: symtab.cc:665 +#: symtab.cc:701 #, c-format msgid "versym for symbol %zu out of range: %u" msgstr "" -#: symtab.cc:672 +#: symtab.cc:709 #, c-format msgid "versym for symbol %zu has no name: %u" msgstr "" -#: symtab.cc:1241 symtab.cc:1444 +#: symtab.cc:1427 symtab.cc:1630 #, c-format msgid "%s: unsupported symbol section 0x%x" msgstr "" @@ -791,11 +912,11 @@ msgstr "" msgid "reloc has bad offset %zu" msgstr "" -#: tls.h:58 x86_64.cc:1538 +#: tls.h:58 msgid "TLS relocation out of range" msgstr "" -#: tls.h:72 x86_64.cc:1551 +#: tls.h:72 msgid "TLS relocation against invalid instruction" msgstr "" @@ -814,17 +935,12 @@ msgid "" "This program has absolutely no warranty.\n" msgstr "" -#. FIXME: This needs to specify the location somehow. -#: x86_64.cc:154 -msgid "missing expected TLS relocation\n" -msgstr "" - -#: x86_64.cc:1047 +#: x86_64.cc:1137 #, c-format msgid "%s: unsupported REL reloc section" msgstr "" -#: x86_64.cc:1389 +#: x86_64.cc:1535 #, c-format msgid "unsupported reloc type %u" msgstr "" -- 2.30.2