"Incomplete" stack-trace
tl;dr: backward-cpp gives incomplete stack-traces (while gdb gives complete ones); I'm trying to understand if this is solvable.
Problem
I'm experiencing an issue where backward-cpp gives me a stack-trace like this:
Stack trace (most recent call last):
#1 Object "", at 0, in
#0 Object "/lib64/libc-2.33.so", at 0x7fd373d1e52f, in
while gdb gives me a stack-trace like this:
backtrace:
#0 0x0000000000000000 in ?? ()
#1 0x0000555555558813 in cls::mthd (this=0x7fffffffdabf) at ./unit.cpp:13
#2 0x000055555555882e in do_it () at ./unit.cpp:18
#3 0x0000555555558949 in main () at main.cpp:44
Notice: gdb has do_it and cls::mthd, while backward-cpp does not.
This is an example I have found "in the wild", but some of my stack-traces are correct (I'm saying this because I believe I am using backward-cpp correctly; e.g., using the correct defines/link flags).
Question
Is it possible to get backwards-cpp to give better (/"more correct") stack-traces here?
Example code
When I found this issue, I used https://github.com/marxin/cvise to automatically construct my "failing test-case" (if the code looks weird, maybe it is, but it is derived from valid code that displays the same behaviour; I'm actually surprised that this code links, given there's no definition of d::e).
unit.cpp
struct b {
virtual void c() {}
};
struct d : b {
virtual int e(int, int);
} * f;
struct cls {
int mthd();
};
int cls::mthd() {
b g;
f = (d *)&g;
f->e(1, 1);
return 1;
}
void do_it() {
cls a;
a.mthd();
}
main.cpp
#include <unit.cpp>
#define BACKWARD_HAS_BACKTRACE 0
#define BACKWARD_HAS_BACKTRACE_SYMBOL 0
#define BACKWARD_HAS_BFD 0
#define BACKWARD_HAS_DW 1
#define BACKWARD_HAS_DWARF 0
#define BACKWARD_HAS_LIBUNWIND 0
#define BACKWARD_HAS_UNWIND 1
#include <backward.hpp>
#ifdef USE_HANDLERS
void handler(int sig) {
using namespace backward;
StackTrace st;
st.load_here(64);
st.skip_n_firsts(3);
Printer p;
p.print(st);
exit(1);
}
void setup_handlers(void) {
signal(SIGSEGV, handler);
signal(SIGABRT, handler);
signal(SIGBUS, handler);
signal(SIGILL, handler);
signal(SIGFPE, handler);
}
#else
namespace backward {
backward::SignalHandling sh;
}
#endif
int main(void) {
#ifdef USE_HANDLERS
setup_handlers();
#endif
do_it();
return 0;
}
Compilation
use_handlers=1
if [ $use_handlers -eq 1 ]; then
defines="-DUSE_HANDLERS"
else
defines=""
fi
g++ -g $defines -Wall -Wextra -Wpedantic -Werror -std=c++11 -I. main.cpp -ldw -ldl -lunwind -o main
Output
When using "manual" signal handlers (i.e., p.print(st);)
stderr via backward-cpp
Stack trace (most recent call last):
#1 Object "", at 0, in
#0 Object "/lib64/libc-2.33.so", at 0x7fd373d1e52f, in
gdb
backtrace:
#0 0x0000000000000000 in ?? ()
#1 0x0000555555558813 in cls::mthd (this=0x7fffffffdabf) at ./unit.cpp:13
#2 0x000055555555882e in do_it () at ./unit.cpp:18
#3 0x0000555555558949 in main () at main.cpp:44
When using "automatic" signal handlers (i.e., backward::SignalHandling sh)
stderr via backward-cpp
Stack trace (most recent call last):
#5 Object "", at 0, in
#4 Object "/lib64/libc-2.33.so", at 0x7f98f98f352f, in
#3 Source "./backward.hpp", line 4256, in sig_handler [0x559943bca0c5]
4253: #endif
4254: static void
4255: sig_handler(int signo, siginfo_t *info, void *_ctx) {
>4256: handleSignal(signo, info, _ctx);
4257:
4258: // try to forward the signal.
4259: raise(info->si_signo);
#2 Source "./backward.hpp", line 4233, in handleSignal [0x559943bca005]
4230: st.load_from(error_addr, 32, reinterpret_cast<void *>(uctx),
4231: info->si_addr);
4232: } else {
>4233: st.load_here(32, reinterpret_cast<void *>(uctx), info->si_addr);
4234: }
4235:
4236: Printer printer;
#1 Source "./backward.hpp", line 862, in load_here [0x559943bc738a]
859: return 0;
860: }
861: _stacktrace.resize(depth);
> 862: size_t trace_cnt = details::unwind(callback(*this), depth);
863: _stacktrace.resize(trace_cnt);
864: skip_n_firsts(0);
865: return size();
#0 Source "./backward.hpp", line 844, in unwind<backward::StackTraceImpl<backward::system_tag::linux_tag>::callback> [0x559943bca590]
842: template <typename F> size_t unwind(F f, size_t depth) {
843: Unwinder<F> unwinder;
> 844: return unwinder(f, depth);
845: }
846:
847: } // namespace details
Segmentation fault (Address not mapped to object [(nil)])
gdb
backtrace:
#0 0x0000000000000000 in ?? ()
#1 0x0000555555558883 in cls::mthd (this=0x7fffffffdabf) at ./unit.cpp:13
#2 0x000055555555889e in do_it () at ./unit.cpp:18
#3 0x00005555555588aa in main () at main.cpp:44
System specifics
atg@vapvdatg01:/tmp> uname -a
Linux vapvdatg01 5.11.11-1-default #1 SMP Tue Mar 30 17:57:52 UTC 2021 (dbc4a02) x86_64 x86_64 x86_64 GNU/Linux
atg@vapvdatg01:/tmp> lsb-release -a
LSB Version: n/a
Distributor ID: openSUSE
Description: openSUSE Tumbleweed
Release: 20210408
Codename: n/a
atg@vapvdatg01:/tmp> /lib64/libc.so.6 --version
GNU C Library (GNU libc) release release version 2.33 (git 9826b03b74).
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Configured for x86_64-suse-linux.
Compiled by GNU CC version 10.2.1 20210303 [revision 85977f624a34eac309f9d77a58164553dfc82975].
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<http://bugs.opensuse.org>.
atg@vapvdatg01:/tmp> gcc --version
gcc (SUSE Linux) 10.2.1 20210401 [revision 892024d4af83b258801ff7484bf28f0cf1a1a999]
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Library versions
backward-cpp@ 9f4b0ddlibelf-devel@ 0.183-2.1libdw-devel@ 0.183-2.1libunwind-devel@ 1.5.0-1.3
Okay, so changing:
#define BACKWARD_HAS_LIBUNWIND 0
#define BACKWARD_HAS_UNWIND 1
to
#define BACKWARD_HAS_LIBUNWIND 1
#define BACKWARD_HAS_UNWIND 0
gives me better traces:
Stack trace (most recent call last):
#3 Source "../sysdeps/x86_64/start.S", line 120, in _start
#2 Object "/lib64/libc-2.33.so", at 0x7fea802d8b24, in __libc_start_main
#1 Source "./main.cpp", line 44, in main
41: #ifdef USE_HANDLERS
42: setup_handlers();
43: #endif
> 44: do_it();
45: return 0;
46: }
#0 Source "./unit.cpp", line 13, in mthd
10: int cls::mthd() {
11: b g;
12: f = (d *)&g;
> 13: f->e(1, 1);
14: return 1;
15: }
16: void do_it() {
Interestingly, I took the defines from CMakeFiles/test_stacktrace.dir/flags.make, which uses BACKWARD_HAS_UNWIND over BACKWARD_HAS_LIBUNWIND.
gdb might be looking for the debug symbols in the various .debug directories.
https://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html