StackWalk64() возвращает один кадр

При попытке получить стек вызовов потока какого-либо процесса, я всегда получаю один и тот же кадр, хотя он наверняка имеет больше (по крайней мере, 5 кадров).

StackWalk64 () всегда завершается успешно при первом вызове - возвращает кадр с:

AddrPC.Offset = 18446744072850558156

Но сразу при втором вызове происходит сбой с идентификатором ошибки 998-ERROR_NOACCESS (возможно, эта ошибка не из-за этого вызова, как говорит MSDN).

Более того, попытка преобразовать этот адрес в его имя символа с помощью SymFromAddr() завершается неудачно с ошибкой 126-ERROR_MOD_NOT_FOUND (после успешного вызова SymInitialize(m_processHandler,NULL,TRUE)).

Вот код:

#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

что это может быть?

3 ответа

Решение

Решение:

Я пропустил часть сказал, что контекстная структура должна быть правильно инициализирована. Добавление следующего решило мою проблему:

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

Спасибо

Для тех, кто столкнется с этой проблемой в будущем, я также страдал от этого в нашей собственной локальной кодовой базе при получении информации о стеке из другого процесса в текущий. Причина заключалась в том, что мы пропустили PROCESS_VM_READ при получении дескриптора процесса с помощью OpenProcess().

Я рекомендую проект StackWalker на github. Он имеет лицензию BSD-2, если вы хотите использовать его напрямую. Это отличный рабочий пример кода, если вы предпочитаете создать свой собственный.

https://github.com/JochenKalmbach/StackWalker

Другие вопросы по тегам