转自:https://blog.csdn.net/littlefang/article/details/42295803

有四种方法可以获得Linux的函数调用堆栈,参见CALL STACK TRACE GENERATION。

在这里简单罗列一下文中提到的四个方案:

方法1 GCC内置函数__builtin_return_address

方法2 Glibc中的backtrace函数

方法3 Jeff Muizelaar实现的增强backtrace,除了函数名,还能获得代码行号

方法4 libunwind

这里面的方法2和方法4都尝试过,方法2的backtrace函数是通过读取操作系统的一个全局信息区,在多线程并发调用时,会造成严重的锁冲突。

方法4的libunwind也存在开销较大的问题。

最终采用了下面的方案:

#define STACKCALL __attribute__((regparm(1),noinline))
void ** STACKCALL getEBP(void){
void **ebp=NULL;
__asm__ __volatile__("mov %%rbp, %0;\n\t"
:"=m"(ebp) /* 输出 */
: /* 输入 */
:"memory"); /* 不受影响的寄存器 */
return (void **)(*ebp);
}
int my_backtrace(void **buffer,int size){

int frame=0;
void ** ebp;
void **ret=NULL;
unsigned long long func_frame_distance=0;
if(buffer!=NULL && size >0)
{
ebp=getEBP();
func_frame_distance=(unsigned long long)(*ebp) - (unsigned long long)ebp;
while(ebp&& frame<size
&&(func_frame_distance< (1ULL<<24))//assume function ebp more than 16M
&&(func_frame_distance>0))
{
ret=ebp+1;
buffer[frame++]=*ret;
ebp=(void**)(*ebp);
func_frame_distance=(unsigned long long)(*ebp) - (unsigned long long)ebp;
}
}
return frame;
}

my_backtrace返回的内容和glibc的backtrace相同,可以用《使用backtrace获得动态链接库的调用地址》中的方法获得可读的调用栈。

局限性:

如果源代码编译时使用了-O1或-O2优化选项,可执行代码会把ebp/rbp/rsp寄存器当作普通寄存器使用,导致backtrace失败。为了防止这种情况发生,可以在编译时使用-O2  -fno-omit-frame-pointer  或-Og 来避免优化中使用上述寄存器。

文中的关于my_backtrace的实现主要归功于WangPeng同学。

参考文献

http://blog.chinaunix.net/uid-24774106-id-3457205.html

http://www.linuxidc.com/Linux/2011-08/41641.htm
---------------------
作者:镇关西
来源:CSDN
原文:https://blog.csdn.net/littlefang/article/details/42295803
版权声明:本文为博主原创文章,转载请附上博文链接!

高效获得Linux函数调用栈/backtrace的方法【转】的更多相关文章

  1. 嵌入式 linux下利用backtrace追踪函数调用堆栈以及定位段错误

    嵌入式 linux下利用backtrace追踪函数调用堆栈以及定位段错误 2015-05-27 14:19 184人阅读 评论(0) 收藏 举报  分类: 嵌入式(928)  一般察看函数运行时堆栈的 ...

  2. linux下利用backtrace追踪函数调用堆栈以及定位段错误

    一般察看函数运行时堆栈的方法是使用GDB(bt命令)之类的外部调试器,但是,有些时候为了分析程序的BUG,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的. 在glibc ...

  3. Linux下利用backtrace追踪函数调用堆栈以及定位段错误【转】

    转自:https://www.linuxidc.com/Linux/2012-11/73470p2.htm 通常情况系,程序发生段错误时系统会发送SIGSEGV信号给程序,缺省处理是退出函数.我们可以 ...

  4. 在linux代码中打印函数调用的堆栈的方法

    之前一直有这样的需求,当时问到,也没搜到方法,现在竟然既问到了,也搜到了,哎,世事真是不能强求啊! 在Linux内核调试中,经常用到的打印函数调用堆栈的方法非常简单,只需在需要查看堆栈的函数中加入: ...

  5. Linux Debugging(一): 使用反汇编理解C++程序函数调用栈

    拿到CoreDump后,如果看到的地址都是????,那么基本上可以确定,程序的栈被破坏掉了.GDB也是使用函数的调用栈去还原"事故现场"的.因此理解函数调用栈,是使用GDB进行现场 ...

  6. 理解 Linux 网络栈(1):Linux 网络协议栈简单总结

    本系列文章总结 Linux 网络栈,包括: (1)Linux 网络协议栈总结 (2)非虚拟化Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO (3)QEMU/KVM + Vx ...

  7. (转)Java里的堆(heap)栈(stack)和方法区(method)(精华帖,多读读)

    [color=red][/color]<一> 基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收.   引用数据类型,需要用new来创建,既在栈 ...

  8. C语言函数调用栈(一)

    程序的执行过程可看作连续的函数调用.当一个函数执行完毕时,程序要回到调用指令的下一条指令(紧接call指令)处继续执行.函数调用过程通常使用堆栈实现,每个用户态进程对应一个调用栈结构(call sta ...

  9. Java里的堆(heap)栈(stack)和方法区(method)

    基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收.   引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 . 方法 ...

随机推荐

  1. linux chmod命令使用

    chmod:更改文件9个属性 Linux文件属性有两种设置方法,一种是数字,一种是符号. Linux文件的基本权限就有九个,分别是owner/group/others三种身份各有自己的read/wri ...

  2. windows安装mysql5.7.xx解压版

    解压后修改配置文件 my.ini [mysql] # 设置mysql客户端默认字符集 default-character-set=utf8 [mysqld] #设置3306端口 port = 3306 ...

  3. mysql 用户及权限管理 小结

    MySQL 默认有个root用户,但是这个用户权限太大,一般只在管理数据库时候才用.如果在项目中要连接 MySQL 数据库,则建议新建一个权限较小的用户来连接. 在 MySQL 命令行模式下输入如下命 ...

  4. 【leetcode-102,107,103】 二叉树的层次遍历

    102. 二叉树的层次遍历 (1过,隐蔽错误花时间很多,简单题目本应很快,下次注意红色错误的地方) 给定一个二叉树,返回其按层次遍历的节点值. (即逐层地,从左到右访问所有节点). 例如:给定二叉树: ...

  5. 剑指offer面试题4: 二维数组中的查找

    题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数 ...

  6. VS Code +node npm 调试 js

    打开vsCode的调试控制台里面的终端 然后输入下面代码 npm install express-generator -g 1 创建一个命名为 myapp 的应用. express myapp 你就可 ...

  7. None.js 第四步 事件驱动程序

    Node.js 有多个内置的事件,我们可以通过引入 events 模块,并通过实例化 EventEmitter 类来绑定和监听事件 // 导入events模块 var events = require ...

  8. REST POST PUT差别

    rest api http://www.cnblogs.com/zhangpengshou/archive/2012/07/09/2583096.html Rest模式get,put,post,del ...

  9. python3.x与2.x区别

    1.性能 Py3.0运行 pystone benchmark的速度比Py2.5慢30%.Guido认为Py3.0有极大的优化空间,在字符串和整形操作上可 以取得很好的优化结果. Py3.1性能比Py2 ...

  10. 广度优先遍历(BFS )(转)

    宽度优先搜索(BFS, Breadth First Search)是一个针对图和树的遍历算法.发明于上世纪50年代末60年代初,最初用于解决迷宫最短路径和网络路由等问题. 对于下面的树而言,BFS方法 ...