I'm tring to use program ***to print frame stack *** in C/C++ code.
Below is a demo find form internet:
#include <cassert>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <iomanip>
#include <cxxabi.h> // __cxa_demangle
#include <elfutils/libdwfl.h> // Dwfl*
#include <execinfo.h> // backtrace
#include <unistd.h> // getpid
using namespace std;
// https://stackoverflow.com/questions/281818/unmangling-the-result-of-stdtype-infoname
std::string demangle(const char* name) {
int status = -4;
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
std::string debug_info(Dwfl* dwfl, void* ip) {
uintptr_t ip2 = reinterpret_cast<uintptr_t>(ip);
Dwfl_Module* module = dwfl_addrmodule(dwfl, ip2);
char const* name = dwfl_module_addrname(module, ip2);
std::string function_name = name ? demangle(name) : "<unknown>";
int line_num = -1;
char const* file_name;
if (Dwfl_Line* dwfl_line = dwfl_module_getsrc(module, ip2)) {
Dwarf_Addr addr;
file_name = dwfl_lineinfo(dwfl_line, &addr, &line_num, nullptr, nullptr, nullptr);
}
std::stringstream ss;
ss << std::setw(16)<<std::setfill('0') <<ip << ' ' << function_name;
if (file_name)
ss << " at " << file_name << ':' << line_num;
ss << std::endl;
return ss.str();
}
std::string gen_framestack_backtrace() {
// Initialize Dwfl.
Dwfl* dwfl = nullptr;
{
Dwfl_Callbacks callbacks = {};
char* debuginfo_path = nullptr;
callbacks.find_elf = dwfl_linux_proc_find_elf;
callbacks.find_debuginfo = dwfl_standard_find_debuginfo;
callbacks.debuginfo_path = &debuginfo_path;
dwfl = dwfl_begin(&callbacks);
assert(dwfl);
int r;
r = dwfl_linux_proc_report(dwfl, getpid());
assert(!r);
r = dwfl_report_end(dwfl, nullptr, nullptr);
assert(!r);
static_cast<void>(r);
}
// Loop over stack frames.
std::stringstream ss;
{
void* stack[512];
int stack_size = ::backtrace(stack, sizeof stack / sizeof *stack);
for (int i = 0; i < stack_size; ++i) {
ss << i << ": ";
// Works.
ss << debug_info(dwfl, stack[i]);
#if 0
// TODO intended to do the same as above, but segfaults,
// so possibly UB In above function that does not blow up by chance?
void *ip = stack[i];
std::string function;
int line = -1;
char const* file;
uintptr_t ip2 = reinterpret_cast<uintptr_t>(ip);
Dwfl_Module* module = dwfl_addrmodule(dwfl, ip2);
char const* name = dwfl_module_addrname(module, ip2);
function = name ? demangle(name) : "<unknown>";
// TODO if I comment out this line it does not blow up anymore.
if (Dwfl_Line* dwfl_line = dwfl_module_getsrc(module, ip2)) {
Dwarf_Addr addr;
file = dwfl_lineinfo(dwfl_line, &addr, &line, nullptr, nullptr, nullptr);
}
ss << ip << ' ' << function;
if (file)
ss << " at " << file << ':' << line;
ss << std::endl;
#endif
}
}
dwfl_end(dwfl);
return ss.str();
}
void my_func_2() {
std::cout << gen_framestack_backtrace() << std::endl;
std::cout.flush();
}
void my_func_1(double f) {
(void)f;
my_func_2();
}
void my_func_1(int i) {
(void)i;
my_func_2();
}
int main(int argc, char **argv) {
long long unsigned int n;
if (argc > 1) {
n = strtoul(argv[1], NULL, 0);
} else {
n = 1;
}
for (long long unsigned int i = 0; i < n; ++i) {
my_func_1(1); // line 122
my_func_1(2.0); // line 123
}
}
Run:
$ sudo apt install libdw-dev libunwind-dev
$
$ g++ -fno-pie -ggdb3 -O0 -no-pie -o a.out -std=c++11 -Wall -Wextra -pedantic-errors test.cpp -ldw -lunwind -ggdb
$ ./a.out
Result:
0: 000000000x401ab1 stacktrace[abi:cxx11]() at /home/wxq/test/test7.cpp:71
1: 000000000x401c11 my_func_2() at /home/wxq/test/test7.cpp:106
2: 000000000x401ca2 my_func_1(int) at /home/wxq/test/test7.cpp:117
3: 000000000x401d01 main at /home/wxq/test/test7.cpp:128
4: 000x7f3e4ee4dbf6 __libc_start_main at ../csu/libc-start.c:310
5: 000000000x401479 _start at ../csu/libc-start.c:-1
0: 000000000x401ab1 stacktrace[abi:cxx11]() at /home/wxq/test/test7.cpp:71
1: 000000000x401c11 my_func_2() at /home/wxq/test/test7.cpp:106
2: 000000000x401c8f my_func_1(double) at /home/wxq/test/test7.cpp:112
3: 000000000x401d16 main at /home/wxq/test/test7.cpp:129
4: 000x7f3e4ee4dbf6 __libc_start_main at ../csu/libc-start.c:310
5: 000000000x401479 _start at ../csu/libc-start.c:-1
But above solution can not print function arguments
Does any one have solution to print backtrace in C/C++ program, just like gdb bt
command?
Just like below command
#0 createObj1 (handle=0x5555559291c0, shimHandle=0x55555595a850) at /home/wxq/setup.cpp:983
#1 0x00007ffff60a3763 in initialize (this=0x55555595a850, config=...)at /home/wxq/test.cpp:197
#2 0x00007ffff60a24f2 in create_extended (setup=0x5555559291c0) at /home/wxq/test.cpp:509
#3 0x0000555555555538 in main (argc=5, argv=0x7fffffffe0e8) at /home/wxq/core_model.cpp:145