【问题标题】:How to determine end of call stack?如何确定调用堆栈的结束?
【发布时间】:2012-04-18 08:22:54
【问题描述】:

所以我写了两个简单的类——X86StackFrame 和 X86CallStack:

class X86StackFrame {
public:
    X86StackFrame(void *frmAddr, void *retAddr);

    inline void *GetFrameAddress() const 
        { return frmAddr_; }
    inline void *GetReturnAddress() const 
        { return retAddr_; }

private:
    void *frmAddr_;
    void *retAddr_;
};

class X86CallStack {
public:
    X86CallStack();

    inline std::deque<X86StackFrame> GetFrames() const {
        return frames_;
    }

private:
    std::deque<X86StackFrame> frames_;
};

这里的关键方法是X86CallStack的ctor:

static inline void *GetReturnAddress(void *frmAddr) {
    return *reinterpret_cast<void**>(reinterpret_cast<char*>(frmAddr) + 4);
}

static inline void *GetNextFrame(void *frmAddr) {
    return *reinterpret_cast<void**>(frmAddr);
}

X86CallStack::X86CallStack()
    : frames_()
{
    void *frmAddr;
    void *retAddr;

    #if defined _MSC_VER
        __asm mov dword ptr [frmAddr], ebp
    #elif defined __GNUC__
        __asm__ __volatile__(
            "movl %%ebp, %0;" : "=r"(frmAddr) : : );
    #endif  

    do {
        if (frmAddr == 0) {
            break;
        }
        retAddr = GetReturnAddress(frmAddr);
        if (retAddr == 0) {
            break;
        }
        frmAddr = GetNextFrame(frmAddr);
        frames_.push_back(X86StackFrame(frmAddr, retAddr));
    } while (true);
}

问题是……我该如何结束这个循环?我的意思是,根据 0 检查帧/返回地址有时会奏效,但并非总是如此(至少在 Windows 上是这样)。

有什么建议吗?

【问题讨论】:

  • 我发现 gcc.tgz/gcc/config/ia64/unwind-ia64.c,可能有用。此外,getcontext 和 pthread 库中的某些内容很可能会为您提供线程堆栈内存区域。
  • AFAIK 仅依赖堆栈帧并不是一个完美的解决方案,因为有些函数不遵循此标准(即创建标准堆栈帧)。 MSVC 调试器还需要符号来完全恢复调用堆栈。无论如何,如果堆栈帧是一致的 - 堆栈的末尾确实由零返回地址标记。

标签: c++ callstack


【解决方案1】:

在 Windows 上,读取 Thread Information Block 可以为您提供堆栈的顶部和底部,因此您可以在读取超出该范围的任何内容之前停止。不过,我不知道如何在其他操作系统上获取类似信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 2012-09-06
    • 2010-09-28
    • 2019-04-29
    • 2020-09-27
    • 2023-03-11
    • 2011-02-04
    相关资源
    最近更新 更多