Linux C++语言函数调用栈打印
在Linux 系统应用程序开发过程中,会遇到调用栈打印的场景,在上一篇文章《Linux C语言函数调用栈打印》中讲述了C语言函数调用栈的用法。C++ 语言的函数调用栈与C语言类似,只不过符号翻译有所不同。话不多说,直接上代码和运行结果。
main.cpp
// main.cpp
#include "a.h"
int main() {
A a;
a.run();
return 0;
}
a.h
// a.h
#include <string.h>
#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
class A {
public:
A() {}
~A() {}
int run();
};
a.cpp
// a.cpp
#include "a.h"
#include <execinfo.h>
#include "backtrace.h"
int A::run() {
void* callstack[128];
size_t frames = backtrace(callstack, 128);
vector<string> symbols = BacktraceCxxSymbols(callstack, frames);
for (auto s : symbols)
std::cout << s << std::endl;
std::cout << "------------------------" << std::endl;
char** strings = backtrace_symbols(callstack, frames);
for (int i = 0; i < frames; i++) {
std::cout << strings[i] << std::endl;
}
free(strings);
return 0;
}
backtrace.h
//backtrace.h
#include <string>
#include <vector>
std::vector<std::string> BacktraceCxxSymbols(void** array, int size);
backtrace.cpp
//backtrace.cpp
#include <cxxabi.h>
#include <string.h>
#include "backtrace.h"
using std::vector;
using std::string;
// #define __USE_GNU
#include <dlfcn.h>
vector<string> BacktraceCxxSymbols(void** array, int size) {
int status = 0;
char buf[4096] = {0};
char* p_demangled_name = NULL;
vector<string> symbol_vec;
Dl_info info = {0};
int i = 0;
void* addr_offset = NULL;
if (NULL == array || 0 == size) {
return symbol_vec;
}
for (i = 0; i < size; i++) {
memset(&info, 0, sizeof(Dl_info));
if (0 == dladdr(array[i], &info)) {
continue;
}
if (info.dli_saddr) {
addr_offset = (void*)((char*)array[i] - (char*)info.dli_saddr);
} else {
addr_offset = (void*)((char*)array[i] - (char*)info.dli_fbase);
}
if (!info.dli_sname) {
info.dli_sname = "";
}
if (!info.dli_fname) {
info.dli_fname = "";
}
memset(buf, 0, sizeof(buf));
p_demangled_name = abi::__cxa_demangle(info.dli_sname, NULL, NULL, &status);
if (0 == status && p_demangled_name) {
snprintf(buf, sizeof(buf), "%s(%s+%p) [%p]", info.dli_fname, p_demangled_name, addr_offset, array[i]);
} else {
snprintf(buf, sizeof(buf), "%s(%s+%p) [%p]", info.dli_fname, info.dli_sname, addr_offset, array[i]);
}
if (p_demangled_name) {
free(p_demangled_name);
}
symbol_vec.push_back(buf);
}
return symbol_vec;
}
Makefile
CXXFLAGES:= -fpic -O0 -g
# CXXFLAGES:=
all: test
# export LD_LIBRARY_PATH=/root/BASE1_0_r/build_x86:$LD_LIBRARY_PATH
test: main.o liba.so backtrace.so
g++ -I ./ -o test main.o -L ./ -la -lbacktrace -ldl $(CXXFLAGES)
liba.so: a.o
g++ -shared -o liba.so a.o
# libb.so: b.o
# g++ -shared -o libb.so b.o
backtrace.so: backtrace.o
g++ -shared -o libbacktrace.so backtrace.o
a.o: a.cpp
g++ $(CXXFLAGES) -c a.cpp
# b.o: b.c
# g++ $(CXXFLAGES) -c b.c
main.o: main.cpp
g++ $(CXXFLAGES) -c main.c
backtrace.o: backtrace.cpp
g++ $(CXXFLAGES) -c backtrace.cpp
clean: FORCE
rm -rf *.o
rm -rf *.so
rm -rf test
FORCE:
运行结果
./test
/root/BASE1_0_r/build_x86/liba.so(A::run()+0x3a) [0x7fdea6260594]
./test(+0x11fd) [0x5636bb7a71fd]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7fdea5e46083]
./test(+0x110e) [0x5636bb7a710e]
------------------------
/root/BASE1_0_r/build_x86/liba.so(_ZN1A3runEv+0x3a) [0x7fdea6260594]
./test(+0x11fd) [0x5636bb7a71fd]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7fdea5e46083]
./test(+0x110e) [0x5636bb7a710e]