4

そこで、X86StackFrame と X86CallStack という 2 つの単純なクラスを作成しました。

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 では)。

助言がありますか?

4

1 に答える 1

3

Windows では、スレッド情報ブロックを読み取ると、スタックの上部と下部が得られるため、その範囲を超えるものを読み取る前に停止できます。ただし、他のOSで同様の情報を取得する方法はわかりません。

于 2012-04-04T15:42:56.320 に答える