Is there a portable/standard-compliant way to get filenames and linenumbers in a stack trace?
Asked Answered
S

3

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.
Swage answered 22/11, 2016 at 21:19 Comment(8)
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.Hamlett
@JonathanLeffler: But doesn't, say, gdb do it on many platforms? Even for binaries not compiled with gcc?Swage
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.Hamlett
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./OSNeckwear
@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.Swage
Does this answer your question? print call stack in C or C++ Especially this answer should be useful.Enthronement
There's libbacktrace which works on many platformsSacrarium
@ChrisDodd: See my answer about a C++'ish library to this effect which also works on many platforms.Swage
S
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
Swage answered 22/2, 2018 at 10:27 Comment(3)
What flags did you compile with? I'm not getting the filenames and line numbers no matter what I do.Cultivable
are you forget to add -g flag which add debugging information like filepath and line numbers?Chatham
@Fox: I don't think so, but that was 4 years ago.Swage
W
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).

Waltman answered 24/11, 2016 at 4:16 Comment(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.Swage
C
0

There are a number of stacktrace libraries that can be used to collect this information.

As einpoklum pointed out there is boost stacktrace but this lbirary relies on external dependencies and has portability issues. Additionally note that its stack trace generation is not async-signal safe without safe_dump_to.

Cpptrace is a simple and portable stack trace library for C++11 and newer. It does not currently support signal safe tracing however it provides a raw trace interface that can be used to resolve a vector of program counters later. In conjunction with the referenced question in the initial post, How to automatically generate a stacktrace when my program crashes, a stack trace can be generated with backtrace and then handed off to cpptrace to resolve.

Another option is backward-cpp which offers a utility for tracing from signal handlers.

Caucasian answered 9/10, 2023 at 20:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.