summaryrefslogtreecommitdiff
path: root/rtemstoolkit
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2018-05-11 06:12:27 +1200
committerChris Johns <chrisj@rtems.org>2018-06-18 12:26:16 +1000
commitd8eef0a463d4998d221ff318dd952dab18e5dfbf (patch)
treebf30a7ecbdf998a24e9393c1c83b603b04a3f057 /rtemstoolkit
parent1318c11e5df8ccc86383e4ce255e68f3279a94d8 (diff)
rtemstoolkit: Add DWARF function support.
Load the functions in each CU.
Diffstat (limited to 'rtemstoolkit')
-rw-r--r--rtemstoolkit/defaults.mc122
-rw-r--r--rtemstoolkit/elftoolchain/libdwarf/dwarf_die.c5
-rw-r--r--rtemstoolkit/rld-dwarf-types.h37
-rw-r--r--rtemstoolkit/rld-dwarf.cpp926
-rw-r--r--rtemstoolkit/rld-dwarf.h292
5 files changed, 1344 insertions, 38 deletions
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@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);