summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/DWARFLinker/DWARFLinker.cpp5
-rw-r--r--llvm/test/tools/dsymutil/Inputs/inlined-static-variable/4.obin0 -> 3352 bytes
-rw-r--r--llvm/test/tools/dsymutil/X86/dead-stripped.cpp37
-rw-r--r--llvm/test/tools/dsymutil/X86/dummy-debug-map.map5
-rw-r--r--llvm/test/tools/dsymutil/X86/inlined-static-variable.cpp59
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
new file mode 100644
index 000000000000..cec573c89789
--- /dev/null
+++ b/llvm/test/tools/dsymutil/Inputs/inlined-static-variable/4.o
Binary files differ
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