[Lldb-commits] [lldb] de2c7ca - Add support for DW_AT_export_symbols for anonymous structs

via lldb-commits lldb-commits at lists.llvm.org
Mon Oct 28 14:28:22 PDT 2019


Author: shafik
Date: 2019-10-28T14:26:54-07:00
New Revision: de2c7cab715e195c9d559d317beb760cf0b95262

URL: https://github.com/llvm/llvm-project/commit/de2c7cab715e195c9d559d317beb760cf0b95262
DIFF: https://github.com/llvm/llvm-project/commit/de2c7cab715e195c9d559d317beb760cf0b95262.diff

LOG: Add support for DW_AT_export_symbols for anonymous structs

Summary:
We add support for DW_AT_export_symbols to detect anonymous struct on top of the heuristics implemented in D66175
This should allow us to differentiate anonymous structs and unnamed structs.
We also fix TestTypeList.py which was incorrectly detecting an unnamed struct as an anonymous struct.

Differential Revision: https://reviews.llvm.org/D68961

Added: 
    lldb/test/Shell/SymbolFile/DWARF/anon_class_w_and_wo_export_symbols.ll
    lldb/test/Shell/SymbolFile/DWARF/clang-ast-from-dwarf-unamed-and-anon-structs.cpp

Modified: 
    lldb/include/lldb/Symbol/ClangASTContext.h
    lldb/packages/Python/lldbsuite/test/python_api/type/TestTypeList.py
    lldb/packages/Python/lldbsuite/test/python_api/type/main.cpp
    lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
    lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
    lldb/source/Symbol/ClangASTContext.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h
index c5d840973ae6..e59e756276c8 100644
--- a/lldb/include/lldb/Symbol/ClangASTContext.h
+++ b/lldb/include/lldb/Symbol/ClangASTContext.h
@@ -261,7 +261,8 @@ class ClangASTContext : public TypeSystem {
   CompilerType CreateRecordType(clang::DeclContext *decl_ctx,
                                 lldb::AccessType access_type, const char *name,
                                 int kind, lldb::LanguageType language,
-                                ClangASTMetadata *metadata = nullptr);
+                                ClangASTMetadata *metadata = nullptr,
+                                bool exports_symbols = false);
 
   class TemplateParameterInfos {
   public:

diff  --git a/lldb/packages/Python/lldbsuite/test/python_api/type/TestTypeList.py b/lldb/packages/Python/lldbsuite/test/python_api/type/TestTypeList.py
index b3b321c6ca8c..75a793a95b29 100644
--- a/lldb/packages/Python/lldbsuite/test/python_api/type/TestTypeList.py
+++ b/lldb/packages/Python/lldbsuite/test/python_api/type/TestTypeList.py
@@ -73,13 +73,17 @@ def test(self):
                         self.assertTrue(enum_member)
                         self.DebugSBType(enum_member.type)
                 elif field.name == "my_type_is_nameless":
-                    self.assertTrue(
+                    self.assertFalse(
                         field.type.IsAnonymousType(),
-                        "my_type_is_nameless has an anonymous type")
+                        "my_type_is_nameless is not an anonymous type")
                 elif field.name == "my_type_is_named":
                     self.assertFalse(
                         field.type.IsAnonymousType(),
                         "my_type_is_named has a named type")
+                elif field.name == None:
+                    self.assertTrue(
+                        field.type.IsAnonymousType(),
+                        "Nameless type is not anonymous")
 
         # Pass an empty string.  LLDB should not crash. :-)
         fuzz_types = target.FindTypes(None)

diff  --git a/lldb/packages/Python/lldbsuite/test/python_api/type/main.cpp b/lldb/packages/Python/lldbsuite/test/python_api/type/main.cpp
index 8f5b93927c7f..b43b617b0f90 100644
--- a/lldb/packages/Python/lldbsuite/test/python_api/type/main.cpp
+++ b/lldb/packages/Python/lldbsuite/test/python_api/type/main.cpp
@@ -15,6 +15,14 @@ class Task {
         TASK_TYPE_1,
         TASK_TYPE_2
     } type;
+    // This struct is anonymous b/c it does not have a name
+    // and it is not unnamed class.
+    // Anonymous classes are a GNU extension.
+    struct {
+      int y;
+    };
+    // This struct is an unnamed class see [class.pre]p1
+    // http://eel.is/c++draft/class#pre-1.sentence-6
     struct {
       int x;
     } my_type_is_nameless;

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 636e6032b877..42e25f727e4b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -347,6 +347,9 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
     case DW_AT_GNU_vector:
       is_vector = form_value.Boolean();
       break;
+    case DW_AT_export_symbols:
+      exports_symbols = form_value.Boolean();
+      break;
     }
   }
 }
@@ -1546,7 +1549,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const DWARFDIE &die,
       clang_type_was_created = true;
       clang_type = m_ast.CreateRecordType(
           decl_ctx, attrs.accessibility, attrs.name.GetCString(), tag_decl_kind,
-          attrs.class_language, &metadata);
+          attrs.class_language, &metadata, attrs.exports_symbols);
     }
   }
 

diff  --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
index 106f9254a449..1f46178108bd 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h
@@ -181,6 +181,7 @@ struct ParsedDWARFTypeAttributes {
   bool is_scoped_enum = false;
   bool is_vector = false;
   bool is_virtual = false;
+  bool exports_symbols = false;
   clang::StorageClass storage = clang::SC_None;
   const char *mangled_name = nullptr;
   lldb_private::ConstString name;

diff  --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp
index 565b15a007da..4a44ee0b1c73 100644
--- a/lldb/source/Symbol/ClangASTContext.cpp
+++ b/lldb/source/Symbol/ClangASTContext.cpp
@@ -1347,11 +1347,9 @@ CompilerType ClangASTContext::GetTypeForDecl(ObjCInterfaceDecl *decl) {
 
 #pragma mark Structure, Unions, Classes
 
-CompilerType ClangASTContext::CreateRecordType(DeclContext *decl_ctx,
-                                               AccessType access_type,
-                                               const char *name, int kind,
-                                               LanguageType language,
-                                               ClangASTMetadata *metadata) {
+CompilerType ClangASTContext::CreateRecordType(
+    DeclContext *decl_ctx, AccessType access_type, const char *name, int kind,
+    LanguageType language, ClangASTMetadata *metadata, bool exports_symbols) {
   ASTContext *ast = getASTContext();
   assert(ast != nullptr);
 
@@ -1402,10 +1400,7 @@ CompilerType ClangASTContext::CreateRecordType(DeclContext *decl_ctx,
     // Anonymous classes is a GNU/MSVC extension that clang supports. It
     // requires the anonymous class be embedded within a class. So the new
     // heuristic verifies this condition.
-    //
-    // FIXME: An unnamed class within a class is also wrongly recognized as an
-    // anonymous struct.
-    if (isa<CXXRecordDecl>(decl_ctx))
+    if (isa<CXXRecordDecl>(decl_ctx) && exports_symbols)
       decl->setAnonymousStructOrUnion(true);
   }
 
@@ -8989,7 +8984,7 @@ void ClangASTContext::DumpFromSymbolFile(Stream &s,
     TypeSP type = type_list.GetTypeAtIndex(i);
 
     if (!symbol_name.empty())
-      if (symbol_name.compare(type->GetName().GetStringRef()) != 0)
+      if (symbol_name != type->GetName().GetStringRef())
         continue;
 
     s << type->GetName().AsCString() << "\n";

diff  --git a/lldb/test/Shell/SymbolFile/DWARF/anon_class_w_and_wo_export_symbols.ll b/lldb/test/Shell/SymbolFile/DWARF/anon_class_w_and_wo_export_symbols.ll
new file mode 100644
index 000000000000..b0a9f2295057
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/anon_class_w_and_wo_export_symbols.ll
@@ -0,0 +1,77 @@
+; This test verifies that we do the right thing with DIFlagExportSymbols which is the new
+; behavioir and without the DIFlagExportSymbols which is the old behavior for the given
+; definitions below.
+;
+;```
+; struct A{
+;   struct {
+;    int x;
+;   };
+;   struct {
+;    int y;
+;   };
+;   struct {
+;    int z;
+;   } unnamed;
+; } a;
+;```
+;
+; RUN: %clang++ -g -c -o %t.o %s
+; RUN: lldb-test symbols -dump-clang-ast %t.o | FileCheck %s
+; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix DWARFDUMP
+
+%struct.A = type { %struct.anon, %struct.anon.0, %struct.anon.1 }
+%struct.anon = type { i32 }
+%struct.anon.0 = type { i32 }
+%struct.anon.1 = type { i32 }
+
+ at a = global %struct.A zeroinitializer, align 4, !dbg !0
+
+!llvm.module.flags = !{!21, !22}
+!llvm.dbg.cu = !{!2}
+!llvm.ident = !{!23}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 11, type: !6, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 10.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None)
+!3 = !DIFile(filename: "anon_old_new.cpp", directory: "/dir")
+!4 = !{}
+!5 = !{!0}
+!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !3, line: 1, size: 96, flags: DIFlagTypePassByValue, elements: !7, identifier: "_ZTS1A")
+; CHECK: struct A definition
+!7 = !{!8, !13, !17}
+!8 = !DIDerivedType(tag: DW_TAG_member, scope: !6, file: !3, line: 2, baseType: !9, size: 32)
+!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !6, file: !3, line: 2, size: 32, flags: DIFlagExportSymbols | DIFlagTypePassByValue, elements: !10, identifier: "_ZTSN1AUt_E")
+; Correctly identify an anonymous class with DIFlagExportSymbols
+; CHECK: struct definition
+; CHECK: DefinitionData is_anonymous pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal
+!10 = !{!11}
+!11 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !9, file: !3, line: 3, baseType: !12, size: 32)
+!12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!13 = !DIDerivedType(tag: DW_TAG_member, scope: !6, file: !3, line: 5, baseType: !14, size: 32, offset: 32)
+!14 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !6, file: !3, line: 5, size: 32, flags: DIFlagTypePassByValue, elements: !15, identifier: "_ZTSN1AUt0_E")
+; Correctly identify an anonymous class without DIFlagExportSymbols
+; This works b/c we have additional checks when we fields to A.
+; CHECK: struct definition
+; CHECK: DefinitionData is_anonymous pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal
+!15 = !{!16}
+!16 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !14, file: !3, line: 6, baseType: !12, size: 32)
+!17 = !DIDerivedType(tag: DW_TAG_member, name: "unnamed", scope: !6, file: !3, line: 10, baseType: !18, size: 32, offset: 64)
+!18 = distinct !DICompositeType(tag: DW_TAG_structure_type, scope: !6, file: !3, line: 8, size: 32, flags: DIFlagTypePassByValue, elements: !19, identifier: "_ZTSN1AUt1_E")
+; Correctly identify an unamed class
+; CHECK: struct definition
+; CHECK: DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal
+!19 = !{!20}
+!20 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !18, file: !3, line: 9, baseType: !12, size: 32)
+!21 = !{i32 2, !"Dwarf Version", i32 4}
+!22 = !{i32 2, !"Debug Info Version", i32 3}
+!23 = !{!"clang version 10.0.0"}
+
+; DWARFDUMP: DW_TAG_structure_type
+; DWARFDUMP: DW_AT_name	("A")
+;
+; DWARFDUMP: DW_TAG_structure_type
+; DWARFDUMP: DW_AT_export_symbols	(true)
+;
+; DWARFDUMP: DW_TAG_structure_type
+; DWARFDUMP-NOT: DW_AT_export_symbols   (true)

diff  --git a/lldb/test/Shell/SymbolFile/DWARF/clang-ast-from-dwarf-unamed-and-anon-structs.cpp b/lldb/test/Shell/SymbolFile/DWARF/clang-ast-from-dwarf-unamed-and-anon-structs.cpp
new file mode 100644
index 000000000000..f1254fe3b1b5
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/clang-ast-from-dwarf-unamed-and-anon-structs.cpp
@@ -0,0 +1,19 @@
+// Test to verify we are corectly generating anonymous flags when parsing
+// anonymous class and unnamed structs from DWARF to the a clang AST node.
+
+// RUN: %clang++ -g -c -o %t.o %s
+// RUN: lldb-test symbols -dump-clang-ast %t.o | FileCheck %s
+
+struct A {
+  struct {
+    int x;
+  };
+  struct {
+    int y;
+  } C;
+} a;
+
+// CHECK: A::(anonymous struct)
+// CHECK: |-DefinitionData is_anonymous pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal
+// CHECK: A::(anonymous struct)
+// CHECK: |-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal


        


More information about the lldb-commits mailing list