aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog48
-rw-r--r--gold/Makefile.am2
-rw-r--r--gold/Makefile.in23
-rw-r--r--gold/archive.cc194
-rw-r--r--gold/archive.h31
-rw-r--r--gold/cref.cc253
-rw-r--r--gold/cref.h73
-rw-r--r--gold/dynobj.cc39
-rw-r--r--gold/dynobj.h11
-rw-r--r--gold/main.cc4
-rw-r--r--gold/object.cc67
-rw-r--r--gold/object.h37
-rw-r--r--gold/options.h4
-rw-r--r--gold/symtab.cc53
-rw-r--r--gold/symtab.h10
15 files changed, 780 insertions, 69 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 5901d3d..ce2a4e3 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -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
@@ -212,7 +258,7 @@
* 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_
diff --git a/gold/Makefile.am b/gold/Makefile.am
index 3d1b82a..fd5870a 100644
--- a/gold/Makefile.am
+++ b/gold/Makefile.am
@@ -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 \
diff --git a/gold/Makefile.in b/gold/Makefile.in
index 48ae0ba..242924b 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -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@
diff --git a/gold/archive.cc b/gold/archive.cc
index 737f3e2..8d11797 100644
--- a/gold/archive.cc
+++ b/gold/archive.cc
@@ -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.
diff --git a/gold/archive.h b/gold/archive.h
index c8b05e4..53b8452d8 100644
--- a/gold/archive.h
+++ b/gold/archive.h
@@ -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
index 0000000..ec95f36
--- /dev/null
+++ b/gold/cref.cc
@@ -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
index 0000000..3da5d3a
--- /dev/null
+++ b/gold/cref.h
@@ -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)
diff --git a/gold/dynobj.cc b/gold/dynobj.cc
index a95787d..9247a79 100644
--- a/gold/dynobj.cc
+++ b/gold/dynobj.cc
@@ -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.
diff --git a/gold/dynobj.h b/gold/dynobj.h
index bd5e12d..b5b9bd9 100644
--- a/gold/dynobj.h
+++ b/gold/dynobj.h
@@ -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
diff --git a/gold/main.cc b/gold/main.cc
index 3577283..e10600b 100644
--- a/gold/main.cc
+++ b/gold/main.cc
@@ -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)
diff --git a/gold/object.cc b/gold/object.cc
index 2ecb8a9..d8f5ec8 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -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
diff --git a/gold/object.h b/gold/object.h
index df509b2..7334492 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -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
diff --git a/gold/options.h b/gold/options.h
index 653f5fc..2641d98 100644
--- a/gold/options.h
+++ b/gold/options.h
@@ -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);
diff --git a/gold/symtab.cc b/gold/symtab.cc
index f9bbcc0..03e592e 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -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)
diff --git a/gold/symtab.h b/gold/symtab.h
index 7d99cd5..9afdfe9 100644
--- a/gold/symtab.h
+++ b/gold/symtab.h
@@ -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.