[PATCH 3/5] rtemstoolkit/dwarf: C++ object relates fixes and a dump report.

Chris Johns chrisj at rtems.org
Mon Aug 6 00:43:20 UTC 2018


- Various C++ object fixes that improve stability where data from
  libdwarf is moving between object instances.
- Functions now provide better detail with inlined functions picking
  up attributes from an abstrtact DIE.
- Dump to a provide stream not stdout.
---
 rtemstoolkit/rld-dwarf.cpp | 504 +++++++++++++++++++++++++++++++++------------
 rtemstoolkit/rld-dwarf.h   | 122 +++++++++--
 2 files changed, 477 insertions(+), 149 deletions(-)

diff --git a/rtemstoolkit/rld-dwarf.cpp b/rtemstoolkit/rld-dwarf.cpp
index 9b92ec0..9cdd84a 100644
--- a/rtemstoolkit/rld-dwarf.cpp
+++ b/rtemstoolkit/rld-dwarf.cpp
@@ -82,7 +82,7 @@ namespace rld
         std::ostringstream exe_where;
         std::string        what;
         exe_where << "dwarf:" << where;
-        what = dwarf_errmsg (error);
+        what = ::dwarf_errmsg (error);
         throw rld::error (what, exe_where.str ());
       }
     }
@@ -299,7 +299,7 @@ namespace rld
     }
 
     void
-    range::dump ()
+    range::dump (std::ostream& out) const
     {
       dwarf_ranges_type type_ = type ();
       const char*       type_s = "invalid";
@@ -310,10 +310,11 @@ namespace rld
       };
       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 ();
+      out << type_s << '-'
+          << std::hex << std::setfill ('0')
+          << "0x" << std::setw (8) << addr1 ()
+          << ":0x" << std::setw (8) << addr2 ()
+          << std::dec << std::setfill (' ');
     }
 
     address_ranges::address_ranges (file& debug)
@@ -344,7 +345,9 @@ namespace rld
 
     address_ranges::address_ranges (const address_ranges& orig)
       : debug (orig.debug),
-        offset (orig.offset)
+        offset (orig.offset),
+        dranges (nullptr),
+        dranges_count (0)
     {
       load (orig.offset);
     }
@@ -392,6 +395,8 @@ namespace rld
         if (dranges != nullptr)
           ::dwarf_ranges_dealloc (debug, dranges, dranges_count);
 
+        ranges_.clear ();
+
         dranges = nullptr;
         dranges_count = 0;
 
@@ -444,18 +449,18 @@ namespace rld
     }
 
     void
-    address_ranges::dump ()
+    address_ranges::dump (std::ostream& out) const
     {
       bool first = true;
-      std::cout << '[';
+      out << '[';
       for (auto& r : ranges_)
       {
         if (!first)
-          std::cout << ',';
-        r.dump ();
+          out << ',';
+        r.dump (out);
         first = false;
       }
-      std::cout << ']';
+      out << ']';
     }
 
     line_addresses::line_addresses (file&             debug,
@@ -576,9 +581,12 @@ namespace rld
         external_ (false),
         declaration_ (false),
         inline_ (DW_INL_not_inlined),
+        entry_pc_ (0),
+        has_entry_pc_ (false),
         pc_low_ (0),
         pc_high_ (0),
-        ranges_ (debug)
+        ranges_ (debug),
+        call_line_ (0)
     {
       dwarf_bool db;
 
@@ -588,16 +596,18 @@ namespace rld
       if (die.attribute (DW_AT_declaration, db, false))
         declaration_ = db ? true : false;
 
+      if (die.attribute (DW_AT_entry_pc, entry_pc_, false))
+        has_entry_pc_ = true;
+
       die.attribute (DW_AT_linkage_name, linkage_name_, false);
+      die.attribute (DW_AT_call_file, decl_file_, false);
+      die.attribute (DW_AT_call_line, decl_line_, false);
+      die.attribute (DW_AT_call_file, call_file_, false);
+      die.attribute (DW_AT_call_line, call_line_, 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.
@@ -653,7 +663,17 @@ namespace rld
             {
               debug_info_entry abst_at_die (debug, abst_at_die_offset);
               if (abst_at_die.attribute (DW_AT_name, name_, false))
+              {
                 found = true;
+                abst_at_die.attribute (DW_AT_inline, inline_, false);
+                if (abst_at_die.attribute (DW_AT_external, db, false))
+                  external_ = db ? true : false;
+                if (abst_at_die.attribute (DW_AT_declaration, db, false))
+                  declaration_ = db ? true : false;
+                abst_at_die.attribute (DW_AT_linkage_name, linkage_name_, false);
+                abst_at_die.attribute (DW_AT_decl_file, decl_file_, false);
+                abst_at_die.attribute (DW_AT_decl_line, decl_line_, false);
+              }
             }
           }
 
@@ -675,36 +695,48 @@ namespace rld
               {
                 debug_info_entry spec_die (debug, spec_die_offset);
                 if (spec_die.attribute (DW_AT_name, name_, false))
+                {
                   found = true;
+                  if (spec_die.attribute (DW_AT_external, db, false))
+                    external_ = db ? true : false;
+                  if (spec_die.attribute (DW_AT_declaration, db, false))
+                    declaration_ = db ? true : false;
+                  spec_die.attribute (DW_AT_linkage_name, linkage_name_, false);
+                  spec_die.attribute (DW_AT_decl_file, decl_file_, false);
+                  spec_die.attribute (DW_AT_decl_line, decl_line_, false);
+                }
               }
             }
           }
         }
-
-        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 (' ');
+        dump (std::cout);
         std::cout << std::endl;
       }
     }
 
+    function::function (const function& orig)
+      : debug (orig.debug),
+        machine_code_ (orig.machine_code_),
+        external_ (orig.external_),
+        declaration_ (orig.declaration_),
+        inline_ (orig.inline_),
+        entry_pc_ (orig.entry_pc_),
+        has_entry_pc_ (orig.has_entry_pc_),
+        pc_low_ (orig.pc_low_),
+        pc_high_ (orig.pc_high_),
+        ranges_ (orig.ranges_),
+        name_ (orig.name_),
+        linkage_name_ (orig.linkage_name_),
+        call_file_ (orig.call_file_),
+        call_line_ (orig.call_line_)
+    {
+    }
+
     function::~function ()
     {
     }
@@ -724,28 +756,36 @@ namespace rld
     dwarf_unsigned
     function::pc_low () const
     {
-      if (ranges_.empty ())
-        return pc_low_;
-      dwarf_address addr = ~0;
-      for (auto& r : ranges_.get ())
+      dwarf_address addr = pc_low_;
+      if (!ranges_.empty ())
       {
-        if (!r.end () && !r.empty () && r.addr1 () < addr)
-          addr = r.addr1 ();
+        addr = ~0;
+        for (auto& r : ranges_.get ())
+        {
+          if (!r.end () && !r.empty () && r.addr1 () < addr)
+            addr = r.addr1 ();
+        }
       }
+      if (has_entry_pc_ && addr < entry_pc_)
+        addr += entry_pc_;
       return addr;
     }
 
     dwarf_unsigned
     function::pc_high () const
     {
-      if (ranges_.empty ())
-        return pc_high_;
-      dwarf_address addr = 0;
-      for (auto& r : ranges_.get ())
+      dwarf_address addr = pc_high_;
+      if (!ranges_.empty ())
       {
-        if (!r.end () && !r.empty () && r.addr2 () > addr)
-          addr = r.addr1 ();
+        addr = 0;
+        for (auto& r : ranges_.get ())
+        {
+          if (!r.end () && !r.empty () && r.addr2 () > addr)
+            addr = r.addr2 ();
+        }
       }
+      if (has_entry_pc_ && addr < entry_pc_)
+        addr += entry_pc_;
       return addr;
     }
 
@@ -770,7 +810,7 @@ namespace rld
     bool
     function::is_inlined () const
     {
-      return inline_ == DW_INL_declared_inlined;
+      return inline_ == DW_INL_inlined || inline_ == DW_INL_declared_inlined;
     }
 
     std::string
@@ -786,6 +826,97 @@ namespace rld
         addr >= pc_low () && addr <= pc_high ();
     }
 
+    size_t
+    function::size () const
+    {
+      size_t s = 0;
+      if (!name_.empty () && has_machine_code ())
+        s = pc_high () - pc_low ();
+      return s;
+    }
+
+    function&
+    function::operator = (const function& rhs)
+    {
+      if (this != &rhs)
+      {
+        debug = rhs.debug;
+        machine_code_ = rhs.machine_code_;
+        external_ = rhs.external_;
+        declaration_ = rhs.declaration_;
+        inline_ = rhs.inline_;
+        entry_pc_ = rhs.entry_pc_;
+        has_entry_pc_ = rhs.has_entry_pc_;
+        pc_low_ = rhs.pc_low_;
+        pc_high_ = rhs.pc_high_;
+        ranges_ = rhs.ranges_;
+        name_ = rhs.name_;
+        linkage_name_ = rhs.linkage_name_;
+        call_file_ = rhs.call_file_;
+      }
+      return *this;
+    }
+
+    void
+    function::dump (std::ostream& out) const
+    {
+      if (name_.empty ())
+        out << "NO-NAME";
+      else
+        out << name_;
+      out << " ["
+          << (char) (machine_code_ ? 'M' : '-')
+          << (char) (external_ ? 'E' : '-')
+          << (char) (declaration_ ? 'D' : '-')
+          << (char) (is_inlined () ? 'I' : '-')
+          << (char) (has_entry_pc_ ? 'P' : '-')
+          << "] size=" << size ()
+          << std::hex << std::setfill ('0')
+          << " (0x" << size () << ')';
+      if (has_entry_pc_)
+        out << " epc=0x" << entry_pc_;
+      out << " pc_low=0x" << pc_low_
+          << " pc_high=0x" << pc_high_;
+      if (!linkage_name_.empty ())
+        out << " ln=" << linkage_name_;
+      out << std::dec << std::setfill (' ');
+      if (!call_file_.empty ())
+        out << " cf=" << call_file_ << ':' << call_line_;
+      if (!ranges_.empty ())
+      {
+        out << " ranges=";
+        ranges_.dump (out);
+      }
+    }
+
+    bool
+    function_compare::operator () (const function& a,
+                                   const function& b) const
+    {
+      bool r = true;
+
+      switch (by)
+      {
+        case fc_by_name:
+        default:
+          r =  a.name () < b.name ();
+          break;
+        case fc_by_size:
+          r = a.size () < b.size ();
+          break;
+        case fc_by_address:
+          r = a.pc_low () < b.pc_low ();
+          break;
+      }
+
+      return r;
+    }
+
+    function_compare:: function_compare (const function_compare::sort_by by)
+      : by (by)
+    {
+    }
+
     debug_info_entry::debug_info_entry (file& debug)
       : debug (debug),
         die (nullptr),
@@ -800,6 +931,7 @@ namespace rld
         tag_ (0),
         offset_ (0)
     {
+      update ();
     }
 
     debug_info_entry::debug_info_entry (file& debug, dwarf_offset offset__)
@@ -808,12 +940,7 @@ 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;
+      update ();
     }
 
     debug_info_entry::debug_info_entry (const debug_info_entry& orig)
@@ -822,20 +949,48 @@ namespace rld
         tag_ (orig.tag_),
         offset_ (orig.offset_)
     {
-      if (offset_ != 0)
+      update ();
+    }
+
+    debug_info_entry::~debug_info_entry ()
+    {
+      dealloc ();
+    }
+
+    void
+    debug_info_entry::update ()
+    {
+      dwarf_error de;
+      int         dr;
+      if (offset_ == 0 && die != nullptr)
       {
-        dwarf_die   ddie;
-        dwarf_error de;
-        int         dr;
+        dr = ::dwarf_dieoffset (die, &offset_, &de);
+        libdwarf_error_check ("debug_info_entry:update", dr, de);
+      }
+      if (offset_ != 0 && die == nullptr)
+      {
+        dwarf_die ddie;
         dr = ::dwarf_offdie (debug, offset_, &ddie, &de);
-        libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de);
+        libdwarf_error_check ("debug_info_entry:update", dr, de);
         die = ddie;
       }
+      valid ();
     }
 
-    debug_info_entry::~debug_info_entry ()
+    bool
+    debug_info_entry::valid (bool fatal) const
     {
-      dealloc ();
+      bool r = die == nullptr || offset_ == 0;
+      if (r && fatal)
+      {
+        std::string what = "no DIE and offset";
+        if (offset_ != 0)
+          what = "no DIE";
+        else if (die != nullptr)
+          what = "no offset";
+        throw rld::error (what, "debug_info_entry:valid");
+      }
+      return r;
     }
 
     dwarf_die
@@ -867,6 +1022,8 @@ namespace rld
         tag_ = rhs.tag_;
         offset_ = rhs.offset_;
         rhs.die = nullptr;
+        if (offset_ != 0 || die != nullptr)
+          update ();
       }
       return *this;
     }
@@ -877,14 +1034,9 @@ namespace rld
       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;
+        update ();
       }
       return *this;
     }
@@ -910,7 +1062,7 @@ namespace rld
         dwarf_error de;
         int         dr;
         dr = ::dwarf_tag (die, &tag_, &de);
-        libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de);
+        libdwarf_error_check ("debug_info_entry:tag", dr, de);
       }
       return tag_;
     }
@@ -923,7 +1075,7 @@ namespace rld
         dwarf_error de;
         int         dr;
         dr = ::dwarf_dieoffset (die, &offset_, &de);
-        libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de);
+        libdwarf_error_check ("debug_info_entry:offset", dr, de);
       }
       return offset_;
     }
@@ -1057,26 +1209,55 @@ namespace rld
     bool
     debug_info_entry::get_child (debug_info_entry& child_die)
     {
+      debug_info_entry ret_die (get_debug ());
+      dwarf_error      de;
+      int              dr;
+      dr = ::dwarf_child (die, ret_die, &de);
+      if (dr == DW_DLV_OK)
+      {
+        ret_die.update ();
+        child_die = ret_die;
+        child_die.valid ();
+      }
+      return dr == DW_DLV_OK;
+    }
+
+    bool
+    debug_info_entry::has_child () const
+    {
+      debug_info_entry ret_die (get_debug ());
       dwarf_error      de;
       int              dr;
-      dr = ::dwarf_child (die, child_die, &de);
+      dr = ::dwarf_child (die, ret_die, &de);
       return dr == DW_DLV_OK;
     }
 
     bool
     debug_info_entry::get_sibling (debug_info_entry& sibling_die)
     {
+      debug_info_entry ret_die (get_debug ());
       dwarf_error      de;
       int              dr;
-      dr = ::dwarf_siblingof (debug, die, sibling_die, &de);
+      dr = ::dwarf_siblingof (debug, die, ret_die, &de);
       if (dr == DW_DLV_NO_ENTRY)
         return false;
       libdwarf_error_check ("compilation_unit::sibling", dr, de);
+      sibling_die = ret_die;
       return true;
     }
 
+    bool
+    debug_info_entry::has_sibling () const
+    {
+      debug_info_entry ret_die (get_debug ());
+      dwarf_error      de;
+      int              dr;
+      dr = ::dwarf_siblingof (debug, die, ret_die, &de);
+      return dr == DW_DLV_OK;
+    }
+
     file&
-    debug_info_entry::get_debug ()
+    debug_info_entry::get_debug () const
     {
       return debug;
     }
@@ -1091,11 +1272,32 @@ namespace rld
     }
 
     void
-    debug_info_entry::dump (std::string prefix, bool newline)
+    debug_info_entry::dump (std::ostream& out,
+                            std::string   prefix,
+                            bool          newline)
     {
+      std::string level_prefix;
+
+      for (auto c : prefix)
+      {
+        switch (c)
+        {
+          case '+':
+            c = '|';
+            break;
+          case '-':
+            c = ' ';
+            break;
+          default:
+            break;
+        }
+        level_prefix += c;
+      }
+
       const char* s;
       ::dwarf_get_TAG_name (tag (), &s);
-      std::cout << prefix << s << std::endl;
+      out << level_prefix.substr (0, level_prefix.length () - 1)
+          << "+- " << s << std::endl;
 
       dwarf_attribute* attributes;
       dwarf_signed     attr_count;
@@ -1117,8 +1319,9 @@ namespace rld
           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 << ']';
+            out << std::endl;
+          out << level_prefix << " +- "
+              << s << " (" << attr << ") [" << f << ']';
           debug_info_entry v_die (debug);
           address_ranges   v_ranges (debug);
           dwarf_unsigned   v_unsigned;
@@ -1139,11 +1342,20 @@ namespace rld
             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 << ')';
+              s = "";
+              switch (attr)
+              {
+                case DW_AT_inline:
+                  dwarf_get_INL_name(v_unsigned, &s);
+                  break;
+                default:
+                  break;
+              }
+              out << " : "
+                  << std::hex << std::setfill ('0')
+                  << std::setw (8) << v_unsigned
+                  << std::dec << std::setfill (' ')
+                  << " (" << v_unsigned << ") " << s;
               break;
             case DW_FORM_ref1:
             case DW_FORM_ref2:
@@ -1152,18 +1364,18 @@ namespace rld
             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 << ')';
+              out << " : "
+                  << 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);
+                  out << std::endl;
+                  v_die.dump (out, prefix + " |  ", false);
                   break;
                 default:
                   break;
@@ -1175,14 +1387,14 @@ namespace rld
             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;
+              out << " : " << 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;
+              out << " : " << s;
               break;
             case DW_FORM_sec_offset:
               switch (attr)
@@ -1190,9 +1402,9 @@ namespace rld
                 case DW_AT_ranges:
                   dr = ::dwarf_global_formref (attributes[a], &v_offset, &de);
                   libdwarf_error_check ("debug_info_entry::dump", dr, de);
-                  std::cout << ' ';
+                  out << ' ';
                   v_ranges.load (v_offset);
-                  v_ranges.dump ();
+                  v_ranges.dump (out);
                   break;
                 default:
                   break;
@@ -1206,38 +1418,39 @@ namespace rld
           }
         }
         if (newline)
-          std::cout << std::endl;
+          out <<  std::endl;
       }
     }
 
     void
-    die_dump_children (debug_info_entry die,
-                       std::string      prefix,
-                       int              nesting,
-                       int              depth)
+    die_dump_children (debug_info_entry& die,
+                       std::ostream&     out,
+                       std::string       prefix,
+                       int               depth,
+                       int               nesting)
     {
       debug_info_entry child (die.get_debug ());
       if (die.get_child (child))
-        die_dump (child, prefix, nesting, depth);
+        die_dump (child, out, prefix, depth, nesting);
     }
 
     void
-    die_dump (debug_info_entry die,
-              std::string      prefix,
-              int              nesting,
-              int              depth)
+    die_dump (debug_info_entry& die,
+              std::ostream&     out,
+              std::string       prefix,
+              int               depth,
+              int               nesting)
     {
       ++nesting;
 
-      for (int n = 0; n < nesting; ++n)
-        prefix += ' ';
-
       while (true)
       {
-        die.dump (prefix);
+        char v = die.has_sibling () || die.has_child () ? '+' : ' ';
+
+        die.dump (out, prefix + v);
 
         if (depth < 0 || nesting < depth)
-          die_dump_children (die, prefix);
+          die_dump_children (die, out, prefix + "+   ", depth, nesting);
 
         debug_info_entry next (die.get_debug ());
 
@@ -1422,12 +1635,9 @@ namespace rld
     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);
+      debug_info_entry child (debug);
+      if (die.get_child (child))
+        load_functions (child);
     }
 
     void
@@ -1440,27 +1650,18 @@ namespace rld
             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);
-          }
+          functions_.push_back (func);
         }
 
-        debug_info_entry ret_die (debug);
-        dwarf_error      de;
-        int              dr;
+        debug_info_entry next (die.get_debug ());
 
-        dr = ::dwarf_child(die, ret_die, &de);
-        if (dr == DW_DLV_OK)
-          load_functions (ret_die);
+        if (die.get_child (next))
+          load_functions (next);
 
-        dr = ::dwarf_siblingof (debug, die, ret_die, &de);
-        if (dr == DW_DLV_NO_ENTRY)
+        if (!die.get_sibling (next))
           break;
-        libdwarf_error_check ("compilation_unit:load_functions", dr, de);
 
-        die = ret_die;
+        die = next;
       }
     }
 
@@ -1549,11 +1750,13 @@ namespace rld
     }
 
     void
-    compilation_unit::dump_die ()
+    compilation_unit::dump_die (std::ostream&     out,
+                                const std::string prefix,
+                                int               depth)
     {
       debug_info_entry die (debug, die_offset);
-      std::cout << "CU @ 0x" << std::hex << offset_ << std::dec << std::endl;
-      die_dump_children (die, "");
+      out << "CU @ 0x" << std::hex << offset_ << std::dec << std::endl;
+      die_dump (die, out, prefix, depth);
     }
 
     source_flags::source_flags (const std::string& source)
@@ -1570,7 +1773,7 @@ namespace rld
       return a.source < b.source;
     }
 
-    source_flags_compare:: source_flags_compare (bool by_basename)
+    source_flags_compare::source_flags_compare (bool by_basename)
       : by_basename (by_basename)
     {
     }
@@ -1662,6 +1865,45 @@ namespace rld
       }
     }
 
+    void
+    file::dump (std::ostream&     out,
+                const std::string prefix,
+                int               depth)
+    {
+      dwarf_unsigned cu_offset = 0;
+
+      while (true)
+      {
+        dwarf_unsigned cu_next_offset = 0;
+        dwarf_error    de;
+        int            dr;
+
+        dr = ::dwarf_next_cu_header_c(debug, 1,
+                                      nullptr, nullptr, nullptr,  nullptr,
+                                      nullptr, nullptr, nullptr,  nullptr,
+                                      &cu_next_offset, &de);
+        if (dr != DW_DLV_OK)
+          break;
+
+        /*
+         * Find the CU DIE by asking the CU for it's first DIE.
+         */
+        debug_info_entry die (*this);
+
+        while (true)
+        {
+          debug_info_entry sibling (*this);
+          if (!die.get_sibling (sibling))
+            break;
+          if (sibling.tag () == DW_TAG_compile_unit)
+            die_dump (sibling, out, prefix, depth);
+          die = sibling;
+        }
+
+        cu_offset = cu_next_offset;
+      }
+    }
+
     void
     file::load_debug ()
     {
diff --git a/rtemstoolkit/rld-dwarf.h b/rtemstoolkit/rld-dwarf.h
index cfca9a6..d4e4c8a 100644
--- a/rtemstoolkit/rld-dwarf.h
+++ b/rtemstoolkit/rld-dwarf.h
@@ -25,6 +25,8 @@
 #if !defined (_RLD_DWARF_H_)
 #define _RLD_DWARF_H_
 
+#include <iostream>
+
 #include <rld.h>
 #include <rld-dwarf-types.h>
 
@@ -152,7 +154,7 @@ namespace rld
       /**
        * Dump the range.
        */
-      void dump ();
+      void dump (std::ostream& out) const;
 
     private:
 
@@ -201,7 +203,7 @@ namespace rld
       /**
        * Dump the address ranges.
        */
-      void dump ();
+      void dump (std::ostream& out) const;
 
     private:
 
@@ -281,6 +283,7 @@ namespace rld
     {
     public:
       function (file& debug, debug_info_entry& die);
+      function (const function& orig);
       ~function ();
 
       /**
@@ -339,23 +342,63 @@ namespace rld
        */
       bool inside (dwarf_address addr) const;
 
+      /**
+       * Size of the function.
+       */
+      size_t size () const;
+
+      /**
+       * Assigment operator.
+       */
+      function& operator = (const function& rhs);
+
+      /**
+       * Dump the function.
+       */
+      void dump (std::ostream& out) const;
+
     private:
 
       file&          debug;
       bool           machine_code_;
       bool           external_;
       bool           declaration_;
+      bool           prototyped_;
       dwarf_unsigned inline_;
+      dwarf_unsigned entry_pc_;
+      bool           has_entry_pc_;
       dwarf_unsigned pc_low_;
       dwarf_unsigned pc_high_;
       address_ranges ranges_;
       std::string    name_;
       std::string    linkage_name_;
+      std::string    decl_file_;
+      dwarf_unsigned decl_line_;
       std::string    call_file_;
+      dwarf_unsigned call_line_;
     };
 
     typedef std::vector < function > functions;
 
+    /**
+     * Worker to sort the functions.
+     */
+    struct function_compare
+    {
+      enum sort_by
+      {
+        fc_by_name,
+        fc_by_size,
+        fc_by_address
+      };
+
+      const sort_by by;
+
+      bool operator () (const function& a, const function& b) const;
+
+      function_compare (sort_by by = fc_by_name);
+    };
+
     /**
      * Debug Information Element (DIE).
      *
@@ -377,6 +420,11 @@ namespace rld
        */
       ~debug_info_entry ();
 
+      /**
+       * Is the DIE valid?
+       */
+      bool valid (bool fatal = true) const;
+
       /**
        * Get the DIE.
        */
@@ -474,15 +522,25 @@ namespace rld
        */
       bool get_child (debug_info_entry& child_die);
 
+      /**
+       * Has a child?
+       */
+      bool has_child () const;
+
       /**
        * Get the silbing
        */
       bool get_sibling (debug_info_entry& sibling_die);
 
+      /**
+       * Has a silbing?
+       */
+      bool has_sibling () const;
+
       /**
        * Get the debug info for this DIE.
        */
-      file& get_debug ();
+      file& get_debug () const;
 
       /**
        * deallocate the DIE.
@@ -492,10 +550,17 @@ namespace rld
       /**
        * Dump this DIE.
        */
-      void dump (std::string prefix, bool newline = true);
+      void dump (std::ostream& out,
+                 std::string   prefix,
+                 bool          newline = true);
 
     private:
 
+      /**
+       * Update the internal DIE and offset values.
+       */
+      void update ();
+
       file&        debug;
       dwarf_die    die;
       dwarf_tag    tag_;
@@ -506,18 +571,20 @@ 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);
+    void die_dump_children (debug_info_entry& die,
+                            std::ostream&     out,
+                            std::string       prefix,
+                            int               depth = -1,
+                            int               nesting = 0);
 
     /**
      * 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);
+    void die_dump (debug_info_entry& die,
+                   std::ostream&     out,
+                   std::string       prefix,
+                   int               depth = -1,
+                   int               nesting = 0);
 
     /**
      * Compilation Unit.
@@ -588,7 +655,9 @@ namespace rld
       /**
        * Output the DIE tree.
        */
-      void dump_die ();
+      void dump_die (std::ostream&     out,
+                     const std::string prefix = " ",
+                     int               depth = -1);
 
     private:
 
@@ -703,15 +772,25 @@ namespace rld
                        int&               source_line);
 
       /**
-       * Get the function given an address.
+       * Get the producer sources from the compilation units.
        */
-      bool get_function (const unsigned int address,
-                         std::string&       name);
+      void get_producer_sources (producer_sources& producers);
 
       /**
-       * Get the producer sources from the compilation units.
+       * Does the function exist.
        */
-      void get_producer_sources (producer_sources& producers);
+      bool function_valid (std::string&name);
+
+      /**
+       * Get the function given a name. Raises an exception if not found.
+       */
+      function& get_function (std::string& name);
+
+      /**
+       * Get the function given an address.
+       */
+      bool get_function (const unsigned int address,
+                         std::string&       name);
 
       /**
        * Get the DWARF debug information reference.
@@ -733,6 +812,13 @@ namespace rld
        */
       const std::string& name () const;
 
+      /**
+       * Dump the DWARF data.
+       */
+      void dump (std::ostream&     out,
+                 const std::string prefix = " ",
+                 int               depth = -1);
+
     private:
 
       /**
-- 
2.15.1




More information about the devel mailing list