[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