}
}
-/// 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;
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) {
; 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
; 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)
; 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")
; 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")
; 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).
; 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)
; 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)
; 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)
; 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)
; 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)
; 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)
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 **")
# 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 ()
# 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: {{.}}
# 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:
.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:
.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
.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
.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
.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: