summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDodji Seketeli <dodji@redhat.com>2022-02-17 12:22:25 +0100
committerDodji Seketeli <dodji@redhat.com>2022-02-28 10:24:46 +0100
commit1483f6cb492a6bd89bc1ab0b5be50f9c25fa3407 (patch)
treed662b2412f90cc8cd4ffcbebe00c0b03200700ac
parentconfigure: Remove use of obsolete AC_CONFIG_HEADER (diff)
downloadlibabigail-1483f6cb492a6bd89bc1ab0b5be50f9c25fa3407.tar.gz
libabigail-1483f6cb492a6bd89bc1ab0b5be50f9c25fa3407.tar.bz2
libabigail-1483f6cb492a6bd89bc1ab0b5be50f9c25fa3407.tar.xz
abilint: add the --show-type-use option
"abilint --show-type-use <type-id> <abixml-file>" is a facility that shows how a type defined in an abixml file is used. That is, it emits a textual representation of how the use a type is used up until the function or global variable that constitutes an entry point in the API corpus. Here is an example of its use: test-read-write$ abilint --noout --show-type-use type-id-5 test17.xml Type ID 'type-id-5' is for type 'enum E' The usage graph for that type is: | -> enum E -> E S::m2 -> class S -> S* -> method void S::S() | -> enum E -> E S::m2 -> class S -> S* -> method void S::__base_ctor () | -> enum E -> E S::m2 -> class S -> S* -> method void S::__comp_ctor () | -> enum E -> E S::m2 -> class S -> S* -> method void S::S(S&) | -> enum E -> E S::m2 -> class S -> S* -> S& -> method void S::S(S&) | -> enum E -> E S::m2 -> class S -> S* -> S& -> S var | -> enum E -> E S::m2 -> class S -> S* -> S& -> E S::m2 -> class S -> S* -> method void S::S() | -> enum E -> E S::m2 -> class S -> S* -> S& -> E S::m2 -> class S -> S* -> method void S::__base_ctor () | -> enum E -> E S::m2 -> class S -> S* -> S& -> E S::m2 -> class S -> S* -> method void S::__comp_ctor () | -> enum E -> E S::m2 -> class S -> S* -> S& -> E S::m2 -> class S -> S* -> method void S::S(S&) | -> enum E -> E S::m2 -> class S -> S* -> S& -> E S::m2 -> class S -> S* -> S& -> method void S::S(S&) | -> enum E -> E S::m2 -> class S -> S* -> S& -> E S::m2 -> class S -> S* -> S& -> S var $ The screenshot above should be self explanatory. This facility is useful to analyse type usage and find potential issues in how libabigail represents some types. To activate this feature, one needs to configure the package with the configure option "--enable-show-type-use-in-abilint". * configure.ac: Define the --enable-show-type-use-in-abilint configure option. It defines the WITH_SHOW_TYPE_USE_IN_ABILINT macro. * include/abg-reader.h (read_translation_unit): Add an overload that takes the read context. (get_types_from_type_id, get_artifact_used_by_relation_map): Declare new functions. * src/abg-reader.cc (get_types_from_type_id) (get_artifact_used_by_relation_map): Declare these functions as friend of the read_context type. (read_context::m_artifact_used_by_map): (read_context::key_type_decl): Replace the shared_ptr<type_base> type of the first parm by the equivalent type_base_sptr type. (read_context::{record_artifact_as_used_by, record_artifacts_as_used_in_fn_decl, record_artifacts_as_used_in_fn_type}): Add new methods guarded by the WITH_SHOW_TYPE_USE_IN_ABILINT macro. (get_types_from_type_id, get_artifact_used_by_relation_map): Define new functions guarded by the WITH_SHOW_TYPE_USE_IN_ABILINT macro. (read_translation_unit): Define new overload. (RECORD_ARTIFACT_AS_USED_BY, RECORD_ARTIFACTS_AS_USED_IN_FN_DECL) (RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE): Define new macros. (build_function_decl, build_var_decl, build_qualified_type_decl) (build_pointer_type_def, build_reference_type_def) (build_function_type, build_array_type_def, build_enum_type_decl) (build_typedef_decl, build_class_decl, build_union_decl): Use the macros above to mark the relevant sub-types as used by the artifact being built. * tools/abilint.cc (struct artifact_use_relation_tree): Define new type, guarded by the WITH_SHOW_TYPE_USE_IN_ABILINT macro. (fill_artifact_use_tree, build_type_use_tree, emit_trace) (emit_artifact_use_trace, emit_artifact_use_trace) (show_how_type_is_used): Define static functions guarded by the WITH_SHOW_TYPE_USE_IN_ABILINT macro. (display_usage): Add doc string for the --show-type-use option, guarded by the WITH_SHOW_TYPE_USE_IN_ABILINT macro. (parse_command_line): Parse the --show-type-use option, guarded by the WITH_SHOW_TYPE_USE_IN_ABILINT macro. (main): Slight re-organisation to make the abixml file reading use a read_context. That read context is then used to analyze how a given type is used whenever the --show-type-use option is used. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
-rw-r--r--configure.ac17
-rw-r--r--include/abg-reader.h13
-rw-r--r--src/abg-reader.cc221
-rw-r--r--tools/abilint.cc436
4 files changed, 664 insertions, 23 deletions
diff --git a/configure.ac b/configure.ac
index fc35a31a..97b3469f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -83,6 +83,12 @@ AC_ARG_ENABLE(debug-type-canonicalization,
83 ENABLE_DEBUG_TYPE_CANONICALIZATION=$enableval, 83 ENABLE_DEBUG_TYPE_CANONICALIZATION=$enableval,
84 ENABLE_DEBUG_TYPE_CANONICALIZATION=no) 84 ENABLE_DEBUG_TYPE_CANONICALIZATION=no)
85 85
86AC_ARG_ENABLE(show-type-use-in-abilint,
87 AS_HELP_STRING([--enable-show-type-use-in-abilint=yes|no],
88 ['enable abilint --show-type-use'(default is no)]),
89 ENABLE_SHOW_TYPE_USE_IN_ABILINT=$enableval,
90 ENABLE_SHOW_TYPE_USE_IN_ABILINT=no)
91
86AC_ARG_ENABLE(deb, 92AC_ARG_ENABLE(deb,
87 AS_HELP_STRING([--enable-deb=yes|no|auto], 93 AS_HELP_STRING([--enable-deb=yes|no|auto],
88 [enable the support of deb in abipkgdiff (default is auto)]), 94 [enable the support of deb in abipkgdiff (default is auto)]),
@@ -373,6 +379,16 @@ fi
373 379
374AM_CONDITIONAL(ENABLE_DEBUG_SELF_COMPARISON, test x$ENABLE_DEBUG_SELF_COMPARISON = xyes) 380AM_CONDITIONAL(ENABLE_DEBUG_SELF_COMPARISON, test x$ENABLE_DEBUG_SELF_COMPARISON = xyes)
375 381
382dnl enable support of abilint --show-type-use <type-id>
383if test x$ENABLE_SHOW_TYPE_USE_IN_ABILINT = xyes; then
384 AC_DEFINE([WITH_SHOW_TYPE_USE_IN_ABILINT], 1, [compile support of abilint --show-type-use])
385 AC_MSG_NOTICE([support of abilint --show-type-use <type-id> is enabled])
386else
387 AC_MSG_NOTICE([support of abilint --show-type-use <type-id> is disabled])
388fi
389
390AM_CONDITIONAL(ENABLE_SHOW_TYPE_USE_IN_ABILINT, test x$ENABLE_SHOW_TYPE_USE_IN_ABILINT = xyes)
391
376dnl enable the debugging of type canonicalization when doing abidw --debug-tc <binary> 392dnl enable the debugging of type canonicalization when doing abidw --debug-tc <binary>
377if test x$ENABLE_DEBUG_TYPE_CANONICALIZATION = xyes; then 393if test x$ENABLE_DEBUG_TYPE_CANONICALIZATION = xyes; then
378 AC_DEFINE([WITH_DEBUG_TYPE_CANONICALIZATION], 394 AC_DEFINE([WITH_DEBUG_TYPE_CANONICALIZATION],
@@ -1011,6 +1027,7 @@ AC_MSG_NOTICE([
1011 libdw has the dwarf_getalt function : ${FOUND_DWARF_GETALT_IN_LIBDW} 1027 libdw has the dwarf_getalt function : ${FOUND_DWARF_GETALT_IN_LIBDW}
1012 Enable rpm support in abipkgdiff : ${ENABLE_RPM} 1028 Enable rpm support in abipkgdiff : ${ENABLE_RPM}
1013 Enable rpm/zstd in abipkgdiff testing : ${ENABLE_RPM_ZSTD} 1029 Enable rpm/zstd in abipkgdiff testing : ${ENABLE_RPM_ZSTD}
1030 Enable abilint --show-type-use <type-id> : ${ENABLE_SHOW_TYPE_USE_IN_ABILINT}
1014 Enable self comparison debugging : ${ENABLE_DEBUG_SELF_COMPARISON} 1031 Enable self comparison debugging : ${ENABLE_DEBUG_SELF_COMPARISON}
1015 Enable type canonicalization debugging : ${ENABLE_DEBUG_TYPE_CANONICALIZATION} 1032 Enable type canonicalization debugging : ${ENABLE_DEBUG_TYPE_CANONICALIZATION}
1016 Enable deb support in abipkgdiff : ${ENABLE_DEB} 1033 Enable deb support in abipkgdiff : ${ENABLE_DEB}
diff --git a/include/abg-reader.h b/include/abg-reader.h
index a3aa0f85..78771c56 100644
--- a/include/abg-reader.h
+++ b/include/abg-reader.h
@@ -26,6 +26,8 @@ namespace xml_reader
26 26
27using namespace abigail::ir; 27using namespace abigail::ir;
28 28
29class read_context;
30
29translation_unit_sptr 31translation_unit_sptr
30read_translation_unit_from_file(const std::string& file_path, 32read_translation_unit_from_file(const std::string& file_path,
31 environment* env); 33 environment* env);
@@ -38,7 +40,8 @@ translation_unit_sptr
38read_translation_unit_from_istream(std::istream* in, 40read_translation_unit_from_istream(std::istream* in,
39 environment* env); 41 environment* env);
40 42
41class read_context; 43translation_unit_sptr
44read_translation_unit(read_context&);
42 45
43/// A convenience typedef for a shared pointer to read_context. 46/// A convenience typedef for a shared pointer to read_context.
44typedef shared_ptr<read_context> read_context_sptr; 47typedef shared_ptr<read_context> read_context_sptr;
@@ -81,6 +84,14 @@ add_read_context_suppressions(read_context& ctxt,
81void 84void
82consider_types_not_reachable_from_public_interfaces(read_context& ctxt, 85consider_types_not_reachable_from_public_interfaces(read_context& ctxt,
83 bool flag); 86 bool flag);
87
88#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
89vector<type_base_sptr>*
90get_types_from_type_id(read_context&, const string&);
91
92unordered_map<type_or_decl_base*, vector<type_or_decl_base*>>*
93get_artifact_used_by_relation_map(read_context&);
94#endif
84}//end xml_reader 95}//end xml_reader
85 96
86#ifdef WITH_DEBUG_SELF_COMPARISON 97#ifdef WITH_DEBUG_SELF_COMPARISON
diff --git a/src/abg-reader.cc b/src/abg-reader.cc
index 541ca179..7070fa9f 100644
--- a/src/abg-reader.cc
+++ b/src/abg-reader.cc
@@ -102,6 +102,12 @@ public:
102 102
103 typedef unordered_map<xmlNodePtr, decl_base_sptr> xml_node_decl_base_sptr_map; 103 typedef unordered_map<xmlNodePtr, decl_base_sptr> xml_node_decl_base_sptr_map;
104 104
105 friend vector<type_base_sptr>* get_types_from_type_id(read_context&,
106 const string&);
107
108 friend unordered_map<type_or_decl_base*, vector<type_or_decl_base*>>*
109 get_artifact_used_by_relation_map(read_context& ctxt);
110
105private: 111private:
106 string m_path; 112 string m_path;
107 environment* m_env; 113 environment* m_env;
@@ -120,6 +126,10 @@ private:
120 suppr::suppressions_type m_supprs; 126 suppr::suppressions_type m_supprs;
121 bool m_tracking_non_reachable_types; 127 bool m_tracking_non_reachable_types;
122 bool m_drop_undefined_syms; 128 bool m_drop_undefined_syms;
129#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
130 unordered_map<type_or_decl_base*,
131 vector<type_or_decl_base*>> m_artifact_used_by_map;
132#endif
123 133
124 read_context(); 134 read_context();
125 135
@@ -551,7 +561,7 @@ public:
551 /// 561 ///
552 /// @return true upon successful completion. 562 /// @return true upon successful completion.
553 bool 563 bool
554 key_type_decl(shared_ptr<type_base> type, const string& id) 564 key_type_decl(const type_base_sptr& type, const string& id)
555 { 565 {
556 if (!type) 566 if (!type)
557 return false; 567 return false;
@@ -584,7 +594,7 @@ public:
584 return true; 594 return true;
585 } 595 }
586 596
587 /// Associate an ID to a class template. 597 /// Associate an ID to a class template.
588 /// 598 ///
589 /// @param class_tmpl_decl the class template to consider. 599 /// @param class_tmpl_decl the class template to consider.
590 /// 600 ///
@@ -607,6 +617,94 @@ public:
607 return true; 617 return true;
608 } 618 }
609 619
620#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
621 /// Record that an artifact is used by another one.
622 ///
623 /// If a type is "used" by another one (as in the type is a sub-type
624 /// of another one), this function records that relation.
625 ///
626 /// @param used the type that is used.
627 ///
628 /// @param user the type that uses @p used.
629 void
630 record_artifact_as_used_by(type_or_decl_base* used,
631 type_or_decl_base* user)
632 {
633 if (m_artifact_used_by_map.find(used) == m_artifact_used_by_map.end())
634 {
635 vector<type_or_decl_base*> v;
636 m_artifact_used_by_map[used] = v;
637 }
638 m_artifact_used_by_map[used].push_back(user);
639 }
640
641 /// Record that an artifact is used by another one.
642 ///
643 /// If a type is "used" by another one (as in the type is a sub-type
644 /// of another one), this function records that relation.
645 ///
646 /// @param used the type that is used.
647 ///
648 /// @param user the type that uses @p used.
649 void
650 record_artifact_as_used_by(const type_or_decl_base_sptr& used,
651 const type_or_decl_base_sptr& user)
652 {record_artifact_as_used_by(used.get(), user.get());}
653
654 /// Record the sub-types of a fn-decl as being used by the fn-decl.
655 ///
656 /// @param fn the function decl to consider.
657 void
658 record_artifacts_as_used_in_fn_decl(const function_decl *fn)
659 {
660 if (!fn)
661 return;
662
663 type_base_sptr t = fn->get_return_type();
664 record_artifact_as_used_by(t.get(), const_cast<function_decl*>(fn));
665
666 for (auto pit : fn->get_parameters())
667 {
668 type_base_sptr t = pit->get_type();
669 record_artifact_as_used_by(t.get(), const_cast<function_decl*>(fn));
670 }
671 }
672
673 /// Record the sub-types of a function decl as being used by it.
674 ///
675 /// @param fn the function decl to consider.
676 void
677 record_artifacts_as_used_in_fn_decl(const function_decl_sptr& fn)
678 {record_artifacts_as_used_in_fn_decl(fn.get());}
679
680 /// Record the sub-types of a function type as being used by it.
681 ///
682 /// @param fn_type the function decl to consider.
683 void
684 record_artifacts_as_used_in_fn_type(const function_type *fn_type)
685 {
686 if (!fn_type)
687 return;
688
689 type_base_sptr t = fn_type->get_return_type();
690 record_artifact_as_used_by(t.get(), const_cast<function_type*>(fn_type));
691
692 for (auto pit : fn_type->get_parameters())
693 {
694 type_base_sptr t = pit->get_type();
695 record_artifact_as_used_by(t.get(),
696 const_cast<function_type*>(fn_type));
697 }
698 }
699
700 /// Record the sub-types of a function type as being used by it.
701 ///
702 /// @param fn_type the function decl to consider.
703 void
704 record_artifacts_as_used_in_fn_type(const function_type_sptr& fn_type)
705 {record_artifacts_as_used_in_fn_type(fn_type.get());}
706#endif
707
610 /// This function must be called on each declaration that is created during 708 /// This function must be called on each declaration that is created during
611 /// the parsing. It adds the declaration to the current scope, and updates 709 /// the parsing. It adds the declaration to the current scope, and updates
612 /// the state of the parsing context accordingly. 710 /// the state of the parsing context accordingly.
@@ -1138,10 +1236,8 @@ public:
1138};// end class read_context 1236};// end class read_context
1139 1237
1140static int advance_cursor(read_context&); 1238static int advance_cursor(read_context&);
1141static bool 1239static bool read_translation_unit(read_context&, translation_unit&, xmlNodePtr);
1142read_translation_unit(read_context&, translation_unit&, xmlNodePtr); 1240static translation_unit_sptr get_or_read_and_add_translation_unit(read_context&, xmlNodePtr);
1143static translation_unit_sptr
1144get_or_read_and_add_translation_unit(read_context&, xmlNodePtr);
1145static translation_unit_sptr read_translation_unit_from_input(read_context&); 1241static translation_unit_sptr read_translation_unit_from_input(read_context&);
1146static bool read_symbol_db_from_input(read_context&, 1242static bool read_symbol_db_from_input(read_context&,
1147 string_elf_symbols_map_sptr&, 1243 string_elf_symbols_map_sptr&,
@@ -1300,6 +1396,19 @@ static decl_base_sptr handle_union_decl(read_context&, xmlNodePtr, bool);
1300static decl_base_sptr handle_function_tdecl(read_context&, xmlNodePtr, bool); 1396static decl_base_sptr handle_function_tdecl(read_context&, xmlNodePtr, bool);
1301static decl_base_sptr handle_class_tdecl(read_context&, xmlNodePtr, bool); 1397static decl_base_sptr handle_class_tdecl(read_context&, xmlNodePtr, bool);
1302 1398
1399#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
1400#define RECORD_ARTIFACT_AS_USED_BY(ctxt, used, user) \
1401 ctxt.record_artifact_as_used_by(used,user)
1402#define RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(ctxt, fn) \
1403 ctxt.record_artifacts_as_used_in_fn_decl(fn)
1404#define RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(ctxt, fn_type)\
1405 ctxt.record_artifacts_as_used_in_fn_type(fn_type)
1406#else
1407#define RECORD_ARTIFACT_AS_USED_BY(ctxt, used, user)
1408#define RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(ctxt, fn)
1409#define RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(ctxt, fn_type)
1410#endif
1411
1303/// Get the IR node representing the scope for a given XML node. 1412/// Get the IR node representing the scope for a given XML node.
1304/// 1413///
1305/// This function might trigger the building of a full sub-tree of IR. 1414/// This function might trigger the building of a full sub-tree of IR.
@@ -1846,6 +1955,35 @@ consider_types_not_reachable_from_public_interfaces(read_context& ctxt,
1846 bool flag) 1955 bool flag)
1847{ctxt.tracking_non_reachable_types(flag);} 1956{ctxt.tracking_non_reachable_types(flag);}
1848 1957
1958#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
1959/// Get the vector of types that have a given type-id.
1960///
1961/// This function is available only if the project has been configured
1962/// with --enable-show-type-use-in-abilint.
1963///
1964/// @param ctxt the abixml text reader context to use.
1965///
1966/// @param type_id the type-id to consider.
1967vector<type_base_sptr>*
1968get_types_from_type_id(read_context& ctxt, const string& type_id)
1969{
1970 auto it = ctxt.m_types_map.find(type_id);
1971 if (it == ctxt.m_types_map.end())
1972 return nullptr;
1973 return &it->second;
1974}
1975
1976/// Get the map that associates an artififact to its users.
1977///
1978/// This function is available only if the project has been configured
1979/// with --enable-show-type-use-in-abilint.
1980///
1981/// @param ctxt the abixml text reader context to use.
1982unordered_map<type_or_decl_base*, vector<type_or_decl_base*>>*
1983get_artifact_used_by_relation_map(read_context& ctxt)
1984{return &ctxt.m_artifact_used_by_map;}
1985#endif
1986
1849/// Read the "version" attribute from the current XML element which is 1987/// Read the "version" attribute from the current XML element which is
1850/// supposed to be a corpus or a corpus group and set the format 1988/// supposed to be a corpus or a corpus group and set the format
1851/// version to the corpus object accordingly. 1989/// version to the corpus object accordingly.
@@ -2219,6 +2357,23 @@ read_translation_unit_from_buffer(const string& buffer,
2219 return tu; 2357 return tu;
2220} 2358}
2221 2359
2360/// Parse a translation unit from an abixml input from a given
2361/// context.
2362///
2363/// @param ctxt the @ref read_context to consider.
2364///
2365/// @return the constructed @ref translation_unit from the content of
2366/// the input abixml.
2367translation_unit_sptr
2368read_translation_unit(read_context& ctxt)
2369{
2370 translation_unit_sptr tu = read_translation_unit_from_input(ctxt);
2371 ctxt.get_environment()->canonicalization_is_done(false);
2372 ctxt.perform_late_type_canonicalizing();
2373 ctxt.get_environment()->canonicalization_is_done(true);
2374 return tu;
2375}
2376
2222/// This function is called by @ref read_translation_unit_from_input. 2377/// This function is called by @ref read_translation_unit_from_input.
2223/// It handles the current xml element node of the reading context. 2378/// It handles the current xml element node of the reading context.
2224/// The result of the "handling" is to build the representation of the 2379/// The result of the "handling" is to build the representation of the
@@ -3407,6 +3562,7 @@ build_function_decl(read_context& ctxt,
3407 3562
3408 maybe_set_artificial_location(ctxt, node, fn_decl); 3563 maybe_set_artificial_location(ctxt, node, fn_decl);
3409 ctxt.push_decl_to_current_scope(fn_decl, add_to_current_scope); 3564 ctxt.push_decl_to_current_scope(fn_decl, add_to_current_scope);
3565 RECORD_ARTIFACTS_AS_USED_IN_FN_DECL(ctxt, fn_decl);
3410 3566
3411 elf_symbol_sptr sym = build_elf_symbol_from_reference(ctxt, node); 3567 elf_symbol_sptr sym = build_elf_symbol_from_reference(ctxt, node);
3412 if (sym) 3568 if (sym)
@@ -3645,6 +3801,10 @@ build_var_decl(read_context& ctxt,
3645 decl->set_symbol(sym); 3801 decl->set_symbol(sym);
3646 3802
3647 ctxt.push_decl_to_current_scope(decl, add_to_current_scope); 3803 ctxt.push_decl_to_current_scope(decl, add_to_current_scope);
3804 if (add_to_current_scope)
3805 // This variable is really being kept in the IR, so let's record
3806 // that it's using its type.
3807 RECORD_ARTIFACT_AS_USED_BY(ctxt, underlying_type, decl);
3648 3808
3649 if (decl->get_symbol() && decl->get_symbol()->is_public()) 3809 if (decl->get_symbol() && decl->get_symbol()->is_public())
3650 decl->set_is_in_public_symbol_table(true); 3810 decl->set_is_in_public_symbol_table(true);
@@ -3813,6 +3973,7 @@ build_qualified_type_decl(read_context& ctxt,
3813 decl.reset(new qualified_type_def(underlying_type, cv, loc)); 3973 decl.reset(new qualified_type_def(underlying_type, cv, loc));
3814 maybe_set_artificial_location(ctxt, node, decl); 3974 maybe_set_artificial_location(ctxt, node, decl);
3815 ctxt.push_and_key_type_decl(decl, id, add_to_current_scope); 3975 ctxt.push_and_key_type_decl(decl, id, add_to_current_scope);
3976 RECORD_ARTIFACT_AS_USED_BY(ctxt, underlying_type, decl);
3816 } 3977 }
3817 3978
3818 ctxt.map_xml_node_to_decl(node, decl); 3979 ctxt.map_xml_node_to_decl(node, decl);
@@ -3891,7 +4052,7 @@ build_pointer_type_def(read_context& ctxt,
3891 ABG_ASSERT(pointed_to_type); 4052 ABG_ASSERT(pointed_to_type);
3892 4053
3893 t->set_pointed_to_type(pointed_to_type); 4054 t->set_pointed_to_type(pointed_to_type);
3894 4055 RECORD_ARTIFACT_AS_USED_BY(ctxt, pointed_to_type, t);
3895 return t; 4056 return t;
3896} 4057}
3897 4058
@@ -3970,6 +4131,7 @@ build_reference_type_def(read_context& ctxt,
3970 ctxt.build_or_get_type_decl(type_id,/*add_to_current_scope=*/ true); 4131 ctxt.build_or_get_type_decl(type_id,/*add_to_current_scope=*/ true);
3971 ABG_ASSERT(pointed_to_type); 4132 ABG_ASSERT(pointed_to_type);
3972 t->set_pointed_to_type(pointed_to_type); 4133 t->set_pointed_to_type(pointed_to_type);
4134 RECORD_ARTIFACT_AS_USED_BY(ctxt, pointed_to_type, t);
3973 4135
3974 return t; 4136 return t;
3975} 4137}
@@ -4034,6 +4196,7 @@ build_function_type(read_context& ctxt,
4034 4196
4035 ctxt.get_translation_unit()->bind_function_type_life_time(fn_type); 4197 ctxt.get_translation_unit()->bind_function_type_life_time(fn_type);
4036 ctxt.key_type_decl(fn_type, id); 4198 ctxt.key_type_decl(fn_type, id);
4199 RECORD_ARTIFACTS_AS_USED_IN_FN_TYPE(ctxt, fn_type);
4037 4200
4038 for (xmlNodePtr n = xmlFirstElementChild(node); 4201 for (xmlNodePtr n = xmlFirstElementChild(node);
4039 n; 4202 n;
@@ -4291,6 +4454,7 @@ build_array_type_def(read_context& ctxt,
4291 maybe_set_artificial_location(ctxt, node, ar_type); 4454 maybe_set_artificial_location(ctxt, node, ar_type);
4292 if (ctxt.push_and_key_type_decl(ar_type, id, add_to_current_scope)) 4455 if (ctxt.push_and_key_type_decl(ar_type, id, add_to_current_scope))
4293 ctxt.map_xml_node_to_decl(node, ar_type); 4456 ctxt.map_xml_node_to_decl(node, ar_type);
4457 RECORD_ARTIFACT_AS_USED_BY(ctxt, type, ar_type);
4294 4458
4295 if (dimensions != ar_type->get_dimension_count() 4459 if (dimensions != ar_type->get_dimension_count()
4296 || (alignment_in_bits 4460 || (alignment_in_bits
@@ -4472,6 +4636,7 @@ build_enum_type_decl(read_context& ctxt,
4472 { 4636 {
4473 maybe_set_naming_typedef(ctxt, node, t); 4637 maybe_set_naming_typedef(ctxt, node, t);
4474 ctxt.map_xml_node_to_decl(node, t); 4638 ctxt.map_xml_node_to_decl(node, t);
4639 RECORD_ARTIFACT_AS_USED_BY(ctxt, underlying_type, t);
4475 return t; 4640 return t;
4476 } 4641 }
4477 4642
@@ -4534,6 +4699,7 @@ build_typedef_decl(read_context& ctxt,
4534 maybe_set_artificial_location(ctxt, node, t); 4699 maybe_set_artificial_location(ctxt, node, t);
4535 ctxt.push_and_key_type_decl(t, id, add_to_current_scope); 4700 ctxt.push_and_key_type_decl(t, id, add_to_current_scope);
4536 ctxt.map_xml_node_to_decl(node, t); 4701 ctxt.map_xml_node_to_decl(node, t);
4702 RECORD_ARTIFACT_AS_USED_BY(ctxt, underlying_type, t);
4537 4703
4538 return t; 4704 return t;
4539} 4705}
@@ -4897,6 +5063,21 @@ build_class_decl(read_context& ctxt,
4897 offset_in_bits); 5063 offset_in_bits);
4898 if (is_static) 5064 if (is_static)
4899 ctxt.maybe_add_var_to_exported_decls(v.get()); 5065 ctxt.maybe_add_var_to_exported_decls(v.get());
5066 // Now let's record the fact that the data
5067 // member uses its type and that the class being
5068 // built uses the data member.
5069 if (is_anonymous_data_member(v))
5070 // This data member is anonymous so recording
5071 // that it uses its type is useless because we
5072 // can't name it. Rather, let's record that
5073 // the class being built uses the type of the
5074 // (anonymous) data member.
5075 RECORD_ARTIFACT_AS_USED_BY(ctxt, v->get_type(), decl);
5076 else
5077 {
5078 RECORD_ARTIFACT_AS_USED_BY(ctxt, v->get_type(), v);
5079 RECORD_ARTIFACT_AS_USED_BY(ctxt, v, decl);
5080 }
4900 } 5081 }
4901 } 5082 }
4902 } 5083 }
@@ -5243,10 +5424,27 @@ build_union_decl(read_context& ctxt,
5243 } 5424 }
5244 if (!is_static 5425 if (!is_static
5245 || !variable_is_suppressed(ctxt, decl.get(), *v)) 5426 || !variable_is_suppressed(ctxt, decl.get(), *v))
5246 decl->add_data_member(v, access, 5427 {
5247 is_laid_out, 5428 decl->add_data_member(v, access,
5248 is_static, 5429 is_laid_out,
5249 offset_in_bits); 5430 is_static,
5431 offset_in_bits);
5432 // Now let's record the fact that the data
5433 // member uses its type and that the union being
5434 // built uses the data member.
5435 if (is_anonymous_data_member(v))
5436 // This data member is anonymous so recording
5437 // that it uses its type is useless because we
5438 // can't name it. Rather, let's record that
5439 // the class being built uses the type of the
5440 // (anonymous) data member.
5441 RECORD_ARTIFACT_AS_USED_BY(ctxt, v->get_type(), decl);
5442 else
5443 {
5444 RECORD_ARTIFACT_AS_USED_BY(ctxt, v->get_type(), v);
5445 RECORD_ARTIFACT_AS_USED_BY(ctxt, v, decl);
5446 }
5447 }
5250 } 5448 }
5251 } 5449 }
5252 } 5450 }
@@ -5526,7 +5724,6 @@ build_type_tparameter(read_context& ctxt,
5526 return result; 5724 return result;
5527} 5725}
5528 5726
5529
5530/// Build a tmpl_parm_type_composition from a 5727/// Build a tmpl_parm_type_composition from a
5531/// "template-parameter-type-composition" xml element node. 5728/// "template-parameter-type-composition" xml element node.
5532/// 5729///
diff --git a/tools/abilint.cc b/tools/abilint.cc
index efddd77b..ba2de634 100644
--- a/tools/abilint.cc
+++ b/tools/abilint.cc
@@ -41,6 +41,8 @@ using std::cout;
41using std::ostream; 41using std::ostream;
42using std::ofstream; 42using std::ofstream;
43using std::vector; 43using std::vector;
44using std::unordered_set;
45using std::unique_ptr;
44using abigail::tools_utils::emit_prefix; 46using abigail::tools_utils::emit_prefix;
45using abigail::tools_utils::check_file; 47using abigail::tools_utils::check_file;
46using abigail::tools_utils::file_type; 48using abigail::tools_utils::file_type;
@@ -48,6 +50,10 @@ using abigail::tools_utils::guess_file_type;
48using abigail::suppr::suppression_sptr; 50using abigail::suppr::suppression_sptr;
49using abigail::suppr::suppressions_type; 51using abigail::suppr::suppressions_type;
50using abigail::suppr::read_suppressions; 52using abigail::suppr::read_suppressions;
53using abigail::type_base;
54using abigail::type_or_decl_base;
55using abigail::type_base_sptr;
56using abigail::type_or_decl_base_sptr;
51using abigail::corpus; 57using abigail::corpus;
52using abigail::corpus_sptr; 58using abigail::corpus_sptr;
53using abigail::xml_reader::read_translation_unit_from_file; 59using abigail::xml_reader::read_translation_unit_from_file;
@@ -55,6 +61,10 @@ using abigail::xml_reader::read_translation_unit_from_istream;
55using abigail::xml_reader::read_corpus_from_native_xml; 61using abigail::xml_reader::read_corpus_from_native_xml;
56using abigail::xml_reader::read_corpus_from_native_xml_file; 62using abigail::xml_reader::read_corpus_from_native_xml_file;
57using abigail::xml_reader::read_corpus_group_from_input; 63using abigail::xml_reader::read_corpus_group_from_input;
64#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
65using abigail::xml_reader::get_types_from_type_id;
66using abigail::xml_reader::get_artifact_used_by_relation_map;
67#endif
58using abigail::dwarf_reader::read_corpus_from_elf; 68using abigail::dwarf_reader::read_corpus_from_elf;
59using abigail::xml_writer::write_translation_unit; 69using abigail::xml_writer::write_translation_unit;
60using abigail::xml_writer::write_context_sptr; 70using abigail::xml_writer::write_context_sptr;
@@ -78,6 +88,9 @@ struct options
78 vector<string> suppression_paths; 88 vector<string> suppression_paths;
79 string headers_dir; 89 string headers_dir;
80 vector<string> header_files; 90 vector<string> header_files;
91#if WITH_SHOW_TYPE_USE_IN_ABILINT
92 string type_id_to_show;
93#endif
81 94
82 options() 95 options()
83 : display_version(false), 96 : display_version(false),
@@ -92,6 +105,374 @@ struct options
92 {} 105 {}
93};//end struct options; 106};//end struct options;
94 107
108#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
109/// A tree node representing the "use" relation between an artifact A
110/// (e.g, a type) and a set of artifacts {A'} that use "A" as in "A"
111/// is a sub-type of A'.
112///
113/// So the node contains the artifact A and a vector children nodes
114/// that contain the A' artifacts that use A.
115struct artifact_use_relation_tree
116{
117 artifact_use_relation_tree *root_node = nullptr;
118 /// The parent node of this one. Is nullptr if this node is the root
119 /// node.
120 artifact_use_relation_tree *parent = nullptr;
121 /// The artifact contained in this node.
122 type_or_decl_base* artifact = nullptr;
123 /// The vector of children nodes that carry the artifacts that
124 /// actually use the 'artifact' above. In other words, the
125 /// 'artifact" data member above is a sub-type of each artifact
126 /// contained in this vector.
127 vector<unique_ptr<artifact_use_relation_tree>> artifact_users;
128 /// This is the set of artifacts that have been added to the tree.
129 /// This is useful to ensure that all artifacts are added just once
130 /// in the tree to prevent infinite loops.
131 unordered_set<type_or_decl_base *> artifacts;
132
133 /// The constructor of the tree node.
134 ///
135 /// @param the artifact to consider.
136 artifact_use_relation_tree(type_or_decl_base* t)
137 : artifact (t)
138 {
139 ABG_ASSERT(t && !artifact_in_tree(t));
140 record_artifact(t);
141 }
142
143 /// Add a user artifact node for the artifact carried by this node.
144 ///
145 /// The artifact carried by the current node is a sub-type of the
146 /// artifact carried by the 'user' node being added.
147 ///
148 /// @param user a tree node that carries an artifact that uses the
149 /// artifact carried by the current node.
150 void
151 add_artifact_user(artifact_use_relation_tree *user)
152 {
153 ABG_ASSERT(user && !artifact_in_tree(user->artifact ));
154 artifact_users.push_back(unique_ptr<artifact_use_relation_tree>(user));
155 user->parent = this;
156 record_artifact(user->artifact);
157 }
158
159 /// Move constructor.
160 ///
161 /// @param o the source of the move.
162 artifact_use_relation_tree(artifact_use_relation_tree &&o)
163 {
164 parent = o.parent;
165 artifact = o.artifact;
166 artifact_users = std::move(o.artifact_users);
167 artifacts = std::move(o.artifacts);
168 }
169
170 /// Move assignment operator.
171 ///
172 /// @param o the source of the assignment.
173 artifact_use_relation_tree& operator=(artifact_use_relation_tree&& o)
174 {
175 parent = o.parent;
176 artifact = o.artifact;
177 artifact_users = std::move(o.artifact_users);
178 artifacts = std::move(o.artifacts);
179 return *this;
180 }
181
182 /// Test if the current node is a leaf node.
183 ///
184 /// @return true if the artifact carried by the current node has no
185 /// user artifacts.
186 bool
187 is_leaf() const
188 {return artifact_users.empty();}
189
190 /// Test if the current node is a root node.
191 ///
192 /// @return true if the current artifact uses no other artifact.
193 bool
194 is_root() const
195 {return parent == nullptr;}
196
197 /// Test wether a given artifact has been added to the tree.
198 ///
199 /// Here, the tree means the tree that the current tree node is part
200 /// of.
201 ///
202 /// An artifact is considered as having been added to the tree if
203 /// artifact_use_relation_tree::record_artifact has been invoked on
204 /// it.
205 ///
206 /// @param artifact the artifact to consider.
207 ///
208 /// @return true iff @p artifact is present in the tree.
209 bool
210 artifact_in_tree(type_or_decl_base *artifact)
211 {
212 artifact_use_relation_tree *root_node = get_root_node();
213 ABG_ASSERT(root_node);
214 return root_node->artifacts.find(artifact) != root_node->artifacts.end();
215 }
216
217 /// Record an artifact as being added to the current tree.
218 ///
219 /// Note that this function assumes the artifact is not already
220 /// present in the tree containing the current tree node.
221 ///
222 /// @param artifact the artifact to consider.
223 void
224 record_artifact(type_or_decl_base *artifact)
225 {
226 ABG_ASSERT(!artifact_in_tree(artifact));
227 artifact_use_relation_tree *root_node = get_root_node();
228 ABG_ASSERT(root_node);
229 root_node->artifacts.insert(artifact);
230 }
231
232 /// Get the root node of the current tree.
233 ///
234 /// @return the root node of the current tree.
235 artifact_use_relation_tree*
236 get_root_node()
237 {
238 if (root_node)
239 return root_node;
240
241 if (parent == nullptr)
242 return this;
243
244 root_node = parent->get_root_node();
245 return root_node;
246 }
247
248 artifact_use_relation_tree(const artifact_use_relation_tree&) = delete;
249 artifact_use_relation_tree& operator=(const artifact_use_relation_tree&) = delete;
250}; // end struct artifact_use_relation_tree
251
252/// Fill an "artifact use" tree from a map that associates a type T
253/// (or artifact) to artifacts that use T as a sub-type.
254///
255/// @param artifact_use_rel the map that establishes the relation
256/// between a type T and the artifacts that use T as a sub-type.
257///
258/// @parm tree output parameter. This function will fill up this tree
259/// from the information carried in @p artifact_use_rel. Each node of
260/// the tree contains an artifact A and its children nodes contain the
261/// artifacts A' that use A as a sub-type.
262static void
263fill_artifact_use_tree(const std::unordered_map<type_or_decl_base*,
264 vector<type_or_decl_base*>>& artifact_use_rel,
265 artifact_use_relation_tree& tree)
266{
267 auto r = artifact_use_rel.find(tree.artifact);
268 if (r == artifact_use_rel.end())
269 return;
270
271 // Walk the users of "artifact", create a tree node for each one of
272 // them, and add them as children node of the current tree node
273 // named 'tree'.
274 for (auto user : r->second)
275 {
276 if (tree.artifact_in_tree(user))
277 // The artifact has already been added to the tree, so skip it
278 // otherwise we can loop for ever.
279 continue;
280
281 artifact_use_relation_tree *user_tree =
282 new artifact_use_relation_tree(user);
283
284 // Now add the new user node as a child of the current tree
285 // node.
286 tree.add_artifact_user(user_tree);
287
288 // Recursively fill the newly created tree node.
289 fill_artifact_use_tree(artifact_use_rel, *user_tree);
290 }
291}
292
293/// construct an "artifact use tree" for a type designated by a "type-id".
294/// (or artifact) to artifacts that use T as a sub-type.
295///
296/// Each node of the "artifact use tree" contains a type T and its
297/// children nodes contain the artifacts A' that use T as a sub-type.
298/// The root node is the type designed by a given type-id.
299///
300/// @param ctxt the abixml read context to consider.
301///
302/// @param type_id the type-id of the type to construct the "use tree"
303/// for.
304static unique_ptr<artifact_use_relation_tree>
305build_type_use_tree(abigail::xml_reader::read_context &ctxt,
306 const string& type_id)
307{
308 unique_ptr<artifact_use_relation_tree> result;
309 vector<type_base_sptr>* types = get_types_from_type_id(ctxt, type_id);
310 if (!types)
311 return result;
312
313 std::unordered_map<type_or_decl_base*, vector<type_or_decl_base*>>*
314 artifact_use_rel = get_artifact_used_by_relation_map(ctxt);
315 if (!artifact_use_rel)
316 return result;
317
318 type_or_decl_base_sptr type = types->front();
319 unique_ptr<artifact_use_relation_tree> use_tree
320 (new artifact_use_relation_tree(type.get()));
321
322 fill_artifact_use_tree(*artifact_use_rel, *use_tree);
323
324 result = std::move(use_tree);
325 return result;
326}
327
328/// Emit a visual representation of a "type use trace".
329///
330/// The trace is vector of strings. Each string is the textual
331/// representation of a type. The next element in the vector is a
332/// type using the previous element, as in, the "previous element is a
333/// sub-type of the next element".
334///
335/// This is a sub-routine of emit_artifact_use_trace.
336///
337/// @param the trace vector to emit.
338///
339/// @param out the output stream to emit the trace to.
340static void
341emit_trace(const vector<string>& trace, ostream& out)
342{
343 if (trace.empty())
344 return;
345
346 if (!trace.empty())
347 // Make the beginning of the trace line of the usage of a given
348 // type be easily recognizeable by a "pattern".
349 out << "===";
350
351 for (auto element : trace)
352 out << "-> " << element << " ";
353
354 if (!trace.empty())
355 // Make the end of the trace line of the usage of a given type be
356 // easily recognizeable by another "pattern".
357 out << " <-~~~";
358
359 out << "\n";
360}
361
362/// Walk a @ref artifact_use_relation_tree to emit a "type-is-used-by"
363/// trace.
364///
365/// The tree carries the information about how a given type is used by
366/// other types. This function walks the tree by visiting a node
367/// carrying a given type T, and then the nodes for which T is a
368/// sub-type. The function accumulates a trace made of the textual
369/// representation of the visited nodes and then emits that trace on
370/// an output stream.
371///
372/// @param artifact_use_tree the tree to walk.
373///
374/// @param trace the accumulated vector of the textual representations
375/// of the types carried by the visited nodes.
376///
377/// @param out the output stream to emit the trace to.
378static void
379emit_artifact_use_trace(const artifact_use_relation_tree& artifact_use_tree,
380 vector<string>& trace, ostream& out)
381{
382 type_or_decl_base* artifact = artifact_use_tree.artifact;
383 if (!artifact)
384 return;
385
386 string repr = artifact->get_pretty_representation();
387 trace.push_back(repr);
388
389 if (artifact_use_tree.artifact_users.empty())
390 {
391 // We reached a leaf node. This means that no other artifact
392 // uses the artifact carried by this leaf node. So, we want to
393 // emit the trace accumulated to this point.
394
395 // But we only want to emit the usage traces that end up with a
396 // function of variable that have an associated ELF symbol.
397 bool do_emit_trace = false;
398 if (is_decl(artifact))
399 {
400 if (abigail::ir::var_decl* v = is_var_decl(artifact))
401 if (v->get_symbol())
402 do_emit_trace = true;
403 if (abigail::ir::function_decl* f = is_function_decl(artifact))
404 if (f->get_symbol())
405 do_emit_trace = true;
406 }
407
408 // OK now, really emit the trace.
409 if (do_emit_trace)
410 emit_trace(trace, out);
411
412 trace.pop_back();
413 return;
414 }
415
416 for (const auto &user : artifact_use_tree.artifact_users)
417 emit_artifact_use_trace(*user, trace, out);
418
419 trace.pop_back();
420}
421
422/// Walk a @ref artifact_use_relation_tree to emit a "type-is-used-by"
423/// trace.
424///
425/// The tree carries the information about how a given type is used by
426/// other types. This function walks the tree by visiting a node
427/// carrying a given type T, and then the nodes for which T is a
428/// sub-type. The function then emits a trace of how the root type is
429/// used.
430///
431/// @param artifact_use_tree the tree to walk.
432///
433/// @param out the output stream to emit the trace to.
434static void
435emit_artifact_use_trace(const artifact_use_relation_tree& artifact_use_tree,
436 ostream& out)
437{
438 vector<string> trace;
439 emit_artifact_use_trace(artifact_use_tree, trace, out);
440}
441
442/// Show how a type is used.
443///
444/// The type to consider is designated by a type-id string that is
445/// carried by the options data structure.
446///
447/// @param ctxt the abixml read context to consider.
448///
449/// @param the type_id of the type which usage to analyse.
450static bool
451show_how_type_is_used(abigail::xml_reader::read_context &ctxt,
452 const string& type_id)
453{
454 if (type_id.empty())
455 return false;
456
457 unique_ptr<artifact_use_relation_tree> use_tree =
458 build_type_use_tree(ctxt, type_id);
459 if (!use_tree)
460 return false;
461
462 // Now walk the use_tree to emit the type use trace
463 if (use_tree->artifact)
464 {
465 std::cout << "Type ID '"
466 << type_id << "' is for type '"
467 << use_tree->artifact->get_pretty_representation()
468 << "'\n"
469 << "The usage graph for that type is:\n";
470 emit_artifact_use_trace(*use_tree, std::cout);
471 }
472 return true;
473}
474#endif // WITH_SHOW_TYPE_USE_IN_ABILINT
475
95static void 476static void
96display_usage(const string& prog_name, ostream& out) 477display_usage(const string& prog_name, ostream& out)
97{ 478{
@@ -113,6 +494,9 @@ display_usage(const string& prog_name, ostream& out)
113#ifdef WITH_CTF 494#ifdef WITH_CTF
114 << " --ctf use CTF instead of DWARF in ELF files\n" 495 << " --ctf use CTF instead of DWARF in ELF files\n"
115#endif 496#endif
497#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
498 << " --show-type-use <type-id> show how a type is used from the abixml file\n"
499#endif
116 ; 500 ;
117} 501}
118 502
@@ -195,6 +579,15 @@ parse_command_line(int argc, char* argv[], options& opts)
195 opts.diff = true; 579 opts.diff = true;
196 else if (!strcmp(argv[i], "--noout")) 580 else if (!strcmp(argv[i], "--noout"))
197 opts.noout = true; 581 opts.noout = true;
582#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
583 else if (!strcmp(argv[i], "--show-type-use"))
584 {
585 ++i;
586 if (i >= argc || argv[i][0] == '-')
587 return false;
588 opts.type_id_to_show = argv[i];
589 }
590#endif
198 else 591 else
199 { 592 {
200 if (strlen(argv[i]) >= 2 && argv[i][0] == '-' && argv[i][1] == '-') 593 if (strlen(argv[i]) >= 2 && argv[i][0] == '-' && argv[i][1] == '-')
@@ -203,8 +596,17 @@ parse_command_line(int argc, char* argv[], options& opts)
203 } 596 }
204 } 597 }
205 598
206 if (opts.file_path.empty()) 599#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
600 if (!opts.type_id_to_show.empty()
601 && opts.file_path.empty())
602 emit_prefix(argv[0], cout)
603 << "WARNING: --show-type-use <type-id> "
604 "must be accompanied with an abixml file\n";
605
606 if (opts.file_path.empty()
607 && opts.type_id_to_show.empty())
207 opts.read_from_stdin = true; 608 opts.read_from_stdin = true;
609#endif
208 610
209 if (opts.read_from_stdin && !opts.file_path.empty()) 611 if (opts.read_from_stdin && !opts.file_path.empty())
210 { 612 {
@@ -349,6 +751,7 @@ main(int argc, char* argv[])
349 abigail::elf_reader::status s = abigail::elf_reader::STATUS_OK; 751 abigail::elf_reader::status s = abigail::elf_reader::STATUS_OK;
350 char* di_root_path = 0; 752 char* di_root_path = 0;
351 file_type type = guess_file_type(opts.file_path); 753 file_type type = guess_file_type(opts.file_path);
754 abigail::xml_reader::read_context_sptr abixml_read_ctxt;
352 755
353 switch (type) 756 switch (type)
354 { 757 {
@@ -358,7 +761,12 @@ main(int argc, char* argv[])
358 << "\n"; 761 << "\n";
359 return 1; 762 return 1;
360 case abigail::tools_utils::FILE_TYPE_NATIVE_BI: 763 case abigail::tools_utils::FILE_TYPE_NATIVE_BI:
361 tu = read_translation_unit_from_file(opts.file_path, env.get()); 764 {
765 abixml_read_ctxt =
766 abigail::xml_reader::create_native_xml_read_context(opts.file_path,
767 env.get());
768 tu = read_translation_unit(*abixml_read_ctxt);
769 }
362 break; 770 break;
363 case abigail::tools_utils::FILE_TYPE_ELF: 771 case abigail::tools_utils::FILE_TYPE_ELF:
364 case abigail::tools_utils::FILE_TYPE_AR: 772 case abigail::tools_utils::FILE_TYPE_AR:
@@ -391,22 +799,22 @@ main(int argc, char* argv[])
391 break; 799 break;
392 case abigail::tools_utils::FILE_TYPE_XML_CORPUS: 800 case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
393 { 801 {
394 abigail::xml_reader::read_context_sptr ctxt = 802 abixml_read_ctxt =
395 abigail::xml_reader::create_native_xml_read_context(opts.file_path, 803 abigail::xml_reader::create_native_xml_read_context(opts.file_path,
396 env.get()); 804 env.get());
397 assert(ctxt); 805 assert(abixml_read_ctxt);
398 set_suppressions(*ctxt, opts); 806 set_suppressions(*abixml_read_ctxt, opts);
399 corp = read_corpus_from_input(*ctxt); 807 corp = read_corpus_from_input(*abixml_read_ctxt);
400 break; 808 break;
401 } 809 }
402 case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP: 810 case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
403 { 811 {
404 abigail::xml_reader::read_context_sptr ctxt = 812 abixml_read_ctxt =
405 abigail::xml_reader::create_native_xml_read_context(opts.file_path, 813 abigail::xml_reader::create_native_xml_read_context(opts.file_path,
406 env.get()); 814 env.get());
407 assert(ctxt); 815 assert(abixml_read_ctxt);
408 set_suppressions(*ctxt, opts); 816 set_suppressions(*abixml_read_ctxt, opts);
409 group = read_corpus_group_from_input(*ctxt); 817 group = read_corpus_group_from_input(*abixml_read_ctxt);
410 } 818 }
411 break; 819 break;
412 case abigail::tools_utils::FILE_TYPE_RPM: 820 case abigail::tools_utils::FILE_TYPE_RPM:
@@ -517,6 +925,14 @@ main(int argc, char* argv[])
517 is_ok = false; 925 is_ok = false;
518 } 926 }
519 927
928#ifdef WITH_SHOW_TYPE_USE_IN_ABILINT
929 if (is_ok
930 && !opts.type_id_to_show.empty())
931 {
932 ABG_ASSERT(abixml_read_ctxt);
933 show_how_type_is_used(*abixml_read_ctxt, opts.type_id_to_show);
934 }
935#endif
520 return is_ok ? 0 : 1; 936 return is_ok ? 0 : 1;
521 } 937 }
522 938