[2/2,v2,abidiff] Add more leaf change reporting.

Message ID 20200313153429.142808-1-gprocida@google.com
State Committed
Headers
Series None |

Commit Message

Giuliano Procida March 13, 2020, 3:34 p.m. UTC
  The leaf-changes-only reporting path does not report on all the same
kinds of differences as the default reporting path does, such as
reporting about changes to variables, even though they can be
considered leaf changs.

    - The addition or removal of any symbol affects the ABI and is
      clearly a leaf change.
    - A change to a variable's declaration may be local rather than
      caused by a type change elsewhere.

This patch adds these missing pieces and reorders some of the existing
leaf reporting, bringing the default and leaf corpus_diff functions
closer to the point where they can be trivially merged or refactored.

This patch also corrects an error in reporting the total number of
leaf changes.

	* src/abg-comparison.cc (emit_diff_stats): Exclude non-leaf
	changes to variables from the reported total of leaf changes.
	* src/abg-default-reporter.cc (report): In the corpus_diff
	override, move some code and comments for clarity.
	* src/abg-leaf-reporter.cc (report): In the corpus_diff
	override, additionally report removed/added/changed variables
	and removed/added symbols absent from debug info.
	* tests/data/Makefile.am: Add new test case files.
	* tests/data/test-abidiff-exit/test-leaf0-report.txt: Update
	to include reporting of variable diff (change of type).
	* tests/data/test-abidiff-exit/test-leaf1-report.txt: New test
	case with added/removed variables/functions and changed
	variables (both local and non-local type changes).
	* tests/data/test-abidiff-exit/test-leaf1-v0.cc: Ditto.
	* tests/data/test-abidiff-exit/test-leaf1-v0.o: Ditto.
	* tests/data/test-abidiff-exit/test-leaf1-v1.cc: Ditto.
	* tests/data/test-abidiff-exit/test-leaf1-v1.o: Ditto.
	* tests/test-abidiff-exit.cc: Run new test case. Supply
	--redundant otherwise the test isn't meaningful.

Signed-off-by: Giuliano Procida <gprocida@google.com>
---
 src/abg-comparison.cc                         |   2 +-
 src/abg-default-reporter.cc                   |  12 +-
 src/abg-leaf-reporter.cc                      | 327 ++++++++++++++++--
 tests/data/Makefile.am                        |   5 +
 .../test-abidiff-exit/test-leaf0-report.txt   |   9 +
 .../test-abidiff-exit/test-leaf1-report.txt   |  46 +++
 tests/data/test-abidiff-exit/test-leaf1-v0.cc |  16 +
 tests/data/test-abidiff-exit/test-leaf1-v0.o  | Bin 0 -> 3792 bytes
 tests/data/test-abidiff-exit/test-leaf1-v1.cc |  16 +
 tests/data/test-abidiff-exit/test-leaf1-v1.o  | Bin 0 -> 3808 bytes
 tests/test-abidiff-exit.cc                    |  11 +
 11 files changed, 406 insertions(+), 38 deletions(-)
 create mode 100644 tests/data/test-abidiff-exit/test-leaf1-report.txt
 create mode 100644 tests/data/test-abidiff-exit/test-leaf1-v0.cc
 create mode 100644 tests/data/test-abidiff-exit/test-leaf1-v0.o
 create mode 100644 tests/data/test-abidiff-exit/test-leaf1-v1.cc
 create mode 100644 tests/data/test-abidiff-exit/test-leaf1-v1.o
  

Comments

Dodji Seketeli March 13, 2020, 5:02 p.m. UTC | #1
Giuliano Procida <gprocida@google.com> a ?crit:

> The leaf-changes-only reporting path does not report on all the same
> kinds of differences as the default reporting path does, such as
> reporting about changes to variables, even though they can be
> considered leaf changs.
>
>     - The addition or removal of any symbol affects the ABI and is
>       clearly a leaf change.
>     - A change to a variable's declaration may be local rather than
>       caused by a type change elsewhere.
>
> This patch adds these missing pieces and reorders some of the existing
> leaf reporting, bringing the default and leaf corpus_diff functions
> closer to the point where they can be trivially merged or refactored.
>
> This patch also corrects an error in reporting the total number of
> leaf changes.
>
> 	* src/abg-comparison.cc (emit_diff_stats): Exclude non-leaf
> 	changes to variables from the reported total of leaf changes.
> 	* src/abg-default-reporter.cc (report): In the corpus_diff
> 	override, move some code and comments for clarity.
> 	* src/abg-leaf-reporter.cc (report): In the corpus_diff
> 	override, additionally report removed/added/changed variables
> 	and removed/added symbols absent from debug info.
> 	* tests/data/Makefile.am: Add new test case files.
> 	* tests/data/test-abidiff-exit/test-leaf0-report.txt: Update
> 	to include reporting of variable diff (change of type).
> 	* tests/data/test-abidiff-exit/test-leaf1-report.txt: New test
> 	case with added/removed variables/functions and changed
> 	variables (both local and non-local type changes).
> 	* tests/data/test-abidiff-exit/test-leaf1-v0.cc: Ditto.
> 	* tests/data/test-abidiff-exit/test-leaf1-v0.o: Ditto.
> 	* tests/data/test-abidiff-exit/test-leaf1-v1.cc: Ditto.
> 	* tests/data/test-abidiff-exit/test-leaf1-v1.o: Ditto.
> 	* tests/test-abidiff-exit.cc: Run new test case. Supply
> 	--redundant otherwise the test isn't meaningful.

This looks OK to me.  I have just updated the manual of the abi{pkg}diff
tools to say that --leaf-changes-only implies --redudant, just as you
did in the help string of these tools.

The patch was applied to master.

Thanks!
  
Giuliano Procida March 13, 2020, 5:22 p.m. UTC | #2
I was confused by your comment. Then I looked at the patch.

The usage string change was supposed to be in "Fix interaction of
--redundant and --leaf-changes-only options." not this patch.

Sorry about this. Looks like it slipped through during a rebase to
reorder changes.

On Fri, 13 Mar 2020 at 17:02, Dodji Seketeli <dodji@seketeli.org> wrote:
>
> Giuliano Procida <gprocida@google.com> a ?crit:
>
> > The leaf-changes-only reporting path does not report on all the same
> > kinds of differences as the default reporting path does, such as
> > reporting about changes to variables, even though they can be
> > considered leaf changs.
> >
> >     - The addition or removal of any symbol affects the ABI and is
> >       clearly a leaf change.
> >     - A change to a variable's declaration may be local rather than
> >       caused by a type change elsewhere.
> >
> > This patch adds these missing pieces and reorders some of the existing
> > leaf reporting, bringing the default and leaf corpus_diff functions
> > closer to the point where they can be trivially merged or refactored.
> >
> > This patch also corrects an error in reporting the total number of
> > leaf changes.
> >
> >       * src/abg-comparison.cc (emit_diff_stats): Exclude non-leaf
> >       changes to variables from the reported total of leaf changes.
> >       * src/abg-default-reporter.cc (report): In the corpus_diff
> >       override, move some code and comments for clarity.
> >       * src/abg-leaf-reporter.cc (report): In the corpus_diff
> >       override, additionally report removed/added/changed variables
> >       and removed/added symbols absent from debug info.
> >       * tests/data/Makefile.am: Add new test case files.
> >       * tests/data/test-abidiff-exit/test-leaf0-report.txt: Update
> >       to include reporting of variable diff (change of type).
> >       * tests/data/test-abidiff-exit/test-leaf1-report.txt: New test
> >       case with added/removed variables/functions and changed
> >       variables (both local and non-local type changes).
> >       * tests/data/test-abidiff-exit/test-leaf1-v0.cc: Ditto.
> >       * tests/data/test-abidiff-exit/test-leaf1-v0.o: Ditto.
> >       * tests/data/test-abidiff-exit/test-leaf1-v1.cc: Ditto.
> >       * tests/data/test-abidiff-exit/test-leaf1-v1.o: Ditto.
> >       * tests/test-abidiff-exit.cc: Run new test case. Supply
> >       --redundant otherwise the test isn't meaningful.
>
> This looks OK to me.  I have just updated the manual of the abi{pkg}diff
> tools to say that --leaf-changes-only implies --redudant, just as you
> did in the help string of these tools.
>
> The patch was applied to master.
>
> Thanks!
>
> --
>                 Dodji
  
Giuliano Procida March 13, 2020, 5:26 p.m. UTC | #3
Actually, my mistake. You attached that doc change to the wrong patch.
No harm done.

On Fri, 13 Mar 2020 at 17:22, Giuliano Procida <gprocida@google.com> wrote:
>
> I was confused by your comment. Then I looked at the patch.
>
> The usage string change was supposed to be in "Fix interaction of
> --redundant and --leaf-changes-only options." not this patch.
>
> Sorry about this. Looks like it slipped through during a rebase to
> reorder changes.
>
> On Fri, 13 Mar 2020 at 17:02, Dodji Seketeli <dodji@seketeli.org> wrote:
> >
> > Giuliano Procida <gprocida@google.com> a ?crit:
> >
> > > The leaf-changes-only reporting path does not report on all the same
> > > kinds of differences as the default reporting path does, such as
> > > reporting about changes to variables, even though they can be
> > > considered leaf changs.
> > >
> > >     - The addition or removal of any symbol affects the ABI and is
> > >       clearly a leaf change.
> > >     - A change to a variable's declaration may be local rather than
> > >       caused by a type change elsewhere.
> > >
> > > This patch adds these missing pieces and reorders some of the existing
> > > leaf reporting, bringing the default and leaf corpus_diff functions
> > > closer to the point where they can be trivially merged or refactored.
> > >
> > > This patch also corrects an error in reporting the total number of
> > > leaf changes.
> > >
> > >       * src/abg-comparison.cc (emit_diff_stats): Exclude non-leaf
> > >       changes to variables from the reported total of leaf changes.
> > >       * src/abg-default-reporter.cc (report): In the corpus_diff
> > >       override, move some code and comments for clarity.
> > >       * src/abg-leaf-reporter.cc (report): In the corpus_diff
> > >       override, additionally report removed/added/changed variables
> > >       and removed/added symbols absent from debug info.
> > >       * tests/data/Makefile.am: Add new test case files.
> > >       * tests/data/test-abidiff-exit/test-leaf0-report.txt: Update
> > >       to include reporting of variable diff (change of type).
> > >       * tests/data/test-abidiff-exit/test-leaf1-report.txt: New test
> > >       case with added/removed variables/functions and changed
> > >       variables (both local and non-local type changes).
> > >       * tests/data/test-abidiff-exit/test-leaf1-v0.cc: Ditto.
> > >       * tests/data/test-abidiff-exit/test-leaf1-v0.o: Ditto.
> > >       * tests/data/test-abidiff-exit/test-leaf1-v1.cc: Ditto.
> > >       * tests/data/test-abidiff-exit/test-leaf1-v1.o: Ditto.
> > >       * tests/test-abidiff-exit.cc: Run new test case. Supply
> > >       --redundant otherwise the test isn't meaningful.
> >
> > This looks OK to me.  I have just updated the manual of the abi{pkg}diff
> > tools to say that --leaf-changes-only implies --redudant, just as you
> > did in the help string of these tools.
> >
> > The patch was applied to master.
> >
> > Thanks!
> >
> > --
> >                 Dodji
  

Patch

diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index b99cfa7d..6539ed7a 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -9841,7 +9841,7 @@  corpus_diff::priv::emit_diff_stats(const diff_stats&	s,
     s.net_num_leaf_func_changes() +
     s.net_num_vars_removed() +
     s.net_num_vars_added() +
-    s.net_num_vars_changed() +
+    s.net_num_leaf_var_changes() +
     s.net_num_leaf_type_changes();
 
   if (!sonames_equal_)
diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index 2ac93d41..3bfdfbc4 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -1761,18 +1761,12 @@  void
 default_reporter::report(const corpus_diff& d, ostream& out,
 			 const string& indent) const
 {
-  size_t total = 0;
   const corpus_diff::diff_stats &s =
     const_cast<corpus_diff&>(d).
     apply_filters_and_suppressions_before_reporting();
 
   const diff_context_sptr& ctxt = d.context();
 
-  /// Report removed/added/changed functions.
-  total = s.net_num_func_removed() + s.net_num_func_added() +
-    s.net_num_func_changed();
-  const unsigned large_num = 100;
-
   d.priv_->emit_diff_stats(s, out, indent);
   if (ctxt->show_stats_only())
     return;
@@ -1790,6 +1784,11 @@  default_reporter::report(const corpus_diff& d, ostream& out,
 	<< d.first_corpus()->get_architecture_name() << "' to '"
 	<< d.second_corpus()->get_architecture_name() << "'\n\n";
 
+  /// Report removed/added/changed functions.
+  size_t total = s.net_num_func_removed() + s.net_num_func_added() +
+    s.net_num_func_changed();
+  const unsigned large_num = 100;
+
   if (ctxt->show_deleted_fns())
     {
       if (s.net_num_func_removed() == 1)
@@ -2249,7 +2248,6 @@  default_reporter::report(const corpus_diff& d, ostream& out,
 
   // Report added/removed/changed types not reacheable from public
   // interfaces.
-
   maybe_report_unreachable_type_changes(d, s, indent, out);
 
   d.priv_->maybe_dump_diff_tree();
diff --git a/src/abg-leaf-reporter.cc b/src/abg-leaf-reporter.cc
index 4b85d816..cccc1225 100644
--- a/src/abg-leaf-reporter.cc
+++ b/src/abg-leaf-reporter.cc
@@ -1034,16 +1034,15 @@  leaf_reporter::report(const corpus_diff& d,
   if (!d.has_changes())
     return;
 
-  const diff_context_sptr& ctxt = d.context();
-
   const corpus_diff::diff_stats &s =
     const_cast<corpus_diff&>(d).
     apply_filters_and_suppressions_before_reporting();
 
+  const diff_context_sptr& ctxt = d.context();
+
   d.priv_->emit_diff_stats(s, out, indent);
   if (ctxt->show_stats_only())
     return;
-
   out << "\n";
 
   if (ctxt->show_soname_change()
@@ -1058,6 +1057,7 @@  leaf_reporter::report(const corpus_diff& d,
 	<< d.first_corpus()->get_architecture_name() << "' to '"
 	<< d.second_corpus()->get_architecture_name() << "'\n\n";
 
+  /// Report removed/added/changed functions.
   if (ctxt->show_deleted_fns())
     {
       if (s.net_num_func_removed() == 1)
@@ -1104,6 +1104,55 @@  leaf_reporter::report(const corpus_diff& d,
 	out << "\n";
     }
 
+  if (ctxt->show_added_fns())
+    {
+      if (s.net_num_func_added() == 1)
+        out << indent << "1 Added function:\n\n";
+      else if (s.net_num_func_added() > 1)
+        out << indent << s.net_num_func_added()
+            << " Added functions:\n\n";
+      bool emitted = false;
+      vector<function_decl*> sorted_added_fns;
+      sort_string_function_ptr_map(d.priv_->added_fns_, sorted_added_fns);
+      for (vector<function_decl*>::const_iterator i = sorted_added_fns.begin();
+           i != sorted_added_fns.end();
+           ++i)
+        {
+          if (d.priv_->added_function_is_suppressed(*i))
+            continue;
+
+          out
+            << indent
+            << "  ";
+          out << "[A] ";
+          out << "'"
+              << (*i)->get_pretty_representation()
+              << "'";
+          if (ctxt->show_linkage_names())
+            {
+              out << "    {";
+              show_linkage_name_and_aliases
+                (out, "", *(*i)->get_symbol(),
+                 d.second_corpus()->get_fun_symbol_map());
+              out << "}";
+            }
+          out << "\n";
+          if (is_member_function(*i) && get_member_function_is_virtual(*i))
+            {
+              class_decl_sptr c =
+                is_class_type(is_method_type((*i)->get_type())->get_class_type());
+              out << indent
+                  << "    "
+                  << "note that this adds a new entry to the vtable of "
+                  << c->get_pretty_representation()
+                  << "\n";
+            }
+          emitted = true;
+        }
+      if (emitted)
+        out << "\n";
+    }
+
   if (ctxt->show_changed_fns())
     {
       // Show changed functions.
@@ -1174,55 +1223,273 @@  leaf_reporter::report(const corpus_diff& d,
 	out << "\n";
     }
 
-  if (ctxt->show_added_fns())
+  // Report removed/added/changed variables.
+  if (ctxt->show_deleted_vars())
     {
-      if (s.net_num_func_added() == 1)
-	out << indent << "1 Added function:\n\n";
-      else if (s.net_num_func_added() > 1)
-	out << indent << s.net_num_func_added()
-	    << " Added functions:\n\n";
+      if (s.net_num_vars_removed() == 1)
+	out << indent << "1 Removed variable:\n\n";
+      else if (s.net_num_vars_removed() > 1)
+	out << indent << s.net_num_vars_removed()
+	    << " Removed variables:\n\n";
+      string n;
       bool emitted = false;
-      vector<function_decl*> sorted_added_fns;
-      sort_string_function_ptr_map(d.priv_->added_fns_, sorted_added_fns);
-      for (vector<function_decl*>::const_iterator i = sorted_added_fns.begin();
-	   i != sorted_added_fns.end();
+      vector<var_decl*> sorted_deleted_vars;
+      sort_string_var_ptr_map(d.priv_->deleted_vars_, sorted_deleted_vars);
+      for (vector<var_decl*>::const_iterator i =
+	     sorted_deleted_vars.begin();
+	   i != sorted_deleted_vars.end();
 	   ++i)
 	{
-	  if (d.priv_->added_function_is_suppressed(*i))
+	  if (d.priv_->deleted_variable_is_suppressed(*i))
 	    continue;
 
-	  out
-	    << indent
-	    << "  ";
-	  out << "[A] ";
+	  n = (*i)->get_pretty_representation();
+
+	  out << indent
+	      << "  ";
+	  out << "[D] ";
 	  out << "'"
-	      << (*i)->get_pretty_representation()
+	      << n
 	      << "'";
 	  if (ctxt->show_linkage_names())
 	    {
 	      out << "    {";
-	      show_linkage_name_and_aliases
-		(out, "", *(*i)->get_symbol(),
-		 d.second_corpus()->get_fun_symbol_map());
+	      show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
+					    d.first_corpus()->get_var_symbol_map());
 	      out << "}";
 	    }
 	  out << "\n";
-	  if (is_member_function(*i) && get_member_function_is_virtual(*i))
+	  emitted = true;
+	}
+      if (emitted)
+        out << "\n";
+    }
+
+  if (ctxt->show_added_vars())
+    {
+      if (s.net_num_vars_added() == 1)
+	out << indent << "1 Added variable:\n\n";
+      else if (s.net_num_vars_added() > 1)
+	out << indent << s.net_num_vars_added()
+	    << " Added variables:\n\n";
+      string n;
+      bool emitted = false;
+      vector<var_decl*> sorted_added_vars;
+      sort_string_var_ptr_map(d.priv_->added_vars_, sorted_added_vars);
+      for (vector<var_decl*>::const_iterator i =
+	     sorted_added_vars.begin();
+	   i != sorted_added_vars.end();
+	   ++i)
+	{
+	  if (d.priv_->added_variable_is_suppressed(*i))
+	    continue;
+
+	  n = (*i)->get_pretty_representation();
+
+	  out << indent
+	      << "  ";
+	  out << "[A] ";
+	  out << "'" << n << "'";
+	  if (ctxt->show_linkage_names())
 	    {
-	      class_decl_sptr c =
-		is_class_type(is_method_type((*i)->get_type())->get_class_type());
-	      out << indent
-		  << "    "
-		  << "note that this adds a new entry to the vtable of "
-		  << c->get_pretty_representation()
-		  << "\n";
+	      out << "    {";
+	      show_linkage_name_and_aliases(out, "", *(*i)->get_symbol(),
+					    d.second_corpus()->get_var_symbol_map());
+	      out << "}";
 	    }
+	  out << "\n";
 	  emitted = true;
 	}
       if (emitted)
 	out << "\n";
     }
 
+  if (ctxt->show_changed_vars())
+    {
+      size_t num_changed = s.net_num_leaf_var_changes();
+      if (num_changed == 1)
+	out << indent << "1 Changed variable:\n\n";
+      else if (num_changed > 1)
+	out << indent << num_changed
+	    << " Changed variables:\n\n";
+      string n1, n2;
+      bool emitted = false;
+      for (var_diff_sptrs_type::const_iterator i =
+	     d.priv_->sorted_changed_vars_.begin();
+	   i != d.priv_->sorted_changed_vars_.end();
+	   ++i)
+	{
+	  diff_sptr diff = *i;
+
+	  if (!diff)
+	    continue;
+
+	  if (!diff_to_be_reported(diff.get()))
+            continue;
+
+	  n1 = diff->first_subject()->get_pretty_representation();
+	  n2 = diff->second_subject()->get_pretty_representation();
+
+	  out << indent << "  [C] '" << n1 << "' was changed";
+	  if (n1 != n2)
+	    out << " to '" << n2 << "'";
+	  report_loc_info(diff->second_subject(), *ctxt, out);
+	  out << ":\n";
+	  diff->report(out, indent + "    ");
+	  out << "\n";
+          emitted = true;
+	}
+      if (emitted)
+	out << "\n";
+    }
+
+  // Report removed function symbols not referenced by any debug info.
+  if (ctxt->show_symbols_unreferenced_by_debug_info()
+      && d.priv_->deleted_unrefed_fn_syms_.size())
+    {
+      if (s.net_num_removed_func_syms() == 1)
+	out << indent
+	    << "1 Removed function symbol not referenced by debug info:\n\n";
+      else if (s.net_num_removed_func_syms() > 0)
+	out << indent
+	    << s.net_num_removed_func_syms()
+	    << " Removed function symbols not referenced by debug info:\n\n";
+
+      bool emitted = false;
+      vector<elf_symbol_sptr> sorted_deleted_unrefed_fn_syms;
+      sort_string_elf_symbol_map(d.priv_->deleted_unrefed_fn_syms_,
+				 sorted_deleted_unrefed_fn_syms);
+      for (vector<elf_symbol_sptr>::const_iterator i =
+	     sorted_deleted_unrefed_fn_syms.begin();
+	   i != sorted_deleted_unrefed_fn_syms.end();
+	   ++i)
+	{
+	  if (d.priv_->deleted_unrefed_fn_sym_is_suppressed((*i).get()))
+	    continue;
+
+	  out << indent << "  ";
+	  out << "[D] ";
+
+	  show_linkage_name_and_aliases(out, "", **i,
+					d.first_corpus()->get_fun_symbol_map());
+	  out << "\n";
+          emitted = true;
+	}
+      if (emitted)
+	out << "\n";
+    }
+
+  // Report added function symbols not referenced by any debug info.
+  if (ctxt->show_symbols_unreferenced_by_debug_info()
+      && ctxt->show_added_symbols_unreferenced_by_debug_info()
+      && d.priv_->added_unrefed_fn_syms_.size())
+    {
+      if (s.net_num_added_func_syms() == 1)
+	out << indent
+	    << "1 Added function symbol not referenced by debug info:\n\n";
+      else if (s.net_num_added_func_syms() > 0)
+	out << indent
+	    << s.net_num_added_func_syms()
+	    << " Added function symbols not referenced by debug info:\n\n";
+
+      bool emitted = false;
+      vector<elf_symbol_sptr> sorted_added_unrefed_fn_syms;
+      sort_string_elf_symbol_map(d.priv_->added_unrefed_fn_syms_,
+				 sorted_added_unrefed_fn_syms);
+      for (vector<elf_symbol_sptr>::const_iterator i =
+	     sorted_added_unrefed_fn_syms.begin();
+	   i != sorted_added_unrefed_fn_syms.end();
+	   ++i)
+	{
+	  if (d.priv_->added_unrefed_fn_sym_is_suppressed((*i).get()))
+	    continue;
+
+	  out << indent << "  ";
+	  out << "[A] ";
+	  show_linkage_name_and_aliases(out, "",
+					**i,
+					d.second_corpus()->get_fun_symbol_map());
+	  out << "\n";
+          emitted = true;
+	}
+      if (emitted)
+	out << "\n";
+    }
+
+  // Report removed variable symbols not referenced by any debug info.
+  if (ctxt->show_symbols_unreferenced_by_debug_info()
+      && d.priv_->deleted_unrefed_var_syms_.size())
+    {
+      if (s.net_num_removed_var_syms() == 1)
+	out << indent
+	    << "1 Removed variable symbol not referenced by debug info:\n\n";
+      else if (s.net_num_removed_var_syms() > 0)
+	out << indent
+	    << s.net_num_removed_var_syms()
+	    << " Removed variable symbols not referenced by debug info:\n\n";
+
+      bool emitted = false;
+      vector<elf_symbol_sptr> sorted_deleted_unrefed_var_syms;
+      sort_string_elf_symbol_map(d.priv_->deleted_unrefed_var_syms_,
+				 sorted_deleted_unrefed_var_syms);
+      for (vector<elf_symbol_sptr>::const_iterator i =
+	     sorted_deleted_unrefed_var_syms.begin();
+	   i != sorted_deleted_unrefed_var_syms.end();
+	   ++i)
+	{
+	  if (d.priv_->deleted_unrefed_var_sym_is_suppressed((*i).get()))
+	    continue;
+
+	  out << indent << "  ";
+	  out << "[D] ";
+
+	  show_linkage_name_and_aliases
+	    (out, "", **i,
+	     d.first_corpus()->get_fun_symbol_map());
+
+	  out << "\n";
+          emitted = true;
+	}
+      if (emitted)
+	out << "\n";
+    }
+
+  // Report added variable symbols not referenced by any debug info.
+  if (ctxt->show_symbols_unreferenced_by_debug_info()
+      && ctxt->show_added_symbols_unreferenced_by_debug_info()
+      && d.priv_->added_unrefed_var_syms_.size())
+    {
+      if (s.net_num_added_var_syms() == 1)
+	out << indent
+	    << "1 Added variable symbol not referenced by debug info:\n\n";
+      else if (s.net_num_added_var_syms() > 0)
+	out << indent
+	    << s.net_num_added_var_syms()
+	    << " Added variable symbols not referenced by debug info:\n\n";
+
+      bool emitted = false;
+      vector<elf_symbol_sptr> sorted_added_unrefed_var_syms;
+      sort_string_elf_symbol_map(d.priv_->added_unrefed_var_syms_,
+				 sorted_added_unrefed_var_syms);
+      for (vector<elf_symbol_sptr>::const_iterator i =
+	     sorted_added_unrefed_var_syms.begin();
+	   i != sorted_added_unrefed_var_syms.end();
+	   ++i)
+	{
+	  if (d.priv_->added_unrefed_var_sym_is_suppressed((*i).get()))
+	    continue;
+
+	  out << indent << "  ";
+	  out << "[A] ";
+	  show_linkage_name_and_aliases(out, "", **i,
+					d.second_corpus()->get_fun_symbol_map());
+	  out << "\n";
+          emitted = true;
+	}
+      if (emitted)
+	out << "\n";
+    }
+
   // Now show the changed types.
   const diff_maps& leaf_diffs = d.get_leaf_diffs();
   report_type_changes_from_diff_maps(*this, leaf_diffs, out, indent);
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 07077608..5dab8685 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -115,6 +115,11 @@  test-abidiff-exit/test-leaf0-v0.o \
 test-abidiff-exit/test-leaf0-v1.cc \
 test-abidiff-exit/test-leaf0-v1.o \
 test-abidiff-exit/test-leaf0-report.txt \
+test-abidiff-exit/test-leaf1-v0.cc \
+test-abidiff-exit/test-leaf1-v0.o \
+test-abidiff-exit/test-leaf1-v1.cc \
+test-abidiff-exit/test-leaf1-v1.o \
+test-abidiff-exit/test-leaf1-report.txt \
 \
 test-diff-dwarf/test0-v0.cc		\
 test-diff-dwarf/test0-v0.o			\
diff --git a/tests/data/test-abidiff-exit/test-leaf0-report.txt b/tests/data/test-abidiff-exit/test-leaf0-report.txt
index f823789d..7d15e28f 100644
--- a/tests/data/test-abidiff-exit/test-leaf0-report.txt
+++ b/tests/data/test-abidiff-exit/test-leaf0-report.txt
@@ -11,3 +11,12 @@  Removed/Changed/Added variables summary: 0 Removed, 1 Changed, 0 Added variable
       type size changed from 32 to 64 (in bits)
 
 
+1 Changed variable:
+
+  [C] 'int changed_var' was changed to 'long int changed_var':
+    size of symbol changed from 4 to 8
+    type of variable changed:
+     type name changed from 'int' to 'long int'
+     type size changed from 32 to 64 (in bits)
+
+
diff --git a/tests/data/test-abidiff-exit/test-leaf1-report.txt b/tests/data/test-abidiff-exit/test-leaf1-report.txt
new file mode 100644
index 00000000..b51bb4b3
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-leaf1-report.txt
@@ -0,0 +1,46 @@ 
+Leaf changes summary: 7 artifacts changed
+Changed leaf types summary: 1 leaf type changed
+Removed/Changed/Added functions summary: 1 Removed, 1 Changed, 1 Added function
+Removed/Changed/Added variables summary: 1 Removed, 1 Changed, 1 Added variable
+
+1 Removed function:
+
+  [D] 'function int deleted_fun()'    {_Z11deleted_funv}
+
+1 Added function:
+
+  [A] 'function long int added_fun()'    {_Z9added_funv}
+
+1 function with some sub-type change:
+
+  [C] 'function int directly_changed_fun()' has some sub-type changes:
+    return type changed:
+      type name changed from 'int' to 'long int'
+      type size changed from 32 to 64 (in bits)
+
+
+1 Removed variable:
+
+  [D] 'int deleted_var'    {deleted_var}
+
+1 Added variable:
+
+  [A] 'long int added_var'    {added_var}
+
+1 Changed variable:
+
+  [C] 'int directly_changed_var' was changed to 'long int directly_changed_var':
+    size of symbol changed from 4 to 8
+    type of variable changed:
+     type name changed from 'int' to 'long int'
+     type size changed from 32 to 64 (in bits)
+
+
+'struct changed' changed:
+  type size changed from 32 to 64 (in bits)
+  there are data member changes:
+   type 'int' of 'changed::foo' changed:
+     type name changed from 'int' to 'long int'
+     type size changed from 32 to 64 (in bits)
+   and size changed from 32 to 64 (in bits) (by +32 bits)
+
diff --git a/tests/data/test-abidiff-exit/test-leaf1-v0.cc b/tests/data/test-abidiff-exit/test-leaf1-v0.cc
new file mode 100644
index 00000000..bb6505c8
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-leaf1-v0.cc
@@ -0,0 +1,16 @@ 
+struct changed {
+  int foo = 0;
+};
+
+int deleted_var = 0;
+int directly_changed_var = 0;
+changed * indirectly_changed_var;
+
+int deleted_fun() {
+  return 0;
+}
+int directly_changed_fun() {
+  return 0;
+}
+void indirectly_changed_fun(changed * x) {
+}
diff --git a/tests/data/test-abidiff-exit/test-leaf1-v0.o b/tests/data/test-abidiff-exit/test-leaf1-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..a8734481238bda41217440b305307ea7c5464782
GIT binary patch
literal 3792
zcmbtW&2Jl35TEtNu~R3G6Z6p|6><?Ml(3sPgtRH7H3ZUxA{3BvXhr0%?R9KnuOoXC
z96rPWgp^w=ApsH+he-Sl+<PE5Zoof)kht{*LVV2Z&e$){n{r?z@67z>^Sw9w)*rw2
z#(K;!K*)e=(ANY7$eioTg+MGo7A9eP<LH;~NZ+}yi5o{B{eE}ne&7p`#H2%kOp?fK
zBz94eV<Zn5MsfqWS#7nzh$ToybSPf;e29~5#Nz~xn4}Pe=x`*ONZmt^zVC3-LOnrY
z#`rKXp%e?o*WaU*?4o^^Vq^DeFhVwCG$<4{L;yfPCiED2hzA%G#?$F+%1qCsCydEN
z=5frOHOzD>bv5;3Y9(c4an)mBCPQ^Idj-=EJq4-MwUn8}WiEl47Tfiy*m;2AakOq?
zT*5Z4Pl?qF@)yp3@yZnCOvaU*6g6Ul>b#kyb^>=?(sTF=4g#>GLh3;&Fl?h@!Yn=w
z<InUMK7+Bs(>B0&JHFL$ooe1XSg_0GATFMTk+1-&)A4gR<HoJ{g?Sd9osS!z#7s<6
zyuG+kskhy--#9FmYmT?;R*Kbq?*NLo^ZAO~aD4#=>I}pkIBnn@Q1>FuN=6uPz`Ahb
z&F$RU++2Psw_-2a`P||{ekGq@Sj<^Xf8TRgcU{kI*UP9n?Q(6kdu7>LUdma!Ijib)
z4!v@%-SS%d9c$lv4_mN&r_^veQQc56T>WB1qiEW?EDM?Un|mN_(+c6n+S=9JGq1X(
zy5ogiTKUVDw0`Ln9tn;D&*=TP!RTg;nbAb@E}q#1#OX&A4EM|F%xAH+vEg-eK#XiJ
zkrC-E`#YgI($1y<hNbbIc<|4F0RbF_C>ZhH7@e}4Xo(_|ZzA1h!l`?pXEwuYqNj^s
zhS!0pJ#O}{gB}zJCXAg1STiAg20l7~Pa-m*tSh`z0dkCsF8m3`<sBCO0^*a(e#!;5
z&ba8p?=b!taw5S8Uu|^`BL<hobKt#w*em|u<4^s_$<b#@WWr?!38$->E^?xYkb&TH
ztUs#ZPx8o3F;1#FZI={(*;|5a1*f`ivA(6@vz&j2aZ=SOscQc6&UF-jb$UM3{BN;-
zr1+1sOzcaRWgmWJ{TmJcoAqPnvJWy3Cz`+X@q>o53O{LiWS)N0{P$RYpyAW3|G`}P
zVYN2{w65S=%!bSv{>x|JImYSC)pIXsxb%NV!)1TK?i@Dprbq6#LtYcfce_5=6~}kL
zE_FI!x7~(gSKQM6Zn5rFTWAYpr&MaY2dB(Vn?8r9LmG9@l@KfecDdDTy7;Hb_FBGc
z<JZgT_)hs<PUO~#)wa`gx$*zWW-y-4LVX7*Wq}?@7em&2lCMf+CrrP&9o0#Z^?3UK
zLGPg+U*i}#e@UUfvxMdGr{^SG;zu>3rUw6-=<Y30kU}TCAsHSb>Vy2GKK>gEXceD&
zPBQomej9l8AG+@rnski3r@8JzKQxeZ-<ya=_5U+BD)H2R0)Kk{6~y$M2*K-IU+yEq
zh;-i~Vo~*zbcrI#K2d#w^!j^<QBLU-#ej~v{_|QvQH6hi-cj*C@<7pisU&g2KSiU+
zs^4GwK(bNy{fgtc-F^z%6r^s*dQVxu0H31}wSPI@zYTVz{iE-O#LK=?KLfQ9>vH`Q
lZkWEG^qtb<sZ7*T3q1d{KPu_#r@T?|HSYgd4Mtgy{}+ciMVbHr

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-leaf1-v1.cc b/tests/data/test-abidiff-exit/test-leaf1-v1.cc
new file mode 100644
index 00000000..5df5df9d
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-leaf1-v1.cc
@@ -0,0 +1,16 @@ 
+struct changed {
+  long foo = 0;
+};
+
+long directly_changed_var = 0;
+changed * indirectly_changed_var;
+long added_var = 0;
+
+long directly_changed_fun() {
+  return 0;
+}
+void indirectly_changed_fun(changed * x) {
+}
+long added_fun() {
+  return 0;
+}
diff --git a/tests/data/test-abidiff-exit/test-leaf1-v1.o b/tests/data/test-abidiff-exit/test-leaf1-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..324180ca92b91045edb4c9d3b9fef1fd314a09ba
GIT binary patch
literal 3808
zcmbtW&2Jl35TEC*zv{$IVm|UgC0BsbQoM~rNSi`hL!eD4pn{Y`D=M?L*Rh4YF80Pa
zAXEtus3(eq1V~66D#5>iIDrrne*zbdNWiTU2M~ucvpeHFKW`8cBkj)2Z$97KdAob#
z+2=3Blma0I=U`tG6d-?iUoHh=334z4+nYCk`I_`=-;=m`^X)%xg(9PYFF*>D9tvcV
zL}nwgW11WzIi*x;6S-CIbU?)d8RJrMG6pvlPmn{}B7`VJ6PdSA-bWLu!qAp9B9auQ
zvI%08ODMyF`aDIFng~3`t-m3Z9-w`ZYQ{clK$tQ8FBw5itB13>jFnx;POF*Z)cqKl
zQ&u*UIh%PRvzAdgT=gVasZia@oxyevJp`G|ISj&Ou7H&l+xfZJEI{H2TDLGRX~X$B
zv3l99991aIe)9Aj?x?MF+t5Pw(s8XGWrRm*L3m+YaF?6@padhnjh6+BcvtH0>?GcU
zvBIaVz;}Coq2)UDVxeEOt5x!c_)$oQ1yGrfAHEb<SK^PHimP|yGwY!mi(#7b)#asH
zv+Gv<)?T^VaJ(J2R<7@QeQ0&OoqW^t$McW*_nj_qEHu4Hvs0^uiDAr))!^cb+xd-?
zCyOijHGA1E=9ia>YsKQya=y^^cRhD~$MxK9vx=(Itv1#NXI2ZVEBV4szEF31dtSBC
z?RcHtUSZdJ0~;v#PNn7cqI#iXxaQ@EHqmtXv@GM4-@XoE)3mzs)wSUY`T!R<HqPdc
zKjT)Kju&=ZD4srH^bT-O@F?&Zz4<bz!IWB<NTzP#GkXAWx`=|q@Kko{{n*B2;sQD#
zMz$x(h;)$smCzh%XVVzN()gaZb9c;ufED>>B78VTBViU=qR8Smk!iDF<dhH1R(Pm~
zx(F7eMI7N)xZ)9v6bmNDun@;X9YGdMjG^?rrnPm+*_>fqbm1o$pW;k{KZg2@wx9CC
zdx3G$g}=`DeVj+|@uL?pwltplpdNId|I5@HV=hmOK2IW3i?VZs(^L9@K&0uAf#46a
zey@Sg(jX$?Ycn8H^(mu$C89jCr=;6-Lz4Vkp$eCn3qH^KWdmPf{Tg$st4~ec@PCQ*
zp60Jl(>sR$QC`=Fn*R}&iG9kl^x0tj3j<%|JYO*``y=!5jp6?@>)#ppAFThtT=K|#
z{ciYoS-)f8tioR`NFKpuHfUYJZvq?ST$ui=2js~!PP3rTL&?CU|5puM_6O|VUK_sw
z$o+1}8zTAczz4hL_zu{WUJvZ9+j8uhTiM+yH@$iXZGr4mDqXifVs^Upc^nOCH9c2C
zumsrEPP^^mSJU=7zH8%mt<dwG>T8_HZItU>r|oj%|C23XJngOQzoaX%a7+N^<f{|e
z2{Yg1j_#z%W<33m(D^juWv=N@M<@L(6JEs2%t^S!PZ&l+4gR9&zqdp|8hy(fa-4^V
z=8*iPzVx+@n3<E(_zZqYibkd{y<bd>+~>LOk`_y%=}YgesQ!QDMkSv5PvT|vUyI0z
z5Io2AuaKgVS-*_7sQR<?Qb&?~qWT1x^{*pFIi*h&1G>%iA2$k$Dx7}nqvC(!fui}+
zN#caRhenZgzq{r@veESYjN`f8{S>q*NQ00K@3MXYK1LyG|CV_FHrbK(kG>lcFZ)XU
tjMYYL!1aIRhUvRX-zhVm%0w--#Pfdx?K+w3r@T?|1MdH}9*nXX{||`LLr4Gs

literal 0
HcmV?d00001

diff --git a/tests/test-abidiff-exit.cc b/tests/test-abidiff-exit.cc
index 5372b3fe..7a334227 100644
--- a/tests/test-abidiff-exit.cc
+++ b/tests/test-abidiff-exit.cc
@@ -129,6 +129,17 @@  InOutSpec in_out_specs[] =
     "data/test-abidiff-exit/test-leaf0-report.txt",
     "output/test-abidiff-exit/test-leaf0-report.txt"
   },
+  {
+    "data/test-abidiff-exit/test-leaf1-v0.o",
+    "data/test-abidiff-exit/test-leaf1-v1.o",
+    "",
+    // --redundant - pending a bug fix
+    "--no-show-locs --leaf-changes-only --redundant",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE
+    | abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
+    "data/test-abidiff-exit/test-leaf1-report.txt",
+    "output/test-abidiff-exit/test-leaf1-report.txt"
+  },
   {0, 0, 0 ,0,  abigail::tools_utils::ABIDIFF_OK, 0, 0}
 };