Невозможно получить стек вызовов в Windows

0

Почему я получаю ошибку ERROR_INVALID_HANDLE в случае следующего кода? Что я делаю не так?

#include <Windows.h>
#include <DbgHelp.h>

#include <cstddef>
#include <cstring>
#include <iostream>

void print_call_stack()
{
  HANDLE cur_process_handle = GetCurrentProcess();
  HANDLE cur_thread_handle = GetCurrentThread();

  CONTEXT cur_thread_context;
  std::memset(&cur_thread_context, 0, sizeof(CONTEXT));
  cur_thread_context.ContextFlags = CONTEXT_FULL;
  if (!GetThreadContext(cur_thread_handle, &cur_thread_context))
  {
    std::cerr << "An error occurred while using function GetThreadContext. "
      << "Error code: " << GetLastError() << '\n';
    return;
  }

  STACKFRAME64 sf;
  std::memset(&sf, 0, sizeof(sf));
  sf.AddrPC.Mode         = AddrModeFlat;
  sf.AddrStack.Mode      = AddrModeFlat;
  sf.AddrFrame.Mode      = AddrModeFlat;
#ifdef _M_IX86  // Intel Only!
  sf.AddrPC.Offset       = cur_thread_context.Eip;
  sf.AddrStack.Offset    = cur_thread_context.Esp;
  sf.AddrFrame.Offset    = cur_thread_context.Ebp;
#endif
#ifdef _M_X64  // Intel Only!
  sf.AddrPC.Offset       = cur_thread_context.Rip;
  sf.AddrStack.Offset    = cur_thread_context.Rsp;
  sf.AddrFrame.Offset    = cur_thread_context.Rbp;
#endif
#ifdef _M_IA64 // Itanium
#pragma message("fix me")
  sf.AddrPC.Offset       = 0;
  sf.AddrStack.Offset    = 0;
  sf.AddrFrame.Offset    = 0;
#endif

#ifdef _M_IX86
  DWORD machine_type = IMAGE_FILE_MACHINE_I386;
#endif
#ifdef _M_X64
  DWORD machine_type = IMAGE_FILE_MACHINE_AMD64;
#endif
#ifdef _M_IA64
  DWORD machine_type = IMAGE_FILE_MACHINE_IA64;
#endif

  int count = 0;
  // According to MSDN, the sum of FramesToSkip and FramesToCapture
  // must be less than 63 in case of Windows Server 2003 and Windows XP,
  // so set it to 62
  void* trace[62];

  while (StackWalk64(
    machine_type
    , cur_process_handle
    , cur_thread_handle
    , &sf
    , &cur_thread_context
    , NULL
    , SymFunctionTableAccess64
    , SymGetModuleBase64
    , NULL
    ) == TRUE && count < sizeof(trace) / sizeof(*trace))
  {
    trace[count++] = reinterpret_cast<void*>(sf.AddrPC.Offset);
  }

  for (std::size_t i = 0; i < count; ++i)
  {
    const int kMaxNameLength = 256;
    DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]);

    ULONG64 buffer[
      (sizeof(SYMBOL_INFO) +
        kMaxNameLength * sizeof(wchar_t) +
        sizeof(ULONG64) - 1) /
        sizeof(ULONG64)];
      std::memset(buffer, 0, sizeof(buffer));

      // Initialize symbol information retrieval structures.
      DWORD64 sym_displacement = 0;
      PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]);
      symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
      symbol->MaxNameLen = kMaxNameLength - 1;
      BOOL has_symbol = SymFromAddr(
        cur_process_handle
        , frame
        , &sym_displacement
        , symbol
      );
      if (has_symbol == FALSE)
      {
        std::cerr << "An error occurred while using function SymFromAddr."
                  << " Error code: " << GetLastError() << '\n';
      }

      // Attempt to retrieve line number information.
      DWORD line_displacement = 0;
      IMAGEHLP_LINE64 line = {};
      line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
      BOOL has_line = SymGetLineFromAddr64(
        cur_process_handle
        , frame
        , &line_displacement
        , &line
      );
      if (has_line == FALSE)
      {
        std::cerr << "An error occurred while using function SymGetLineFromAddr64."
                  << " Error code: " << GetLastError() << '\n';
      }

      if (has_symbol == TRUE)
      {
        std::cout << symbol->Name << " [0x" << trace[i] << "+"
          << sym_displacement << "]";
      }
      else
      {
        std::cout << "(No symbol) [0x" << trace[i] << "]";
      }

      if (has_line == TRUE)
      {
        std::cout << " (" << line.FileName << ":" << line.LineNumber << ")";
      }

      std::cout << '\n';
  }
}

int main()
{
  print_call_stack();
}
  • 1
    В какой строке кода вы получаете ошибку?
  • 0
    @Mats Petersson У меня есть эти ошибки в случае использования функций SymFromAddr и SymGetLineFromAddr64
Показать ещё 4 комментария
Теги:

1 ответ

2
Лучший ответ

Согласно документам, сначала необходимо вызвать SymInitialize.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню