diff options
-rw-r--r-- | llvm/lib/DWARFLinker/DWARFLinker.cpp | 5 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/Inputs/inlined-static-variable/4.o | bin | 0 -> 3352 bytes | |||
-rw-r--r-- | llvm/test/tools/dsymutil/X86/dead-stripped.cpp | 37 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/X86/dummy-debug-map.map | 5 | ||||
-rw-r--r-- | llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp | 59 |
5 files changed, 91 insertions, 15 deletions
diff --git a/llvm/lib/DWARFLinker/DWARFLinker.cpp b/llvm/lib/DWARFLinker/DWARFLinker.cpp index 022a6a4cb973..ad351eb9d7ce 100644 --- a/llvm/lib/DWARFLinker/DWARFLinker.cpp +++ b/llvm/lib/DWARFLinker/DWARFLinker.cpp @@ -1423,6 +1423,11 @@ DIE *DWARFLinker::DIECloner::cloneDIE(const DWARFDie &InputDIE, Flags |= TF_InFunctionScope; if (!Info.InDebugMap && LLVM_LIKELY(!Update)) Flags |= TF_SkipPC; + } else if (Abbrev->getTag() == dwarf::DW_TAG_variable) { + // Function-local globals could be in the debug map even when the function + // is not, e.g., inlined functions. + if ((Flags & TF_InFunctionScope) && Info.InDebugMap) + Flags &= ~TF_SkipPC; } for (const auto &AttrSpec : Abbrev->attributes()) { diff --git a/llvm/test/tools/dsymutil/Inputs/inlined-static-variable/4.o b/llvm/test/tools/dsymutil/Inputs/inlined-static-variable/4.o Binary files differnew file mode 100644 index 000000000000..cec573c89789 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/inlined-static-variable/4.o diff --git a/llvm/test/tools/dsymutil/X86/dead-stripped.cpp b/llvm/test/tools/dsymutil/X86/dead-stripped.cpp index 8ec1c85a661f..16bbbd672d6d 100644 --- a/llvm/test/tools/dsymutil/X86/dead-stripped.cpp +++ b/llvm/test/tools/dsymutil/X86/dead-stripped.cpp @@ -1,4 +1,4 @@ -// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | FileCheck %s +// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/dead-stripped -o - | llvm-dwarfdump - --debug-info | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" // The test was compiled with: // clang++ -O2 -g -c dead-strip.cpp -o 1.o @@ -8,22 +8,23 @@ // that are still present in the linked debug info (in this case because // they have been DW_TAG_import'd in another namespace). -// Everything in the N namespace bellow doesn't have a debug map entry, and -// thus is considered dead (::foo() has a debug map entry, otherwse dsymutil +// Everything in the N namespace below doesn't have a debug map entry, and +// thus is considered dead (::foo() has a debug map entry, otherwise dsymutil // would just drop the CU altogether). +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_TAG_namespace namespace N { int blah = 42; // This is actually a dsymutil-classic bug that we reproduced // CHECK: DW_TAG_variable -// CHECK-NOT: DW_TAG // CHECK: DW_AT_location __attribute__((always_inline)) int foo() { return blah; } // CHECK: DW_TAG_subprogram -// CHECK-NOT: DW_AT_low_pc -// CHECK-NOT: DW_AT_high_pc -// CHECK: DW_AT_frame_base +// CHECK: DW_AT_frame_base // CHECK: DW_TAG_subprogram @@ -34,15 +35,21 @@ int bar(unsigned i) { return foo(); } // CHECK: DW_TAG_subprogram -// CHECK-NOT: DW_AT_low_pc -// CHECK-NOT: DW_AT_high_pc -// CHECK: DW_AT_frame_base -// CHECK-NOT: DW_AT_location -// CHECK-NOT: DW_AT_low_pc -// CHECK-NOT: DW_AT_high_pc - +// CHECK: DW_AT_frame_base +// CHECK: DW_TAG_formal_parameter +// CHECK: DW_TAG_variable +// CHECK: DW_TAG_inlined_subroutine +// CHECK: NULL +// CHECK: NULL } -// CHECK: TAG_imported_module +// CHECK: DW_TAG_base_type +// CHECK: DW_TAG_imported_module +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_TAG_base_type +// CHECK: NULL + using namespace N; void foo() {} diff --git a/llvm/test/tools/dsymutil/X86/dummy-debug-map.map b/llvm/test/tools/dsymutil/X86/dummy-debug-map.map index aa000182e47b..95b1f726d4ff 100644 --- a/llvm/test/tools/dsymutil/X86/dummy-debug-map.map +++ b/llvm/test/tools/dsymutil/X86/dummy-debug-map.map @@ -18,5 +18,10 @@ objects: symbols: - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x30000, size: 0x10 } - { sym: __ZN1S3bazIiEEvT_, objAddr: 0x0, binAddr: 0x30010, size: 0x10 } + - filename: 4.o + symbols: + - { sym: __Z3foov, objAddr: 0x0, binAddr: 0x40000, size: 0x10 } + - { sym: __ZZ11not_removedvE1b, objAddr: 0x0, binAddr: 0x40010, size: 0x10 } + - { sym: __ZZ7removedvE1a, objAddr: 0x0, binAddr: 0x40020, size: 0x10 } ... diff --git a/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp b/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp new file mode 100644 index 000000000000..5593b2638147 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp @@ -0,0 +1,59 @@ +// RUN: dsymutil -f -y %p/dummy-debug-map.map -oso-prepend-path %p/../Inputs/inlined-static-variable -o - | llvm-dwarfdump - | FileCheck %s --implicit-check-not "{{DW_AT_low_pc|DW_AT_high_pc|DW_AT_location|DW_TAG|NULL}}" + +// clang -g -c inlined-static-variable.cpp -o 4.o + +// The functions removed and not_removed are not in the debug map and are +// considered dead, but they are also inlined into the function foo which is +// in the debug map. Those function-local globals are alive and thus should +// have locations in the debug info even if their functions do not. + +inline __attribute__((always_inline)) int removed() { + static int a = 0; + return ++a; +} + +__attribute__((always_inline)) int not_removed() { + static int b = 0; + return ++b; +} + +int unused() { + static int c = 0; + return ++c; +} + +int foo() { + return removed() + not_removed(); +} + +// CHECK: DW_TAG_compile_unit +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc + +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_name ("removed") +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name ("a") +// CHECK: DW_AT_location +// CHECK: NULL + +// CHECK: DW_TAG_base_type +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_name ("not_removed") +// CHECK: DW_TAG_variable +// CHECK: DW_AT_name ("b") +// CHECK: DW_AT_location +// CHECK: NULL + +// CHECK: DW_TAG_subprogram +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_AT_name ("foo") +// CHECK: DW_TAG_inlined_subroutine +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: DW_TAG_inlined_subroutine +// CHECK: DW_AT_low_pc +// CHECK: DW_AT_high_pc +// CHECK: NULL +// CHECK: NULL |