glibc backtrace() 如何确定哪些堆栈内存是返回地址?

Posted

技术标签:

【中文标题】glibc backtrace() 如何确定哪些堆栈内存是返回地址?【英文标题】:How does glibc backtrace() determine which stack memory are the return addresses? 【发布时间】:2020-11-18 15:29:23 【问题描述】:

就程序而言,堆栈只是一堆内存。回溯函数如何确定哪些堆栈字节是指令指针返回地址,而不是哪些只是函数参数等?

【问题讨论】:

大概是使用.eh_frame stack-unwind 元数据来允许展开,即使没有帧指针;希望这能给你一些谷歌上的东西。 @Peter 我不认为 backtrace() 有那么聪明,我相信它只适用于传统的帧指针布局。 似乎我错了,似乎使用unwind capability from libgcc,这意味着支持时的eh_frame东西。 @PeterCordes 相关:Why GCC compiled C program needs .eh_frame section? 【参考方案1】:

就程序而言,堆栈只是一堆内存。

没错。如果您对程序的结构一无所知,您将无法展开其堆栈。

用于展开的最简单结构是保留一个“帧指针”寄存器以始终指向当前帧,并且该帧包含上一个帧指针在一个已知的偏移量。

这是在i*86 上使用了很长时间的机制,现在仍然在许多RISC 机器上使用。它使堆栈展开变得容易且非常快速,但在寄存器匮乏的机器上效率不高,例如i*x86 和较低程度的x86_64,因为该帧寄存器可以在其他地方更好地使用。

解决方案是创建增强数据,它描述如何在给定当前寄存器集和内存内容的情况下找到当前帧(例如,“当前帧位于从$rsp 偏移 NN 处”,或“在距离$rbp的偏移量MM”,“上一帧在距离当前帧的偏移量J”等)

这实际上就是.eh_frame。将其从您的二进制文件中删除,将无法展开堆栈。

这种机制也比简单的帧指针遍历慢得多,需要复杂的代码,并且容易出错(编译器不能保证发出正确的展开描述符,手工编码的程序集可能根本没有它们)。

other solutions 可以快速轻松地展开,但它们需要不同的调用约定。

【讨论】:

以上是关于glibc backtrace() 如何确定哪些堆栈内存是返回地址?的主要内容,如果未能解决你的问题,请参考以下文章

Linux下利用backtrace追踪函数调用堆栈以及定位段错误[转]

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

内存GLIBC堆内存申请

Java虚拟机:如何判定哪些对象可回收?

有没有比使用 backtrace() 更便宜的方法来查找调用堆栈的深度?

iOS堆内存碎片化及如何定位优化