Hagay Myr
Hagay Myr

Reputation: 409

StackWalk64() returns a single frame

When trying to obtain the call stack of a thread of some process, I always get a single same frame, although it is for sure has more (at least 5 frames).

StackWalk64() always succeeds on the first call - return a frame with:

AddrPC.Offset = 18446744072850558156

But, immediately on the second call it fails with error id 998-ERROR_NOACCESS (it might be that this error is not because of this call, as MSDN says).

Moreover, trying to resolve this address into its symbol name with SymFromAddr() fails with error 126-ERROR_MOD_NOT_FOUND (after successful SymInitialize(m_processHandler,NULL,TRUE) call).

Here is the code:

#ifdef _M_IX86
  //
  // Disable global optimization and ignore /GS waning caused by
  // inline assembly.
  //
  #pragma optimize( "g", off )
  #pragma warning( push )
  #pragma warning( disable : 4748 )
#endif

bool EchoProfiler::getThreadStackTrace(__in HANDLE h_thread, __out vector<DWORD64> &framesVec)
{
CONTEXT threadContext;
if (GetThreadContext(h_thread, &threadContext) == 0)
{
    cout << "Error: GetThreadContext() failed with error ID " << GetLastError() << endl;
    return false;
}

//initialize stack frame
DWORD MachineType;
STACKFRAME64 StackFrame;
ZeroMemory( &StackFrame, sizeof( STACKFRAME64 ) );

MachineType                 = IMAGE_FILE_MACHINE_I386;
StackFrame.AddrPC.Offset    = threadContext.Eip;
StackFrame.AddrPC.Mode      = AddrModeFlat;
StackFrame.AddrFrame.Offset = threadContext.Ebp;
StackFrame.AddrFrame.Mode   = AddrModeFlat;
StackFrame.AddrStack.Offset = threadContext.Esp;
StackFrame.AddrStack.Mode   = AddrModeFlat;

PVOID contextRec = (MachineType == IMAGE_FILE_MACHINE_I386) ? NULL : &threadContext;
int i=0;
// enumerate all the frames in the stack
for (i=1 ; ; i++)
{
    if (StackWalk64( MachineType, targetProcessHandler, h_thread, &StackFrame,
        contextRec, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL ) == false)
    {
        // in case it failed or we have finished walking the stack.
        cout << "Error: StackWalk64() failed with error ID " << GetLastError() << endl;
        i--;
        break;
        // return false;
    }

    if ( StackFrame.AddrPC.Offset != 0 )
    {
        // Valid frame.
        cout << "Frame #" << i << " address - " << StackFrame.AddrPC.Offset << endl;
        framesVec.push_back(StackFrame.AddrPC.Offset);
    }
    else
    {
        // Base reached.
        break;
    }
}

//cout << "StackWalk64 found " << i << " stack frames:" << endl;
//i = 1;
//for (FramesConstItr itr=framesVec.begin() ; itr != framesVec.end() ; itr++ , i++)
//  cout << i << " - " << *itr << endl;

return true;
}

#ifdef _M_IX86
  #pragma warning( pop )
  #pragma optimize( "g", on )
#endif

what could it be?

Upvotes: 3

Views: 2874

Answers (4)

Eric
Eric

Reputation: 1

I have success using RtlCaptureContext(&Context) to capture the current thread's context.

Upvotes: 0

trindflo
trindflo

Reputation: 349

I recommend the StackWalker project on github. It has a BSD-2 license if you wish to use it directly. It is great working sample code if you prefer to make your own.

https://github.com/JochenKalmbach/StackWalker

Upvotes: 0

Luke Haub
Luke Haub

Reputation: 21

For anyone running into this issue in the future, I also suffered from it in our own local codebase when getting stack information from a different process to the current one. The cause was that we were missing PROCESS_VM_READ when getting a handle on the process using OpenProcess().

Upvotes: 2

Hagay Myr
Hagay Myr

Reputation: 409

Solution:

I missed the part said that the context structure must be initialize properly. Adding the following solved my problem:

memset(&threadContext, 0, sizeof(CONTEXT));
threadContext.ContextFlags = CONTEXT_FULL;

Thanks

Upvotes: 3

Related Questions