diff options
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr-types.h | 51 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr1.cpp | 11 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr1.ll | 153 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr2.cpp | 7 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr2.ll | 99 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr3.cpp | 7 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr3.ll | 106 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr4.cpp | 8 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr4.ll | 43 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr5.cpp | 7 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr5.ll | 101 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr6.cpp | 7 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr6.ll | 100 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr7.cpp | 5 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/odr7.ll | 62 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/X86/odr-1.test | 423 | ||||
-rw-r--r-- | llvm/tools/dsymutil/DwarfLinker.cpp | 524 | ||||
-rw-r--r-- | llvm/tools/dsymutil/dsymutil.cpp | 6 | ||||
-rw-r--r-- | llvm/tools/dsymutil/dsymutil.h | 1 |
19 files changed, 1680 insertions, 41 deletions
diff --git a/llvm/test/tools/dsymutil/Inputs/odr-types.h b/llvm/test/tools/dsymutil/Inputs/odr-types.h new file mode 100644 index 00000000000..09057dc9683 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr-types.h @@ -0,0 +1,51 @@ +struct S { + int I; + + void incr() __attribute__((always_inline)) { I++; } + void incr(int Add) __attribute__((always_inline)) { I += Add; } + + typedef int SInt; + + struct Nested { + double D; + + template<typename T> void init(T Val) { D = double(Val); } + }; + + Nested D; + +public: + int foo() { return I; } +}; + +typedef S AliasForS; + +namespace N { +class C { + AliasForS S; +}; +} + +namespace N { +namespace N { +class C { + int S; +}; +} +} + +namespace { + class AnonC { + }; +} + +union U { + class C {} C; + struct S {} S; +}; + +inline int func() { + struct CInsideFunc { int i; }; + auto functor = []() { CInsideFunc dummy; return dummy.i; }; + return functor(); +} diff --git a/llvm/test/tools/dsymutil/Inputs/odr1.cpp b/llvm/test/tools/dsymutil/Inputs/odr1.cpp new file mode 100644 index 00000000000..722247b2504 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr1.cpp @@ -0,0 +1,11 @@ +#include "odr-types.h" + +int foo() { + AliasForS s; + N::C nc; + N::N::C nnc; + AnonC ac; + U u; + + return func(); +} diff --git a/llvm/test/tools/dsymutil/Inputs/odr1.ll b/llvm/test/tools/dsymutil/Inputs/odr1.ll new file mode 100644 index 00000000000..818e0effa3e --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr1.ll @@ -0,0 +1,153 @@ +; Generated from odr1.cpp and odr-types.h by running: +; clang -emit-llvm -g -S -std=c++11 odr1.cpp +; ModuleID = 'odr1.cpp' +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +%struct.S = type { i32, %"struct.S::Nested" } +%"struct.S::Nested" = type { double } +%"class.N::C" = type { %struct.S } +%"class.N::N::C" = type { i32 } +%"class.(anonymous namespace)::AnonC" = type { i8 } +%union.U = type { %"class.U::C" } +%"class.U::C" = type { i8 } +%class.anon = type { i8 } +%struct.CInsideFunc = type { i32 } + +; Function Attrs: ssp uwtable +define i32 @_Z3foov() #0 { +entry: + %s = alloca %struct.S, align 8 + %nc = alloca %"class.N::C", align 8 + %nnc = alloca %"class.N::N::C", align 4 + %ac = alloca %"class.(anonymous namespace)::AnonC", align 1 + %u = alloca %union.U, align 1 + call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !59, metadata !60), !dbg !61 + call void @llvm.dbg.declare(metadata %"class.N::C"* %nc, metadata !62, metadata !60), !dbg !63 + call void @llvm.dbg.declare(metadata %"class.N::N::C"* %nnc, metadata !64, metadata !60), !dbg !65 + call void @llvm.dbg.declare(metadata %"class.(anonymous namespace)::AnonC"* %ac, metadata !66, metadata !60), !dbg !69 + call void @llvm.dbg.declare(metadata %union.U* %u, metadata !70, metadata !60), !dbg !71 + %call = call i32 @_Z4funcv(), !dbg !72 + ret i32 %call, !dbg !73 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: inlinehint ssp uwtable +define linkonce_odr i32 @_Z4funcv() #2 { +entry: + %functor = alloca %class.anon, align 1 + call void @llvm.dbg.declare(metadata %class.anon* %functor, metadata !74, metadata !60), !dbg !75 + %call = call i32 @_ZZ4funcvENKUlvE_clEv(%class.anon* %functor), !dbg !76 + ret i32 %call, !dbg !77 +} + +; Function Attrs: inlinehint nounwind ssp uwtable +define linkonce_odr i32 @_ZZ4funcvENKUlvE_clEv(%class.anon* %this) #3 align 2 { +entry: + %this.addr = alloca %class.anon*, align 8 + %dummy = alloca %struct.CInsideFunc, align 4 + store %class.anon* %this, %class.anon** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %class.anon** %this.addr, metadata !78, metadata !60), !dbg !80 + %this1 = load %class.anon*, %class.anon** %this.addr + call void @llvm.dbg.declare(metadata %struct.CInsideFunc* %dummy, metadata !81, metadata !60), !dbg !82 + %i = getelementptr inbounds %struct.CInsideFunc, %struct.CInsideFunc* %dummy, i32 0, i32 0, !dbg !83 + %0 = load i32, i32* %i, align 4, !dbg !83 + ret i32 %0, !dbg !84 +} + +attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { inlinehint ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { inlinehint nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!55, !56, !57} +!llvm.ident = !{!58} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !52) +!1 = !DIFile(filename: "odr1.cpp", directory: "/Inputs") +!2 = !{} +!3 = !{!4, !20, !24, !29, !33, !37, !38, !39, !49} +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S") +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs") +!6 = !{!7, !9, !10, !14, !17} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32) +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64) +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !13, !8} +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false) +!18 = !DISubroutineType(types: !19) +!19 = !{!8, !13} +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE") +!21 = !{!22} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64) +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float) +!24 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: !25, file: !5, line: 24, size: 128, align: 64, elements: !26, identifier: "_ZTSN1N1CE") +!25 = !DINamespace(name: "N", scope: null, file: !5, line: 23) +!26 = !{!27} +!27 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope: !"_ZTSN1N1CE", file: !5, line: 25, baseType: !28, size: 128, align: 64) +!28 = !DIDerivedType(tag: DW_TAG_typedef, name: "AliasForS", file: !5, line: 21, baseType: !"_ZTS1S") +!29 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: !30, file: !5, line: 31, size: 32, align: 32, elements: !31, identifier: "_ZTSN1N1N1CE") +!30 = !DINamespace(name: "N", scope: !25, file: !5, line: 30) +!31 = !{!32} +!32 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope: !"_ZTSN1N1N1CE", file: !5, line: 32, baseType: !8, size: 32, align: 32) +!33 = !DICompositeType(tag: DW_TAG_union_type, name: "U", file: !5, line: 42, size: 8, align: 8, elements: !34, identifier: "_ZTS1U") +!34 = !{!35, !36} +!35 = !DIDerivedType(tag: DW_TAG_member, name: "C", scope: !"_ZTS1U", file: !5, line: 43, baseType: !"_ZTSN1U1CE", size: 8, align: 8) +!36 = !DIDerivedType(tag: DW_TAG_member, name: "S", scope: !"_ZTS1U", file: !5, line: 44, baseType: !"_ZTSN1U1SE", size: 8, align: 8) +!37 = !DICompositeType(tag: DW_TAG_class_type, name: "C", scope: !"_ZTS1U", file: !5, line: 43, size: 8, align: 8, elements: !2, identifier: "_ZTSN1U1CE") +!38 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", scope: !"_ZTS1U", file: !5, line: 44, size: 8, align: 8, elements: !2, identifier: "_ZTSN1U1SE") +!39 = !DICompositeType(tag: DW_TAG_class_type, scope: !40, file: !5, line: 49, size: 8, align: 8, elements: !43, identifier: "_ZTSZ4funcvEUlvE_") +!40 = !DISubprogram(name: "func", linkageName: "_Z4funcv", scope: !5, file: !5, line: 47, type: !41, isLocal: false, isDefinition: true, scopeLine: 47, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z4funcv, variables: !2) +!41 = !DISubroutineType(types: !42) +!42 = !{!8} +!43 = !{!44} +!44 = !DISubprogram(name: "operator()", scope: !"_ZTSZ4funcvEUlvE_", file: !5, line: 49, type: !45, isLocal: false, isDefinition: false, scopeLine: 49, flags: DIFlagPublic | DIFlagPrototyped, isOptimized: false) +!45 = !DISubroutineType(types: !46) +!46 = !{!8, !47} +!47 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !48, size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!48 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !"_ZTSZ4funcvEUlvE_") +!49 = !DICompositeType(tag: DW_TAG_structure_type, name: "CInsideFunc", scope: !40, file: !5, line: 48, size: 32, align: 32, elements: !50, identifier: "_ZTSZ4funcvE11CInsideFunc") +!50 = !{!51} +!51 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !"_ZTSZ4funcvE11CInsideFunc", file: !5, line: 48, baseType: !8, size: 32, align: 32) +!52 = !{!53, !40, !54} +!53 = !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 3, type: !41, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z3foov, variables: !2) +!54 = !DISubprogram(name: "operator()", linkageName: "_ZZ4funcvENKUlvE_clEv", scope: !"_ZTSZ4funcvEUlvE_", file: !5, line: 49, type: !45, isLocal: false, isDefinition: true, scopeLine: 49, flags: DIFlagPrototyped, isOptimized: false, function: i32 (%class.anon*)* @_ZZ4funcvENKUlvE_clEv, declaration: !44, variables: !2) +!55 = !{i32 2, !"Dwarf Version", i32 2} +!56 = !{i32 2, !"Debug Info Version", i32 3} +!57 = !{i32 1, !"PIC Level", i32 2} +!58 = !{!"clang version 3.8.0 (trunk 242534)"} +!59 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !53, file: !1, line: 4, type: !28) +!60 = !DIExpression() +!61 = !DILocation(line: 4, column: 12, scope: !53) +!62 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "nc", scope: !53, file: !1, line: 5, type: !"_ZTSN1N1CE") +!63 = !DILocation(line: 5, column: 7, scope: !53) +!64 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "nnc", scope: !53, file: !1, line: 6, type: !"_ZTSN1N1N1CE") +!65 = !DILocation(line: 6, column: 10, scope: !53) +!66 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "ac", scope: !53, file: !1, line: 7, type: !67) +!67 = !DICompositeType(tag: DW_TAG_class_type, name: "AnonC", scope: !68, file: !5, line: 38, size: 8, align: 8, elements: !2) +!68 = !DINamespace(scope: null, file: !5, line: 37) +!69 = !DILocation(line: 7, column: 8, scope: !53) +!70 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "u", scope: !53, file: !1, line: 8, type: !"_ZTS1U") +!71 = !DILocation(line: 8, column: 4, scope: !53) +!72 = !DILocation(line: 10, column: 9, scope: !53) +!73 = !DILocation(line: 10, column: 2, scope: !53) +!74 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "functor", scope: !40, file: !5, line: 49, type: !"_ZTSZ4funcvEUlvE_") +!75 = !DILocation(line: 49, column: 7, scope: !40) +!76 = !DILocation(line: 50, column: 9, scope: !40) +!77 = !DILocation(line: 50, column: 2, scope: !40) +!78 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !54, type: !79, flags: DIFlagArtificial | DIFlagObjectPointer) +!79 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !48, size: 64, align: 64) +!80 = !DILocation(line: 0, scope: !54) +!81 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "dummy", scope: !54, file: !5, line: 49, type: !"_ZTSZ4funcvE11CInsideFunc") +!82 = !DILocation(line: 49, column: 36, scope: !54) +!83 = !DILocation(line: 49, column: 56, scope: !54) +!84 = !DILocation(line: 49, column: 43, scope: !54) diff --git a/llvm/test/tools/dsymutil/Inputs/odr2.cpp b/llvm/test/tools/dsymutil/Inputs/odr2.cpp new file mode 100644 index 00000000000..4c26fb2d677 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr2.cpp @@ -0,0 +1,7 @@ +#include "odr-types.h" + +int bar() { + S s; + s.incr(); + return s.foo(); +} diff --git a/llvm/test/tools/dsymutil/Inputs/odr2.ll b/llvm/test/tools/dsymutil/Inputs/odr2.ll new file mode 100644 index 00000000000..da66a2d7153 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr2.ll @@ -0,0 +1,99 @@ +; Generated from odr2.cpp and odr-types.h by running: +; clang -emit-llvm -g -S -std=c++11 odr2.cpp +; ModuleID = 'odr2.cpp' +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +%struct.S = type { i32, %"struct.S::Nested" } +%"struct.S::Nested" = type { double } + +; Function Attrs: ssp uwtable +define i32 @_Z3barv() #0 { +entry: + %this.addr.i = alloca %struct.S*, align 8 + %s = alloca %struct.S, align 8 + call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !34, metadata !35), !dbg !36 + store %struct.S* %s, %struct.S** %this.addr.i, align 8, !dbg !37 + %this1.i = load %struct.S*, %struct.S** %this.addr.i, !dbg !37 + %I.i = getelementptr inbounds %struct.S, %struct.S* %this1.i, i32 0, i32 0, !dbg !38 + %0 = load i32, i32* %I.i, align 4, !dbg !40 + %inc.i = add nsw i32 %0, 1, !dbg !40 + store i32 %inc.i, i32* %I.i, align 4, !dbg !40 + %call = call i32 @_ZN1S3fooEv(%struct.S* %s), !dbg !41 + call void @llvm.dbg.declare(metadata %struct.S** %this.addr.i, metadata !42, metadata !35), !dbg !44 + ret i32 %call, !dbg !45 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind ssp uwtable +define linkonce_odr i32 @_ZN1S3fooEv(%struct.S* %this) #2 align 2 { +entry: + %this.addr = alloca %struct.S*, align 8 + store %struct.S* %this, %struct.S** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %struct.S** %this.addr, metadata !46, metadata !35), !dbg !47 + %this1 = load %struct.S*, %struct.S** %this.addr + %I = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32 0, !dbg !48 + %0 = load i32, i32* %I, align 4, !dbg !48 + ret i32 %0, !dbg !49 +} + +attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!30, !31, !32} +!llvm.ident = !{!33} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24) +!1 = !DIFile(filename: "odr2.cpp", directory: "/Inputs") +!2 = !{} +!3 = !{!4, !20} +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S") +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs") +!6 = !{!7, !9, !10, !14, !17} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32) +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64) +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !13, !8} +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false) +!18 = !DISubroutineType(types: !19) +!19 = !{!8, !13} +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE") +!21 = !{!22} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64) +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float) +!24 = !{!25, !28, !29} +!25 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z3barv, variables: !2) +!26 = !DISubroutineType(types: !27) +!27 = !{!8} +!28 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false, declaration: !10, variables: !2) +!29 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false, function: i32 (%struct.S*)* @_ZN1S3fooEv, declaration: !17, variables: !2) +!30 = !{i32 2, !"Dwarf Version", i32 2} +!31 = !{i32 2, !"Debug Info Version", i32 3} +!32 = !{i32 1, !"PIC Level", i32 2} +!33 = !{!"clang version 3.8.0 (trunk 242534)"} +!34 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !25, file: !1, line: 4, type: !"_ZTS1S") +!35 = !DIExpression() +!36 = !DILocation(line: 4, column: 4, scope: !25) +!37 = !DILocation(line: 5, column: 2, scope: !25) +!38 = !DILocation(line: 4, column: 47, scope: !28, inlinedAt: !39) +!39 = distinct !DILocation(line: 5, column: 2, scope: !25) +!40 = !DILocation(line: 4, column: 48, scope: !28, inlinedAt: !39) +!41 = !DILocation(line: 6, column: 9, scope: !25) +!42 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !28, type: !43, flags: DIFlagArtificial | DIFlagObjectPointer) +!43 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64) +!44 = !DILocation(line: 0, scope: !28, inlinedAt: !39) +!45 = !DILocation(line: 6, column: 2, scope: !25) +!46 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !29, type: !43, flags: DIFlagArtificial | DIFlagObjectPointer) +!47 = !DILocation(line: 0, scope: !29) +!48 = !DILocation(line: 18, column: 21, scope: !29) +!49 = !DILocation(line: 18, column: 14, scope: !29) diff --git a/llvm/test/tools/dsymutil/Inputs/odr3.cpp b/llvm/test/tools/dsymutil/Inputs/odr3.cpp new file mode 100644 index 00000000000..1200c670a48 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr3.cpp @@ -0,0 +1,7 @@ +#include "odr-types.h" + +int bar() { + S s; + s.incr(42); + return s.foo(); +} diff --git a/llvm/test/tools/dsymutil/Inputs/odr3.ll b/llvm/test/tools/dsymutil/Inputs/odr3.ll new file mode 100644 index 00000000000..d0fd23963c2 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr3.ll @@ -0,0 +1,106 @@ +; Generated from odr3.cpp and odr-types.h by running: +; clang -emit-llvm -g -S -std=c++11 odr3.cpp +; ModuleID = 'odr3.cpp' +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +%struct.S = type { i32, %"struct.S::Nested" } +%"struct.S::Nested" = type { double } + +; Function Attrs: ssp uwtable +define i32 @_Z3barv() #0 { +entry: + %this.addr.i = alloca %struct.S*, align 8 + %Add.addr.i = alloca i32, align 4 + %s = alloca %struct.S, align 8 + call void @llvm.dbg.declare(metadata %struct.S* %s, metadata !34, metadata !35), !dbg !36 + store %struct.S* %s, %struct.S** %this.addr.i, align 8, !dbg !37 + store i32 42, i32* %Add.addr.i, align 4, !dbg !37 + %this1.i = load %struct.S*, %struct.S** %this.addr.i, !dbg !37 + %0 = load i32, i32* %Add.addr.i, align 4, !dbg !38 + %I.i = getelementptr inbounds %struct.S, %struct.S* %this1.i, i32 0, i32 0, !dbg !40 + %1 = load i32, i32* %I.i, align 4, !dbg !41 + %add.i = add nsw i32 %1, %0, !dbg !41 + store i32 %add.i, i32* %I.i, align 4, !dbg !41 + %call = call i32 @_ZN1S3fooEv(%struct.S* %s), !dbg !42 + call void @llvm.dbg.declare(metadata %struct.S** %this.addr.i, metadata !43, metadata !35), !dbg !45 + call void @llvm.dbg.declare(metadata i32* %Add.addr.i, metadata !46, metadata !35), !dbg !47 + ret i32 %call, !dbg !48 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind ssp uwtable +define linkonce_odr i32 @_ZN1S3fooEv(%struct.S* %this) #2 align 2 { +entry: + %this.addr = alloca %struct.S*, align 8 + store %struct.S* %this, %struct.S** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %struct.S** %this.addr, metadata !49, metadata !35), !dbg !50 + %this1 = load %struct.S*, %struct.S** %this.addr + %I = getelementptr inbounds %struct.S, %struct.S* %this1, i32 0, i32 0, !dbg !51 + %0 = load i32, i32* %I, align 4, !dbg !51 + ret i32 %0, !dbg !52 +} + +attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!30, !31, !32} +!llvm.ident = !{!33} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24) +!1 = !DIFile(filename: "odr3.cpp", directory: "/Inputs") +!2 = !{} +!3 = !{!4, !20} +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S") +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs") +!6 = !{!7, !9, !10, !14, !17} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32) +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64) +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !13, !8} +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false) +!18 = !DISubroutineType(types: !19) +!19 = !{!8, !13} +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE") +!21 = !{!22} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64) +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float) +!24 = !{!25, !28, !29} +!25 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i32 ()* @_Z3barv, variables: !2) +!26 = !DISubroutineType(types: !27) +!27 = !{!8} +!28 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false, declaration: !14, variables: !2) +!29 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: true, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false, function: i32 (%struct.S*)* @_ZN1S3fooEv, declaration: !17, variables: !2) +!30 = !{i32 2, !"Dwarf Version", i32 2} +!31 = !{i32 2, !"Debug Info Version", i32 3} +!32 = !{i32 1, !"PIC Level", i32 2} +!33 = !{!"clang version 3.8.0 (trunk 242534)"} +!34 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "s", scope: !25, file: !1, line: 4, type: !"_ZTS1S") +!35 = !DIExpression() +!36 = !DILocation(line: 4, column: 4, scope: !25) +!37 = !DILocation(line: 5, column: 2, scope: !25) +!38 = !DILocation(line: 5, column: 59, scope: !28, inlinedAt: !39) +!39 = distinct !DILocation(line: 5, column: 2, scope: !25) +!40 = !DILocation(line: 5, column: 54, scope: !28, inlinedAt: !39) +!41 = !DILocation(line: 5, column: 56, scope: !28, inlinedAt: !39) +!42 = !DILocation(line: 6, column: 9, scope: !25) +!43 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !28, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer) +!44 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64) +!45 = !DILocation(line: 0, scope: !28, inlinedAt: !39) +!46 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Add", arg: 2, scope: !28, file: !5, line: 5, type: !8) +!47 = !DILocation(line: 5, column: 16, scope: !28, inlinedAt: !39) +!48 = !DILocation(line: 6, column: 2, scope: !25) +!49 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !29, type: !44, flags: DIFlagArtificial | DIFlagObjectPointer) +!50 = !DILocation(line: 0, scope: !29) +!51 = !DILocation(line: 18, column: 21, scope: !29) +!52 = !DILocation(line: 18, column: 14, scope: !29) diff --git a/llvm/test/tools/dsymutil/Inputs/odr4.cpp b/llvm/test/tools/dsymutil/Inputs/odr4.cpp new file mode 100644 index 00000000000..948dbdbd8e5 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr4.cpp @@ -0,0 +1,8 @@ +namespace { + class AnonC { + }; +} + +void baz() { + AnonC ac; +} diff --git a/llvm/test/tools/dsymutil/Inputs/odr4.ll b/llvm/test/tools/dsymutil/Inputs/odr4.ll new file mode 100644 index 00000000000..ecaf85bd34f --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr4.ll @@ -0,0 +1,43 @@ +; Generated from odr4.cpp and odr-types.h by running: +; clang -emit-llvm -g -S -std=c++11 odr4.cpp +; ModuleID = 'odr4.cpp' +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +%"class.(anonymous namespace)::AnonC" = type { i8 } + +; Function Attrs: nounwind ssp uwtable +define void @_Z3bazv() #0 { +entry: + %ac = alloca %"class.(anonymous namespace)::AnonC", align 1 + call void @llvm.dbg.declare(metadata %"class.(anonymous namespace)::AnonC"* %ac, metadata !11, metadata !14), !dbg !15 + ret void, !dbg !16 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3) +!1 = !DIFile(filename: "odr4.cpp", directory: "/Inputs") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 6, type: !5, isLocal: false, isDefinition: true, scopeLine: 6, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @_Z3bazv, variables: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null} +!7 = !{i32 2, !"Dwarf Version", i32 2} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"PIC Level", i32 2} +!10 = !{!"clang version 3.8.0 (trunk 242534)"} +!11 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "ac", scope: !4, file: !1, line: 7, type: !12) +!12 = !DICompositeType(tag: DW_TAG_class_type, name: "AnonC", scope: !13, file: !1, line: 2, size: 8, align: 8, elements: !2) +!13 = !DINamespace(scope: null, file: !1, line: 1) +!14 = !DIExpression() +!15 = !DILocation(line: 7, column: 8, scope: !4) +!16 = !DILocation(line: 8, column: 1, scope: !4) diff --git a/llvm/test/tools/dsymutil/Inputs/odr5.cpp b/llvm/test/tools/dsymutil/Inputs/odr5.cpp new file mode 100644 index 00000000000..fd694239e37 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr5.cpp @@ -0,0 +1,7 @@ +#include "odr-types.h" + +double baz() { + S::Nested d; + d.init(0); + return d.D; +} diff --git a/llvm/test/tools/dsymutil/Inputs/odr5.ll b/llvm/test/tools/dsymutil/Inputs/odr5.ll new file mode 100644 index 00000000000..7b738be5427 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr5.ll @@ -0,0 +1,101 @@ +; Generated from odr5.cpp and odr-types.h by running: +; clang -emit-llvm -g -S -std=c++11 odr5.cpp +; ModuleID = 'odr5.cpp' +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +%"struct.S::Nested" = type { double } + +; Function Attrs: ssp uwtable +define double @_Z3bazv() #0 { +entry: + %d = alloca %"struct.S::Nested", align 8 + call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %d, metadata !39, metadata !40), !dbg !41 + call void @_ZN1S6Nested4initIiEEvT_(%"struct.S::Nested"* %d, i32 0), !dbg !42 + %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"* %d, i32 0, i32 0, !dbg !43 + %0 = load double, double* %D, align 8, !dbg !43 + ret double %0, !dbg !44 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind ssp uwtable +define linkonce_odr void @_ZN1S6Nested4initIiEEvT_(%"struct.S::Nested"* %this, i32 %Val) #2 align 2 { +entry: + %this.addr = alloca %"struct.S::Nested"*, align 8 + %Val.addr = alloca i32, align 4 + store %"struct.S::Nested"* %this, %"struct.S::Nested"** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %"struct.S::Nested"** %this.addr, metadata !45, metadata !40), !dbg !47 + store i32 %Val, i32* %Val.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %Val.addr, metadata !48, metadata !40), !dbg !49 + %this1 = load %"struct.S::Nested"*, %"struct.S::Nested"** %this.addr + %0 = load i32, i32* %Val.addr, align 4, !dbg !50 + %conv = sitofp i32 %0 to double, !dbg !50 + %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"* %this1, i32 0, i32 0, !dbg !51 + store double %conv, double* %D, align 8, !dbg !52 + ret void, !dbg !53 +} + +attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!35, !36, !37} +!llvm.ident = !{!38} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24) +!1 = !DIFile(filename: "odr5.cpp", directory: "/Inputs") +!2 = !{} +!3 = !{!4, !20, !23} +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S") +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs") +!6 = !{!7, !9, !10, !14, !17} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32) +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64) +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !13, !8} +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false) +!18 = !DISubroutineType(types: !19) +!19 = !{!8, !13} +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE") +!21 = !{!22} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64) +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float) +!24 = !{!25, !28} +!25 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: double ()* @_Z3bazv, variables: !2) +!26 = !DISubroutineType(types: !27) +!27 = !{!23} +!28 = !DISubprogram(name: "init<int>", linkageName: "_ZN1S6Nested4initIiEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12, type: !29, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, function: void (%"struct.S::Nested"*, i32)* @_ZN1S6Nested4initIiEEvT_, templateParams: !32, declaration: !34, variables: !2) +!29 = !DISubroutineType(types: !30) +!30 = !{null, !31, !8} +!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!32 = !{!33} +!33 = !DITemplateTypeParameter(name: "T", type: !8) +!34 = !DISubprogram(name: "init<int>", linkageName: "_ZN1S6Nested4initIiEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12, type: !29, isLocal: false, isDefinition: false, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, templateParams: !32) +!35 = !{i32 2, !"Dwarf Version", i32 2} +!36 = !{i32 2, !"Debug Info Version", i32 3} +!37 = !{i32 1, !"PIC Level", i32 2} +!38 = !{!"clang version 3.8.0 (trunk 242534)"} +!39 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "d", scope: !25, file: !1, line: 4, type: !"_ZTSN1S6NestedE") +!40 = !DIExpression() +!41 = !DILocation(line: 4, column: 12, scope: !25) +!42 = !DILocation(line: 5, column: 2, scope: !25) +!43 = !DILocation(line: 6, column: 11, scope: !25) +!44 = !DILocation(line: 6, column: 2, scope: !25) +!45 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !28, type: !46, flags: DIFlagArtificial | DIFlagObjectPointer) +!46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64) +!47 = !DILocation(line: 0, scope: !28) +!48 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Val", arg: 2, scope: !28, file: !5, line: 12, type: !8) +!49 = !DILocation(line: 12, column: 36, scope: !28) +!50 = !DILocation(line: 12, column: 54, scope: !28) +!51 = !DILocation(line: 12, column: 43, scope: !28) +!52 = !DILocation(line: 12, column: 45, scope: !28) +!53 = !DILocation(line: 12, column: 60, scope: !28) diff --git a/llvm/test/tools/dsymutil/Inputs/odr6.cpp b/llvm/test/tools/dsymutil/Inputs/odr6.cpp new file mode 100644 index 00000000000..2893856ce2a --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr6.cpp @@ -0,0 +1,7 @@ +#include "odr-types.h" + +double baz() { + S::Nested d; + d.init(0.0); + return d.D; +} diff --git a/llvm/test/tools/dsymutil/Inputs/odr6.ll b/llvm/test/tools/dsymutil/Inputs/odr6.ll new file mode 100644 index 00000000000..c17099f1f97 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr6.ll @@ -0,0 +1,100 @@ +; Generated from odr6.cpp and odr-types.h by running: +; clang -emit-llvm -g -S -std=c++11 odr6.cpp +; ModuleID = 'odr6.cpp' +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +%"struct.S::Nested" = type { double } + +; Function Attrs: ssp uwtable +define double @_Z3bazv() #0 { +entry: + %d = alloca %"struct.S::Nested", align 8 + call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %d, metadata !39, metadata !40), !dbg !41 + call void @_ZN1S6Nested4initIdEEvT_(%"struct.S::Nested"* %d, double 0.000000e+00), !dbg !42 + %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"* %d, i32 0, i32 0, !dbg !43 + %0 = load double, double* %D, align 8, !dbg !43 + ret double %0, !dbg !44 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: nounwind ssp uwtable +define linkonce_odr void @_ZN1S6Nested4initIdEEvT_(%"struct.S::Nested"* %this, double %Val) #2 align 2 { +entry: + %this.addr = alloca %"struct.S::Nested"*, align 8 + %Val.addr = alloca double, align 8 + store %"struct.S::Nested"* %this, %"struct.S::Nested"** %this.addr, align 8 + call void @llvm.dbg.declare(metadata %"struct.S::Nested"** %this.addr, metadata !45, metadata !40), !dbg !47 + store double %Val, double* %Val.addr, align 8 + call void @llvm.dbg.declare(metadata double* %Val.addr, metadata !48, metadata !40), !dbg !49 + %this1 = load %"struct.S::Nested"*, %"struct.S::Nested"** %this.addr + %0 = load double, double* %Val.addr, align 8, !dbg !50 + %D = getelementptr inbounds %"struct.S::Nested", %"struct.S::Nested"* %this1, i32 0, i32 0, !dbg !51 + store double %0, double* %D, align 8, !dbg !52 + ret void, !dbg !53 +} + +attributes #0 = { ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!35, !36, !37} +!llvm.ident = !{!38} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24) +!1 = !DIFile(filename: "odr6.cpp", directory: "/Inputs") +!2 = !{} +!3 = !{!4, !20, !23} +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S") +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs") +!6 = !{!7, !9, !10, !14, !17} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32) +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64) +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !13, !8} +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false) +!18 = !DISubroutineType(types: !19) +!19 = !{!8, !13} +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE") +!21 = !{!22} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64) +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float) +!24 = !{!25, !28} +!25 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: double ()* @_Z3bazv, variables: !2) +!26 = !DISubroutineType(types: !27) +!27 = !{!23} +!28 = !DISubprogram(name: "init<double>", linkageName: "_ZN1S6Nested4initIdEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12, type: !29, isLocal: false, isDefinition: true, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, function: void (%"struct.S::Nested"*, double)* @_ZN1S6Nested4initIdEEvT_, templateParams: !32, declaration: !34, variables: !2) +!29 = !DISubroutineType(types: !30) +!30 = !{null, !31, !23} +!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!32 = !{!33} +!33 = !DITemplateTypeParameter(name: "T", type: !23) +!34 = !DISubprogram(name: "init<double>", linkageName: "_ZN1S6Nested4initIdEEvT_", scope: !"_ZTSN1S6NestedE", file: !5, line: 12, type: !29, isLocal: false, isDefinition: false, scopeLine: 12, flags: DIFlagPrototyped, isOptimized: false, templateParams: !32) +!35 = !{i32 2, !"Dwarf Version", i32 2} +!36 = !{i32 2, !"Debug Info Version", i32 3} +!37 = !{i32 1, !"PIC Level", i32 2} +!38 = !{!"clang version 3.8.0 (trunk 242534)"} +!39 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "d", scope: !25, file: !1, line: 4, type: !"_ZTSN1S6NestedE") +!40 = !DIExpression() +!41 = !DILocation(line: 4, column: 12, scope: !25) +!42 = !DILocation(line: 5, column: 2, scope: !25) +!43 = !DILocation(line: 6, column: 11, scope: !25) +!44 = !DILocation(line: 6, column: 2, scope: !25) +!45 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "this", arg: 1, scope: !28, type: !46, flags: DIFlagArtificial | DIFlagObjectPointer) +!46 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64) +!47 = !DILocation(line: 0, scope: !28) +!48 = !DILocalVariable(tag: DW_TAG_arg_variable, name: "Val", arg: 2, scope: !28, file: !5, line: 12, type: !23) +!49 = !DILocation(line: 12, column: 36, scope: !28) +!50 = !DILocation(line: 12, column: 54, scope: !28) +!51 = !DILocation(line: 12, column: 43, scope: !28) +!52 = !DILocation(line: 12, column: 45, scope: !28) +!53 = !DILocation(line: 12, column: 60, scope: !28) diff --git a/llvm/test/tools/dsymutil/Inputs/odr7.cpp b/llvm/test/tools/dsymutil/Inputs/odr7.cpp new file mode 100644 index 00000000000..6056b486972 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr7.cpp @@ -0,0 +1,5 @@ +#include "odr-types.h" + +void foo() { + S::Nested N; +} diff --git a/llvm/test/tools/dsymutil/Inputs/odr7.ll b/llvm/test/tools/dsymutil/Inputs/odr7.ll new file mode 100644 index 00000000000..b4df117f1cf --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/odr7.ll @@ -0,0 +1,62 @@ +; Generated from odr7.cpp and odr-types.h by running: +; clang -emit-llvm -g -S -std=c++11 odr7.cpp +; ModuleID = 'odr7.cpp' +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +%"struct.S::Nested" = type { double } + +; Function Attrs: nounwind ssp uwtable +define void @_Z3foov() #0 { +entry: + %N = alloca %"struct.S::Nested", align 8 + call void @llvm.dbg.declare(metadata %"struct.S::Nested"* %N, metadata !32, metadata !33), !dbg !34 + ret void, !dbg !35 +} + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind ssp uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+cx16,+sse,+sse2,+sse3,+ssse3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!28, !29, !30} +!llvm.ident = !{!31} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 3.8.0 (trunk 242534)", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2, retainedTypes: !3, subprograms: !24) +!1 = !DIFile(filename: "odr7.cpp", directory: "/Inputs") +!2 = !{} +!3 = !{!4, !20} +!4 = !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !5, line: 1, size: 128, align: 64, elements: !6, identifier: "_ZTS1S") +!5 = !DIFile(filename: "./odr-types.h", directory: "/Inputs") +!6 = !{!7, !9, !10, !14, !17} +!7 = !DIDerivedType(tag: DW_TAG_member, name: "I", scope: !"_ZTS1S", file: !5, line: 2, baseType: !8, size: 32, align: 32) +!8 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTS1S", file: !5, line: 15, baseType: !"_ZTSN1S6NestedE", size: 64, align: 64, offset: 64) +!10 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEv", scope: !"_ZTS1S", file: !5, line: 4, type: !11, isLocal: false, isDefinition: false, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: false) +!11 = !DISubroutineType(types: !12) +!12 = !{null, !13} +!13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !"_ZTS1S", size: 64, align: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!14 = !DISubprogram(name: "incr", linkageName: "_ZN1S4incrEi", scope: !"_ZTS1S", file: !5, line: 5, type: !15, isLocal: false, isDefinition: false, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: false) +!15 = !DISubroutineType(types: !16) +!16 = !{null, !13, !8} +!17 = !DISubprogram(name: "foo", linkageName: "_ZN1S3fooEv", scope: !"_ZTS1S", file: !5, line: 18, type: !18, isLocal: false, isDefinition: false, scopeLine: 18, flags: DIFlagPrototyped, isOptimized: false) +!18 = !DISubroutineType(types: !19) +!19 = !{!8, !13} +!20 = !DICompositeType(tag: DW_TAG_structure_type, name: "Nested", scope: !"_ZTS1S", file: !5, line: 9, size: 64, align: 64, elements: !21, identifier: "_ZTSN1S6NestedE") +!21 = !{!22} +!22 = !DIDerivedType(tag: DW_TAG_member, name: "D", scope: !"_ZTSN1S6NestedE", file: !5, line: 10, baseType: !23, size: 64, align: 64) +!23 = !DIBasicType(name: "double", size: 64, align: 64, encoding: DW_ATE_float) +!24 = !{!25} +!25 = !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 3, type: !26, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: void ()* @_Z3foov, variables: !2) +!26 = !DISubroutineType(types: !27) +!27 = !{null} +!28 = !{i32 2, !"Dwarf Version", i32 2} +!29 = !{i32 2, !"Debug Info Version", i32 3} +!30 = !{i32 1, !"PIC Level", i32 2} +!31 = !{!"clang version 3.8.0 (trunk 242534)"} +!32 = !DILocalVariable(tag: DW_TAG_auto_variable, name: "N", scope: !25, file: !1, line: 4, type: !"_ZTSN1S6NestedE") +!33 = !DIExpression() +!34 = !DILocation(line: 4, column: 12, scope: !25) +!35 = !DILocation(line: 5, column: 1, scope: !25) diff --git a/llvm/test/tools/dsymutil/X86/odr-1.test b/llvm/test/tools/dsymutil/X86/odr-1.test new file mode 100644 index 00000000000..b650dc098bf --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/odr-1.test @@ -0,0 +1,423 @@ +# REQUIRES: object-emission +# RUN: rm -rf %t +# RUN: mkdir -p %t +# RUN: llc -filetype=obj %p/../Inputs/odr1.ll -o %t/odr1.o +# RUN: llc -filetype=obj %p/../Inputs/odr2.ll -o %t/odr2.o +# RUN: llc -filetype=obj %p/../Inputs/odr3.ll -o %t/odr3.o +# RUN: llc -filetype=obj %p/../Inputs/odr4.ll -o %t/odr4.o +# RUN: llc -filetype=obj %p/../Inputs/odr5.ll -o %t/odr5.o +# RUN: llc -filetype=obj %p/../Inputs/odr6.ll -o %t/odr6.o +# RUN: llc -filetype=obj %p/../Inputs/odr7.ll -o %t/odr7.o +# RUN: llvm-dsymutil -oso-prepend-path=%t -y %s -o - | llvm-dwarfdump -debug-dump=info - | FileCheck -check-prefix=ODR -check-prefix=CHECK %s +# RUN: llvm-dsymutil -oso-prepend-path=%t -y %s -no-odr -o - | llvm-dwarfdump -debug-dump=info - | FileCheck -check-prefix=NOODR -check-prefix=CHECK %s + +# Totally made up debug map to test ODR uniquing + +--- +triple: 'x86_64-unknown-unknown-macho' +objects: + - filename: odr1.o + symbols: + - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x1000, size: 0x12 } + - { sym: __Z4funcv, objAddr: 0x0, binAddr: 0x2000, size: 0x12 } + - { sym: __ZZ4funcvENKUlvE_clEv, objAddr: 0x0, binAddr: 0x3000, size: 0x12 } + +# Check that all our types are in the first CU. + +# CHECK: TAG_compile_unit +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: AT_name{{.*}}"odr1.cpp" + +# This is "struct S" + +# CHECK: 0x[[S:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# CHECK-NEXT: DW_AT_name{{.*}}"S" +# CHECK-NOT: NULL +# CHECK: 0x[[NESTED:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: DW_AT_name{{.*}}"Nested" +# CHECK: NULL +# CHECK: DW_TAG_subprogram +# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S4incrEv" +# CHECK: NULL +# CHECK: DW_TAG_subprogram +# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S4incrEi" +# CHECK: NULL +# CHECK: DW_TAG_subprogram +# CHECK: DW_AT_MIPS_linkage_name{{.*}}"_ZN1S3fooEv" +# CHECK: NULL +# CHECK: NULL + +# This is "class N::C" + +# CHECK: DW_TAG_namespace +# CHECK-NEXT: DW_AT_name{{.*}}"N" +# CHECK-NOT: NULL +# CHECK: 0x[[NC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +# CHECK-NEXT: DW_AT_name{{.*}}"C" +# CHECK: NULL + +# This is "class N::N::C" + +# CHECK: DW_TAG_namespace +# CHECK-NEXT: DW_AT_name{{.*}}"N" +# CHECK-NOT: NULL +# CHECK: 0x[[NNC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +# CHECK-NEXT: DW_AT_name{{.*}}"C" +# CHECK: NULL +# CHECK: NULL +# CHECK: NULL + +# This is "AliasForS" +# CHECK: 0x[[ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef +# CHECK-NEXT: DW_AT_type{{.*}}[[S]] +# CHECK-NEXT: DW_AT_name{{.*}}"AliasForS" + +# This is "union U" + +# CHECK: 0x[[U:[0-9a-f]*]]:{{.*}}DW_TAG_union_type +# CHECK-NEXT: DW_AT_name{{.*}}"U" +# CHECK-NOT: NULL +# CHECK: 0x[[UC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +# CHECK-NOT: NULL +# CHECK: 0x[[US:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# CHECK: NULL + +# This is "func" free function + +# CHECK: DW_TAG_subprogram +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: DW_AT_name{{.*}}"func" +# CHECK: 0x[[CINSIDEFUNC:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# CHECK-NEXT: DW_AT_name{{.*}}"CInsideFunc" + +# This is "(anonymous namespace)::AnonC" + +# CHECK: DW_TAG_namespace +# CHECK-NOT: {{DW_AT_name|NULL|DW_TAG}} +# CHECK: 0x[[ANONC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +# CHECK-NEXT: DW_AT_name{{.*}}"AnonC" + + - filename: odr1.o + symbols: + - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x4000, size: 0x12 } + - { sym: __Z4funcv, objAddr: 0x0, binAddr: 0x5000, size: 0x12 } + - { sym: __ZZ4funcvENKUlvE_clEv, objAddr: 0x0, binAddr: 0x6000, size: 0x12 } + +# We relink the same file a second time. In the ODR case, everything (except for the +# union for now) should be uniqued. In the non-ODR case, we should get every type +# duplicated. + +# CHECK: TAG_compile_unit +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: AT_name{{.*}}"odr1.cpp" + +# ODR: DW_TAG_union_type +# ODR-NEXT: DW_AT_name{{.*}}"U" +# Types defined inside the union should be uniqued: +# ODR: DW_TAG_member +# ODR-NEXT: DW_AT_name{{.*}}"C" +# ODR-NOT: {{NULL|DW_TAG}} +# ODR: DW_AT_type{{.*}}[[UC]] +# ODR: DW_TAG_member +# ODR-NEXT: DW_AT_name{{.*}}"S" +# ODR-NOT: {{NULL|DW_TAG}} +# ODR: DW_AT_type{{.*}}[[US]] + +# Skip func +# ODR: DW_TAG_subprogram +# ODR-NOT: {{NULL|DW_TAG}} +# ODR: DW_AT_name{{.*}}"func" +# ODR: NULL + +# ODR: DW_TAG_subprogram +# ODR-NOT: {{NULL|DW_TAG}} +# ODR: DW_AT_name{{.*}}"foo" +# ODR-NOT: NULL +# ODR: DW_TAG_variable +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_name{{.*}}"s" +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_type{{.*}}[[ALIASFORS]] +# ODR: DW_TAG_variable +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_name{{.*}}"nc" +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_type{{.*}}[[NC]] +# ODR: DW_TAG_variable +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_name{{.*}}"nnc" +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_type{{.*}}[[NNC]] +# ODR: DW_TAG_variable +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_name{{.*}}"ac" +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_type{{.*}}[[ANONC]] + +# ODR: DW_TAG_subprogram +# ODR-NOT: {{NULL|DW_TAG}} +# ODR: linkage_name{{.*}}"_ZZ4funcvENKUlvE_clEv" +# ODR-NOT: NULL +# ODR: DW_TAG_variable +# ODR-NOT: DW_TAG +# ODR: DW_AT_name{{.*}}"dummy" +# ODR-NOT: NULL +# ODR: DW_AT_type{{.*}}[[CINSIDEFUNC]] + +# With no ODR uniquing, we should get copies of all the types: + +# This is "struct S" +# NOODR: 0x[[DUP_S:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# NOODR-NEXT: DW_AT_name{{.*}}"S" + +# This is "class N::C" +# NOODR: DW_TAG_namespace +# NOODR-NEXT: DW_AT_name{{.*}}"N" +# NOODR: 0x[[DUP_NC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +# NOODR-NEXT: DW_AT_name{{.*}}"C" + +# This is "class N::N::C" +# NOODR: DW_TAG_namespace +# NOODR-NEXT: DW_AT_name{{.*}}"N" +# NOODR: 0x[[DUP_NNC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +# NOODR-NEXT: DW_AT_name{{.*}}"C" + +# This is "AliasForS" +# NOODR: 0x[[DUP_ALIASFORS:[0-9a-f]*]]:{{.*}}DW_TAG_typedef +# NOODR-NOT: {{NULL|DW_TAG}} +# NOODR: DW_AT_name{{.*}}"AliasForS" + +# This is "union U" + +# NOODR: 0x[[U:[0-9a-f]*]]:{{.*}}DW_TAG_union_type +# NOODR-NEXT: DW_AT_name{{.*}}"U" +# NOODR-NOT: NULL +# NOODR: 0x[[DUP_UC:[0-9a-f]*]]:{{.*}}DW_TAG_class_type +# NOODR-NOT: NULL +# NOODR: 0x[[DUP_US:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# NOODR: NULL + +# This is "func" free function + +# NOODR: DW_TAG_subprogram +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_name{{.*}}"func" +# NOODR: 0x[[DUP_CINSIDEFUNC:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# NOODR-NEXT: DW_AT_name{{.*}}"CInsideFunc" + +# NOODR: DW_TAG_subprogram +# NOODR-NOT: {{NULL|DW_TAG}} +# NOODR: DW_AT_name{{.*}}"foo" +# NOODR-NOT: NULL +# NOODR: DW_TAG_variable +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_name{{.*}}"s" +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_type{{.*}}[[DUP_ALIASFORS]] +# NOODR: DW_TAG_variable +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_name{{.*}}"nc" +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_type{{.*}}[[DUP_NC]] +# NOODR: DW_TAG_variable +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_name{{.*}}"nnc" +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_type{{.*}}[[DUP_NNC]] +# NOODR: DW_TAG_variable +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_name{{.*}}"ac" +# NOODR-NOT: {{DW_TAG|NULL}} +# NOODR: DW_AT_type{{.*}}0x[[DUP_ANONC:[0-9a-f]*]] + +# This is the lanbda inside func + +# NOODR: DW_TAG_subprogram +# NOODR-NOT: {{NULL|DW_TAG}} +# NOODR: linkage_name{{.*}}"_ZZ4funcvENKUlvE_clEv" +# NOODR-NOT: NULL +# NOODR: DW_TAG_variable +# NOODR-NOT: DW_TAG +# NOODR: DW_AT_name{{.*}}"dummy" +# NOODR-NOT: NULL +# NOODR: DW_AT_type{{.*}}[[DUP_CINSIDEFUNC]] + +# This is "(anonymous namespace)::AnonC" + +# NOODR: DW_TAG_namespace +# NOODR-NOT: {{DW_AT_name|NULL|DW_TAG}} +# NOODR: 0x[[DUP_ANONC]]:{{.*}}DW_TAG_class_type +# NOODR-NEXT: DW_AT_name{{.*}}"AnonC" + + - filename: odr2.o + symbols: + - { sym: __ZN1S3fooEv, objAddr: 0x0, binAddr: 0x7000, size: 0x12 } + - { sym: __Z3barv, objAddr: 0x0, binAddr: 0x8000, size: 0x12 } + - filename: odr3.o + symbols: + - { sym: __ZN1S3fooEv, objAddr: 0x0, binAddr: 0x8000, size: 0x12 } + - { sym: __Z3barv, objAddr: 0x0, binAddr: 0x9000, size: 0x12 } + +# odr2.cpp and odr3.cpp test that a simple overloaded function doesn't break the +# uniquing (contrary to what we'll see with template/artificial) functions. + +# CHECK: TAG_compile_unit +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: AT_name{{.*}}"odr2.cpp" + +# NO-ODR: DW_TAG_structure_type +# ODR-NOT: DW_TAG_structure_type + +# ODR: DW_TAG_subprogram +# ODR: DW_AT_specification{{.*}}4incr +# ODR: DW_TAG_formal_parameter +# ODR-NEXT: DW_AT_name{{.*}}"this" +# ODR-NEXT: DW_AT_type{{.*}}0x00000000[[S_PTR:[0-9a-f]*]] +# ODR: 0x[[S_PTR]]:{{.*}}DW_TAG_pointer_type +# ODR-NEXT: DW_AT_type{{.*}}[[S]] +# ODR: DW_TAG_subprogram +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_name{{.*}}"bar" +# ODR-NOT: NULL +# ODR: DW_TAG_variable +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_type{{.*}}[[S]] +# ODR-NOT NULL +# DOR: DW_TAG_inlined_subroutine +# ODR-NOT NULL +# ODR: DW_TAG_formal_parameter +# ODR-NOT {{NULL|DW_TAG}} +# ODR: DW_AT_type{{.*}}[[S_PTR]] + +# CHECK: TAG_compile_unit +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: AT_name{{.*}}"odr3.cpp" + +# NO-ODR: DW_TAG_structure_type +# ODR-NOT: DW_TAG_structure_type + +# ODR: DW_TAG_subprogram +# ODR: DW_AT_specification{{.*}}4incr +# ODR: DW_TAG_formal_parameter +# ODR-NEXT: DW_AT_name{{.*}}"this" +# ODR-NEXT: DW_AT_type{{.*}}0x00000000[[S_PTR2:[0-9a-f]*]] +# ODR: 0x[[S_PTR2]]:{{.*}}DW_TAG_pointer_type +# ODR-NEXT: DW_AT_type{{.*}}[[S]] +# ODR: DW_TAG_subprogram +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_name{{.*}}"bar" +# ODR-NOT: NULL +# ODR: DW_TAG_variable +# ODR-NOT: {{DW_TAG|NULL}} +# ODR: DW_AT_type{{.*}}[[S]] +# ODR-NOT NULL +# DOR: DW_TAG_inlined_subroutine +# ODR-NOT NULL +# ODR: DW_TAG_formal_parameter +# ODR-NOT {{NULL|DW_TAG}} +# ODR: DW_AT_type{{.*}}[[S_PTR2]] + + - filename: odr4.o + symbols: + - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xa000, size: 0x12 } + +# odr4.cpp helps check that anonymous namespaces with similarly named contents do +# not get uniqued. + +# CHECK: TAG_compile_unit +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: AT_name{{.*}}"odr4.cpp" + +# CHECK: DW_TAG_subprogram +# CHECK-NOT: NULL +# CHECK: DW_TAG_variable +# CHECK-NOT: DW_TAG +# ODR: DW_AT_type{{.*}}[[LOCALANONC:........]]) +# NOODR: DW_AT_type{{.*}}[[LOCALANONC:........]]}) + +# CHECK: DW_TAG_namespace +# CHECK-NOT: DW_AT_name +# CHECK: [[LOCALANONC]]{{.*}}DW_TAG_class_type +# CHECK-NOT: {{NULL|DW_TAG}} +# CHECK: DW_AT_name{{.*}}"AnonC" + + - filename: odr5.o + symbols: + - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xb000, size: 0x12 } + - { sym: __ZN1S6Nested4initIiEEvT_, objAddr: 0x0, binAddr: 0xc000, size: 0x12 } + - filename: odr6.o + symbols: + - { sym: __Z3bazv, objAddr: 0x0, binAddr: 0xd000, size: 0x12 } + - { sym: __ZN1S6Nested4initIdEEvT_, objAddr: 0x0, binAddr: 0xe000, size: 0x12 } + +# odr5.cpp and odr6.cpp instanciate a template member function of the S class. +# They instanciate it with different types. As DWARF only describes the actual +# intances, these members aren't described in the uniqued class definition of +# odr1.cpp. Both these files should contain a new copy of S' definition with +# the template instance included. + +# CHECK: TAG_compile_unit +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: AT_name{{.*}}"odr5.cpp" + +# CHECK: 0x{{[0-9a-f]*}}:{{.*}}DW_TAG_structure_type +# CHECK-NEXT: DW_AT_name{{.*}}"S" +# CHECK-NOT: NULL +# CHECK: 0x[[NESTED2:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: DW_AT_name{{.*}}"Nested" +# CHECK-NOT: NULL +# CHECK: 0x[[INITTEMPLATE:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram +# CHECK-NEXT:{{.*}}"_ZN1S6Nested4init + +# CHECK: DW_AT_specification{{.*}}[[INITTEMPLATE]] +# CHECK: DW_TAG_formal_parameter +# CHECK-NOT: DW_TAG +# CHECK: DW_AT_type{{.*}}[[NESTED_PTR:[0-9a-f]{8}]]{{[}]?}}) + +# CHECK: 0x[[NESTED_PTR]]{{.*}}DW_TAG_pointer_type +# ODR-NEXT: DW_AT_type{{.*}}[[NESTED]] +# NOODR-NEXT: DW_AT_type{{.*}}[[NESTED2]] + +# CHECK: TAG_compile_unit +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: AT_name{{.*}}"odr6.cpp" + +# CHECK: 0x{{[0-9a-f]*}}:{{.*}}DW_TAG_structure_type +# CHECK-NEXT: DW_AT_name{{.*}}"S" +# CHECK-NOT: NULL +# CHECK: 0x[[NESTED3:[0-9a-f]*]]:{{.*}}DW_TAG_structure_type +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: DW_AT_name{{.*}}"Nested" +# CHECK-NOT: NULL +# CHECK: 0x[[INITTEMPLATE2:[0-9a-f]*]]:{{.*}}DW_TAG_subprogram +# CHECK-NEXT:{{.*}}"_ZN1S6Nested4init + +# CHECK: DW_AT_specification{{.*}}[[INITTEMPLATE2]] +# CHECK: DW_TAG_formal_parameter +# CHECK-NOT: DW_TAG +# CHECK: DW_AT_type{{.*}}[[NESTED_PTR2:[0-9a-f]{8}]]{{[}]?}}) + +# CHECK: 0x[[NESTED_PTR2]]{{.*}}DW_TAG_pointer_type +# ODR-NEXT: DW_AT_type{{.*}}[[NESTED]] +# NOODR-NEXT: DW_AT_type{{.*}}[[NESTED3]] + + - filename: odr7.o + symbols: + - { sym: __Z3foov, objAddr: 0x0, binAddr: 0xf000, size: 0x12 } + +# Check that a reference to a nested class correctly refers to the original +# definition + +# CHECK: TAG_compile_unit +# CHECK-NOT: {{DW_TAG|NULL}} +# CHECK: AT_name{{.*}}"odr7.cpp" + +# ODR: DW_TAG_subprogram +# ODR-NOT: NULL +# ODR: DW_TAG_variable +# ODR-NOT: DW_TAG +# ODR: DW_AT_type{{.*}}[[NESTED]] +... + diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 86c22ddfd89..211f6cb6361 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -15,6 +15,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/DIE.h" +#include "llvm/Config/config.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" @@ -80,6 +81,112 @@ struct PatchLocation { } }; +class CompileUnit; +struct DeclMapInfo; +class NonRelocatableStringpool; + +/// A DeclContext is a named program scope that is used for ODR +/// uniquing of types. +/// The set of DeclContext for the ODR-subject parts of a Dwarf link +/// is expanded (and uniqued) with each new object file processed. We +/// need to determine the context of each DIE in an linked object file +/// to see if the corresponding type has already been emitted. +/// +/// The contexts are conceptually organised as a tree (eg. a function +/// scope is contained in a namespace scope that contains other +/// scopes), but storing/accessing them in an actual tree is too +/// inefficient: we need to be able to very quickly query a context +/// for a given child context by name. Storing a StringMap in each +/// DeclContext would be too space inefficient. +/// The solution here is to give each DeclContext a link to its parent +/// (this allows to walk up the tree), but to query the existance of a +/// specific DeclContext using a separate DenseMap keyed on the hash +/// of the fully qualified name of the context. +class DeclContext { + unsigned QualifiedNameHash; + uint32_t Line; + uint32_t ByteSize; + uint16_t Tag; + StringRef Name; + StringRef File; + const DeclContext &Parent; + const DWARFDebugInfoEntryMinimal *LastSeenDIE; + uint32_t LastSeenCompileUnitID; + uint32_t CanonicalDIEOffset; + + friend DeclMapInfo; + +public: + typedef DenseSet<DeclContext *, DeclMapInfo> Map; + + DeclContext() + : QualifiedNameHash(0), Line(0), ByteSize(0), + Tag(dwarf::DW_TAG_compile_unit), Name(), File(), Parent(*this), + LastSeenDIE(nullptr), LastSeenCompileUnitID(0), CanonicalDIEOffset(0) {} + + DeclContext(unsigned Hash, uint32_t Line, uint32_t ByteSize, uint16_t Tag, + StringRef Name, StringRef File, const DeclContext &Parent, + const DWARFDebugInfoEntryMinimal *LastSeenDIE = nullptr, + unsigned CUId = 0) + : QualifiedNameHash(Hash), Line(Line), ByteSize(ByteSize), Tag(Tag), + Name(Name), File(File), Parent(Parent), LastSeenDIE(LastSeenDIE), + LastSeenCompileUnitID(CUId), CanonicalDIEOffset(0) {} + + uint32_t getQualifiedNameHash() const { return QualifiedNameHash; } + + bool setLastSeenDIE(CompileUnit &U, const DWARFDebugInfoEntryMinimal *Die); + + uint32_t getCanonicalDIEOffset() const { return CanonicalDIEOffset; } + void setCanonicalDIEOffset(uint32_t Offset) { CanonicalDIEOffset = Offset; } + + uint16_t getTag() const { return Tag; } + StringRef getName() const { return Name; } +}; + +/// Info type for the DenseMap storing the DeclContext pointers. +struct DeclMapInfo : private DenseMapInfo<DeclContext *> { + using DenseMapInfo<DeclContext *>::getEmptyKey; + using DenseMapInfo<DeclContext *>::getTombstoneKey; + + static unsigned getHashValue(const DeclContext *Ctxt) { + return Ctxt->QualifiedNameHash; + } + + static bool isEqual(const DeclContext *LHS, const DeclContext *RHS) { + if (RHS == getEmptyKey() || RHS == getTombstoneKey()) + return RHS == LHS; + return LHS->QualifiedNameHash == RHS->QualifiedNameHash && + LHS->Line == RHS->Line && LHS->ByteSize == RHS->ByteSize && + LHS->Name.data() == RHS->Name.data() && + LHS->File.data() == RHS->File.data() && + LHS->Parent.QualifiedNameHash == RHS->Parent.QualifiedNameHash; + } +}; + +/// This class gives a tree-like API to the DenseMap that stores the +/// DeclContext objects. It also holds the BumpPtrAllocator where +/// these objects will be allocated. +class DeclContextTree { + BumpPtrAllocator Allocator; + DeclContext Root; + DeclContext::Map Contexts; + +public: + /// Get the child of \a Context described by \a DIE in \a Unit. The + /// required strings will be interned in \a StringPool. + /// \returns The child DeclContext along with one bit that is set if + /// this context is invalid. + /// FIXME: the invalid bit along the return value is to emulate some + /// dsymutil-classic functionality. See the fucntion definition for + /// a more thorough discussion of its use. + PointerIntPair<DeclContext *, 1> + getChildDeclContext(DeclContext &Context, + const DWARFDebugInfoEntryMinimal *DIE, CompileUnit &Unit, + NonRelocatableStringpool &StringPool); + + DeclContext &getRoot() { return Root; } +}; + /// \brief Stores all information relating to a compile unit, be it in /// its original instance in the object file to its brand new cloned /// and linked DIE tree. @@ -88,16 +195,26 @@ public: /// \brief Information gathered about a DIE in the object file. struct DIEInfo { int64_t AddrAdjust; ///< Address offset to apply to the described entity. + DeclContext *Ctxt; ///< ODR Declaration context. DIE *Clone; ///< Cloned version of that DIE. uint32_t ParentIdx; ///< The index of this DIE's parent. bool Keep; ///< Is the DIE part of the linked output? bool InDebugMap; ///< Was this DIE's entity found in the map? }; - CompileUnit(DWARFUnit &OrigUnit, unsigned ID) + CompileUnit(DWARFUnit &OrigUnit, unsigned ID, bool CanUseODR) : OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0), RangeAlloc(), Ranges(RangeAlloc) { Info.resize(OrigUnit.getNumDIEs()); + + const auto *CUDie = OrigUnit.getUnitDIE(false); + unsigned Lang = CUDie->getAttributeValueAsUnsignedConstant( + &OrigUnit, dwarf::DW_AT_language, 0); + HasODR = CanUseODR && (Lang == dwarf::DW_LANG_C_plus_plus || + Lang == dwarf::DW_LANG_C_plus_plus_03 || + Lang == dwarf::DW_LANG_C_plus_plus_11 || + Lang == dwarf::DW_LANG_C_plus_plus_14 || + Lang == dwarf::DW_LANG_ObjC_plus_plus); } CompileUnit(CompileUnit &&RHS) @@ -116,6 +233,8 @@ public: DIE *getOutputUnitDIE() const { return CUDie; } void setOutputUnitDIE(DIE *Die) { CUDie = Die; } + bool hasODR() const { return HasODR; } + DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; } const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; } @@ -147,9 +266,10 @@ public: /// \brief Keep track of a forward reference to DIE \p Die in \p /// RefUnit by \p Attr. The attribute should be fixed up later to - /// point to the absolute offset of \p Die in the debug_info section. + /// point to the absolute offset of \p Die in the debug_info section + /// or to the canonical offset of \p Ctxt if it is non-null. void noteForwardReference(DIE *Die, const CompileUnit *RefUnit, - PatchLocation Attr); + DeclContext *Ctxt, PatchLocation Attr); /// \brief Apply all fixups recored by noteForwardReference(). void fixupForwardReferences(); @@ -190,11 +310,27 @@ public: const std::vector<AccelInfo> &getPubnames() const { return Pubnames; } const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; } + /// Get the full path for file \a FileNum in the line table + const char *getResolvedPath(unsigned FileNum) { + if (FileNum >= ResolvedPaths.size()) + return nullptr; + return ResolvedPaths[FileNum].size() ? ResolvedPaths[FileNum].c_str() + : nullptr; + } + + /// Set the fully resolved path for the line-table's file \a FileNum + /// to \a Path. + void setResolvedPath(unsigned FileNum, const std::string &Path) { + if (ResolvedPaths.size() <= FileNum) + ResolvedPaths.resize(FileNum + 1); + ResolvedPaths[FileNum] = Path; + } + private: DWARFUnit &OrigUnit; unsigned ID; - std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. - DIE *CUDie; ///< Root of the linked DIE tree. + std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. + DIE *CUDie; ///< Root of the linked DIE tree. uint64_t StartOffset; uint64_t NextUnitOffset; @@ -208,8 +344,8 @@ private: /// The offsets for the attributes in this array couldn't be set while /// cloning because for cross-cu forward refences the target DIE's /// offset isn't known you emit the reference attribute. - std::vector<std::tuple<DIE *, const CompileUnit *, PatchLocation>> - ForwardDIEReferences; + std::vector<std::tuple<DIE *, const CompileUnit *, DeclContext *, + PatchLocation>> ForwardDIEReferences; FunctionIntervals::Allocator RangeAlloc; /// \brief The ranges in that interval map are the PC ranges for @@ -236,6 +372,12 @@ private: std::vector<AccelInfo> Pubnames; std::vector<AccelInfo> Pubtypes; /// @} + + /// Cached resolved paths from the line table. + std::vector<std::string> ResolvedPaths; + + /// Is this unit subject to the ODR rule? + bool HasODR; }; uint64_t CompileUnit::computeNextUnitOffset() { @@ -251,8 +393,8 @@ uint64_t CompileUnit::computeNextUnitOffset() { /// \brief Keep track of a forward cross-cu reference from this unit /// to \p Die that lives in \p RefUnit. void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit, - PatchLocation Attr) { - ForwardDIEReferences.emplace_back(Die, RefUnit, Attr); + DeclContext *Ctxt, PatchLocation Attr) { + ForwardDIEReferences.emplace_back(Die, RefUnit, Ctxt, Attr); } /// \brief Apply all fixups recorded by noteForwardReference(). @@ -261,8 +403,12 @@ void CompileUnit::fixupForwardReferences() { DIE *RefDie; const CompileUnit *RefUnit; PatchLocation Attr; - std::tie(RefDie, RefUnit, Attr) = Ref; - Attr.set(RefDie->getOffset() + RefUnit->getStartOffset()); + DeclContext *Ctxt; + std::tie(RefDie, RefUnit, Ctxt, Attr) = Ref; + if (Ctxt && Ctxt->getCanonicalDIEOffset()) + Attr.set(Ctxt->getCanonicalDIEOffset()); + else + Attr.set(RefDie->getOffset() + RefUnit->getStartOffset()); } } @@ -324,6 +470,12 @@ public: /// one. uint32_t getStringOffset(StringRef S); + /// \brief Get permanent storage for \p S (but do not necessarily + /// emit \p S in the output section). + /// \returns The StringRef that points to permanent storage to use + /// in place of \p S. + StringRef internString(StringRef S); + // \brief Return the first entry of the string table. const MapTy::MapEntryTy *getFirstEntry() const { return getNextEntry(&Sentinel); @@ -367,6 +519,16 @@ uint32_t NonRelocatableStringpool::getStringOffset(StringRef S) { return It->getValue().first; } +/// \brief Put \p S into the StringMap so that it gets permanent +/// storage, but do not actually link it in the chain of elements +/// that go into the output section. A latter call to +/// getStringOffset() with the same string will chain it though. +StringRef NonRelocatableStringpool::internString(StringRef S) { + std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr); + auto InsertResult = Strings.insert(std::make_pair(S, Entry)); + return InsertResult.first->getKey(); +}; + /// \brief The Dwarf streaming logic /// /// All interactions with the MC layer that is used to build the debug @@ -1089,6 +1251,7 @@ private: TF_InFunctionScope = 1 << 1, ///< Current scope is a fucntion scope. TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE. TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE. + TF_ODR = 1 << 4, ///< Use the ODR whhile keeping dependants. }; /// \brief Mark the passed DIE as well as all the ones it depends on @@ -1096,7 +1259,7 @@ private: void keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE, CompileUnit::DIEInfo &MyInfo, const DebugMapObject &DMO, CompileUnit &CU, - unsigned Flags); + bool UseODR); unsigned shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, @@ -1227,11 +1390,14 @@ private: BumpPtrAllocator DIEAlloc; /// @} + /// ODR Contexts for that link. + DeclContextTree ODRContexts; + /// \defgroup Helpers Various helper methods. /// /// @{ const DWARFDebugInfoEntryMinimal * - resolveDIEReference(DWARFFormValue &RefValue, const DWARFUnit &Unit, + resolveDIEReference(const DWARFFormValue &RefValue, const DWARFUnit &Unit, const DWARFDebugInfoEntryMinimal &DIE, CompileUnit *&ReferencedCU); @@ -1296,7 +1462,7 @@ CompileUnit *DwarfLinker::getUnitForOffset(unsigned Offset) { /// CompileUnit which is stored into \p ReferencedCU. /// \returns null if resolving fails for any reason. const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference( - DWARFFormValue &RefValue, const DWARFUnit &Unit, + const DWARFFormValue &RefValue, const DWARFUnit &Unit, const DWARFDebugInfoEntryMinimal &DIE, CompileUnit *&RefCU) { assert(RefValue.isFormClass(DWARFFormValue::FC_Reference)); uint64_t RefOffset = *RefValue.getAsReference(&Unit); @@ -1309,6 +1475,220 @@ const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference( return nullptr; } +/// \returns whether the passed \a Attr type might contain a DIE +/// reference suitable for ODR uniquing. +static bool isODRAttribute(uint16_t Attr) { + switch (Attr) { + default: + return false; + case dwarf::DW_AT_type: + case dwarf::DW_AT_containing_type: + case dwarf::DW_AT_specification: + case dwarf::DW_AT_abstract_origin: + case dwarf::DW_AT_import: + return true; + } + llvm_unreachable("Improper attribute."); +} + +/// Set the last DIE/CU a context was seen in and, possibly invalidate +/// the context if it is ambiguous. +/// +/// In the current implementation, we don't handle overloaded +/// functions well, because the argument types are not taken into +/// account when computing the DeclContext tree. +/// +/// Some of this is mitigated byt using mangled names that do contain +/// the arguments types, but sometimes (eg. with function templates) +/// we don't have that. In that case, just do not unique anything that +/// refers to the contexts we are not able to distinguish. +/// +/// If a context that is not a namespace appears twice in the same CU, +/// we know it is ambiguous. Make it invalid. +bool DeclContext::setLastSeenDIE(CompileUnit &U, + const DWARFDebugInfoEntryMinimal *Die) { + if (LastSeenCompileUnitID == U.getUniqueID()) { + DWARFUnit &OrigUnit = U.getOrigUnit(); + uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE); + U.getInfo(FirstIdx).Ctxt = nullptr; + return false; + } + + LastSeenCompileUnitID = U.getUniqueID(); + LastSeenDIE = Die; + return true; +} + +/// Get the child context of \a Context corresponding to \a DIE. +/// +/// \returns the child context or null if we shouldn't track children +/// contexts. It also returns an additional bit meaning 'invalid'. An +/// invalid context means it shouldn't be considered for uniquing, but +/// its not returning null, because some children of that context +/// might be uniquing candidates. +/// FIXME: this is for dsymutil-classic compatibility, I don't think +/// it buys us much. +PointerIntPair<DeclContext *, 1> DeclContextTree::getChildDeclContext( + DeclContext &Context, const DWARFDebugInfoEntryMinimal *DIE, CompileUnit &U, + NonRelocatableStringpool &StringPool) { + unsigned Tag = DIE->getTag(); + + // FIXME: dsymutil-classic compat: We should bail out here if we + // have a specification or an abstract_origin. We will get the + // parent context wrong here. + + switch (Tag) { + default: + // By default stop gathering child contexts. + return PointerIntPair<DeclContext *, 1>(nullptr); + case dwarf::DW_TAG_compile_unit: + // FIXME: Add support for DW_TAG_module. + return PointerIntPair<DeclContext *, 1>(&Context); + case dwarf::DW_TAG_subprogram: + // Do not unique anything inside CU local functions. + if ((Context.getTag() == dwarf::DW_TAG_namespace || + Context.getTag() == dwarf::DW_TAG_compile_unit) && + !DIE->getAttributeValueAsUnsignedConstant(&U.getOrigUnit(), + dwarf::DW_AT_external, 0)) + return PointerIntPair<DeclContext *, 1>(nullptr); + // Fallthrough + case dwarf::DW_TAG_member: + case dwarf::DW_TAG_namespace: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_typedef: + // Artificial things might be ambiguous, because they might be + // created on demand. For example implicitely defined constructors + // are ambiguous because of the way we identify contexts, and they + // won't be generated everytime everywhere. + if (DIE->getAttributeValueAsUnsignedConstant(&U.getOrigUnit(), + dwarf::DW_AT_artificial, 0)) + return PointerIntPair<DeclContext *, 1>(nullptr); + break; + } + + const char *Name = DIE->getName(&U.getOrigUnit(), DINameKind::LinkageName); + const char *ShortName = DIE->getName(&U.getOrigUnit(), DINameKind::ShortName); + StringRef NameRef; + StringRef ShortNameRef; + StringRef FileRef; + + if (Name) + NameRef = StringPool.internString(Name); + else if (Tag == dwarf::DW_TAG_namespace) + // FIXME: For dsymutil-classic compatibility. I think uniquing + // within anonymous namespaces is wrong. There is no ODR guarantee + // there. + NameRef = StringPool.internString("(anonymous namespace)"); + + if (ShortName && ShortName != Name) + ShortNameRef = StringPool.internString(ShortName); + else + ShortNameRef = NameRef; + + if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type && + Tag != dwarf::DW_TAG_union_type && + Tag != dwarf::DW_TAG_enumeration_type && NameRef.empty()) + return PointerIntPair<DeclContext *, 1>(nullptr); + + std::string File; + unsigned Line = 0; + unsigned ByteSize = 0; + + // Gather some discriminating data about the DeclContext we will be + // creating: File, line number and byte size. This shouldn't be + // necessary, because the ODR is just about names, but given that we + // do some approximations with overloaded functions and anonymous + // namespaces, use these additional data points to make the process safer. + ByteSize = DIE->getAttributeValueAsUnsignedConstant( + &U.getOrigUnit(), dwarf::DW_AT_byte_size, UINT64_MAX); + if (Tag != dwarf::DW_TAG_namespace || !Name) { + if (unsigned FileNum = DIE->getAttributeValueAsUnsignedConstant( + &U.getOrigUnit(), dwarf::DW_AT_decl_file, 0)) { + if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit( + &U.getOrigUnit())) { + // FIXME: dsymutil-classic compatibility. I'd rather not + // unique anything in anonymous namespaces, but if we do, then + // verify that the file and line correspond. + if (!Name && Tag == dwarf::DW_TAG_namespace) + FileNum = 1; + + // FIXME: Passing U.getOrigUnit().getCompilationDir() + // instead of "" would allow more uniquing, but for now, do + // it this way to match dsymutil-classic. + if (LT->getFileNameByIndex( + FileNum, "", + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, + File)) { + Line = DIE->getAttributeValueAsUnsignedConstant( + &U.getOrigUnit(), dwarf::DW_AT_decl_line, 0); +#ifdef HAVE_REALPATH + // Cache the resolved paths, because calling realpath is expansive. + if (const char *ResolvedPath = U.getResolvedPath(FileNum)) { + File = ResolvedPath; + } else { + char RealPath[PATH_MAX + 1]; + RealPath[PATH_MAX] = 0; + if (::realpath(File.c_str(), RealPath)) + File = RealPath; + U.setResolvedPath(FileNum, File); + } +#endif + FileRef = StringPool.internString(File); + } + } + } + } + + if (!Line && NameRef.empty()) + return PointerIntPair<DeclContext *, 1>(nullptr); + + // FIXME: dsymutil-classic compat won't unique the same type + // presented once as a struct and once as a class. Use the Tag in + // the fully qualified name hash to get the same effect. + // We hash NameRef, which is the mangled name, in order to get most + // overloaded functions resolvec correctly. + unsigned Hash = hash_combine(Context.getQualifiedNameHash(), Tag, NameRef); + + // FIXME: dsymutil-classic compatibility: when we don't have a name, + // use the filename. + if (Tag == dwarf::DW_TAG_namespace && NameRef == "(anonymous namespace)") + Hash = hash_combine(Hash, FileRef); + + // Now look if this context already exists. + DeclContext Key(Hash, Line, ByteSize, Tag, NameRef, FileRef, Context); + auto ContextIter = Contexts.find(&Key); + + if (ContextIter == Contexts.end()) { + // The context wasn't found. + bool Inserted; + DeclContext *NewContext = + new (Allocator) DeclContext(Hash, Line, ByteSize, Tag, NameRef, FileRef, + Context, DIE, U.getUniqueID()); + std::tie(ContextIter, Inserted) = Contexts.insert(NewContext); + assert(Inserted && "Failed to insert DeclContext"); + (void)Inserted; + } else if (Tag != dwarf::DW_TAG_namespace && + !(*ContextIter)->setLastSeenDIE(U, DIE)) { + // The context was found, but it is ambiguous with another context + // in the same file. Mark it invalid. + return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1); + } + + assert(ContextIter != Contexts.end()); + // FIXME: dsymutil-classic compatibility. Union types aren't + // uniques, but their children might be. + if ((Tag == dwarf::DW_TAG_subprogram && + Context.getTag() != dwarf::DW_TAG_structure_type && + Context.getTag() != dwarf::DW_TAG_class_type) || + (Tag == dwarf::DW_TAG_union_type)) + return PointerIntPair<DeclContext *, 1>(*ContextIter, /* Invalid= */ 1); + + return PointerIntPair<DeclContext *, 1>(*ContextIter); +} + /// \brief Get the potential name and mangled name for the entity /// described by \p Die and store them in \Info if they are not /// already there. @@ -1355,14 +1735,30 @@ bool DwarfLinker::createStreamer(Triple TheTriple, StringRef OutputFilename) { /// \brief Recursive helper to gather the child->parent relationships in the /// original compile unit. static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE, - unsigned ParentIdx, CompileUnit &CU) { + unsigned ParentIdx, CompileUnit &CU, + DeclContext *CurrentDeclContext, + NonRelocatableStringpool &StringPool, + DeclContextTree &Contexts) { unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE); - CU.getInfo(MyIdx).ParentIdx = ParentIdx; + CompileUnit::DIEInfo &Info = CU.getInfo(MyIdx); + + Info.ParentIdx = ParentIdx; + if (CU.hasODR()) { + if (CurrentDeclContext) { + auto PtrInvalidPair = Contexts.getChildDeclContext(*CurrentDeclContext, + DIE, CU, StringPool); + CurrentDeclContext = PtrInvalidPair.getPointer(); + Info.Ctxt = + PtrInvalidPair.getInt() ? nullptr : PtrInvalidPair.getPointer(); + } else + Info.Ctxt = CurrentDeclContext = nullptr; + } if (DIE->hasChildren()) for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL(); Child = Child->getSibling()) - gatherDIEParents(Child, MyIdx, CU); + gatherDIEParents(Child, MyIdx, CU, CurrentDeclContext, StringPool, + Contexts); } static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) { @@ -1380,6 +1776,12 @@ static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) { llvm_unreachable("Invalid Tag"); } +static unsigned getRefAddrSize(const DWARFUnit &U) { + if (U.getVersion() == 2) + return U.getAddressByteSize(); + return 4; +} + void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) { Units.reserve(Dwarf.getNumCompileUnits()); NextValidReloc = 0; @@ -1686,15 +2088,16 @@ unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE, void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE, CompileUnit::DIEInfo &MyInfo, const DebugMapObject &DMO, - CompileUnit &CU, unsigned Flags) { + CompileUnit &CU, bool UseODR) { const DWARFUnit &Unit = CU.getOrigUnit(); MyInfo.Keep = true; // First mark all the parent chain as kept. unsigned AncestorIdx = MyInfo.ParentIdx; while (!CU.getInfo(AncestorIdx).Keep) { + unsigned ODRFlag = UseODR ? TF_ODR : 0; lookForDIEsToKeep(*Unit.getDIEAtIndex(AncestorIdx), DMO, CU, - TF_ParentWalk | TF_Keep | TF_DependencyWalk); + TF_ParentWalk | TF_Keep | TF_DependencyWalk | ODRFlag); AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx; } @@ -1715,9 +2118,27 @@ void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE, Val.extractValue(Data, &Offset, &Unit); CompileUnit *ReferencedCU; - if (const auto *RefDIE = resolveDIEReference(Val, Unit, DIE, ReferencedCU)) + if (const auto *RefDIE = + resolveDIEReference(Val, Unit, DIE, ReferencedCU)) { + uint32_t RefIdx = ReferencedCU->getOrigUnit().getDIEIndex(RefDIE); + CompileUnit::DIEInfo &Info = ReferencedCU->getInfo(RefIdx); + // If the referenced DIE has a DeclContext that has already been + // emitted, then do not keep the one in this CU. We'll link to + // the canonical DIE in cloneDieReferenceAttribute. + // FIXME: compatibility with dsymutil-classic. UseODR shouldn't + // be necessary and could be advantageously replaced by + // ReferencedCU->hasODR() && CU.hasODR(). + // FIXME: compatibility with dsymutil-classic. There is no + // reason not to unique ref_addr references. + if (AttrSpec.Form != dwarf::DW_FORM_ref_addr && UseODR && Info.Ctxt && + Info.Ctxt != ReferencedCU->getInfo(Info.ParentIdx).Ctxt && + Info.Ctxt->getCanonicalDIEOffset() && isODRAttribute(AttrSpec.Attr)) + continue; + + unsigned ODRFlag = UseODR ? TF_ODR : 0; lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU, - TF_Keep | TF_DependencyWalk); + TF_Keep | TF_DependencyWalk | ODRFlag); + } } } @@ -1752,9 +2173,10 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE, Flags = shouldKeepDIE(DIE, CU, MyInfo, Flags); // If it is a newly kept DIE mark it as well as all its dependencies as kept. - if (!AlreadyKept && (Flags & TF_Keep)) - keepDIEAndDenpendencies(DIE, MyInfo, DMO, CU, Flags); - + if (!AlreadyKept && (Flags & TF_Keep)) { + bool UseOdr = (Flags & TF_DependencyWalk) ? (Flags & TF_ODR) : CU.hasODR(); + keepDIEAndDenpendencies(DIE, MyInfo, DMO, CU, UseOdr); + } // The TF_ParentWalk flag tells us that we are currently walking up // the parent chain of a required DIE, and we don't want to mark all // the children of the parents as kept (consider for example a @@ -1823,24 +2245,34 @@ unsigned DwarfLinker::cloneDieReferenceAttribute( DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val, CompileUnit &Unit) { - uint32_t Ref = *Val.getAsReference(&Unit.getOrigUnit()); + const DWARFUnit &U = Unit.getOrigUnit(); + uint32_t Ref = *Val.getAsReference(&U); DIE *NewRefDie = nullptr; CompileUnit *RefUnit = nullptr; - const DWARFDebugInfoEntryMinimal *RefDie = nullptr; - - if (!(RefUnit = getUnitForOffset(Ref)) || - !(RefDie = RefUnit->getOrigUnit().getDIEForOffset(Ref))) { - const char *AttributeString = dwarf::AttributeString(AttrSpec.Attr); - if (!AttributeString) - AttributeString = "DW_AT_???"; - reportWarning(Twine("Missing DIE for ref in attribute ") + AttributeString + - ". Dropping.", - &Unit.getOrigUnit(), &InputDIE); + DeclContext *Ctxt = nullptr; + + const DWARFDebugInfoEntryMinimal *RefDie = + resolveDIEReference(Val, U, InputDIE, RefUnit); + + // If the referenced DIE is not found, drop the attribute. + if (!RefDie) return 0; - } unsigned Idx = RefUnit->getOrigUnit().getDIEIndex(RefDie); CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(Idx); + + // If we already have emitted an equivalent DeclContext, just point + // at it. + if (isODRAttribute(AttrSpec.Attr)) { + Ctxt = RefInfo.Ctxt; + if (Ctxt && Ctxt->getCanonicalDIEOffset()) { + DIEInteger Attr(Ctxt->getCanonicalDIEOffset()); + Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), + dwarf::DW_FORM_ref_addr, Attr); + return getRefAddrSize(U); + } + } + if (!RefInfo.Clone) { assert(Ref > InputDIE.getOffset()); // We haven't cloned this DIE yet. Just create an empty one and @@ -1849,7 +2281,8 @@ unsigned DwarfLinker::cloneDieReferenceAttribute( } NewRefDie = RefInfo.Clone; - if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) { + if (AttrSpec.Form == dwarf::DW_FORM_ref_addr || + (Unit.hasODR() && isODRAttribute(AttrSpec.Attr))) { // We cannot currently rely on a DIEEntry to emit ref_addr // references, because the implementation calls back to DwarfDebug // to find the unit offset. (We don't have a DwarfDebug) @@ -1867,11 +2300,11 @@ unsigned DwarfLinker::cloneDieReferenceAttribute( // A forward reference. Note and fixup later. Attr = 0xBADDEF; Unit.noteForwardReference( - NewRefDie, RefUnit, + NewRefDie, RefUnit, Ctxt, Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_ref_addr, DIEInteger(Attr))); } - return AttrSize; + return getRefAddrSize(U); } Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), @@ -2150,6 +2583,14 @@ DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, Die = Info.Clone = DIE::get(DIEAlloc, dwarf::Tag(InputDIE.getTag())); assert(Die->getTag() == InputDIE.getTag()); Die->setOffset(OutOffset); + if (Unit.hasODR() && Die->getTag() != dwarf::DW_TAG_namespace && Info.Ctxt && + Info.Ctxt != Unit.getInfo(Info.ParentIdx).Ctxt && + !Info.Ctxt->getCanonicalDIEOffset()) { + // We are about to emit a DIE that is the root of its own valid + // DeclContext tree. Make the current offset the canonical offset + // for this context. + Info.Ctxt->setCanonicalDIEOffset(OutOffset + Unit.getStartOffset()); + } // Extract and clone every attribute. DataExtractor Data = U.getDebugInfoExtractor(); @@ -2611,8 +3052,9 @@ bool DwarfLinker::link(const DebugMap &Map) { outs() << "Input compilation unit:"; CUDie->dump(outs(), CU.get(), 0); } - Units.emplace_back(*CU, UnitID++); - gatherDIEParents(CUDie, 0, Units.back()); + Units.emplace_back(*CU, UnitID++, !Options.NoODR); + gatherDIEParents(CUDie, 0, Units.back(), &ODRContexts.getRoot(), + StringPool, ODRContexts); } // Then mark all the DIEs that need to be present in the linked diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp index 50091935a44..f063fb514df 100644 --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -47,6 +47,11 @@ static opt<bool> desc("Do the link in memory, but do not emit the result file."), init(false)); +static opt<bool> + NoODR("no-odr", + desc("Do not use ODR (One Definition Rule) for type uniquing."), + init(false)); + static opt<bool> DumpDebugMap( "dump-debug-map", desc("Parse and dump the debug map to standard output. Not DWARF link " @@ -71,6 +76,7 @@ int main(int argc, char **argv) { Options.Verbose = Verbose; Options.NoOutput = NoOutput; + Options.NoODR = NoODR; llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); diff --git a/llvm/tools/dsymutil/dsymutil.h b/llvm/tools/dsymutil/dsymutil.h index 40891877983..cd530a1177a 100644 --- a/llvm/tools/dsymutil/dsymutil.h +++ b/llvm/tools/dsymutil/dsymutil.h @@ -27,6 +27,7 @@ namespace dsymutil { struct LinkOptions { bool Verbose; ///< Verbosity bool NoOutput; ///< Skip emitting output + bool NoODR; ///< Do not unique types according to ODR LinkOptions() : Verbose(false), NoOutput(false) {} }; |