高效获得Linux函数调用栈/backtrace的方法【转】
转自: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的方法【转】的更多相关文章
- 嵌入式 linux下利用backtrace追踪函数调用堆栈以及定位段错误
嵌入式 linux下利用backtrace追踪函数调用堆栈以及定位段错误 2015-05-27 14:19 184人阅读 评论(0) 收藏 举报 分类: 嵌入式(928) 一般察看函数运行时堆栈的 ...
- linux下利用backtrace追踪函数调用堆栈以及定位段错误
一般察看函数运行时堆栈的方法是使用GDB(bt命令)之类的外部调试器,但是,有些时候为了分析程序的BUG,(主要针对长时间运行程序的分析),在程序出错时打印出函数的调用堆栈是非常有用的. 在glibc ...
- Linux下利用backtrace追踪函数调用堆栈以及定位段错误【转】
转自:https://www.linuxidc.com/Linux/2012-11/73470p2.htm 通常情况系,程序发生段错误时系统会发送SIGSEGV信号给程序,缺省处理是退出函数.我们可以 ...
- 在linux代码中打印函数调用的堆栈的方法
之前一直有这样的需求,当时问到,也没搜到方法,现在竟然既问到了,也搜到了,哎,世事真是不能强求啊! 在Linux内核调试中,经常用到的打印函数调用堆栈的方法非常简单,只需在需要查看堆栈的函数中加入: ...
- Linux Debugging(一): 使用反汇编理解C++程序函数调用栈
拿到CoreDump后,如果看到的地址都是????,那么基本上可以确定,程序的栈被破坏掉了.GDB也是使用函数的调用栈去还原"事故现场"的.因此理解函数调用栈,是使用GDB进行现场 ...
- 理解 Linux 网络栈(1):Linux 网络协议栈简单总结
本系列文章总结 Linux 网络栈,包括: (1)Linux 网络协议栈总结 (2)非虚拟化Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO (3)QEMU/KVM + Vx ...
- (转)Java里的堆(heap)栈(stack)和方法区(method)(精华帖,多读读)
[color=red][/color]<一> 基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收. 引用数据类型,需要用new来创建,既在栈 ...
- C语言函数调用栈(一)
程序的执行过程可看作连续的函数调用.当一个函数执行完毕时,程序要回到调用指令的下一条指令(紧接call指令)处继续执行.函数调用过程通常使用堆栈实现,每个用户态进程对应一个调用栈结构(call sta ...
- Java里的堆(heap)栈(stack)和方法区(method)
基础数据类型直接在栈空间分配, 方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收. 引用数据类型,需要用new来创建,既在栈空间分配一个地址空间,又在堆空间分配对象的类变量 . 方法 ...
随机推荐
- docker 基础 之安装
一.安装 系统要求 Docker CE 支持 64 位版本 CentOS 7,并且要求内核版本不低于 3.10. CentOS 7 满足最低内核的要求,但由于内核版本比较低,部分功(如 overlay ...
- Nginx自定义404页面并返回404状态码
Nginx定义404页面并返回404状态码, WebServer是nginx,直接告诉我应该他们配置了nginx的404错误页面,虽然请求不存在的资源可以成功返回404页面,但返回状态码确是200. ...
- 【JQ】jq动态绑定事件.on()、解绑事件off()
#JQ 绑定与解绑事件的方法的历史演变 1. jquery1.4 及之前的版本,由.click() 或 .bind()方法绑定的事件,不能适用脚本创建的新元素:即是说页面加载完成后,再动态创建的DOM ...
- Freemarker中的日期输出
<p> ${scheme.createTime?string("yyyy年MM月dd日 HH:mm:ss")}</p>
- 阿里云部署Web项目
1.首先最基本的购买服务器和域名(学生党可以享受每月9块钱的优惠,不知道为什么,pc端不能购买,只能下载阿里云APP购买) 下载APP后打开:学生专区-学生特权-购买(我选择的是ubuntu,这个随 ...
- [复现]蝉知cms 5.6 前台注入
https://share.weiyun.com/5cbff06337d32a9748d0f1bead5ddbd5 前台注入 在/chanzhieps/system/module/cart/contr ...
- JMeter之Ramp-up Period(in seconds)说明(可同时并发)
Ramp-up Period(in seconds) [1]决定多长时间启动所有线程.如果使用10个线程,ramp-up period是100秒,那么JMeter用100秒使所有10个线程启动并运行. ...
- Golang入门教程(七)基本数据类型使用案例
18种基本数据类型使用 代码案例1 package main import "fmt" func main() { //使用 var 定义一个布尔类型并且初始化 var flag ...
- Mac Office 2016 破解
官方最新版本office 是2016.15.38 此版本主要是修复了Excel内存损害漏洞. 官方下载的版本大小是1.67G,因为其他途径下载的版本,不确保是最新版本且为完整的版本.不知道我说的这个大 ...
- 使用wget命令下载JDK失败(文件特别小)
问题RT: 我们在网页上下载的时候要点一下 “Accept License Agreement ” ,使用wget下载的时候也需要提交这个 accept,方法如下: wget --no-check-c ...