From 40f15935582f685326ff8e5c95e0f185ae1acd3c Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Fri, 3 Sep 2021 12:18:13 -0700 Subject: [PATCH] DebugInfo: Correct/improve type formatting (pointers to function types especially) This does add some extra superfluous whitespace (eg: "int *") intended to make the Simplified Template Names work easier - this makes the DIE-based names match more exactly the clang-generated names, so it's easier to identify cases that don't generate matching names. (arguably we could change clang to skip that whitespace or add some fuzzy matching to accommodate differences in certain whitespace - but this seemed easier and fairly low-impact) --- llvm/lib/DebugInfo/DWARF/DWARFDie.cpp | 143 ++++++++++++++++----- llvm/test/DebugInfo/MSP430/dwarf-basics.ll | 4 +- llvm/test/DebugInfo/X86/dwarfdump-allocatedVar.ll | 2 +- llvm/test/DebugInfo/X86/dwarfdump-associatedVar.ll | 2 +- llvm/test/DebugInfo/X86/tu-to-non-named-type.ll | 2 +- llvm/test/MC/WebAssembly/dwarfdump.ll | 12 +- llvm/test/MC/WebAssembly/dwarfdump64.ll | 6 +- llvm/test/tools/dsymutil/X86/dwarf5.test | 2 +- .../llvm-dwarfdump/X86/DW_AT_object_pointer.s | 2 +- .../tools/llvm-dwarfdump/X86/prettyprint_types.s | 50 +++++-- 10 files changed, 169 insertions(+), 56 deletions(-) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp index b3d361b..338f58d 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDie.cpp @@ -161,43 +161,114 @@ static void dumpArrayType(raw_ostream &OS, const DWARFDie &D) { } } -/// Recursively dump the DIE type name when applicable. -static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) { - if (!D.isValid()) - return; - +static void dumpTypeName(raw_ostream &OS, const DWARFDie &D, bool SkipFirstParamIfArtificial = false); +static DWARFDie dumpTypeNameBefore(raw_ostream &OS, DWARFDie D, bool *Word = nullptr); + +static void dumpPointerLikeTypeBefore(raw_ostream &OS, DWARFDie D, DWARFDie Inner, StringRef Ptr, bool *Word) { + bool SubWord; + dumpTypeNameBefore(OS, Inner, &SubWord); + bool NeedsParens = + Inner && (Inner.getTag() == llvm::dwarf::DW_TAG_subroutine_type || + Inner.getTag() == llvm::dwarf::DW_TAG_array_type); + if (NeedsParens) + OS << '('; + else if (SubWord) + OS << ' '; + OS << Ptr; + if (Word) + *Word = false; +} + +static DWARFDie dumpTypeNameBefore(raw_ostream &OS, DWARFDie D, bool *Word) { + if (!D) { + OS << "void"; + if (Word) + *Word = true; + return DWARFDie(); + } if (const char *Name = D.getName(DINameKind::LinkageName)) { OS << Name; - return; + if (Word) + *Word = true; + return DWARFDie(); } - // FIXME: We should have pretty printers per language. Currently we print - // everything as if it was C++ and fall back to the TAG type name. + DWARFDie Inner = D.getAttributeValueAsReferencedDie(DW_AT_type); const dwarf::Tag T = D.getTag(); switch (T) { - case DW_TAG_array_type: - case DW_TAG_pointer_type: - case DW_TAG_ptr_to_member_type: + case DW_TAG_pointer_type: { + dumpPointerLikeTypeBefore(OS, D, Inner, "*", Word); + break; + } + case DW_TAG_subroutine_type: { + bool SubWord; + dumpTypeNameBefore(OS, Inner, &SubWord); + if (SubWord) { + OS << ' '; + } + if (Word) + *Word = false; + break; + } + case DW_TAG_array_type: { + bool SubWord; + dumpTypeNameBefore(OS, Inner, &SubWord); + if (SubWord) + OS << ' '; + if (Word) + *Word = false; + break; + } case DW_TAG_reference_type: + dumpPointerLikeTypeBefore(OS, D, Inner, "&", Word); + break; case DW_TAG_rvalue_reference_type: - case DW_TAG_subroutine_type: + dumpPointerLikeTypeBefore(OS, D, Inner, "&&", Word); + break; + case DW_TAG_ptr_to_member_type: { + bool SubWord; + dumpTypeNameBefore(OS, Inner, &SubWord); + bool NeedsParens = + Inner && (Inner.getTag() == llvm::dwarf::DW_TAG_subroutine_type || + Inner.getTag() == llvm::dwarf::DW_TAG_array_type); + if (NeedsParens) + OS << '('; + else if (SubWord) + OS << ' '; + if (DWARFDie Cont = + D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) { + dumpTypeName(OS, Cont); + OS << "::"; + } + OS << "*"; + if (Word) + *Word = false; break; + } default: dumpTypeTagName(OS, T); + dumpTypeNameBefore(OS, Inner); + break; } + return Inner; +} - // Follow the DW_AT_type if possible. - DWARFDie TypeDie = D.getAttributeValueAsReferencedDie(DW_AT_type); - dumpTypeName(OS, TypeDie); - - switch (T) { +static void dumpTypeNameAfter(raw_ostream &OS, DWARFDie D, DWARFDie Inner, + bool SkipFirstParamIfArtificial = false) { + if (!D) + return; + switch(D.getTag()) { case DW_TAG_subroutine_type: { - if (!TypeDie) - OS << "void"; OS << '('; bool First = true; + bool RealFirst = true; for (const DWARFDie &C : D.children()) { if (C.getTag() == DW_TAG_formal_parameter) { + if (SkipFirstParamIfArtificial && RealFirst && + C.find(DW_AT_artificial)) { + RealFirst = false; + continue; + } if (!First) OS << ", "; First = false; @@ -211,28 +282,36 @@ static void dumpTypeName(raw_ostream &OS, const DWARFDie &D) { dumpArrayType(OS, D); break; } - case DW_TAG_pointer_type: - OS << '*'; - break; case DW_TAG_ptr_to_member_type: - if (DWARFDie Cont = - D.getAttributeValueAsReferencedDie(DW_AT_containing_type)) { - dumpTypeName(OS << ' ', Cont); - OS << "::"; - } - OS << '*'; - break; case DW_TAG_reference_type: - OS << '&'; - break; case DW_TAG_rvalue_reference_type: - OS << "&&"; + case DW_TAG_pointer_type: { + bool NeedsParens = + Inner && (Inner.getTag() == llvm::dwarf::DW_TAG_subroutine_type || + Inner.getTag() == llvm::dwarf::DW_TAG_array_type); + if (NeedsParens) + OS << ')'; + dumpTypeNameAfter(OS, Inner, D.getAttributeValueAsReferencedDie(DW_AT_type), + /*SkipFirstParamIfArtificial=*/D.getTag() == + DW_TAG_ptr_to_member_type); break; + } default: break; } } +/// Recursively dump the DIE type name when applicable. +static void dumpTypeName(raw_ostream &OS, const DWARFDie &D, bool SkipFirstParamIfArtificial) { + if (!D.isValid() || D.isNULL()) + return; + + // FIXME: We should have pretty printers per language. Currently we print + // everything as if it was C++ and fall back to the TAG type name. + DWARFDie Inner = dumpTypeNameBefore(OS, D); + dumpTypeNameAfter(OS, D, Inner, SkipFirstParamIfArtificial); +} + static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die, const DWARFAttribute &AttrValue, unsigned Indent, DIDumpOptions DumpOpts) { diff --git a/llvm/test/DebugInfo/MSP430/dwarf-basics.ll b/llvm/test/DebugInfo/MSP430/dwarf-basics.ll index d324472..592e3a5 100644 --- a/llvm/test/DebugInfo/MSP430/dwarf-basics.ll +++ b/llvm/test/DebugInfo/MSP430/dwarf-basics.ll @@ -56,7 +56,7 @@ ; CHECK: DW_AT_name ("p") ; CHECK: DW_AT_decl_file ("/tmp{{[/\\]}}dwarf-basics.c") ; CHECK: DW_AT_decl_line (5) -; CHECK: DW_AT_type (0x{{.*}} "X*") +; CHECK: DW_AT_type (0x{{.*}} "X *") ; CHECK: NULL @@ -81,7 +81,7 @@ ; CHECK: DW_TAG_member ; CHECK: DW_AT_name ("a") -; CHECK: DW_AT_type (0x{{.*}} "*") +; CHECK: DW_AT_type (0x{{.*}} "void *") ; CHECK: DW_AT_decl_file ("/tmp{{[/\\]}}dwarf-basics.c") ; CHECK: DW_AT_decl_line (2) ; CHECK: DW_AT_data_member_location (0) diff --git a/llvm/test/DebugInfo/X86/dwarfdump-allocatedVar.ll b/llvm/test/DebugInfo/X86/dwarfdump-allocatedVar.ll index 5636151..4a65078 100644 --- a/llvm/test/DebugInfo/X86/dwarfdump-allocatedVar.ll +++ b/llvm/test/DebugInfo/X86/dwarfdump-allocatedVar.ll @@ -8,7 +8,7 @@ ; CHECK: [[ALCDIE:0x.+]]: DW_TAG_variable ; CHECK: DW_AT_type ({{0x[0-9]+}} "logical") ; CHECK: [[LOCDIE:0x.+]]: DW_TAG_variable -; CHECK: DW_AT_type ({{0x[0-9]+}} "integer*") +; CHECK: DW_AT_type ({{0x[0-9]+}} "integer *") ; CHECK: DW_AT_artificial (true) ; CHECK: DW_TAG_variable ; CHECK: DW_AT_name ("arr") diff --git a/llvm/test/DebugInfo/X86/dwarfdump-associatedVar.ll b/llvm/test/DebugInfo/X86/dwarfdump-associatedVar.ll index eda7852..1039fad 100644 --- a/llvm/test/DebugInfo/X86/dwarfdump-associatedVar.ll +++ b/llvm/test/DebugInfo/X86/dwarfdump-associatedVar.ll @@ -8,7 +8,7 @@ ; CHECK: [[ALCDIE:0x.+]]: DW_TAG_variable ; CHECK: DW_AT_type ({{0x[0-9]+}} "logical") ; CHECK: [[LOCDIE:0x.+]]: DW_TAG_variable -; CHECK: DW_AT_type ({{0x[0-9]+}} "integer*") +; CHECK: DW_AT_type ({{0x[0-9]+}} "integer *") ; CHECK: DW_AT_artificial (true) ; CHECK: DW_TAG_variable ; CHECK: DW_AT_name ("arr") diff --git a/llvm/test/DebugInfo/X86/tu-to-non-named-type.ll b/llvm/test/DebugInfo/X86/tu-to-non-named-type.ll index 883bab1..095509f 100644 --- a/llvm/test/DebugInfo/X86/tu-to-non-named-type.ll +++ b/llvm/test/DebugInfo/X86/tu-to-non-named-type.ll @@ -11,7 +11,7 @@ ; CHECK-NOT: {{DW_TAG|NULL}} ; CHECK: DW_TAG_member ; CHECK-NEXT: DW_AT_name ("x") -; CHECK-NEXT: DW_AT_type ({{.*}} "int[1]" +; CHECK-NEXT: DW_AT_type ({{.*}} "int [1]" ; But make sure we still use a type unit for an anonymous type that still has a ; name for linkage purposes (due to being defined in a typedef). diff --git a/llvm/test/MC/WebAssembly/dwarfdump.ll b/llvm/test/MC/WebAssembly/dwarfdump.ll index 5383646..cb2e3e6 100644 --- a/llvm/test/MC/WebAssembly/dwarfdump.ll +++ b/llvm/test/MC/WebAssembly/dwarfdump.ll @@ -17,7 +17,7 @@ ; CHECK: 0x00000026: DW_TAG_variable ; CHECK-NEXT: DW_AT_name ("foo") -; CHECK-NEXT: DW_AT_type (0x00000037 "int*") +; CHECK-NEXT: DW_AT_type (0x00000037 "int *") ; CHECK-NEXT: DW_AT_external (true) ; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple{{[/\\]}}test.c") ; CHECK-NEXT: DW_AT_decl_line (4) @@ -33,14 +33,14 @@ ; CHECK: 0x00000043: DW_TAG_variable ; CHECK-NEXT: DW_AT_name ("ptr2") -; CHECK-NEXT: DW_AT_type (0x00000054 "void()*") +; CHECK-NEXT: DW_AT_type (0x00000054 "void (*)()") ; CHECK-NEXT: DW_AT_external (true) ; CHECK-NEXT: DW_AT_decl_file ("/usr/local/google/home/sbc/dev/wasm/simple{{[/\\]}}test.c") ; CHECK-NEXT: DW_AT_decl_line (5) ; CHECK-NEXT: DW_AT_location (DW_OP_addr 0x4) ; CHECK: 0x00000054: DW_TAG_pointer_type -; CHECK-NEXT: DW_AT_type (0x00000059 "void()") +; CHECK-NEXT: DW_AT_type (0x00000059 "void ()") ; CHECK: 0x00000059: DW_TAG_subroutine_type ; CHECK-NEXT: DW_AT_prototyped (true) @@ -70,7 +70,7 @@ ; SPLIT: 0x00000019: DW_TAG_variable ; SPLIT-NEXT: DW_AT_name ("foo") -; SPLIT-NEXT: DW_AT_type (0x00000024 "int*") +; SPLIT-NEXT: DW_AT_type (0x00000024 "int *") ; SPLIT-NEXT: DW_AT_external (true) ; SPLIT-NEXT: DW_AT_decl_file (0x01) ; SPLIT-NEXT: DW_AT_decl_line (4) @@ -86,14 +86,14 @@ ; SPLIT: 0x0000002d: DW_TAG_variable ; SPLIT-NEXT: DW_AT_name ("ptr2") -; SPLIT-NEXT: DW_AT_type (0x00000038 "void()*") +; SPLIT-NEXT: DW_AT_type (0x00000038 "void (*)()") ; SPLIT-NEXT: DW_AT_external (true) ; SPLIT-NEXT: DW_AT_decl_file (0x01) ; SPLIT-NEXT: DW_AT_decl_line (5) ; SPLIT-NEXT: DW_AT_location (DW_OP_GNU_addr_index 0x1) ; SPLIT: 0x00000038: DW_TAG_pointer_type -; SPLIT-NEXT: DW_AT_type (0x0000003d "void()") +; SPLIT-NEXT: DW_AT_type (0x0000003d "void ()") ; SPLIT: 0x0000003d: DW_TAG_subroutine_type ; SPLIT-NEXT: DW_AT_prototyped (true) diff --git a/llvm/test/MC/WebAssembly/dwarfdump64.ll b/llvm/test/MC/WebAssembly/dwarfdump64.ll index ff711ed..603f610 100644 --- a/llvm/test/MC/WebAssembly/dwarfdump64.ll +++ b/llvm/test/MC/WebAssembly/dwarfdump64.ll @@ -16,7 +16,7 @@ ; CHECK: 0x0000002a: DW_TAG_variable ; CHECK-NEXT: DW_AT_name [DW_FORM_strp] ("foo") -; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (0x0000003f "int*") +; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (0x0000003f "int *") ; CHECK-NEXT: DW_AT_external [DW_FORM_flag_present] (true) ; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] ("/usr/local/google/home/sbc/dev/wasm/simple{{[/\\]}}test.c") ; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] (4) @@ -32,14 +32,14 @@ ; CHECK: 0x0000004b: DW_TAG_variable ; CHECK-NEXT: DW_AT_name [DW_FORM_strp] ("ptr2") -; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (0x00000060 "void()*") +; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (0x00000060 "void (*)()") ; CHECK-NEXT: DW_AT_external [DW_FORM_flag_present] (true) ; CHECK-NEXT: DW_AT_decl_file [DW_FORM_data1] ("/usr/local/google/home/sbc/dev/wasm/simple{{[/\\]}}test.c") ; CHECK-NEXT: DW_AT_decl_line [DW_FORM_data1] (5) ; CHECK-NEXT: DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x8) ; CHECK: 0x00000060: DW_TAG_pointer_type -; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (0x00000065 "void()") +; CHECK-NEXT: DW_AT_type [DW_FORM_ref4] (0x00000065 "void ()") ; CHECK: 0x00000065: DW_TAG_subroutine_type ; CHECK-NEXT: DW_AT_prototyped [DW_FORM_flag_present] (true) diff --git a/llvm/test/tools/dsymutil/X86/dwarf5.test b/llvm/test/tools/dsymutil/X86/dwarf5.test index 3c36aac..a37b4f3 100644 --- a/llvm/test/tools/dsymutil/X86/dwarf5.test +++ b/llvm/test/tools/dsymutil/X86/dwarf5.test @@ -56,4 +56,4 @@ DWARF: DW_TAG_formal_parameter DWARF: DW_AT_name ("argv") DWARF: DW_AT_decl_file (0x00) DWARF: DW_AT_decl_line (7) -DWARF: DW_AT_type (0x0000009d "char**") +DWARF: DW_AT_type (0x0000009d "char **") diff --git a/llvm/test/tools/llvm-dwarfdump/X86/DW_AT_object_pointer.s b/llvm/test/tools/llvm-dwarfdump/X86/DW_AT_object_pointer.s index d9d212c..d94a377 100644 --- a/llvm/test/tools/llvm-dwarfdump/X86/DW_AT_object_pointer.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/DW_AT_object_pointer.s @@ -1,7 +1,7 @@ # RUN: llvm-mc %s -filetype obj -triple x86_64-apple-darwin -o %t.o # RUN: llvm-dwarfdump -diff %t.o | FileCheck %s -# CHECK: DW_AT_type ("A*") +# CHECK: DW_AT_type ("A *") # CHECK: DW_AT_specification ("A") # CHECK: DW_AT_object_pointer () diff --git a/llvm/test/tools/llvm-dwarfdump/X86/prettyprint_types.s b/llvm/test/tools/llvm-dwarfdump/X86/prettyprint_types.s index afeee4c..74e52c2 100644 --- a/llvm/test/tools/llvm-dwarfdump/X86/prettyprint_types.s +++ b/llvm/test/tools/llvm-dwarfdump/X86/prettyprint_types.s @@ -7,19 +7,22 @@ # CHECK: DW_AT_type{{.*}}"int" # pointer_type -# CHECK: DW_AT_type{{.*}}"int*" +# CHECK: DW_AT_type{{.*}}"int *" # reference_type -# CHECK: DW_AT_type{{.*}}"int&" +# CHECK: DW_AT_type{{.*}}"int &" # rvalue_reference_type -# CHECK: DW_AT_type{{.*}}"int&&" +# CHECK: DW_AT_type{{.*}}"int &&" # ptr_to_member_type # CHECK: DW_AT_type{{.*}}"int foo::*" +# ptr_to_member_type to a member function +# CHECK: DW_AT_type{{.*}}"void (foo::*)(int)" + # array_type -# CHECK: DW_AT_type{{.*}}"int +# CHECK: DW_AT_type{{.*}}"int{{ }} # Testing with a default lower bound of 0 and the following explicit bounds: # lower_bound(1) # CHECK-NOT: {{.}} @@ -45,14 +48,15 @@ # subroutine types -# CHECK: DW_AT_type{{.*}}"int()" -# CHECK: DW_AT_type{{.*}}"void(int)" -# CHECK: DW_AT_type{{.*}}"void(int, int)" +# CHECK: DW_AT_type{{.*}}"int ()" +# CHECK: DW_AT_type{{.*}}"void (int)" +# CHECK: DW_AT_type{{.*}}"void (int, int)" +# CHECK: DW_AT_type{{.*}}"void (*)(foo *, int)" # array_type with a language with a default lower bound of 1 instead of 0 and # an upper bound of 2. This describes an array with 2 elements (whereas with a # default lower bound of 0 it would be an array of 3 elements) -# CHECK: DW_AT_type{{.*}}"int[2]" +# CHECK: DW_AT_type{{.*}}"int [2]" .section .debug_str,"MS",@progbits,1 .Lint_name: @@ -188,6 +192,15 @@ .byte 0 # DW_CHILDREN_no .byte 0 # EOM(1) .byte 0 # EOM(2) + .byte 19 # Abbreviation Code + .byte 0x5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0x34 # DW_AT_artificial + .byte 0x19 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) .byte 0 # EOM(3) .section .debug_info,"",@progbits .Lcu_begin: @@ -213,10 +226,17 @@ .Lstruct_type: .byte 14 # DW_TAG_structure_type .long .Lfoo_name # DW_AT_name +.Lstruct_ptr_type: + .byte 4 # DW_TAG_pointer_type + .long .Lstruct_type - .Lcu_begin # DW_AT_type .Lptr_to_member_type: .byte 7 # DW_TAG_ptr_to_member_type .long .Lint_type - .Lcu_begin # DW_AT_type .long .Lstruct_type - .Lcu_begin # DW_AT_containing_type +.Lptr_to_member_type_function: + .byte 7 # DW_TAG_ptr_to_member_type + .long .Lsub_void_foo_int_type - .Lcu_begin # DW_AT_type + .long .Lstruct_type - .Lcu_begin # DW_AT_containing_type .Larray_type: .byte 8 # DW_TAG_array_type .long .Lint_type - .Lcu_begin # DW_AT_type @@ -252,6 +272,16 @@ .byte 17 # DW_TAG_formal_parameter .long .Lint_type - .Lcu_begin # DW_AT_type .byte 0 # End Of Children Mark +.Lsub_void_foo_int_type: + .byte 16 # DW_TAG_subroutine_type + .byte 19 # DW_TAG_formal_parameter + .long .Lstruct_ptr_type - .Lcu_begin # DW_AT_type + .byte 17 # DW_TAG_formal_parameter + .long .Lint_type - .Lcu_begin # DW_AT_type + .byte 0 # End Of Children Mark +.Lpointer_to_function_type: + .byte 4 # DW_TAG_pointer_type + .long .Lsub_void_foo_int_type - .Lcu_begin # DW_AT_type .byte 3 # DW_TAG_variable .long .Lint_type - .Lcu_begin # DW_AT_type @@ -264,6 +294,8 @@ .byte 3 # DW_TAG_variable .long .Lptr_to_member_type - .Lcu_begin # DW_AT_type .byte 3 # DW_TAG_variable + .long .Lptr_to_member_type_function - .Lcu_begin # DW_AT_type + .byte 3 # DW_TAG_variable .long .Larray_type - .Lcu_begin # DW_AT_type .byte 3 # DW_TAG_variable .long .Lsub_int_empty_type - .Lcu_begin # DW_AT_type @@ -271,6 +303,8 @@ .long .Lsub_void_int_type - .Lcu_begin # DW_AT_type .byte 3 # DW_TAG_variable .long .Lsub_void_int_int_type - .Lcu_begin # DW_AT_type + .byte 3 # DW_TAG_variable + .long .Lpointer_to_function_type - .Lcu_begin # DW_AT_type .byte 0 # End Of Children Mark .Lunit_end: .Lcu2_begin: -- 2.7.4