summaryrefslogtreecommitdiff
path: root/linkers/rld-symbols.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'linkers/rld-symbols.cpp')
-rw-r--r--linkers/rld-symbols.cpp389
1 files changed, 389 insertions, 0 deletions
diff --git a/linkers/rld-symbols.cpp b/linkers/rld-symbols.cpp
new file mode 100644
index 0000000..3464017
--- /dev/null
+++ b/linkers/rld-symbols.cpp
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-ld
+ *
+ * @brief RTEMS Linker symbols manages the symbols from all the object files.
+ *
+ */
+
+#include <string.h>
+
+#include <iomanip>
+
+#include <rld.h>
+
+#include <libiberty/demangle.h>
+
+namespace rld
+{
+ namespace symbols
+ {
+ /**
+ * Get the demangled name.
+ */
+ static void
+ denamgle_name (std::string& name, std::string& demangled)
+ {
+ char* demangled_name = ::cplus_demangle (name.c_str (),
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name)
+ {
+ demangled = demangled_name;
+ ::free (demangled_name);
+ }
+ }
+
+ symbol::symbol ()
+ : index_ (-1),
+ object_ (0),
+ references_ (0)
+ {
+ memset (&esym_, 0, sizeof (esym_));
+ }
+
+ symbol::symbol (int index,
+ const std::string& name,
+ files::object& object,
+ const elf::elf_sym& esym)
+ : index_ (index),
+ name_ (name),
+ object_ (&object),
+ esym_ (esym),
+ references_ (0)
+ {
+ if (!object_)
+ throw rld_error_at ("object pointer is 0");
+ if (is_cplusplus ())
+ denamgle_name (name_, demangled_);
+ }
+
+ symbol::symbol (int index,
+ const std::string& name,
+ const elf::elf_sym& esym)
+ : index_ (index),
+ name_ (name),
+ object_ (0),
+ esym_ (esym),
+ references_ (0)
+ {
+ if (is_cplusplus ())
+ denamgle_name (name_, demangled_);
+ }
+
+ symbol::symbol (const std::string& name,
+ const elf::elf_addr value)
+ : index_ (-1),
+ name_ (name),
+ object_ (0),
+ references_ (0)
+ {
+ memset (&esym_, 0, sizeof (esym_));
+ esym_.st_value = value;
+ }
+
+ symbol::symbol (const char* name,
+ const elf::elf_addr value)
+ : index_ (-1),
+ name_ (name),
+ object_ (0),
+ references_ (0)
+ {
+ memset (&esym_, 0, sizeof (esym_));
+ esym_.st_value = value;
+ }
+
+ int
+ symbol::index () const
+ {
+ return index_;
+ }
+
+ const std::string&
+ symbol::name () const
+ {
+ return name_;
+ }
+
+ const std::string&
+ symbol::demangled () const
+ {
+ return demangled_;
+ }
+
+ bool
+ symbol::is_cplusplus () const
+ {
+ return (name_[0] == '_') && (name_[1] == 'Z');
+ }
+
+ int
+ symbol::type () const
+ {
+ return GELF_ST_TYPE (esym_.st_info);
+ }
+
+ int
+ symbol::binding () const
+ {
+ return GELF_ST_BIND (esym_.st_info);
+ }
+
+ int
+ symbol::section_index () const
+ {
+ return esym_.st_shndx;
+ }
+
+ elf::elf_addr
+ symbol::value () const
+ {
+ return esym_.st_value;
+ }
+
+ uint32_t
+ symbol::info () const
+ {
+ return esym_.st_info;
+ }
+
+ rld::files::object*
+ symbol::object () const
+ {
+ return object_;
+ }
+
+ void
+ symbol::set_object (rld::files::object& obj)
+ {
+ object_ = &obj;
+ }
+
+ const elf::elf_sym&
+ symbol::esym () const
+ {
+ return esym_;
+ }
+
+ void
+ symbol::referenced ()
+ {
+ ++references_;
+ if (object_)
+ object_->symbol_referenced ();
+ }
+
+ bool
+ symbol::operator< (const symbol& rhs) const
+ {
+ return name_ < rhs.name_;
+ }
+
+ void
+ symbol::output (std::ostream& out) const
+ {
+ const elf::elf_sym& es = esym ();
+
+ std::string binding;
+ int binding_val = GELF_ST_BIND (es.st_info);
+ switch (binding_val)
+ {
+ case STB_LOCAL:
+ binding = "STB_LOCAL ";
+ break;
+ case STB_GLOBAL:
+ binding = "STB_GLOBAL";
+ break;
+ case STB_WEAK:
+ binding = "STB_WEAK ";
+ break;
+ default:
+ if ((binding_val >= STB_LOPROC) && (binding_val <= STB_HIPROC))
+ binding = "STB_LOPROC(" + rld::to_string (binding_val) + ")";
+ else
+ binding = "STB_INVALID(" + rld::to_string (binding_val) + ")";
+ break;
+ }
+
+ std::string type;
+ int type_val = GELF_ST_TYPE (es.st_info);
+ switch (type_val)
+ {
+ case STT_NOTYPE:
+ type = "STT_NOTYPE ";
+ break;
+ case STT_OBJECT:
+ type = "STT_OBJECT ";
+ break;
+ case STT_FUNC:
+ type = "STT_FUNC ";
+ break;
+ case STT_SECTION:
+ type = "STT_SECTION";
+ break;
+ case STT_FILE:
+ type = "STT_FILE ";
+ break;
+ default:
+ if ((type_val >= STT_LOPROC) && (type_val <= STT_HIPROC))
+ type = "STT_LOPROC(" + rld::to_string (type_val) + ")";
+ else
+ type = "STT_INVALID(" + rld::to_string (type_val) + ")";
+ break;
+ }
+
+ out << std::setw (4) << index_
+ << ' ' << binding
+ << ' ' << type
+ << ' ' << std::setw(6) << es.st_shndx
+ << " 0x" << std::setw (8) << std::setfill ('0') << std::hex
+ << es.st_value
+ << std::dec << std::setfill (' ')
+ << ' ' << std::setw (7) << es.st_size
+ << ' ';
+
+ if (is_cplusplus ())
+ out << demangled ();
+ else
+ out << name ();
+
+ if (object ())
+ out << " (" << object ()->name ().basename () << ')';
+ }
+
+ table::table ()
+ {
+ }
+
+ table::~table ()
+ {
+ }
+
+ void
+ table::add_external (symbol& sym)
+ {
+ _externals[sym.name ()] = &sym;
+ }
+
+ void
+ table::add_weak (symbol& sym)
+ {
+ _weaks[sym.name ()] = &sym;
+ }
+
+ symbol*
+ table::find_external (const std::string& name)
+ {
+ symtab::iterator sti = _externals.find (name);
+ if (sti == _externals.end ())
+ return 0;
+ return (*sti).second;
+ }
+
+ symbol*
+ table::find_weak (const std::string& name)
+ {
+ symtab::iterator sti = _weaks.find (name);
+ if (sti == _weaks.end ())
+ return 0;
+ return (*sti).second;
+ }
+
+ size_t
+ table::size () const
+ {
+ return _externals.size () + _weaks.size ();
+ }
+
+ const symtab&
+ table::externals () const
+ {
+ return _externals;
+ }
+
+ const symtab&
+ table::weaks () const
+ {
+ return _weaks;
+ }
+
+ void
+ load (bucket& bucket_, table& table_)
+ {
+ for (bucket::iterator sbi = bucket_.begin ();
+ sbi != bucket_.end ();
+ ++sbi)
+ {
+ table_.add_external (*sbi);
+ }
+ }
+
+ void
+ load (bucket& bucket_, symtab& table_)
+ {
+ for (bucket::iterator sbi = bucket_.begin ();
+ sbi != bucket_.end ();
+ ++sbi)
+ {
+ symbol& sym = *sbi;
+ table_[sym.name ()] = &sym;
+ }
+ }
+
+ size_t
+ referenced (pointers& symbols)
+ {
+ size_t used = 0;
+ for (pointers::iterator sli = symbols.begin ();
+ sli != symbols.end ();
+ ++sli)
+ {
+ symbol& sym = *(*sli);
+ if (sym.references ())
+ ++used;
+ }
+
+ return used;
+ }
+
+ void
+ output (std::ostream& out, const table& symbols)
+ {
+ out << "Externals:" << std::endl;
+ output (out, symbols.externals ());
+ out << "Weaks:" << std::endl;
+ output (out, symbols.weaks ());
+ }
+
+ void
+ output (std::ostream& out, const symtab& symbols)
+ {
+ std::cout << " No. Scope Type Address Size Name" << std::endl;
+ int index = 0;
+ for (symtab::const_iterator si = symbols.begin ();
+ si != symbols.end ();
+ ++si)
+ {
+ const symbol& sym = *((*si).second);
+ out << std::setw (5) << index << ' ' << sym << std::endl;
+ ++index;
+ }
+ }
+
+ }
+}