6

I've just read

How to generate a stacktrace when my gcc C++ app crashes

which is pretty old by now (5 years). Some answers suggest solutions allowing you to get, for every stack frame, the name of the function and an offset (within the stack I guess). But what I (and may others) really need is the source filename and line number where the call was made (assuming the code was compiled with debug information). One of the answers linked to a part of glibc which does this (libSegfault; see files in this directory - segfault.c, backtracesyms.c, backtracesymsfd.c) - so it is possible.

My questions are:

  • Can this information be extracted in a platform-independent fashion, or one that conforms to some standard (POSIX??)
  • Why doesn't libunwind support this? (I think it doesn't, after looking through ther website)
  • Does this necessarily depend on your compiler's C/C++ standard library (for C/C++ apps, at least)?

Notes:

  • You may assume the binary has debugging info, so in the case of C/C++ it was compiled with -g; of course, in a proper library we would check whether debug info is available or not.
Community
  • 1
  • 1
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 1
    No; there isn't a standard way; neither the C nor C++ language standards nor the POSIX o/s standard stipulates a way to do it. Libunwind is probably as close to being as portable as you can get — there may be a few other comparable libraries. And yes, it depends on the platform — o/s and compiler. Stack traces in signal handlers can be … entertaining. – Jonathan Leffler Nov 22 '16 at 22:48
  • @JonathanLeffler: But doesn't, say, gdb do it on many platforms? Even for binaries not compiled with gcc? – einpoklum Nov 22 '16 at 22:49
  • Yes, but GDB has complex code that varies by platform to do it. Go and take a look — it won't be trivial. It works to the ABI defined for the platform, and depends on the debugging model (Dwarf vs …), and the object file (and executable file) format (ELF vs COFF vs …) and so on. What works on macOS won't work on Windows, and neither will work on Linux. That's where libraries such as libunwind come into play. – Jonathan Leffler Nov 22 '16 at 22:49
  • If you use `gdb` (or any of its' relatives, like `ddd`) 1) the C program or C++ program must have been compiled with the `-g` option otherwise the stack trace information, with file names and line numbers is not available. Even then when debugging the problem, the original source code files must be available to the debugger. Also, the executable must not have been `stripped` of the debug information. Such debug information is related to the C and C++ compiler and linker, not to the environment./OS – user3629249 Nov 23 '16 at 02:57
  • @user3629249: Yes, I know all that (although the source files only need to be there if you want to inspect them; you can list their names even if they're missing). That wasn't my question though. – einpoklum Nov 23 '16 at 07:22
  • Does this answer your question? [print call stack in C or C++](https://stackoverflow.com/questions/3899870/print-call-stack-in-c-or-c) Especially [this answer](https://stackoverflow.com/a/54365144/7621674) should be useful. – m7913d Jun 16 '20 at 08:20

2 Answers2

3

Adding to @EmployedRussian's valid answer - there is now a multi-platform library which does this:

Boost StackTrace

And just to illustrate what a trace looks like, if you were to write:

// This following definition may be necessary to ensure you can get
// line numbers included in the stack trace; see:
// https://stackoverflow.com/questions/3899870/
// for details
//
#define BOOST_STACKTRACE_USE_ADDR2LINE

#include <boost/stacktrace.hpp>

// ... somewhere inside the `bar(int)` function that is called recursively:
std::cout << boost::stacktrace::stacktrace();

you might get something like (on Linux for example):

0# bar(int) at /path/to/source/file.cpp:70
1# bar(int) at /path/to/source/file.cpp:70
2# bar(int) at /path/to/source/file.cpp:70
3# bar(int) at /path/to/source/file.cpp:70
4# main at /path/to/main.cpp:93
5# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
6# _start
einpoklum
  • 118,144
  • 57
  • 340
  • 684
2

Can this information be extracted in a platform-independent fashion, or one that conforms to some standard (POSIX??)

Not unless someone writes a platform-independent library to do so. There are no such libraries (that I am aware of) at the moment.

Also, if by platform independent you mean "also works on Windows", then note that the Windows-native debugging format -- the PDB, was proprietary and undocumented until very recently.

Why doesn't libunwind support this? (I think it doesn't, after looking through ther website)

libunwind could support this if someone contributed such support (are you volunteering?). However, that would probably quadruple its size, and it currently is effectively unmaintained.

Does this necessarily depend on your compiler's C/C++ standard library (for C/C++ apps, at least)?

No, it only depends on the debug format. So long as the format is documented (e.g. DWARF4 on Linux and PDB on Windows), it's possible to write a library to parse such format, and there is no reason for such library to necessarily depend on C++ standard library.

P.S. I assume that dependence on the C standard library isn't a real concern for you. It's also possible to be independent of the C library, but one would have to reinvent the wheel a lot, and there is no practical reason to do so.

P.P.S.

GDB has complex code that varies by platform to do it.

Yes, and you need that complex code, and it will vary by platform. Whether that code lives in GDB or in libunwind doesn't change that.

P.P.P.S. There is also lldb, which provides much of that code as a library (but I am not sure how mature that code on various platforms is).

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • 1
    I would volunteer, if I had more free time on my hands. I have released some FOSS before... but alas, doing that does not promote my research in any way so I can't do it on "work time". The PPPS should be a promising lead, though. – einpoklum Nov 24 '16 at 09:55