Skip to content

[DebugInfo] Emit linkage name into DWARF for types for Swift #112802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 22, 2024

Conversation

augusto2112
Copy link
Contributor

@augusto2112 augusto2112 commented Oct 17, 2024

Store Swift mangled names in DW_AT_linkage_name. The Swift compiler
emits only the type mangled name in debug information, and LLDB uses
those mangled names as keys to look up size, alignment, fields, etc
from either reflection metadata or Swift modules.

Additionally, emit types linkage names for types into the accelerator
table if they exist and they're different from the display name.

@llvmbot
Copy link
Member

llvmbot commented Oct 17, 2024

@llvm/pr-subscribers-debuginfo

Author: Augusto Noronha (augusto2112)

Changes

Store Swift mangled names in DW_AT_linkage_name.

Additionally, emit types linkage names for types into the accelerator table if they exist and they're different from the display name.


Full diff: https://github.com/llvm/llvm-project/pull/112802.diff

4 Files Affected:

  • (modified) llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp (+14-4)
  • (modified) llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp (+14-6)
  • (added) llvm/test/DebugInfo/Generic/debug-names-accel-table-types.ll (+55)
  • (added) llvm/test/tools/dsymutil/debug-names-accel-table-types.test (+56)
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index e76b0fe2081c07..715968c335ca03 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -645,15 +645,21 @@ void DwarfUnit::updateAcceleratorTables(const DIScope *Context,
 
   // add temporary record for this type to be added later
 
-  bool IsImplementation = false;
+  unsigned Flags = 0;
   if (auto *CT = dyn_cast<DICompositeType>(Ty)) {
     // A runtime language of 0 actually means C/C++ and that any
     // non-negative value is some version of Objective-C/C++.
-    IsImplementation = CT->getRuntimeLang() == 0 || CT->isObjcClassComplete();
+    if (CT->getRuntimeLang() == 0 || CT->isObjcClassComplete())
+      Flags = dwarf::DW_FLAG_type_implementation;
   }
-  unsigned Flags = IsImplementation ? dwarf::DW_FLAG_type_implementation : 0;
+
   DD->addAccelType(*this, CUNode->getNameTableKind(), Ty->getName(), TyDIE,
-                   Flags);
+                   Flags);;;
+
+  if (auto *CT = dyn_cast<DICompositeType>(Ty))
+    if (Ty->getName() != CT->getIdentifier())
+      DD->addAccelType(*this, CUNode->getNameTableKind(), CT->getIdentifier(),
+                       TyDIE, Flags);
 
   addGlobalType(Ty, TyDIE, Context);
 }
@@ -1042,6 +1048,10 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
   if (!Name.empty())
     addString(Buffer, dwarf::DW_AT_name, Name);
 
+  // For Swift, mangled names are put into DW_AT_linkage_name.
+  if (CTy->getRuntimeLang() == dwarf::DW_LANG_Swift && CTy->getRawIdentifier())
+    addString(Buffer, dwarf::DW_AT_linkage_name, CTy->getIdentifier());
+
   addAnnotation(Buffer, CTy->getAnnotations());
 
   if (Tag == dwarf::DW_TAG_enumeration_type ||
diff --git a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
index 280d3f1861ff00..88bc494439f6cf 100644
--- a/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
+++ b/llvm/lib/DWARFLinker/Classic/DWARFLinker.cpp
@@ -1837,10 +1837,8 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
     Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
   } else if (Tag == dwarf::DW_TAG_imported_declaration && AttrInfo.Name) {
     Unit.addNamespaceAccelerator(Die, AttrInfo.Name);
-  } else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration &&
-             getDIENames(InputDIE, AttrInfo, DebugStrPool) && AttrInfo.Name &&
-             AttrInfo.Name.getString()[0]) {
-    uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit, File);
+  } else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration) {
+    bool Success = getDIENames(InputDIE, AttrInfo, DebugStrPool);
     uint64_t RuntimeLang =
         dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_runtime_class))
             .value_or(0);
@@ -1849,8 +1847,18 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE,
          RuntimeLang == dwarf::DW_LANG_ObjC_plus_plus) &&
         dwarf::toUnsigned(InputDIE.find(dwarf::DW_AT_APPLE_objc_complete_type))
             .value_or(0);
-    Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,
-                            Hash);
+    if (Success && AttrInfo.Name && AttrInfo.Name.getString()[0]) {
+      uint32_t Hash = hashFullyQualifiedName(InputDIE, Unit, File);
+      Unit.addTypeAccelerator(Die, AttrInfo.Name, ObjCClassIsImplementation,
+                              Hash);
+    }
+
+    if (Success && AttrInfo.MangledName &&
+        AttrInfo.MangledName != AttrInfo.Name) {
+      auto Hash = djbHash(AttrInfo.MangledName.getString().data());
+      Unit.addTypeAccelerator(Die, AttrInfo.MangledName,
+                              ObjCClassIsImplementation, Hash);
+    }
   }
 
   // Determine whether there are any children that we want to keep.
diff --git a/llvm/test/DebugInfo/Generic/debug-names-accel-table-types.ll b/llvm/test/DebugInfo/Generic/debug-names-accel-table-types.ll
new file mode 100644
index 00000000000000..e88afe1b4c5118
--- /dev/null
+++ b/llvm/test/DebugInfo/Generic/debug-names-accel-table-types.ll
@@ -0,0 +1,55 @@
+; RUN: %llc_dwarf -debugger-tune=lldb -accel-tables=Dwarf -filetype=obj -o %t < %s
+; RUN: llvm-dwarfdump %t | FileCheck %s
+; RUN: llvm-dwarfdump -debug-names %t | FileCheck --check-prefix=SAME-NAME %s
+; RUN: llvm-dwarfdump -debug-names %t | FileCheck --check-prefix=DIFFERENT-NAME %s
+; RUN: llvm-dwarfdump -debug-names %t | FileCheck --check-prefix=UNIQUE-DIFFERENT-NAME %s
+; RUN: llvm-dwarfdump -debug-names -verify %t | FileCheck --check-prefix=VERIFY %s
+
+
+; CHECK: DW_TAG_structure_type
+; CHECK: DW_AT_name ("SameName")
+; CHECK: DW_AT_linkage_name ("SameName")
+
+; CHECK: DW_TAG_structure_type
+; CHECK: DW_AT_name ("DifferentName")
+; CHECK: DW_AT_linkage_name ("UniqueDifferentName")
+
+; The name count should be 5 (the two variables, the two human readable names, one mangled name).
+; SAME-NAME: Name count: 5
+
+; The accelarator should only have one entry for the three following names.
+; SAME-NAME: "SameName" 
+; SAME-NAME-NOT: "SameName" 
+
+; DIFFERENT-NAME: "DifferentName"
+; DIFFERENT-NAME-NOT: "DifferentName"
+
+; UNIQUE-DIFFERENT-NAME: "UniqueDifferentName"
+; UNIQUE-DIFFERENT-NAME-NOT: "UniqueDifferentName"
+
+; Verification should succeed.
+; VERIFY: No errors.
+
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+@q = common global i8* null, align 8, !dbg !102
+@r = common global i8* null, align 8, !dbg !105
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!6, !7}
+
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, emissionKind: FullDebug, globals: !5)
+!3 = !DIFile(filename: "/tmp/p.c", directory: "/")
+!4 = !{}
+!5 = !{!102, !105}
+!6 = !{i32 2, !"Dwarf Version", i32 4}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+
+; marking the types as Swift is necessary because we only emit the linkage names for Swift types.
+!11 = !DICompositeType(tag: DW_TAG_structure_type, name: "SameName", file: !3, size: 64, runtimeLang: DW_LANG_Swift, identifier: "SameName")
+!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "DifferentName", file: !3, size: 64, runtimeLang: DW_LANG_Swift, identifier: "UniqueDifferentName")
+
+!102 = !DIGlobalVariableExpression(var: !103, expr: !DIExpression())
+!103 = distinct !DIGlobalVariable(name: "q", scope: !2, file: !3, line: 1, type: !11, isLocal: false, isDefinition: true)
+!104 = distinct !DIGlobalVariable(name: "r", scope: !2, file: !3, line: 1, type: !12, isLocal: false, isDefinition: true)
+!105 = !DIGlobalVariableExpression(var: !104, expr: !DIExpression())
diff --git a/llvm/test/tools/dsymutil/debug-names-accel-table-types.test b/llvm/test/tools/dsymutil/debug-names-accel-table-types.test
new file mode 100644
index 00000000000000..90cdaded8523a9
--- /dev/null
+++ b/llvm/test/tools/dsymutil/debug-names-accel-table-types.test
@@ -0,0 +1,56 @@
+; RUN: %llc_dwarf -debugger-tune=lldb -accel-tables=Dwarf -filetype=obj -o %t < %s
+; RUN: dsymutil %t -o %t.dSYM
+; RUN: llvm-dwarfdump %t | FileCheck %s
+; RUN: llvm-dwarfdump -debug-names %t | FileCheck --check-prefix=SAME-NAME %s
+; RUN: llvm-dwarfdump -debug-names %t | FileCheck --check-prefix=DIFFERENT-NAME %s
+; RUN: llvm-dwarfdump -debug-names %t | FileCheck --check-prefix=UNIQUE-DIFFERENT-NAME %s
+; RUN: llvm-dwarfdump -debug-names -verify %t | FileCheck --check-prefix=VERIFY %s
+
+
+; CHECK: DW_TAG_structure_type
+; CHECK: DW_AT_name ("SameName")
+; CHECK: DW_AT_linkage_name ("SameName")
+
+; CHECK: DW_TAG_structure_type
+; CHECK: DW_AT_name ("DifferentName")
+; CHECK: DW_AT_linkage_name ("UniqueDifferentName")
+
+; The name count should be 5 (the two variables, the two human readable names, one mangled name).
+; SAME-NAME: Name count: 5
+
+; The accelarator should only have one entry for the three following names.
+; SAME-NAME: "SameName" 
+; SAME-NAME-NOT: "SameName" 
+
+; DIFFERENT-NAME: "DifferentName"
+; DIFFERENT-NAME-NOT: "DifferentName"
+
+; UNIQUE-DIFFERENT-NAME: "UniqueDifferentName"
+; UNIQUE-DIFFERENT-NAME-NOT: "UniqueDifferentName"
+
+; Verification should succeed.
+; VERIFY: No errors.
+
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+@q = common global i8* null, align 8, !dbg !102
+@r = common global i8* null, align 8, !dbg !105
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!6, !7}
+
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, emissionKind: FullDebug, globals: !5)
+!3 = !DIFile(filename: "/tmp/p.c", directory: "/")
+!4 = !{}
+!5 = !{!102, !105}
+!6 = !{i32 2, !"Dwarf Version", i32 4}
+!7 = !{i32 2, !"Debug Info Version", i32 3}
+
+; marking the types as Swift is necessary because we only emit the linkage names for Swift types.
+!11 = !DICompositeType(tag: DW_TAG_structure_type, name: "SameName", file: !3, size: 64, runtimeLang: DW_LANG_Swift, identifier: "SameName")
+!12 = !DICompositeType(tag: DW_TAG_structure_type, name: "DifferentName", file: !3, size: 64, runtimeLang: DW_LANG_Swift, identifier: "UniqueDifferentName")
+
+!102 = !DIGlobalVariableExpression(var: !103, expr: !DIExpression())
+!103 = distinct !DIGlobalVariable(name: "q", scope: !2, file: !3, line: 1, type: !11, isLocal: false, isDefinition: true)
+!104 = distinct !DIGlobalVariable(name: "r", scope: !2, file: !3, line: 1, type: !12, isLocal: false, isDefinition: true)
+!105 = !DIGlobalVariableExpression(var: !104, expr: !DIExpression())

Copy link

github-actions bot commented Oct 17, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@dwblaikie
Copy link
Collaborator

Out of curiosity: what's the need/use case?

@augusto2112
Copy link
Contributor Author

Out of curiosity: what's the need/use case?

We use the mangled names to find type information both in Swift metadata and Swift modules.

@augusto2112
Copy link
Contributor Author

Out of curiosity: what's the need/use case?

To expand a bit on this: the Swift compiler emits only the type mangled name in debug information, and LLDB uses those mangled names as keys to look up size, alignment, fields, etc from either reflection metadata or Swift modules.

The compiler also have a separate mode where it emits more full debug information so LLDB doesn't need to rely on in reflection metadata/Swift modules existing (that's related to my other "number of extra inhabitants" patch).

@dwblaikie
Copy link
Collaborator

Out of curiosity: what's the need/use case?

To expand a bit on this: the Swift compiler emits only the type mangled name in debug information, and LLDB uses those mangled names as keys to look up size, alignment, fields, etc from either reflection metadata or Swift modules.

so why is this code change needed? Because up until now the mangled name has been put in DW_AT_name, so didn't need LLVM-side support? Or it's been in downstream patches that are being upstreamed? It'd be good to know about what's new/different/etc to add this change now (even if it's just "we've been doing this downstream for a while, and now have time to upstream it" (in which case a bit of info about the original decision that added the functionality would be handy too - but I think you've mostly covered that in this comment, perhaps))

@augusto2112
Copy link
Contributor Author

so why is this code change needed? Because up until now the mangled name has been put in DW_AT_name, so didn't need LLVM-side support? Or it's been in downstream patches that are being upstreamed? It'd be good to know about what's new/different/etc to add this change now (even if it's just "we've been doing this downstream for a while, and now have time to upstream it" (in which case a bit of info about the original decision that added the functionality would be handy too - but I think you've mostly covered that in this comment, perhaps))

Right, emitting linkage names for types has been downstream for a really long time. Emitting the type linkage names into accelerator tables is new behavior, which is needed to do global searches by linkage names (I'll have another patch soon on the LLDB side to support FindTypes optionally looking types up by linkage name).

@augusto2112 augusto2112 force-pushed the swift-link-name-accel-table branch from c5ad77c to e2a5a66 Compare October 18, 2024 18:31
@augusto2112
Copy link
Contributor Author

I've updated the commit message to explain why we'd want type mangled names in DWARF.

Copy link
Collaborator

@dwblaikie dwblaikie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM

@augusto2112
Copy link
Contributor Author

I've restricted emitting linkage names into accelerator tables to Swift only since some tests were failing it should be the only language (as far as I'm aware) that uses mangled names for types pervasively anyway.

I can also keep it generic and update the tests.

@dwblaikie
Copy link
Collaborator

I've restricted emitting linkage names into accelerator tables to Swift only since some tests were failing it should be the only language (as far as I'm aware) that uses mangled names for types pervasively anyway.

The identifier field is used for any producer that wants to deduplicate type information - either in LTO at the LLVM IR level, or also in the DWARF (using DWARF type units) at the (ELF only, I think) object level. So, yeah, reusing it for a fairly different debugger interaction probably needs to be restricted to Swift - but also may present complications for Swift on ELF, since it might confuse the two signals/uses of the identifier field... not sure what, if anything, to do about that.

Store Swift mangled names in DW_AT_linkage_name. The Swift compiler
emits only the type mangled name in debug information, and LLDB uses
those mangled names as keys to look up size, alignment, fields, etc
from either reflection metadata or Swift modules.

Additionally, emit types linkage names for types into the accelerator
table if they exist and they're different from the display name.
@augusto2112 augusto2112 force-pushed the swift-link-name-accel-table branch from 29e9a7b to 5141bea Compare October 21, 2024 22:17
@augusto2112 augusto2112 force-pushed the swift-link-name-accel-table branch 2 times, most recently from d09a187 to 6a63b7a Compare October 22, 2024 20:01
@augusto2112 augusto2112 force-pushed the swift-link-name-accel-table branch from 6a63b7a to ac85d19 Compare October 22, 2024 21:34
@augusto2112 augusto2112 merged commit 8234f8a into llvm:main Oct 22, 2024
8 checks passed
augusto2112 added a commit to augusto2112/llvm-project that referenced this pull request Oct 22, 2024
…2802)

Store Swift mangled names in DW_AT_linkage_name. The Swift compiler
emits only the type mangled name in debug information, and LLDB uses
those mangled names as keys to look up size, alignment, fields, etc
from either reflection metadata or Swift modules.

Additionally, emit types linkage names for types into the accelerator
table if they exist and they're different from the display name.

(cherry picked from commit 8234f8a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants