* cref.cc: New file.
authorIan Lance Taylor <ian@airs.com>
Tue, 22 Jul 2008 22:08:43 +0000 (22:08 +0000)
committerIan Lance Taylor <ian@airs.com>
Tue, 22 Jul 2008 22:08:43 +0000 (22:08 +0000)
* cref.h: New file.
* options.h (class General_options): Add --print-symbol-counts.
* main.cc (main): Issue defined symbol report if requested.
* archive.cc (Archive::interpret_header): Make into a const member
function.
(Archive::add_symbols): Call Input_objects::archive_start and
archive_stop.
(Archive::const_iterator): Define new class.
(Archive::begin, Archive::end): New functions.
(Archive::include_all_members): Rewrite to use iterator.
(Archive::count_members): New function.
* archive.h (class Archive): Update declarations.
(Archive::filename): New function.
* object.cc: Include "cref.h".
(Sized_relobj::Sized_relobj): Initialize defined_count_.
(Sized_relobj::do_get_global_symbol_counts): New function.
(Input_objects::add_object): Add object to cross-referencer.
(Input_objects::archive_start): New function.
(Input_objects::archive_stop): New function.
(Input_objects::print_symbol_counts): New function.
* object.h: Declare Cref and Archive.
(Object::get_global_symbol_counts): New function.
(Object::do_get_global_symbol_counts): New pure virtual function.
(class Sized_relobj): Add defined_count_ field.  Update
declarations.
(class Input_objects): Add cref_ field.  Update constructor.
Update declarations.
* dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize symbols_ and
defined_count_.
(Sized_dynobj::do_add_symbols): Allocate symbols_ if printing
symbol counts.
(Sized_dynobj::do_get_global_symbol_counts): New function.
* dynobj.h (class Sized_dynobj): Add fields symbols_ and
defined_count_.  Update declarations.  Define Symbols typedef.
* symtab.cc (Symbol_table::add_from_relobj): Add defined
parameter.  Change all callers.
(Symbol_table::add_from_dynobj): Add sympointers and defined
parameters.  Change all callers.
* symtab.h (class Symbol_table): Update declarations.
* Makefile.am (CCFILES): Add cref.cc.
(HFILES): Add cref.h.
* Makefile.in: Rebuild.

15 files changed:
gold/ChangeLog
gold/Makefile.am
gold/Makefile.in
gold/archive.cc
gold/archive.h
gold/cref.cc [new file with mode: 0644]
gold/cref.h [new file with mode: 0644]
gold/dynobj.cc
gold/dynobj.h
gold/main.cc
gold/object.cc
gold/object.h
gold/options.h
gold/symtab.cc
gold/symtab.h

index 5901d3d18f683fbb0e944f9933bf3de9a980e8f3..ce2a4e316c8ef7b2192ffd839577d292aa882c11 100644 (file)
@@ -1,3 +1,49 @@
+2008-07-22  Ian Lance Taylor  <iant@google.com>
+
+       * cref.cc: New file.
+       * cref.h: New file.
+       * options.h (class General_options): Add --print-symbol-counts.
+       * main.cc (main): Issue defined symbol report if requested.
+       * archive.cc (Archive::interpret_header): Make into a const member
+       function.
+       (Archive::add_symbols): Call Input_objects::archive_start and
+       archive_stop.
+       (Archive::const_iterator): Define new class.
+       (Archive::begin, Archive::end): New functions.
+       (Archive::include_all_members): Rewrite to use iterator.
+       (Archive::count_members): New function.
+       * archive.h (class Archive): Update declarations.
+       (Archive::filename): New function.
+       * object.cc: Include "cref.h".
+       (Sized_relobj::Sized_relobj): Initialize defined_count_.
+       (Sized_relobj::do_get_global_symbol_counts): New function.
+       (Input_objects::add_object): Add object to cross-referencer.
+       (Input_objects::archive_start): New function.
+       (Input_objects::archive_stop): New function.
+       (Input_objects::print_symbol_counts): New function.
+       * object.h: Declare Cref and Archive.
+       (Object::get_global_symbol_counts): New function.
+       (Object::do_get_global_symbol_counts): New pure virtual function.
+       (class Sized_relobj): Add defined_count_ field.  Update
+       declarations.
+       (class Input_objects): Add cref_ field.  Update constructor.
+       Update declarations.
+       * dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize symbols_ and
+       defined_count_.
+       (Sized_dynobj::do_add_symbols): Allocate symbols_ if printing
+       symbol counts.
+       (Sized_dynobj::do_get_global_symbol_counts): New function.
+       * dynobj.h (class Sized_dynobj): Add fields symbols_ and
+       defined_count_.  Update declarations.  Define Symbols typedef.
+       * symtab.cc (Symbol_table::add_from_relobj): Add defined
+       parameter.  Change all callers.
+       (Symbol_table::add_from_dynobj): Add sympointers and defined
+       parameters.  Change all callers.
+       * symtab.h (class Symbol_table): Update declarations.
+       * Makefile.am (CCFILES): Add cref.cc.
+       (HFILES): Add cref.h.
+       * Makefile.in: Rebuild.
+
 2008-07-22  Simon Baldwin  <simonb@google.com>
 
        * symtab.cc (Symbol_table::sized_write_symbol): Set symbol size
 
        * reduced_debug_output.cc: New file.
        * reduced_debug_output.h: New file.
-       * options.h (class General_optoins): Add --strip-debug-non-line.
+       * options.h (class General_options): Add --strip-debug-non-line.
        * options.cc (General_options::finalize): Add strip_debug_non_line
        to the strip heirarchy.
        * layout.h (class Layout): Add debug_abbrev_ and debug_info_
index 3d1b82a04fbc3cdcd8866d44a6baf93ddef819c5..fd5870aefe92e874f8a9fe9f9c507b50023fffff 100644 (file)
@@ -34,6 +34,7 @@ CCFILES = \
        common.cc \
        compressed_output.cc \
        copy-relocs.cc \
+       cref.cc \
        defstd.cc \
        dirsearch.cc \
        dynobj.cc \
@@ -70,6 +71,7 @@ HFILES = \
        common.h \
        compressed_output.h \
        copy-relocs.h \
+       cref.h \
        defstd.h \
        dirsearch.h \
        dynobj.h \
index 48ae0bad4e75e8f812aa4a8d47f5da9cb6327ccf..242924b2880832afb43d564f55edda0166d242f9 100644 (file)
@@ -76,16 +76,16 @@ libgold_a_AR = $(AR) $(ARFLAGS)
 libgold_a_LIBADD =
 am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \
        compressed_output.$(OBJEXT) copy-relocs.$(OBJEXT) \
-       defstd.$(OBJEXT) dirsearch.$(OBJEXT) dynobj.$(OBJEXT) \
-       dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) errors.$(OBJEXT) \
-       expression.$(OBJEXT) fileread.$(OBJEXT) gold.$(OBJEXT) \
-       gold-threads.$(OBJEXT) layout.$(OBJEXT) mapfile.$(OBJEXT) \
-       merge.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
-       output.$(OBJEXT) parameters.$(OBJEXT) readsyms.$(OBJEXT) \
-       reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \
-       resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \
-       stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \
-       version.$(OBJEXT) workqueue.$(OBJEXT) \
+       cref.$(OBJEXT) defstd.$(OBJEXT) dirsearch.$(OBJEXT) \
+       dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) \
+       errors.$(OBJEXT) expression.$(OBJEXT) fileread.$(OBJEXT) \
+       gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \
+       mapfile.$(OBJEXT) merge.$(OBJEXT) object.$(OBJEXT) \
+       options.$(OBJEXT) output.$(OBJEXT) parameters.$(OBJEXT) \
+       readsyms.$(OBJEXT) reduced_debug_output.$(OBJEXT) \
+       reloc.$(OBJEXT) resolve.$(OBJEXT) script-sections.$(OBJEXT) \
+       script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \
+       target-select.$(OBJEXT) version.$(OBJEXT) workqueue.$(OBJEXT) \
        workqueue-threads.$(OBJEXT)
 am__objects_2 =
 am__objects_3 = yyscript.$(OBJEXT)
@@ -316,6 +316,7 @@ CCFILES = \
        common.cc \
        compressed_output.cc \
        copy-relocs.cc \
+       cref.cc \
        defstd.cc \
        dirsearch.cc \
        dynobj.cc \
@@ -352,6 +353,7 @@ HFILES = \
        common.h \
        compressed_output.h \
        copy-relocs.h \
+       cref.h \
        defstd.h \
        dirsearch.h \
        dynobj.h \
@@ -524,6 +526,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compressed_output.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy-relocs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cref.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@
index 737f3e21729141f49dbaa807a0c96e5b2d647ca9..8d11797defa726e9de4f3d41bfed6e93e9e62cf2 100644 (file)
@@ -191,7 +191,7 @@ Archive::read_header(off_t off, bool cache, std::string* pname,
 
 off_t
 Archive::interpret_header(const Archive_header* hdr, off_t off,
-                          std::string* pname, off_t* nested_off)
+                          std::string* pname, off_t* nested_off) const
 {
   if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0)
     {
@@ -293,6 +293,8 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout,
     return this->include_all_members(symtab, layout, input_objects,
                                     mapfile);
 
+  input_objects->archive_start(this);
+
   const size_t armap_size = this->armap_.size();
 
   // This is a quick optimization, since we usually see many symbols
@@ -359,56 +361,170 @@ Archive::add_symbols(Symbol_table* symtab, Layout* layout,
        }
     }
   while (added_new_object);
+
+  input_objects->archive_stop(this);
 }
 
-// Include all the archive members in the link.  This is for --whole-archive.
+// An archive member iterator.
+
+class Archive::const_iterator
+{
+ public:
+  // The header of an archive member.  This is what this iterator
+  // points to.
+  struct Header
+  {
+    // The name of the member.
+    std::string name;
+    // The file offset of the member.
+    off_t off;
+    // The file offset of a nested archive member.
+    off_t nested_off;
+    // The size of the member.
+    off_t size;
+  };
+
+  const_iterator(const Archive* archive, off_t off)
+    : archive_(archive), off_(off)
+  { this->read_next_header(); }
+
+  const Header&
+  operator*() const
+  { return this->header_; }
+
+  const Header*
+  operator->() const
+  { return &this->header_; }
+
+  const_iterator&
+  operator++()
+  {
+    if (this->off_ == this->archive_->file().filesize())
+      return *this;
+    this->off_ += sizeof(Archive_header);
+    if (!this->archive_->is_thin_archive())
+      this->off_ += this->header_.size;
+    if ((this->off_ & 1) != 0)
+      ++this->off_;
+    this->read_next_header();
+    return *this;
+  }
+
+  const_iterator
+  operator++(int)
+  {
+    const_iterator ret = *this;
+    ++*this;
+    return ret;
+  }
+
+  bool
+  operator==(const const_iterator p) const
+  { return this->off_ == p->off; }
+
+  bool
+  operator!=(const const_iterator p) const
+  { return this->off_ != p->off; }
+
+ private:
+  void
+  read_next_header();
+
+  // The underlying archive.
+  const Archive* archive_;
+  // The current offset in the file.
+  off_t off_;
+  // The current archive header.
+  Header header_;
+};
+
+// Read the next archive header.
 
 void
-Archive::include_all_members(Symbol_table* symtab, Layout* layout,
-                             Input_objects* input_objects, Mapfile* mapfile)
+Archive::const_iterator::read_next_header()
 {
-  off_t off = sarmag;
-  off_t filesize = this->input_file_->file().filesize();
+  off_t filesize = this->archive_->file().filesize();
   while (true)
     {
-      if (filesize - off < static_cast<off_t>(sizeof(Archive_header)))
-        {
-          if (filesize != off)
-           gold_error(_("%s: short archive header at %zu"),
-                      this->name().c_str(), static_cast<size_t>(off));
-          break;
-        }
+      if (filesize - this->off_ < static_cast<off_t>(sizeof(Archive_header)))
+       {
+         if (filesize != this->off_)
+           {
+             gold_error(_("%s: short archive header at %zu"),
+                        this->archive_->filename().c_str(),
+                        static_cast<size_t>(this->off_));
+             this->off_ = filesize;
+           }
+         this->header_.off = filesize;
+         return;
+       }
 
-      unsigned char hdr_buf[sizeof(Archive_header)];
-      this->input_file_->file().read(off, sizeof(Archive_header), hdr_buf);
+      unsigned char buf[sizeof(Archive_header)];
+      this->archive_->file().read(this->off_, sizeof(Archive_header), buf);
 
-      const Archive_header* hdr =
-       reinterpret_cast<const Archive_header*>(hdr_buf);
-      std::string name;
-      off_t size = this->interpret_header(hdr, off, &name, NULL);
-      bool special_member = false;
-      if (name.empty())
-        {
-          // Symbol table.
-          special_member = true;
-        }
-      else if (name == "/")
-        {
-          // Extended name table.
-          special_member = true;
-        }
-      else
-        this->include_member(symtab, layout, input_objects, off,
-                            mapfile, NULL, "--whole-archive");
-
-      off += sizeof(Archive_header);
-      if (special_member || !this->is_thin_archive_)
-        off += size;
-      if ((off & 1) != 0)
-        ++off;
+      const Archive_header* hdr = reinterpret_cast<const Archive_header*>(buf);
+      this->header_.size =
+       this->archive_->interpret_header(hdr, this->off_, &this->header_.name,
+                                        &this->header_.nested_off);
+      this->header_.off = this->off_;
+
+      // Skip special members.
+      if (!this->header_.name.empty() && this->header_.name != "/")
+       return;
+
+      this->off_ += sizeof(Archive_header) + this->header_.size;
+      if ((this->off_ & 1) != 0)
+       ++this->off_;
     }
 }
 
+// Initial iterator.
+
+Archive::const_iterator
+Archive::begin() const
+{
+  return Archive::const_iterator(this, sarmag);
+}
+
+// Final iterator.
+
+Archive::const_iterator
+Archive::end() const
+{
+  return Archive::const_iterator(this, this->input_file_->file().filesize());
+}
+
+// Include all the archive members in the link.  This is for --whole-archive.
+
+void
+Archive::include_all_members(Symbol_table* symtab, Layout* layout,
+                             Input_objects* input_objects, Mapfile* mapfile)
+{
+  input_objects->archive_start(this);
+
+  for (Archive::const_iterator p = this->begin();
+       p != this->end();
+       ++p)
+    this->include_member(symtab, layout, input_objects, p->off,
+                        mapfile, NULL, "--whole-archive");
+
+  input_objects->archive_stop(this);
+}
+
+// Return the number of members in the archive.  This is only used for
+// reports.
+
+size_t
+Archive::count_members() const
+{
+  size_t ret = 0;
+  for (Archive::const_iterator p = this->begin();
+       p != this->end();
+       ++p)
+    ++ret;
+  return ret;
+}
+
 // Include an archive member in the link.  OFF is the file offset of
 // the member header.  WHY is the reason we are including this member.
 
index c8b05e442da25b853c93412158f381c7bceb1c20..53b8452d81d757297ddf462d063f776731cde8ac 100644 (file)
@@ -62,11 +62,18 @@ class Archive
   // The string expected at the end of an archive member header.
   static const char arfmag[2];
 
-  // The name of the object.
+  // The name of the object.  This is the name used on the command
+  // line; e.g., if "-lgcc" is on the command line, this will be
+  // "gcc".
   const std::string&
   name() const
   { return this->name_; }
 
+  // The file name.
+  const std::string&
+  filename() const
+  { return this->input_file_->filename(); }
+
   // Set up the archive: read the symbol map.
   void
   setup();
@@ -110,6 +117,11 @@ class Archive
   clear_uncached_views()
   { this->input_file_->file().clear_uncached_views(); }
 
+  // Whether this is a thin archive.
+  bool
+  is_thin_archive() const
+  { return this->is_thin_archive_; }
+
   // Unlock any nested archives.
   void
   unlock_nested_archives();
@@ -119,6 +131,10 @@ class Archive
   void
   add_symbols(Symbol_table*, Layout*, Input_objects*, Mapfile*);
 
+  // Return the number of members in the archive.
+  size_t
+  count_members() const;
+
  private:
   Archive(const Archive&);
   Archive& operator=(const Archive&);
@@ -144,7 +160,7 @@ class Archive
   // member, and set *PNAME to the name.
   off_t
   interpret_header(const Archive_header* hdr, off_t off, std::string* pname,
-                   off_t* nested_off);
+                   off_t* nested_off) const;
 
   // Include all the archive members in the link.
   void
@@ -155,6 +171,17 @@ class Archive
   include_member(Symbol_table*, Layout*, Input_objects*, off_t off,
                 Mapfile*, Symbol*, const char* why);
 
+  // Iterate over archive members.
+  class const_iterator;
+
+  const_iterator
+  begin() const;
+
+  const_iterator
+  end() const;
+
+  friend class const_iterator;
+
   // An entry in the archive map of symbols to object files.
   struct Armap_entry
   {
diff --git a/gold/cref.cc b/gold/cref.cc
new file mode 100644 (file)
index 0000000..ec95f36
--- /dev/null
@@ -0,0 +1,253 @@
+// cref.cc -- cross reference for gold
+
+// Copyright 2008 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 <cerrno>
+#include <cstdio>
+#include <cstring>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "object.h"
+#include "archive.h"
+#include "cref.h"
+
+namespace gold
+{
+
+// Class Cref_inputs.  This is used to hold the list of input files
+// for cross referencing.
+
+class Cref_inputs
+{
+ public:
+  Cref_inputs()
+    : objects_(), archives_(), current_(&this->objects_)
+  { }
+
+  // Add an input object file.
+  void
+  add_object(Object* object);
+
+  // Start adding an archive.  We support nested archives for future
+  // flexibility.
+  void
+  add_archive_start(Archive*);
+
+  // Finish adding an archive.
+  void
+  add_archive_stop(Archive*);
+
+  // Report symbol counts.
+  void
+  print_symbol_counts(const Symbol_table*, FILE*) const;
+
+ private:
+  // A list of input objects.
+  typedef std::vector<Object*> Objects;
+
+  // Information we record for an archive.
+  struct Archive_info
+  {
+    // Archive name.
+    std::string name;
+    // List of objects included from the archive.
+    Objects* objects;
+    // Number of archive members.
+    size_t member_count;
+  };
+
+  // A mapping from the name of an archive to the list of objects in
+  // that archive.
+  typedef std::map<std::string, Archive_info> Archives;
+
+  // Report symbol counts for a list of Objects.
+  void
+  print_objects_symbol_counts(const Symbol_table*, FILE*, const Objects*) const;
+
+  // Report symbol counts for an object.
+  void
+  print_object_symbol_counts(const Symbol_table*, FILE*, const Object*) const;
+
+  // List of input objects.
+  Objects objects_;
+  // List of input archives.  This is a mapping from the archive file
+  // name to the list of objects.
+  Archives archives_;
+  // The list to which we are currently adding objects.
+  Objects* current_;
+};
+
+// Add an object.
+
+void
+Cref_inputs::add_object(Object* object)
+{
+  this->current_->push_back(object);
+}
+
+// Start adding an archive.
+
+void
+Cref_inputs::add_archive_start(Archive* archive)
+{
+  gold_assert(this->current_ == &this->objects_);
+  if (this->archives_.find(archive->name()) == this->archives_.end())
+    {
+      Archive_info* pai = &this->archives_[archive->name()];
+      pai->name = archive->filename();
+      pai->objects = new Objects();
+      pai->member_count = archive->count_members();
+    }
+  this->current_ = this->archives_[archive->name()].objects;
+}
+
+// Stop adding an archive.
+
+void
+Cref_inputs::add_archive_stop(Archive*)
+{
+  gold_assert(this->current_ != &this->objects_);
+  this->current_ = &this->objects_;
+}
+
+// Report symbol counts for an object.
+
+void
+Cref_inputs::print_object_symbol_counts(const Symbol_table* symtab,
+                                       FILE* f,
+                                       const Object* object) const
+{
+  size_t defined, used;
+  object->get_global_symbol_counts(symtab, &defined, &used);
+  fprintf(f, "symbols %s %zu %zu\n", object->name().c_str(), defined, used);
+}
+
+// Report symbol counts for a list of Inputs.
+
+void
+Cref_inputs::print_objects_symbol_counts(const Symbol_table* symtab,
+                                        FILE* f,
+                                        const Objects* objects) const
+{
+  for (Objects::const_iterator p = objects->begin();
+       p != objects->end();
+       ++p)
+    this->print_object_symbol_counts(symtab, f, *p);
+}
+
+// Print symbol counts.  This implements --print-symbol-counts.  This
+// is intended to be easily read by a program.  This outputs a series
+// of lines.  There are two different types of lines.
+
+// The first is "symbols FILENAME DEFINED USED".  FILENAME is the name
+// of an object file included in the link; for an archive, this will
+// be ARCHIVEFILENAME(MEMBERNAME).  DEFINED is the number of symbols
+// which the object file defines.  USED is the number of symbols which
+// are used in the final output; this is the number of symbols which
+// appear in the final output table as having been defined by this
+// object.  These numbers will be different when weak symbols are
+// used, and they will be different for dynamic objects.
+
+// The second is "archives FILENAME MEMBERS USED".  FILENAME is the
+// name of an archive file included in the link.  MEMBERS is the
+// number of members of the archive.  USED is the number of archive
+// members included in the link.
+
+void
+Cref_inputs::print_symbol_counts(const Symbol_table* symtab, FILE* f) const
+{
+  this->print_objects_symbol_counts(symtab, f, &this->objects_);
+  for (Archives::const_iterator p = this->archives_.begin();
+       p != this->archives_.end();
+       ++p)
+    {
+      fprintf(f, "archive %s %zu %zu\n", p->second.name.c_str(),
+            p->second.member_count, p->second.objects->size());
+      this->print_objects_symbol_counts(symtab, f, p->second.objects);
+    }
+}
+
+// Class Cref.
+
+// Make sure the Cref_inputs object has been created.
+
+void
+Cref::need_inputs()
+{
+  if (this->inputs_ == NULL)
+    this->inputs_ = new Cref_inputs();
+}
+
+// Add an input object file.
+
+void
+Cref::add_object(Object* object)
+{
+  this->need_inputs();
+  this->inputs_->add_object(object);
+}
+
+// Start adding an archive.
+
+void
+Cref::add_archive_start(Archive* archive)
+{
+  this->need_inputs();
+  this->inputs_->add_archive_start(archive);
+}
+
+// Stop adding an archive.
+
+void
+Cref::add_archive_stop(Archive* archive)
+{
+  this->inputs_->add_archive_stop(archive);
+}
+
+// Print symbol counts.
+
+void
+Cref::print_symbol_counts(const Symbol_table* symtab) const
+{
+  if (parameters->options().user_set_print_symbol_counts()
+      && this->inputs_ != NULL)
+    {
+      FILE* f;
+      if (strcmp(parameters->options().print_symbol_counts(), "-") == 0)
+       f = stdout;
+      else
+       {
+         f = fopen(parameters->options().print_symbol_counts(), "w");
+         if (f == NULL)
+           gold_error(_("cannot open symbol count file %s: %s"),
+                      parameters->options().print_symbol_counts(),
+                      strerror(errno));
+       }
+      if (f != NULL)
+       this->inputs_->print_symbol_counts(symtab, f);
+    }
+}
+
+} // End namespace gold.
diff --git a/gold/cref.h b/gold/cref.h
new file mode 100644 (file)
index 0000000..3da5d3a
--- /dev/null
@@ -0,0 +1,73 @@
+// cref.h -- cross reference reports for gold   -*- C++ -*-
+
+// Copyright 2008 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_CREF_H
+#define GOLD_CREF_H
+
+namespace gold
+{
+
+class Object;
+class Archive;
+class Cref_inputs;
+
+// This class collects data for cross reference and other reporting.
+
+class Cref
+{
+ public:
+  Cref()
+    : inputs_(NULL)
+  { }
+
+  // Record an input object file.  This is called for each object file
+  // in the order in which it is processed.
+  void
+  add_object(Object*);
+
+  // Start recording an input archive.  This is called for each
+  // archive in the order in which it appears on the command line.  A
+  // call to add_archive_start precedes calls to add_object for each
+  // object included from the archive.
+  void
+  add_archive_start(Archive*);
+
+  // Finish recording an input archive.  This is called after
+  // add_object has been called for each object included from the
+  // archive.
+  void
+  add_archive_stop(Archive*);
+
+  // Print symbol counts.
+  void
+  print_symbol_counts(const Symbol_table*) const;
+
+ private:
+  void
+  need_inputs();
+
+  Cref_inputs* inputs_;
+};
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_CREF_H)
index a95787d9f5bdfbf7154b108d0e7a566638090573..9247a79d7d51484dbef7f32dbae58ae93a2a0f52 100644 (file)
@@ -73,7 +73,9 @@ Sized_dynobj<size, big_endian>::Sized_dynobj(
     const elfcpp::Ehdr<size, big_endian>& ehdr)
   : Dynobj(name, input_file, offset),
     elf_file_(this, ehdr),
-    dynsym_shndx_(-1U)
+    dynsym_shndx_(-1U),
+    symbols_(NULL),
+    defined_count_(0)
 {
 }
 
@@ -675,6 +677,14 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
   Version_map version_map;
   this->make_version_map(sd, &version_map);
 
+  // If printing symbol counts, we want to track symbols.
+  
+  if (parameters->options().user_set_print_symbol_counts())
+    {
+      this->symbols_ = new Symbols();
+      this->symbols_->resize(symcount);
+    }
+
   const char* sym_names =
     reinterpret_cast<const char*>(sd->symbol_names->data());
   symtab->add_from_dynobj(this, sd->symbols->data(), symcount,
@@ -683,7 +693,9 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
                           ? NULL
                           : sd->versym->data()),
                          sd->versym_size,
-                         &version_map);
+                         &version_map,
+                         this->symbols_,
+                         &this->defined_count_);
 
   delete sd->symbols;
   sd->symbols = NULL;
@@ -710,6 +722,29 @@ Sized_dynobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
   this->clear_view_cache_marks();
 }
 
+// Get symbol counts.
+
+template<int size, bool big_endian>
+void
+Sized_dynobj<size, big_endian>::do_get_global_symbol_counts(
+    const Symbol_table*,
+    size_t* defined,
+    size_t* used) const
+{
+  *defined = this->defined_count_;
+  size_t count = 0;
+  for (typename Symbols::const_iterator p = this->symbols_->begin();
+       p != this->symbols_->end();
+       ++p)
+    if (*p != NULL
+       && (*p)->source() == Symbol::FROM_OBJECT
+       && (*p)->object() == this
+       && (*p)->is_defined()
+       && (*p)->dynsym_index() != -1U)
+      ++count;
+  *used = count;
+}
+
 // Given a vector of hash codes, compute the number of hash buckets to
 // use.
 
index bd5e12dc5e1bacc72192b2c6c05bf757a3611f74..b5b9bd9725dd6113e60d81cbeeb249e6149d30ba 100644 (file)
@@ -156,6 +156,8 @@ template<int size, bool big_endian>
 class Sized_dynobj : public Dynobj
 {
  public:
+  typedef typename Sized_relobj<size, big_endian>::Symbols Symbols;
+
   Sized_dynobj(const std::string& name, Input_file* input_file, off_t offset,
               const typename elfcpp::Ehdr<size, big_endian>&);
 
@@ -225,6 +227,10 @@ class Sized_dynobj : public Dynobj
   Xindex*
   do_initialize_xindex();
 
+  // Get symbol counts.
+  void
+  do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const;
+
  private:
   // For convenience.
   typedef Sized_dynobj<size, big_endian> This;
@@ -288,6 +294,11 @@ class Sized_dynobj : public Dynobj
   elfcpp::Elf_file<size, big_endian, Object> elf_file_;
   // The section index of the dynamic symbol table.
   unsigned int dynsym_shndx_;
+  // The entries in the symbol table for the symbols.  We only keep
+  // this if we need it to print symbol information.
+  Symbols* symbols_;
+  // Number of defined symbols.
+  size_t defined_count_;
 };
 
 // A base class for Verdef and Verneed_version which just handles the
index 35772839e4fe9e5a3e820d6cf2610c57dd354b67..e10600b195da3650f7eac2775eff8288e022422e 100644 (file)
@@ -237,6 +237,10 @@ main(int argc, char** argv)
   if (mapfile != NULL)
     mapfile->close();
 
+  // Issue defined symbol report.
+  if (command_line.options().user_set_print_symbol_counts())
+    input_objects.print_symbol_counts(&symtab);
+
   if (parameters->options().fatal_warnings()
       && errors.warning_count() > 0
       && errors.error_count() == 0)
index 2ecb8a9e915e93062fe01f944be5b34851df9ce4..d8f5ec8027492d2178404413e4f352d7b8dd05fc 100644 (file)
@@ -33,6 +33,7 @@
 #include "layout.h"
 #include "output.h"
 #include "symtab.h"
+#include "cref.h"
 #include "reloc.h"
 #include "object.h"
 #include "dynobj.h"
@@ -245,6 +246,7 @@ Sized_relobj<size, big_endian>::Sized_relobj(
     output_local_symbol_count_(0),
     output_local_dynsym_count_(0),
     symbols_(),
+    defined_count_(0),
     local_symbol_offset_(0),
     local_dynsym_offset_(0),
     local_values_(),
@@ -1087,7 +1089,8 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
                          sd->symbols->data() + sd->external_symbols_offset,
                          symcount, this->local_symbol_count_,
                          sym_names, sd->symbol_names_size,
-                         &this->symbols_);
+                         &this->symbols_,
+                         &this->defined_count_);
 
   delete sd->symbols;
   sd->symbols = NULL;
@@ -1577,6 +1580,28 @@ Sized_relobj<size, big_endian>::map_to_kept_section(
   return 0;
 }
 
+// Get symbol counts.
+
+template<int size, bool big_endian>
+void
+Sized_relobj<size, big_endian>::do_get_global_symbol_counts(
+    const Symbol_table*,
+    size_t* defined,
+    size_t* used) const
+{
+  *defined = this->defined_count_;
+  size_t count = 0;
+  for (Symbols::const_iterator p = this->symbols_.begin();
+       p != this->symbols_.end();
+       ++p)
+    if (*p != NULL
+       && (*p)->source() == Symbol::FROM_OBJECT
+       && (*p)->object() == this
+       && (*p)->is_defined())
+      ++count;
+  *used = count;
+}
+
 // Input_objects methods.
 
 // Add a regular relocatable object to the list.  Return false if this
@@ -1631,6 +1656,14 @@ Input_objects::add_object(Object* obj)
        }
     }
 
+  // Add this object to the cross-referencer if requested.
+  if (parameters->options().user_set_print_symbol_counts())
+    {
+      if (this->cref_ == NULL)
+       this->cref_ = new Cref();
+      this->cref_->add_object(obj);
+    }
+
   return true;
 }
 
@@ -1671,6 +1704,38 @@ Input_objects::check_dynamic_dependencies() const
     }
 }
 
+// Start processing an archive.
+
+void
+Input_objects::archive_start(Archive* archive)
+{
+  if (parameters->options().user_set_print_symbol_counts())
+    {
+      if (this->cref_ == NULL)
+       this->cref_ = new Cref();
+      this->cref_->add_archive_start(archive);
+    }
+}
+
+// Stop processing an archive.
+
+void
+Input_objects::archive_stop(Archive* archive)
+{
+  if (parameters->options().user_set_print_symbol_counts())
+    this->cref_->add_archive_stop(archive);
+}
+
+// Print symbol counts
+
+void
+Input_objects::print_symbol_counts(const Symbol_table* symtab) const
+{
+  if (parameters->options().user_set_print_symbol_counts()
+      && this->cref_ != NULL)
+    this->cref_->print_symbol_counts(symtab);
+}
+
 // Relocate_info methods.
 
 // Return a string describing the location of a relocation.  This is
index df509b23de900d3cf28c127fc1d3bab880e37ac6..7334492fb237a5a1208996a4f546693cc14ab318 100644 (file)
@@ -36,6 +36,8 @@ namespace gold
 
 class General_options;
 class Task;
+class Cref;
+class Archive;
 class Layout;
 class Output_section;
 class Output_file;
@@ -421,6 +423,14 @@ class Object
   clear_view_cache_marks()
   { this->input_file()->file().clear_view_cache_marks(); }
 
+  // Get the number of global symbols defined by this object, and the
+  // number of the symbols whose final definition came from this
+  // object.
+  void
+  get_global_symbol_counts(const Symbol_table* symtab, size_t* defined,
+                          size_t* used) const
+  { this->do_get_global_symbol_counts(symtab, defined, used); }
+
  protected:
   // Read the symbols--implemented by child class.
   virtual void
@@ -476,6 +486,10 @@ class Object
   virtual Xindex*
   do_initialize_xindex() = 0;
 
+  // Implement get_global_symbol_counts--implemented by child class.
+  virtual void
+  do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const = 0;
+
   // Get the file.  We pass on const-ness.
   Input_file*
   input_file()
@@ -1395,6 +1409,10 @@ class Sized_relobj : public Relobj
   Xindex*
   do_initialize_xindex();
 
+  // Get symbol counts.
+  void
+  do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const;
+
   // Get the offset of a section.
   uint64_t
   do_output_section_offset(unsigned int shndx) const
@@ -1628,6 +1646,8 @@ class Sized_relobj : public Relobj
   unsigned int output_local_dynsym_count_;
   // The entries in the symbol table for the external symbols.
   Symbols symbols_;
+  // Number of symbols defined in object file itself.
+  size_t defined_count_;
   // File offset for local symbols.
   off_t local_symbol_offset_;
   // File offset for local dynamic symbols.
@@ -1655,7 +1675,8 @@ class Input_objects
 {
  public:
   Input_objects()
-    : relobj_list_(), dynobj_list_(), sonames_(), system_library_directory_()
+    : relobj_list_(), dynobj_list_(), sonames_(), system_library_directory_(),
+      cref_(NULL)
   { }
 
   // The type of the list of input relocateable objects.
@@ -1671,6 +1692,14 @@ class Input_objects
   bool
   add_object(Object*);
 
+  // Start processing an archive.
+  void
+  archive_start(Archive*);
+
+  // Stop processing an archive.
+  void
+  archive_stop(Archive*);
+
   // For each dynamic object, check whether we've seen all of its
   // explicit dependencies.
   void
@@ -1681,6 +1710,10 @@ class Input_objects
   bool
   found_in_system_library_directory(const Object*) const;
 
+  // Print symbol counts.
+  void
+  print_symbol_counts(const Symbol_table*) const;
+
   // Iterate over all regular objects.
 
   Relobj_iterator
@@ -1723,6 +1756,8 @@ class Input_objects
   Unordered_set<std::string> sonames_;
   // The directory in which we find the libc.so.
   std::string system_library_directory_;
+  // Manage cross-references if requested.
+  Cref* cref_;
 };
 
 // Some of the information we pass to the relocation routines.  We
index 653f5fc09d1fef81f866ba8ef6776aab0992d4cc..2641d986ef4401ec16c8f29e2c4a320f8a162d36 100644 (file)
@@ -679,6 +679,10 @@ class General_options
   DEFINE_string(oformat, options::EXACTLY_TWO_DASHES, '\0', "elf",
                N_("Set output format"), N_("[binary]"));
 
+  DEFINE_string(print_symbol_counts, options::TWO_DASHES, '\0', NULL,
+               N_("Print symbols defined and used for each input"),
+               N_("FILENAME"));
+
   DEFINE_bool(Qy, options::EXACTLY_ONE_DASH, '\0', false,
              N_("Ignored for SVR4 compatibility"), NULL);
 
index f9bbcc0b2f24333400a36309725b560338666669..03e592e6587e157c4cb99dfb91c4d06a2a6ac557 100644 (file)
@@ -835,8 +835,11 @@ Symbol_table::add_from_relobj(
     size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
-    typename Sized_relobj<size, big_endian>::Symbols* sympointers)
+    typename Sized_relobj<size, big_endian>::Symbols* sympointers,
+    size_t *defined)
 {
+  *defined = 0;
+
   gold_assert(size == relobj->target()->get_size());
   gold_assert(size == parameters->target().get_size());
 
@@ -847,6 +850,8 @@ Symbol_table::add_from_relobj(
   const unsigned char* p = syms;
   for (size_t i = 0; i < count; ++i, p += sym_size)
     {
+      (*sympointers)[i] = NULL;
+
       elfcpp::Sym<size, big_endian> sym(p);
 
       unsigned int st_name = sym.get_st_name();
@@ -867,6 +872,9 @@ Symbol_table::add_from_relobj(
       if (!is_ordinary)
        orig_st_shndx = elfcpp::SHN_UNDEF;
 
+      if (st_shndx != elfcpp::SHN_UNDEF)
+       ++*defined;
+
       // A symbol defined in a section which we are not including must
       // be treated as an undefined symbol.
       if (st_shndx != elfcpp::SHN_UNDEF
@@ -977,8 +985,12 @@ Symbol_table::add_from_dynobj(
     size_t sym_name_size,
     const unsigned char* versym,
     size_t versym_size,
-    const std::vector<const char*>* version_map)
+    const std::vector<const char*>* version_map,
+    typename Sized_relobj<size, big_endian>::Symbols* sympointers,
+    size_t* defined)
 {
+  *defined = 0;
+
   gold_assert(size == dynobj->target()->get_size());
   gold_assert(size == parameters->target().get_size());
 
@@ -1012,6 +1024,9 @@ Symbol_table::add_from_dynobj(
     {
       elfcpp::Sym<size, big_endian> sym(p);
 
+      if (sympointers != NULL)
+       (*sympointers)[i] = NULL;
+
       // Ignore symbols with local binding or that have
       // internal or hidden visibility.
       if (sym.get_st_bind() == elfcpp::STB_LOCAL
@@ -1047,6 +1062,9 @@ Symbol_table::add_from_dynobj(
       unsigned int st_shndx = dynobj->adjust_sym_shndx(i, psym->get_st_shndx(),
                                                       &is_ordinary);
 
+      if (st_shndx != elfcpp::SHN_UNDEF)
+       ++*defined;
+
       Sized_symbol<size>* res;
 
       if (versym == NULL)
@@ -1142,6 +1160,9 @@ Symbol_table::add_from_dynobj(
          && res->source() == Symbol::FROM_OBJECT
          && res->object() == dynobj)
        object_symbols.push_back(res);
+
+      if (sympointers != NULL)
+       (*sympointers)[i] = res;
     }
 
   this->record_weak_aliases(&object_symbols);
@@ -2628,7 +2649,8 @@ Symbol_table::add_from_relobj<32, false>(
     size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
-    Sized_relobj<32, true>::Symbols* sympointers);
+    Sized_relobj<32, true>::Symbols* sympointers,
+    size_t* defined);
 #endif
 
 #ifdef HAVE_TARGET_32_BIG
@@ -2641,7 +2663,8 @@ Symbol_table::add_from_relobj<32, true>(
     size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
-    Sized_relobj<32, false>::Symbols* sympointers);
+    Sized_relobj<32, false>::Symbols* sympointers,
+    size_t* defined);
 #endif
 
 #ifdef HAVE_TARGET_64_LITTLE
@@ -2654,7 +2677,8 @@ Symbol_table::add_from_relobj<64, false>(
     size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
-    Sized_relobj<64, true>::Symbols* sympointers);
+    Sized_relobj<64, true>::Symbols* sympointers,
+    size_t* defined);
 #endif
 
 #ifdef HAVE_TARGET_64_BIG
@@ -2667,7 +2691,8 @@ Symbol_table::add_from_relobj<64, true>(
     size_t symndx_offset,
     const char* sym_names,
     size_t sym_name_size,
-    Sized_relobj<64, false>::Symbols* sympointers);
+    Sized_relobj<64, false>::Symbols* sympointers,
+    size_t* defined);
 #endif
 
 #ifdef HAVE_TARGET_32_LITTLE
@@ -2681,7 +2706,9 @@ Symbol_table::add_from_dynobj<32, false>(
     size_t sym_name_size,
     const unsigned char* versym,
     size_t versym_size,
-    const std::vector<const char*>* version_map);
+    const std::vector<const char*>* version_map,
+    Sized_relobj<32, false>::Symbols* sympointers,
+    size_t* defined);
 #endif
 
 #ifdef HAVE_TARGET_32_BIG
@@ -2695,7 +2722,9 @@ Symbol_table::add_from_dynobj<32, true>(
     size_t sym_name_size,
     const unsigned char* versym,
     size_t versym_size,
-    const std::vector<const char*>* version_map);
+    const std::vector<const char*>* version_map,
+    Sized_relobj<32, true>::Symbols* sympointers,
+    size_t* defined);
 #endif
 
 #ifdef HAVE_TARGET_64_LITTLE
@@ -2709,7 +2738,9 @@ Symbol_table::add_from_dynobj<64, false>(
     size_t sym_name_size,
     const unsigned char* versym,
     size_t versym_size,
-    const std::vector<const char*>* version_map);
+    const std::vector<const char*>* version_map,
+    Sized_relobj<64, false>::Symbols* sympointers,
+    size_t* defined);
 #endif
 
 #ifdef HAVE_TARGET_64_BIG
@@ -2723,7 +2754,9 @@ Symbol_table::add_from_dynobj<64, true>(
     size_t sym_name_size,
     const unsigned char* versym,
     size_t versym_size,
-    const std::vector<const char*>* version_map);
+    const std::vector<const char*>* version_map,
+    Sized_relobj<64, true>::Symbols* sympointers,
+    size_t* defined);
 #endif
 
 #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
index 7d99cd52bb61303d002ad5760ee73d119beaefde..9afdfe92996bcbde8e2779fe67ca17e57fd8b21f 100644 (file)
@@ -1086,14 +1086,16 @@ class Symbol_table
   // the symbol table.  SYMS is the symbols, SYMNDX_OFFSET is the
   // offset in the symbol table of the first symbol, SYM_NAMES is
   // their names, SYM_NAME_SIZE is the size of SYM_NAMES.  This sets
-  // SYMPOINTERS to point to the symbols in the symbol table.
+  // SYMPOINTERS to point to the symbols in the symbol table.  It sets
+  // *DEFINED to the number of defined symbols.
   template<int size, bool big_endian>
   void
   add_from_relobj(Sized_relobj<size, big_endian>* relobj,
                  const unsigned char* syms, size_t count,
                  size_t symndx_offset, const char* sym_names,
                  size_t sym_name_size,
-                 typename Sized_relobj<size, big_endian>::Symbols*);
+                 typename Sized_relobj<size, big_endian>::Symbols*,
+                 size_t* defined);
 
   // Add COUNT dynamic symbols from the dynamic object DYNOBJ to the
   // symbol table.  SYMS is the symbols.  SYM_NAMES is their names.
@@ -1105,7 +1107,9 @@ class Symbol_table
                  const unsigned char* syms, size_t count,
                  const char* sym_names, size_t sym_name_size,
                  const unsigned char* versym, size_t versym_size,
-                 const std::vector<const char*>*);
+                 const std::vector<const char*>*,
+                 typename Sized_relobj<size, big_endian>::Symbols*,
+                 size_t* defined);
 
   // Define a special symbol based on an Output_data.  It is a
   // multiple definition error if this symbol is already defined.