How to see useful information (filename, line no) in stacktrace of C++ program
Asked Answered
O

1

6

This is a complicated one since depends on Boost version and platform too.

I'm using boost stacktrace to print backtrace where some assertions fail. There are some external compile-time and run-time deps, depending on what mode you use (the link documents ~5 modes). I'd prefer something based on both debug info and exports info (the latter of which I presume would work in production builds too). But I can get to work neither of default mode or BOOST_STACKTRACE_USE_ADDR2LINE or BOOST_STACKTRACE_USE_BACKTRACE - all 3 show just addresses in the call stack for my actual program code - see below a stacktrace from a google-test test:

 0# 0x000055E47D43BDC2 in Debug/myprog
 1# 0x000055E47D489055 in Debug/myprog
 2# 0x000055E47D567FDF in Debug/myprog
 3# 0x000055E47D560CDE in Debug/myprog
 4# void testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void>(testing::Test*, void (testing::Test::*)(), char const*) in /usr/lib/libgtest.so.1.8.1
 5# testing::Test::Run() in /usr/lib/libgtest.so.1.8.1
 6# testing::TestInfo::Run() in /usr/lib/libgtest.so.1.8.1
 7# testing::TestCase::Run() in /usr/lib/libgtest.so.1.8.1
 8# testing::internal::UnitTestImpl::RunAllTests() in /usr/lib/libgtest.so.1.8.1

What I tried: -rdynamic, -fno-pie and -fPIC, (I'm already on -O0), -ggdb3 instead of the default -g3, nothing makes the function names to show up.

Related: this, this.

I'm on: gcc 8.2, boost 1.69 (header-only mode for the stracktrace lib), Arch Linux (on this system I'd have to manually install libbacktrace which is not packaged so I'd prefer to go with the ADDR2LINE approach)


Edit: updated link to latest boost.stacktrace.


Edit2: I noticed the boost.stacktrace doc contains this hint

Function names from shared libraries may not be decoded due to address space layout randomization. Still better than nothing.

... which sounds helpful but for me it's the other way around, I'm not getting symbols in my own executable but I am for libgtest.so for example. So it's as if there is something wrong with the debug info setting. Any ideas appreciated.

Overshine answered 18/2, 2019 at 21:45 Comment(10)
Wouldn't it be better to collect core dump or smth in case of the application crash? It would provide much more useful information than just a stack trace.Deposition
@RealFresh generally yes, but we also log stack traces in scenarios other than crashesOvershine
@haelix: It is very hard to find problem with above info, because it depends not only on compiler settings, but also on whole toolchain that you are using. For example: debug symbols can be stripped away from your binary. Can you see function symbols when you use objdump -CD YOUR_BINARY?Meander
@MichałŁoś yes I agree causes can be many-fold. But I'm in full control of the entire stack (it's a greenfield project) and can promptly follow up guidance. To answer, with objdump -CD yes I can see the very symbols I should be seeing in the call stacks.Overshine
You're on linux. Have you considered using GDB or valgrind?Fidelafidelas
@Chipster to do what?Overshine
To help you debug. They are debug tools.Fidelafidelas
@Chipster yeah the question is not specifically about figuring out why a program crashed; I sometimes print stacktraces simply to gather info about what code paths happen in my program. I've updated the title to reflect this.Overshine
I followed this link(https://mcmap.net/q/64721/-how-to-print-a-stack-trace-whenever-a-certain-function-is-called/…) I also have arch linux with almost same configurations like yours. Previously I don't have -no-pie , after adding "-no-pie -g" everything works fine (Now i can see line number and file name) You mentioned "-fno-pie", but in the link above, the author actually used a "-no-pie" in addition of the "-fno-pie"Labrecque
There is a bug in boost.stacktrace. It takes virtual address (VMA) and calls addr2line on this address while addr2line needs program address. It works only if program is loaded at 0x0 address, which is not true under some configurations (as in yours).Curling
I
0

Part 1

I had put together the following files (adapted from here). Since there is no execinfo.h in Windows (that I am aware of), this only works in Linux. It does not use boost, but it may be useful anyway.

backtrace_util.h:

#ifndef BACKTRACE_UTIL_H
#define BACKTRACE_UTIL_H
void backtrace_print(void);
#endif // BACKTRACE_UTIL_H

backtrace_util.cc:

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void backtrace_print(void) {
    int j, nptrs;
#define SIZE 100
    void *buffer[100];
    char **strings;

    nptrs = backtrace(buffer, SIZE);
    printf("backtrace() returned %d addresses\n", nptrs);

    /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
     would produce similar output to the following: */

    strings = backtrace_symbols(buffer, nptrs);
    if (strings == NULL) {
        perror("backtrace_symbols");
        exit(EXIT_FAILURE);
    }

    for (j = 0; j < nptrs; j++)
        printf("%s\n", strings[j]);

    free(strings);
}

backtrace_test.cc:

#include <stdio.h>
#include <stdlib.h>

#include "backtrace_util.h"

void myfunc(int ncalls) {
    if (ncalls > 1)
        myfunc(ncalls - 1);
    else {
        backtrace_print();
    }
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "%s num-calls\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    myfunc(atoi(argv[1]));
    exit(EXIT_SUCCESS);
}

Compiled/linked with -std=c++17 -g, linked with -rdynamic. The output is

$ ./backtrace_test 2
backtrace() returned 6 addresses
./backtrace_test(_Z15backtrace_printv+0x2e) [0x55c51759bc51]
./backtrace_test(_Z6myfunci+0x25) [0x55c51759bbbb]
./backtrace_test(_Z6myfunci+0x1e) [0x55c51759bbb4]
./backtrace_test(main+0x5b) [0x55c51759bc19]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xe7) [0x7f3c2c2f5b97]
./backtrace_test(_start+0x2a) [0x55c51759baaa]


Part 2

When trying to demangle the names obtained, I came across this, and this. I did not follow up on putting together the whole thing.

Incorporeity answered 22/2, 2019 at 13:11 Comment(3)
Well, it's regrettable that we need to ditch boost/stacktrace, is that what you're suggesting? If anybody does it well (in a quasi-standard way), it would be Boost.Overshine
@Overshine - I do not mean that we need to do that. I am simply posting one possible route to the answer of your question (though it clearly needs more work). I agree that boost is a major player here.Incorporeity
@Overshine - I recall needing something boost-free (!) (but I do not remember why). Then I found what led me to this.Incorporeity

© 2022 - 2024 — McMap. All rights reserved.