Skip to content

Commit b9a9220

Browse files
committed
[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
1 parent e531750 commit b9a9220

File tree

4 files changed

+107
-3
lines changed

4 files changed

+107
-3
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp

+21-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
3131
Dl_info info;
3232
int result = dladdr((const void *)addr, &info);
3333
if (!result) return false;
34+
35+
CHECK(addr >= reinterpret_cast<uptr>(info.dli_saddr));
36+
stack->info.function_offset = addr - reinterpret_cast<uptr>(info.dli_saddr);
3437
const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
3538
if (!demangled) return false;
3639
stack->info.function = internal_strdup(demangled);
@@ -145,12 +148,29 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
145148
const char *buf = process_->SendCommand(command);
146149
if (!buf) return false;
147150
uptr line;
151+
uptr start_address = AddressInfo::kUnknown;
148152
if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
149-
&stack->info.file, &line, nullptr)) {
153+
&stack->info.file, &line, &start_address)) {
150154
process_ = nullptr;
151155
return false;
152156
}
153157
stack->info.line = (int)line;
158+
159+
if (start_address == AddressInfo::kUnknown) {
160+
// Fallback to dladdr() to get function start address if atos doesn't report
161+
// it.
162+
Dl_info info;
163+
int result = dladdr((const void *)addr, &info);
164+
if (result)
165+
start_address = reinterpret_cast<uptr>(info.dli_saddr);
166+
}
167+
168+
// Only assig to `function_offset` if we were able to get the function's
169+
// start address.
170+
if (start_address != AddressInfo::kUnknown) {
171+
CHECK(addr >= start_address);
172+
stack->info.function_offset = addr - start_address;
173+
}
154174
return true;
155175
}
156176

compiler-rt/test/asan/TestCases/Darwin/asan-symbolize-partial-report-no-external-symbolizer.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
// source location is not and instead module name and offset are
1818
// printed.
1919
// CHECK-PS: WRITE of size 4
20-
// CHECK-PS: #0 0x{{.+}} in foo ({{.+}}.executable:{{.+}}+0x{{.+}})
21-
// CHECK-PS: #1 0x{{.+}} in main ({{.+}}.executable:{{.+}}+0x{{.+}})
20+
// CHECK-PS: #0 0x{{.+}} in foo{{(\+0x[0-9a-f]+)?}} ({{.+}}.executable:{{.+}}+0x{{.+}})
21+
// CHECK-PS: #1 0x{{.+}} in main{{(\+0x[0-9a-f]+)?}} ({{.+}}.executable:{{.+}}+0x{{.+}})
2222

2323
// CHECK-FS: WRITE of size 4
2424

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %clangxx %s -g -O0 -o %t-with-debug
2+
3+
// With debug info atos reports the source location, but no function offset. We fallback to dladdr() to retrieve the function offset.
4+
// 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
5+
// RUN: FileCheck -input-file=%t-with-debug.output %s
6+
7+
// Without debug info atos reports the function offset and so dladdr() fallback is not used.
8+
// RUN: rm -rf %t-with-debug.dSYM
9+
// 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
10+
// RUN: FileCheck -input-file=%t-no-debug.output %s
11+
12+
#include <sanitizer/common_interface_defs.h>
13+
#include <stdio.h>
14+
15+
void baz() {
16+
printf("Do stuff in baz\n");
17+
__sanitizer_print_stack_trace();
18+
}
19+
20+
void bar() {
21+
printf("Do stuff in bar\n");
22+
baz();
23+
}
24+
25+
void foo() {
26+
printf("Do stuff in foo\n");
27+
bar();
28+
}
29+
30+
int main() {
31+
printf("Do stuff in main\n");
32+
foo();
33+
return 0;
34+
}
35+
36+
// CHECK: Using atos found at:
37+
38+
// These `function_offset` patterns are designed to disallow `0x0` which is the
39+
// value printed for `kUnknown`.
40+
// CHECK: function_name:baz{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
41+
// CHECK: function_name:bar{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
42+
// CHECK: function_name:foo{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
43+
// CHECK: function_name:main{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// UNSUPPORTED: lsan
2+
// This test fails with LSan enabled because the dladdr symbolizer actually leaks
3+
// memory because the call to `__sanitizer::DemangleCXXABI` leaks memory which LSan
4+
// detects (rdar://problem/42868950).
5+
6+
// RUN: %clangxx %s -O0 -o %t
7+
// RUN: %env_tool_opts=verbosity=2,external_symbolizer_path=,stack_trace_format='"function_name:%f function_offset:%q"' %run %t > %t.output 2>&1
8+
// RUN: FileCheck -input-file=%t.output %s
9+
#include <sanitizer/common_interface_defs.h>
10+
#include <stdio.h>
11+
12+
void baz() {
13+
printf("Do stuff in baz\n");
14+
__sanitizer_print_stack_trace();
15+
}
16+
17+
void bar() {
18+
printf("Do stuff in bar\n");
19+
baz();
20+
}
21+
22+
void foo() {
23+
printf("Do stuff in foo\n");
24+
bar();
25+
}
26+
27+
int main() {
28+
printf("Do stuff in main\n");
29+
foo();
30+
return 0;
31+
}
32+
33+
// CHECK: External symbolizer is explicitly disabled
34+
// CHECK: Using dladdr symbolizer
35+
36+
// These `function_offset` patterns are designed to disallow `0x0` which is the
37+
// value printed for `kUnknown`.
38+
// CHECK: function_name:baz{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
39+
// CHECK: function_name:bar{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
40+
// CHECK: function_name:foo{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}
41+
// CHECK: function_name:main{{(\(\))?}} function_offset:0x{{0*[1-9a-f][0-9a-f]*$}}

0 commit comments

Comments
 (0)