【发布时间】: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 调试器还需要符号来完全恢复调用堆栈。无论如何,如果堆栈帧是一致的 - 堆栈的末尾确实由零返回地址标记。