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

Chris Johns chrisj at rtems.org
Tue Jun 19 03:44:43 UTC 2018


Module:    rtems-tools
Branch:    master
Commit:    d8eef0a463d4998d221ff318dd952dab18e5dfbf
Changeset: http://git.rtems.org/rtems-tools/commit/?id=d8eef0a463d4998d221ff318dd952dab18e5dfbf

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

rtemstoolkit: Add DWARF function support.

Load the functions in each CU.

---

 linkers/rtems-addr2line.cpp                    |  20 +-
 linkers/rtems-exeinfo.cpp                      |   2 +
 rtemstoolkit/defaults.mc                       | 122 ++++
 rtemstoolkit/elftoolchain/libdwarf/dwarf_die.c |   5 +-
 rtemstoolkit/rld-dwarf-types.h                 |  37 +-
 rtemstoolkit/rld-dwarf.cpp                     | 926 ++++++++++++++++++++++++-
 rtemstoolkit/rld-dwarf.h                       | 292 +++++++-
 7 files changed, 1364 insertions(+), 40 deletions(-)

diff --git a/linkers/rtems-addr2line.cpp b/linkers/rtems-addr2line.cpp
index 2e79c62..8aab7de 100644
--- a/linkers/rtems-addr2line.cpp
+++ b/linkers/rtems-addr2line.cpp
@@ -54,6 +54,7 @@ static struct option rld_opts[] = {
   { "version",      no_argument,            NULL,           'V' },
   { "verbose",      no_argument,            NULL,           'v' },
   { "executable",   required_argument,      NULL,           'e' },
+  { "functions" ,   no_argument,            NULL,           'f' },
   { "addresses",    no_argument,            NULL,           'a' },
   { "pretty-print", no_argument,            NULL,           'p' },
   { "basenames",    no_argument,            NULL,           's' },
@@ -69,7 +70,8 @@ usage (int exit_code)
             << " -V        : print version number and exit (also --version)" << std::endl
             << " -v        : verbose (trace import parts), can supply multiple times" << std::endl
             << "             to increase verbosity (also --verbose)" << std::endl
-            << " -e        : executable (also --executablewarn)" << std::endl
+            << " -e        : executable (also --executable)" << std::endl
+            << " -f        : show function names (also --functions)" << std::endl
             << " -a        : show addresses (also --addresses)" << std::endl
             << " -p        : human readable format (also --pretty-print)" << std::endl
             << " -s        : Strip directory paths (also --basenames)" << std::endl;
@@ -127,6 +129,7 @@ main (int argc, char* argv[])
   try
   {
     std::string exe_name = "a.out";
+    bool        show_functions = false;
     bool        show_addresses = false;
     bool        pretty_print = false;
     bool        show_basenames = false;
@@ -135,7 +138,7 @@ main (int argc, char* argv[])
 
     while (true)
     {
-      int opt = ::getopt_long (argc, argv, "hvVe:aps", rld_opts, NULL);
+      int opt = ::getopt_long (argc, argv, "hvVe:faps", rld_opts, NULL);
       if (opt < 0)
         break;
 
@@ -156,6 +159,10 @@ main (int argc, char* argv[])
           exe_name = optarg;
           break;
 
+        case 'f':
+          show_functions = true;
+          break;
+
         case 'a':
           show_addresses = true;
           break;
@@ -213,6 +220,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)
       {
@@ -244,6 +253,13 @@ main (int argc, char* argv[])
             std::cout << std::endl;
         }
 
+        if (show_functions)
+        {
+          std::string function;
+          debug.get_function (location, function);
+          std::cout << function << " at ";
+        }
+
         if (show_basenames)
           std::cout << rld::path::basename (path);
         else
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..410011c 100644
--- a/rtemstoolkit/rld-dwarf-types.h
+++ b/rtemstoolkit/rld-dwarf-types.h
@@ -35,22 +35,27 @@ 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 enum ::Dwarf_Form_Class        dwarf_form_class;
+    typedef ::Dwarf_Type                   dwarf_type;
   }
 }
 
diff --git a/rtemstoolkit/rld-dwarf.cpp b/rtemstoolkit/rld-dwarf.cpp
index 674ac8f..f06bbad 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,230 @@ 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;
+    }
+
+    bool
+    range::empty () const
+    {
+      /**
+       * See DWARF 2.17.3.
+       *
+       * A bounded range entry whose beginning and ending address offsets are
+       * equal (including zero) indicates an empty range and may be ignored.
+       */
+      return type () == DW_RANGES_ENTRY && addr1 () == addr2 ();
+    }
+
+    bool
+    range::end () const
+    {
+      return type () == DW_RANGES_END;
+    }
+
+    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[] = {
+        "BOUNDED",
+        "BASE",
+        "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 +569,223 @@ namespace rld
       return *this;
     }
 
+
+    function::function (file& debug, debug_info_entry& die)
+      : debug (debug),
+        machine_code_ (false),
+        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 ranges are not found see if the PC low and PC high attributes
+       * can be found.
+       */
+      ranges_.load (die, false);
+      if (ranges_.empty ())
+      {
+        bool is_address;
+        if (die.get_lowpc (pc_low_) && die.get_highpc (pc_high_, is_address))
+        {
+          machine_code_ = true;
+          if (!is_address)
+            pc_high_ += pc_low_;
+        }
+      }
+      else
+      {
+        for (auto& r : ranges_.get ())
+        {
+          if (!r.end () && !r.empty ())
+          {
+            machine_code_ = true;
+            break;
+          }
+        }
+      }
+
+      if (declaration_)
+      {
+        die.attribute (DW_AT_name, name_);
+      }
+      else
+      {
+        /*
+         * 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 (die.tag () == DW_TAG_inlined_subroutine)
+        {
+          die.attribute (DW_AT_call_file, call_file_, false);
+        }
+      }
+
+      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
+      {
+        std::cout << "dwarf::function: ";
+        if (name_.empty ())
+          std::cout << "NO NAME";
+        else
+          std::cout << name_;
+        if (!has_machine_code ())
+          std::cout << " NO MACHINE CODE";
+        else
+          std::cout << std::hex << std::setfill ('0')
+                    << " pc_low = 0x" << std::setw (8) << pc_low ()
+                    << " pc_high = 0x" << std::setw (8) << pc_high ()
+                    << std::dec << std::setfill (' ');
+        std::cout << 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
+    {
+      if (ranges_.empty ())
+        return pc_low_;
+      dwarf_address addr = ~0;
+      for (auto& r : ranges_.get ())
+      {
+        if (!r.end () && !r.empty () && r.addr1 () < addr)
+          addr = r.addr1 ();
+      }
+      return addr;
+    }
+
+    dwarf_unsigned
+    function::pc_high () const
+    {
+      if (ranges_.empty ())
+        return pc_high_;
+      dwarf_address addr = 0;
+      for (auto& r : ranges_.get ())
+      {
+        if (!r.end () && !r.empty () && r.addr2 () > addr)
+          addr = r.addr1 ();
+      }
+      return addr;
+    }
+
+    bool
+    function::has_machine_code () const
+    {
+      return machine_code_;
+    }
+
+    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_;
+    }
+
+    bool
+    function::inside (dwarf_address addr) const
+    {
+      return !name_.empty () && has_machine_code () &&
+        addr >= pc_low () && addr <= pc_high ();
+    }
+
     debug_info_entry::debug_info_entry (file& debug)
       : debug (debug),
         die (nullptr),
@@ -334,10 +808,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 ()
@@ -378,6 +871,24 @@ namespace rld
       return *this;
     }
 
+    debug_info_entry&
+    debug_info_entry::operator = (dwarf_offset offset__)
+    {
+      dealloc ();
+      if (offset__ != 0)
+      {
+        dwarf_die   ddie;
+        dwarf_error de;
+        int         dr;
+        offset_ = offset__;
+        tag_ = 0;
+        dr = ::dwarf_offdie (debug, offset_, &ddie, &de);
+        libdwarf_error_check ("debug_info_entry:operator=", dr, de);
+        die = ddie;
+      }
+      return *this;
+    }
+
     bool
     debug_info_entry::operator == (debug_info_entry& rhs) const
     {
@@ -398,7 +909,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 +929,59 @@ 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&          is_address,
+                                  bool           error) const
+    {
+      dwarf_half       form;
+      dwarf_form_class class_;
+      dwarf_error      de;
+      int              dr;
+      dr = ::dwarf_highpc_b (die, &addr, &form, &class_, &de);
+      if (error)
+        libdwarf_error_check ("debug_info_entry:highpc", dr, de);
+      is_address = class_ == DW_FORM_CLASS_ADDRESS;
+      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 +990,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 +1005,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 +1037,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 +1090,164 @@ namespace rld
       }
     }
 
+    void
+    debug_info_entry::dump (std::string prefix, bool newline)
+    {
+      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 ("debug_info_entry::dump", dr, de);
+          dwarf_half form;
+          dr = ::dwarf_whatform (attributes[a], &form, &de);
+          libdwarf_error_check ("debug_info_entry::dump", dr, de);
+          const char* f;
+          dwarf_get_FORM_name (form, &f);
+          dwarf_get_AT_name (attr, &s);
+          if (a > 0)
+            std::cout << std::endl;
+          std::cout << prefix << " - " << s << " (" << attr << ") [" << f << ']';
+          debug_info_entry v_die (debug);
+          address_ranges   v_ranges (debug);
+          dwarf_unsigned   v_unsigned;
+          dwarf_bool       v_bool;
+          dwarf_offset     v_offset;
+          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:
+              dr = ::dwarf_attrval_unsigned (die, attr, &v_unsigned, &de);
+              libdwarf_error_check ("debug_info_entry::dump", dr, de);
+              std::cout << " : "
+                        << std::hex << std::setfill ('0')
+                        << std::setw (8) << v_unsigned
+                        << std::dec << std::setfill (' ')
+                        << " (" << v_unsigned << ')';
+              break;
+            case DW_FORM_ref1:
+            case DW_FORM_ref2:
+            case DW_FORM_ref4:
+            case DW_FORM_ref8:
+            case DW_FORM_ref_udata:
+              dr = ::dwarf_global_formref (attributes[a], &v_offset, &de);
+              libdwarf_error_check ("debug_info_entry::dump", dr, de);
+              std::cout << " : "
+                        << std::hex << std::setfill ('0')
+                        << std::setw (8) << v_offset
+                        << std::dec << std::setfill (' ')
+                        << " (" << v_offset << ')';
+              switch (attr)
+              {
+                case DW_AT_abstract_origin:
+                case DW_AT_specification:
+                  v_die = v_offset;
+                  std::cout << std::endl;
+                  v_die.dump (' ' + prefix, false);
+                  break;
+                default:
+                  break;
+              }
+              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 ("debug_info_entry::dump", 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 ("debug_info_entry::dump", 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 ("debug_info_entry::dump", 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 (newline)
+          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)
@@ -489,6 +1255,7 @@ namespace rld
         offset_ (offset),
         pc_low_ (0),
         pc_high_ (0),
+        ranges_ (debug),
         die_offset (die.offset ()),
         source_ (debug, die_offset)
     {
@@ -497,13 +1264,35 @@ namespace rld
 
       die.attribute (DW_AT_producer, producer_);
 
-      die.attribute (DW_AT_low_pc, pc_low_, false);
+      ranges_.load (die, false);
 
-      if (!die.attribute (DW_AT_high_pc, pc_high_, false))
-        pc_high_ = ~0U;
-
-      if (pc_high_ < pc_low_)
-        pc_high_ += pc_low_;
+      if (ranges_.empty ())
+      {
+        bool is_address;
+        die.get_lowpc (pc_low_);
+        if (die.get_highpc (pc_high_, is_address))
+        {
+          if (!is_address)
+            pc_high_ += pc_low_;
+        }
+        else
+          pc_high_ = ~0U;
+      }
+      else
+      {
+        pc_low_ = ~0U;
+        for (auto& r : ranges_.get ())
+        {
+          if (!r.end () && !r.empty () && r.addr1 () < pc_low_)
+            pc_low_ = r.addr1 ();
+        }
+        pc_high_ = 0U;
+        for (auto& r : ranges_.get ())
+        {
+          if (!r.end () && !r.empty () && r.addr2 () > pc_high_)
+            pc_high_ = r.addr2 ();
+        }
+      }
 
       if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
       {
@@ -512,8 +1301,8 @@ namespace rld
                   << rld::path::basename (name_)
                   << ": (0x" << std::setw (8) << offset_ << ") ";
         if (pc_low_ != 0 && pc_high_ != ~0U)
-          std::cout << "pc_low = " << std::setw (8) << pc_low_
-                    << " pc_high = " << std::setw (8) << pc_high_;
+          std::cout << "pc_low = 0x" << std::setw (8) << pc_low_
+                    << " pc_high = 0x" << std::setw (8) << pc_high_;
        std::cout  << std::setfill (' ') << std::dec
                   << std::endl
                   << " ] " << producer_
@@ -610,6 +1399,7 @@ namespace rld
         producer_ (orig.producer_),
         pc_low_ (orig.pc_low_),
         pc_high_ (orig.pc_high_),
+        ranges_ (orig.ranges_),
         die_offset (orig.die_offset),
         source_ (debug, die_offset)
     {
@@ -622,6 +1412,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;
+      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)
+        {
+          function func (debug, die);
+          if (func.has_machine_code () &&
+              func.pc_low () >= pc_low_ && func.pc_high () <= pc_high_)
+          {
+            functions_.push_back (func);
+          }
+        }
+
+        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
     {
@@ -669,15 +1511,15 @@ namespace rld
       return false;
     }
 
+    functions&
+    compilation_unit::get_functions ()
+    {
+      return functions_;
+    }
+
     bool
     compilation_unit::inside (dwarf_unsigned addr) const
     {
-      if (!addr_lines_.empty ())
-      {
-        auto first = addr_lines_.begin ();
-        auto last = addr_lines_.end () - 1;
-        return first->location () <= addr && addr <= last->location ();
-      }
       return addr >= pc_low_ && addr < pc_high_;
     }
 
@@ -700,11 +1542,20 @@ namespace rld
           addr_lines_.push_back (address (line, source_));
         pc_low_ = rhs.pc_low_;
         pc_high_ = rhs.pc_high_;
+        ranges_ = rhs.ranges_;
         die_offset = rhs.die_offset;
       }
       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 +1587,7 @@ namespace rld
     file::file ()
       : debug (nullptr),
         elf_ (nullptr)
-      {
+    {
     }
 
     file::~file ()
@@ -830,7 +1681,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 +1705,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,
@@ -898,6 +1763,27 @@ namespace rld
       return r;
     }
 
+    bool
+    file::get_function (const unsigned int addr,
+                        std::string&       name)
+    {
+      name = "unknown";
+
+      for (auto& cu : cus)
+      {
+        for (auto& func : cu.get_functions ())
+        {
+          if (func.inside (addr))
+          {
+            name = func.name ();
+            return true;
+          }
+        }
+      }
+
+      return false;
+    }
+
     void
     file::get_producer_sources (producer_sources& producers)
     {
diff --git a/rtemstoolkit/rld-dwarf.h b/rtemstoolkit/rld-dwarf.h
index 1207728..cfca9a6 100644
--- a/rtemstoolkit/rld-dwarf.h
+++ b/rtemstoolkit/rld-dwarf.h
@@ -114,6 +114,105 @@ 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;
+
+      /**
+       * Is the range the end?
+       */
+      bool end () const;
+
+      /**
+       * Is the range empty? See DWARF 2.17.3.
+       */
+      bool empty () 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 +249,6 @@ namespace rld
     public:
       sources (file& debug, dwarf_offset die_offset);
       sources (const sources& orig);
-      //sources (sources&& orig);
       ~sources ();
 
       /**
@@ -177,6 +275,88 @@ 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;
+
+      /**
+       * Does the function have machine code in the image?
+       */
+      bool has_machine_code () 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;
+
+      /**
+       * Is the address inside the function.
+       */
+      bool inside (dwarf_address addr) const;
+
+    private:
+
+      file&          debug;
+      bool           machine_code_;
+      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 +370,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.
@@ -211,6 +392,7 @@ namespace rld
        * Assignment operators.
        */
       debug_info_entry& operator = (debug_info_entry& rhs);
+      debug_info_entry& operator = (dwarf_offset offset);
 
       /**
        * Compare operators.
@@ -229,6 +411,32 @@ 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&          is_address,
+                       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 +465,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, bool newline = true);
+
     private:
 
       file&        debug;
@@ -271,6 +504,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 +532,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;
@@ -311,6 +570,11 @@ namespace rld
                        address&            addr_line);
 
       /**
+       * Get the functions.
+       */
+      functions& get_functions ();
+
+      /**
        * Is the address inside the CU? If the PC low and high attributes are
        * valid they are used or the lines are checked.
        */
@@ -321,19 +585,29 @@ 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.
       std::string    producer_;   ///< The producer of the CU.
       dwarf_unsigned pc_low_;     ///< The PC low address
       dwarf_unsigned pc_high_;    ///< The PC high address.
+      address_ranges ranges_;     ///< Non-continous address range.
 
       dwarf_offset   die_offset;  ///< The offset of the DIE in the image.
 
       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 +686,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,
@@ -419,6 +703,12 @@ namespace rld
                        int&               source_line);
 
       /**
+       * Get the function given an address.
+       */
+      bool get_function (const unsigned int address,
+                         std::string&       name);
+
+      /**
        * Get the producer sources from the compilation units.
        */
       void get_producer_sources (producer_sources& producers);



More information about the vc mailing list