您的位置:首页 > 其它

利用backtrace函数打印函数调用栈

2016-10-24 13:05 274 查看
我们一般打印函数调用栈可以选择GDB的backtrace命令,简写bt命令都可以。这里有一个新的方法,那就是利用backtrace函数打印,不过还要加上backtrace_symbols()函数。

int backtrace(void **buffer, int size)


该函数用于获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针列表。参数 size 用来指定buffer中可以保存多少个void* 元素。函数返回值是实际获取的指针个数,最大不超过size大小

在buffer中的指针实际是从堆栈中获取的返回地址,每一个堆栈框架有一个返回地址

backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组. 参数buffer应该是从backtrace函数获取的指针数组,size是该数组中的元素个数(backtrace的返回值)函数返回值是一个指向字符串数组的指针,它的大小同buffer相同.每个字符串包含了一个相对于buffer中对应元素的可打印信息.它包括函数名,函数的偏移地址,和实际的返回地址下面来看一个例子:

#include <iostream>
#include <stdlib.h>
#include <string>
#include <execinfo.h>
using namespace std;

string st;

void fun1_a(int a);
void fun2_b(char b);
int  fun3_c(double c);
void fun4_d(int a);

void fun1_a(int a)
{
fun2_b(1.1);
}

void fun2_b(char b)
{
fun3_c(1.1);
}

int fun3_c(double c)
{
const int len = 200;
void* buffer[len];
int nptr = ::backtrace(buffer, len);
char **strings = ::backtrace_symbols(buffer, nptr);
if(strings){
for(int i=0; i<nptr; ++i){
st.append(strings[i]);
st.push_back('\n');
}
free(strings);
}
fun4_d(4);
return 0;
}

void fun4_d(int a)
{
cout<<st;
}

int main()
{
fun1_a(1);
return 0;
}


输出如下:



直接运行的话输出是这样的,我们看不出调用了什么函数,下面加上一个选项。



选项 -rdynamic 用来通知链接器将所有符号添加到动态符号表中。_Z6是所有函数返回值,其中fun3_c是int类型,也是_Z6,这不就是我们说的返回值类型不能决定函数重载吗?fun3_c函数名,d是double类型,其他函数和fun3_c都一样。

如果我们想知道函数在第几行,可以这样:



OK。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息