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追踪函数调用堆栈以及定位段错误