[applied] Bug 28584 - Don't drop global variables that lack DW_AT_external

Message ID 87y25p5q8j.fsf@redhat.com
State New
Headers
Series [applied] Bug 28584 - Don't drop global variables that lack DW_AT_external |

Commit Message

Dodji Seketeli Nov. 15, 2021, 4:38 p.m. UTC
  Hello,

Clang doesn't always emit the DW_AT_external property that flags a
decl as being external.  In those cases, the DWARF reader just drops
the variable on the floor as it considers it as being "non-exported".

This patch considers that a variable decl that is at named namespace
scope is essentially "external".  Then if the variable has an ELF
symbol associated to it, then an IR node will be created for it.

The other changes are just needed adaptations due to the core change.

	* src/abg-dwarf-reader.cc (die_is_effectively_public_decl): Define
	new static function.
	(die_flag_attribute, die_is_public_decl): Adjust const-ness.
	(build_ir_node_from_die): When building an IR for a variable,
	consider the variable as being external if the variable is at
	namespace scope, even if its DIE doesn't have the DW_AT_external
	attribute.
	* tests/data/test-read-dwarf/PR28584/PR28584-smv.cc: New source
	code for a new clang-built binary.
	* tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o: New
	clang-built input binary for testing purposes.
	* tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi: The
	reference output abixml.
	* tests/data/Makefile.am: Add the new test material above to
	source distribution.
	* tests/test-read-dwarf.cc (in_out_specs): Add the new test input
	to this test harness.
	* tests/data/test-read-dwarf/PR22122-libftdc.so.abi: Adjust.
	* tests/data/test-read-dwarf/test-libandroid.so.abi: Likewise.

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

---
 src/abg-dwarf-reader.cc                       |  71 +++++++++--
 tests/data/Makefile.am                        |   3 +
 .../test-read-dwarf/PR22122-libftdc.so.abi    | 115 ++++++++++--------
 .../test-read-dwarf/PR28584/PR28584-smv.cc    |   4 +
 .../PR28584/PR28584-smv.clang.o               | Bin 0 -> 1824 bytes
 .../PR28584/PR28584-smv.clang.o.abi           |  15 +++
 .../test-read-dwarf/test-libandroid.so.abi    |   8 +-
 tests/test-read-dwarf.cc                      |   8 ++
 8 files changed, 158 insertions(+), 66 deletions(-)
 create mode 100644 tests/data/test-read-dwarf/PR28584/PR28584-smv.cc
 create mode 100644 tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o
 create mode 100644 tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi
  

Patch

diff --git a/src/abg-dwarf-reader.cc b/src/abg-dwarf-reader.cc
index 6c7c1dae..ec92f3f8 100644
--- a/src/abg-dwarf-reader.cc
+++ b/src/abg-dwarf-reader.cc
@@ -6445,15 +6445,15 @@  form_is_DW_FORM_line_strp(unsigned form)
 /// @return true if the DIE has a flag attribute named @p attr_name,
 /// false otherwise.
 static bool
-die_flag_attribute(Dwarf_Die* die,
+die_flag_attribute(const Dwarf_Die* die,
 		   unsigned attr_name,
 		   bool& flag,
 		   bool recursively = true)
 {
   Dwarf_Attribute attr;
   if (recursively
-      ? !dwarf_attr_integrate(die, attr_name, &attr)
-      : !dwarf_attr(die, attr_name, &attr))
+      ? !dwarf_attr_integrate(const_cast<Dwarf_Die*>(die), attr_name, &attr)
+      : !dwarf_attr(const_cast<Dwarf_Die*>(die), attr_name, &attr))
     return false;
 
   bool f = false;
@@ -6697,13 +6697,56 @@  die_access_specifier(Dwarf_Die * die, access_specifier& access)
 /// @return true if a DW_AT_external attribute is present and its
 /// value is set to the true; return false otherwise.
 static bool
-die_is_public_decl(Dwarf_Die* die)
+die_is_public_decl(const Dwarf_Die* die)
 {
   bool is_public = false;
   die_flag_attribute(die, DW_AT_external, is_public);
   return is_public;
 }
 
+/// Test if a DIE is effectively public.
+///
+/// This is meant to return true when either the DIE is public or when
+/// it's a variable DIE that is at (global) namespace level.
+///
+/// @return true iff either the DIE is public or is a variable DIE
+/// that is at (global) namespace level.
+static bool
+die_is_effectively_public_decl(const read_context& ctxt,
+			       const Dwarf_Die* die)
+{
+  if (die_is_public_decl(die))
+    return true;
+
+  unsigned tag = dwarf_tag(const_cast<Dwarf_Die*>(die));
+  if (tag == DW_TAG_variable || tag == DW_TAG_member)
+    {
+      // The DIE is a variable.
+      Dwarf_Die parent_die;
+      size_t where_offset = 0;
+      if (!get_parent_die(ctxt, die, parent_die, where_offset))
+	return false;
+
+      tag = dwarf_tag(&parent_die);
+      if (tag == DW_TAG_compile_unit
+	  || tag == DW_TAG_partial_unit
+	  || tag == DW_TAG_type_unit)
+	// The DIE is at global scope.
+	return true;
+
+      if (tag == DW_TAG_namespace)
+	{
+	  string name = die_name(&parent_die);
+	  if (name.empty())
+	    // The DIE at unnamed namespace scope, so it's not public.
+	    return false;
+	  // The DIE is at namespace scope.
+	  return true;
+	}
+    }
+  return false;
+}
+
 /// Test whether a given DIE represents a declaration-only DIE.
 ///
 /// That is, if the DIE has the DW_AT_declaration flag set.
@@ -15065,9 +15108,11 @@  build_ir_node_from_die(read_context&	ctxt,
 	    || (var_is_cloned = die_die_attribute(die, DW_AT_abstract_origin,
 						  spec_die, false)))
 	  {
-	    scope_decl_sptr spec_scope = get_scope_for_die(ctxt, &spec_die,
-							   called_from_public_decl,
-							   where_offset);
+	    scope_decl_sptr spec_scope =
+	      get_scope_for_die(ctxt, &spec_die,
+				/*called_from_public_decl=*/
+				die_is_effectively_public_decl(ctxt, die),
+				where_offset);
 	    if (spec_scope)
 	      {
 		decl_base_sptr d =
@@ -15377,8 +15422,18 @@  build_ir_node_from_die(read_context&	ctxt,
                                     true);
     }
 
+  // Normaly, a decl that is meant to be external has a DW_AT_external
+  // set.  But then some compilers fail to always emit that flag.  For
+  // instance, for static data members, some compilers won't emit the
+  // DW_AT_external.  In that case, we assume that if the variable is
+  // at global or named namespace scope, then we can assume it's
+  // external.  If the variable doesn't have any ELF symbol associated
+  // to it, it'll be dropped on the floor anyway.  Those variable
+  // decls are considered as being "effectively public".
+  bool consider_as_called_from_public_decl =
+    called_from_public_decl || die_is_effectively_public_decl(ctxt, die);
   scope_decl_sptr scope = get_scope_for_die(ctxt, die,
-					    called_from_public_decl,
+					    consider_as_called_from_public_decl,
 					    where_offset);
   return build_ir_node_from_die(ctxt, die, scope.get(),
 				called_from_public_decl,
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index bc2577da..b83f05be 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -580,6 +580,9 @@  test-read-dwarf/PR27700/test-PR27700.c  \
 test-read-dwarf/PR27700/test-PR27700.o  \
 test-read-dwarf/test-libaaudio.so       \
 test-read-dwarf/test-libaaudio.so.abi   \
+test-read-dwarf/PR28584/PR28584-smv.cc  \
+test-read-dwarf/PR28584/PR28584-smv.clang.o \
+test-read-dwarf/PR28584/PR28584-smv.clang.o.abi \
 \
 test-annotate/test0.abi			\
 test-annotate/test1.abi			\
diff --git a/tests/data/test-read-dwarf/PR22122-libftdc.so.abi b/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
index 085ff0f9..16e867ef 100644
--- a/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
+++ b/tests/data/test-read-dwarf/PR22122-libftdc.so.abi
@@ -7797,34 +7797,36 @@ 
       <subrange length='8' type-id='type-id-4' id='type-id-348'/>
     </array-type-def>
     <type-decl name='signed char' size-in-bits='8' id='type-id-357'/>
-    <qualified-type-def type-id='type-id-209' const='yes' id='type-id-358'/>
-    <reference-type-def kind='lvalue' type-id='type-id-358' size-in-bits='64' id='type-id-359'/>
-    <reference-type-def kind='lvalue' type-id='type-id-355' size-in-bits='64' id='type-id-360'/>
-    <reference-type-def kind='lvalue' type-id='type-id-356' size-in-bits='64' id='type-id-361'/>
-    <qualified-type-def type-id='type-id-19' const='yes' id='type-id-362'/>
-    <reference-type-def kind='lvalue' type-id='type-id-362' size-in-bits='64' id='type-id-363'/>
-    <reference-type-def kind='lvalue' type-id='type-id-16' size-in-bits='64' id='type-id-364'/>
-    <reference-type-def kind='rvalue' type-id='type-id-19' size-in-bits='64' id='type-id-365'/>
-    <pointer-type-def type-id='type-id-19' size-in-bits='64' id='type-id-366'/>
-    <pointer-type-def type-id='type-id-20' size-in-bits='64' id='type-id-367'/>
-    <pointer-type-def type-id='type-id-357' size-in-bits='64' id='type-id-368'/>
-    <reference-type-def kind='rvalue' type-id='type-id-23' size-in-bits='64' id='type-id-369'/>
+    <typedef-decl name='int64_t' type-id='type-id-18' filepath='/usr/include/x86_64-linux-gnu/sys/types.h' line='197' column='1' id='type-id-358'/>
+    <qualified-type-def type-id='type-id-209' const='yes' id='type-id-359'/>
+    <reference-type-def kind='lvalue' type-id='type-id-359' size-in-bits='64' id='type-id-360'/>
+    <reference-type-def kind='lvalue' type-id='type-id-355' size-in-bits='64' id='type-id-361'/>
+    <reference-type-def kind='lvalue' type-id='type-id-356' size-in-bits='64' id='type-id-362'/>
+    <qualified-type-def type-id='type-id-358' const='yes' id='type-id-363'/>
+    <qualified-type-def type-id='type-id-19' const='yes' id='type-id-364'/>
+    <reference-type-def kind='lvalue' type-id='type-id-364' size-in-bits='64' id='type-id-365'/>
+    <reference-type-def kind='lvalue' type-id='type-id-16' size-in-bits='64' id='type-id-366'/>
+    <reference-type-def kind='rvalue' type-id='type-id-19' size-in-bits='64' id='type-id-367'/>
+    <pointer-type-def type-id='type-id-19' size-in-bits='64' id='type-id-368'/>
+    <pointer-type-def type-id='type-id-20' size-in-bits='64' id='type-id-369'/>
+    <pointer-type-def type-id='type-id-357' size-in-bits='64' id='type-id-370'/>
+    <reference-type-def kind='rvalue' type-id='type-id-23' size-in-bits='64' id='type-id-371'/>
     <namespace-decl name='std'>
       <class-decl name='__anonymous_struct__' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-type access='private'>
-          <typedef-decl name='const_reference' type-id='type-id-371' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h' line='230' column='1' id='type-id-370'/>
+          <typedef-decl name='const_reference' type-id='type-id-373' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h' line='230' column='1' id='type-id-372'/>
         </member-type>
         <member-function access='public'>
           <function-decl name='emplace_back&lt;unsigned int&gt;' mangled-name='_ZNSt6vectorImSaImEE12emplace_backIJjEEEvDpOT_' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h' line='936' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
-            <parameter type-id='type-id-369'/>
+            <parameter type-id='type-id-371'/>
             <return type-id='type-id-126'/>
           </function-decl>
         </member-function>
         <member-function access='public'>
           <function-decl name='emplace_back&lt;long long&gt;' mangled-name='_ZNSt6vectorImSaImEE12emplace_backIJxEEEvDpOT_' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h' line='936' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
-            <parameter type-id='type-id-365'/>
+            <parameter type-id='type-id-367'/>
             <return type-id='type-id-126'/>
           </function-decl>
         </member-function>
@@ -7839,13 +7841,13 @@ 
           <function-decl name='operator[]' mangled-name='_ZNKSt6vectorImSaImEEixEm' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h' line='794' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-70' is-artificial='yes'/>
             <parameter type-id='type-id-28'/>
-            <return type-id='type-id-370'/>
+            <return type-id='type-id-372'/>
           </function-decl>
         </member-function>
         <member-function access='protected'>
           <function-decl name='_M_emplace_back_aux&lt;long long&gt;' mangled-name='_ZNSt6vectorImSaImEE19_M_emplace_back_auxIJxEEEvDpOT_' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h' line='1417' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZNSt6vectorImSaImEE19_M_emplace_back_auxIJxEEEvDpOT_'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
-            <parameter type-id='type-id-365'/>
+            <parameter type-id='type-id-367'/>
             <return type-id='type-id-126'/>
           </function-decl>
         </member-function>
@@ -7859,7 +7861,7 @@ 
         <member-function access='protected'>
           <function-decl name='_M_emplace_back_aux&lt;unsigned int&gt;' mangled-name='_ZNSt6vectorImSaImEE19_M_emplace_back_auxIJjEEEvDpOT_' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/stl_vector.h' line='1417' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZNSt6vectorImSaImEE19_M_emplace_back_auxIJjEEEvDpOT_'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
-            <parameter type-id='type-id-369'/>
+            <parameter type-id='type-id-371'/>
             <return type-id='type-id-126'/>
           </function-decl>
         </member-function>
@@ -7877,7 +7879,7 @@ 
           <function-decl name='construct&lt;unsigned long, long long&gt;' mangled-name='_ZNSt16allocator_traitsISaImEE9constructImJxEEEvRS0_PT_DpOT0_' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/alloc_traits.h' line='529' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-112'/>
             <parameter type-id='type-id-216'/>
-            <parameter type-id='type-id-365'/>
+            <parameter type-id='type-id-367'/>
             <return type-id='type-id-126'/>
           </function-decl>
         </member-function>
@@ -7885,7 +7887,7 @@ 
           <function-decl name='construct&lt;unsigned long, unsigned int&gt;' mangled-name='_ZNSt16allocator_traitsISaImEE9constructImJjEEEvRS0_PT_DpOT0_' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/bits/alloc_traits.h' line='529' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-112'/>
             <parameter type-id='type-id-216'/>
-            <parameter type-id='type-id-369'/>
+            <parameter type-id='type-id-371'/>
             <return type-id='type-id-126'/>
           </function-decl>
         </member-function>
@@ -7909,7 +7911,7 @@ 
     <namespace-decl name='__gnu_cxx'>
       <class-decl name='__anonymous_struct__' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-type access='public'>
-          <typedef-decl name='const_reference' type-id='type-id-359' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/ext/alloc_traits.h' line='110' column='1' id='type-id-371'/>
+          <typedef-decl name='const_reference' type-id='type-id-360' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/ext/alloc_traits.h' line='110' column='1' id='type-id-373'/>
         </member-type>
         <member-type access='public'>
           <class-decl name='__anonymous_struct__' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
@@ -7930,7 +7932,7 @@ 
           <function-decl name='construct&lt;unsigned long, long long&gt;' mangled-name='_ZN9__gnu_cxx13new_allocatorImE9constructImJxEEEvPT_DpOT0_' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/ext/new_allocator.h' line='119' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
             <parameter type-id='type-id-216'/>
-            <parameter type-id='type-id-365'/>
+            <parameter type-id='type-id-367'/>
             <return type-id='type-id-126'/>
           </function-decl>
         </member-function>
@@ -7938,7 +7940,7 @@ 
           <function-decl name='construct&lt;unsigned long, unsigned int&gt;' mangled-name='_ZN9__gnu_cxx13new_allocatorImE9constructImJjEEEvPT_DpOT0_' filepath='/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/ext/new_allocator.h' line='119' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
             <parameter type-id='type-id-216'/>
-            <parameter type-id='type-id-369'/>
+            <parameter type-id='type-id-371'/>
             <return type-id='type-id-126'/>
           </function-decl>
         </member-function>
@@ -7950,21 +7952,21 @@ 
           <member-function access='public'>
             <function-decl name='operator&lt;&lt;&lt;char [8]&gt;' mangled-name='_ZN10mongoutils3str6streamlsIA8_cEERS1_RKT_' filepath='src/mongo/util/mongoutils/str.h' line='61' column='1' visibility='default' binding='global' size-in-bits='64'>
               <parameter type-id='type-id-63' is-artificial='yes'/>
-              <parameter type-id='type-id-361'/>
+              <parameter type-id='type-id-362'/>
               <return type-id='type-id-61'/>
             </function-decl>
           </member-function>
           <member-function access='public'>
             <function-decl name='operator&lt;&lt;&lt;long long&gt;' mangled-name='_ZN10mongoutils3str6streamlsIxEERS1_RKT_' filepath='src/mongo/util/mongoutils/str.h' line='61' column='1' visibility='default' binding='global' size-in-bits='64'>
               <parameter type-id='type-id-63' is-artificial='yes'/>
-              <parameter type-id='type-id-363'/>
+              <parameter type-id='type-id-365'/>
               <return type-id='type-id-61'/>
             </function-decl>
           </member-function>
           <member-function access='public'>
             <function-decl name='operator&lt;&lt;&lt;char [7]&gt;' mangled-name='_ZN10mongoutils3str6streamlsIA7_cEERS1_RKT_' filepath='src/mongo/util/mongoutils/str.h' line='61' column='1' visibility='default' binding='global' size-in-bits='64'>
               <parameter type-id='type-id-63' is-artificial='yes'/>
-              <parameter type-id='type-id-360'/>
+              <parameter type-id='type-id-361'/>
               <return type-id='type-id-61'/>
             </function-decl>
           </member-function>
@@ -7972,7 +7974,11 @@ 
       </namespace-decl>
     </namespace-decl>
     <namespace-decl name='mongo'>
-      <class-decl name='__anonymous_struct__' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
+      <class-decl name='__anonymous_struct__' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+        <data-member access='public' static='yes'>
+          <var-decl name='kPeriodMillisDefault' type-id='type-id-363' mangled-name='_ZN5mongo10FTDCConfig20kPeriodMillisDefaultE' visibility='default' filepath='src/mongo/db/ftdc/config.h' line='88' column='1' elf-symbol-id='_ZN5mongo10FTDCConfig20kPeriodMillisDefaultE'/>
+        </data-member>
+      </class-decl>
       <class-decl name='__anonymous_struct__1' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
       <class-decl name='__anonymous_struct__2' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
       <class-decl name='__anonymous_struct__3' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
@@ -7981,12 +7987,13 @@ 
       <class-decl name='__anonymous_struct__6' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
       <class-decl name='__anonymous_struct__7' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
       <class-decl name='__anonymous_struct__8' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
-      <class-decl name='__anonymous_struct__9' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__9' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
+      <class-decl name='__anonymous_struct__10' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-type access='private'>
           <class-decl name='__anonymous_struct__' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
         </member-type>
       </class-decl>
-      <class-decl name='__anonymous_struct__10' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__11' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-function access='public'>
           <function-decl name='BSONObjIterator' mangled-name='_ZN5mongo15BSONObjIteratorC2ERKNS_7BSONObjE' filepath='src/mongo/bson/bsonobj.h' line='597' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
@@ -8001,7 +8008,7 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__11' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__12' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-type access='public'>
           <class-decl name='__anonymous_struct__' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
         </member-type>
@@ -8012,7 +8019,7 @@ 
           <class-decl name='__anonymous_struct__2' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
             <member-function access='public' static='yes'>
               <function-decl name='unsafeLoad' mangled-name='_ZN5mongo8DataType7HandlerIxvE10unsafeLoadEPxPKcPm' filepath='src/mongo/base/data_type.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64'>
-                <parameter type-id='type-id-366'/>
+                <parameter type-id='type-id-368'/>
                 <parameter type-id='type-id-72'/>
                 <parameter type-id='type-id-194'/>
                 <return type-id='type-id-126'/>
@@ -8020,7 +8027,7 @@ 
             </member-function>
             <member-function access='public' static='yes'>
               <function-decl name='unsafeStore' mangled-name='_ZN5mongo8DataType7HandlerIxvE11unsafeStoreERKxPcPm' filepath='src/mongo/base/data_type.h' line='87' column='1' visibility='default' binding='global' size-in-bits='64'>
-                <parameter type-id='type-id-363'/>
+                <parameter type-id='type-id-365'/>
                 <parameter type-id='type-id-64'/>
                 <parameter type-id='type-id-194'/>
                 <return type-id='type-id-126'/>
@@ -8035,7 +8042,7 @@ 
           <class-decl name='__anonymous_struct__4' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
             <member-function access='public' static='yes'>
               <function-decl name='unsafeLoad' mangled-name='_ZN5mongo8DataType7HandlerIyvE10unsafeLoadEPyPKcPm' filepath='src/mongo/base/data_type.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64'>
-                <parameter type-id='type-id-367'/>
+                <parameter type-id='type-id-369'/>
                 <parameter type-id='type-id-72'/>
                 <parameter type-id='type-id-194'/>
                 <return type-id='type-id-126'/>
@@ -8050,7 +8057,7 @@ 
           <class-decl name='__anonymous_struct__6' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
             <member-function access='public' static='yes'>
               <function-decl name='unsafeLoad' mangled-name='_ZN5mongo8DataType7HandlerIavE10unsafeLoadEPaPKcPm' filepath='src/mongo/base/data_type.h' line='59' column='1' visibility='default' binding='global' size-in-bits='64'>
-                <parameter type-id='type-id-368'/>
+                <parameter type-id='type-id-370'/>
                 <parameter type-id='type-id-72'/>
                 <parameter type-id='type-id-194'/>
                 <return type-id='type-id-126'/>
@@ -8066,7 +8073,7 @@ 
         </member-type>
         <member-function access='public' static='yes'>
           <function-decl name='unsafeLoad&lt;long long&gt;' mangled-name='_ZN5mongo8DataType10unsafeLoadIxEEvPT_PKcPm' filepath='src/mongo/base/data_type.h' line='150' column='1' visibility='default' binding='global' size-in-bits='64'>
-            <parameter type-id='type-id-366'/>
+            <parameter type-id='type-id-368'/>
             <parameter type-id='type-id-72'/>
             <parameter type-id='type-id-194'/>
             <return type-id='type-id-126'/>
@@ -8082,7 +8089,7 @@ 
         </member-function>
         <member-function access='public' static='yes'>
           <function-decl name='unsafeLoad&lt;unsigned long long&gt;' mangled-name='_ZN5mongo8DataType10unsafeLoadIyEEvPT_PKcPm' filepath='src/mongo/base/data_type.h' line='150' column='1' visibility='default' binding='global' size-in-bits='64'>
-            <parameter type-id='type-id-367'/>
+            <parameter type-id='type-id-369'/>
             <parameter type-id='type-id-72'/>
             <parameter type-id='type-id-194'/>
             <return type-id='type-id-126'/>
@@ -8098,7 +8105,7 @@ 
         </member-function>
         <member-function access='public' static='yes'>
           <function-decl name='unsafeLoad&lt;signed char&gt;' mangled-name='_ZN5mongo8DataType10unsafeLoadIaEEvPT_PKcPm' filepath='src/mongo/base/data_type.h' line='150' column='1' visibility='default' binding='global' size-in-bits='64'>
-            <parameter type-id='type-id-368'/>
+            <parameter type-id='type-id-370'/>
             <parameter type-id='type-id-72'/>
             <parameter type-id='type-id-194'/>
             <return type-id='type-id-126'/>
@@ -8106,7 +8113,7 @@ 
         </member-function>
         <member-function access='public' static='yes'>
           <function-decl name='unsafeStore&lt;long long&gt;' mangled-name='_ZN5mongo8DataType11unsafeStoreIxEEvRKT_PcPm' filepath='src/mongo/base/data_type.h' line='155' column='1' visibility='default' binding='global' size-in-bits='64'>
-            <parameter type-id='type-id-363'/>
+            <parameter type-id='type-id-365'/>
             <parameter type-id='type-id-64'/>
             <parameter type-id='type-id-194'/>
             <return type-id='type-id-126'/>
@@ -8121,7 +8128,7 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__12' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__13' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-function access='public'>
           <function-decl name='read&lt;mongo::LittleEndian&lt;long long&gt; &gt;' mangled-name='_ZNK5mongo13ConstDataView4readINS_12LittleEndianIxEEEERKS0_PT_m' filepath='src/mongo/base/data_view.h' line='50' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-70' is-artificial='yes'/>
@@ -8155,7 +8162,7 @@ 
         <member-function access='public'>
           <function-decl name='read&lt;signed char&gt;' mangled-name='_ZNK5mongo13ConstDataView4readIaEERKS0_PT_m' filepath='src/mongo/base/data_view.h' line='50' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-70' is-artificial='yes'/>
-            <parameter type-id='type-id-368'/>
+            <parameter type-id='type-id-370'/>
             <parameter type-id='type-id-54'/>
             <return type-id='type-id-69'/>
           </function-decl>
@@ -8168,7 +8175,7 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__13' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__14' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-function access='public'>
           <function-decl name='BSONElement' mangled-name='_ZN5mongo11BSONElementC2Ev' filepath='src/mongo/bson/bsonelement.h' line='560' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
@@ -8257,7 +8264,7 @@ 
         <member-function access='public'>
           <function-decl name='binData' mangled-name='_ZNK5mongo11BSONElement7binDataERi' filepath='src/mongo/bson/bsonelement.h' line='446' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-70' is-artificial='yes'/>
-            <parameter type-id='type-id-364'/>
+            <parameter type-id='type-id-366'/>
             <return type-id='type-id-72'/>
           </function-decl>
         </member-function>
@@ -8305,20 +8312,20 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__14' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
-      <class-decl name='__anonymous_struct__15' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__15' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
+      <class-decl name='__anonymous_struct__16' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-type access='private'>
           <class-decl name='__anonymous_struct__' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
         </member-type>
       </class-decl>
-      <class-decl name='__anonymous_struct__16' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
       <class-decl name='__anonymous_struct__17' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
-      <class-decl name='__anonymous_struct__18' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__18' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
+      <class-decl name='__anonymous_struct__19' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-type access='private'>
           <class-decl name='__anonymous_struct__' is-struct='yes' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
         </member-type>
       </class-decl>
-      <class-decl name='__anonymous_struct__19' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__20' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-function access='private'>
           <function-decl name='appendNumImpl&lt;int&gt;' mangled-name='_ZN5mongo11_BufBuilderINS_21SharedBufferAllocatorEE13appendNumImplIiEEvT_' filepath='src/mongo/bson/util/builder.h' line='334' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
@@ -8354,9 +8361,9 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__20' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
       <class-decl name='__anonymous_struct__21' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
-      <class-decl name='__anonymous_struct__22' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__22' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
+      <class-decl name='__anonymous_struct__23' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-function access='public'>
           <function-decl name='append' mangled-name='_ZN5mongo14BSONObjBuilder6appendENS_10StringDataENS_9TimestampE' filepath='src/mongo/bson/bsonobjbuilder.h' line='437' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
@@ -8431,7 +8438,7 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__23' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__24' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-function access='public'>
           <function-decl name='write&lt;mongo::LittleEndian&lt;long long&gt; &gt;' mangled-name='_ZN5mongo8DataView5writeINS_12LittleEndianIxEEEERS0_RKT_m' filepath='src/mongo/base/data_view.h' line='82' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
@@ -8441,7 +8448,7 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__24' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__25' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-function access='public'>
           <function-decl name='StatusWith' mangled-name='_ZN5mongo10StatusWithINS_12FTDCBSONUtil8FTDCTypeEEC2ES2_' filepath='src/mongo/base/status_with.h' line='92' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
@@ -8450,7 +8457,7 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__25' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__26' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
         <member-function access='public'>
           <function-decl name='operator&lt;&lt;' mangled-name='_ZN5mongo17StringBuilderImplINS_21SharedBufferAllocatorEElsEx' filepath='src/mongo/bson/util/builder.h' line='412' column='1' visibility='default' binding='global' size-in-bits='64'>
             <parameter type-id='type-id-63' is-artificial='yes'/>
@@ -8480,9 +8487,9 @@ 
           </function-decl>
         </member-function>
       </class-decl>
-      <class-decl name='__anonymous_struct__26' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
+      <class-decl name='__anonymous_struct__27' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'>
       </class-decl>
-      <class-decl name='__anonymous_struct__27' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
+      <class-decl name='__anonymous_struct__28' is-anonymous='yes' visibility='default' is-declaration-only='yes' id='type-id-60'/>
       <var-decl name='kFTDCInterimFile' type-id='type-id-320' mangled-name='_ZN5mongo16kFTDCInterimFileE' visibility='default' filepath='src/mongo/db/ftdc/util.cpp' line='51' column='1' elf-symbol-id='_ZN5mongo16kFTDCInterimFileE'/>
       <var-decl name='kFTDCArchiveFile' type-id='type-id-356' mangled-name='_ZN5mongo16kFTDCArchiveFileE' visibility='default' filepath='src/mongo/db/ftdc/util.cpp' line='53' column='1' elf-symbol-id='_ZN5mongo16kFTDCArchiveFileE'/>
       <var-decl name='kFTDCIdField' type-id='type-id-349' mangled-name='_ZN5mongo12kFTDCIdFieldE' visibility='default' filepath='src/mongo/db/ftdc/util.cpp' line='55' column='1' elf-symbol-id='_ZN5mongo12kFTDCIdFieldE'/>
diff --git a/tests/data/test-read-dwarf/PR28584/PR28584-smv.cc b/tests/data/test-read-dwarf/PR28584/PR28584-smv.cc
new file mode 100644
index 00000000..ee43efbf
--- /dev/null
+++ b/tests/data/test-read-dwarf/PR28584/PR28584-smv.cc
@@ -0,0 +1,4 @@ 
+namespace N {
+struct S { static int D; };
+int S::D = 17;
+}
diff --git a/tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o b/tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o
new file mode 100644
index 0000000000000000000000000000000000000000..c8a3e22383f983e9489b041d8350ecc178520857
GIT binary patch
literal 1824
zcmbtUOK;Oa5FW=#DVPRA1hgPQky^y7c8w|o1+_V(6i|pN6(qzZ@?$Yp{Xn)8fjCgk
zaDacq&*8!k;LM@SIJ1h`Rs@Na?V0bJ`PQS|+5NE9dsx#nkVAtFm>|gleAg#_r*u0o
zhnX$(wU)NrY&Z1g>GKzx0JVFXjz(XD?RITGLAT!4?ihO0FxHLx20&vD^ycF>fz5>n
z3ji}qNNgAe#$X5EdijIdvW_dIFF!SM^iBL6uM~ue1_d;&R@xr<m^wpbqYho+hEB5R
zMNSedjzpG+X|ibBrfsgStle~nVdUG8$0O78z#8V66{VgNSwWfxk+5E;v9N+SS?Yzp
zWBFoa<wbz6Q-t0i7O^X`!N|!%$BhK^p$lPBz%C44_U*pCYj?Nc-wIg5V(V~;YS*-1
zO<Y|Zgy`Yw5dMAm7_P(5gQK!^URX7z!!eaAu?{B=@gI?C!DQ{nTg6L_F;bM9#LAOw
ziJzzd&M5pc<8u{W&P~*X3QzOgVtiTQ_ZZ(`OAA=`1moLmWj#a2cNIQo+)?<L@l%CQ
z8H4EycNh#D*UiKT%tE{^!1U5M7T6UW%!>@nOhgXjFnN`NnWTj<xBJgmu(iBBFr#P`
z4;<geb`7L53KJoF!Nh3_#|1Ng7njy|3g?fulQsQ^rS+`to1AKg$<LBtOY2=7rw|ZV
z9>q$aQ}L^Ab<c@^k1y%f8al|)Q1ewxTD2z9b?Jjc?&BC8&NVS`l>RFVo=G8FHTOF5
zYE6{-h!4s5k^`V~LVY?*K^*gAGrkVcUu7)K4|et?!B+lX+Ox=$uj&OST%Dp{XT6dJ
ypX3jefJ(oZqQ5pp{{-WD?|_ciel=D0pXB5{qyC@HarHiu`QJG43ljv7TL0gY(TI}(

literal 0
HcmV?d00001

diff --git a/tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi b/tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi
new file mode 100644
index 00000000..b6ab4779
--- /dev/null
+++ b/tests/data/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi
@@ -0,0 +1,15 @@ 
+<abi-corpus version='2.1' path='data/test-read-dwarf/PR28584/PR28584-smv.clang.o'>
+  <elf-variable-symbols>
+    <elf-symbol name='_ZN1N1S1DE' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-variable-symbols>
+  <abi-instr address-size='64' path='smv.cc' comp-dir-path='/usr/local/google/home/gprocida/dev/stg/static_member_variable' language='LANG_C_plus_plus_14'>
+    <type-decl name='int' size-in-bits='32' id='type-id-1'/>
+    <namespace-decl name='N'>
+      <class-decl name='S' size-in-bits='8' is-struct='yes' visibility='default' filepath='/usr/local/google/home/gprocida/dev/stg/static_member_variable/smv.cc' line='2' column='1' id='type-id-2'>
+        <data-member access='public' static='yes'>
+          <var-decl name='D' type-id='type-id-1' mangled-name='_ZN1N1S1DE' visibility='default' filepath='/usr/local/google/home/gprocida/dev/stg/static_member_variable/smv.cc' line='2' column='1' elf-symbol-id='_ZN1N1S1DE'/>
+        </data-member>
+      </class-decl>
+    </namespace-decl>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-read-dwarf/test-libandroid.so.abi b/tests/data/test-read-dwarf/test-libandroid.so.abi
index 66235756..815c82ce 100644
--- a/tests/data/test-read-dwarf/test-libandroid.so.abi
+++ b/tests/data/test-read-dwarf/test-libandroid.so.abi
@@ -19478,10 +19478,10 @@ 
       <class-decl name='IMountService' size-in-bits='96' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IMountService.h' line='32' column='1' id='bf075117'>
         <base-class access='public' layout-offset-in-bits='0' type-id='40b6343a'/>
         <data-member access='public' static='yes'>
-          <var-decl name='descriptor' type-id='a3cec311' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IMountService.h' line='34' column='1'/>
+          <var-decl name='descriptor' type-id='a3cec311' mangled-name='_ZN7android13IMountService10descriptorE' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IMountService.h' line='34' column='1'/>
         </data-member>
         <data-member access='private' static='yes'>
-          <var-decl name='default_impl' type-id='34e3553c' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IMountService.h' line='34' column='1'/>
+          <var-decl name='default_impl' type-id='34e3553c' mangled-name='_ZN7android13IMountService12default_implE' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IMountService.h' line='34' column='1'/>
         </data-member>
         <member-function access='public' constructor='yes'>
           <function-decl name='IMountService' mangled-name='_ZN7android13IMountServiceC2Ev' filepath='frameworks/base/libs/storage/include/storage/IMountService.h' line='34' column='1' visibility='default' binding='global' size-in-bits='32'>
@@ -19754,10 +19754,10 @@ 
       <class-decl name='IObbActionListener' size-in-bits='96' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IObbActionListener.h' line='27' column='1' id='f7c5ae1e'>
         <base-class access='public' layout-offset-in-bits='0' type-id='40b6343a'/>
         <data-member access='public' static='yes'>
-          <var-decl name='descriptor' type-id='a3cec311' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IObbActionListener.h' line='30' column='1'/>
+          <var-decl name='descriptor' type-id='a3cec311' mangled-name='_ZN7android18IObbActionListener10descriptorE' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IObbActionListener.h' line='30' column='1'/>
         </data-member>
         <data-member access='private' static='yes'>
-          <var-decl name='default_impl' type-id='c722890a' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IObbActionListener.h' line='30' column='1'/>
+          <var-decl name='default_impl' type-id='c722890a' mangled-name='_ZN7android18IObbActionListener12default_implE' visibility='default' filepath='frameworks/base/libs/storage/include/storage/IObbActionListener.h' line='30' column='1'/>
         </data-member>
         <member-function access='public' constructor='yes'>
           <function-decl name='IObbActionListener' mangled-name='_ZN7android18IObbActionListenerC2Ev' filepath='frameworks/base/libs/storage/include/storage/IObbActionListener.h' line='30' column='1' visibility='default' binding='global' size-in-bits='32'>
diff --git a/tests/test-read-dwarf.cc b/tests/test-read-dwarf.cc
index 726786a1..585aca5e 100644
--- a/tests/test-read-dwarf.cc
+++ b/tests/test-read-dwarf.cc
@@ -496,6 +496,14 @@  InOutSpec in_out_specs[] =
     "data/test-read-dwarf/test-libaaudio.so.abi",
     "output/test-read-dwarf/test-libaaudio.so.abi",
   },
+  {
+    "data/test-read-dwarf/PR28584/PR28584-smv.clang.o",
+    "",
+    "",
+    SEQUENCE_TYPE_ID_STYLE,
+    "data/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi",
+    "output/test-read-dwarf/PR28584/PR28584-smv.clang.o.abi",
+  },
   // This should be the last entry.
   {NULL, NULL, NULL, SEQUENCE_TYPE_ID_STYLE, NULL, NULL}
 };