changes. Added or removed functions and variables do not have any
diff nodes tree associated to them.
+ * ``--stats``
+
+ Emit statistics about various internal things.
+
.. _abidiff_return_value_label:
Return values
makes ``abidw`` load *all* the types defined in the binaries, even
those that are not reachable from public declarations.
+ * ``--stats``
+
+ Emit statistics about various internal things.
+
Notes
=====
bool
get_type_of_elf_file(const string& path, elf_type& type);
+
+bool
+get_show_stats(read_context_sptr& ctxt);
+
+void
+set_show_stats(read_context_sptr& ctxt,
+ bool f);
+
}// end namespace dwarf_reader
}// end namespace abigail
#include <cmath>
#include <elfutils/libdwfl.h>
#include <dwarf.h>
+#include <iostream>
#include <tr1/unordered_map>
#include <stack>
#include <deque>
namespace abigail
{
+using std::cerr;
+
/// The namespace for the DWARF reader.
namespace dwarf_reader
{
string elf_architecture_;
corpus::exported_decls_builder* exported_decls_builder_;
bool load_all_types_;
+ bool show_stats_;
read_context();
verdef_section_(),
verneed_section_(),
exported_decls_builder_(),
- load_all_types_()
+ load_all_types_(),
+ show_stats_()
{}
/// Clear the data that is relevant only for the current translation
return die_type_map_;
}
+ /// Return the map that associates DIEs to the type they represent.
+ ///
+ /// @param in_alt_die true iff the DIE is in the alternate debug info section.
+ ///
+ /// @return return the map that associated DIEs to the type they represent.
+ const die_type_map_type&
+ die_type_map(bool in_alt_die) const
+ {
+ if (in_alt_die)
+ return alternate_die_type_map_;
+ return die_type_map_;
+ }
+
/// Associated a DIE (representing a type) at a given offset to the
/// type that it represents.
///
/// or NULL if no type is associated to the DIE.
type_base_sptr
lookup_type_from_die_offset(size_t die_offset,
- bool in_alt_die)
+ bool in_alt_die) const
{
type_base_sptr result;
- die_type_map_type& m = die_type_map(in_alt_die);
- die_type_map_type::iterator i = m.find(die_offset);
+ const die_type_map_type& m = die_type_map(in_alt_die);
+ die_type_map_type::const_iterator i = m.find(die_offset);
if (i != m.end())
result = i->second;
}
}
+ /// Compute the number of canonicalized and missed types in the late
+ /// canonicalization phase.
+ ///
+ /// @param in_alt_di if set to yes, this means to look for types in
+ /// the alternate debug info. If set to no, this means to look for
+ /// the main debug info.
+ ///
+ /// @param canonicalized the number of types that got canonicalized
+ /// is added to the value already present in this parameter.
+ ///
+ /// @param missed the number of types scheduled for late
+ /// canonicalization and which couldn't be canonicalized (for a
+ /// reason) is added to the value already present in this parameter.
+ void
+ add_late_canonicalized_types_stats(bool in_alt_di,
+ size_t& canonicalized,
+ size_t& missed) const
+ {
+ for (vector<Dwarf_Off>::const_iterator i =
+ types_to_canonicalize(in_alt_di).begin();
+ i != types_to_canonicalize(in_alt_di).end();
+ ++i)
+ {
+ type_base_sptr t = lookup_type_from_die_offset(*i, in_alt_di);
+ if (t->get_canonical_type())
+ ++canonicalized;
+ else
+ ++missed;
+ }
+ }
+
+ /// Compute the number of canonicalized and missed types in the late
+ /// canonicalization phase.
+ ///
+ /// @param canonicalized the number of types that got canonicalized
+ /// is added to the value already present in this parameter.
+ ///
+ /// @param missed the number of types scheduled for late
+ /// canonicalization and which couldn't be canonicalized (for a
+ /// reason) is added to the value already present in this parameter.
+ void
+ add_late_canonicalized_types_stats(size_t& canonicalized,
+ size_t& missed) const
+ {
+ add_late_canonicalized_types_stats(/*in_alt_di=*/true,
+ canonicalized,
+ missed);
+
+ add_late_canonicalized_types_stats(/*in_alt_di=*/false,
+ canonicalized,
+ missed);
+ }
+
// Look at the types that need to be canonicalized after the
// translation unit has been constructed and canonicalize them.
void
{
canonicalize_types_scheduled(/*in_alt_di=*/false);
canonicalize_types_scheduled(/*in_alt_di=*/true);
+
+ if (show_stats())
+ {
+ size_t num_canonicalized = 0, num_missed = 0, total = 0;
+ add_late_canonicalized_types_stats(num_canonicalized,
+ num_missed);
+ total = num_canonicalized + num_missed;
+ cerr << "binary: "
+ << elf_path()
+ << "\n";
+ cerr << " # late canonicalized types: "
+ << num_canonicalized
+ << " (" << num_canonicalized * 100 / total << "%)\n"
+ << " # missed canonicalization opportunities: "
+ << num_missed
+ << " (" << num_missed * 100 / total << "%)\n";
+ }
+
}
const die_tu_map_type&
load_all_types(bool f)
{load_all_types_ = f;}
+ /// Getter of the "show_stats" flag.
+ ///
+ /// This flag tells if we should emit statistics about various
+ /// internal stuff.
+ ///
+ /// @return the value of the flag.
+ bool
+ show_stats() const
+ {return show_stats_;}
+
+ /// Setter of the "show_stats" flag.
+ ///
+ /// This flag tells if we should emit statistics about various
+ /// internal stuff.
+ ///
+ /// @param f the value of the flag.
+ void
+ show_stats(bool f)
+ {show_stats_ = f;}
+
/// If a given function decl is suitable for the set of exported
/// functions of the current corpus, this function adds it to that
/// set.
function_decl_sptr f,
class_decl_sptr klass);
+/// Getter of the "show_stats" flag.
+///
+/// This flag tells if we should emit statistics about various
+/// internal stuff.
+///
+/// @param ctx the read context to consider for this flag.
+///
+/// @return the value of the flag.
+bool
+get_show_stats(read_context_sptr& ctxt)
+{
+ if(!ctxt)
+ return false;
+ return ctxt->show_stats();
+}
+
+/// Setter of the "show_stats" flag.
+///
+/// This flag tells if we should emit statistics about various
+/// internal stuff.
+///
+/// @param ctxt the read context to consider for this flag.
+///
+/// @param f the value of the flag.
+void
+set_show_stats(read_context_sptr& ctxt,
+ bool f)
+{
+ if (ctxt)
+ ctxt->show_stats(f);
+}
+
/// Constructor for a default Dwfl handle that knows how to load debug
/// info from a library or executable elf file.
///
bool show_redundant_changes;
bool show_symbols_not_referenced_by_debug_info;
bool dump_diff_tree;
+ bool show_stats;
shared_ptr<char> di_root_path1;
shared_ptr<char> di_root_path2;
show_harmless_changes(false),
show_redundant_changes(false),
show_symbols_not_referenced_by_debug_info(true),
- dump_diff_tree()
+ dump_diff_tree(),
+ show_stats()
{}
};//end struct options;
<< " where options can be:\n"
<< " --debug-info-dir1|--d1 <path> the root for the debug info of file1\n"
<< " --debug-info-dir2|--d2 <path> the root for the debug info of file2\n"
+ << " --help|-h display this message\n "
<< " --stat only display the diff stats\n"
<< " --symtabs only display the symbol tables of the corpora\n"
<< " --deleted-fns display deleted public functions\n"
"(this is the default)\n"
<< " --dump-diff-tree emit a debug dump of the internal diff tree to "
"the error output stream\n"
- << " --help|-h display this message\n";
+ << " --stats show statistics about various internal stuff\n";
}
/// Parse the command line and set the options accordingly.
opts.show_redundant_changes = false;
else if (!strcmp(argv[i], "--dump-diff-tree"))
opts.dump_diff_tree = true;
+ else if (!strcmp(argv[i], "--stats"))
+ opts.show_stats = true;
else
return false;
}
break;
case abigail::tools_utils::FILE_TYPE_ELF:
case abigail::tools_utils::FILE_TYPE_AR:
- di_dir1 = opts.di_root_path1.get();
- c1 = abigail::dwarf_reader::read_corpus_from_elf(opts.file1,
- &di_dir1,
- /*load_all_types=*/false,
- c1_status);
+ {
+ di_dir1 = opts.di_root_path1.get();
+ abigail::dwarf_reader::read_context_sptr ctxt =
+ abigail::dwarf_reader::create_read_context(opts.file1,
+ &di_dir1,
+ /*read_all_types=*/false);
+ assert(ctxt);
+ abigail::dwarf_reader::set_show_stats
+ (ctxt, opts.show_stats);
+
+ c1 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c1_status);
+ }
break;
case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
c1 =
break;
case abigail::tools_utils::FILE_TYPE_ELF:
case abigail::tools_utils::FILE_TYPE_AR:
- di_dir2 = opts.di_root_path2.get();
- c2 = abigail::dwarf_reader::read_corpus_from_elf(opts.file2,
- &di_dir2,
- /*load_all_types=*/false,
- c2_status);
+ {
+ di_dir2 = opts.di_root_path2.get();
+ abigail::dwarf_reader::read_context_sptr ctxt =
+ abigail::dwarf_reader::create_read_context(opts.file2,
+ &di_dir2,
+ /*read_all_types=*/false);
+ assert(ctxt);
+ abigail::dwarf_reader::set_show_stats
+ (ctxt, opts.show_stats);
+ c2 = abigail::dwarf_reader::read_corpus_from_elf(*ctxt, c2_status);
+ }
break;
case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
c2 =
bool show_base_name_alt_debug_info_path;
bool write_architecture;
bool load_all_types;
+ bool show_stats;
options()
: check_alt_debug_info_path(),
show_base_name_alt_debug_info_path(),
write_architecture(true),
- load_all_types()
+ load_all_types(),
+ show_stats()
{}
};
"debug info of <elf-path>, and show its base name\n"
<< " --load-all-types read all types including those not reachable from"
"exported declarations\n"
+ << " --stats show statistics about various internal stuff\n";
;
}
}
else if (!strcmp(argv[i], "--load-all-types"))
opts.load_all_types = true;
+ else if (!strcmp(argv[i], "--stats"))
+ opts.show_stats = true;
else if (!strcmp(argv[i], "--help")
|| !strcmp(argv[i], "--h"))
return false;
corpus_sptr corp;
read_context_sptr c = create_read_context(opts.in_file_path, &p,
opts.load_all_types);
+ set_show_stats(c, opts.show_stats);
read_context& ctxt = *c;
if (opts.check_alt_debug_info_path)