mirror of
git://sourceware.org/git/libabigail.git
synced 2025-01-31 13:51:40 +00:00
Improve type (de)serialization instability debugging
When debugging an issue uncovered by performing self comparison (abidw --abidiff <binary>) I realized that I needed a stronger verification of canonical types changing between type serialization and type de-serialization. Namely, when a type T with canonical type C is serialized, its de-serialized type should still have the same canonical type C. Otherwise, it means some "type instability" took place during serialization and de-serialization. This patch implements that verification and also cleans up things that came across while working on adding this debugging check. * include/abg-fwd.h (is_non_canonicalized_type): Declare new function. * src/abg-ir-priv.h: Include abg-corpus.h (environment::priv::pointer_type_id_map_): Fix comment. (environment::priv::check_canonical_type_from_abixml_during_self_comp): Define new member function. * src/abg-ir.cc (unmark_types_as_being_compared): Factorize this from ... (return_comparison_result): ... here. Also, add a parameter to control whether this function should perform the "canonical type propagation optimization" or not. By default the optimization is performed. This can be changed for debugging purposes later. (type_base::get_canonical_type_for): Re-organise the self comparison debugging process to invoke the new function environment::priv::check_canonical_type_from_abixml_during_self_comp each time a canonical type is computed, in addition to doing the previous verification that was done when no canonical type was found. Emit better error messages. (is_non_canonicalized_type): Rename the static function is_allowed_non_canonicalized_type into this and make it non-static. (hash_as_canonical_type_or_constant): Adjust. * src/abg-reader.cc (maybe_map_type_with_type_id): Define new static function. (read_context::maybe_check_abixml_canonical_type_stability): Ignore types that were not canonicalized. (read_corpus_from_input): Set the origin of the corpus early enough so that it's available to the canonicalizer even for types being canonicalized early. (MAYBE_MAP_TYPE_WITH_TYPE_ID): Factorize this macro out of ... (build_type): ... this. That macro is defined only when debugging self comparison. (build_array_type_def): Map the read subrange type with its type-id. (handle_{type_decl, qualified_type, pointer_type_def, reference_type_def, function_type, array_type_def,enum_type_decl, typedef_decl, class_decl, union_decl}): Map the read type with its type-id. (load_canonical_type_ids): Ignore non-canonicalized types that which ids were saved in the type-id file. * src/abg-writer.cc (write_type_record): Factorize from ... (write_canonical_type_ids): ... here. Don't forget to write the type-ids of decl-only types. This can be useful for eye inspection. * tools/abidw.cc (load_corpus_and_write_abixml): Wait until the end of the function before removing the type-id file. This can be useful for eye inspection. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
parent
c757289e0f
commit
ec8dc110a1
@ -1379,6 +1379,12 @@ hash_type_or_decl(const type_or_decl_base *);
|
||||
size_t
|
||||
hash_type_or_decl(const type_or_decl_base_sptr &);
|
||||
|
||||
bool
|
||||
is_non_canonicalized_type(const type_base *);
|
||||
|
||||
bool
|
||||
is_non_canonicalized_type(const type_base_sptr&);
|
||||
|
||||
bool
|
||||
function_decl_is_less_than(const function_decl&f, const function_decl &s);
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "abg-ir.h"
|
||||
#include "abg-corpus.h"
|
||||
|
||||
namespace abigail
|
||||
{
|
||||
@ -377,8 +378,8 @@ struct environment::priv
|
||||
// 'abidw --debug-abidiff <binary>'. It holds the set of mapping of
|
||||
// an abixml (canonical) type and its type-id.
|
||||
unordered_map<string, uintptr_t> type_id_canonical_type_map_;
|
||||
// Likewise. It holds a map that associates the pointer to a type read from
|
||||
// abixml and the type-id string it corresponds to.
|
||||
// Likewise. It holds a map that associates the pointer to a type
|
||||
// read from abixml and the type-id string it corresponds to.
|
||||
unordered_map<uintptr_t, string> pointer_type_id_map_;
|
||||
#endif
|
||||
bool canonicalization_is_done_;
|
||||
@ -674,6 +675,80 @@ struct environment::priv
|
||||
types_with_non_confirmed_propagated_ct_.erase(i);
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
/// When debugging self comparison, verify that a type T
|
||||
/// de-serialized from abixml has the same canonical type as the
|
||||
/// initial type built from DWARF that was serialized into T in the
|
||||
/// first place.
|
||||
///
|
||||
/// @param t deserialized type (from abixml) to consider.
|
||||
///
|
||||
/// @param c the canonical type @p t should have.
|
||||
///
|
||||
/// @return true iff @p c is the canonical type that @p t should
|
||||
/// have.
|
||||
bool
|
||||
check_canonical_type_from_abixml_during_self_comp(const type_base* t,
|
||||
const type_base* c)
|
||||
{
|
||||
if (!t || !t->get_corpus() || !c)
|
||||
return false;
|
||||
|
||||
if (!(t->get_corpus()->get_origin() == ir::corpus::NATIVE_XML_ORIGIN))
|
||||
return false;
|
||||
|
||||
// Get the abixml type-id that this type was constructed from.
|
||||
string type_id;
|
||||
{
|
||||
unordered_map<uintptr_t, string>::const_iterator it =
|
||||
pointer_type_id_map_.find(reinterpret_cast<uintptr_t>(t));
|
||||
if (it == pointer_type_id_map_.end())
|
||||
return false;
|
||||
type_id = it->second;
|
||||
}
|
||||
|
||||
// Get the canonical type the original in-memory type (constructed
|
||||
// from DWARF) had when it was serialized into abixml in the first place.
|
||||
type_base *original_canonical_type = nullptr;
|
||||
if (!type_id.empty())
|
||||
{
|
||||
unordered_map<string, uintptr_t>::const_iterator it =
|
||||
type_id_canonical_type_map_.find(type_id);
|
||||
if (it == type_id_canonical_type_map_.end())
|
||||
return false;
|
||||
original_canonical_type = reinterpret_cast<type_base*>(it->second);
|
||||
}
|
||||
|
||||
// Now perform the real check.
|
||||
//
|
||||
// We want to ensure that the canonical type 'c' of 't' is the
|
||||
// same as the canonical type of initial in-memory type (built
|
||||
// from DWARF) that was serialized into 't' (in abixml) in the
|
||||
// first place.
|
||||
if (original_canonical_type == c)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// When debugging self comparison, verify that a type T
|
||||
/// de-serialized from abixml has the same canonical type as the
|
||||
/// initial type built from DWARF that was serialized into T in the
|
||||
/// first place.
|
||||
///
|
||||
/// @param t deserialized type (from abixml) to consider.
|
||||
///
|
||||
/// @param c the canonical type @p t should have.
|
||||
///
|
||||
/// @return true iff @p c is the canonical type that @p t should
|
||||
/// have.
|
||||
bool
|
||||
check_canonical_type_from_abixml_during_self_comp(const type_base_sptr& t,
|
||||
const type_base_sptr& c)
|
||||
{
|
||||
return check_canonical_type_from_abixml_during_self_comp(t.get(), c.get());
|
||||
}
|
||||
#endif
|
||||
};// end struct environment::priv
|
||||
|
||||
// <class_or_union::priv definitions>
|
||||
|
143
src/abg-ir.cc
143
src/abg-ir.cc
@ -936,6 +936,26 @@ mark_types_as_being_compared(T& l, T&r)
|
||||
push_composite_type_comparison_operands(l, r);
|
||||
}
|
||||
|
||||
/// Mark a pair of types as being not compared anymore.
|
||||
///
|
||||
/// This is helpful to later detect recursive cycles in the comparison
|
||||
/// stack.
|
||||
///
|
||||
/// Note that the types must have been passed to
|
||||
/// mark_types_as_being_compared prior to calling this function.
|
||||
///
|
||||
/// @param l the left-hand-side operand of the comparison.
|
||||
///
|
||||
/// @parm r the right-hand-side operand of the comparison.
|
||||
template<typename T>
|
||||
void
|
||||
unmark_types_as_being_compared(T& l, T&r)
|
||||
{
|
||||
l.priv_->unmark_as_being_compared(l);
|
||||
l.priv_->unmark_as_being_compared(r);
|
||||
pop_composite_type_comparison_operands(l, r);
|
||||
}
|
||||
|
||||
/// Return the result of the comparison of two (sub) types.
|
||||
///
|
||||
/// The function does the necessary book keeping before returning the
|
||||
@ -951,21 +971,25 @@ mark_types_as_being_compared(T& l, T&r)
|
||||
///
|
||||
/// @param r the right-hand-side operand of the type comparison
|
||||
///
|
||||
/// @param propagate_canonical_type if true, it means the function
|
||||
/// performs the @ref OnTheFlyCanonicalization, aka, "canonical type
|
||||
/// propagation optimization".
|
||||
///
|
||||
/// @param value the result of the comparison of @p l and @p r.
|
||||
///
|
||||
/// @return the value @p value.
|
||||
template<typename T>
|
||||
bool
|
||||
return_comparison_result(T& l, T& r, bool value)
|
||||
return_comparison_result(T& l, T& r, bool value,
|
||||
bool propagate_canonical_type = true)
|
||||
{
|
||||
if (value == true)
|
||||
if (propagate_canonical_type && (value == true))
|
||||
maybe_propagate_canonical_type(l, r);
|
||||
l.priv_->unmark_as_being_compared(l);
|
||||
l.priv_->unmark_as_being_compared(r);
|
||||
|
||||
pop_composite_type_comparison_operands(l, r);
|
||||
unmark_types_as_being_compared(l, r);
|
||||
|
||||
const environment* env = l.get_environment();
|
||||
if (env->do_on_the_fly_canonicalization())
|
||||
if (propagate_canonical_type && env->do_on_the_fly_canonicalization())
|
||||
// We are instructed to perform the "canonical type propagation"
|
||||
// optimization, making 'r' to possibly get the canonical type of
|
||||
// 'l' if it has one. This mostly means that we are currently
|
||||
@ -3634,7 +3658,7 @@ void
|
||||
environment::self_comparison_debug_is_on(bool f)
|
||||
{priv_->self_comparison_debug_on_ = f;}
|
||||
|
||||
/// Test if the we are in the process of the 'self-comparison
|
||||
/// Test if we are in the process of the 'self-comparison
|
||||
/// debugging' as triggered by 'abidw --debug-abidiff' command.
|
||||
///
|
||||
/// @return true if self comparison debug is on.
|
||||
@ -13655,45 +13679,73 @@ type_base::get_canonical_type_for(type_base_sptr t)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
if (env->self_comparison_debug_is_on())
|
||||
if (env->self_comparison_debug_is_on())
|
||||
{
|
||||
// So we are debugging the canonicalization process,
|
||||
// possibly via the use of 'abidw --debug-abidiff <binary>'.
|
||||
corpus_sptr corp1, corp2;
|
||||
env->get_self_comparison_debug_inputs(corp1, corp2);
|
||||
if (corp1 && corp2 && t->get_corpus() == corp2.get())
|
||||
{
|
||||
// So we are debugging the canonicalization process,
|
||||
// possibly via the use of 'abidw --debug-abidiff <binary>'.
|
||||
//
|
||||
// If 't' comes from the second corpus, then it *must*
|
||||
// be equal to its matching canonical type coming from
|
||||
// the first corpus because the second corpus is the
|
||||
// abixml representation of the first corpus. In other
|
||||
// words, all types coming from the second corpus must
|
||||
// have canonical types coming from the first corpus.
|
||||
//
|
||||
// We are in the case where 't' is different from all
|
||||
// the canonical types of the same name that come from
|
||||
// the first corpus.
|
||||
//
|
||||
// If 't' indeed comes from the second corpus then this
|
||||
// clearly is a canonicalization failure.
|
||||
//
|
||||
// There was a problem either during the serialization
|
||||
// of 't' into abixml, or during the de-serialization
|
||||
// from abixml into abigail::ir. Further debugging is
|
||||
// needed to determine what that root cause problem is.
|
||||
//
|
||||
// Note that the first canonicalization problem of this
|
||||
// kind must be fixed before looking at the subsequent
|
||||
// ones, because the later might well just be
|
||||
// consequences of the former.
|
||||
corpus_sptr corp1, corp2;
|
||||
env->get_self_comparison_debug_inputs(corp1, corp2);
|
||||
if (corp1 && corp2 && (t->get_corpus() == corp2.get()))
|
||||
std::cerr << "error: problem detected with type '"
|
||||
<< repr
|
||||
<< "' from second corpus\n" << std::flush;
|
||||
if (result)
|
||||
{
|
||||
if (!env->priv_->
|
||||
check_canonical_type_from_abixml_during_self_comp(t,
|
||||
result))
|
||||
// The canonical type of the type re-read from abixml
|
||||
// type doesn't match the canonical type that was
|
||||
// initially serialized down.
|
||||
std::cerr << "error: wrong canonical type for '"
|
||||
<< repr
|
||||
<< "' / type: @"
|
||||
<< std::hex
|
||||
<< t.get()
|
||||
<< "/ canon: @"
|
||||
<< result.get()
|
||||
<< std::endl;
|
||||
}
|
||||
else //!result
|
||||
{
|
||||
uintptr_t ptr_val = reinterpret_cast<uintptr_t>(t.get());
|
||||
string type_id = env->get_type_id_from_pointer(ptr_val);
|
||||
if (type_id.empty())
|
||||
type_id = "type-id-<not-found>";
|
||||
// We are in the case where 't' is different from all
|
||||
// the canonical types of the same name that come from
|
||||
// the first corpus.
|
||||
//
|
||||
// If 't' indeed comes from the second corpus then this
|
||||
// clearly is a canonicalization failure.
|
||||
//
|
||||
// There was a problem either during the serialization
|
||||
// of 't' into abixml, or during the de-serialization
|
||||
// from abixml into abigail::ir. Further debugging is
|
||||
// needed to determine what that root cause problem is.
|
||||
//
|
||||
// Note that the first canonicalization problem of this
|
||||
// kind must be fixed before looking at the subsequent
|
||||
// ones, because the later might well just be
|
||||
// consequences of the former.
|
||||
std::cerr << "error: wrong induced canonical type for '"
|
||||
<< repr
|
||||
<< "' from second corpus"
|
||||
<< ", ptr: " << std::hex << t.get()
|
||||
<< "type-id: " << type_id
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!result)
|
||||
{
|
||||
v.push_back(t);
|
||||
result = t;
|
||||
}
|
||||
@ -25010,8 +25062,8 @@ hash_type_or_decl(const type_or_decl_base_sptr& tod)
|
||||
///
|
||||
/// @return true iff @p t is a one of the only types allowed to be
|
||||
/// non-canonicalized in the system.
|
||||
static bool
|
||||
is_allowed_non_canonicalized_type(const type_base *t)
|
||||
bool
|
||||
is_non_canonicalized_type(const type_base *t)
|
||||
{
|
||||
if (!t)
|
||||
return true;
|
||||
@ -25020,6 +25072,19 @@ is_allowed_non_canonicalized_type(const type_base *t)
|
||||
return is_declaration_only_class_or_union_type(t) || env->is_void_type(t);
|
||||
}
|
||||
|
||||
/// Test if a given type is allowed to be non canonicalized
|
||||
///
|
||||
/// This is a subroutine of hash_as_canonical_type_or_constant.
|
||||
///
|
||||
/// For now, the only types allowed to be non canonicalized in the
|
||||
/// system are decl-only class/union and the void type.
|
||||
///
|
||||
/// @return true iff @p t is a one of the only types allowed to be
|
||||
/// non-canonicalized in the system.
|
||||
bool
|
||||
is_non_canonicalized_type(const type_base_sptr& t)
|
||||
{return is_non_canonicalized_type(t.get());}
|
||||
|
||||
/// Hash a type by either returning the pointer value of its canonical
|
||||
/// type or by returning a constant if the type doesn't have a
|
||||
/// canonical type.
|
||||
@ -25062,7 +25127,7 @@ hash_as_canonical_type_or_constant(const type_base *t)
|
||||
// non-canonicalized type. It must be a decl-only class or a void
|
||||
// type, otherwise it means that for some weird reason, the type
|
||||
// hasn't been canonicalized. It should be!
|
||||
ABG_ASSERT(is_allowed_non_canonicalized_type(t));
|
||||
ABG_ASSERT(is_non_canonicalized_type(t));
|
||||
|
||||
return 0xDEADBABE;
|
||||
}
|
||||
|
@ -61,6 +61,14 @@ static bool read_is_non_reachable_type(xmlNodePtr, bool&);
|
||||
static bool read_naming_typedef_id_string(xmlNodePtr, string&);
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
static bool read_type_id_string(xmlNodePtr, string&);
|
||||
static bool maybe_map_type_with_type_id(const type_base_sptr&,
|
||||
xmlNodePtr);
|
||||
static bool maybe_map_type_with_type_id(const type_base_sptr&,
|
||||
const string&);
|
||||
#define MAYBE_MAP_TYPE_WITH_TYPE_ID(type, xml_node) \
|
||||
maybe_map_type_with_type_id(type, xml_node)
|
||||
#else
|
||||
#define MAYBE_MAP_TYPE_WITH_TYPE_ID(type, xml_node)
|
||||
#endif
|
||||
static void maybe_set_naming_typedef(read_context& ctxt, xmlNodePtr, const decl_base_sptr &);
|
||||
class read_context;
|
||||
@ -839,9 +847,12 @@ public:
|
||||
// was being serialized.
|
||||
auto j = m_env->get_type_id_canonical_type_map().find(type_id);
|
||||
if (j == m_env->get_type_id_canonical_type_map().end())
|
||||
std::cerr << "error: no type with type-id: '"
|
||||
<< type_id
|
||||
<< "' could be read back from the typeid file\n";
|
||||
{
|
||||
if (t->get_naked_canonical_type())
|
||||
std::cerr << "error: no type with type-id: '"
|
||||
<< type_id
|
||||
<< "' could be read back from the typeid file\n";
|
||||
}
|
||||
else if (j->second
|
||||
!= reinterpret_cast<uintptr_t>(t->get_canonical_type().get()))
|
||||
// So thecanonical type of 't' (at abixml de-serialization
|
||||
@ -1911,6 +1922,7 @@ read_corpus_from_input(read_context& ctxt)
|
||||
ctxt.clear_per_corpus_data();
|
||||
|
||||
corpus& corp = *ctxt.get_corpus();
|
||||
corp.set_origin(corpus::NATIVE_XML_ORIGIN);
|
||||
ctxt.set_exported_decls_builder(corp.get_exported_decls_builder().get());
|
||||
|
||||
handle_version_attribute(reader, corp);
|
||||
@ -1970,6 +1982,8 @@ read_corpus_from_input(read_context& ctxt)
|
||||
ctxt.clear_per_corpus_data();
|
||||
|
||||
corpus& corp = *ctxt.get_corpus();
|
||||
corp.set_origin(corpus::NATIVE_XML_ORIGIN);
|
||||
|
||||
ctxt.set_exported_decls_builder(corp.get_exported_decls_builder().get());
|
||||
|
||||
xml::xml_char_sptr path_str = XML_NODE_GET_ATTRIBUTE(node, "path");
|
||||
@ -2036,8 +2050,6 @@ read_corpus_from_input(read_context& ctxt)
|
||||
|
||||
ctxt.get_environment()->canonicalization_is_done(true);
|
||||
|
||||
corp.set_origin(corpus::NATIVE_XML_ORIGIN);
|
||||
|
||||
if (call_reader_next)
|
||||
{
|
||||
// This is the necessary counter-part of the xmlTextReaderExpand()
|
||||
@ -2863,6 +2875,70 @@ read_type_id_string(xmlNodePtr node, string& type_id)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Associate a type-id string with the type that was constructed from
|
||||
/// it.
|
||||
///
|
||||
/// Note that if we are not in "self comparison debugging" mode or if
|
||||
/// the type we are looking at is not canonicalized, then this
|
||||
/// function does nothing.
|
||||
///
|
||||
/// @param t the type built from the a type XML node that has a
|
||||
/// particular type-id.
|
||||
///
|
||||
/// @param type_id the type-id of type @p t.
|
||||
///
|
||||
/// @return true if the association was performed.
|
||||
static bool
|
||||
maybe_map_type_with_type_id(const type_base_sptr& t,
|
||||
const string& type_id)
|
||||
{
|
||||
if (!t)
|
||||
return false;
|
||||
|
||||
environment *env = t->get_environment();
|
||||
if (!env->self_comparison_debug_is_on()
|
||||
|| is_non_canonicalized_type(t.get()))
|
||||
return false;
|
||||
|
||||
env->get_pointer_type_id_map()[reinterpret_cast<uintptr_t>(t.get())] =
|
||||
type_id;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Associate a type-id string with the type that was constructed from
|
||||
/// it.
|
||||
///
|
||||
/// Note that if we are not in "self comparison debugging" mode or if
|
||||
/// the type we are looking at is not canonicalized, then this
|
||||
/// function does nothing.
|
||||
///
|
||||
/// @param t the type built from the a type XML node that has a
|
||||
/// particular type-id.
|
||||
///
|
||||
/// @param type_id the type-id of type @p t.
|
||||
///
|
||||
/// @return true if the association was performed.
|
||||
static bool
|
||||
maybe_map_type_with_type_id(const type_base_sptr& t,
|
||||
xmlNodePtr node)
|
||||
{
|
||||
if (!t)
|
||||
return false;
|
||||
|
||||
environment *env = t->get_environment();
|
||||
if (!env->self_comparison_debug_is_on()
|
||||
|| is_non_canonicalized_type(t.get()))
|
||||
return false;
|
||||
|
||||
string type_id;
|
||||
if (!read_type_id_string(node, type_id) || type_id.empty())
|
||||
return false;
|
||||
|
||||
return maybe_map_type_with_type_id(t, type_id);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// Set the naming typedef to a given decl depending on the content of
|
||||
@ -4196,6 +4272,7 @@ build_array_type_def(read_context& ctxt,
|
||||
if (array_type_def::subrange_sptr s =
|
||||
build_subrange_type(ctxt, n))
|
||||
{
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(s, n);
|
||||
if (add_to_current_scope)
|
||||
{
|
||||
add_decl_to_scope(s, ctxt.get_cur_scope());
|
||||
@ -5705,16 +5782,7 @@ build_type(read_context& ctxt,
|
||||
abi->record_type_as_reachable_from_public_interfaces(*t);
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
environment *env = ctxt.get_environment();
|
||||
if (t && env->self_comparison_debug_is_on())
|
||||
{
|
||||
string type_id;
|
||||
if (read_type_id_string(node, type_id))
|
||||
// Let's store the type-id of this type pointer.
|
||||
env->get_pointer_type_id_map()[reinterpret_cast<uintptr_t>(t.get())] = type_id;
|
||||
}
|
||||
#endif
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(t, node);
|
||||
|
||||
if (t)
|
||||
ctxt.maybe_canonicalize_type(t,/*force_delay=*/false );
|
||||
@ -5732,6 +5800,7 @@ handle_type_decl(read_context& ctxt,
|
||||
bool add_to_current_scope)
|
||||
{
|
||||
type_decl_sptr decl = build_type_decl(ctxt, node, add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
|
||||
if (decl && decl->get_scope())
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
@ -5765,6 +5834,7 @@ handle_qualified_type_decl(read_context& ctxt,
|
||||
qualified_type_def_sptr decl =
|
||||
build_qualified_type_decl(ctxt, node,
|
||||
add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
|
||||
if (decl && decl->get_scope())
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
@ -5782,6 +5852,7 @@ handle_pointer_type_def(read_context& ctxt,
|
||||
{
|
||||
pointer_type_def_sptr decl = build_pointer_type_def(ctxt, node,
|
||||
add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
|
||||
if (decl && decl->get_scope())
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
@ -5799,6 +5870,7 @@ handle_reference_type_def(read_context& ctxt,
|
||||
{
|
||||
reference_type_def_sptr decl = build_reference_type_def(ctxt, node,
|
||||
add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
|
||||
if (decl && decl->get_scope())
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
@ -5816,6 +5888,7 @@ handle_function_type(read_context& ctxt,
|
||||
{
|
||||
function_type_sptr type = build_function_type(ctxt, node,
|
||||
add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(type, node);
|
||||
ctxt.maybe_canonicalize_type(type, /*force_delay=*/true);
|
||||
return type;
|
||||
}
|
||||
@ -5832,6 +5905,7 @@ handle_array_type_def(read_context& ctxt,
|
||||
{
|
||||
array_type_def_sptr decl = build_array_type_def(ctxt, node,
|
||||
add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
}
|
||||
@ -5847,6 +5921,7 @@ handle_enum_type_decl(read_context& ctxt,
|
||||
enum_type_decl_sptr decl =
|
||||
build_enum_type_decl_if_not_suppressed(ctxt, node,
|
||||
add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
|
||||
if (decl && decl->get_scope())
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
@ -5862,6 +5937,7 @@ handle_typedef_decl(read_context& ctxt,
|
||||
{
|
||||
typedef_decl_sptr decl = build_typedef_decl(ctxt, node,
|
||||
add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(decl, node);
|
||||
if (decl && decl->get_scope())
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
@ -5914,6 +5990,7 @@ handle_class_decl(read_context& ctxt,
|
||||
{
|
||||
class_decl_sptr decl =
|
||||
build_class_decl_if_not_suppressed(ctxt, node, add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(is_type(decl), node);
|
||||
if (decl && decl->get_scope())
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
@ -5932,6 +6009,7 @@ handle_union_decl(read_context& ctxt,
|
||||
{
|
||||
union_decl_sptr decl =
|
||||
build_union_decl_if_not_suppressed(ctxt, node, add_to_current_scope);
|
||||
MAYBE_MAP_TYPE_WITH_TYPE_ID(is_type(decl), node);
|
||||
if (decl && decl->get_scope())
|
||||
ctxt.maybe_canonicalize_type(decl, /*force_delay=*/false);
|
||||
return decl;
|
||||
@ -6162,7 +6240,11 @@ load_canonical_type_ids(xml_reader::read_context& ctxt, const string &file_path)
|
||||
s << canonical_address;
|
||||
uintptr_t v = 0;
|
||||
s >> std::hex >> v;
|
||||
if (!id.empty())
|
||||
if (!id.empty()
|
||||
// 0xdeadbabe is the special value the hash of types
|
||||
// that are not canonicalized. Look into function
|
||||
// hash_as_canonical_type_or_constant for the details.
|
||||
&& v != 0xdeadbabe)
|
||||
ctxt.get_environment()->get_type_id_canonical_type_map()[id] = v;
|
||||
}
|
||||
}
|
||||
|
@ -836,6 +836,20 @@ public:
|
||||
m_emitted_decls_map[irepr] = true;
|
||||
}
|
||||
|
||||
/// Get the set of types that have been emitted.
|
||||
///
|
||||
/// @return the set of types that have been emitted.
|
||||
const type_ptr_set_type&
|
||||
get_emitted_types_set() const
|
||||
{return m_emitted_type_set;}
|
||||
|
||||
/// Get the set of types that have been emitted.
|
||||
///
|
||||
/// @return the set of types that have been emitted.
|
||||
const type_ptr_set_type&
|
||||
get_emitted_decl_only_types_set() const
|
||||
{return m_emitted_decl_only_set;}
|
||||
|
||||
/// Clear the map that contains the IDs of the types that has been
|
||||
/// recorded as having been written out to the XML output.
|
||||
void
|
||||
@ -4764,6 +4778,47 @@ dump_decl_location(const decl_base_sptr d)
|
||||
{dump_decl_location(d.get());}
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
/// Write one of the records of the "type-ids" debugging file.
|
||||
///
|
||||
/// This is a sub-routine of write_canonical_type_ids.
|
||||
///
|
||||
/// @param ctxt the context to use.
|
||||
///
|
||||
/// @param type the type which canonical type pointer value to emit.
|
||||
///
|
||||
/// @param o the output stream to write to.
|
||||
static void
|
||||
write_type_record(xml_writer::write_context& ctxt,
|
||||
const type_base* type,
|
||||
ostream& o)
|
||||
{
|
||||
// We want to serialize a type record which content looks like:
|
||||
//
|
||||
// <type>
|
||||
// <id>type-id-573</id>
|
||||
// <c>0x262ee28</c>
|
||||
// </type>
|
||||
// <type>
|
||||
// <id>type-id-569</id>
|
||||
// <c>0x2628298</c>
|
||||
// </type>
|
||||
// <type>
|
||||
// <id>type-id-575</id>
|
||||
// <c>0x25f9ba8</c>
|
||||
// </type>
|
||||
|
||||
string id = ctxt.get_id_for_type (type);
|
||||
o << " <type>\n"
|
||||
<< " <id>" << id << "</id>\n"
|
||||
<< " <c>"
|
||||
<< std::hex
|
||||
<< (type->get_canonical_type()
|
||||
? reinterpret_cast<uintptr_t>(type->get_canonical_type().get())
|
||||
: 0xdeadbabe)
|
||||
<< "</c>\n"
|
||||
<< " </type>\n";
|
||||
}
|
||||
|
||||
/// Serialize the map that is stored at
|
||||
/// environment::get_type_id_canonical_type_map() to an output stream.
|
||||
///
|
||||
@ -4794,17 +4849,13 @@ write_canonical_type_ids(xml_writer::write_context& ctxt, ostream& o)
|
||||
// <abixml-types-check>
|
||||
|
||||
o << "<abixml-types-check>\n";
|
||||
for (const auto &p : ctxt.get_environment()->get_canonical_types_map())
|
||||
for (const auto& type_sptr : p.second)
|
||||
{
|
||||
string id = ctxt.get_id_for_type (type_sptr);
|
||||
o << " <type>\n"
|
||||
<< " <id>" << id << "</id>\n"
|
||||
<< " <c>"
|
||||
<< std::hex << type_sptr->get_canonical_type().get()
|
||||
<< "</c>\n"
|
||||
<< " </type>\n";
|
||||
}
|
||||
|
||||
for (const auto &type : ctxt.get_emitted_types_set())
|
||||
write_type_record(ctxt, type, o);
|
||||
|
||||
for (const auto &type : ctxt.get_emitted_decl_only_types_set())
|
||||
write_type_record(ctxt, type, o);
|
||||
|
||||
o << "</abixml-types-check>\n";
|
||||
}
|
||||
|
||||
|
@ -591,10 +591,7 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
if (opts.debug_abidiff
|
||||
&& !opts.type_id_file_path.empty())
|
||||
{
|
||||
load_canonical_type_ids(*read_ctxt, opts.type_id_file_path);
|
||||
remove(opts.type_id_file_path.c_str());
|
||||
}
|
||||
load_canonical_type_ids(*read_ctxt, opts.type_id_file_path);
|
||||
#endif
|
||||
t.start();
|
||||
corpus_sptr corp2 =
|
||||
@ -636,6 +633,12 @@ load_corpus_and_write_abixml(char* argv[],
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_DEBUG_SELF_COMPARISON
|
||||
if (opts.debug_abidiff
|
||||
&& !opts.type_id_file_path.empty())
|
||||
remove(opts.type_id_file_path.c_str());
|
||||
#endif
|
||||
|
||||
if (opts.noout)
|
||||
return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user