显现函数的调用联系是调试器的必备功用,假如咱们在程序的运转中呈现了溃散的状况,经过函数的调用联系能够快速定位问题的本源,懂得函数调用联系的完成原理也能够扩大自己的知识面,在没有调试器的状况下,咱们也能够自己来完成显现函数的调用联系。在咱们自己动手写backtrace函数之前,先来看看glibc供给的backtrace函数的运用。代码如下:
#include
#include
#include
#define MAX_LEVEL 4
static void call2()
{
int i = 0;
void* buffer[MAX_LEVEL] = {0};
int size=backtrace(buffer, MAX_LEVEL);
for(i = 0; i < size; i++)
{
printf("called by %p\n", buffer[i]);
}
return;
}
static void call1()
{
call2();
return;
}
static void call()
{
call1();
return;
}
int main(int argc, char* argv[])
{
call();
return 0;
}
在此先讲解下backtrace()函数的运用:
int backtrace(void **buffer,int size)
该函数用来获取当时线程的调用仓库,获取的信息将会被存放在buffer中,它是一个指针列表。参数 size 用来指定buffer中能够保存多少个void* 元素。函数回来值是实践获取的指针个数,最大不超越size巨细,在buffer中的指针实践是从仓库中获取的回来地址,每一个仓库结构有一个回来地址。
接下来的使命便是编译运转了。
root@ubuntu:/home/shiyan# gcc -g -Wall sss.c -o p
root@ubuntu:/home/shiyan# ./p
输出成果为:
called by 0x8048440
called by 0x804847d
called by 0x804848a
called by 0x8048497
上面的运转成果便是调用者的地址,看起来还不是那么的直观,咱们运用addr2line东西来完成地址到源代码方位的转化。
运转
root@ubuntu:/home/shiyan# ./p |awk ‘{print "addr2line "$3" -e p"}’>t.sh;. t.sh;rm -f t.sh
输出成果为:
/home/shiyan/sss.c:12
/home/shiyan/sss.c:27
/home/shiyan/sss.c:34
/home/shiyan/sss.c:40
接下来看看在栈中数据的结构。
