backtrace就是回溯程序的函数栈,我们在代码调试中经常会遇到,现总结下笔者所知道的以下四种backtrace方式:
1、直接调用libc函数 int backtrace(void**, int)
2、通过gcc内置函数__builtin_return_address获取函数返回地址,从而得到栈信息
3、直接内嵌汇编指令,读取寄存器数据,获取函数返回地址
4、使用libunwind.so接口函数int unw_backtrace (void**, int)
对比上述4种方式的性能, 1)的性能最差,和2)、3)、4)差一个数量级; 2)和3)性能最好, 性能是4)的3倍多
具体测试代码如下:
#include <execinfo.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include <thread> #include <dlfcn.h> /* gcc内置函数 */ /***********************************************/ #define GCCBT(i) \ if(i >= size) return i;\ frameNow = __builtin_frame_address(i);\ if((unsigned long)frameNow <= (unsigned long)frameLast ||\ ((unsigned long)frameLast != 0 && (unsigned long)frameNow > (unsigned long)frameLast + (1ULL<<24)))\ return i;\ frameLast = frameNow;\ stack[i] = __builtin_extract_return_addr(__builtin_return_address(i));\ static int gccBacktrace(void** stack, int size) { void* frameNow = 0; void* frameLast = 0; GCCBT(0); GCCBT(1); GCCBT(2); GCCBT(3); GCCBT(4); GCCBT(5); GCCBT(6); GCCBT(7); GCCBT(8); GCCBT(9); GCCBT(10); GCCBT(11); GCCBT(12); GCCBT(13); GCCBT(14); GCCBT(15); GCCBT(16); GCCBT(17); GCCBT(18); GCCBT(19); GCCBT(20); GCCBT(21); GCCBT(22); GCCBT(23); GCCBT(24); GCCBT(25); GCCBT(26); GCCBT(27); GCCBT(28); GCCBT(29); GCCBT(30); GCCBT(31); return 32; } /* 内置汇编获取寄存器返回值 */ /***********************************************/ static int asmBacktrace(void** stack, int size) { #ifndef __x86_64__ return 0; #else int frame = 0; void ** ebp; unsigned long long func_frame_distance = 0; __asm__ __volatile__("mov %%rbp, %0;\n\t" : "=m"(ebp) ::"memory"); while (ebp && frame < size && (unsigned long long)(*ebp) < (unsigned long long)(ebp) + (1ULL << 24)//16M && (unsigned long long)(*ebp) > (unsigned long long)(ebp)) { stack[frame++] = *(ebp + 1); ebp = (void**)(*ebp); } return frame; #endif } static int flag = 1; static int(*pfnBt)(void**, int); void func5() { void *btbuf[16]; int btnum = pfnBt(btbuf, 16); if (flag == 1) { flag = 2; char **strings = backtrace_symbols(btbuf, btnum); for (int i = 0; i < btnum; ++i) { printf("%p %s\n", btbuf[i], strings[i]); } free(strings); } } void func4() { func5(); } void func3() { func4(); } void func2() { func3(); } void func1(int num) { for (int i = 0; i < num; ++i) { func2(); } } int main(int argc, char** argv) { if (argc != 3) { printf("param1: int -- each thread loop number\n"); printf("param2: string --bt method libc/gcc/asm/unw\n"); return -1; } int loopNum = atoi(argv[1]); std::string method = argv[2]; if (method == "libc") { printf("test libc\n"); pfnBt = backtrace; } else if (method == "gcc") { printf("test gcc\n"); pfnBt = gccBacktrace; } else if (method == "asm") { printf("test asm\n"); pfnBt = asmBacktrace; } else if (method == "uwn") { printf("test uwn\n"); void* handle = dlopen("./libunwind.so",RTLD_LAZY|RTLD_LOCAL); if (handle == NULL) { printf("dlopen failed, %s\n", dlerror()); return -1; } pfnBt = (int(*)(void**, int))dlsym(handle, "unw_backtrace"); if (pfnBt == NULL) { printf("dlsym failed, %s\n", dlerror()); return -1; } } else { printf("please input right method lic/gcc/asm/uwn\n"); return -1; } std::thread thd[20]; for (int i = 0; i < 20; ++i) { thd[i] = std::thread(func1, loopNum); } for (int i = 0; i < 20; ++i) { thd[i].join(); } return 0; }
编译命令:
g++ bt.cpp -o bt -lpthread -ldl -std=c++11 -g
对比测试效果截图如下:
标签:return,int,backtrace,void,几种,printf,include,方法 From: https://www.cnblogs.com/ho966/p/17084350.html