mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-11 10:26:44 +00:00
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
This commit is contained in:
parent
85b718f53a
commit
de2c7cab71
@ -261,7 +261,8 @@ public:
|
||||
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:
|
||||
|
@ -73,13 +73,17 @@ class TypeAndTypeListTestCase(TestBase):
|
||||
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)
|
||||
|
@ -15,6 +15,14 @@ public:
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
|
@ -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 }
|
||||
|
||||
@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)
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user