diff --git a/configure.ac b/configure.ac
index ad021de5..03ca50aa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,19 @@ LT_INIT
AC_LANG([C++])
AC_LANG_COMPILER_REQUIRE
+dnl Check for dependency: libdw (elfutils)
+DW_LIBS=
+AC_CHECK_LIB(dw, dwfl_begin, [DW_LIBS=-ldw])
+AC_CHECK_HEADER(elfutils/libdwfl.h,
+ [],
+ [AC_MSG_ERROR([could not find elfutils/libdwfl.h installed])])
+
+if test x$DW_LIBS = x; then
+ AC_MSG_ERROR([could not find elfutils dwarf library installed])
+fi
+
+AC_SUBST(DW_LIBS)
+
dnl Check for dependency: libxml
LIBXML2_VERSION=2.6.22
PKG_CHECK_MODULES(XML, libxml-2.0 >= $LIBXML2_VERSION)
@@ -59,7 +72,7 @@ AC_SUBST(LIBZIP_CFLAGS)
DEPS_CPPFLAGS="$XML_CFLAGS $LIBZIP_CFLAGS"
AC_SUBST(DEPS_CPPFLAGS)
-DEPS_LIBS="$XML_LIBS $LIBZIP_LIBS"
+DEPS_LIBS="$XML_LIBS $LIBZIP_LIBS $DW_LIBS"
AC_SUBST(DEPS_LIBS)
if test x$ABIGAIL_DEVEL != x; then
diff --git a/include/Makefile.am b/include/Makefile.am
index c8d590dc..76062b8d 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -2,6 +2,7 @@ headers = \
abg-ir.h \
abg-corpus.h \
abg-reader.h \
+abg-dwarf-reader.h \
abg-writer.h \
abg-comparison.h \
abg-diff-utils.h \
diff --git a/include/abg-dwarf-reader.h b/include/abg-dwarf-reader.h
new file mode 100644
index 00000000..2cef414e
--- /dev/null
+++ b/include/abg-dwarf-reader.h
@@ -0,0 +1,47 @@
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2013 Red Hat, Inc.
+//
+// This file is part of the GNU Application Binary Interface Generic
+// Analysis and Instrumentation Library (libabigail). This library is
+// free software; you can redistribute it and/or modify it under the
+// terms of the GNU Lesser General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option) any
+// later version.
+
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with this program; see the file COPYING-LGPLV3. If
+// not, see .
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This file contains the declarations of the entry points to
+/// de-serialize an instance of @ref corpus from a file in elf format,
+/// containing dwarf information.
+
+#include "abg-corpus.h"
+
+#ifndef __ABG_DWARF_READER_H__
+#define __ABG_DWARF_READER_H__
+
+namespace abigail
+{
+
+namespace dwarf_reader
+{
+
+corpus_sptr
+read_corpus_from_elf(const std::string& elf_path);
+
+}// end namespace dwarf_reader
+
+}// end namespace abigail
+
+#endif //__ABG_DWARF_READER_H__
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index d317e0bb..9b2b8ae8 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -31,6 +31,7 @@
#include
#include
#include // for std::rel_ops, at least.
+#include
#include "abg-hash.h"
/// Toplevel namespace for libabigail.
@@ -168,17 +169,35 @@ get_type_name(const shared_ptr);
shared_ptr
get_type_declaration(const shared_ptr);
+void
+dump(const shared_ptr, std::ostream&);
+
void
dump(const shared_ptr);
+void
+dump(const shared_ptr, std::ostream&);
+
void
dump(const shared_ptr);
+void
+dump(const shared_ptr, std::ostream&);
+
void
dump(const shared_ptr);
+void
+dump(const translation_unit&, std::ostream&);
+
void
dump(const translation_unit&);
+void
+dump(const shared_ptr, std::ostream&);
+
+void
+dump(const shared_ptr);
+
} // end namespace abigail
#endif // __ABG_IRFWD_H__
diff --git a/include/abg-ir.h b/include/abg-ir.h
index f4079817..5c6a672b 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -104,21 +104,18 @@ typedef std::vector translation_units;
/// into a translation unit.
class translation_unit : public traversable_base
{
-public:
+ struct priv;
+ typedef shared_ptr priv_sptr;
- /// Convenience typedef for a shared pointer on a @ref global_scope.
- typedef shared_ptr global_scope_sptr;
-
-private:
- std::string path_;
- location_manager loc_mgr_;
- mutable global_scope_sptr global_scope_;
+ priv_sptr priv_;
// Forbidden
translation_unit();
+public:
+ /// Convenience typedef for a shared pointer on a @ref global_scope.
+ typedef shared_ptr global_scope_sptr;
public:
-
translation_unit(const std::string& path);
virtual ~translation_unit();
@@ -141,6 +138,12 @@ public:
bool
is_empty() const;
+ shared_ptr
+ canonicalize_type(shared_ptr) const;
+
+ shared_ptr
+ canonicalize_type(shared_ptr) const;
+
void
traverse(ir_node_visitor& v);
};//end class translation_unit
diff --git a/src/Makefile.am b/src/Makefile.am
index 6ac394ad..95f7e676 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,6 +9,7 @@ $(h)/abg-corpus.cc \
$(h)/abg-diff-utils.cc \
$(h)/abg-comparison.cc \
$(h)/abg-reader.cc \
+$(h)/abg-dwarf-reader.cc \
$(h)/abg-libxml-utils.cc \
$(h)/abg-libzip-utils.cc \
$(h)/abg-hash.cc \
diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
new file mode 100644
index 00000000..0243d7a7
--- /dev/null
+++ b/src/abg-dwarf-reader.cc
@@ -0,0 +1,742 @@
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2013 Red Hat, Inc.
+//
+// This file is part of the GNU Application Binary Interface Generic
+// Analysis and Instrumentation Library (libabigail). This library is
+// free software; you can redistribute it and/or modify it under the
+// terms of the GNU Lesser General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option) any
+// later version.
+
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with this program; see the file COPYING-LGPLV3. If
+// not, see .
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This file contains the definitions of the entry points to
+/// de-serialize an instance of @ref corpus from a file in elf format,
+/// containing dwarf information.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "abg-dwarf-reader.h"
+
+using std::string;
+
+namespace abigail
+{
+
+namespace dwarf_reader
+{
+
+using std::tr1::dynamic_pointer_cast;
+using std::tr1::unordered_map;
+using std::stack;
+
+/// A functor used by @ref dwfl_sptr.
+struct dwfl_deleter
+{
+ void
+ operator()(Dwfl* dwfl)
+ {dwfl_end(dwfl);}
+};//end struct dwfl_deleter
+
+/// A convenience typedef for a shared pointer to a Dwfl.
+typedef shared_ptr dwfl_sptr;
+
+/// A map hashing functor for Dwarf_Die*.
+struct die_hash
+{
+ size_t
+ operator()(Dwarf_Die* die) const
+ {return std::hash()(die->addr);}
+};
+
+/// Convenience typedef for a map which key is a dwarf die, and which
+/// value is the corresponding decl_base.
+typedef unordered_map die_decl_map_type;
+
+/// Convenience typedef for a stack containing the scopes up to the
+/// current point in the abigail Internal Representation (aka IR) tree
+/// that is being built.
+typedef stack scope_stack_type;
+
+/// Convenience typedef for a map that contains the decls of the types
+/// that have been built so far. This is used to canonicalize the
+/// types we create so that only one copy of a given type remains in
+/// the system per translation unit, when that makes sense.
+typedef unordered_map type_decl_map;
+
+/// The context accumulated during the reading of dwarf debug info and
+/// building of the resulting ABI Corpus as a result.
+///
+/// This context is to be created by the top-most function that wants
+/// to read debug info and build an ABI corpus from it. It's then
+/// passed to all the routines that read specific dwarf bits as they
+/// get some important data from it.
+class read_context
+{
+ dwfl_sptr handle_;
+ const string elf_path_;
+ die_decl_map_type die_decl_map_;
+ corpus_sptr cur_corpus_;
+ translation_unit_sptr cur_tu_;
+ scope_stack_type scope_stack_;
+
+ read_context();
+
+public:
+ read_context(dwfl_sptr handle,
+ const string& elf_path)
+ : handle_(handle),
+ elf_path_(elf_path)
+ {}
+
+ dwfl_sptr
+ dwfl_handle()
+ {return handle_;}
+
+ const string&
+ elf_path() const
+ {return elf_path_;}
+
+ const die_decl_map_type&
+ die_decl_map() const
+ {return die_decl_map_;}
+
+ die_decl_map_type&
+ die_decl_map()
+ {return die_decl_map_;}
+
+ const corpus_sptr
+ current_corpus() const
+ {return cur_corpus_;}
+
+ corpus_sptr
+ current_corpus()
+ {return cur_corpus_;}
+
+ void
+ current_corpus(corpus_sptr c)
+ {
+ if (c)
+ cur_corpus_ = c;
+ }
+
+ void
+ reset_current_corpus()
+ {cur_corpus_.reset();}
+
+ const translation_unit_sptr
+ current_translation_unit() const
+ {return cur_tu_;}
+
+ translation_unit_sptr
+ current_translation_unit()
+ {return cur_tu_;}
+
+ void
+ current_translation_unit(translation_unit_sptr tu)
+ {
+ if (tu)
+ cur_tu_ = tu;
+ }
+
+ const scope_stack_type&
+ scope_stack() const
+ {return scope_stack_;}
+
+ scope_stack_type&
+ scope_stack()
+ {return scope_stack_;}
+
+ scope_decl_sptr
+ current_scope()
+ {
+ if (scope_stack().empty())
+ {
+ if (current_translation_unit())
+ scope_stack().push(current_translation_unit()->get_global_scope());
+ }
+ return scope_stack().top();
+ }
+};// end class read_context.
+
+static decl_base_sptr
+build_ir_node_from_die(read_context& ctxt,
+ Dwarf_Die* die);
+
+/// Constructor for a default Dwfl handle that knows how to load debug
+/// info from a library or executable elf file.
+///
+/// @return the constructed Dwfl handle.
+static Dwfl*
+create_default_dwfl()
+{
+ static const Dwfl_Callbacks offline_callbacks =
+ {
+ 0,
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .section_address = dwfl_offline_section_address,
+ 0
+ };
+
+ return dwfl_begin(&offline_callbacks);
+}
+
+
+/// Create a shared pointer for a pointer to Dwfl.
+///
+/// @param dwlf the pointer to Dwfl to create the shared pointer for.
+///
+/// @return the newly created shared pointer.
+static dwfl_sptr
+create_dwfl_sptr(Dwfl* dwfl)
+{
+ dwfl_sptr result(dwfl, dwfl_deleter());
+ return result;
+}
+
+/// Create a shared pointer to a default Dwfl handle. This uses the
+/// create_default_dwfl() function.
+///
+/// @return the created shared pointer.
+static dwfl_sptr
+create_default_dwfl_sptr()
+{return create_dwfl_sptr(create_default_dwfl());}
+
+/// Load the debug info associated with an elf file that is at a given
+/// path. To do so, we need a handle to the DWARF Front End Library
+/// as it's that library that is going to do the heavy work.
+///
+/// @param handle a smart pointer to the DWARF Front End Library
+/// handle. This can be created by the function
+/// create_default_dwfl_sptr().
+///
+/// @param elf_path the path to the elf file to load the debug info
+/// from.
+///
+/// @return true upon successful debug info loading, false otherwise.
+static bool
+load_debug_info_from_elf(dwfl_sptr handle,
+ const string& elf_path)
+{
+ if (!handle)
+ return false;
+
+ Dwfl_Module* module =
+ dwfl_report_offline(handle.get(),
+ basename(const_cast(elf_path.c_str())),
+ elf_path.c_str(),
+ -1);
+ dwfl_report_end(handle.get(), 0, 0);
+
+ Dwarf_Addr bias = 0;
+ if (dwfl_module_getdwarf(module, &bias) == 0)
+ return false;
+
+ return true;
+}
+
+/// Get the value of an attribute that is supposed to be a string, or
+/// an empty string if the attribute could not be found.
+///
+/// @param die the DIE to get the attribute value from.
+///
+/// @param attr_name the attribute name. Must come from dwarf.h and
+/// be an enumerator representing an attribute like, e.g, DW_AT_name.
+///
+/// @return a the string representing the value of the attribute, or
+/// an empty string if no string attribute could be found.
+static string
+die_string_attribute(Dwarf_Die* die, unsigned attr_name)
+{
+ if (!die)
+ return "";
+
+ Dwarf_Attribute attr;
+ if (!dwarf_attr(die, attr_name, &attr))
+ return "";
+
+ const char* str = dwarf_formstring(&attr);
+ return str ? str : "";
+}
+
+/// Get the value of an attribute that is supposed to be an unsigned
+/// constant.
+///
+/// @param attr_name the DW_AT_* name of the attribute. Must come
+/// from dwarf.h and be an enumerator representing an attribute like,
+/// e.g, DW_AT_decl_line.
+static bool
+die_unsigned_constant_attribute(Dwarf_Die* die,
+ unsigned attr_name,
+ size_t& cst)
+{
+ if (!die)
+ return false;
+
+ Dwarf_Attribute attr;
+ Dwarf_Word result = 0;
+ if (!dwarf_attr(die, attr_name, &attr)
+ || dwarf_formudata(&attr, &result))
+ return false;
+
+ cst = result;
+ return true;
+}
+
+#if 0
+static bool
+die_signed_constant_attribute(Dwarf_Die* die,
+ unsigned attr_name,
+ ssize_t& cst)
+{
+ if (!die)
+ return false;
+
+ Dwarf_Attribute attr;
+ Dwarf_Sword result = 0;
+ if (!dwarf_attr(die, attr_name, &attr)
+ || dwarf_formsdata(&attr, &result))
+ return false;
+
+ cst = result;
+ return true;
+}
+#endif
+
+/// Get the mangled name from a given DIE.
+///
+/// @param die the DIE to read the mangled name from.
+///
+/// @return the mangled name if it's present in the DIE, or just an
+/// empty string if it's not.
+static string
+die_mangled_name(Dwarf_Die* die)
+{
+ if (!die)
+ return "";
+
+ string mangled_name = die_string_attribute(die, DW_AT_linkage_name);
+ if (mangled_name.empty())
+ mangled_name = die_string_attribute(die, DW_AT_MIPS_linkage_name);
+ return mangled_name;
+}
+
+/// Get the file path that is the value of the DW_AT_decl_file
+/// attribute on a given DIE, if the DIE is a decl DIE having that
+/// attribute.
+///
+/// @param die the DIE to consider.
+///
+/// @return a string containing the file path that is the logical
+/// value of the DW_AT_decl_file attribute. If the DIE @ref die
+/// doesn't have a DW_AT_decl_file attribute, then the return value is
+/// just an empty string.
+static string
+die_decl_file_attribute(Dwarf_Die* die)
+{
+ if (!die)
+ return "";
+
+ const char* str = dwarf_decl_file(die);
+
+ return str ? str : "";
+}
+
+/// Get the value of an attribute which value is supposed to be a
+/// reference to a DIE.
+///
+/// @param die the DIE to read the value from.
+///
+/// @param the DW_AT_* attribute name to read.
+///
+/// @param result the DIE resulting from reading the attribute value.
+/// This is set iff the function returns true.
+///
+/// @return true if the DIE @ref die contains an attribute named @ref
+/// attr_name that is a DIE reference, false otherwise.
+static bool
+die_die_attribute(Dwarf_Die* die, unsigned attr_name, Dwarf_Die& result)
+{
+ Dwarf_Attribute attr;
+ if (!dwarf_attr(die, attr_name, &attr))
+ return false;
+ return dwarf_formref_die(&attr, &result);
+}
+
+/// Returns the source location associated with a decl DIE.
+///
+/// @param ctxt the @ref read_context to use.
+///
+/// @param die the DIE the read the source location from.
+static location
+die_location(read_context& ctxt, Dwarf_Die* die)
+{
+ if (!die)
+ return location();
+
+ string file = die_decl_file_attribute(die);
+ size_t line = 0;
+ die_unsigned_constant_attribute(die, DW_AT_decl_line, line);
+
+ translation_unit_sptr tu = ctxt.current_translation_unit();
+ location l = tu->get_loc_mgr().create_new_location(file, line, 1);
+ return l;
+}
+
+/// Given a DW_TAG_compile_unit, build and return the corresponding
+/// abigail::translation_unit ir node.
+///
+/// @param ctxt the read_context to use.
+///
+/// @param die the DW_TAG_compile_unit DIE to consider.
+///
+/// @param recurse if set to yes, this function recursively reads the
+/// children dies of @ref die and populate the resulting translation
+/// unit.
+///
+/// @return a pointer to the resulting translation_unit.
+static translation_unit_sptr
+build_translation_unit(read_context& ctxt,
+ Dwarf_Die* die,
+ bool recurse = false)
+{
+ translation_unit_sptr result;
+
+ if (!die)
+ return result;
+ assert(dwarf_tag(die) == DW_TAG_compile_unit);
+
+ string path = die_string_attribute(die, DW_AT_name);
+ result.reset(new translation_unit(path));
+
+ ctxt.current_corpus()->add(result);
+ ctxt.current_translation_unit(result);
+
+ Dwarf_Die child;
+ if (!recurse
+ || (dwarf_child(die, &child) != 0))
+ return result;
+
+ do
+ build_ir_node_from_die(ctxt, &child);
+ while (dwarf_siblingof(&child, &child) == 0);
+
+ return result;
+}
+
+/// Build a @ref type_decl out of a DW_TAG_base_type DIE.
+///
+/// @param die the DW_TAG_base_type to consider.
+///
+/// @return the resulting decl_base_sptr.
+static type_decl_sptr
+build_type_decl(read_context& /*ctxt*/,
+ Dwarf_Die* die)
+{
+ type_decl_sptr result;
+
+ if (!die)
+ return result;
+ assert(dwarf_tag(die) == DW_TAG_base_type);
+
+ string type_name = die_string_attribute(die, DW_AT_name);
+ size_t byte_size = 0, bit_size = 0;
+ if (!die_unsigned_constant_attribute(die, DW_AT_byte_size, byte_size))
+ if (!die_unsigned_constant_attribute(die, DW_AT_bit_size, bit_size))
+ return result;
+
+ if (byte_size == 0 && bit_size == 0)
+ return result;
+
+ if (bit_size == 0)
+ bit_size = byte_size * 8;
+
+ size_t alignment = bit_size < 8 ? 8 : bit_size;
+ string mangled_name = die_mangled_name(die);
+
+ result.reset(new type_decl(type_name, bit_size, alignment,
+ location(), mangled_name));
+ return result;
+}
+
+/// Build a @ref var_decl out of a DW_TAG_variable DIE.
+///
+/// @param ctxt the read context to use.
+///
+/// @param die the DIE to read from to build the @ref var_decl.
+///
+/// @return a pointer to the newly created var_decl. If the var_decl
+/// could not be built, this function returns NULL.
+static var_decl_sptr
+build_var_decl(read_context& ctxt,
+ Dwarf_Die *die)
+{
+ var_decl_sptr result;
+
+ if (!die)
+ return result;
+ assert(dwarf_tag(die) == DW_TAG_variable);
+
+ type_base_sptr type;
+ Dwarf_Die type_die;
+ if (die_die_attribute(die, DW_AT_type, type_die))
+ {
+ decl_base_sptr ty = build_ir_node_from_die(ctxt, &type_die);
+ if (!ty)
+ return result;
+ type = is_type(ty);
+ assert(type);
+ }
+
+ string name = die_string_attribute(die, DW_AT_name);
+ string mangled_name = die_mangled_name(die);
+ location loc = die_location(ctxt, die);
+
+ result.reset(new var_decl(name, type, loc, mangled_name));
+
+ return result;
+}
+
+/// Read all @ref translation_unit possible from the debug info
+/// accessible through a DWARF Front End Library handle, and stuff
+/// them into a libabigail ABI Corpus.
+///
+/// @param ctxt the read context.
+///
+/// @return a pointer to the resulting corpus, or NULL if the corpus
+/// could not be constructed.
+static corpus_sptr
+build_corpus(read_context& ctxt)
+{
+ Dwarf_Die *cu = 0;
+
+ Dwarf_Addr bias = 0;
+
+ while ((cu = dwfl_nextcu(ctxt.dwfl_handle().get(), cu, &bias)))
+ {
+ if (!ctxt.current_corpus())
+ {
+ corpus_sptr corp (new corpus(ctxt.elf_path()));
+ ctxt.current_corpus(corp);
+ }
+
+ // Build a translation_unit IR node from cu; note that cu must
+ // be a DW_TAG_compile_unit die.
+ translation_unit_sptr ir_node = build_translation_unit(ctxt, cu,
+ /*recurse=*/true);
+ assert(ir_node);
+ }
+ return ctxt.current_corpus();
+}
+/// Build an IR node from a given DIE and add the node to the current
+/// IR being build and held in the read_context.
+///
+/// @param ctxt the read context.
+///
+/// @parm die the DIE to consider.
+///
+/// @return the resulting IR node.
+static decl_base_sptr
+build_ir_node_from_die(read_context& ctxt,
+ Dwarf_Die* die)
+{
+ decl_base_sptr result;
+
+ if (!die)
+ return result;
+
+ die_decl_map_type::const_iterator it = ctxt.die_decl_map().find(die);
+ if (it != ctxt.die_decl_map().end())
+ return it->second;
+
+ int tag = dwarf_tag(die);
+ switch (tag)
+ {
+ // Type DIEs we intent to support someday, maybe.
+ case DW_TAG_base_type:
+ if((result = build_type_decl(ctxt, die)))
+ {
+ result = ctxt.current_translation_unit()->canonicalize_type(result);
+ assert(result);
+
+ if (result->get_scope())
+ // This base type is the same as a type that was already added
+ // to the IR tree. Do not add a new one. Just re-use the
+ // previous one.
+ ;
+ else
+ add_decl_to_scope(result, ctxt.current_scope());
+ }
+ break;
+ case DW_TAG_typedef:
+ break;
+ case DW_TAG_pointer_type:
+ break;
+ case DW_TAG_reference_type:
+ break;
+ case DW_TAG_rvalue_reference_type:
+ break;
+ case DW_TAG_const_type:
+ break;
+ case DW_TAG_volatile_type:
+ break;
+ case DW_TAG_enumeration_type:
+ break;
+ case DW_TAG_class_type:
+ break;
+ case DW_TAG_string_type:
+ break;
+ case DW_TAG_structure_type:
+ break;
+ case DW_TAG_subroutine_type:
+ break;
+ case DW_TAG_union_type:
+ break;
+ case DW_TAG_array_type:
+ break;
+ case DW_TAG_packed_type:
+ break;
+ case DW_TAG_set_type:
+ break;
+ case DW_TAG_file_type:
+ break;
+ case DW_TAG_ptr_to_member_type:
+ break;
+ case DW_TAG_subrange_type:
+ break;
+ case DW_TAG_thrown_type:
+ break;
+ case DW_TAG_restrict_type:
+ break;
+ case DW_TAG_interface_type:
+ break;
+ case DW_TAG_unspecified_type:
+ break;
+ case DW_TAG_mutable_type:
+ break;
+ case DW_TAG_shared_type:
+ break;
+
+ // Other declarations we intend to support someday, maybe.
+
+ case DW_TAG_compile_unit:
+ // We shouldn't reach this point b/c this should be handled by
+ // build_translation_unit.
+ abort();
+ break;
+
+ case DW_TAG_namespace:
+ break;
+ case DW_TAG_variable:
+ if ((result = build_var_decl(ctxt, die)))
+ add_decl_to_scope(result, ctxt.current_scope());
+ break;
+ case DW_TAG_subprogram:
+ break;
+ case DW_TAG_formal_parameter:
+ break;
+ case DW_TAG_constant:
+ break;
+ case DW_TAG_enumerator:
+ break;
+
+ // Other declaration we don't really intend to support.
+ case DW_TAG_dwarf_procedure:
+ case DW_TAG_imported_declaration:
+ case DW_TAG_entry_point:
+ case DW_TAG_label:
+ case DW_TAG_lexical_block:
+ case DW_TAG_member:
+ case DW_TAG_unspecified_parameters:
+ case DW_TAG_variant:
+ case DW_TAG_common_block:
+ case DW_TAG_common_inclusion:
+ case DW_TAG_inheritance:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_module:
+ case DW_TAG_with_stmt:
+ case DW_TAG_access_declaration:
+ case DW_TAG_catch_block:
+ case DW_TAG_friend:
+ case DW_TAG_namelist:
+ case DW_TAG_namelist_item:
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ case DW_TAG_try_block:
+ case DW_TAG_variant_part:
+ case DW_TAG_imported_module:
+ case DW_TAG_partial_unit:
+ case DW_TAG_imported_unit:
+ case DW_TAG_condition:
+ case DW_TAG_type_unit:
+ case DW_TAG_template_alias:
+ case DW_TAG_lo_user:
+ case DW_TAG_MIPS_loop:
+ case DW_TAG_format_label:
+ case DW_TAG_function_template:
+ case DW_TAG_class_template:
+ case DW_TAG_GNU_BINCL:
+ case DW_TAG_GNU_EINCL:
+ case DW_TAG_GNU_template_template_param:
+ case DW_TAG_GNU_template_parameter_pack:
+ case DW_TAG_GNU_formal_parameter_pack:
+ case DW_TAG_GNU_call_site:
+ case DW_TAG_GNU_call_site_parameter:
+ case DW_TAG_hi_user:
+ default:
+ break;
+ }
+
+ if (result)
+ ctxt.die_decl_map()[die] = result;
+
+ return result;
+}
+
+/// Read all @ref translation_unit possible from the debug info
+/// accessible from an elf file, stuff them into a libabigail ABI
+/// Corpus and return it.
+///
+/// @param elf_path the path to the elf file.
+///
+/// @return a pointer to the resulting @ref corpus.
+corpus_sptr
+read_corpus_from_elf(const std::string& elf_path)
+{
+ // Create a DWARF Front End Library handle to be used by functions
+ // of that library.
+ dwfl_sptr handle = create_default_dwfl_sptr();
+
+ // Load debug info from the elf path.
+ if (!load_debug_info_from_elf(handle, elf_path))
+ return corpus_sptr();
+
+ read_context ctxt(handle, elf_path);
+
+ // Now, read an ABI corpus proper from the debug info we have
+ // through the dwfl handle.
+ corpus_sptr corp = build_corpus(ctxt);
+
+ return corp;
+}
+
+}// end namespace dwarf_reader
+
+}// end namespace abigail
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index c7b87c77..7e6102d6 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include "abg-ir.h"
namespace abigail
@@ -37,6 +38,7 @@ namespace abigail
using std::string;
using std::list;
using std::vector;
+using std::tr1::unordered_map;
using std::tr1::dynamic_pointer_cast;
using std::tr1::static_pointer_cast;
@@ -141,13 +143,28 @@ location_manager::expand_location(const location location,
column = l.column_;
}
+typedef unordered_map,
+ bool,
+ type_base::shared_ptr_hash,
+ type_shared_ptr_equal> type_ptr_map;
+
+/// Private type to hold private members of @ref translation_unit
+struct translation_unit::priv
+{
+ std::string path_;
+ location_manager loc_mgr_;
+ mutable global_scope_sptr global_scope_;
+ type_ptr_map canonical_types_;
+}; // end translation_unit::priv
+
+//
+
/// Constructor of translation_unit.
///
/// @param path the location of the translation unit.
translation_unit::translation_unit(const std::string& path)
- : path_ (path)
-{
-}
+ : priv_(new priv)
+{priv_->path_ = path;}
/// Getter of the the global scope of the translation unit.
///
@@ -157,18 +174,17 @@ translation_unit::translation_unit(const std::string& path)
const shared_ptr
translation_unit::get_global_scope() const
{
- if (!global_scope_)
- global_scope_.reset(new global_scope(const_cast(this)));
- return global_scope_;
+ if (!priv_->global_scope_)
+ priv_->global_scope_.reset
+ (new global_scope(const_cast(this)));
+ return priv_->global_scope_;
}
/// @return the path of the compilation unit associated to the current
/// instance of translation_unit.
const std::string&
translation_unit::get_path() const
-{
- return path_;
-}
+{return priv_->path_;}
/// Set the path associated to the current instance of
/// translation_unit.
@@ -176,9 +192,7 @@ translation_unit::get_path() const
/// @param a_path the new path to set.
void
translation_unit::set_path(const string& a_path)
-{
- path_ = a_path;
-}
+{priv_->path_ = a_path;}
/// Getter of the location manager for the current translation unit.
///
@@ -186,7 +200,7 @@ translation_unit::set_path(const string& a_path)
/// translation unit.
location_manager&
translation_unit::get_loc_mgr()
-{return loc_mgr_;}
+{return priv_->loc_mgr_;}
/// const Getter of the location manager.
///
@@ -194,7 +208,7 @@ translation_unit::get_loc_mgr()
/// translation unit.
const location_manager&
translation_unit::get_loc_mgr() const
-{return loc_mgr_;}
+{return priv_->loc_mgr_;}
/// Tests whether if the current translation unit contains ABI
/// artifacts or not.
@@ -204,6 +218,59 @@ bool
translation_unit::is_empty() const
{return get_global_scope()->is_empty();}
+/// If the current translation_unit "knows" about a type T' that is
+/// equivalent to a given T, then this method returns T' when passed
+/// T. Otherwise, the function stores T, so that next time it sees a
+/// T'', it can say that it is equivalent to T and then return that T.
+///
+/// In other words, this methods can be used to help enforce that if
+/// we build two types that are equivalent at the same scope then we
+/// can decide to just keep one.
+///
+/// @param t the type to canonicalize.
+///
+/// @return the canonical type for @ref t.
+type_base_sptr
+translation_unit::canonicalize_type(type_base_sptr t) const
+{
+ if (!t)
+ return t;
+
+ type_ptr_map::iterator e =
+ priv_->canonical_types_.find(t);
+
+ if (e == priv_->canonical_types_.end())
+ {
+ priv_->canonical_types_[t] = true;
+ return t;
+ }
+ return e->first;
+}
+
+/// Canonicalize the type of a given type declaration.
+///
+/// To understand more about type canonicalization, please read the
+/// API doc of the overload of this function that takes a @ref
+/// type_base_sptr.
+///
+/// @param t the type declaration to return a canonical type
+/// declaration for.
+///
+/// @return the declaration for the canonical type of the type for
+/// @ref t.
+decl_base_sptr
+translation_unit::canonicalize_type(decl_base_sptr t) const
+{
+ type_base_sptr type = is_type(t);
+
+ if (!type)
+ return t;
+
+ type = canonicalize_type(type);
+ assert(type);
+
+ return get_type_declaration(type);
+}
/// This implements the traversable_base::traverse pure virtual
/// function.
///
@@ -216,6 +283,8 @@ translation_unit::traverse(ir_node_visitor& v)
translation_unit::~translation_unit()
{}
+//
+
//
decl_base::decl_base(const std::string& name, location locus,
diff --git a/src/abg-writer.cc b/src/abg-writer.cc
index 950605ec..7d62d3c0 100644
--- a/src/abg-writer.cc
+++ b/src/abg-writer.cc
@@ -1780,45 +1780,102 @@ write_corpus_to_archive(const corpus_sptr corp)
//
+/// Serialize a pointer to decl_base to an output stream.
+///
+/// @param d the pointer to decl_base to serialize.
+///
+/// @param o the output stream to consider.
+void
+dump(const decl_base_sptr d, std::ostream& o)
+{
+ xml_writer::write_context ctxt(o);
+ write_decl(d, ctxt, /*indent=*/0);
+ cerr << "\n";
+}
+
/// Serialize a pointer to decl_base to stderr.
///
/// @param d the pointer to decl_base to serialize.
void
dump(const decl_base_sptr d)
-{
- xml_writer::write_context ctxt(cerr);
- write_decl(d, ctxt, /*indent=*/0);
- cerr << "\n";
-}
+{dump(d, cerr);}
+
+/// Serialize a pointer to type_base to an output stream.
+///
+/// @param t the pointer to type_base to serialize.
+///
+/// @param o the output stream to serialize the @ref type_base to.
+void
+dump(const type_base_sptr t, std::ostream& o)
+{dump(get_type_declaration(t), o);}
/// Serialize a pointer to type_base to stderr.
///
/// @param t the pointer to type_base to serialize.
void
dump(const type_base_sptr t)
-{return dump(dynamic_pointer_cast(t));}
+{dump(t, cerr);}
+
+/// Serialize a pointer to var_decl to an output stream.
+///
+/// @param v the pointer to var_decl to serialize.
+///
+/// @param o the output stream to serialize the @ref var_decl to.
+void
+dump(const var_decl_sptr v, std::ostream& o)
+{
+ xml_writer::write_context ctxt(o);
+ write_var_decl(v, ctxt, /*mangled_name*/true, /*indent=*/0);
+ cerr << "\n";
+}
/// Serialize a pointer to var_decl to stderr.
///
/// @param v the pointer to var_decl to serialize.
void
dump(const var_decl_sptr v)
-{
- xml_writer::write_context ctxt(cerr);
- write_var_decl(v, ctxt, /*mangled_name*/true, /*indent=*/0);
- cerr << "\n";
-}
+{dump(v, cerr);}
-/// Serialize an instance of translation_unit to stderr.
+/// Serialize a @ref translation_unit to an output stream.
///
/// @param t the translation_unit to serialize.
+///
+/// @param o the outpout stream to serialize the translation_unit to.
void
-dump(const translation_unit& t)
+dump(const translation_unit& t, std::ostream& o)
{
- xml_writer::write_context ctxt(cerr);
+ xml_writer::write_context ctxt(o);
write_translation_unit(t, ctxt, /*indent=*/0);
cerr << "\n";
}
+/// Serialize an instance of @ref translation_unit to stderr.
+///
+/// @param t the translation_unit to serialize.
+void
+dump(const translation_unit& t)
+{dump(t, cerr);}
+
+/// Serialize a pointer to @ref translation_unit to an output stream.
+///
+/// @param t the @ref translation_unit_sptr to serialize.
+///
+/// @param o the output stream to serialize the translation unit to.
+void
+dump(const translation_unit_sptr t, std::ostream& o)
+{
+ if (t)
+ dump(*t, o);
+}
+
+/// Serialize a pointer to @ref translation_unit to stderr.
+///
+/// @param t the translation_unit_sptr to serialize.
+void
+dump(const translation_unit_sptr t)
+{
+ if (t)
+ dump(*t);
+}
//
} //end namespace abigail
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 00bd21d3..b463b1ef 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -7,7 +7,7 @@ libtoolsutils_la_SOURCES= \
$(h)/abg-tools-utils.h \
$(h)/abg-tools-utils.cc
-bin_PROGRAMS = biar bidiff bilint
+bin_PROGRAMS = biar bidiff bilint bidw
biar_SOURCES = $(h)/biar.cc
biardir = $(bindir)
biar_LDFLAGS = $(abs_top_builddir)/src/libabigail.la $(abs_top_builddir)/tools/libtoolsutils.la
@@ -23,4 +23,9 @@ bilintdir = $(bindir)
bilint_LDFLAGS = $(abs_top_builddir)/src/libabigail.la $(abs_top_builddir)/tools/libtoolsutils.la
bilint_DEPENDENCIES = libtoolsutils.la
+bidw_SOURCES = $(h)/bidw.cc
+bidwdir = $(bindir)
+bidw_LDFLAGS = $(abs_top_builddir)/src/libabigail.la $(abs_top_builddir)/tools/libtoolsutils.la
+bidw_DEPENDENCIES = libtoolsutils.la
+
AM_CPPFLAGS=-I$(abs_top_srcdir)/include -I$(abs_top_srcdir)/tools
diff --git a/tools/bidw.cc b/tools/bidw.cc
new file mode 100644
index 00000000..50e43506
--- /dev/null
+++ b/tools/bidw.cc
@@ -0,0 +1,135 @@
+// -*- Mode: C++ -*-
+//
+// Copyright (C) 2013 Red Hat, Inc.
+//
+// This file is part of the GNU Application Binary Interface Generic
+// Analysis and Instrumentation Library (libabigail). This library is
+// free software; you can redistribute it and/or modify it under the
+// terms of the GNU Lesser General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option) any
+// later version.
+
+// This library is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Lesser Public License for more details.
+
+// You should have received a copy of the GNU Lesser General Public
+// License along with this program; see the file COPYING-LGPLV3. If
+// not, see .
+//
+// Author: Dodji Seketeli
+
+/// @file
+///
+/// This program reads an elf file, try to load its debug info (in
+/// DWARF format) and emit it back in a set of "text sections" in native
+/// libabigail XML format.
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "abg-tools-utils.h"
+#include "abg-corpus.h"
+#include "abg-dwarf-reader.h"
+
+using std::string;
+using std::cerr;
+using std::cout;
+using std::ostream;
+using std::ofstream;
+using abigail::tools::check_file;
+
+struct options
+{
+ string in_file_path;
+ string out_file_path;
+};
+
+static void
+display_usage(const string& prog_name, ostream& out)
+{
+ out << "usage: " << prog_name << "[options] []\n"
+ << " where options can be: \n"
+ << " --help display this message\n"
+ << " --out-file write the output to 'file-path'\n";
+}
+
+static bool
+parse_command_line(int argc, char* argv[], options& opts)
+{
+ if (argc < 2)
+ return false;
+
+ for (int i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] != '-')
+ {
+ if (opts.in_file_path.empty())
+ opts.in_file_path = argv[i];
+ else
+ return false;
+ }
+ else if (!strcmp(argv[i], "--out-file"))
+ {
+ if (argc <= i + 1
+ || argv[i + 1][0] == '-'
+ || !opts.out_file_path.empty())
+ return false;
+
+ opts.out_file_path = argv[i + 1];
+ ++i;
+ }
+ else if (!strcmp(argv[i], "--help"))
+ return false;
+ else
+ return false;
+ }
+
+ return true;
+}
+
+int
+main(int argc, char* argv[])
+{
+ options opts;
+
+ if (!parse_command_line(argc, argv, opts))
+ {
+ display_usage(argv[0], cerr);
+ return 1;
+ }
+
+ assert(!opts.in_file_path.empty());
+ if (!check_file(opts.in_file_path, cerr))
+ return 1;
+
+ using abigail::corpus;
+ using abigail::corpus_sptr;
+ using abigail::translation_units;
+ using abigail::dwarf_reader::read_corpus_from_elf;
+
+ corpus_sptr corp = read_corpus_from_elf(opts.in_file_path);
+ if (!corp)
+ {
+ cerr << "Could not read debug info from " << opts.in_file_path << "\n";
+ return 1;
+ }
+
+ cout << "for corpus " << corp->get_path() << ":\n";
+ for (translation_units::const_iterator it =
+ corp->get_translation_units().begin();
+ it != corp->get_translation_units().end();
+ ++it)
+ {
+ cout << "translation unit: " << (*it)->get_path() << ":\n";
+ dump(*it, cout);
+ cout << "\n";
+ }
+
+ return 0;
+}