In backtraces produced by perf record --call-graph dwarf
and printed by perf script
, I am consistently getting wrong addresses for maybe 5% of call stacks, i.e. unwinding fails. One example is
my_bin 770395 705462.825887: 3560360 cycles:
7f0398b9b7e2 __vsnprintf_internal+0x12 (/usr/lib/x86_64-linux-gnu/libc-2.32.so)
7ffcdb6fbfdf [unknown] ([stack])
my_bin 770395 705462.827040: 3447195 cycles:
7f0398ba1624 __GI__IO_default_xsputn+0x104 (inlined)
7ffcdb6fb7af [unknown] ([stack])
and it was produced from this code (compiled with g++ -O3 -g -fno-omit-frame-pointer my_bin.cpp -o my_bin
):
#include <cstdio>
#include <iostream>
int __attribute__ ((noinline)) libc_string(int x) {
char buf[64] = {0};
// Some nonsense workload using libc
int res = 0;
for (int i = 0; i < x; ++i) {
res += snprintf(buf, 64, "%d %d %d Can I bring my friends to tea?", (i%10), (i%3)*10, i+2);
res = res % 128;
}
return res;
}
int main() {
int result = libc_string(20000000);
std::cout << result << "\n";
}
I'm pretty sure that my program should not have executable code in the stack, so these addresses seem wrong. It's not only one program, but most programs that I've profiled which have about 5% wrong call stacks. These call stacks mostly just have two stack frames, with the innermost one sometimes in libraries like Eigen (even though they generally have correct calls stacks) and sometimes in the C++ STL or libc. I've seen the unwinding end up in unknown
, [stack]
, [heap]
, anon
, //anon
, libstdc++.so.6.0.28
, or <my_bin>
.
I've seen this on Ubuntu 18.04, 20.04 and 20.10.
This happens only with DWARF unwinding. How can this be fixed?