C语言的那些小秘密之函数的调用关系
显示函数的调用关系是调试器的必备功能,如果我们在程序的运行中出现了崩溃的情况,通过函数的调用关系可以快速定位问题的根源,懂得函数调用关系的实现原理也可以扩充自己的知识面,在没有调试器的情况下,我们也可以自己来实现显示函数的调用关系。在我们自己动手写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 %pn", 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
接下来看看在栈中数据的结构。
![](http://editerupload.eepw.com.cn/201503/e02049ee98853eeaa65b9214caed65cc.gif)
![](https://webstorage.eepw.com.cn/images/2014/m/wx.png)
加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW
或用微信扫描左侧二维码
相关文章
-
-
2024-04-16
-
-
2024-03-21
-
网络与存储 2024-02-28
-
2024-02-01
-
2024-01-30
-
2024-01-18