* 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 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_
common.cc \
compressed_output.cc \
copy-relocs.cc \
+ cref.cc \
defstd.cc \
dirsearch.cc \
dynobj.cc \
common.h \
compressed_output.h \
copy-relocs.h \
+ cref.h \
defstd.h \
dirsearch.h \
dynobj.h \
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)
common.cc \
compressed_output.cc \
copy-relocs.cc \
+ cref.cc \
defstd.cc \
dirsearch.cc \
dynobj.cc \
common.h \
compressed_output.h \
copy-relocs.h \
+ cref.h \
defstd.h \
dirsearch.h \
dynobj.h \
@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@
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)
{
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
}
}
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.
// 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();
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();
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&);
// 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
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
{
--- /dev/null
+// 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.
--- /dev/null
+// 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)
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)
{
}
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,
? NULL
: sd->versym->data()),
sd->versym_size,
- &version_map);
+ &version_map,
+ this->symbols_,
+ &this->defined_count_);
delete sd->symbols;
sd->symbols = NULL;
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.
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>&);
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;
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
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)
#include "layout.h"
#include "output.h"
#include "symtab.h"
+#include "cref.h"
#include "reloc.h"
#include "object.h"
#include "dynobj.h"
output_local_symbol_count_(0),
output_local_dynsym_count_(0),
symbols_(),
+ defined_count_(0),
local_symbol_offset_(0),
local_dynsym_offset_(0),
local_values_(),
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;
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
}
}
+ // 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;
}
}
}
+// 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
class General_options;
class Task;
+class Cref;
+class Archive;
class Layout;
class Output_section;
class Output_file;
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
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()
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
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.
{
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.
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
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
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
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);
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());
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();
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
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());
{
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
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)
&& 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);
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
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
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
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
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
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
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
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)
// 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.
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.