OSDN Git Service

From Craig Silverstein: Add first version of generating error messages
authoriant <iant>
Fri, 2 Nov 2007 23:02:43 +0000 (23:02 +0000)
committeriant <iant>
Fri, 2 Nov 2007 23:02:43 +0000 (23:02 +0000)
with file name and line number.

elfcpp/dwarf.h
gold/Makefile.am
gold/Makefile.in
gold/dwarf_reader.cc [new file with mode: 0644]
gold/dwarf_reader.h [new file with mode: 0644]
gold/object.cc
gold/po/POTFILES.in
gold/po/gold.pot

index 0b98bcc..b60bdbd 100644 (file)
 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
index c9cde9c..a91a1c8 100644 (file)
@@ -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 \
index a7e3f73..9ca3701 100644 (file)
@@ -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 (file)
index 0000000..05809a7
--- /dev/null
@@ -0,0 +1,529 @@
+// dwarf_reader.cc -- parse dwarf2/3 debug information
+
+// Copyright 2007 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@google.com>.
+
+// 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<uint64_t>(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<uint64_t>(byte & 0x7f) << shift);
+      shift += 7;
+    }
+  while (byte & 0x80);
+
+  if ((shift < 8 * static_cast<int>(sizeof(result))) && (byte & 0x40))
+    result |= -((static_cast<int64_t>(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<int size, bool big_endian>
+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<const signed char*>(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<int>(directories_.size()));
+          directories_.push_back(reinterpret_cast<const char*>(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<const char*>(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<int>(files_.size()));
+          files_.push_back(std::pair<int, std::string>(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<const char*>(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<int, std::string>(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<Offset_to_lineno_entry>& offsets = line_number_map_[shndx];
+  std::vector<Offset_to_lineno_entry>::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<int>(files_.size()));
+  const std::pair<int, std::string>& filename_pair = files_[it->file_num];
+  gold_assert(filename_pair.first < static_cast<int>(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 (file)
index 0000000..a367715
--- /dev/null
@@ -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 <iant@google.com>.
+
+// 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 <vector>
+
+#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<int size, bool big_endian>
+  void
+  read_line_mappings()
+  {
+    while (buffer_ < buffer_end_)
+      {
+        const unsigned char* lineptr = buffer_;
+        lineptr = this->read_header_prolog<size, big_endian>(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<int size, bool big_endian>
+  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<unsigned char> 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<std::string> directories_;
+  // The first part is an index into directories_, the second the filename.
+  std::vector< std::pair<int, std::string> > 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<unsigned int, std::vector<Offset_to_lineno_entry> >
+  Lineno_map;
+
+  Lineno_map line_number_map_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_DWARF_READER_H)
index 269acc5..58f0db0 100644 (file)
@@ -27,6 +27,7 @@
 #include <cstdarg>
 
 #include "target-select.h"
+#include "dwarf_reader.h"
 #include "layout.h"
 #include "output.h"
 #include "symtab.h"
@@ -844,7 +845,7 @@ Sized_relobj<size, big_endian>::get_symbol_location_info(
       else if (sym.get_st_shndx() == shndx
                && static_cast<off_t>(sym.get_st_value()) <= offset
                && (static_cast<off_t>(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<int size, bool big_endian>
 std::string
 Relocate_info<size, big_endian>::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<size, big_endian>();
+            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<long>(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<long>(offset));
-  ret += buf;
   return ret;
 }
 
index bb32fdf..a78d65d 100644 (file)
@@ -6,6 +6,8 @@ defstd.cc
 defstd.h
 dirsearch.cc
 dirsearch.h
+dwarf_reader.cc
+dwarf_reader.h
 dynobj.cc
 dynobj.h
 ehframe.cc
index 12770a6..d79701c 100644 (file)
@@ -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 <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\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 ""