This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

gold patch: --print-symbol-counts


I committed a patch to add a new option to gold:
--print-symbol-counts=FILENAME.  This prints out information about how
many symbols are defined and used by each input file.  This is a first
step toward full cross reference information, and is useful by itself
to analyze a complicated build.

Sample output for hello world:

symbols /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crt1.o 5 5
symbols /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crti.o 2 2
symbols /usr/lib/gcc/i386-redhat-linux/4.1.2/crtbegin.o 1 1
symbols /home/iant/hello+.o 1 1
symbols /usr/lib/gcc/i386-redhat-linux/4.1.2/libstdc++.so 3159 5
symbols /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../libm.so 327 0
symbols /usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc_s.so 94 0
symbols /lib/libc.so.6 2254 2
symbols /lib/ld-linux.so.2 28 0
symbols /usr/lib/gcc/i386-redhat-linux/4.1.2/crtend.o 1 1
symbols /usr/lib/gcc/i386-redhat-linux/4.1.2/../../../crtn.o 0 0
archive /usr/lib/libc_nonshared.a 14 1
symbols /usr/lib/libc_nonshared.a(elf-init.oS) 3 3
archive /usr/lib/gcc/i386-redhat-linux/4.1.2/libgcc.a 73 0

The "symbols" lines show symbols defined by the file and symbols used
from the file.  The "archive" lines show number of members in the
archive and numbers of members included.

Ian


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.


Index: Makefile.am
===================================================================
RCS file: /cvs/src/src/gold/Makefile.am,v
retrieving revision 1.39
diff -p -u -r1.39 Makefile.am
--- Makefile.am	21 Jul 2008 05:55:27 -0000	1.39
+++ Makefile.am	22 Jul 2008 22:05:54 -0000
@@ -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: archive.cc
===================================================================
RCS file: /cvs/src/src/gold/archive.cc,v
retrieving revision 1.32
diff -p -u -r1.32 archive.cc
--- archive.cc	30 May 2008 21:24:43 -0000	1.32
+++ archive.cc	22 Jul 2008 22:05:54 -0000
@@ -191,7 +191,7 @@ Archive::read_header(off_t off, bool cac
 
 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* symta
     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* symta
 	}
     }
   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: archive.h
===================================================================
RCS file: /cvs/src/src/gold/archive.h,v
retrieving revision 1.20
diff -p -u -r1.20 archive.h
--- archive.h	21 May 2008 21:37:44 -0000	1.20
+++ archive.h	22 Jul 2008 22:05:54 -0000
@@ -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
   {
Index: cref.cc
===================================================================
RCS file: cref.cc
diff -N cref.cc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cref.cc	22 Jul 2008 22:05:54 -0000
@@ -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.
Index: cref.h
===================================================================
RCS file: cref.h
diff -N cref.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cref.h	22 Jul 2008 22:05:54 -0000
@@ -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: dynobj.cc
===================================================================
RCS file: /cvs/src/src/gold/dynobj.cc,v
retrieving revision 1.39
diff -p -u -r1.39 dynobj.cc
--- dynobj.cc	18 Jul 2008 06:58:04 -0000	1.39
+++ dynobj.cc	22 Jul 2008 22:05:54 -0000
@@ -73,7 +73,9 @@ Sized_dynobj<size, big_endian>::Sized_dy
     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_s
   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_s
 			   ? 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_s
   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: dynobj.h
===================================================================
RCS file: /cvs/src/src/gold/dynobj.h,v
retrieving revision 1.26
diff -p -u -r1.26 dynobj.h
--- dynobj.h	19 Apr 2008 18:30:58 -0000	1.26
+++ dynobj.h	22 Jul 2008 22:05:54 -0000
@@ -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: main.cc
===================================================================
RCS file: /cvs/src/src/gold/main.cc,v
retrieving revision 1.25
diff -p -u -r1.25 main.cc
--- main.cc	21 May 2008 21:37:44 -0000	1.25
+++ main.cc	22 Jul 2008 22:05:54 -0000
@@ -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: object.cc
===================================================================
RCS file: /cvs/src/src/gold/object.cc,v
retrieving revision 1.76
diff -p -u -r1.76 object.cc
--- object.cc	10 Jul 2008 23:01:19 -0000	1.76
+++ object.cc	22 Jul 2008 22:05:54 -0000
@@ -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_re
     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_s
 			  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_k
   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_dependencie
     }
 }
 
+// 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: object.h
===================================================================
RCS file: /cvs/src/src/gold/object.h,v
retrieving revision 1.61
diff -p -u -r1.61 object.h
--- object.h	10 Jul 2008 23:01:19 -0000	1.61
+++ object.h	22 Jul 2008 22:05:54 -0000
@@ -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: options.h
===================================================================
RCS file: /cvs/src/src/gold/options.h,v
retrieving revision 1.80
diff -p -u -r1.80 options.h
--- options.h	28 May 2008 20:48:16 -0000	1.80
+++ options.h	22 Jul 2008 22:05:54 -0000
@@ -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: symtab.cc
===================================================================
RCS file: /cvs/src/src/gold/symtab.cc,v
retrieving revision 1.103
diff -p -u -r1.103 symtab.cc
--- symtab.cc	22 Jul 2008 21:02:44 -0000	1.103
+++ symtab.cc	22 Jul 2008 22:05:54 -0000
@@ -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: symtab.h
===================================================================
RCS file: /cvs/src/src/gold/symtab.h,v
retrieving revision 1.79
diff -p -u -r1.79 symtab.h
--- symtab.h	21 May 2008 21:37:44 -0000	1.79
+++ symtab.h	22 Jul 2008 22:05:54 -0000
@@ -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.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]