[compiler-rt] b9a9220 - [Symbolizers] On Darwin compute function offset when possible.
Dan Liew via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 19 10:05:01 PST 2019
Author: Dan Liew
Date: 2019-11-19T10:04:44-08:00
New Revision: b9a92206b6ef8b369dc266d8cb70553ebef293bd
URL: https://github.com/llvm/llvm-project/commit/b9a92206b6ef8b369dc266d8cb70553ebef293bd
DIFF: https://github.com/llvm/llvm-project/commit/b9a92206b6ef8b369dc266d8cb70553ebef293bd.diff
LOG: [Symbolizers] On Darwin compute function offset when possible.
Summary:
The sanitizer symbolizers support printing the function offset
(difference between pc and function start) of a stackframe using the
`%q` format specifier.
Unfortunately this didn't actually work because neither the atos
or dladdr symbolizer set the `AddressInfo::function_offset` field.
This patch teaches both symbolizers to try to compute the function
offset. In the case of the atos symbolizer, atos might not report the
function offset (e.g. it reports a source location instead) so in this
case it fallsback to using `dladdr()` to compute the function offset.
Two test cases are included.
rdar://problem/56695185
Reviewers: kubamracek, yln
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D69549
Added:
compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-function-offset-atos.cpp
compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-function-offset-dladdr.cpp
Modified:
compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp
compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-partial-report-no-external-symbolizer.cpp
Removed:
################################################################################
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp
index a619ed092f0b..f26efe5c50b5 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp
@@ -31,6 +31,9 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
Dl_info info;
int result = dladdr((const void *)addr, &info);
if (!result) return false;
+
+ CHECK(addr >= reinterpret_cast<uptr>(info.dli_saddr));
+ stack->info.function_offset = addr - reinterpret_cast<uptr>(info.dli_saddr);
const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
if (!demangled) return false;
stack->info.function = internal_strdup(demangled);
@@ -145,12 +148,29 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
const char *buf = process_->SendCommand(command);
if (!buf) return false;
uptr line;
+ uptr start_address = AddressInfo::kUnknown;
if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
- &stack->info.file, &line, nullptr)) {
+ &stack->info.file, &line, &start_address)) {
process_ = nullptr;
return false;
}
stack->info.line = (int)line;
+
+ if (start_address == AddressInfo::kUnknown) {
+ // Fallback to dladdr() to get function start address if atos doesn't report
+ // it.
+ Dl_info info;
+ int result = dladdr((const void *)addr, &info);
+ if (result)
+ start_address = reinterpret_cast<uptr>(info.dli_saddr);
+ }
+
+ // Only assig to `function_offset` if we were able to get the function's
+ // start address.
+ if (start_address != AddressInfo::kUnknown) {
+ CHECK(addr >= start_address);
+ stack->info.function_offset = addr - start_address;
+ }
return true;
}
diff --git a/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-partial-report-no-external-symbolizer.cpp b/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-partial-report-no-external-symbolizer.cpp
index cb96ff762103..e9b657edcea2 100644
--- a/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-partial-report-no-external-symbolizer.cpp
+++ b/compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-partial-report-no-external-symbolizer.cpp
@@ -17,8 +17,8 @@
// source location is not and instead module name and offset are
// printed.
// CHECK-PS: WRITE of size 4
-// CHECK-PS: #0 0x{{.+}} in foo ({{.+}}.executable:{{.+}}+0x{{.+}})
-// CHECK-PS: #1 0x{{.+}} in main ({{.+}}.executable:{{.+}}+0x{{.+}})
+// CHECK-PS: #0 0x{{.+}} in foo{{(\+0x[0-9a-f]+)?}} ({{.+}}.executable:{{.+}}+0x{{.+}})
+// CHECK-PS: #1 0x{{.+}} in main{{(\+0x[0-9a-f]+)?}} ({{.+}}.executable:{{.+}}+0x{{.+}})
// CHECK-FS: WRITE of size 4
diff --git a/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-function-offset-atos.cpp b/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-function-offset-atos.cpp
new file mode 100644
index 000000000000..da1bf2cdcf25
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-function-offset-atos.cpp
@@ -0,0 +1,43 @@
+// RUN: %clangxx %s -g -O0 -o %t-with-debug
+
+// With debug info atos reports the source location, but no function offset. We fallback to dladdr() to retrieve the function offset.
+// RUN: %env_tool_opts=verbosity=2,stack_trace_format='"function_name:%f function_offset:%q"' %run %t-with-debug > %t-with-debug.output 2>&1
+// RUN: FileCheck -input-file=%t-with-debug.output %s
+
+// Without debug info atos reports the function offset and so dladdr() fallback is not used.
+// RUN: rm -rf %t-with-debug.dSYM
+// RUN: %env_tool_opts=verbosity=2,stack_trace_format='"function_name:%f function_offset:%q"' %run %t-with-debug > %t-no-debug.output 2>&1
+// RUN: FileCheck -input-file=%t-no-debug.output %s
+
+#include <sanitizer/common_interface_defs.h>
+#include <stdio.h>
+
+void baz() {
+ printf("Do stuff in baz\n");
+ __sanitizer_print_stack_trace();
+}
+
+void bar() {
+ printf("Do stuff in bar\n");
+ baz();
+}
+
+void foo() {
+ printf("Do stuff in foo\n");
+ bar();
+}
+
+int main() {
+ printf("Do stuff in main\n");
+ foo();
+ return 0;
+}
+
+// CHECK: Using atos found at:
+
+// These `function_offset` patterns are designed to disallow `0x0` which is the
+// value printed for `kUnknown`.
+// CHECK: function_name:baz{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
+// CHECK: function_name:bar{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
+// CHECK: function_name:foo{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
+// CHECK: function_name:main{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
diff --git a/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-function-offset-dladdr.cpp b/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-function-offset-dladdr.cpp
new file mode 100644
index 000000000000..69288cbf8c81
--- /dev/null
+++ b/compiler-rt/test/sanitizer_common/TestCases/Darwin/symbolizer-function-offset-dladdr.cpp
@@ -0,0 +1,41 @@
+// UNSUPPORTED: lsan
+// This test fails with LSan enabled because the dladdr symbolizer actually leaks
+// memory because the call to `__sanitizer::DemangleCXXABI` leaks memory which LSan
+// detects (rdar://problem/42868950).
+
+// RUN: %clangxx %s -O0 -o %t
+// RUN: %env_tool_opts=verbosity=2,external_symbolizer_path=,stack_trace_format='"function_name:%f function_offset:%q"' %run %t > %t.output 2>&1
+// RUN: FileCheck -input-file=%t.output %s
+#include <sanitizer/common_interface_defs.h>
+#include <stdio.h>
+
+void baz() {
+ printf("Do stuff in baz\n");
+ __sanitizer_print_stack_trace();
+}
+
+void bar() {
+ printf("Do stuff in bar\n");
+ baz();
+}
+
+void foo() {
+ printf("Do stuff in foo\n");
+ bar();
+}
+
+int main() {
+ printf("Do stuff in main\n");
+ foo();
+ return 0;
+}
+
+// CHECK: External symbolizer is explicitly disabled
+// CHECK: Using dladdr symbolizer
+
+// These `function_offset` patterns are designed to disallow `0x0` which is the
+// value printed for `kUnknown`.
+// CHECK: function_name:baz{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
+// CHECK: function_name:bar{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
+// CHECK: function_name:foo{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
+// CHECK: function_name:main{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
More information about the llvm-commits
mailing list