libabigail/tests/test-ir-walker.cc

149 lines
3.0 KiB
C++
Raw Normal View History

// -*- Mode: C++ -*-
//
Update copyright years * include/abg-comp-filter.h: Update copyright years. * include/abg-comparison.h: Likewise. * include/abg-config.h: Likewise. * include/abg-corpus.h: Likewise. * include/abg-diff-utils.h: Likewise. * include/abg-dwarf-reader.h: Likewise. * include/abg-fwd.h: Likewise. * include/abg-hash.h: Likewise. * include/abg-ini.h: Likewise. * include/abg-ir.h: Likewise. * include/abg-libxml-utils.h: Likewise. * include/abg-libzip-utils.h: Likewise. * include/abg-reader.h: Likewise. * include/abg-sptr-utils.h: Likewise. * include/abg-traverse.h: Likewise. * include/abg-viz-common.h: Likewise. * include/abg-viz-dot.h: Likewise. * include/abg-viz-svg.h: Likewise. * include/abg-writer.h: Likewise. * src/abg-comp-filter.cc: Likewise. * src/abg-comparison.cc: Likewise. * src/abg-config.cc: Likewise. * src/abg-corpus.cc: Likewise. * src/abg-diff-utils.cc: Likewise. * src/abg-dwarf-reader.cc: Likewise. * src/abg-hash.cc: Likewise. * src/abg-ini.cc: Likewise. * src/abg-ir.cc: Likewise. * src/abg-libxml-utils.cc: Likewise. * src/abg-libzip-utils.cc: Likewise. * src/abg-reader.cc: Likewise. * src/abg-traverse.cc: Likewise. * src/abg-viz-common.cc: Likewise. * src/abg-viz-dot.cc: Likewise. * src/abg-viz-svg.cc: Likewise. * src/abg-writer.cc: Likewise. * tests/print-diff-tree.cc: Likewise. * tests/test-abidiff.cc: Likewise. * tests/test-alt-dwarf-file.cc: Likewise. * tests/test-core-diff.cc: Likewise. * tests/test-diff-dwarf.cc: Likewise. * tests/test-diff-filter.cc: Likewise. * tests/test-diff-suppr.cc: Likewise. * tests/test-diff2.cc: Likewise. * tests/test-ir-walker.cc: Likewise. * tests/test-lookup-syms.cc: Likewise. * tests/test-read-dwarf.cc: Likewise. * tests/test-read-write.cc: Likewise. * tests/test-utils.cc: Likewise. * tests/test-utils.h: Likewise. * tests/test-write-read-archive.cc: Likewise. * tools/abg-tools-utils.cc: Likewise. * tools/abg-tools-utils.h: Likewise. * tools/abiar.cc: Likewise. * tools/abidiff.cc: Likewise. * tools/abidw.cc: Likewise. * tools/abilint.cc: Likewise. * tools/abisym.cc: Likewise. * tools/binilint.cc: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-01-07 12:53:58 +00:00
// Copyright (C) 2013-2015 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/>.
#include <string>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include "abg-ir.h"
Prepare serialization API for multiple backends * include/abg-reader.h: New file with abigail::xml_reader APIs. * include/abg-writer.h: New file with abigail::xml_writer APIs. * include/Makefile.am: Add the new files above to the source distribution. * src/abg-reader.cc: Update top-file comments. (namespace xml_reader): Rename namespace reader into this. (read_to_translation_unit, read_corpus_from_archive): New static functions. (read_translation_unit_from_file) (read_translation_unit_from_file, read_corpus_from_file): New entry points. (struct array_deleter): New functor. (translation_unit::read): Remove this. * src/abg-writer.cc: Update top file comments. (namespace xml_writer): Rename namespace writer into this. (struct archive_write_ctxt): New internal type. (create_archive_write_context, write_translation_unit_to_archive) (write_translation_unit, write_corpus_to_archive): New low level static functions overloads. (write_corpus_to_archive, write_translation_unit): Public higher level overloads. (translation_unit::write): Remove. (dump): Update for new xml_writer namespace. * include/abg-ir.h (translation_unit::{read, write}): Remove these serialization methods. * include/abg-corpus.h (corpus_sptr): New convenience typedef. (corpus::{read, write}): Remove these methods. * src/abg-corpus.cc (corpus::{read, write}) (corpus::impl::{serialized_tus, archive}): Remove these members. (corpus::impl::{get_archive, close_archive, write_tu_to_archive, read_to_translation_unit}): Remove these methods. * tests/test-bidiff.cc (main): Update for usage of the new xml_reader API. * tests/test-read-write.cc (main): Likewise. Update for the usage of the new xml_writer API, too. * tests/test-walker.cc (main): Update for the usage of the new xml_reader API. * tests/test-write-read-archive.cc (main): Likewise. And for the xml_writer API, too. * tools/biar.cc (add_tus_to_archive, extract_tus_from_archive): Likewise. * tools/bidiff.cc (main): Likewise, for xml_reader APIs. * tools/bilint.cc (main): Likewise, for xml_writer APIs, too. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2013-12-04 08:44:20 +00:00
#include "abg-reader.h"
#include "test-utils.h"
using std::string;
using std::ofstream;
using std::cerr;
using std::cout;
struct name_printing_visitor : public abigail::ir_node_visitor
{
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
unsigned level_;
name_printing_visitor()
: level_()
{}
void
build_level_prefix(string& str)
{
str.clear();
for (unsigned i = 0; i < level_; ++i)
str += ' ';
}
string
build_level_prefix()
{
string prefix;
build_level_prefix(prefix);
return prefix;
}
bool
visit_begin(abigail::namespace_decl* ns)
{
string prefix = build_level_prefix();
cout << prefix << ns->get_pretty_representation() << "\n"
<< prefix << "{\n";
++level_;
return true;
}
bool
visit_end(abigail::namespace_decl*)
{
string prefix = build_level_prefix();
cout << prefix << "}\n";
--level_;
return true;
}
bool
visit_begin(abigail::class_decl* klass)
{
string prefix = build_level_prefix();
cout << prefix << klass->get_pretty_representation() << "\n"
<< prefix << "{\n";
++level_;
return true;
}
bool
visit_end(abigail::class_decl*)
{
string prefix = build_level_prefix();
cout << prefix << "}\n";
--level_;
return true;
}
bool
visit_begin(abigail::function_decl* f)
{
string prefix = build_level_prefix();
cout << prefix << f->get_pretty_representation() << "\n";
++level_;
return true;
}
bool
visit_end(abigail::function_decl*)
{
--level_;
return true;
}
bool
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
visit_begin(abigail::var_decl* v)
{
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
string prefix = build_level_prefix();
cout << prefix << v->get_pretty_representation() << "\n";
++level_;
return true;
}
bool
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
visit_end(abigail::var_decl*)
{
Canonicalize types either early or late after TU reading While trying to diff two identical files (abidiff foo.so foo.so) it appeared that canonicalizing types during e.g, the DWARF reading process was leading to subtle errors because it's extremely hard to know when a type is complete. That is, during the building of a class type C, a pointer to C can be built before C is complete. Worse, even after reading the DIE (from DWARF) of class C, there can be DIE seen later in the translation unit that modifies type C. In these late cases, one needs to wait -- not only until C is fully built, but also sometimes, after the translation unit is fully built -- to canonicalize C and then the pointer to C. This kind of things. So now there are two possible points in time when canonicalization of a type can happen. It can happen early, when the type is built. This is the case for basic types and composite types for which all sub-types are canonicalized already. It can happen late, right after we've finished reading the debug info for the current translation unit. So this patch fixes the IR traversal and uses that to walk the translation unit (or even types) after it's built. It does away with the first attempt to perform early canonicalizing only. The patch also handles type canonicalizing while reading xml-abi format. * include/abg-fwd.h (is_class_type) (type_has_non_canonicalized_subtype): Declare new functions. (is_member_type): Remove the overload that takes a decl_base_sptr. It's superfluous. We just need the one that takes a type_base_sptr. * include/abg-ir.h (translation_unit::{is_constructed, set_is_constructed}): Add new methods. (class_decl::has_virtual_member_functions): Likewise. (class decl_base): Makes it virtually inherit ir_traversable_base. (class type_base): Make this virtually inherit traversable_base too. (type_base::canonicalize): Renamed enable_canonical_equality into this. (type_base::traverse): Declare new virtual method. (canonicalize): Renamed enable_canonical_equality into this. (scope_type_decl::traverse): Declare new virtual method. (namespace_decl::get_pretty_representation): Declare new virtual method. (function_type::traverse): Likewise. (class_decl::base_spec::traverse): Likewise. (ir_node_visitor::visit): Remove the overloads and replace each of them with a pair of ... (ir_node_visitor::{visit_begin, visit_end}): ... of these. * include/abg-traverse.h (traversable_base::visiting): New method. (traversable_base::visiting_): New data member. (traversable_base::traversable_base): New constructor. * src/abg-ir.cc ({scope_decl, type_decl, namespace_decl, qualified_type_def, pointer_type_def, reference_type_def, array_type_def, enum_type_decl, typedef_decl, var_decl, function_decl, function_decl::parameter, class_decl, class_decl::member_function_template, class_decl::member_class_template, function_tdecl, class_tdecl}::traverse): Fix this to properly set the traversable_base::visiting_ flag and to reflect the new signatures of the ir_node_visitor methods. ({type_base, scope_type_decl, function_type, class_decl::base_spec}::traverse): New method. (type_base::get_canonical_type_for): Handle the case of the type already having a canonical type. Properly hash the type using the dynamic type hasher. Look through declaration-only classes to consider the definition of the class instead. Fix logic to have a single pointer of return, to ease debugging. (canonicalize): Renamed enable_canonical_equality into this. (namespace_decl::get_pretty_representation): Define new method. (ir_node_visitor::visit): Replace each of these overloads with a pair of visit_begin/visit_end ones. (translation_unit::priv::is_constructed_): New data member. (translation_unit::priv::priv): Initialize it. (translation_unit::{is_constructed, set_is_constructed}): Define new methods. (is_member_type(const decl_base_sptr)): Remove. (is_class_type(decl_base *d)): Define new function. (class_decl::has_virtual_member_functions): Define new method. (equals(const class_decl&, const class_decl&, change_kind*)): If the containing translation unit is not constructed yet, do not take virtual member functions in account when comparing the classes. This is because when reading from DWARF, there can be DIEs that change the number of virtual member functions after the DIE of the class. So one needs to start taking virtual members into account only after the translation unit has been constructed. (class non_canonicalized_subtype_detector): Define new type. (type_has_non_canonicalized_subtype): Define new function. * src/abg-corpus.cc (symtab_build_visitor_type::visit): Renamed this into symtab_build_visitor_type::visit_end. * src/abg-dwarf-reader.cc (die_type_map_type): New typedef. (die_class_map_type): This is now a typedef on a map of Dwarf_Off/class_decl_sptr. (read_context::{die_type_map_, alternate_die_type_map_, types_to_canonicalize_, alt_types_to_canonicalize_}): New data members. (read_context::{associate_die_to_decl, associate_die_to_decl_primary}): Make these methods public. (read_context::{associate_die_to_type, lookup_type_from_die_offset, is_wip_class_die_offset, types_to_canonicalize, schedule_type_for_canonicalization}): Define new methods. (build_type_decl, build_enum_type) (build_class_type_and_add_to_ir, build_qualified_type) (build_pointer_type_def, build_reference_type, build_array_type) (build_typedef_type, build_function_decl): Do not canonicalize types here. (maybe_canonicalize_type): Define new function. (build_ir_node_from_die): Take a new flag that says if the ir node is a member type/function or not. Early-canonicalize base types. Canonicalize composite types that have only canonicalized sub-types. Schedule the other types for late canonicalizing. For class types, early canonicalize those that are non-member types, that are fully constructed and that have only canonicalized sub-types. Adjust to the new signature of build_ir_node_from_die. (get_scope_for_die, build_namespace_decl_and_add_to_ir) (build_qualified_type, build_pointer_type_def) (build_reference_type, build_array_type, build_typedef_type) (build_var_decl, build_function_decl): Adjust for the new signature of build_ir_node_from_die. (build_translation_unit_and_add_to_ir): Likewise. Perform the late canonicalizing of the types that have been scheduled for that. (build_class_type_and_add_to_ir): Return a class_decl_sptr, not a decl_base_sptr. Adjust for the new signature of build_ir_node_from_die. Early canonicalize member types that are created and added to a given class, or schedule them for late canonicalizing. * src/abg-reader.cc (class read_context::{m_wip_classes_map, m_types_to_canonicalize}): New data members. (read_context::{clear_types_to_canonicalize, clear_wip_classes_map, mark_class_as_wip, unmark_class_as_wip, is_wip_class, maybe_canonicalize_type, schedule_type_for_late_canonicalizing, perform_late_type_canonicalizing}): Add new method definitions. (read_context::clear_per_translation_unit_data): Call read_context::clear_types_to_canonicalize(). (read_translation_unit_from_input): Call read_context::perform_late_type_canonicalizing() at the end of the function. (build_function_decl): Fix the function type canonicalizing (per translation) that was already in place. Do the canonicalizing of these only when the type is fully built. Oops. This was really brokend. Also, when the function type is constructed, consider it for type canonicalizing. (build_type_decl): Early canonicalize basic types. (build_qualified_type_decl, build_pointer_type_def) (build_pointer_type_def, build_reference_type_def) (build_array_type_def, build_enum_type_decl, build_typedef_decl): Handle the canonicalizing for these composite types: either early or late. (build_class_decl): Likewise. Also, mark this class a 'being built' until it's fully built. This helps the canonicalizing code to know that it should leave a class alone until it's fully built. * tests/test-ir-walker.cc (struct name_printing_visitor): Adjust to the visitor methods naming change. * configure.ac: Generate the tests/runtestcanonicalizetypes.sh testing script from tests/runtestcanonicalizetypes.sh.in. * tests/runtestcanonicalizetypes.sh.in: Add the template for the new runtestcanonicalizetypes.sh script that test for type canonicalizing. * tests/Makefile.am: Add the new runtestcanonicalizetypes.sh regression testing script to the build system. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2015-02-13 19:20:57 +00:00
--level_;
return true;
}
};
int
main(int argc, char **argv)
{
if (argc < 2)
return 0;
string file_name = argv[1];
abigail::translation_unit tu(file_name);
Prepare serialization API for multiple backends * include/abg-reader.h: New file with abigail::xml_reader APIs. * include/abg-writer.h: New file with abigail::xml_writer APIs. * include/Makefile.am: Add the new files above to the source distribution. * src/abg-reader.cc: Update top-file comments. (namespace xml_reader): Rename namespace reader into this. (read_to_translation_unit, read_corpus_from_archive): New static functions. (read_translation_unit_from_file) (read_translation_unit_from_file, read_corpus_from_file): New entry points. (struct array_deleter): New functor. (translation_unit::read): Remove this. * src/abg-writer.cc: Update top file comments. (namespace xml_writer): Rename namespace writer into this. (struct archive_write_ctxt): New internal type. (create_archive_write_context, write_translation_unit_to_archive) (write_translation_unit, write_corpus_to_archive): New low level static functions overloads. (write_corpus_to_archive, write_translation_unit): Public higher level overloads. (translation_unit::write): Remove. (dump): Update for new xml_writer namespace. * include/abg-ir.h (translation_unit::{read, write}): Remove these serialization methods. * include/abg-corpus.h (corpus_sptr): New convenience typedef. (corpus::{read, write}): Remove these methods. * src/abg-corpus.cc (corpus::{read, write}) (corpus::impl::{serialized_tus, archive}): Remove these members. (corpus::impl::{get_archive, close_archive, write_tu_to_archive, read_to_translation_unit}): Remove these methods. * tests/test-bidiff.cc (main): Update for usage of the new xml_reader API. * tests/test-read-write.cc (main): Likewise. Update for the usage of the new xml_writer API, too. * tests/test-walker.cc (main): Update for the usage of the new xml_reader API. * tests/test-write-read-archive.cc (main): Likewise. And for the xml_writer API, too. * tools/biar.cc (add_tus_to_archive, extract_tus_from_archive): Likewise. * tools/bidiff.cc (main): Likewise, for xml_reader APIs. * tools/bilint.cc (main): Likewise, for xml_writer APIs, too. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2013-12-04 08:44:20 +00:00
if (!abigail::xml_reader::read_translation_unit_from_file(tu))
{
cerr << "failed to read " << file_name << "\n";
return 1;
}
name_printing_visitor v;
tu.traverse(v);
}