有时我们遇到问题去想查看call stack时,一般利用gdb工具,断点再bt即可查看,但是很多时候也许没有条件去使用gdb工具,这时就可以利用backtrace函数。下面就对该函数进行简单的原理分析和方法介绍

用法介绍

按照下图的code写即可显示出调用堆栈

不过需要注意的是,如果在gcc的时候 没有加上-rdynamic选项,那么在显示调用堆栈的时候,是没有显示那个函数调用的,像下图

如果加上了-rdynamic选项,就会显示出对应的函数了,我们project Makefile都有加这个选项

-rdynamic选项 主要是将所有的链接符号加到动态链接表(.dynsym)里,但不包含static修饰的函数

可利用readelf -s 命令查看dynsym表

对每个API进行分析

int backtrace(void **buffer, int size);

返回调用堆栈

buffer :提供一个指针的数组

size :指定缓冲区的个数,即设置的调用深度

int : 返回实际返回的调用深度

每个地址指针由 函数名、地址偏移、返回地址组成

char **backtrace_symbols(void *const *buffer, int size);

字符串结果通过该API返回,会在该函数中malloc,由我们free

一般的程序员写到上面就结束了或者看到上面就结束了,不一般的还会继续下面的内容

原理分析

想要弄清backtrace函数是怎么实现,需要先弄清调用栈

因为不同的芯片架构,指令、寄存器表示均不同,这里用ARM架构去看效果

将之前测试code全部贴出来如下,以这个code为例子

将main反汇编

lr寄存器,Link register,记录之前的执行位置,在退出时,赋给pc寄存器,返回执行

pc寄存器,Program counter,当前程序执行位置,随程序执行变化

sp寄存器,Stack pointer,当前栈指针的位置,随栈变化,每次PUSH -4 ;POP +4

r11寄存器,用来记录栈帧底部的地址

分析上面的main汇编语句

<+0> push {r11, lr}

将r11 和 lr寄存器推入至栈中

就是将上一个程序的栈帧底部位置保存至栈里,退出程序的时候好恢复,上一个程序的栈位置

<+4> add r11, sp, #4

将 sp + 4 赋给 r11

将该程序的栈帧底部位置保存至r11寄存器,

<+8> bl  0x89c4<fun1>

跳转至fun1函数

<+12> mov  r3, #0

赋给r3寄存器 3 值

<+16> mov r0, r3

将r3寄存器赋给r0

<+20> pop {r11, pc}

从栈中恢复r11寄存器,并将之前保存的lr寄存器的值赋给pc,以便恢复到之前的函数运行的状态

有点糊涂,没关系,再看一下fun1函数的汇编语句

再分析下fun1的汇编语句

<+0> push {r11, lr}

同样地,将r11寄存器和lr寄存器压入栈,这里的r11寄存器的值,就是在main函数中的栈帧底部的位置,这里的lr寄存器的值,就是在main函数执行bl命令时,将pc的值赋给了lr寄存器

<+4> add r11, sp, #4

就是将 sp + 4 赋给r11,现在r11的值就为fun1函数栈帧底部地址

<+8> bl 0x89b4 <fun2>

跳转至fun2函数

<+12> pop {r11, pc}

从栈中取出 之前保存的main函数的r11 和 lr,赋值给r11 和 pc,这样就恢复了main函数的运行

晓得上述流程之后,就可以实现backtrace函数,

首先,拿到本函数的r11寄存器,所指示的栈地址,出栈,就能得到调用函数的lr寄存器的值,然后就能通过dynsym动态链接表,找到对应的函数名

再出栈,就能得到调用函数的r11寄存器的值,以此类推,最终得到整个调用栈

本来想把glibc库中的实现秀出来,不过这个库是有调到so文件实现

延伸 

利用该API还可以迅速定位出段错误来,段错误时,会发送SIGSEGV信号,重载信号处理程序,将上面code加入进去,就能够得到调用堆栈

接着利用objdump 反编译出来objdump -d test > test.s,即可大致推测哪个语句导致的段错误

甚至,巧妙的利用send SIGTSTP信号和上述函数,就能制造出断点,和gdb一样的效果调试

使用BackTrace查看调用堆栈相关推荐

  1. 一种获取过程调用堆栈信息的简单方法

    在程序崩溃或出现异常时,通常需要给开发人员提供基本的过程调用的信息,这里给出一个简单的C++实现.主要思路是:过程调用的开始时,在栈上创建一个类,利用类的构造函数记录相关信息,在过程调用完毕时会自动调 ...

  2. 转:eclipse 调用堆栈 快捷键

    转自:http://www.verydemo.com/demo_c288_i65529.html Eclipse 修改Eclipse堆栈大小 修改Eclipse堆栈大小 -Xmx512M-Xms512 ...

  3. linux中追踪函数backtrace调用堆栈

    From: http://www.embeddedlinux.org.cn/html/jishuzixun/201211/19-2388.html 一般察看函数运行时堆栈的方法是使用GDB之类的外部调 ...

  4. linux c 用户态 调试追踪函数 调用堆栈 定位段错误

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

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

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

  6. 【听歌】GDB入门教程之查看函数调用堆栈

    写在前面:又到周末啦~上上周忍痛买了个雅马哈声卡和 AKG 话筒,这周六才正式打开试用了下,效果还不错,我自己还挺享受的.不过这玩意儿太高端,还不会用 AI 调音.小伙伴们感觉下这首加了一点点电音效果 ...

  7. 程序退出前的遗言----linux下利用backtrace追踪函数调用堆栈以及定位段错误

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

  8. libuv 编译使用,打印调用堆栈

    libuv 编译选项: CFLAGS='-g -O0 -funwind-tables' ./configure --disable-silent-rules --disable-udev --enab ...

  9. javascript 堆栈_JavaScript调用堆栈-它是什么以及为什么它是必需的

    javascript 堆栈 The JavaScript engine (which is found in a hosting environment like the browser), is a ...

最新文章

  1. 卡联科技与正元地理合作 打造智慧城市
  2. SPQuery 查询知多少
  3. Eclipse中修改tomcat内存大小
  4. java里面运行js_在java中利用rhino执行javascript
  5. android程序中关于webview加载html文件
  6. 百度C2C对决淘宝的两把利器
  7. php 分表 实战,PHP实战:1亿条数据如何分表100张到Mysql数据库中(PHP)
  8. Arquillian和Jboss的版本问题
  9. 设计模式之抽象工厂模式(Java实现)
  10. 监视Python程式自动退出,并重新启动程式
  11. html回调函数,JS 回调函数
  12. 特教学校计算机课,特教学校引入编程课 为听障孩子打开智能之门
  13. OEM 11g在win7 ie11下报错“证书错误,导航已阻止”的恢复方法
  14. 蓝光光盘的区域位置代码
  15. 微信公众平台的运营管理
  16. JSON和list之间的转换
  17. Tuscany SCA软件架构设计理念分析(二)
  18. beecloud对接——微信支付
  19. Unity—JsonFx序列化场景
  20. 粒子背景php,html5+canvas圆形粒子移动背景动画特效

热门文章

  1. 方程组的极大线性无关组与线性无关解的个数
  2. 4rx4 服务器内存2rx4_服务器内存条上写8GB,2RX4,其中2RX4是什么意思?是单条8G的。...
  3. 最新Winrar 32位中国代理版爆破笔记
  4. 美国NCEES的PE考试介绍
  5. 定义一个数组来存储10个学生的成绩,计算并输出学生的平均成绩
  6. 置顶!!!主页禁言提示原因:在自己论坛发动态误带敏感词,在自己论坛禁止评论90天
  7. 如何正确的使用vray渲染出高质量的画面?
  8. MMO即时战斗:地图角色同步管理和防作弊实现
  9. 001 扩展传感器分类介绍
  10. 陈慧娴《永远是你的朋友》专辑歌词