[rtems-tools commit] rtemstoolkit: Add DWARF type support.

Chris Johns chrisj at rtems.org
Tue Jun 12 04:13:50 UTC 2018


Module:    rtems-tools
Branch:    dwarf-types
Commit:    2d94207f02c10da8e349eec4755b3aa2a40b2c2a
Changeset: http://git.rtems.org/rtems-tools/commit/?id=2d94207f02c10da8e349eec4755b3aa2a40b2c2a

Author:    Chris Johns <chrisj at rtems.org>
Date:      Fri May 11 06:12:27 2018 +1200

rtemstoolkit: Add DWARF type support.

---

 linkers/rtems-addr2line.cpp                    |   2 +
 linkers/rtems-exeinfo.cpp                      |   2 +
 rtemstoolkit/defaults.mc                       | 122 ++++
 rtemstoolkit/elftoolchain/libdwarf/dwarf_die.c |   5 +-
 rtemstoolkit/rld-dwarf-types.h                 |  36 +-
 rtemstoolkit/rld-dwarf.cpp                     | 797 ++++++++++++++++++++++++-
 rtemstoolkit/rld-dwarf.h                       | 256 +++++++-
 7 files changed, 1196 insertions(+), 24 deletions(-)

diff --git a/linkers/rtems-addr2line.cpp b/linkers/rtems-addr2line.cpp
index 2e79c62..144f117 100644
--- a/linkers/rtems-addr2line.cpp
+++ b/linkers/rtems-addr2line.cpp
@@ -213,6 +213,8 @@ main (int argc, char* argv[])
       exe.begin ();
       debug.begin (exe.elf ());
       debug.load_debug ();
+      debug.load_types ();
+      debug.load_functions ();
 
       for (int arg = 0; arg < argc; ++arg)
       {
diff --git a/linkers/rtems-exeinfo.cpp b/linkers/rtems-exeinfo.cpp
index ef1b653..4fc5f00 100644
--- a/linkers/rtems-exeinfo.cpp
+++ b/linkers/rtems-exeinfo.cpp
@@ -293,6 +293,7 @@ namespace rld
        */
       exe.load_symbols (symbols, true);
       debug.load_debug ();
+      debug.load_types ();
       symbols.globals (addresses);
       symbols.weaks (addresses);
       symbols.locals (addresses);
@@ -321,6 +322,7 @@ namespace rld
                                        "-fno-stack-protector",
                                        "-fbuilding-libgcc",
                                        "-fno-implicit-templates",
+                                       "-fimplicit-templates",
                                        "-ffunction-sections",
                                        "-fdata-sections",
                                        "-frandom-seed=",
diff --git a/rtemstoolkit/defaults.mc b/rtemstoolkit/defaults.mc
new file mode 100644
index 0000000..36996c3
--- /dev/null
+++ b/rtemstoolkit/defaults.mc
@@ -0,0 +1,122 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2015 Chris Johns (chrisj at rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# All paths in defaults must be Unix format. Do not store any Windows format
+# paths in the defaults.
+#
+# Every entry must describe the type of checking a host must pass.
+#
+# Records:
+#  key: type, attribute, value
+#   type     : none, dir, exe, triplet
+#   attribute: none, required, optional
+#   value    : 'single line', '''multi line'''
+#
+
+#
+# Global defaults
+#
+[global]
+
+# Nothing
+nil:                 none,    none,     ''
+
+# Paths
+_topdir:             dir,     required, '%{_prefix}'
+_docdir:             dir,     none,     '%{_defaultdocdir}'
+_tmppath:            dir,     none,     '%{_topdir}/build/tmp'
+_tmproot:            dir,     none,     '%{_tmppath}/rt/%{_bset}'
+_datadir:            dir,     none,     '%{_prefix}/share'
+_defaultdocdir:      dir,     none,     '%{_prefix}/share/doc'
+_exeext:             none,    none,     ''
+_exec_prefix:        dir,     none,     '%{_prefix}'
+_bindir:             dir,     none,     '%{_exec_prefix}/bin'
+_sbindir:            dir,     none,     '%{_exec_prefix}/sbin'
+_libexecdir:         dir,     none,     '%{_exec_prefix}/libexec'
+_datarootdir:        dir,     none,     '%{_prefix}/share'
+_datadir:            dir,     none,     '%{_datarootdir}'
+_sysconfdir:         dir,     none,     '%{_prefix}/etc'
+_sharedstatedir:     dir,     none,     '%{_prefix}/com'
+_localstatedir:      dir,     none,     '%{prefix}/var'
+_includedir:         dir,     none,     '%{_prefix}/include'
+_lib:                dir,     none,     'lib'
+_libdir:             dir,     none,     '%{_exec_prefix}/%{_lib}'
+_libexecdir:         dir,     none,     '%{_exec_prefix}/libexec'
+_mandir:             dir,     none,     '%{_datarootdir}/man'
+_infodir:            dir,     none,     '%{_datarootdir}/info'
+_localedir:          dir,     none,     '%{_datarootdir}/locale'
+_localedir:          dir,     none,     '%{_datadir}/locale'
+_localstatedir:      dir,     none,     '%{_prefix}/var'
+_usr:                dir,     none,     '/usr/local'
+_usrsrc:             dir,     none,     '%{_usr}/src'
+_var:                dir,     none,     '/usr/local/var'
+_varrun:             dir,     none,     '%{_var}/run'
+
+# Defaults, override in platform specific modules.
+__arch_install_post: exe,     none,     '%{nil}'
+__bash:              exe,     optional, '/bin/bash'
+__bzip2:             exe,     required, '/usr/bin/bzip2'
+__cat:               exe,     required, '/bin/cat'
+__chgrp:             exe,     required, '/usr/bin/chgrp'
+__chmod:             exe,     required, '/bin/chmod'
+__chown:             exe,     required, '/usr/sbin/chown'
+__cp:                exe,     required, '/bin/cp'
+__git:               exe,     required, '/usr/bin/git'
+__grep:              exe,     required, '/usr/bin/grep'
+__gzip:              exe,     required, '/usr/bin/gzip'
+__id:                exe,     required, '/usr/bin/id'
+__id_u:              exe,     none,     '%{__id} -u'
+__ln_s:              exe,     none,     'ln -s'
+__make:              exe,     required, 'make'
+__mkdir:             exe,     required, '/bin/mkdir'
+__mkdir_p:           exe,     none,     '/bin/mkdir -p'
+__mv:                exe,     required, '/bin/mv'
+__patch_bin:         exe,     required, '/usr/bin/patch'
+__patch_opts:        none,    none,     '%{nil}'
+__patch:             exe,     none,     '%{__patch_bin} %{__patch_opts}'
+__svn:               exe,     optional, '/usr/bin/svn'
+__rm:                exe,     required, '/bin/rm'
+__rmfile:            exe,     none,     '%{__rm} -f'
+__rmdir:             exe,     none,     '%{__rm} -rf'
+__sed:               exe,     required, '/usr/bin/sed'
+__sh:                exe,     required, '/bin/sh'
+__tar:               exe,     required, '/usr/bin/tar'
+__tar_extract:       exe,     none,     '%{__tar} -xvvf'
+__touch:             exe,     required, '/usr/bin/touch'
+__unzip:             exe,     required, '/usr/bin/unzip'
+__xz:                exe,     required, '/usr/bin/xz'
+
+# Default settings
+_target:             none,    none,     '%{nil}'
+
+# Paths
+_rtbase:             none,    none,     '%{_rtdir}'
+_configdir:          none,    none,     '%{_rtbase}/config:%{_rtbase}'
diff --git a/rtemstoolkit/elftoolchain/libdwarf/dwarf_die.c b/rtemstoolkit/elftoolchain/libdwarf/dwarf_die.c
index de6351a..4b46d85 100644
--- a/rtemstoolkit/elftoolchain/libdwarf/dwarf_die.c
+++ b/rtemstoolkit/elftoolchain/libdwarf/dwarf_die.c
@@ -78,7 +78,10 @@ dwarf_siblingof_b(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die,
 	}
 
 	ds = is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec;
-	cu = is_info ? dbg->dbg_cu_current : dbg->dbg_tu_current;
+	if (die != NULL && die->die_cu != NULL)
+		cu = die->die_cu;
+	else
+		cu = is_info ? dbg->dbg_cu_current : dbg->dbg_tu_current;
 
 	if (cu == NULL) {
 		DWARF_SET_ERROR(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
diff --git a/rtemstoolkit/rld-dwarf-types.h b/rtemstoolkit/rld-dwarf-types.h
index 4a11639..51e139e 100644
--- a/rtemstoolkit/rld-dwarf-types.h
+++ b/rtemstoolkit/rld-dwarf-types.h
@@ -35,22 +35,26 @@ namespace rld
     /**
      * Hide the types from libdwarf we use.
      */
-    typedef ::Dwarf_Debug    dwarf;
-    typedef ::Dwarf_Handler  dwarf_handler;
-    typedef ::Dwarf_Error    dwarf_error;
-    typedef ::Dwarf_Die      dwarf_die;
-    typedef ::Dwarf_Line     dwarf_line;
-    typedef ::Dwarf_Ptr      dwarf_pointer;
-    typedef ::Dwarf_Addr     dwarf_address;
-    typedef ::Dwarf_Off      dwarf_offset;
-    typedef ::Dwarf_Half     dwarf_half;
-    typedef ::Dwarf_Signed   dwarf_signed;
-    typedef ::Dwarf_Unsigned dwarf_unsigned;
-    typedef ::Dwarf_Bool     dwarf_bool;
-    typedef ::Dwarf_Sig8     dwarf_sig8;
-    typedef ::Dwarf_Line     dwarf_line;
-    typedef ::Dwarf_Half     dwarf_tag;
-    typedef ::Dwarf_Half     dwarf_attr;
+    typedef ::Dwarf_Debug                  dwarf;
+    typedef ::Dwarf_Handler                dwarf_handler;
+    typedef ::Dwarf_Error                  dwarf_error;
+    typedef ::Dwarf_Die                    dwarf_die;
+    typedef ::Dwarf_Line                   dwarf_line;
+    typedef ::Dwarf_Ptr                    dwarf_pointer;
+    typedef ::Dwarf_Addr                   dwarf_address;
+    typedef ::Dwarf_Off                    dwarf_offset;
+    typedef ::Dwarf_Half                   dwarf_half;
+    typedef ::Dwarf_Signed                 dwarf_signed;
+    typedef ::Dwarf_Unsigned               dwarf_unsigned;
+    typedef ::Dwarf_Bool                   dwarf_bool;
+    typedef ::Dwarf_Sig8                   dwarf_sig8;
+    typedef ::Dwarf_Line                   dwarf_line;
+    typedef ::Dwarf_Half                   dwarf_tag;
+    typedef ::Dwarf_Attribute              dwarf_attribute;
+    typedef ::Dwarf_Half                   dwarf_attr;
+    typedef ::Dwarf_Ranges                 dwarf_ranges;
+    typedef enum ::Dwarf_Ranges_Entry_Type dwarf_ranges_type;
+    typedef ::Dwarf_Type                   dwarf_type;
   }
 }
 
diff --git a/rtemstoolkit/rld-dwarf.cpp b/rtemstoolkit/rld-dwarf.cpp
index 674ac8f..919d7fa 100644
--- a/rtemstoolkit/rld-dwarf.cpp
+++ b/rtemstoolkit/rld-dwarf.cpp
@@ -37,6 +37,39 @@ namespace rld
 {
   namespace dwarf
   {
+    typedef std::vector < dwarf_die > dies_active;
+    dies_active active_dies;
+
+    bool active_dies_present (dwarf_die die)
+    {
+      return std::find (active_dies.begin(), active_dies.end(), die) != active_dies.end();
+    }
+
+    void dies_active_add (dwarf_die die)
+    {
+      if (active_dies_present (die))
+      {
+        std::cout << "DDdd : dup : " << die << std::endl;
+      }
+      else
+      {
+        active_dies.push_back (die);
+      }
+    }
+
+    void dies_active_remove (dwarf_die die)
+    {
+      dies_active::iterator di = std::find (active_dies.begin(), active_dies.end(), die);
+      if (di == active_dies.end ())
+      {
+        std::cout << "DDdd : no found : " << die << std::endl;
+      }
+      else
+      {
+        active_dies.erase (di);
+      }
+    }
+
     /**
      * The libdwarf error.
      */
@@ -201,6 +234,212 @@ namespace rld
       return addr < rhs.addr;
     }
 
+    range::range (const dwarf_ranges* range)
+      : range_ (range)
+    {
+    }
+
+    range::range (const range& orig)
+      : range_ (orig.range_)
+    {
+    }
+
+    range::~range ()
+    {
+    }
+
+    dwarf_unsigned
+    range::addr1 () const
+    {
+      if (range_ == nullptr)
+        throw rld::error ("No valid range", "rld:dwarf:range:addr1");
+      return range_->dwr_addr1;
+    }
+
+    dwarf_unsigned
+    range::addr2 () const
+    {
+      if (range_ == nullptr)
+        throw rld::error ("No valid range", "rld:dwarf:range:addr2");
+      return range_->dwr_addr2;
+    }
+
+    dwarf_ranges_type
+    range::type () const
+    {
+      if (range_ == nullptr)
+        throw rld::error ("No valid range", "rld:dwarf:range:type");
+      return range_->dwr_type;
+    }
+
+    range&
+    range::operator = (const range& rhs)
+    {
+      if (this != &rhs)
+        range_ = rhs.range_;
+      return *this;
+    }
+
+    void
+    range::dump ()
+    {
+      dwarf_ranges_type type_ = type ();
+      const char*       type_s = "invalid";
+      const char*       type_labels[] = {
+        "ENTRY",
+        "ADDRESS_SELECTION",
+        "END"
+      };
+      if (type_ <= DW_RANGES_END)
+        type_s = type_labels[type_];
+      std::cout << type_s << '-'
+                << std::hex << std::setfill ('0')
+                << "0x" << std::setw (8) << addr1 ()
+                << ":0x" << std::setw (8) << addr2 ();
+    }
+
+    address_ranges::address_ranges (file& debug)
+      : debug (debug),
+        offset (-1),
+        dranges (nullptr),
+        dranges_count (0)
+    {
+    }
+
+    address_ranges::address_ranges (debug_info_entry& die)
+      : debug (die.get_debug ()),
+        offset (-1),
+        dranges (nullptr),
+        dranges_count (0)
+    {
+      load (die);
+    }
+
+    address_ranges::address_ranges (file& debug, dwarf_offset offset)
+      : debug (debug),
+        offset (offset),
+        dranges (nullptr),
+        dranges_count (0)
+    {
+      load (offset);
+    }
+
+    address_ranges::address_ranges (const address_ranges& orig)
+      : debug (orig.debug),
+        offset (orig.offset)
+    {
+      load (orig.offset);
+    }
+
+    address_ranges::~address_ranges ()
+    {
+      if (dranges != nullptr)
+      {
+        ::dwarf_ranges_dealloc (debug, dranges, dranges_count);
+        dranges = nullptr;
+        dranges_count = 0;
+        ranges_.clear ();
+      }
+    }
+
+    bool
+    address_ranges::load (debug_info_entry& die, bool error)
+    {
+      dwarf_attribute attr;
+      dwarf_error     de;
+      int             dr;
+      dr = ::dwarf_attr (die, DW_AT_ranges, &attr, &de);
+      if (dr != DW_DLV_OK)
+      {
+        if (!error)
+          return false;
+        libdwarf_error_check ("rld:dwarf::address_ranges:load", dr, de);
+      }
+      dr = ::dwarf_global_formref (attr, &offset, &de);
+      if (dr != DW_DLV_OK)
+      {
+        if (!error)
+          return false;
+        libdwarf_error_check ("rld:dwarf::address_ranges:load", dr, de);
+      }
+      load (offset);
+      return true;
+    }
+
+    bool
+    address_ranges::load (dwarf_offset offset_, bool error)
+    {
+      if (offset_ > 0)
+      {
+        if (dranges != nullptr)
+          ::dwarf_ranges_dealloc (debug, dranges, dranges_count);
+
+        dranges = nullptr;
+        dranges_count = 0;
+
+        offset = offset_;
+
+        dwarf_error de;
+        int         dr;
+
+        dr = ::dwarf_get_ranges (debug, offset,
+                                 &dranges, &dranges_count, nullptr, &de);
+        if (dr != DW_DLV_OK)
+        {
+          if (!error)
+            return false;
+          libdwarf_error_check ("rld:dwarf::ranges:load", dr, de);
+        }
+
+        if (dranges != nullptr && dranges_count > 0)
+        {
+          for (dwarf_signed r = 0; r < dranges_count; ++r)
+            ranges_.push_back (range (&dranges[r]));
+        }
+      }
+
+      return true;
+    }
+
+    const ranges&
+    address_ranges::get () const
+    {
+      return ranges_;
+    }
+
+    bool
+    address_ranges::empty () const
+    {
+      return ranges_.empty ();
+    }
+
+    address_ranges&
+    address_ranges::operator = (const address_ranges& rhs)
+    {
+      if (this != &rhs)
+      {
+        if (debug != rhs.debug)
+          throw rld::error ("invalid debug", "address_ranges:=");
+        load (rhs.offset);
+      }
+      return *this;
+    }
+
+    void
+    address_ranges::dump ()
+    {
+      bool first = true;
+      std::cout << '[';
+      for (auto& r : ranges_)
+      {
+        if (!first)
+          std::cout << ',';
+        r.dump ();
+        first = false;
+      }
+      std::cout << ']';
+    }
+
     line_addresses::line_addresses (file&             debug,
                                     debug_info_entry& die)
       : debug (debug),
@@ -312,6 +551,193 @@ namespace rld
       return *this;
     }
 
+    function::function (file& debug, debug_info_entry& die)
+      : debug (debug),
+        external_ (false),
+        declaration_ (false),
+        inline_ (DW_INL_not_inlined),
+        pc_low_ (0),
+        pc_high_ (0),
+        ranges_ (debug)
+    {
+      dwarf_bool db;
+
+      if (die.attribute (DW_AT_external, db, false))
+        external_ = db ? true : false;
+
+      if (die.attribute (DW_AT_declaration, db, false))
+        declaration_ = db ? true : false;
+
+      die.attribute (DW_AT_linkage_name, linkage_name_, false);
+
+      if (!die.attribute (DW_AT_inline, inline_, false))
+        inline_ = DW_INL_not_inlined;
+
+      if (inline_ == DW_INL_declared_inlined)
+      {
+        die_dump_children (die, " +");
+      }
+
+      if (declaration_)
+      {
+        die.attribute (DW_AT_name, name_);
+      }
+      else
+      {
+        if (ranges_.load (die, false))
+        {
+          std::cout << "  ]]] " << ranges_.get ().size () << std::endl;
+          for (auto& r : ranges_.get ())
+            std::cout << "  ["
+                      << (void*) r.addr1 ()
+                      << ", "
+                      << (void*) r.addr2 ()
+                      << ")"
+                      << std::endl;
+        }
+
+        /*
+         * If ranges are not found see if the PC low and PC high attributes
+         * can be found.
+         */
+        if (ranges_.empty ())
+        {
+          die.get_lowpc (pc_low_);
+          die.get_highpc (pc_high_);
+
+          /*
+           * Handle DWARF4 spec, section 2.17.2.
+           */
+          dwarf_attribute attr;
+          if (die.attribute (DW_AT_high_pc, attr, false))
+          {
+            dwarf_half  form;
+            dwarf_error de;
+            int         dr;
+            dr = ::dwarf_whatform (attr, &form, &de);
+            libdwarf_error_check ("function:function", dr, de);
+            pc_high_ += pc_low_;
+
+            std::cout << "-=-= 1 l:" << (void*) pc_low_
+                      << " h:" << (void*) pc_high_
+                      << std::endl;
+          }
+        }
+
+        /*
+         * Get the name attribute. (if present)
+         */
+        if (!die.attribute (DW_AT_name, name_, false))
+        {
+          bool found = false;
+
+          /*
+           * For inlined function, the actual name is probably in the DIE
+           * referenced by DW_AT_abstract_origin. (if present)
+           */
+          dwarf_attribute abst_at;
+          if (die.attribute (DW_AT_abstract_origin, abst_at, false))
+          {
+            dwarf_offset abst_at_die_offset;
+            dwarf_error  de;
+            int          dr;
+            dr = ::dwarf_global_formref (abst_at, &abst_at_die_offset, &de);
+            if (dr == DW_DLV_OK)
+            {
+              debug_info_entry abst_at_die (debug, abst_at_die_offset);
+              if (abst_at_die.attribute (DW_AT_name, name_, false))
+                found = true;
+            }
+          }
+
+          /*
+           * If DW_AT_name is not present, but DW_AT_specification is present,
+           * then probably the actual name is in the DIE referenced by
+           * DW_AT_specification.
+           */
+          if (!found)
+          {
+            dwarf_attribute spec;
+            if (die.attribute (DW_AT_specification, spec, false))
+            {
+              dwarf_offset spec_die_offset;
+              dwarf_error  de;
+              int          dr;
+              dr = ::dwarf_global_formref (abst_at, &spec_die_offset, &de);
+              if (dr == DW_DLV_OK)
+              {
+                debug_info_entry spec_die (debug, spec_die_offset);
+                if (spec_die.attribute (DW_AT_name, name_, false))
+                  found = true;
+              }
+            }
+          }
+
+          if (!found)
+            throw rld::error ("Name not found", "function:function");
+        }
+
+        if (die.tag () == DW_TAG_inlined_subroutine)
+        {
+          die.attribute (DW_AT_call_file, call_file_, false);
+        }
+      }
+
+      std::cout << "]] " << name_ << std::endl;
+    }
+
+    function::~function ()
+    {
+    }
+
+    std::string
+    function::name () const
+    {
+      return name_;
+    }
+
+    const address_ranges&
+    function::get_ranges () const
+    {
+      return ranges_;
+    }
+
+    dwarf_unsigned
+    function::pc_low () const
+    {
+      return pc_low_;
+    }
+
+    dwarf_unsigned
+    function::pc_high () const
+    {
+      return pc_high_;
+    }
+
+    bool
+    function::is_external () const
+    {
+      return external_;
+    }
+
+    bool
+    function::is_declaration () const
+    {
+      return declaration_;
+    }
+
+    bool
+    function::is_inlined () const
+    {
+      return inline_ == DW_INL_declared_inlined;
+    }
+
+    std::string
+    function::call_file () const
+    {
+      return call_file_;
+    }
+
     debug_info_entry::debug_info_entry (file& debug)
       : debug (debug),
         die (nullptr),
@@ -334,10 +760,29 @@ namespace rld
         tag_ (0),
         offset_ (offset__)
     {
+      dwarf_die   ddie;
+      dwarf_error de;
+      int         dr;
+      dr = ::dwarf_offdie (debug, offset_, &ddie, &de);
+      libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de);
+      die = ddie;
+    }
+
+    debug_info_entry::debug_info_entry (const debug_info_entry& orig)
+      : debug (orig.debug),
+        die (nullptr),
+        tag_ (orig.tag_),
+        offset_ (orig.offset_)
+    {
+      if (offset_ != 0)
+      {
+        dwarf_die   ddie;
         dwarf_error de;
         int         dr;
-        dr = ::dwarf_offdie (debug, offset_, &die, &de);
+        dr = ::dwarf_offdie (debug, offset_, &ddie, &de);
         libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de);
+        die = ddie;
+      }
     }
 
     debug_info_entry::~debug_info_entry ()
@@ -398,7 +843,7 @@ namespace rld
       {
         dwarf_error de;
         int         dr;
-        dr = ::dwarf_tag(die, &tag_, &de);
+        dr = ::dwarf_tag (die, &tag_, &de);
         libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de);
       }
       return tag_;
@@ -418,6 +863,54 @@ namespace rld
     }
 
     bool
+    debug_info_entry::get_lowpc (dwarf_address& addr, bool error) const
+    {
+      dwarf_error de;
+      int         dr;
+      dr = ::dwarf_lowpc (die, &addr, &de);
+      if (error)
+        libdwarf_error_check ("debug_info_entry:lowpc", dr, de);
+      return dr == DW_DLV_OK;
+    }
+
+    bool
+    debug_info_entry::get_highpc (dwarf_address& addr, bool error) const
+    {
+      dwarf_error de;
+      int         dr;
+      dr = ::dwarf_highpc (die, &addr, &de);
+      if (error)
+        libdwarf_error_check ("debug_info_entry:highpc", dr, de);
+      return dr == DW_DLV_OK;
+    }
+
+    bool
+    debug_info_entry::attribute (dwarf_attr       attr,
+                                 dwarf_attribute& value,
+                                 bool             error) const
+    {
+      dwarf_error de;
+      int         dr;
+      dr = ::dwarf_attr (die, attr, &value, &de);
+      if (error)
+        libdwarf_error_check ("debug_info_entry:attribute(attr)", dr, de);
+      return dr == DW_DLV_OK;
+    }
+
+    bool
+    debug_info_entry::attribute (dwarf_attr  attr,
+                                 dwarf_bool& value,
+                                 bool        error) const
+    {
+      dwarf_error de;
+      int         dr;
+      dr = ::dwarf_attrval_flag (die, attr, &value, &de);
+      if (error)
+        libdwarf_error_check ("debug_info_entry:attribute(flag)", dr, de);
+      return dr == DW_DLV_OK;
+    }
+
+    bool
     debug_info_entry::attribute (dwarf_attr      attr,
                                  dwarf_unsigned& value,
                                  bool            error) const
@@ -426,7 +919,7 @@ namespace rld
       int         dr;
       dr = ::dwarf_attrval_unsigned (die, attr, &value, &de);
       if (error)
-        libdwarf_error_check ("debug_info_entry:attribute ", dr, de);
+        libdwarf_error_check ("debug_info_entry:attribute(unsigned)", dr, de);
       return dr == DW_DLV_OK;
     }
 
@@ -441,7 +934,7 @@ namespace rld
       value.clear ();
       dr = ::dwarf_attrval_string (die, attr, &s, &de);
       if (error)
-        libdwarf_error_check ("debug_info_entry:attribute ", dr, de);
+        libdwarf_error_check ("debug_info_entry:attribute(string)", dr, de);
       if (s != nullptr)
         value = s;
       return dr == DW_DLV_OK;
@@ -473,6 +966,50 @@ namespace rld
       libdwarf_error_check ("debug_info_entry:source_files ", dr, de);
     }
 
+    bool
+    debug_info_entry::ranges (dwarf_ranges*& ranges,
+                              dwarf_signed&  rangescount) const
+    {
+      dwarf_unsigned ranges_off;
+      if (attribute (DW_AT_ranges, ranges_off, false))
+      {
+        dwarf_error de;
+        int         dr;
+        dr = ::dwarf_get_ranges (debug, ranges_off,
+                                 &ranges, &rangescount, nullptr, &de);
+        libdwarf_error_check ("debug_info_entry:ranges ", dr, de);
+        return ranges != nullptr && rangescount > 0;
+      }
+      return false;
+    }
+
+    bool
+    debug_info_entry::get_child (debug_info_entry& child_die)
+    {
+      dwarf_error      de;
+      int              dr;
+      dr = ::dwarf_child (die, child_die, &de);
+      return dr == DW_DLV_OK;
+    }
+
+    bool
+    debug_info_entry::get_sibling (debug_info_entry& sibling_die)
+    {
+      dwarf_error      de;
+      int              dr;
+      dr = ::dwarf_siblingof (debug, die, sibling_die, &de);
+      if (dr == DW_DLV_NO_ENTRY)
+        return false;
+      libdwarf_error_check ("compilation_unit::sibling", dr, de);
+      return true;
+    }
+
+    file&
+    debug_info_entry::get_debug ()
+    {
+      return debug;
+    }
+
     void
     debug_info_entry::dealloc ()
     {
@@ -482,6 +1019,178 @@ namespace rld
       }
     }
 
+    void
+    debug_info_entry::dump (std::string prefix)
+    {
+      const char* s;
+      ::dwarf_get_TAG_name (tag (), &s);
+      std::cout << prefix << s << std::endl;
+
+      dwarf_attribute* attributes;
+      dwarf_signed     attr_count;
+      dwarf_error      de;
+      int              dr;
+
+      dr = ::dwarf_attrlist (die, &attributes, &attr_count, &de);
+      if (dr == DW_DLV_OK)
+      {
+        for (int a = 0; a < attr_count; ++a)
+        {
+          dwarf_attr attr;
+          dr = ::dwarf_whatattr (attributes[a], &attr, &de);
+          libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+          dwarf_half form;
+          dr = ::dwarf_whatform (attributes[a], &form, &de);
+          libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+          const char* f;
+          dwarf_get_FORM_name (form, &f);
+          dwarf_get_AT_name (attr, &s);
+          std::cout << prefix << " - " << s << " (" << attr << ") [" << f << ']';
+          dwarf_unsigned  v_unsigned;
+          dwarf_bool      v_bool;
+          dwarf_offset    v_offset;
+          address_ranges  v_ranges (debug);
+          switch (form)
+          {
+            case DW_FORM_block:
+            case DW_FORM_block1:
+            case DW_FORM_block2:
+            case DW_FORM_block4:
+              break;
+            case DW_FORM_addr:
+            case DW_FORM_data1:
+            case DW_FORM_data2:
+            case DW_FORM_data4:
+            case DW_FORM_data8:
+            case DW_FORM_udata:
+            case DW_FORM_ref1:
+            case DW_FORM_ref2:
+            case DW_FORM_ref4:
+            case DW_FORM_ref8:
+            case DW_FORM_ref_udata:
+              dr = ::dwarf_attrval_unsigned (die, attr, &v_unsigned, &de);
+              libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+              std::cout << " : "
+                        << std::hex << std::setfill ('0')
+                        << std::setw (8) << v_unsigned
+                        << std::dec << std::setfill (' ')
+                        << " (" << v_unsigned << ')';
+              break;
+            case DW_FORM_exprloc:
+              break;
+            case DW_FORM_flag:
+            case DW_FORM_flag_present:
+              dr = ::dwarf_attrval_flag (die, attr, &v_bool, &de);
+              libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+              std::cout << " : " << v_bool;
+              break;
+              break;
+            case DW_FORM_string:
+            case DW_FORM_strp:
+              dr = ::dwarf_attrval_string (die, attr, &s, &de);
+              libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+              std::cout << " : " << s;
+              break;
+            case DW_FORM_sec_offset:
+              switch (attr)
+              {
+                case DW_AT_ranges:
+                  dr = ::dwarf_global_formref (attributes[a], &v_offset, &de);
+                  libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+                  std::cout << ' ';
+                  v_ranges.load (v_offset);
+                  v_ranges.dump ();
+                  break;
+                default:
+                  break;
+              }
+              break;
+            case DW_FORM_indirect:
+            case DW_FORM_ref_addr:
+            case DW_FORM_ref_sig8:
+            case DW_FORM_sdata:
+              break;
+          }
+          #if 0
+          switch (attr)
+          {
+            case DW_AT_external:
+            case DW_AT_declaration:
+            case DW_AT_prototyped:
+              dr = ::dwarf_attrval_flag (die, attr, &v_bool, &de);
+              libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+              std::cout << " : " << v_bool;
+              break;
+            case DW_AT_name:
+            case DW_AT_linkage_name:
+              dr = ::dwarf_attrval_string (die, attr, &s, &de);
+              libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+              std::cout << " : " << s;
+              break;
+            case DW_AT_decl_line:
+            case DW_AT_decl_file:
+            case DW_AT_type:
+            case DW_AT_byte_size:
+              dr = ::dwarf_attrval_unsigned (die, attr, &v_unsigned, &de);
+              libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+              std::cout << " : " << v_unsigned;
+              break;
+            case DW_AT_inline:
+              dr = ::dwarf_attrval_unsigned (die, attr, &v_unsigned, &de);
+              libdwarf_error_check ("compilation_unit::dump_die", dr, de);
+              dr = dwarf_get_INL_name (v_unsigned, &s);
+              if (dr == DW_DLV_OK)
+                std::cout << " : " << s;
+              else
+                std::cout << " : invalid attr";
+              break;
+            default:
+              break;
+          }
+          #endif
+          std::cout << std::endl;
+        }
+      }
+    }
+
+    void
+    die_dump_children (debug_info_entry die,
+                       std::string      prefix,
+                       int              nesting,
+                       int              depth)
+    {
+      debug_info_entry child (die.get_debug ());
+      if (die.get_child (child))
+        die_dump (child, prefix, nesting, depth);
+    }
+
+    void
+    die_dump (debug_info_entry die,
+              std::string      prefix,
+              int              nesting,
+              int              depth)
+    {
+      ++nesting;
+
+      for (int n = 0; n < nesting; ++n)
+        prefix += ' ';
+
+      while (true)
+      {
+        die.dump (prefix);
+
+        if (depth < 0 || nesting < depth)
+          die_dump_children (die, prefix);
+
+        debug_info_entry next (die.get_debug ());
+
+        if (!die.get_sibling (next))
+          break;
+
+        die = next;
+      }
+    }
+
     compilation_unit::compilation_unit (file&             debug,
                                         debug_info_entry& die,
                                         dwarf_unsigned    offset)
@@ -492,6 +1201,8 @@ namespace rld
         die_offset (die.offset ()),
         source_ (debug, die_offset)
     {
+      die.dump ("C ");
+
       die.attribute (DW_AT_name, name_);
       name_ = name_;
 
@@ -622,6 +1333,58 @@ namespace rld
     {
     }
 
+    void
+    compilation_unit::load_types ()
+    {
+      //dump_die ();
+    }
+
+    void
+    compilation_unit::load_functions ()
+    {
+      debug_info_entry die (debug, die_offset);
+      debug_info_entry ret_die (debug);
+      dwarf_error      de;
+      int              dr;
+
+      std::cout << "CU @ 0x" << std::hex << offset_ << std::dec << std::endl;
+
+      dr = ::dwarf_child(die, ret_die, &de);
+      if (dr == DW_DLV_OK)
+        load_functions (ret_die);
+    }
+
+    void
+    compilation_unit::load_functions (debug_info_entry& die)
+    {
+      while (true)
+      {
+        if (die.tag () == DW_TAG_subprogram ||
+            die.tag () == DW_TAG_entry_point ||
+            die.tag () == DW_TAG_inlined_subroutine)
+        {
+          std::cout << "----------------------------------------------" << std::endl;
+          die.dump ("D ");
+          functions_.push_back (function (debug, die));
+        }
+
+        debug_info_entry ret_die (debug);
+        dwarf_error      de;
+        int              dr;
+
+        dr = ::dwarf_child(die, ret_die, &de);
+        if (dr == DW_DLV_OK)
+          load_functions (ret_die);
+
+        dr = ::dwarf_siblingof (debug, die, ret_die, &de);
+        if (dr == DW_DLV_NO_ENTRY)
+          break;
+        libdwarf_error_check ("compilation_unit:load_functions", dr, de);
+
+        die = ret_die;
+      }
+    }
+
     std::string
     compilation_unit::name () const
     {
@@ -705,6 +1468,14 @@ namespace rld
       return *this;
     }
 
+    void
+    compilation_unit::dump_die ()
+    {
+      debug_info_entry die (debug, die_offset);
+      std::cout << "CU @ 0x" << std::hex << offset_ << std::dec << std::endl;
+      die_dump_children (die, "");
+    }
+
     source_flags::source_flags (const std::string& source)
       : source (source)
     {
@@ -736,7 +1507,7 @@ namespace rld
     file::file ()
       : debug (nullptr),
         elf_ (nullptr)
-      {
+    {
     }
 
     file::~file ()
@@ -830,7 +1601,7 @@ namespace rld
           break;
 
         /*
-         * Fnd the CU DIE.
+         * Find the CU DIE.
          */
         debug_info_entry die (*this);
         debug_info_entry ret_die (*this);
@@ -854,6 +1625,20 @@ namespace rld
       }
     }
 
+    void
+    file::load_types ()
+    {
+      for (auto& cu : cus)
+        cu.load_types ();
+    }
+
+    void
+    file::load_functions ()
+    {
+      for (auto& cu : cus)
+        cu.load_functions ();
+    }
+
     bool
     file::get_source (const unsigned int addr,
                       std::string&       source_file,
diff --git a/rtemstoolkit/rld-dwarf.h b/rtemstoolkit/rld-dwarf.h
index 1207728..454fc1f 100644
--- a/rtemstoolkit/rld-dwarf.h
+++ b/rtemstoolkit/rld-dwarf.h
@@ -114,6 +114,95 @@ namespace rld
     typedef std::vector < address > addresses;
 
     /**
+     * Range, one entry in an address range container.
+     */
+    class range
+    {
+    public:
+      range (const dwarf_ranges* range);
+      range (const range& orig);
+      ~range ();
+
+      /**
+       * Address 1 in the range.
+       */
+      dwarf_unsigned addr1 () const;
+      dwarf_unsigned addr2 () const;
+
+      /**
+       * Get the type of range.
+       */
+      dwarf_ranges_type type () const;
+
+      /**
+       * Assigment operator.
+       */
+      range& operator = (const range& rhs);
+
+      /**
+       * Dump the range.
+       */
+      void dump ();
+
+    private:
+
+      const dwarf_ranges* range_;
+    };
+
+    typedef std::vector < range > ranges;
+
+    /**
+     * Address ranges, is a range of addresses.
+     */
+    class address_ranges
+    {
+    public:
+      address_ranges (file& debug);
+      address_ranges (debug_info_entry& die);
+      address_ranges (file& debug, dwarf_offset offset);
+      address_ranges (const address_ranges& orig);
+      ~address_ranges ();
+
+      /**
+       * Load the ranges from the DIE.
+       */
+      bool load (debug_info_entry& die, bool error = true);
+
+      /**
+       * Load the ranges from the debug info.
+       */
+      bool load (dwarf_offset offset, bool error = true);
+
+      /**
+       * Get the container.
+       */
+      const ranges& get () const;
+
+      /**
+       * Address range empty?
+       */
+      bool empty () const;
+
+      /**
+       * Assigment operator.
+       */
+      address_ranges& operator = (const address_ranges& rhs);
+
+      /**
+       * Dump the address ranges.
+       */
+      void dump ();
+
+    private:
+
+      file&         debug;
+      dwarf_offset  offset;
+      dwarf_ranges* dranges;
+      dwarf_signed  dranges_count;
+      ranges        ranges_;
+    };
+
+    /**
      * Line addresses.
      */
     class line_addresses
@@ -150,7 +239,6 @@ namespace rld
     public:
       sources (file& debug, dwarf_offset die_offset);
       sources (const sources& orig);
-      //sources (sources&& orig);
       ~sources ();
 
       /**
@@ -177,6 +265,77 @@ namespace rld
     };
 
     /**
+     * Function.
+     */
+    class function
+    {
+    public:
+      function (file& debug, debug_info_entry& die);
+      ~function ();
+
+      /**
+       * Get the name of the function.
+       */
+      std::string name () const;
+
+      /**
+       * Get the linkage name of the function.
+       */
+      std::string linkage_name () const;
+
+      /**
+       * Get the ranges for the funcion, if empty the PC low and PC high values
+       * will be valid.
+       */
+      const address_ranges& get_ranges () const;
+
+      /**
+       * Get the PC low address, valid if ranges is empty.
+       */
+      dwarf_unsigned pc_low () const;
+
+      /**
+       * Get the PC high address, valid if ranges is empty.
+       */
+      dwarf_unsigned pc_high () const;
+
+      /**
+       * Is the function external?
+       */
+      bool is_external () const;
+
+      /**
+       * Is this just a declaration?
+       */
+      bool is_declaration () const;
+
+      /**
+       * Is the function inlined?
+       */
+      bool is_inlined () const;
+
+      /**
+       * Get the call file of the inlined function.
+       */
+      std::string call_file () const;
+
+    private:
+
+      file&          debug;
+      bool           external_;
+      bool           declaration_;
+      dwarf_unsigned inline_;
+      dwarf_unsigned pc_low_;
+      dwarf_unsigned pc_high_;
+      address_ranges ranges_;
+      std::string    name_;
+      std::string    linkage_name_;
+      std::string    call_file_;
+    };
+
+    typedef std::vector < function > functions;
+
+    /**
      * Debug Information Element (DIE).
      *
      * This class clean up and deallocations a DIE when it desctructs.
@@ -190,6 +349,7 @@ namespace rld
       debug_info_entry (file& debug);
       debug_info_entry (file& debug, dwarf_die& die);
       debug_info_entry (file& debug, dwarf_offset offset);
+      debug_info_entry (const debug_info_entry& orig);
 
       /**
        * Destruct and clean up.
@@ -229,6 +389,30 @@ namespace rld
       dwarf_offset offset ();
 
       /**
+       * Get the low PC.
+       */
+      bool get_lowpc (dwarf_address& addr, bool error = false) const;
+
+      /**
+       * Get the high PC.
+       */
+      bool get_highpc (dwarf_address& addr, bool error = false) const;
+
+      /**
+       * Get an attribute.
+       */
+      bool attribute (dwarf_attr       attr,
+                      dwarf_attribute& value,
+                      bool             error = true) const;
+
+      /**
+       * Get a flag.
+       */
+      bool attribute (dwarf_attr  attr,
+                      dwarf_bool& value,
+                      bool        error = true) const;
+
+      /**
        * Get an unsigned attribute.
        */
       bool attribute (dwarf_attr      attr,
@@ -257,10 +441,35 @@ namespace rld
                          dwarf_signed& sourcecount) const;
 
       /**
+       * Get the ranges.
+       */
+      bool ranges (dwarf_ranges*& ranges, dwarf_signed& rangescount) const;
+
+      /**
+       * Get the child.
+       */
+      bool get_child (debug_info_entry& child_die);
+
+      /**
+       * Get the silbing
+       */
+      bool get_sibling (debug_info_entry& sibling_die);
+
+      /**
+       * Get the debug info for this DIE.
+       */
+      file& get_debug ();
+
+      /**
        * deallocate the DIE.
        */
       void dealloc ();
 
+      /**
+       * Dump this DIE.
+       */
+      void dump (std::string prefix);
+
     private:
 
       file&        debug;
@@ -271,6 +480,22 @@ namespace rld
     };
 
     /**
+     * Dump the DIE and all it's children and siblings.
+     */
+    void die_dump_children (debug_info_entry die,
+                            std::string      prefix,
+                            int              nesting = 0,
+                            int              depth = -1);
+
+    /**
+     * Dump the DIE and all it's children and siblings.
+     */
+    void die_dump (debug_info_entry die,
+                   std::string      prefix,
+                   int              nesting = 0,
+                   int              depth = -1);
+
+    /**
      * Compilation Unit.
      */
     class compilation_unit
@@ -283,6 +508,16 @@ namespace rld
       ~compilation_unit ();
 
       /**
+       * Load the types.
+       */
+      void load_types ();
+
+      /**
+       * Load the functions.
+       */
+      void load_functions ();
+
+      /**
        * Name of the CU.
        */
       std::string name () const;
@@ -321,8 +556,15 @@ namespace rld
        */
       compilation_unit& operator = (const compilation_unit& rhs);
 
+      /**
+       * Output the DIE tree.
+       */
+      void dump_die ();
+
     private:
 
+      void load_functions (debug_info_entry& die);
+
       file&          debug;       ///< The DWARF debug handle.
       dwarf_unsigned offset_;     ///< The CU offset in .debug_info
       std::string    name_;       ///< The name of the CU.
@@ -334,6 +576,8 @@ namespace rld
 
       sources        source_;     ///< Sources table for this CU.
       addresses      addr_lines_; ///< Address table.
+
+      functions      functions_;  ///< The functions in the CU.
     };
 
     typedef std::list < compilation_unit > compilation_units;
@@ -412,6 +656,16 @@ namespace rld
       void load_debug ();
 
       /**
+       * Load the DWARF type information.
+       */
+      void load_types ();
+
+      /**
+       * Load the DWARF functions information.
+       */
+      void load_functions ();
+
+      /**
        * Get the source location given an address.
        */
       bool get_source (const unsigned int address,




More information about the vc mailing list