Linux c/c++开发环境下,可以使用以下函数来获取进程调用的堆栈信息
#include <execinfo.h>
int backtrace(void **buffer, int size);
该函数用于获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针列表。
参数 size 用来指定buffer中可以保存多少个void* 元素。
函数返回值是实际获取的指针个数,最大不超过size大小,为了取得全部的函数调用列表,
应保证buffer和size足够大。
char **backtrace_symbols(void *const *buffer, int size);
backtrace_symbols函数将从backtrace函数获取的信息转化为一个字符串数组。
参数buffer是从backtrace函数获取的指针数组,size是该数组中的元素个数(backtrace的返回值),
函数返回值是一个指向字符串数组的指针,它的大小同buffer相同,每个字符串包含buffer中每个元
素对应地址的信息:它包括函数名、函数的偏移地址、和实际的返回地址。
简单的
#include <iostream>
#include <execinfo.h>
#include <signal.h>
using namespace std;
void test_sig(int sig)
{
void *array[10];
int size, i;
char **strings;
fprintf(stderr, "\nSegmentation fault\n");
size = backtrace(array, 10);
fprintf(stderr, "\nBacktrace (%d deep):\n", size);
strings = backtrace_symbols(array, size);
for (i=0; i < size; i++)
{
fprintf(stderr, "%d: %s, signal is %d\n", i, strings[i], sig);
}
free(strings);
strings = NULL;
}
int main()
{
signal(SIGSEGV, test_sig);
int *p = nullptr;
*p = 1;
}
输出结果
Segmentation fault
Backtrace (5 deep):
0: ./a() [0x4011e0], signal is 11
1: /lib/x86_64-linux-gnu/libc.so.6(+0x430c0) [0x7ff39e8f80c0], signal is 11
2: ./a() [0x40129c], signal is 11
3: /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7ff39e8d90b3], signal is 11
4: ./a() [0x4010ee], signal is 11
通过addr2line 可以定位的有段错误的地方
xxx@xxx:~/test$ addr2line -e a 0x40129c
/home/dwb/test/a.cpp:58
动态库
动态库找到的地址不是函数实际的地址,需要将堆栈异常的地址减去库文件加载的开始地址。可通过查询 /proc下的maps来确定库文件的开始地址。
可在main函数中加入
char maps[128] = {0x00};
snprintf(maps, sizeof(maps), "cat /proc/%d/maps", getpid());
system(maps);
结果会在终端输出。
如果是将异常导入到txt文件中的话,需要按照如下操作
结果
计算两个地址的差值,然后用addr2line来输出异常的地方如下:
int system(const char *command)
system()函数调用/bin/sh来执行参数指定的命令,/bin/sh 一般是一个软连接,指向某个具体的shell