2012-04-04 13 views
4

Also schrieb ich zwei einfache Klassen - X86StackFrame und X86CallStack:Wie wird das Ende des Aufrufs festgelegt?

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_; 
}; 

Der Schlüssel Methode hier ist Ctor der X86CallStack:

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); 
} 

Und das Problem ist ... Wie beende ich die Schleife? Ich meine, Frame/Return-Adresse gegen 0 zu überprüfen, tut manchmal den Trick, aber nicht immer (zumindest hier unter Windows).

Irgendwelche Vorschläge?

+0

I gcc.tgz/gcc/config/ia64/Abroll-ia64.c gefunden, könnte nützlich sein. Auch getcontext und höchstwahrscheinlich etwas von pthread library gibt Ihnen den Thread-Stack-Speicherbereich. –

+0

AFAIK, das nur auf Stack-Frames angewiesen ist, ist keine perfekte Lösung, da es Funktionen gibt, die diesem Standard nicht entsprechen (d. H. Einen Standard-Stack-Frame erstellen). Der MSVC-Debugger benötigt auch Symbole, um den Callstack vollständig wiederherzustellen. Wie auch immer, wenn Stapelrahmen konsistent sind - das Ende des Stapels ist tatsächlich durch eine Null-Rückkehradresse markiert. – valdo

Antwort

3

unter Windows die Thread Information Block lesen können Sie die Ober- und Unterseite des Stapels, so dass Sie vor dem Lesen etwas über diesen Bereich hinaus zu stoppen. Ich habe keine Ahnung, wie man ähnliche Informationen über andere Betriebssysteme bekommt.

+0

Großartig, danke !! – szx