mirror of
git://sourceware.org/git/libabigail.git
synced 2024-12-14 14:04:45 +00:00
Initial support of reading an ABI Corpus from DWARF
* configure.ac: Check the presence of libdw.so and elfutils/libdwfl.h headers from elfutils and define the necessary linking flags. * include/abg-dwarf-reader.h: New header file * include/Makefile.am: Add the new header file to the source distribution. * src/abg-dwarf-reader.cc:: New file. * src/Makefile.am: Add the new file to the source distribution. * include/abg-fwd.h (dump): Add declarations for several overloads to allow dumping to a given output stream. * include/abg-ir.h (class translation_unit): Use a pimpl idiom for this now. (translation_unit::canonicalize_type): Declare new method. * src/abg-ir.cc (struct translation_unit::priv): New private type for the pimpl idiom for translation_unit. (translation_unit::{translation_unit, get_global_scope, get_path, set_path, get_loc_mgr}): Adjust for pimpl idiom. (translation_unit::canonicalize_type): Define this new method and one overload. * src/abg-writer.cc (dump): Define several overloads to dump IR nodes to given output streams. * tools/bidw.cc: New file for the new bidw tool. * tools/Makefile.am: Define rules to build the new bidw tools. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
parent
96fba7d95f
commit
bd1af4cd52
15
configure.ac
15
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
|
||||
|
@ -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 \
|
||||
|
47
include/abg-dwarf-reader.h
Normal file
47
include/abg-dwarf-reader.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// 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__
|
@ -31,6 +31,7 @@
|
||||
#include <tr1/functional>
|
||||
#include <typeinfo>
|
||||
#include <utility> // for std::rel_ops, at least.
|
||||
#include <ostream>
|
||||
#include "abg-hash.h"
|
||||
|
||||
/// Toplevel namespace for libabigail.
|
||||
@ -168,17 +169,35 @@ get_type_name(const shared_ptr<type_base>);
|
||||
shared_ptr<decl_base>
|
||||
get_type_declaration(const shared_ptr<type_base>);
|
||||
|
||||
void
|
||||
dump(const shared_ptr<decl_base>, std::ostream&);
|
||||
|
||||
void
|
||||
dump(const shared_ptr<decl_base>);
|
||||
|
||||
void
|
||||
dump(const shared_ptr<type_base>, std::ostream&);
|
||||
|
||||
void
|
||||
dump(const shared_ptr<type_base>);
|
||||
|
||||
void
|
||||
dump(const shared_ptr<var_decl>, std::ostream&);
|
||||
|
||||
void
|
||||
dump(const shared_ptr<var_decl>);
|
||||
|
||||
void
|
||||
dump(const translation_unit&, std::ostream&);
|
||||
|
||||
void
|
||||
dump(const translation_unit&);
|
||||
|
||||
void
|
||||
dump(const shared_ptr<translation_unit>, std::ostream&);
|
||||
|
||||
void
|
||||
dump(const shared_ptr<translation_unit>);
|
||||
|
||||
} // end namespace abigail
|
||||
#endif // __ABG_IRFWD_H__
|
||||
|
@ -104,21 +104,18 @@ typedef std::vector<translation_unit_sptr> translation_units;
|
||||
/// into a translation unit.
|
||||
class translation_unit : public traversable_base
|
||||
{
|
||||
public:
|
||||
struct priv;
|
||||
typedef shared_ptr<priv> priv_sptr;
|
||||
|
||||
/// Convenience typedef for a shared pointer on a @ref global_scope.
|
||||
typedef shared_ptr<global_scope> 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> global_scope_sptr;
|
||||
|
||||
public:
|
||||
|
||||
translation_unit(const std::string& path);
|
||||
|
||||
virtual ~translation_unit();
|
||||
@ -141,6 +138,12 @@ public:
|
||||
bool
|
||||
is_empty() const;
|
||||
|
||||
shared_ptr<type_base>
|
||||
canonicalize_type(shared_ptr<type_base>) const;
|
||||
|
||||
shared_ptr<decl_base>
|
||||
canonicalize_type(shared_ptr<decl_base>) const;
|
||||
|
||||
void
|
||||
traverse(ir_node_visitor& v);
|
||||
};//end class translation_unit
|
||||
|
@ -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 \
|
||||
|
742
src/abg-dwarf-reader.cc
Normal file
742
src/abg-dwarf-reader.cc
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// 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 <libgen.h>
|
||||
#include <assert.h>
|
||||
#include <cstring>
|
||||
#include <elfutils/libdwfl.h>
|
||||
#include <dwarf.h>
|
||||
#include <tr1/unordered_map>
|
||||
#include <stack>
|
||||
#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> dwfl_sptr;
|
||||
|
||||
/// A map hashing functor for Dwarf_Die*.
|
||||
struct die_hash
|
||||
{
|
||||
size_t
|
||||
operator()(Dwarf_Die* die) const
|
||||
{return std::hash<void*>()(die->addr);}
|
||||
};
|
||||
|
||||
/// Convenience typedef for a map which key is a dwarf die, and which
|
||||
/// value is the corresponding decl_base.
|
||||
typedef unordered_map<Dwarf_Die*, decl_base_sptr, die_hash> 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_decl_sptr> 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<decl_base_sptr, bool> 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<char*>(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
|
@ -29,6 +29,7 @@
|
||||
#include <iterator>
|
||||
#include <typeinfo>
|
||||
#include <tr1/memory>
|
||||
#include <tr1/unordered_map>
|
||||
#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<shared_ptr<type_base>,
|
||||
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
|
||||
|
||||
// <translation_unit stuff>
|
||||
|
||||
/// 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<global_scope>
|
||||
translation_unit::get_global_scope() const
|
||||
{
|
||||
if (!global_scope_)
|
||||
global_scope_.reset(new global_scope(const_cast<translation_unit*>(this)));
|
||||
return global_scope_;
|
||||
if (!priv_->global_scope_)
|
||||
priv_->global_scope_.reset
|
||||
(new global_scope(const_cast<translation_unit*>(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()
|
||||
{}
|
||||
|
||||
// </translation_unit stuff>
|
||||
|
||||
// <Decl definition>
|
||||
|
||||
decl_base::decl_base(const std::string& name, location locus,
|
||||
|
@ -1780,45 +1780,102 @@ write_corpus_to_archive(const corpus_sptr corp)
|
||||
|
||||
// <Debugging routines>
|
||||
|
||||
/// 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<decl_base>(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);
|
||||
}
|
||||
// </Debugging routines>
|
||||
} //end namespace abigail
|
||||
|
@ -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
|
||||
|
135
tools/bidw.cc
Normal file
135
tools/bidw.cc
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// 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 <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#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] [<path-to-elf-file>]\n"
|
||||
<< " where options can be: \n"
|
||||
<< " --help display this message\n"
|
||||
<< " --out-file <file-path> 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user