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

时间:2009-02-24 17:27:12

标签: c linux stack backtrace

我的日志代码使用backtrace()的返回值来确定当前的堆栈深度(用于漂亮的打印目的),但我可以从分析中看到这是一个非常昂贵的调用。

我认为没有更便宜的方法吗?请注意,我不关心帧地址,只关注它们中有多少。

编辑:这些日志记录功能遍布大型代码库,因此手动跟踪堆栈深度并不是一种选择。

4 个答案:

答案 0 :(得分:5)

自己走堆栈很快 - backtrace()中的大部分缓慢来自于查找符号名称。在x86上,您可以执行以下操作:

inline uint32_t get_ebp(void)
{
    __asm__ __volatile__("mov %%ebp, %%eax");
}

int get_stack_depth(void)
{
    uint32_t ebp = get_ebp();
    int stack_depth = 0;
    while(ebp != 0)
    {
        ebp = *(uint32_t *)ebp;
        stack_depth++;
    }
    return stack_depth;
}

这将走ebp指针链。请记住,这是非常不便携的。另请注意,这不会计算内联或尾调用优化的任何函数(当然,backtrace()也有同样的问题)。

另一个重要问题是终止条件 - 一旦你追溯到main(),通常不能保证你在堆栈中找到什么。因此,如果libc没有放置空帧指针,那么很可能是段错误。您可以在main()的最开头查看终止值。

答案 1 :(得分:2)

如果合理地包含了漂亮的打印功能,那么将缩进(或缩进大小)作为参数传递,并在调用其他显示函数时将其递增。

答案 2 :(得分:2)

难道你不能随身携带一个TLS变量,并称之为“深度”并将其递增/递减每个函数吗?虽然你可以编写自己的代码来更快地遍历堆栈,但它仍然比仅仅携带变量更慢。

答案 3 :(得分:2)

对于手臂架构:

register unsigned long *rfp asm("fp");
unsigned long *fp = rfp;
unsigned long depth = 0;

while(fp)
{
    fp = (unsigned long *)(*(fp -3));
    depth++;
}

return depth;