Skip to content
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

[lldb] Skip declaration DIEs in the debug_names index #94744

Merged
merged 1 commit into from
Jun 11, 2024

Conversation

labath
Copy link
Collaborator

@labath labath commented Jun 7, 2024

This makes sure we try to process declaration DIEs that are erroneously present in the index. Until bd5c636, clang was emitting index entries for declaration DIEs with DW_AT_signature attributes. This makes sure to avoid returning those DIEs as the definitions of a type, but also makes sure to pass through DIEs referring to static constexpr member variables, which is a (probably nonconforming) extension used by dsymutil.

It adds test cases for both of the scenarios. It is essentially a recommit of #91808.

This makes sure we try to process declaration DIEs that are erroneously
present in the index. Until bd5c636, clang was emitting index
entries for declaration DIEs with DW_AT_signature attributes. This makes
sure to avoid returning those DIEs as the definitions of a type, but
also makes sure to pass through DIEs referring to static constexpr
member variables, which is a (probably nonconforming) extension used by
dsymutil.

It adds test cases for both of the scenarios. It is essentially a
recommit of llvm#91808.
@llvmbot
Copy link
Collaborator

llvmbot commented Jun 7, 2024

@llvm/pr-subscribers-lldb

Author: Pavel Labath (labath)

Changes

This makes sure we try to process declaration DIEs that are erroneously present in the index. Until bd5c636, clang was emitting index entries for declaration DIEs with DW_AT_signature attributes. This makes sure to avoid returning those DIEs as the definitions of a type, but also makes sure to pass through DIEs referring to static constexpr member variables, which is a (probably nonconforming) extension used by dsymutil.

It adds test cases for both of the scenarios. It is essentially a recommit of #91808.


Patch is 26.03 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/94744.diff

3 Files Affected:

  • (modified) lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp (+5)
  • (added) lldb/test/Shell/SymbolFile/DWARF/x86/debug-names-signature.s (+265)
  • (added) lldb/test/Shell/SymbolFile/DWARF/x86/debug-names-static-constexpr-member.s (+169)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
index 90e42be7202d8..1d17f20670eed 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DebugNamesDWARFIndex.cpp
@@ -85,6 +85,11 @@ bool DebugNamesDWARFIndex::ProcessEntry(
   DWARFDIE die = GetDIE(entry);
   if (!die)
     return true;
+  // Clang used to erroneously emit index entries for declaration DIEs in case
+  // when the definition is in a type unit (llvm.org/pr77696).
+  if (die.IsStructUnionOrClass() &&
+      die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0))
+    return true;
   return callback(die);
 }
 
diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-names-signature.s b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-names-signature.s
new file mode 100644
index 0000000000000..7b845a72bbed4
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-names-signature.s
@@ -0,0 +1,265 @@
+## Test that we can correctly complete types even if the debug_names index
+## contains entries referring to declaration dies (clang emitted entries like
+## that until bd5c6367bd7).
+##
+## This test consists of two compile units and one type unit. CU1 has the
+## definition of a variable, but only a forward-declaration of its type. When
+## attempting to find a definition, the debug_names lookup will return the DIE
+## in CU0, which is also a forward-declaration (with a reference to a type
+## unit). LLDB needs to find the definition of the type within the type unit.
+
+# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj %s > %t
+# RUN: %lldb %t -o "target variable s" -o exit | FileCheck %s
+
+# CHECK:      (lldb) target variable s
+# CHECK-NEXT: (Struct) s = (member = 47)
+
+        .data
+        .p2align        2, 0x0
+        .long   0
+s:
+        .long   47                              # 0x2f
+
+        .section        .debug_abbrev,"",@progbits
+        .byte   1                               # Abbreviation Code
+        .byte   65                              # DW_TAG_type_unit
+        .byte   1                               # DW_CHILDREN_yes
+        .byte   19                              # DW_AT_language
+        .byte   5                               # DW_FORM_data2
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   2                               # Abbreviation Code
+        .byte   19                              # DW_TAG_structure_type
+        .byte   1                               # DW_CHILDREN_yes
+        .byte   54                              # DW_AT_calling_convention
+        .byte   11                              # DW_FORM_data1
+        .byte   3                               # DW_AT_name
+        .byte   14                              # DW_FORM_strp
+        .byte   11                              # DW_AT_byte_size
+        .byte   11                              # DW_FORM_data1
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   3                               # Abbreviation Code
+        .byte   13                              # DW_TAG_member
+        .byte   0                               # DW_CHILDREN_no
+        .byte   3                               # DW_AT_name
+        .byte   14                              # DW_FORM_strp
+        .byte   73                              # DW_AT_type
+        .byte   19                              # DW_FORM_ref4
+        .byte   56                              # DW_AT_data_member_location
+        .byte   11                              # DW_FORM_data1
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   4                               # Abbreviation Code
+        .byte   36                              # DW_TAG_base_type
+        .byte   0                               # DW_CHILDREN_no
+        .byte   3                               # DW_AT_name
+        .byte   14                              # DW_FORM_strp
+        .byte   62                              # DW_AT_encoding
+        .byte   11                              # DW_FORM_data1
+        .byte   11                              # DW_AT_byte_size
+        .byte   11                              # DW_FORM_data1
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   5                               # Abbreviation Code
+        .byte   17                              # DW_TAG_compile_unit
+        .byte   1                               # DW_CHILDREN_yes
+        .byte   37                              # DW_AT_producer
+        .byte   8                               # DW_FORM_string
+        .byte   19                              # DW_AT_language
+        .byte   5                               # DW_FORM_data2
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   6                               # Abbreviation Code
+        .byte   52                              # DW_TAG_variable
+        .byte   0                               # DW_CHILDREN_no
+        .byte   3                               # DW_AT_name
+        .byte   14                              # DW_FORM_strp
+        .byte   73                              # DW_AT_type
+        .byte   19                              # DW_FORM_ref4
+        .byte   2                               # DW_AT_location
+        .byte   24                              # DW_FORM_exprloc
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   7                               # Abbreviation Code
+        .byte   19                              # DW_TAG_structure_type
+        .byte   0                               # DW_CHILDREN_no
+        .byte   60                              # DW_AT_declaration
+        .byte   25                              # DW_FORM_flag_present
+        .byte   105                             # DW_AT_signature
+        .byte   32                              # DW_FORM_ref_sig8
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   8                               # Abbreviation Code
+        .byte   19                              # DW_TAG_structure_type
+        .byte   0                               # DW_CHILDREN_no
+        .byte   3                               # DW_AT_name
+        .byte   14                              # DW_FORM_strp
+        .byte   60                              # DW_AT_declaration
+        .byte   25                              # DW_FORM_flag_present
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   0                               # EOM(3)
+
+        .section        .debug_info,"",@progbits
+.Ltu_begin0:
+        .long   .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
+.Ldebug_info_start0:
+        .short  5                               # DWARF version number
+        .byte   2                               # DWARF Unit Type
+        .byte   8                               # Address Size (in bytes)
+        .long   .debug_abbrev                   # Offset Into Abbrev. Section
+        .quad   4878254330033667422             # Type Signature
+        .long   .LStruct_def-.Ltu_begin0        # Type DIE Offset
+        .byte   1                               # Abbrev [1] 0x18:0x20 DW_TAG_type_unit
+        .short  33                              # DW_AT_language
+.LStruct_def:
+        .byte   2                               # Abbrev [2] 0x23:0x10 DW_TAG_structure_type
+        .byte   5                               # DW_AT_calling_convention
+        .long   .Linfo_string6                  # DW_AT_name
+        .byte   4                               # DW_AT_byte_size
+        .byte   3                               # Abbrev [3] 0x29:0x9 DW_TAG_member
+        .long   .Linfo_string4                  # DW_AT_name
+        .long   .Lint-.Ltu_begin0               # DW_AT_type
+        .byte   0                               # DW_AT_data_member_location
+        .byte   0                               # End Of Children Mark
+.Lint:
+        .byte   4                               # Abbrev [4] 0x33:0x4 DW_TAG_base_type
+        .long   .Linfo_string5                  # DW_AT_name
+        .byte   5                               # DW_AT_encoding
+        .byte   4                               # DW_AT_byte_size
+        .byte   0                               # End Of Children Mark
+.Ldebug_info_end0:
+
+.Lcu_begin0:
+        .long   .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit
+.Ldebug_info_start1:
+        .short  5                               # DWARF version number
+        .byte   1                               # DWARF Unit Type
+        .byte   8                               # Address Size (in bytes)
+        .long   .debug_abbrev                   # Offset Into Abbrev. Section
+        .byte   5                               # Abbrev [5] 0xc:0x27 DW_TAG_compile_unit
+        .asciz  "Hand-written DWARF"            # DW_AT_producer
+        .short  33                              # DW_AT_language
+.Ls:
+        .byte   6                               # Abbrev [6] 0x1e:0xb DW_TAG_variable
+        .long   .Linfo_string3                  # DW_AT_name
+        .long   .LStruct_decl2-.Lcu_begin0       # DW_AT_type
+        .byte   9                               # DW_AT_location
+        .byte   3
+        .quad   s
+.LStruct_decl2:
+        .byte   8                               # Abbrev [8] 0x29:0x9 DW_TAG_structure_type
+        .long   .Linfo_string6                  # DW_AT_name
+                                                # DW_AT_declaration
+        .byte   0                               # End Of Children Mark
+.Ldebug_info_end1:
+
+.Lcu_begin1:
+        .long   .Ldebug_info_end2-.Ldebug_info_start2 # Length of Unit
+.Ldebug_info_start2:
+        .short  5                               # DWARF version number
+        .byte   1                               # DWARF Unit Type
+        .byte   8                               # Address Size (in bytes)
+        .long   .debug_abbrev                   # Offset Into Abbrev. Section
+        .byte   5                               # Abbrev [5] 0xc:0x27 DW_TAG_compile_unit
+        .asciz  "Hand-written DWARF"            # DW_AT_producer
+        .short  33                              # DW_AT_language
+.LStruct_decl:
+        .byte   7                               # Abbrev [7] 0x29:0x9 DW_TAG_structure_type
+                                                # DW_AT_declaration
+        .quad   4878254330033667422             # DW_AT_signature
+        .byte   0                               # End Of Children Mark
+.Ldebug_info_end2:
+
+        .section        .debug_str,"MS",@progbits,1
+.Linfo_string3:
+        .asciz  "s"                             # string offset=60
+.Linfo_string4:
+        .asciz  "member"                        # string offset=62
+.Linfo_string5:
+        .asciz  "int"                           # string offset=69
+.Linfo_string6:
+        .asciz  "Struct"                        # string offset=73
+
+        .section        .debug_names,"",@progbits
+        .long   .Lnames_end0-.Lnames_start0     # Header: unit length
+.Lnames_start0:
+        .short  5                               # Header: version
+        .short  0                               # Header: padding
+        .long   2                               # Header: compilation unit count
+        .long   1                               # Header: local type unit count
+        .long   0                               # Header: foreign type unit count
+        .long   0                               # Header: bucket count
+        .long   3                               # Header: name count
+        .long   .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size
+        .long   8                               # Header: augmentation string size
+        .ascii  "LLVM0700"                      # Header: augmentation string
+        .long   .Lcu_begin0                     # Compilation unit 0
+        .long   .Lcu_begin1                     # Compilation unit 1
+        .long   .Ltu_begin0                     # Type unit 0
+        .long   .Linfo_string6                  # String in Bucket 0: Struct
+        .long   .Linfo_string3                  # String in Bucket 1: s
+        .long   .Linfo_string5                  # String in Bucket 2: int
+        .long   .Lnames1-.Lnames_entries0       # Offset in Bucket 0
+        .long   .Lnames2-.Lnames_entries0       # Offset in Bucket 1
+        .long   .Lnames0-.Lnames_entries0       # Offset in Bucket 2
+.Lnames_abbrev_start0:
+        .byte   1                               # Abbrev code
+        .byte   19                              # DW_TAG_structure_type
+        .byte   2                               # DW_IDX_type_unit
+        .byte   11                              # DW_FORM_data1
+        .byte   3                               # DW_IDX_die_offset
+        .byte   19                              # DW_FORM_ref4
+        .byte   0                               # End of abbrev
+        .byte   0                               # End of abbrev
+        .byte   2                               # Abbrev code
+        .byte   52                              # DW_TAG_variable
+        .byte   1                               # DW_IDX_compile_unit
+        .byte   11                              # DW_FORM_data1
+        .byte   3                               # DW_IDX_die_offset
+        .byte   19                              # DW_FORM_ref4
+        .byte   0                               # End of abbrev
+        .byte   0                               # End of abbrev
+        .byte   3                               # Abbrev code
+        .byte   36                              # DW_TAG_base_type
+        .byte   2                               # DW_IDX_type_unit
+        .byte   11                              # DW_FORM_data1
+        .byte   3                               # DW_IDX_die_offset
+        .byte   19                              # DW_FORM_ref4
+        .byte   0                               # End of abbrev
+        .byte   0                               # End of abbrev
+        .byte   4                               # Abbrev code
+        .byte   19                              # DW_TAG_structure_type
+        .byte   1                               # DW_IDX_compile_unit
+        .byte   11                              # DW_FORM_data1
+        .byte   3                               # DW_IDX_die_offset
+        .byte   19                              # DW_FORM_ref4
+        .byte   0                               # End of abbrev
+        .byte   0                               # End of abbrev
+        .byte   0                               # End of abbrev list
+.Lnames_abbrev_end0:
+.Lnames_entries0:
+.Lnames1:
+        .byte   4                               # Abbreviation code
+        .byte   1                               # DW_IDX_compile_unit
+        .long   .LStruct_decl-.Lcu_begin1       # DW_IDX_die_offset
+        .byte   1                               # Abbreviation code
+        .byte   0                               # DW_IDX_type_unit
+        .long   .LStruct_def-.Ltu_begin0        # DW_IDX_die_offset
+        .byte   0
+                                        # End of list: Struct
+.Lnames2:
+        .byte   2                               # Abbreviation code
+        .byte   0                               # DW_IDX_compile_unit
+        .long   .Ls-.Lcu_begin0                 # DW_IDX_die_offset
+        .byte   0
+                                        # End of list: s
+.Lnames0:
+        .byte   3                               # Abbreviation code
+        .byte   0                               # DW_IDX_type_unit
+        .long   .Lint-.Ltu_begin0               # DW_IDX_die_offset
+        .byte   0
+                                        # End of list: int
+        .p2align        2, 0x0
+.Lnames_end0:
diff --git a/lldb/test/Shell/SymbolFile/DWARF/x86/debug-names-static-constexpr-member.s b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-names-static-constexpr-member.s
new file mode 100644
index 0000000000000..9cb534207c3d1
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/x86/debug-names-static-constexpr-member.s
@@ -0,0 +1,169 @@
+## Check that lldb can locate a static constant variable when its declaration is
+## referenced by a debug_names index. This is a non-conforming extension used by
+## dsymutil.
+
+# RUN: llvm-mc -triple=x86_64-pc-linux -filetype=obj %s > %t
+# RUN: %lldb %t -o "target variable Class::constant" \
+# RUN:   -o "expr -l c++ -- Class::constant" -o exit | FileCheck %s
+
+# CHECK:      (lldb) target variable Class::constant
+# CHECK-NEXT: (const int) Class::constant = 47
+# CHECK:      (lldb) expr -l c++ -- Class::constant
+# CHECK-NEXT: (const int) $0 = 47
+
+        .section        .debug_abbrev,"",@progbits
+        .byte   1                               # Abbreviation Code
+        .byte   17                              # DW_TAG_compile_unit
+        .byte   1                               # DW_CHILDREN_yes
+        .byte   37                              # DW_AT_producer
+        .byte   8                               # DW_FORM_string
+        .byte   19                              # DW_AT_language
+        .byte   5                               # DW_FORM_data2
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   3                               # Abbreviation Code
+        .byte   2                               # DW_TAG_class_type
+        .byte   1                               # DW_CHILDREN_yes
+        .byte   54                              # DW_AT_calling_convention
+        .byte   11                              # DW_FORM_data1
+        .byte   3                               # DW_AT_name
+        .byte   14                              # DW_FORM_strp
+        .byte   11                              # DW_AT_byte_size
+        .byte   11                              # DW_FORM_data1
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   4                               # Abbreviation Code
+        .byte   52                              # DW_TAG_variable
+        .byte   0                               # DW_CHILDREN_no
+        .byte   3                               # DW_AT_name
+        .byte   14                              # DW_FORM_strp
+        .byte   73                              # DW_AT_type
+        .byte   19                              # DW_FORM_ref4
+        .byte   63                              # DW_AT_external
+        .byte   25                              # DW_FORM_flag_present
+        .byte   60                              # DW_AT_declaration
+        .byte   25                              # DW_FORM_flag_present
+        .byte   28                              # DW_AT_const_value
+        .byte   13                              # DW_FORM_sdata
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   5                               # Abbreviation Code
+        .byte   38                              # DW_TAG_const_type
+        .byte   0                               # DW_CHILDREN_no
+        .byte   73                              # DW_AT_type
+        .byte   19                              # DW_FORM_ref4
+        .byte   0                               # EOM(1)
+        .byte   0                               # EOM(2)
+        .byte   6                               # Abbreviation Code
+        .byte   36                              # DW_TAG_base_type
+        .byte   0                               # DW_CHILDREN_no
+        .byte   3                               # DW_AT_name
+      ...
[truncated]

@labath
Copy link
Collaborator Author

labath commented Jun 7, 2024

I should add that I'm pretty sure the index entries pointing to signature declaration DIEs were not the cause of crashes in @ZequanWu's PR, after creating the test case (what I think is the worst possible situation) and stepping through the code, I realized that these DIEs would get filtered out anyway on line DWARFIndex.cpp:126 (because GetDWARFDeclContext does not work on DW_AT_signature DIEs). Nonetheless, I think that this change makes sense because the fact that GetDWARFDeclContext is a bug that's probably preventing the correct lookup of types in some type unit scenarios. The check may very well become load-bearing if that function is fixed.

Copy link
Member

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

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

LGTM, thanks for the tests

@labath labath merged commit c0e1ad7 into llvm:main Jun 11, 2024
7 checks passed
@labath labath deleted the names-decl branch June 11, 2024 14:17
Copy link
Collaborator

@clayborg clayborg left a comment

Choose a reason for hiding this comment

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

LGTM.

@HerrCai0907 HerrCai0907 mentioned this pull request Jun 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants