转载时请注明出处和作者联系方式
作者联系方式:李先静 <xianjimli at hotmail dot com>

开发嵌入式软件通常是比较麻烦的事,一些常用的工具往往无法使用,在开发PC软件时简单的任务,此时变得很复杂。今天就遇到了这样一件事,折腾了几个小时,仅仅是为知道call stack。

我编译了一个程序放到PDA(ARM9+LINUX+UCLIBC)上面运行,出现了一个ASSERT,并显示了文件名和行号,原来是调用了一个没有实现的函数,我很想知道是谁调用了它,这看似简单的问题却让我很头疼,如果有gdb,那好办-用bt命令就可以搞定,如果用的libc,那也好办-用backtrace函数就可以搞定,问题是两者都没有。

想来想去只有自己写一个backtrace,要实现这个功能并不难,如果我们知道调用堆栈的格式,就可以很容易取出上层调用者的指令地址,有了这些上层调用者的指令地址,我们可以通过MAP文件找到指令地址对应的源文件名和行号。

下面简要介绍一下实现原理:

要获得调用者的地址,有必要介绍一下堆栈的格式:

+---------------------------+ (高地址)
+_参数1__________+
+---------------------------+
+_参数2__________+
+---------------------------+ 参数的顺序依赖于调用方式
+_参数.__________+
+---------------------------+
+_参数N__________+
+---------------------------+
+_eip____________+ 返回本次调用后,下一条指令的地址
+----------------------------+
+_ebp____________+ 这里保存的调用者的ebp
+----------------------------+
(ebp 指向这里:相当于调用者和被调用者的分界线)
+----------------------------+
+_临时变量1_______+
+----------------------------+
+_临时变量2_______+
+----------------------------+
+_临时变量.________+
+----------------------------+
+----------------------------+
+_临时变量N_______+
+----------------------------+(低地址)
由于优化、调用方式、编译器的不同,上述布局部可能有所不同,但一般来说,第一个局部变量前是调用者的ebp,ebp前是返回后下一条指令的地址。

知道了这个结构,要获得上层调用的者指令地址就容易了,我们可以用如下代码模拟glibc提供的backtrace的功能:
int backtrace (void **BUFFER, int SIZE)
{
    int n = 0;
    int *p = &n;
    int i = 0;

int ebp = p[1];
    int eip = p[2];

for(i = 0; i < SIZE; i++)
    {
        BUFFER[i] = (void*)eip;
        p = (int*)ebp;
        ebp = p[0];
        eip = p[1];
    }

return SIZE;
}

附:
  通过addr2line可以找到地址对应的文件名和行号,不用手动去查MAP文件了。

谁在CALL我 -- callstack的实现原理相关推荐

  1. Native层HIDL服务的注册原理-Android10.0 HwBinder通信原理(六)

    摘要:本节主要来讲解Android10.0 Native层HIDL服务的注册原理 阅读本文大约需要花费23分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Androi ...

  2. Android10.0 Binder通信原理(四)-Native-C\C++实例分析

    摘要:本节主要来讲解Android10.0 Binder的Native层实例流程 阅读本文大约需要花费35分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Androi ...

  3. SendMessage、PostMessage原理

    SendMessage.PostMessage原理 本文讲解SendMessage.PostMessage两个函数的实现原理,分为三个步骤进行讲解,分别适合初级.中级.高级程序员进行理解,三个步骤分别 ...

  4. SAP CRM One Order函数CRM_Object_FILL_OW的设计原理

    标题:SAP CRM One Order函数CRM_FILL_OW的设计原理 There are totally 60 function modules in One order with namin ...

  5. SendMessage、PostMessage原理和源代码详解

    本文讲解SendMessage.PostMessage两个函数的实现原理,分为三个步骤进行讲解,分别适合初级.中级.高级程序员进行理解,三个步骤分别为: 1.SendMessage.PostMessa ...

  6. Kotlin 协程,怎么开始的又是怎么结束的?原理讲解!

    九心 | 作者 承香墨影 | 校对 https://juejin.cn/post/6862548590092140558 | 原文 Hi,大家好,这里是承香墨影! 上周我们聊到 Kotlin 协程的使 ...

  7. 一篇读懂:Android手机如何通过USB接口与外设通信(附原理分析及方案选型)

    更多技术干货,欢迎扫码关注博主微信公众号:HowieXue,共同探讨软件知识经验,关注就有海量学习资料免费领哦: 目录 0背景 1.手机USB接口通信特点 1.1 使用方便 1.2 通用性强 1.3 ...

  8. ZT自老罗的博客 Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析...

    Android系统的智能指针(轻量级指针.强指针和弱指针)的实现原理分析 分类: Android 2011-09-23 00:59 31568人阅读 评论(42) 收藏 举报 androidclass ...

  9. ATECC508A芯片开发笔记(八):ECDH算法配置方法、执行过程及实现原理

    目录 AATECC508A芯片开发笔记(八):ECDH算法配置方法.过程原理及示例代码 1.ECDH介绍及原理 2.ECDH执行过程 3.508A某一slot执行Ecdh需要配置的参数 4.示例代码 ...

最新文章

  1. 新加坡计划通过区块链促进东盟金融包容性
  2. 设计模式学习----装饰器模式
  3. Redis 键(key) 命令
  4. IoU 判断矩形区域重叠
  5. SpringBoot配置Druid
  6. windows与linux中的路径书写,斜杠、反斜杠用法总结
  7. linux 文件夹 含义 表示(转)
  8. 3_4 IteratorMode 迭代器模式
  9. @Deprecated 注解 (@Documented 、@Retention、@Target)
  10. ssm如何在mapper插入实时的时间_第一个ssm整合
  11. ToolStripStatusRollingLabel——滚动显示状态栏标签
  12. 在web.config中添加配置信息
  13. 【算法基础】动态规划解题实例之野营问题
  14. 关于秩的等式与不等式总结
  15. 魅族魅蓝note3完美开启usb调试模式的经验
  16. Java进阶之路,技术要点
  17. 多目标遗传优化算法nsga2[python源码实现]
  18. STM32驱动TM1616程序加原理图
  19. 计算机导论 ——绪论
  20. Bentley MicroStation CE版的颜色变换(CONNECT Edition)

热门文章

  1. python seo分析器_python与SEO浅谈Python+ELK打造seo数据分析监控系统
  2. 计算机网络网站qige,海尔第三代七哥 Air Magic体感应用体验
  3. 华为DCIP Datacom认证分类
  4. 义嘉泰携手----炬芯蓝牙双模ATS3085 ATS3085C
  5. 响铃:智能小程序瞄准民生,发红包之外百度App的春节谋局
  6. 2019年,我被裁了!
  7. 东北大学20春计算机在线作业,东北大学19春《冶金工程计算机控制与仿真》在线作业123...
  8. HX711称重传感器的功能实现
  9. Java期末作业——王者荣耀的洛克王国版游戏
  10. rctimer二轴云台及云台控制板调试(Simple bgc 8位破解板)