[applied] dwarf-reader: Canonicalize opaque enums and classes

Message ID 87wnt7tt8w.fsf@redhat.com
State Committed
Headers
Series [applied] dwarf-reader: Canonicalize opaque enums and classes |

Commit Message

Dodji Seketeli April 12, 2021, 3:30 p.m. UTC
  Hello,

This issue was reported in bug https://sourceware.org/bugzilla/show_bug.cgi?id=27700.

When we construct an opaque type (triggered by the use of
--drop-private-types along with the --headers-dir option on abidw, for
instance) with get_opaque_version_of_type we forget to canonicalize
the resulting type.

Later, at abixml emitting time (for instance)
nhash_as_canonical_type_or_constant would rightfully abort because the
type wasn't canonicalized.  We want all types (okay, modulo one
exception) in the system to be canonicalized.

This patch fixes the problem by canonicalizing opaque types.

	* src/abg-dwarf-reader.cc (build_ir_node_from_die): Canonicalize
	opaque enums and classes.
	* tests/data/test-read-dwarf/PR27700/include-dir/priv.h: New test
	header file.
	* tests/data/test-read-dwarf/PR27700/include-dir/pub.h: Likewise
	* tests/data/test-read-dwarf/PR27700/pub-incdir/inc.h: Likewise.
	* tests/data/test-read-dwarf/PR27700/test-PR27700.o: New binary
	input file.
	* tests/data/test-read-dwarf/PR27700/test-PR27700.abi: Reference
	abi file of the binary above.
	* tests/data/test-read-dwarf/PR27700/test-PR27700.c: Source file
	of the binary above.
	* tests/data/Makefile.am: Add the test material above to source
	distribution.
	* tests/test-read-dwarf.cc (InOutSpec::in_public_headers_path):
	Add new data member.
	(in_out_specs): Adjust to reflect the new data member in the
	InOutSpec type.  Add a new test input.
	(set_suppressions_from_headers): Define new static function.
	(test_task::perform): Use the content of the new
	InOutSpec::in_public_headers_path to construct and add
	"--headers-dir <headers-dir> --drop-private-types" to the options
	of the abidw program run.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>

Applied to master.

---
 src/abg-dwarf-reader.cc                       |  34 +++---
 tests/data/Makefile.am                        |   6 +
 .../PR27700/include-dir/priv.h                |   7 ++
 .../test-read-dwarf/PR27700/include-dir/pub.h |   0
 .../test-read-dwarf/PR27700/pub-incdir/inc.h  |   0
 .../test-read-dwarf/PR27700/test-PR27700.abi  |  17 +++
 .../test-read-dwarf/PR27700/test-PR27700.c    |   6 +
 .../test-read-dwarf/PR27700/test-PR27700.o    | Bin 0 -> 3248 bytes
 tests/test-read-dwarf.cc                      | 107 +++++++++++++++++-
 9 files changed, 160 insertions(+), 17 deletions(-)
 create mode 100644 tests/data/test-read-dwarf/PR27700/include-dir/priv.h
 create mode 100644 tests/data/test-read-dwarf/PR27700/include-dir/pub.h
 create mode 100644 tests/data/test-read-dwarf/PR27700/pub-incdir/inc.h
 create mode 100644 tests/data/test-read-dwarf/PR27700/test-PR27700.abi
 create mode 100644 tests/data/test-read-dwarf/PR27700/test-PR27700.c
 create mode 100644 tests/data/test-read-dwarf/PR27700/test-PR27700.o
  

Patch

diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index 47d63a7a..604c76e3 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -14807,13 +14807,16 @@  build_ir_node_from_die(read_context&	ctxt,
 	bool type_suppressed =
 	  type_is_suppressed(ctxt, scope, die, type_is_private);
 	if (type_suppressed && type_is_private)
-	  // The type is suppressed because it's private.  If other
-	  // non-suppressed and declaration-only instances of this
-	  // type exist in the current corpus, then it means those
-	  // non-suppressed instances are opaque versions of the
-	  // suppressed private type.  Lets return one of these opaque
-	  // types then.
-	  result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
+	  {
+	    // The type is suppressed because it's private.  If other
+	    // non-suppressed and declaration-only instances of this
+	    // type exist in the current corpus, then it means those
+	    // non-suppressed instances are opaque versions of the
+	    // suppressed private type.  Lets return one of these opaque
+	    // types then.
+	    result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
+	    maybe_canonicalize_type(is_type(result), ctxt);
+	  }
 	else if (!type_suppressed)
 	  {
 	    enum_type_decl_sptr e = build_enum_type(ctxt, die, scope,
@@ -14837,13 +14840,16 @@  build_ir_node_from_die(read_context&	ctxt,
 	  type_is_suppressed(ctxt, scope, die, type_is_private);
 
 	if (type_suppressed && type_is_private)
-	  // The type is suppressed because it's private.  If other
-	  // non-suppressed and declaration-only instances of this
-	  // type exist in the current corpus, then it means those
-	  // non-suppressed instances are opaque versions of the
-	  // suppressed private type.  Lets return one of these opaque
-	  // types then.
-	  result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
+	  {
+	    // The type is suppressed because it's private.  If other
+	    // non-suppressed and declaration-only instances of this
+	    // type exist in the current corpus, then it means those
+	    // non-suppressed instances are opaque versions of the
+	    // suppressed private type.  Lets return one of these opaque
+	    // types then.
+	    result = get_opaque_version_of_type(ctxt, scope, die, where_offset);
+	    maybe_canonicalize_type(is_type(result), ctxt);
+	  }
 	else if (!type_suppressed)
 	  {
 	    Dwarf_Die spec_die;
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 53faec67..576309e8 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -556,6 +556,12 @@  test-read-dwarf/test-suppressed-alias.c \
 test-read-dwarf/test-suppressed-alias.o \
 test-read-dwarf/test-suppressed-alias.o.abi \
 test-read-dwarf/test-suppressed-alias.suppr \
+test-read-dwarf/PR27700/include-dir/priv.h  \
+test-read-dwarf/PR27700/include-dir/pub.h  \
+test-read-dwarf/PR27700/pub-incdir/inc.h  \
+test-read-dwarf/PR27700/test-PR27700.abi  \
+test-read-dwarf/PR27700/test-PR27700.c  \
+test-read-dwarf/PR27700/test-PR27700.o  \
 \
 test-annotate/test0.abi			\
 test-annotate/test1.abi			\
diff --git a/tests/data/test-read-dwarf/PR27700/include-dir/priv.h b/tests/data/test-read-dwarf/PR27700/include-dir/priv.h
new file mode 100644
index 00000000..e76683d4
--- /dev/null
+++ b/tests/data/test-read-dwarf/PR27700/include-dir/priv.h
@@ -0,0 +1,7 @@ 
+enum foo
+{
+  foo_e0,
+  foo_e1,
+  foo_e2,
+  foo_e3
+};
diff --git a/tests/data/test-read-dwarf/PR27700/include-dir/pub.h b/tests/data/test-read-dwarf/PR27700/include-dir/pub.h
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/data/test-read-dwarf/PR27700/pub-incdir/inc.h b/tests/data/test-read-dwarf/PR27700/pub-incdir/inc.h
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/data/test-read-dwarf/PR27700/test-PR27700.abi b/tests/data/test-read-dwarf/PR27700/test-PR27700.abi
new file mode 100644
index 00000000..5c49e369
--- /dev/null
+++ b/tests/data/test-read-dwarf/PR27700/test-PR27700.abi
@@ -0,0 +1,17 @@ 
+<abi-corpus version='2.0' path='data/test-read-dwarf/PR27700/test-PR27700.o'>
+  <elf-function-symbols>
+    <elf-symbol name='foo' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' path='test-PR27700.c' comp-dir-path='/home/dodji/git/libabigail/PR27700/tests/data/test-read-dwarf/PR27700' language='LANG_C11'>
+    <type-decl name='unnamed-enum-underlying-type-32' is-anonymous='yes' size-in-bits='32' alignment-in-bits='32' id='9cac1fee'/>
+    <type-decl name='void' id='48b5725f'/>
+    <enum-decl name='foo' is-artificial='yes' filepath='include-dir/priv.h' line='1' column='1' id='022218d8'>
+      <underlying-type type-id='9cac1fee'/>
+    </enum-decl>
+    <pointer-type-def type-id='022218d8' size-in-bits='64' id='8750e847'/>
+    <function-decl name='foo' mangled-name='foo' filepath='/home/dodji/git/libabigail/PR27700/tests/data/test-read-dwarf/PR27700/test-PR27700.c' line='4' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='foo'>
+      <parameter type-id='8750e847' name='c' filepath='/home/dodji/git/libabigail/PR27700/tests/data/test-read-dwarf/PR27700/test-PR27700.c' line='4' column='1'/>
+      <return type-id='48b5725f'/>
+    </function-decl>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-dwarf/PR27700/test-PR27700.c b/tests/data/test-read-dwarf/PR27700/test-PR27700.c
new file mode 100644
index 00000000..b44a3226
--- /dev/null
+++ b/tests/data/test-read-dwarf/PR27700/test-PR27700.c
@@ -0,0 +1,6 @@ 
+#include "include-dir/priv.h"
+
+void
+foo(enum foo* c __attribute__((unused)))
+{
+}
diff --git a/tests/data/test-read-dwarf/PR27700/test-PR27700.o b/tests/data/test-read-dwarf/PR27700/test-PR27700.o
new file mode 100644
index 0000000000000000000000000000000000000000..3f084d2132f0f43a683769ea91e9733fc599700a
GIT binary patch
literal 3248
zcmb_e&2Jl35TCbe$1dAAAFfJ6in1V}DZ*<zg{A~0xCHVczM`N=Ac3s4_t{>s*VTGc
zLJ^`85>f>cL2!d365@u0#6N(zapR7-AaUhZi37~+&T}@e8x;Yg_|433X5P%3_py2Z
zxfeDJAwZFUH8|1~3h-^=NN&Vp1I|Dh_O@>Qwsq^h+lO!b@Cm|s5Jj>YG~7=^nyi#!
zc7{VJ<X%I_5EI0bwDFh}WW=%wxm=t)PZ1(Fu1?J+zWf-YC)#M6BFXr)2Zf@85{N}G
zOXtzim=O<`%9gn>zc3?a3)A-km^on<*DTB0F0WWmSx;J`43K*WENjg&OSlwAJUwR?
z6WfJ33TvFZF-Kk#c~FM!vT+WeFoj{;Xo1J507?yUA7Y6HRqPmG;br7`^u2^!2=QlW
zk{GQKe<&;@lc8>)JY}MgB9RwxYV2|L1H;6a{b1yG1L@g*5W(h4d-i&L*{;`}np3lv
zYD;zcvln;KVatu!P^n$CD}!i1kgHu8$k1=2>W1y!>cN%EmCKLYl`dfWoAOe^Y6+_+
zYzeBp;Xqcsq4%a=?fOx*@3-8R-*x?db!T^JdAU}rMsgI5s-7FUu~-SE>s7qB-LRuv
zfLto<@3jA?N&TSR-}hw2^Fuv>mhW2VUw3){o9pW<_9Axf;y-8`@5UMC;>IqBgK05;
zx==jCEj*7n{fOc-aJ4l3p|L(Wv4IW=oH^17$iW|fWf^gkvtTg!<mpBeEm?#&D+@;N
zi4*YDBarei;Z#aH63r7%y$Pp}oKlhrc<nOCgsBV^Z!k>Wflnhco9fT_-f4SHZwZmw
zgL_a;uUgGaIIT|UvnUf0PQMLOkj^G-jI#>&u|PXEzNjca$~euTY9Q!p3a7kH);Bf0
z!}^OFK4AS74S$vO*EO6~z+)eiUZ?5_)tP4>V$^3M-T%P^9`|97^+z=P3)X8I{x$1Q
zX!!T6uW0y>tUt?Kug7MbdY|q;IHPw4k=sHZg$eH|DUt^fIP_A1(;AJy31#1PJlWds
zHvOP8L|ZJotyU<nA2Yk58+7IIkiH*C6@n?0NN_XO+rz;?;#=(m!$>;#?o>vR+kT5D
zmc3>tbO(|b@*mke##4{fzN+aOER639>*SlJ2T&nQe^H)KJEdej{sP+Qy#L$yI>zdA
zQaY9YGg4Bd`_lKBUcE-jCl>i|+Z-^1Ao;1gi68lxR&mtlB*QPU6(D4;nC`oS1|1{c
z9R}5XI4PdinN`2d8>-@|etNC-`aQ(5^50}oy&LEjlkQ9JQC9vP&VR^pl%L)&J^wYt
zXiilpiZT7ni6R9sSNRox7xAq4O}^Ye-6j5`6XMH!AggzY|D5ABH+V)r(Cnb<R{q~`
z{IRzPu`Q0jq8yp4{weq?6tepNEB9ZWQ|do`HC4RAsUAHyLU5Dw_qbsC&e7LckEcD&
eTI%mq6q5QsDADdbYgAWO{B5rPI~B-W@891PcJreE

literal 0
HcmV?d00001

diff --git a/tests/test-read-dwarf.cc b/tests/test-read-dwarf.cc
index e327909f..a04cef08 100644
--- a/tests/test-read-dwarf.cc
+++ b/tests/test-read-dwarf.cc
@@ -46,6 +46,7 @@  struct InOutSpec
 {
   const char* in_elf_path;
   const char* in_suppr_spec_path;
+  const char* in_public_headers_path;
   type_id_style_kind type_id_style;
   const char* in_abi_path;
   const char* out_abi_path;
@@ -57,6 +58,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test0",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test0.abi",
     "output/test-read-dwarf/test0.abi"
@@ -64,6 +66,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test0",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test0.hash.abi",
     "output/test-read-dwarf/test0.hash.abi"
@@ -71,6 +74,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test1",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test1.abi",
     "output/test-read-dwarf/test1.abi"
@@ -78,6 +82,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test1",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test1.hash.abi",
     "output/test-read-dwarf/test1.hash.abi"
@@ -85,6 +90,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test2.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test2.so.abi",
     "output/test-read-dwarf/test2.so.abi"
@@ -92,6 +98,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test2.so",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test2.so.hash.abi",
     "output/test-read-dwarf/test2.so.hash.abi"
@@ -99,6 +106,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test3.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3.so.abi",
     "output/test-read-dwarf/test3.so.abi"
@@ -106,6 +114,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test3.so",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3.so.hash.abi",
     "output/test-read-dwarf/test3.so.hash.abi"
@@ -114,6 +123,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test3.so",
     "data/test-read-dwarf/test3-alias-1.suppr",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3-alias-1.so.hash.abi",
     "output/test-read-dwarf/test3-alias-1.so.hash.abi"
@@ -122,6 +132,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test3.so",
     "data/test-read-dwarf/test3-alias-2.suppr",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3-alias-2.so.hash.abi",
     "output/test-read-dwarf/test3-alias-2.so.hash.abi"
@@ -130,6 +141,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test3.so",
     "data/test-read-dwarf/test3-alias-3.suppr",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3-alias-3.so.hash.abi",
     "output/test-read-dwarf/test3-alias-3.so.hash.abi"
@@ -138,6 +150,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test3.so",
     "data/test-read-dwarf/test3-alias-4.suppr",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test3-alias-4.so.hash.abi",
     "output/test-read-dwarf/test3-alias-4.so.hash.abi"
@@ -146,6 +159,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test-suppressed-alias.o",
     "data/test-read-dwarf/test-suppressed-alias.suppr",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-suppressed-alias.o.abi",
     "output/test-read-dwarf/test-suppressed-alias.o.abi",
@@ -153,6 +167,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test4.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test4.so.abi",
     "output/test-read-dwarf/test4.so.abi"
@@ -160,6 +175,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test4.so",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test4.so.hash.abi",
     "output/test-read-dwarf/test4.so.hash.abi"
@@ -167,6 +183,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test5.o",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test5.o.abi",
     "output/test-read-dwarf/test5.o.abi"
@@ -174,6 +191,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test5.o",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test5.o.hash.abi",
     "output/test-read-dwarf/test5.o.hash.abi"
@@ -181,6 +199,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test6.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test6.so.abi",
     "output/test-read-dwarf/test6.so.abi"
@@ -188,6 +207,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test6.so",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test6.so.hash.abi",
     "output/test-read-dwarf/test6.so.hash.abi"
@@ -195,6 +215,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test7.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test7.so.abi",
     "output/test-read-dwarf/test7.so.abi"
@@ -202,6 +223,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test7.so",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test7.so.hash.abi",
     "output/test-read-dwarf/test7.so.hash.abi"
@@ -209,6 +231,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test8-qualified-this-pointer.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test8-qualified-this-pointer.so.abi",
     "output/test-read-dwarf/test8-qualified-this-pointer.so.abi"
@@ -216,6 +239,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test8-qualified-this-pointer.so",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test8-qualified-this-pointer.so.hash.abi",
     "output/test-read-dwarf/test8-qualified-this-pointer.so.hash.abi"
@@ -223,6 +247,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test9-pr18818-clang.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test9-pr18818-clang.so.abi",
     "output/test-read-dwarf/test9-pr18818-clang.so.abi"
@@ -230,6 +255,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test10-pr18818-gcc.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test10-pr18818-gcc.so.abi",
     "output/test-read-dwarf/test10-pr18818-gcc.so.abi"
@@ -237,6 +263,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test11-pr18828.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test11-pr18828.so.abi",
     "output/test-read-dwarf/test11-pr18828.so.abi",
@@ -244,6 +271,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test12-pr18844.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test12-pr18844.so.abi",
     "output/test-read-dwarf/test12-pr18844.so.abi",
@@ -251,6 +279,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test13-pr18894.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test13-pr18894.so.abi",
     "output/test-read-dwarf/test13-pr18894.so.abi",
@@ -258,6 +287,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test14-pr18893.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test14-pr18893.so.abi",
     "output/test-read-dwarf/test14-pr18893.so.abi",
@@ -265,6 +295,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test15-pr18892.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test15-pr18892.so.abi",
     "output/test-read-dwarf/test15-pr18892.so.abi",
@@ -272,6 +303,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test16-pr18904.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test16-pr18904.so.abi",
     "output/test-read-dwarf/test16-pr18904.so.abi",
@@ -279,6 +311,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test17-pr19027.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test17-pr19027.so.abi",
     "output/test-read-dwarf/test17-pr19027.so.abi",
@@ -286,6 +319,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi",
     "output/test-read-dwarf/test18-pr19037-libvtkRenderingLIC-6.1.so.abi",
@@ -293,6 +327,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi",
     "output/test-read-dwarf/test19-pr19023-libtcmalloc_and_profiler.so.abi",
@@ -300,6 +335,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi",
     "output/test-read-dwarf/test20-pr19025-libvtkParallelCore-6.1.so.abi",
@@ -307,6 +343,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test21-pr19092.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test21-pr19092.so.abi",
     "output/test-read-dwarf/test21-pr19092.so.abi",
@@ -314,6 +351,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi",
     "output/test-read-dwarf/test22-pr19097-libstdc++.so.6.0.17.so.abi",
@@ -321,6 +359,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/libtest23.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/libtest23.so.abi",
     "output/test-read-dwarf/libtest23.so.abi",
@@ -328,6 +367,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/libtest24-drop-fns.so",
     "data/test-read-dwarf/test24-drop-fns-0.suppr",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/libtest24-drop-fns.so.abi",
     "output/test-read-dwarf/libtest24-drop-fns.so.abi",
@@ -335,6 +375,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/libtest24-drop-fns.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/libtest24-drop-fns-2.so.abi",
     "output/test-read-dwarf/libtest24-drop-fns-2.so.abi",
@@ -342,6 +383,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/PR22015-libboost_iostreams.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR22015-libboost_iostreams.so.abi",
     "output/test-read-dwarf/PR22015-libboost_iostreams.so.abi",
@@ -349,6 +391,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/PR22122-libftdc.so",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR22122-libftdc.so.abi",
     "output/test-read-dwarf/PR22122-libftdc.so.abi",
@@ -356,6 +399,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/PR24378-fn-is-not-scope.o",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR24378-fn-is-not-scope.abi",
     "output/test-read-dwarf/PR24378-fn-is-not-scope.abi",
@@ -364,6 +408,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/PR25007-sdhci.ko",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR25007-sdhci.ko.abi",
     "output/test-read-dwarf/PR25007-sdhci.ko.abi",
@@ -373,6 +418,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/PR25042-libgdbm-clang-dwarf5.so.6.0.0",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR25042-libgdbm-clang-dwarf5.so.6.0.0.abi",
     "output/test-read-dwarf/PR25042-libgdbm-clang-dwarf5.so.6.0.0.abi",
@@ -381,6 +427,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test25-bogus-binary.elf",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     NULL,
     NULL,
@@ -388,6 +435,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test26-bogus-binary.elf",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     NULL,
     NULL,
@@ -395,6 +443,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test27-bogus-binary.elf",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     NULL,
     NULL,
@@ -402,6 +451,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/PR26261/PR26261-exe",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/PR26261/PR26261-exe.abi",
     "output/test-read-dwarf/PR26261/PR26261-exe.abi",
@@ -409,6 +459,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test-PR26568-1.o",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-PR26568-1.o.abi",
     "output/test-read-dwarf/test-PR26568-1.o.abi",
@@ -416,6 +467,7 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test-PR26568-2.o",
     "",
+    "",
     SEQUENCE_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-PR26568-2.o.abi",
     "output/test-read-dwarf/test-PR26568-2.o.abi",
@@ -423,12 +475,21 @@  InOutSpec in_out_specs[] =
   {
     "data/test-read-dwarf/test-libandroid.so",
     "",
+    "",
     HASH_TYPE_ID_STYLE,
     "data/test-read-dwarf/test-libandroid.so.abi",
     "output/test-read-dwarf/test-libandroid.so.abi",
   },
+  {
+    "data/test-read-dwarf/PR27700/test-PR27700.o",
+    "",
+    "data/test-read-dwarf/PR27700/pub-incdir",
+    HASH_TYPE_ID_STYLE,
+    "data/test-read-dwarf/PR27700/test-PR27700.abi",
+    "output/test-read-dwarf/PR27700/test-PR27700.abi",
+  },
   // This should be the last entry.
-  {NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
+  {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
 };
 
 using abigail::suppr::suppression_sptr;
@@ -448,6 +509,33 @@  set_suppressions(read_context& read_ctxt, const string& path)
   add_read_context_suppressions(read_ctxt, supprs);
 }
 
+/// Define what headers contain public types definitions.
+///
+/// This automatically generates suppression specifications from the
+/// set of header files present under a given directory.  Those
+/// specifications actually suppress types that are *not* defined in
+/// the headers found at a given directory.
+///
+/// @param read_ctxt the context used to read the ELF binary.
+///
+/// @param path the path to a directory where header files are to be
+/// found.
+static void
+set_suppressions_from_headers(read_context& read_ctxt, const string& path)
+{
+  vector<string> files;
+  suppression_sptr suppr =
+    abigail::tools_utils::gen_suppr_spec_from_headers(path, files);
+
+  if (suppr)
+    {
+      suppr->set_drops_artifact_from_ir(true);
+      suppressions_type supprs;
+      supprs.push_back(suppr);
+      add_read_context_suppressions(read_ctxt, supprs);
+    }
+}
+
 /// The task that peforms the tests.
 struct test_task : public abigail::workers::task
 {
@@ -477,7 +565,8 @@  struct test_task : public abigail::workers::task
   virtual void
   perform()
   {
-    string in_elf_path, in_abi_path, in_suppr_spec_path, out_abi_path;
+    string in_elf_path, in_abi_path, in_suppr_spec_path, in_public_headers_path,
+      out_abi_path;
     abigail::ir::environment_sptr env;
 
     in_elf_path = in_elf_base + spec.in_elf_path;
@@ -486,6 +575,11 @@  struct test_task : public abigail::workers::task
     else
       in_suppr_spec_path.clear();
 
+    if (spec.in_public_headers_path)
+      in_public_headers_path = spec.in_public_headers_path;
+    if (!in_public_headers_path.empty())
+      in_public_headers_path = in_elf_base + spec.in_public_headers_path;
+
     env.reset(new abigail::ir::environment);
     abigail::dwarf_reader::status status =
     abigail::dwarf_reader::STATUS_UNKNOWN;
@@ -498,6 +592,9 @@  struct test_task : public abigail::workers::task
     if (!in_suppr_spec_path.empty())
       set_suppressions(*ctxt, in_suppr_spec_path);
 
+    if (!in_public_headers_path.empty())
+      set_suppressions_from_headers(*ctxt, in_public_headers_path);
+
     abigail::corpus_sptr corp = read_corpus_from_elf(*ctxt, status);
     // if there is no output and no input, assume that we do not care about the
     // actual read result, just that it succeeded.
@@ -541,7 +638,11 @@  struct test_task : public abigail::workers::task
     of.close();
 
     string abidw = string(get_build_dir()) + "/tools/abidw";
-    string cmd = abidw + " --abidiff " + in_elf_path;
+    string drop_private_types;
+    if (!in_public_headers_path.empty())
+      drop_private_types += "--headers-dir " + in_public_headers_path +
+	" --drop-private-types";
+    string cmd = abidw + " " + drop_private_types + " --abidiff " + in_elf_path;
     if (system(cmd.c_str()))
       {
 	error_message = string("ABIs differ:\n")