[PATCH] abicompat: Add the ability to process abi corpus group

Dodji Seketeli dodji@seketeli.net
Thu Aug 21 16:40:24 GMT 2025


Hello Claudiu,

claudiu.zissulescu-ianculescu@oracle.com a écrit:

> From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
>
> This patch introduces a new option `--soname` to the `abicompat` tool.
> This new option allows users to specify a shared library name when
> comparing ABI XML files that contain groups of corpora. This is useful
> when dealing with multiple shared libraries that have their ABIs
> stored within a single XML file.

Thank you for taking the time to craft this patch.

Fundamentally, I think the reason why you've needed to do this is
because I fell short in making a corpus group be a "particular" kind of
corpus, even if that was the initial intent behind making the
abigail::ir::corpus_group class inheritabigail::ir::corpus.

Please bear with me for a few paragraphs.

To perform compatibility verifications,
perform_compat_check_in_weak_mode compares each function F (respectively
variable V) expected by the application against the function F exported
by the library.  This is done by invoking corpus::lookup_functions on
the ABI corpus of the library, for each F.

The core problem we face is that corpus_group::lookup_functions and
corpus_group::lookup_variables hasn't been implemented yet, making it
cumbersome to handle a (set of) library represented by a corpus_group.

And this has compelled you to walking the corpora of a the corpus_group
of the library "by hand" in tools/abicompat.cc and needing the user to
specify the soname of the particular corpus (in the corpus group) to
consider as a provider for F.  Tedious.

I think you shouldn't have to do that and the user shouldn't be forced
to know about that soname detail.

Rather, I am amending the patch to make it do what I should have done to
begin with, which is, provide
corpus_group::lookup_{functions,variables}, so that once the
corpus_group (for the library) is constructed,
perform_compat_check_in_weak_mode just works on it as it works on any
other corpus.  I kept everything else as you did.

Please find the amended patch below.  You can get it in-extenso from git
in the branch "users/dodji/abicompat-corpus-group" at
https://sourceware.org/cgit/libabigail/log/?h=users/dodji/abicompat-corpus-group.

What do you think?

Many thanks.

>From 22bb528d00a457fb0ff601a4adca22d8d3338a35 Mon Sep 17 00:00:00 2001
From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
Date: Thu, 7 Aug 2025 18:17:57 +0300
Subject: [PATCH] abicompat: Add the ability to process abi corpus group

abicompat doesn't seem to support libraries being represented by
corpus group abixml files.

This patch fixes that.

First, the patch makes abigail::ir::corpus::lookup_{functions,variables} be
virtual member functions.  Then, it adds
abigail::ir::corpus_group::lookup_{functions,variables} overloads to the
abigail::ir::corpus_group child class of abigail::ir::corpus.

Basically, abigail::corpus_group::lookup_functions cycles over the
corpora of the group and invokes abigail::corpus::lookup_functions on
each corpus until it finds a corpus that has the functions. Similarly
for abigail::corpus_group::lookup_variables.

The function read_corpus in abicompat.cc is amended to support corpus
group ABIXML files by calling read_corpus_group_from_input on them.
Because a corpus_group is a particular type of corpus, the rest of the
code should now do the right thing.

The patch also adds a new test case for this functionality.

	* include/abg-corpus.h (corpus::lookup_{function,variable}s):
	Make these member functions virtual.
	(corpus_group::{lookup_{function,variable}s): Add new overloads.
	* src/abg-corpus.cc (corpus_group::{lookup_{function,variable}s):
	Define new virtual overloads that walk over each corpus, invokes
	corpus::lookup_{functions,variables} on them and return the first
	one that is non-nil.
	* tests/data/test-abicompat/libtest11-fn-changed.xml: New test input.
	* tests/data/test-abicompat/test11-fn-changed-app.xml: Likewise.
	* tests/data/test-abicompat/test11-fn-changed.txt: Likewise.
	* tests/test-abicompat.cc (in_out_specs): Add the new test
	material above to this test harness.
	* tools/abicompat.cc (read_corpus): Support
	abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP kind of input file.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-corpus.h                          | 20 +++-
 src/abg-corpus.cc                             | 96 +++++++++++++++++++
 tests/data/Makefile.am                        |  3 +
 .../test-abicompat/libtest11-fn-changed.xml   | 86 +++++++++++++++++
 .../test-abicompat/test11-fn-changed-app.xml  | 45 +++++++++
 .../data/test-abicompat/test11-fn-changed.txt | 14 +++
 tests/test-abicompat.cc                       | 10 ++
 tools/abicompat.cc                            |  7 +-
 8 files changed, 275 insertions(+), 6 deletions(-)
 create mode 100644 tests/data/test-abicompat/libtest11-fn-changed.xml
 create mode 100644 tests/data/test-abicompat/test11-fn-changed-app.xml
 create mode 100644 tests/data/test-abicompat/test11-fn-changed.txt

diff --git a/include/abg-corpus.h b/include/abg-corpus.h
index 62121543..0a7cf165 100644
--- a/include/abg-corpus.h
+++ b/include/abg-corpus.h
@@ -224,16 +224,16 @@ public:
   virtual const functions&
   get_functions() const;
 
-  const std::unordered_set<function_decl*>*
+  virtual const std::unordered_set<function_decl*>*
   lookup_functions(const interned_string& id) const;
 
-  const std::unordered_set<function_decl*>*
+  virtual const std::unordered_set<function_decl*>*
   lookup_functions(const char* id) const;
 
-  const std::unordered_set<var_decl_sptr>*
+  virtual const std::unordered_set<var_decl_sptr>*
   lookup_variables(const interned_string& id) const;
 
-  const std::unordered_set<var_decl_sptr>*
+  virtual const std::unordered_set<var_decl_sptr>*
   lookup_variables(const char* id) const;
 
   void
@@ -445,6 +445,18 @@ public:
 
   bool
   operator==(const corpus_group&) const;
+
+  virtual const std::unordered_set<function_decl*>*
+  lookup_functions(const interned_string& id) const;
+
+  virtual const std::unordered_set<function_decl*>*
+  lookup_functions(const char* id) const;
+
+  virtual const std::unordered_set<var_decl_sptr>*
+  lookup_variables(const interned_string& id) const;
+
+  virtual const std::unordered_set<var_decl_sptr>*
+  lookup_variables(const char* id) const;
 }; // end class corpus_group
 
 corpus_group_sptr
diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index 8d5850e8..a53ae308 100644
--- a/src/abg-corpus.cc
+++ b/src/abg-corpus.cc
@@ -2267,6 +2267,102 @@ bool
 corpus_group::recording_types_reachable_from_public_interface_supported()
 {return !get_public_types_pretty_representations()->empty();}
 
+/// Lookup the function which has a given function ID.
+///
+/// Note that there can have been several functions with the same ID.
+/// This is because debug info can declare the same function in
+/// several different translation units.  Normally, all these
+/// functions should be equal.  But still, this function returns all
+/// these functions.
+///
+/// Also, note that this function cycles over each corpora of the
+/// corpus group, invokes corpus::lookup_functions on them and returns
+/// the result of the first one that succeeds.
+///
+/// @param id the ID of the function to lookup.  This ID must be
+/// either the result of invoking function::get_id() of
+/// elf_symbol::get_id_string().
+///
+/// @return the set of functions which ID is @p id, or nil if no
+/// function with that ID was found.
+const std::unordered_set<function_decl*>*
+corpus_group::lookup_functions(const interned_string& id) const
+{
+  for (auto& corp :get_corpora())
+    if (auto fns = corp->lookup_functions(id))
+      return fns;
+
+  return nullptr;
+}
+
+/// Lookup the function which has a given function ID.
+///
+/// Note that there can have been several functions with the same ID.
+/// This is because debug info can declare the same function in
+/// several different translation units.  Normally, all these
+/// functions should be equal.  But still, this function returns all
+/// these functions.
+///
+/// Also, note that this function cycles over each corpora of the
+/// corpus group, invokes corpus::lookup_functions on them and returns
+/// the result of the first one that succeeds.
+///
+/// @param id the ID of the function to lookup.  This ID must be
+/// either the result of invoking function::get_id() of
+/// elf_symbol::get_id_string().
+///
+/// @return the set of functions which ID is @p id, or nil if no
+/// function with that ID was found.
+const std::unordered_set<function_decl*>*
+corpus_group::lookup_functions(const char* id) const
+{
+  for (auto& corp :get_corpora())
+    if (const auto& fns = corp->lookup_functions(id))
+      return fns;
+
+  return nullptr;
+}
+
+/// Lookup the exported variables which all have a given variable ID.
+///
+/// Note that this function cycles over each corpora of the corpus
+/// group, invokes corpus::lookup_variabless on them and returns the
+/// result of the first one that succeeds.
+///
+/// @param id the ID of the variable to look up.
+///
+/// @return a pointer to the set of variables with ID @p id, or
+/// nullptr if no variable was found with that ID.
+const std::unordered_set<var_decl_sptr>*
+corpus_group::lookup_variables(const interned_string& id) const
+{
+  for (auto& corp :get_corpora())
+    if (const auto& vars = corp->lookup_variables(id))
+      return vars;
+
+  return nullptr;
+}
+
+/// Lookup the exported variables which all have a given variable ID.
+///
+/// Note that this function cycles over each corpora of the corpus
+/// group, invokes corpus::lookup_variabless on them and returns the
+/// result of the first one that succeeds.
+///
+/// @param id the ID of the variable to look up.
+///
+/// @return a pointer to the set of variables with ID @p id, or
+/// nullptr if no variable was found with that ID.
+const std::unordered_set<var_decl_sptr>*
+corpus_group::lookup_variables(const char* id) const
+{
+  for (auto& corp :get_corpora())
+    if (const auto& vars = corp->lookup_variables(id))
+      return vars;
+
+  return nullptr;
+}
+
 /// Test if a @ref corpus is a @ref corpus_group.
 ///
 /// @param corpus the corpus to consider.
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 6c4e2cd2..dc1c4f12 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -2280,6 +2280,9 @@ test-abicompat/test10/test10-fn-changed-report-1.txt \
 test-abicompat/test10/test10-fn-changed-report-2.txt \
 test-abicompat/test10/test10-fn-changed-report-3.txt \
 test-abicompat/test10/test10-fn-changed-report-4.txt \
+test-abicompat/libtest11-fn-changed.xml \
+test-abicompat/test11-fn-changed-app.xml \
+test-abicompat/test11-fn-changed.txt \
 test-abicompat/test-diff-ptr-to-void-ptr/0/libtest-diff-ptr-to-void-ptr-fn.so \
 test-abicompat/test-diff-ptr-to-void-ptr/0/test-diff-ptr-to-void-ptr-fn-v0.c \
 test-abicompat/test-diff-ptr-to-void-ptr/1/libtest-diff-ptr-to-void-ptr-fn.so \
diff --git a/tests/data/test-abicompat/libtest11-fn-changed.xml b/tests/data/test-abicompat/libtest11-fn-changed.xml
new file mode 100644
index 00000000..097af2af
--- /dev/null
+++ b/tests/data/test-abicompat/libtest11-fn-changed.xml
@@ -0,0 +1,86 @@
+<abi-corpus-group version='2.4' architecture='elf-amd-x86_64'>
+  <abi-corpus version='2.4' path='libtest-1.so' architecture='elf-amd-x86_64' soname='libtest-1.so'>
+    <elf-needed>
+      <dependency name='libstdc++.so.6'/>
+      <dependency name='libm.so.6'/>
+      <dependency name='libgcc_s.so.1'/>
+      <dependency name='libc.so.6'/>
+    </elf-needed>
+    <elf-function-symbols>
+      <elf-symbol name='_Z10first_funcv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+      <elf-symbol name='_Z11second_funcR3foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+      <elf-symbol name='_ZN3fooC1Ev' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='yes'/>
+      <elf-symbol name='_ZN3fooC2Ev' type='func-type' binding='weak-binding' visibility='default-visibility' alias='_ZN3fooC1Ev' is-defined='yes'/>
+    </elf-function-symbols>
+    <undefined-elf-function-symbols>
+      <elf-symbol name='_ZdlPvm' version='CXXABI_1.3.9' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='no'/>
+      <elf-symbol name='_Znwm' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='no'/>
+      <elf-symbol name='__cxa_finalize' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+    </undefined-elf-function-symbols>
+    <undefined-elf-variable-symbols>
+      <elf-symbol name='_ITM_deregisterTMCloneTable' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+      <elf-symbol name='_ITM_registerTMCloneTable' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+      <elf-symbol name='__gmon_start__' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+    </undefined-elf-variable-symbols>
+    <abi-instr address-size='64' path='test1.cc' comp-dir-path='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample' language='LANG_C_plus_plus_14'>
+      <type-decl name='char' size-in-bits='8' hash='65b2d157027b431a' id='type-id-1'/>
+      <type-decl name='int' size-in-bits='32' hash='09d17c08f594edc7' id='type-id-2'/>
+      <class-decl name='foo' is-struct='yes' visibility='default' size-in-bits='64' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test1.h' line='1' column='1' hash='b9bca352028d2431' id='type-id-3'>
+        <data-member access='public' layout-offset-in-bits='0'>
+          <var-decl name='m0' type-id='type-id-2' visibility='default' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test1.h' line='3' column='1'/>
+        </data-member>
+        <data-member access='public' layout-offset-in-bits='32'>
+          <var-decl name='m1' type-id='type-id-1' visibility='default' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test1.h' line='4' column='1'/>
+        </data-member>
+        <member-function access='public' constructor='yes'>
+          <function-decl name='foo' mangled-name='_ZN3fooC2Ev' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test1.h' line='6' column='1' declared-inline='yes' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN3fooC2Ev' hash='7f32ffea222edbe7'>
+            <parameter type-id='type-id-4' is-artificial='yes'/>
+            <return type-id='type-id-5'/>
+          </function-decl>
+        </member-function>
+      </class-decl>
+      <reference-type-def kind='lvalue' type-id='type-id-3' size-in-bits='64' hash='1854f0b6950169b7' id='type-id-6'/>
+      <pointer-type-def type-id='type-id-3' size-in-bits='64' hash='dc66dea208456f85' id='type-id-4'/>
+      <qualified-type-def type-id='type-id-4' const='yes' hash='0ee8cf1f479fe91e' id='type-id-7'/>
+      <function-decl name='first_func' mangled-name='_Z10first_funcv' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test1.cc' line='7' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Z10first_funcv' hash='fb51336c1fc02347'>
+        <return type-id='type-id-4'/>
+      </function-decl>
+      <function-decl name='second_func' mangled-name='_Z11second_funcR3foo' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test1.cc' line='14' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Z11second_funcR3foo' hash='01ba306f4098d54e'>
+        <parameter type-id='type-id-6'/>
+        <return type-id='type-id-5'/>
+      </function-decl>
+      <type-decl name='void' id='type-id-5'/>
+    </abi-instr>
+  </abi-corpus>
+  <abi-corpus version='2.4' path='libtest-2.so' architecture='elf-amd-x86_64' soname='libtest-2.so'>
+    <elf-needed>
+      <dependency name='libstdc++.so.6'/>
+      <dependency name='libm.so.6'/>
+      <dependency name='libgcc_s.so.1'/>
+      <dependency name='libc.so.6'/>
+    </elf-needed>
+    <elf-function-symbols>
+      <elf-symbol name='_Z3fooP2S0' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    </elf-function-symbols>
+    <undefined-elf-function-symbols>
+      <elf-symbol name='__cxa_finalize' version='GLIBC_2.2.5' is-default-version='yes' type='func-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+    </undefined-elf-function-symbols>
+    <undefined-elf-variable-symbols>
+      <elf-symbol name='_ITM_deregisterTMCloneTable' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+      <elf-symbol name='_ITM_registerTMCloneTable' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+      <elf-symbol name='__gmon_start__' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+    </undefined-elf-variable-symbols>
+    <abi-instr address-size='64' path='test2.cc' comp-dir-path='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample' language='LANG_C_plus_plus_14'>
+      <class-decl name='S0' is-struct='yes' visibility='default' size-in-bits='32' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test2.cc' line='4' column='1' hash='55ff770e9a972727' id='type-id-8'>
+        <data-member access='public' layout-offset-in-bits='0'>
+          <var-decl name='m0' type-id='type-id-2' visibility='default' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test2.cc' line='6' column='1'/>
+        </data-member>
+      </class-decl>
+      <pointer-type-def type-id='type-id-8' size-in-bits='64' hash='c816e79b49fbd0b0' id='type-id-9'/>
+      <function-decl name='foo' mangled-name='_Z3fooP2S0' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test2.cc' line='10' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Z3fooP2S0' hash='a6fe781ceb581b24'>
+        <parameter type-id='type-id-9'/>
+        <return type-id='type-id-5'/>
+      </function-decl>
+    </abi-instr>
+  </abi-corpus>
+</abi-corpus-group>
diff --git a/tests/data/test-abicompat/test11-fn-changed-app.xml b/tests/data/test-abicompat/test11-fn-changed-app.xml
new file mode 100644
index 00000000..8e5b2728
--- /dev/null
+++ b/tests/data/test-abicompat/test11-fn-changed-app.xml
@@ -0,0 +1,45 @@
+<abi-corpus version='2.4' path='test-app' architecture='elf-amd-x86_64'>
+  <elf-needed>
+    <dependency name='libtest-0.so'/>
+    <dependency name='libstdc++.so.6'/>
+    <dependency name='libm.so.6'/>
+    <dependency name='libgcc_s.so.1'/>
+    <dependency name='libc.so.6'/>
+  </elf-needed>
+  <elf-function-symbols>
+    <elf-symbol name='_start' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='main' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <elf-variable-symbols>
+    <elf-symbol name='_IO_stdin_used' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <undefined-elf-function-symbols>
+    <elf-symbol name='_Z10first_funcv' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='no'/>
+    <elf-symbol name='_Z11second_funcR3foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='no'/>
+    <elf-symbol name='__libc_start_main@GLIBC_2.34' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='no'/>
+  </undefined-elf-function-symbols>
+  <undefined-elf-variable-symbols>
+    <elf-symbol name='__gmon_start__' type='no-type' binding='weak-binding' visibility='default-visibility' is-defined='no'/>
+  </undefined-elf-variable-symbols>
+  <abi-instr address-size='64' path='test-app.cc' comp-dir-path='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample' language='LANG_C_plus_plus_14'>
+    <type-decl name='int' size-in-bits='32' hash='09d17c08f594edc7' id='type-id-1'/>
+    <class-decl name='foo' is-struct='yes' visibility='default' size-in-bits='32' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test0.h' line='1' column='1' hash='c994494c47450411' id='type-id-2'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='m0' type-id='type-id-1' visibility='default' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test0.h' line='3' column='1'/>
+      </data-member>
+    </class-decl>
+    <reference-type-def kind='lvalue' type-id='type-id-2' size-in-bits='64' hash='1854f0b6950169b7' id='type-id-3'/>
+    <pointer-type-def type-id='type-id-2' size-in-bits='64' hash='dc66dea208456f85' id='type-id-4'/>
+    <function-decl name='main' mangled-name='main' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test-app.cc' line='7' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='main' hash='388da3fa973fde78'>
+      <return type-id='type-id-1'/>
+    </function-decl>
+    <function-decl name='first_func' mangled-name='_Z10first_funcv' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test0.h' line='11' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Z10first_funcv' hash='fb51336c1fc02347'>
+      <return type-id='type-id-4'/>
+    </function-decl>
+    <function-decl name='second_func' mangled-name='_Z11second_funcR3foo' filepath='/home/cls/Projects/oracle/libabigail_work/BinLibCheck/simpleExample/test0.h' line='14' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_Z11second_funcR3foo' hash='01ba306f4098d54e'>
+      <parameter type-id='type-id-3'/>
+      <return type-id='type-id-5'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-5'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-abicompat/test11-fn-changed.txt b/tests/data/test-abicompat/test11-fn-changed.txt
new file mode 100644
index 00000000..2fade2df
--- /dev/null
+++ b/tests/data/test-abicompat/test11-fn-changed.txt
@@ -0,0 +1,14 @@
+functions defined in library 'libtest11-fn-changed.xml'
+have sub-types that are different from what application 'test11-fn-changed-app.xml' expects:
+
+  function foo* first_func(void):
+    return type changed:
+      in pointed to type 'struct foo' at test1.h:1:1:
+        type size changed from 32 to 64 (in bits)
+        1 data member insertion:
+          'char m1', at offset 32 (in bits) at test1.h:4:1
+
+  function void second_func(foo&):
+    parameter 1 of type 'foo&' has sub-type changes:
+      referenced type 'struct foo' changed at test0.h:1:1, as reported earlier
+
diff --git a/tests/test-abicompat.cc b/tests/test-abicompat.cc
index 051cfba4..ca97884a 100644
--- a/tests/test-abicompat.cc
+++ b/tests/test-abicompat.cc
@@ -334,6 +334,16 @@ InOutSpec in_out_specs[] =
     "data/test-abicompat/test10/test10-fn-changed-report-4.txt",
     "output/test-abicompat/test10/test10-fn-changed-report-4.txt",
   },
+  {
+    "data/test-abicompat/test11-fn-changed-app.xml",
+    "data/test-abicompat/libtest11-fn-changed.xml",
+    "",
+    "",
+    "--show-base-names --weak-mode",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abicompat/test11-fn-changed.txt",
+    "output/test-abicompat/test11-fn-changed.txt",
+  },
   // This entry must be the last one.
   {0, 0, 0, 0, 0, abigail::tools_utils::ABIDIFF_OK, 0, 0}
 };
diff --git a/tools/abicompat.cc b/tools/abicompat.cc
index b3e556dd..820ea129 100644
--- a/tools/abicompat.cc
+++ b/tools/abicompat.cc
@@ -881,14 +881,17 @@ read_corpus(options			opts,
       }
       break;
     case abigail::tools_utils::FILE_TYPE_XML_CORPUS:
+    case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
       {
 	rdr = abixml::create_reader(path, env);
 	assert(rdr);
-	retval = rdr->read_corpus(status);
+	retval =
+	  (type == abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP)
+	  ? abixml::read_corpus_group_from_input(*rdr)
+	  : rdr->read_corpus(status);
       }
       break;
     case abigail::tools_utils::FILE_TYPE_AR:
-    case abigail::tools_utils::FILE_TYPE_XML_CORPUS_GROUP:
     case abigail::tools_utils::FILE_TYPE_RPM:
     case abigail::tools_utils::FILE_TYPE_SRPM:
     case abigail::tools_utils::FILE_TYPE_DEB:
-- 
2.47.3

-- 
		Dodji


More information about the Libabigail mailing list