使用 gdb 恢复堆栈信息

用 C/C++ 编写的程序, 如果遇到 Segmentation Fault 则可以通过生成 coredump 来进行调试, 根据记录的信息定位到出错代码行. 但很多时候可能用 gdb 打开 coredump 文件查看堆栈时, 却出现一堆问号, 无法直接定位到出错代码行. 本文介绍另一种方法来还原错乱的堆栈信息.

例如, 下图是 coredump 后用 gdb 看到的堆栈信息, 可以看到这些代码都是系统依赖库中的函数信息, 如果太多地方调用这些库接口, 就很难定位到问题所在. 下图中应是在调用字符串转数字接口时出错.

coredump 堆栈信息示例

上图中仍无法定位到代码中的具体某一行. 不过寄存器 ebp 中存放了函数帧指针, 这就提供了一个追踪栈信息的线索. 首先将 ebp 的内容打印出来:

寄存器 ebp 的内容

众所周知, 栈即函数的调用栈布局. 每次函数调用, 就会将当前函数的地址及局部变量压入栈顶. 这些调用信息是以一个单向链表来组织的, 上面看到的 ebp 内容就是这个链表的 head 指针. 那么打印出 ebp 内容 0x9e76f354 指针所指内容如下:

寄存器 ebp 内容所指向的区域信息

与 head 节点一样, 第一个节点的最低 4 个字节存储的是下一链表节点位置的指针, 紧随其后的 4 个字节是该层调用的返回地址, 查看其内容如下:

第一个节点调用的返回地址

可以看到, 栈顶的函数地址是与 bt 命令打印的信息一致, 依次打印出该链表上节点信息如下:

链表各节点信息

上述信息已经基本还原了 bt 所能打印出来信息, 上图中后面的节点可以看出导致 coredump 的代码位置, 是在 TtcThmDescOper::tbThmDesc_get 函数中一次 atoll 调用时导致.

以上就是在 bt 无法打印堆栈内容时, 采用另一种方式还原函数调用层级的方式, 希望能对大家定位问题有一定帮助. 另外需要提醒大家的是, 在 64 位系统中, 寄存器 esp 变成了 rsp, 寄存器 ebp 变成了 rbp, 寄存器 ip 变成了 rip. 而在 arm 平台中, 寄存器 ebp 则变成了 fp.

参考文献

  1. gdb 如何还原错乱的堆栈信息 http://hobodong.me/post/81/gdb/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...
    小猪啊呜阅读 10,174评论 1 19
  • 一、温故而知新 1. 内存不够怎么办 内存简单分配策略的问题地址空间不隔离内存使用效率低程序运行的地址不确定 关于...
    SeanCST阅读 12,367评论 0 27
  • 程序core掉,要去debug,但是函数堆栈乱掉了,很恶心.....经过Google/wiki一番,找到两种解决办...
    zjfclimin阅读 9,847评论 0 3
  • 我多想晨起看笑颜如花,日中见岁月静好,夜晚如温暖的城。 我总是倔强地过着生活,也期许着徘徊时候有拥抱,孤单的时候有...
    涟漪瑞克斯旺阅读 715评论 0 0
  • 你须是那有理想的人 但不必鄙夷那鼠目寸光的 你须是那有操守的人 但不必抨击那自甘下流的 你须是那有高尚的人 但不必...
    崇文路2号阅读 1,404评论 0 0