AC_LANG([C++])
AC_LANG_COMPILER_REQUIRE
-dnl Check for dependency: libdw (elfutils)
+dnl Check for dependency: libelf, libdw, libebl (elfutils)
+ELF_LIBS=
+AC_CHECK_LIB([elf], [elf_end], [ELF_LIBS="-lelf"])
+AC_CHECK_HEADER([libelf.h],
+ [],
+ [AC_MSG_ERROR([could not find libelf.h])])
+
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])])
-AC_CHECK_LIB([elf], [elf_end], [ELF_LIBS="-lelf"])
-AC_CHECK_HEADER([libelf.h],
+
+EBL_LIBS=
+AC_CHECK_LIB(ebl, ebl_openbackend, [EBL_LIBS=-lebl], [], [-ldl -lelf])
+AC_CHECK_HEADER(elfutils/libebl.h,
[],
- [AC_MSG_ERROR([could not find libelf.h])])
+ [AC_MSG_ERROR([could not find elfutils/libebl.h installed])])
+
+if test x$ELF_LIBS = x; then
+ AC_MSG_ERROR([could not find elfutils elf library installed])
+fi
if test x$DW_LIBS = x; then
AC_MSG_ERROR([could not find elfutils dwarf library installed])
fi
+if test x$EBL_LIBS = x; then
+ AC_MSG_ERROR([could not find elfutils backend library installed])
+fi
+
AC_SUBST(DW_LIBS)
+AC_SUBST(EBL_LIBS)
AC_SUBST([ELF_LIBS])
dnl Check for dependency: libxml
dnl Set the list of libraries libabigail depends on
-DEPS_LIBS="$XML_LIBS $LIBZIP_LIBS $DW_LIBS $ELF_LIBS"
+DEPS_LIBS="$XML_LIBS $LIBZIP_LIBS $ELF_LIBS $EBL_LIBS $DW_LIBS"
AC_SUBST(DEPS_LIBS)
if test x$ABIGAIL_DEVEL != x; then
bool
show_soname_change() const;
+ void
+ show_architecture_change(bool f);
+
+ bool
+ show_architecture_change() const;
+
void
show_deleted_fns(bool f);
bool
soname_changed() const;
+ bool
+ architecture_changed() const;
+
const string_function_ptr_map&
deleted_functions() const;
void
set_soname(const string&);
+ const string&
+ get_architecture_name();
+
+ void
+ set_architecture_name(const string&);
+
bool
is_empty() const;
bool forbid_traversing_a_node_twice_;
bool show_stats_only_;
bool show_soname_change_;
+ bool show_architecture_change_;
bool show_deleted_fns_;
bool show_changed_fns_;
bool show_added_fns_;
forbid_traversing_a_node_twice_(true),
show_stats_only_(false),
show_soname_change_(true),
+ show_architecture_change_(true),
show_deleted_fns_(true),
show_changed_fns_(true),
show_added_fns_(true),
diff_context::show_soname_change() const
{return priv_->show_soname_change_;}
+/// Setter for the property that says if the comparison module should
+/// show the architecture changes in its report.
+///
+/// @param f the new value of the property.
+void
+diff_context::show_architecture_change(bool f)
+{priv_->show_architecture_change_ = f;}
+
+/// Getter for the property that says if the comparison module should
+/// show the architecture changes in its report.
+///
+/// @return the value of the property.
+bool
+diff_context::show_architecture_change() const
+{return priv_->show_architecture_change_;}
+
/// Set a flag saying to show the deleted functions.
///
/// @param f true to show deleted functions.
<< " is now declared inline\n";
}
+ // Report about the size of the function address
+ if (ff->get_type()->get_size_in_bits() != sf->get_type()->get_size_in_bits())
+ {
+ out << indent << "address size of function changed from "
+ << ff->get_type()->get_size_in_bits()
+ << " bits to "
+ << sf->get_type()->get_size_in_bits()
+ << " bits\n";
+ }
+
+ // Report about the alignment of the function address
+ if (ff->get_type()->get_alignment_in_bits()
+ != sf->get_type()->get_alignment_in_bits())
+ {
+ out << indent << "address alignment of function changed from "
+ << ff->get_type()->get_alignment_in_bits()
+ << " bits to "
+ << sf->get_type()->get_alignment_in_bits()
+ << " bits\n";
+ }
+
// Report about return type differences.
if (priv_->return_type_diff_ && priv_->return_type_diff_->to_be_reported())
{
corpus_diff::diff_stats diff_stats_;
bool filters_and_suppr_applied_;
bool sonames_equal_;
+ bool architectures_equal_;
edit_script fns_edit_script_;
edit_script vars_edit_script_;
edit_script unrefed_fn_syms_edit_script_;
priv()
: finished_(false),
filters_and_suppr_applied_(false),
- sonames_equal_(false)
+ sonames_equal_(false),
+ architectures_equal_(false)
{}
bool
if (!sonames_equal_)
out << indent << "ELF SONAME changed\n";
+ if (!architectures_equal_)
+ out << indent << "ELF architecture changed\n";
+
// function changes summary
out << indent << "Functions changes summary: ";
out << s.num_func_removed() << " Removed, ";
corpus_diff::variable_changes() const
{return priv_->vars_edit_script_;}
-/// Test if the soname of the underying corpus has changed.
+/// Test if the soname of the underlying corpus has changed.
///
/// @return true iff the soname has changed.
bool
corpus_diff::soname_changed() const
{return !priv_->sonames_equal_;}
+/// Test if the architecture of the underlying corpus has changed.
+///
+/// @return true iff the architecture has changed.
+bool
+corpus_diff::architecture_changed() const
+{return !priv_->architectures_equal_;}
+
/// Getter for the deleted functions of the diff.
///
/// @return the the deleted functions of the diff.
corpus_diff::length() const
{
return (soname_changed()
+ + architecture_changed()
+ priv_->deleted_fns_.size()
+ priv_->added_fns_.size()
+ priv_->changed_fns_.size()
<< first_corpus()->get_soname() << "' to '"
<< second_corpus()->get_soname() << "'\n\n";
+ if (context()->show_architecture_change()
+ && !priv_->architectures_equal_)
+ out << indent << "architecture changed from '"
+ << first_corpus()->get_architecture_name() << "' to '"
+ << second_corpus()->get_architecture_name() << "'\n\n";
+
if (context()->show_deleted_fns())
{
if (s.num_func_removed() == 1)
r->priv_->sonames_equal_ = f->get_soname() == s->get_soname();
+ r->priv_->architectures_equal_ =
+ f->get_architecture_name() == s->get_architecture_name();
+
diff_utils::compute_diff<fns_it_type, eq_type>(f->get_functions().begin(),
f->get_functions().end(),
s->get_functions().begin(),
string path;
vector<string> needed;
string soname;
+ string architecture_name;
translation_units members;
vector<function_decl*> fns;
vector<var_decl*> vars;
corpus::set_soname(const string& soname)
{priv_->soname = soname;}
+/// Getter for the architecture name of the corpus.
+///
+/// This property is meaningful for e.g, corpora built from ELF shared
+/// library files. In that case, this is a string representation of
+/// the Elf{32,64}_Ehdr::e_machine field.
+///
+/// @return the architecture name string.
+const string&
+corpus::get_architecture_name()
+{return priv_->architecture_name;}
+
+/// Setter for the architecture name of the corpus.
+///
+/// This property is meaningful for e.g, corpora built from ELF shared
+/// library files. In that case, this is a string representation of
+/// the Elf{32,64}_Ehdr::e_machine field.
+///
+/// @param arch the architecture name string.
+void
+corpus::set_architecture_name(const string& arch)
+{priv_->architecture_name = arch;}
+
/// Tests if the corpus contains no translation unit.
///
/// @return true if the corpus contains no translation unit.
#include <cstring>
#include <cmath>
#include <elfutils/libdwfl.h>
+#include <elfutils/libebl.h>
#include <dwarf.h>
#include <tr1/unordered_map>
#include <stack>
string_elf_symbols_map_sptr undefined_var_syms_;
vector<string> dt_needed_;
string dt_soname_;
+ string elf_architecture_;
read_context();
dt_soname() const
{return dt_soname_;}
+ /// Getter for the ELF architecture of the current file.
+ const string&
+ elf_architecture() const
+ {return elf_architecture_;}
+
/// Getter for the map of global variables symbol address -> global
/// variable symbol index.
///
}
}
+ /// Read the string representing the architecture of the current ELF
+ /// file.
+ void
+ load_elf_architecture()
+ {
+ if (!elf_handle())
+ return;
+
+ elf_architecture_ = ebl_backend_name(ebl_openbackend(elf_handle()));
+ }
+
+ /// Load various ELF data.
+ ///
+ /// This function loads ELF data that are not symbol maps or debug
+ /// info. That is, things like various tags, elf architecture and
+ /// so on.
+ void
+ load_remaining_elf_data()
+ {
+ load_dt_soname_and_needed();
+ load_elf_architecture();
+ }
+
/// This is a sub-routine of maybe_adjust_fn_sym_address and
/// maybe_adjust_var_sym_address.
///
if (!ctxt.load_symbol_maps())
status |= STATUS_NO_SYMBOLS_FOUND;
- ctxt.load_dt_soname_and_needed();
+ ctxt.load_remaining_elf_data();
if (status & STATUS_NO_SYMBOLS_FOUND)
return status;
corp->set_origin(corpus::DWARF_ORIGIN);
corp->set_soname(ctxt.dt_soname());
corp->set_needed(ctxt.dt_needed());
+ corp->set_architecture_name(ctxt.elf_architecture());
corp->set_fun_symbol_map(ctxt.fun_syms_sptr());
corp->set_undefined_fun_symbol_map(ctxt.undefined_fun_syms_sptr());
if (path_str)
corp.set_path(reinterpret_cast<char*>(path_str.get()));
+ xml::xml_char_sptr architecture_str =
+ XML_READER_GET_ATTRIBUTE(reader, "architecture");
+ if (architecture_str)
+ corp.set_architecture_name(reinterpret_cast<char*>(architecture_str.get()));
+
xml::xml_char_sptr soname_str = XML_READER_GET_ATTRIBUTE(reader, "soname");
if (soname_str)
corp.set_soname(reinterpret_cast<char*>(soname_str.get()));
if (!corpus->get_path().empty())
out << " path='" << corpus->get_path() << "'";
+ if (!corpus->get_architecture_name().empty())
+ out << " architecture='" << corpus->get_architecture_name()<< "'";
+
if (!corpus->get_soname().empty())
out << " soname='" << corpus->get_soname()<< "'";
test-diff-dwarf/test22-changed-parm-c-report-0.txt \
test-diff-dwarf/test22-changed-parm-c-v0.c \
test-diff-dwarf/test22-changed-parm-c-v1.c \
+test-diff-dwarf/libtest-23-diff-arch-v0-32.so \
+test-diff-dwarf/libtest-23-diff-arch-v0-64.so \
+test-diff-dwarf/test-23-diff-arch-report-0.txt \
+test-diff-dwarf/test-23-diff-arch-v0.cc \
\
test-read-dwarf/test0 \
test-read-dwarf/test0.abi \
--- /dev/null
+ELF architecture changed
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+architecture changed from 'elf_i386' to 'elf_x86_64'
+
+1 function with some indirect sub-type change:
+
+ [C]'function int foo()' has some indirect sub-type changes:
+ address size of function changed from 32 bits to 64 bits
+ address alignment of function changed from 32 bits to 64 bits
+
--- /dev/null
+// Compile this with:
+// gcc -g -Wall -shared -m32 -o libtest-23-diff-arch-v0-32.so test-23-diff-arch-v0.cc
+
+// And then, compile this again with:
+// gcc -g -Wall -shared -o libtest-23-diff-arch-v0-64.so test-23-diff-arch-v0.cc
+int
+foo()
+{return 0;}
"data/test-diff-dwarf/test22-changed-parm-c-report-0.txt",
"output/test-diff-dwarf/test22-changed-parm-c-report-0.txt"
},
+ {
+ "data/test-diff-dwarf/libtest-23-diff-arch-v0-32.so",
+ "data/test-diff-dwarf/libtest-23-diff-arch-v0-64.so",
+ "data/test-diff-dwarf/test-23-diff-arch-report-0.txt",
+ "output/test-diff-dwarf/test-23-diff-arch-report-0.txt"
+ },
// This should be the last entry
{NULL, NULL, NULL, NULL}
};
continue;
}
corp->set_path(s->in_elf_path);
+ // Do not take architecture names in comparison so that these
+ // test input binaries can come from whatever arch the
+ // programmer likes.
+ corp->set_architecture_name("");
out_abi_path =
abigail::tests::get_build_dir() + "/tests/" + s->out_abi_path;