diff options
Diffstat (limited to 'src/common/Debugging/Windows')
| -rw-r--r-- | src/common/Debugging/Windows/WheatyExceptionReport.cpp | 290 | ||||
| -rw-r--r-- | src/common/Debugging/Windows/WheatyExceptionReport.h | 60 | 
2 files changed, 178 insertions, 172 deletions
diff --git a/src/common/Debugging/Windows/WheatyExceptionReport.cpp b/src/common/Debugging/Windows/WheatyExceptionReport.cpp index cec3a27e002..87bca0add80 100644 --- a/src/common/Debugging/Windows/WheatyExceptionReport.cpp +++ b/src/common/Debugging/Windows/WheatyExceptionReport.cpp @@ -6,7 +6,9 @@  #include "WheatyExceptionReport.h"  #include "Errors.h"  #include "GitRevision.h" +#include <stdexcept>  #include <algorithm> +#include <utility>  #ifdef __clang__  // clang-cl doesn't have these hardcoded types available, correct ehdata_forceinclude.h that relies on it @@ -25,6 +27,12 @@  #pragma comment(linker, "/DEFAULTLIB:dbghelp.lib")  #pragma comment(linker, "/DEFAULTLIB:wbemuuid.lib") +#ifdef _UNICODE +#define PRSTRc "S"  // format specifier for char* strings +#else +#define PRSTRc "s"  // format specifier for char* strings +#endif +  inline LPTSTR ErrorMessage(DWORD dw)  {      LPVOID lpMsgBuf; @@ -48,37 +56,24 @@ inline LPTSTR ErrorMessage(DWORD dw)  }  //============================== Global Variables ============================= - -// -// Declare the static variables of the WheatyExceptionReport class and force their initialization before any other static in the program -// -#pragma warning(push) -#pragma warning(disable: 4073) // C4073: initializers put in library initialization area -#pragma init_seg(lib) -TCHAR WheatyExceptionReport::m_szLogFileName[MAX_PATH]; -TCHAR WheatyExceptionReport::m_szDumpFileName[MAX_PATH]; -LPTOP_LEVEL_EXCEPTION_FILTER WheatyExceptionReport::m_previousFilter; -_invalid_parameter_handler WheatyExceptionReport::m_previousCrtHandler; -FILE* WheatyExceptionReport::m_hReportFile; -HANDLE WheatyExceptionReport::m_hDumpFile; -HANDLE WheatyExceptionReport::m_hProcess; -SymbolPairs WheatyExceptionReport::symbols; -std::stack<SymbolDetail> WheatyExceptionReport::symbolDetails; -bool WheatyExceptionReport::alreadyCrashed; -std::mutex WheatyExceptionReport::alreadyCrashedLock; -WheatyExceptionReport::pRtlGetVersion WheatyExceptionReport::RtlGetVersion; -#pragma warning(pop) +namespace +{ +WheatyExceptionReport* g_WheatyExceptionReport; +}  //============================== Class Methods ============================= -WheatyExceptionReport::WheatyExceptionReport()             // Constructor +WheatyExceptionReport::WheatyExceptionReport() :           // Constructor +    m_logFileName(), +    m_dumpFileName(), +    m_previousFilter(SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter)), +    m_previousCrtHandler(_set_invalid_parameter_handler(WheatyCrtHandler)), +    m_reportFile(nullptr), +    m_dumpFile(), +    m_process(GetCurrentProcess()), +    m_alreadyCrashed(false), +    RtlGetVersion((pRtlGetVersion)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlGetVersion"))  { -    // Install the unhandled exception filter function -    m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter); -    m_previousCrtHandler = _set_invalid_parameter_handler(WheatyCrtHandler); -    m_hProcess = GetCurrentProcess(); -    alreadyCrashed = false; -    RtlGetVersion = (pRtlGetVersion)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlGetVersion");      if (!IsDebuggerPresent())      {          _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); @@ -86,6 +81,9 @@ WheatyExceptionReport::WheatyExceptionReport()             // Constructor          _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);          _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);      } + +    if (std::exchange(g_WheatyExceptionReport, this) != nullptr) +        throw std::logic_error("Only one instance of WheatyExceptionReport can exist");  }  //============ @@ -98,6 +96,8 @@ WheatyExceptionReport::~WheatyExceptionReport()      if (m_previousCrtHandler)          _set_invalid_parameter_handler(m_previousCrtHandler);      ClearSymbols(); + +    g_WheatyExceptionReport = nullptr;  }  //=========================================================== @@ -106,12 +106,17 @@ WheatyExceptionReport::~WheatyExceptionReport()  LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter(  PEXCEPTION_POINTERS pExceptionInfo)  { -    std::unique_lock<std::mutex> guard(alreadyCrashedLock); +    return g_WheatyExceptionReport->UnhandledExceptionFilterImpl(pExceptionInfo); +} + +LONG WheatyExceptionReport::UnhandledExceptionFilterImpl(PEXCEPTION_POINTERS pExceptionInfo) +{ +    std::unique_lock<std::mutex> guard(m_alreadyCrashedLock);      // Handle only 1 exception in the whole process lifetime -    if (alreadyCrashed) +    if (m_alreadyCrashed)          return EXCEPTION_EXECUTE_HANDLER; -    alreadyCrashed = true; +    m_alreadyCrashed = true;      TCHAR module_folder_name[MAX_PATH];      GetModuleFileName(nullptr, module_folder_name, MAX_PATH); @@ -129,21 +134,15 @@ PEXCEPTION_POINTERS pExceptionInfo)              return 0;      } -#ifdef _UNICODE -#define PRSTRc "S" -#else -#define PRSTRc "s" -#endif -      SYSTEMTIME systime;      GetLocalTime(&systime); -    _stprintf_s(m_szDumpFileName, _T("%s\\%" PRSTRc "_%s_[%u-%u_%u-%u-%u].dmp"), +    _stprintf_s(m_dumpFileName, _T("%s\\%" PRSTRc "_%s_[%u-%u_%u-%u-%u].dmp"),          crash_folder_path, GitRevision::GetHash(), pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond); -    _stprintf_s(m_szLogFileName, _T("%s\\%" PRSTRc "_%s_[%u-%u_%u-%u-%u].txt"), +    _stprintf_s(m_logFileName, _T("%s\\%" PRSTRc "_%s_[%u-%u_%u-%u-%u].txt"),          crash_folder_path, GitRevision::GetHash(), pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond); -    m_hDumpFile = CreateFile(m_szDumpFileName, +    m_dumpFile = CreateFile(m_dumpFileName,          GENERIC_WRITE,          0,          nullptr, @@ -151,7 +150,7 @@ PEXCEPTION_POINTERS pExceptionInfo)          FILE_FLAG_WRITE_THROUGH,          nullptr); -    if (m_hDumpFile) +    if (m_dumpFile)      {          MINIDUMP_EXCEPTION_INFORMATION info;          info.ClientPointers = FALSE; @@ -171,20 +170,20 @@ PEXCEPTION_POINTERS pExceptionInfo)              additionalStreamInfo.UserStreamCount = 1;          } -        MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), -            m_hDumpFile, MiniDumpWithIndirectlyReferencedMemory, &info, &additionalStreamInfo, nullptr); +        MiniDumpWriteDump(m_process, GetCurrentProcessId(), +            m_dumpFile, MiniDumpWithIndirectlyReferencedMemory, &info, &additionalStreamInfo, nullptr); -        CloseHandle(m_hDumpFile); +        CloseHandle(m_dumpFile);      } -    m_hReportFile = _tfopen(m_szLogFileName, _T("wb")); +    m_reportFile = _tfopen(m_logFileName, _T("wb")); -    if (m_hReportFile) +    if (m_reportFile)      {          GenerateExceptionReport(pExceptionInfo); -        fclose(m_hReportFile); -        m_hReportFile = nullptr; +        fclose(m_reportFile); +        m_reportFile = nullptr;      }      if (m_previousFilter) @@ -598,7 +597,6 @@ void WheatyExceptionReport::printTracesForAllThreads(bool bWriteVariables)    DWORD dwOwnerPID = GetCurrentProcessId();    DWORD dwCurrentTID = GetCurrentThreadId(); -  m_hProcess = GetCurrentProcess();    // Take a snapshot of all running threads    HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);    if (hThreadSnap == INVALID_HANDLE_VALUE) @@ -652,7 +650,7 @@ PEXCEPTION_POINTERS pExceptionInfo)          GetLocalTime(&systime);          // Start out with a banner -        Log(_T("Revision: %s\r\n"), GitRevision::GetFullVersion()); +        Log(_T("Revision: %" PRSTRc "\r\n"), GitRevision::GetFullVersion());          Log(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);          PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord; @@ -665,7 +663,7 @@ PEXCEPTION_POINTERS pExceptionInfo)          if (pExceptionRecord->ExceptionCode == EXCEPTION_ASSERTION_FAILURE && pExceptionRecord->NumberParameters >= 2)          {              pExceptionRecord->ExceptionAddress = reinterpret_cast<PVOID>(pExceptionRecord->ExceptionInformation[1]); -            Log(_T("Assertion message: %s\r\n"), pExceptionRecord->ExceptionInformation[0]); +            Log(_T("Assertion message: %" PRSTRc "\r\n"), pExceptionRecord->ExceptionInformation[0]);          }          // Now print information about where the fault occured @@ -739,7 +737,7 @@ PEXCEPTION_POINTERS pExceptionInfo)          SymSetOptions(SYMOPT_DEFERRED_LOADS);          // Initialize DbgHelp -        if (!SymInitialize(GetCurrentProcess(), nullptr, TRUE)) +        if (!SymInitialize(m_process, nullptr, TRUE))          {              Log(_T("\r\n"));              Log(_T("----\r\n")); @@ -817,7 +815,7 @@ PEXCEPTION_POINTERS pExceptionInfo)                      PSYMBOL_INFO sym = (PSYMBOL_INFO)&buf[0];                      sym->SizeOfStruct = sizeof(SYMBOL_INFO);                      sym->MaxNameLen = MAX_SYM_NAME; -                    if (SymGetTypeFromName(m_hProcess, (ULONG64)GetModuleHandle(nullptr), undName, sym)) +                    if (SymGetTypeFromName(m_process, (ULONG64)GetModuleHandle(nullptr), undName, sym))                      {                          sym->Address = pExceptionRecord->ExceptionInformation[1];                          sym->Flags = 0; @@ -844,7 +842,7 @@ PEXCEPTION_POINTERS pExceptionInfo)          WriteStackDetails(&trashableContext, true, nullptr);          printTracesForAllThreads(true); -        SymCleanup(GetCurrentProcess()); +        SymCleanup(m_process);          Log(_T("\r\n"));      } @@ -1013,7 +1011,7 @@ bool bWriteVariables, HANDLE pThreadHandle)      {          // Get the next stack frame          if (! StackWalk64(dwMachineType, -            m_hProcess, +            m_process,              pThreadHandle != nullptr ? pThreadHandle : GetCurrentThread(),              &sf,              pContext, @@ -1036,12 +1034,12 @@ bool bWriteVariables, HANDLE pThreadHandle)          // Get the name of the function for this stack frame entry          CSymbolInfoPackage sip;          if (SymFromAddr( -            m_hProcess,                                     // Process handle of the current process +            m_process,                                      // Process handle of the current process              sf.AddrPC.Offset,                               // Symbol address              &symDisplacement,                               // Address of the variable that will receive the displacement              &sip.si))                                       // Address of the SYMBOL_INFO structure (inside "sip" object)          { -            Log(_T("%hs+%I64X"), sip.si.Name, symDisplacement); +            Log(_T("%h" PRSTRc "+%I64X"), sip.si.Name, symDisplacement);          }          else                                                // No symbol found.  Print out the logical address instead. @@ -1062,10 +1060,10 @@ bool bWriteVariables, HANDLE pThreadHandle)          // Get the source line for this stack frame entry          IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };          DWORD dwLineDisplacement; -        if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset, +        if (SymGetLineFromAddr64(m_process, sf.AddrPC.Offset,              &dwLineDisplacement, &lineInfo))          { -            Log(_T("  %s line %u"), lineInfo.FileName, lineInfo.LineNumber); +            Log(_T("  %" PRSTRc " line %u"), lineInfo.FileName, lineInfo.LineNumber);          }          Log(_T("\r\n")); @@ -1076,13 +1074,14 @@ bool bWriteVariables, HANDLE pThreadHandle)              // Use SymSetContext to get just the locals/params for this frame              IMAGEHLP_STACK_FRAME imagehlpStackFrame;              imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset; -            SymSetContext(m_hProcess, &imagehlpStackFrame, nullptr); +            SymSetContext(m_process, &imagehlpStackFrame, nullptr);              // Enumerate the locals/parameters              EnumerateSymbolsCallbackContext ctx;              ctx.sf = &sf;              ctx.context = pContext; -            SymEnumSymbols(m_hProcess, 0, nullptr, EnumerateSymbolsCallback, &ctx); +            ctx.report = this; +            SymEnumSymbols(m_process, 0, nullptr, EnumerateSymbolsCallback, &ctx);              Log(_T("\r\n"));          } @@ -1100,15 +1099,16 @@ PSYMBOL_INFO  pSymInfo,  ULONG         /*SymbolSize*/,  PVOID         UserContext)  { +    EnumerateSymbolsCallbackContext* context = static_cast<EnumerateSymbolsCallbackContext*>(UserContext);      __try      { -        ClearSymbols(); -        FormatSymbolValue(pSymInfo, (EnumerateSymbolsCallbackContext*)UserContext); +        context->report->ClearSymbols(); +        context->report->FormatSymbolValue(pSymInfo, context);      }      __except (EXCEPTION_EXECUTE_HANDLER)      { -        Log(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name); +        context->report->Log(_T("punting on symbol %" PRSTRc ", partial output:\r\n"), pSymInfo->Name);      }      return TRUE; @@ -1121,7 +1121,7 @@ Optional<DWORD_PTR> WheatyExceptionReport::GetIntegerRegisterValue(PCONTEXT cont  #define REG_X(x) ((WORD)(((DWORD_PTR)(x)) & 0xffff))  #define REG_E(x) ((DWORD)(((DWORD_PTR)(x)) & 0xffffffff))  #define REG_R(x) ((DWORD64)(((DWORD_PTR)(x)) & 0xffffffffffffffff)) -#define CPU_REG(reg, field, part) case reg: return part(context->field); +#define CPU_REG(reg, field, part) case reg: return part(context->field)      switch (registerId)      {  #ifdef _M_IX86 @@ -1345,9 +1345,9 @@ EnumerateSymbolsCallbackContext* pCtx)      // Indicate if the variable is a local or parameter      if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER) -        symbolDetails.top().Prefix = "Parameter "; +        m_symbolDetails.top().Prefix = "Parameter ";      else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL) -        symbolDetails.top().Prefix = "Local "; +        m_symbolDetails.top().Prefix = "Local ";      // Determine if the variable is a user defined type (UDT).  IF so, bHandled      // will return true. @@ -1360,16 +1360,16 @@ EnumerateSymbolsCallbackContext* pCtx)          // variable.  Based on the size, we're assuming it's a char, WORD, or          // DWORD.          BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase); -        if (symbolDetails.top().Type.empty()) -            symbolDetails.top().Type = rgBaseType[basicType]; +        if (m_symbolDetails.top().Type.empty()) +            m_symbolDetails.top().Type = rgBaseType[basicType];          // Emit the variable name          if (pSym->Name[0] != '\0') -            symbolDetails.top().Name = pSym->Name; +            m_symbolDetails.top().Name = pSym->Name;          char buffer[50];          FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer)); -        symbolDetails.top().Value = buffer; +        m_symbolDetails.top().Value = buffer;      }      PopSymbolDetail(); @@ -1397,25 +1397,25 @@ bool logChildren)          PushSymbolDetail();      DWORD typeTag; -    if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag)) +    if (!SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))          return;      // Get the name of the symbol.  This will either be a Type name (if a UDT),      // or the structure member name.      WCHAR * pwszTypeName; -    if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME, +    if (SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_GET_SYMNAME,          &pwszTypeName))      {          // handle special cases          if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0)          {              LocalFree(pwszTypeName); -            symbolDetails.top().Type = "std::string"; +            m_symbolDetails.top().Type = "std::string";              char buffer[50];              FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer)); -            symbolDetails.top().Value = buffer; +            m_symbolDetails.top().Value = buffer;              if (Name != nullptr && Name[0] != '\0') -                symbolDetails.top().Name = Name; +                m_symbolDetails.top().Name = Name;              bHandled = true;              return;          } @@ -1425,16 +1425,16 @@ bool logChildren)          buffer[WER_SMALL_BUFFER_SIZE - 1] = '\0';          if (Name != nullptr && Name[0] != '\0')          { -            symbolDetails.top().Type = buffer; -            symbolDetails.top().Name = Name; +            m_symbolDetails.top().Type = buffer; +            m_symbolDetails.top().Name = Name;          }          else if (buffer[0] != '\0') -            symbolDetails.top().Name = buffer; +            m_symbolDetails.top().Name = buffer;          LocalFree(pwszTypeName);      }      else if (Name != nullptr && Name[0] != '\0') -        symbolDetails.top().Name = Name; +        m_symbolDetails.top().Name = Name;      if (!StoreSymbol(dwTypeIndex, offset))      { @@ -1448,30 +1448,30 @@ bool logChildren)      switch (typeTag)      {          case SymTagPointerType: -            if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) +            if (SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))              {                  if (Name != nullptr && Name[0] != '\0') -                    symbolDetails.top().Name = Name; +                    m_symbolDetails.top().Name = Name;                  BOOL isReference; -                SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference); +                SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);                  char addressStr[40];                  memset(addressStr, 0, sizeof(addressStr));                  if (isReference) -                    symbolDetails.top().Suffix += "&"; +                    m_symbolDetails.top().Suffix += "&";                  else -                    symbolDetails.top().Suffix += "*"; +                    m_symbolDetails.top().Suffix += "*";                  // Try to dereference the pointer in a try/except block since it might be invalid                  DWORD_PTR address = DereferenceUnsafePointer(offset);                  char buffer[WER_SMALL_BUFFER_SIZE];                  FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer)); -                symbolDetails.top().Value = buffer; +                m_symbolDetails.top().Value = buffer; -                if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL) +                if (m_symbolDetails.size() >= WER_MAX_NESTING_LEVEL)                      logChildren = false;                  // no need to log any children since the address is invalid anyway @@ -1483,59 +1483,59 @@ bool logChildren)                  if (!bHandled)                  {                      BasicType basicType = GetBasicType(dwTypeIndex, modBase); -                    if (symbolDetails.top().Type.empty()) -                        symbolDetails.top().Type = rgBaseType[basicType]; +                    if (m_symbolDetails.top().Type.empty()) +                        m_symbolDetails.top().Type = rgBaseType[basicType];                      if (address == 0) -                        symbolDetails.top().Value = "NULL"; +                        m_symbolDetails.top().Value = "NULL";                      else if (address == DWORD_PTR(-1)) -                        symbolDetails.top().Value = "<Unable to read memory>"; +                        m_symbolDetails.top().Value = "<Unable to read memory>";                      else                      {                          // Get the size of the child member                          ULONG64 length; -                        SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); +                        SymGetTypeInfo(m_process, modBase, innerTypeID, TI_GET_LENGTH, &length);                          char buffer2[50];                          FormatOutputValue(buffer2, basicType, length, (PVOID)address, sizeof(buffer2)); -                        symbolDetails.top().Value = buffer2; +                        m_symbolDetails.top().Value = buffer2;                      }                      bHandled = true;                      return;                  }                  else if (address == 0) -                    symbolDetails.top().Value = "NULL"; +                    m_symbolDetails.top().Value = "NULL";                  else if (address == DWORD_PTR(-1))                  { -                    symbolDetails.top().Value = "<Unable to read memory>"; +                    m_symbolDetails.top().Value = "<Unable to read memory>";                      bHandled = true;                      return;                  }              }              break;          case SymTagData: -            if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) +            if (SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))              {                  DWORD innerTypeTag; -                if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag)) +                if (!SymGetTypeInfo(m_process, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))                      break;                  switch (innerTypeTag)                  {                      case SymTagUDT: -                        if (symbolDetails.size() >= WER_MAX_NESTING_LEVEL) +                        if (m_symbolDetails.size() >= WER_MAX_NESTING_LEVEL)                              logChildren = false;                          DumpTypeIndex(modBase, innerTypeID, -                            offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); +                            offset, bHandled, m_symbolDetails.top().Name.c_str(), "", false, logChildren);                          break;                      case SymTagPointerType:                          if (Name != nullptr && Name[0] != '\0') -                            symbolDetails.top().Name = Name; +                            m_symbolDetails.top().Name = Name;                          DumpTypeIndex(modBase, innerTypeID, -                            offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); +                            offset, bHandled, m_symbolDetails.top().Name.c_str(), "", false, logChildren);                          break;                      case SymTagArrayType:                          DumpTypeIndex(modBase, innerTypeID, -                            offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren); +                            offset, bHandled, m_symbolDetails.top().Name.c_str(), "", false, logChildren);                          break;                      default:                          break; @@ -1543,35 +1543,35 @@ bool logChildren)              }              break;          case SymTagArrayType: -            if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID)) +            if (SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))              { -                symbolDetails.top().HasChildren = true; +                m_symbolDetails.top().HasChildren = true;                  BasicType basicType = btNoType;                  DumpTypeIndex(modBase, innerTypeID,                      offset, bHandled, Name, "", false, false);                  // Set Value back to an empty string since the Array object itself has no value, only its elements have -                std::string firstElementValue = symbolDetails.top().Value; -                symbolDetails.top().Value.clear(); +                std::string firstElementValue = m_symbolDetails.top().Value; +                m_symbolDetails.top().Value.clear();                  DWORD elementsCount; -                if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount)) -                    symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]"; +                if (SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount)) +                    m_symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]";                  else -                    symbolDetails.top().Suffix += "[<unknown count>]"; +                    m_symbolDetails.top().Suffix += "[<unknown count>]";                  if (!bHandled)                  {                      basicType = GetBasicType(dwTypeIndex, modBase); -                    if (symbolDetails.top().Type.empty()) -                        symbolDetails.top().Type = rgBaseType[basicType]; +                    if (m_symbolDetails.top().Type.empty()) +                        m_symbolDetails.top().Type = rgBaseType[basicType];                      bHandled = true;                  }                  // Get the size of the child member                  ULONG64 length; -                SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length); +                SymGetTypeInfo(m_process, modBase, innerTypeID, TI_GET_LENGTH, &length);                  char buffer[50];                  switch (basicType) @@ -1579,7 +1579,7 @@ bool logChildren)                      case btChar:                      case btStdString:                          FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer), elementsCount); -                        symbolDetails.top().Value = buffer; +                        m_symbolDetails.top().Value = buffer;                          break;                      default:                          for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++) @@ -1593,7 +1593,7 @@ bool logChildren)                                      FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer));                                      firstElementValue = buffer;                                  } -                                symbolDetails.top().Value = firstElementValue; +                                m_symbolDetails.top().Value = firstElementValue;                              }                              else                              { @@ -1601,13 +1601,13 @@ bool logChildren)                                  if (!elementHandled)                                  {                                      FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer)); -                                    symbolDetails.top().Value = buffer; +                                    m_symbolDetails.top().Value = buffer;                                  }                              } -                            symbolDetails.top().Prefix.clear(); -                            symbolDetails.top().Type.clear(); -                            symbolDetails.top().Suffix = "[" + std::to_string(index) + "]"; -                            symbolDetails.top().Name.clear(); +                            m_symbolDetails.top().Prefix.clear(); +                            m_symbolDetails.top().Type.clear(); +                            m_symbolDetails.top().Suffix = "[" + std::to_string(index) + "]"; +                            m_symbolDetails.top().Name.clear();                              PopSymbolDetail();                          }                          break; @@ -1626,7 +1626,7 @@ bool logChildren)      // Determine how many children this type has.      DWORD dwChildrenCount = 0; -    SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount); +    SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount);      if (!dwChildrenCount)                                 // If no children, we're done          return; @@ -1644,7 +1644,7 @@ bool logChildren)      children.Start= 0;      // Get the array of TypeIds, one for each child type -    if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN, +    if (!SymGetTypeInfo(m_process, modBase, dwTypeIndex, TI_FINDCHILDREN,          &children))      {          return; @@ -1654,7 +1654,7 @@ bool logChildren)      for (unsigned i = 0; i < dwChildrenCount; i++)      {          DWORD symTag; -        SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag); +        SymGetTypeInfo(m_process, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag);          if (symTag == SymTagFunction ||              symTag == SymTagEnum || @@ -1664,13 +1664,13 @@ bool logChildren)          // Ignore static fields          DWORD dataKind; -        SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind); +        SymGetTypeInfo(m_process, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind);          if (dataKind == DataIsStaticLocal ||              dataKind == DataIsGlobal ||              dataKind == DataIsStaticMember)              continue; -        symbolDetails.top().HasChildren = true; +        m_symbolDetails.top().HasChildren = true;          if (!logChildren)          {              bHandled = false; @@ -1683,7 +1683,7 @@ bool logChildren)          // Get the offset of the child member, relative to its parent          DWORD dwMemberOffset; -        SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], +        SymGetTypeInfo(m_process, modBase, children.ChildId[i],              TI_GET_OFFSET, &dwMemberOffset);          // Calculate the address of the member @@ -1696,22 +1696,22 @@ bool logChildren)          // If the child wasn't a UDT, format it appropriately          if (!bHandled2)          { -            if (symbolDetails.top().Type.empty()) -                symbolDetails.top().Type = rgBaseType[basicType]; +            if (m_symbolDetails.top().Type.empty()) +                m_symbolDetails.top().Type = rgBaseType[basicType];              // Get the real "TypeId" of the child.  We need this for the              // SymGetTypeInfo(TI_GET_TYPEID) call below.              DWORD typeId; -            SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], +            SymGetTypeInfo(m_process, modBase, children.ChildId[i],                  TI_GET_TYPEID, &typeId);              // Get the size of the child member              ULONG64 length; -            SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length); +            SymGetTypeInfo(m_process, modBase, typeId, TI_GET_LENGTH, &length);              char buffer[50];              FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer)); -            symbolDetails.top().Value = buffer; +            m_symbolDetails.top().Value = buffer;          }          PopSymbolDetail(); @@ -1799,10 +1799,10 @@ size_t countOverride)  }  BasicType -WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) +WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase) const  {      BasicType basicType; -    if (SymGetTypeInfo(m_hProcess, modBase, typeIndex, +    if (SymGetTypeInfo(m_process, modBase, typeIndex,          TI_GET_BASETYPE, &basicType))      {          return basicType; @@ -1811,9 +1811,9 @@ WheatyExceptionReport::GetBasicType(DWORD typeIndex, DWORD64 modBase)      // Get the real "TypeId" of the child.  We need this for the      // SymGetTypeInfo(TI_GET_TYPEID) call below.      DWORD typeId; -    if (SymGetTypeInfo(m_hProcess, modBase, typeIndex, TI_GET_TYPEID, &typeId)) +    if (SymGetTypeInfo(m_process, modBase, typeIndex, TI_GET_TYPEID, &typeId))      { -        if (SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_BASETYPE, +        if (SymGetTypeInfo(m_process, modBase, typeId, TI_GET_BASETYPE,              &basicType))          {              return basicType; @@ -1839,54 +1839,54 @@ DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer(DWORD_PTR address)  // Helper function that writes to the report file, and allows the user to use  // printf style formating  //============================================================================ -int __cdecl WheatyExceptionReport::Log(const TCHAR * format, ...) +int WheatyExceptionReport::Log(const TCHAR * format, ...)  {      va_list argptr;      va_start(argptr, format); -    int retValue = _vftprintf(m_hReportFile, format, argptr); +    int retValue = _vftprintf(m_reportFile, format, argptr);      va_end(argptr);      return retValue;  }  bool WheatyExceptionReport::StoreSymbol(DWORD type, DWORD_PTR offset)  { -    return symbols.insert(SymbolPair(type, offset)).second; +    return m_symbols.insert(SymbolPair(type, offset)).second;  }  void WheatyExceptionReport::ClearSymbols()  { -    symbols.clear(); -    while (!symbolDetails.empty()) -        symbolDetails.pop(); +    m_symbols.clear(); +    while (!m_symbolDetails.empty()) +        m_symbolDetails.pop();  }  void WheatyExceptionReport::PushSymbolDetail()  {      // Log current symbol and then add another to the stack to keep the hierarchy format      PrintSymbolDetail(); -    symbolDetails.emplace(); +    m_symbolDetails.emplace();  }  void WheatyExceptionReport::PopSymbolDetail()  {      PrintSymbolDetail(); -    symbolDetails.pop(); +    m_symbolDetails.pop();  }  void WheatyExceptionReport::PrintSymbolDetail()  { -    if (symbolDetails.empty()) +    if (m_symbolDetails.empty())          return;      // Don't log anything if has been logged already or if it's empty -    if (symbolDetails.top().Logged || symbolDetails.top().empty()) +    if (m_symbolDetails.top().Logged || m_symbolDetails.top().empty())          return;      // Add appropriate indentation level (since this routine is recursive) -    for (size_t i = 0; i < symbolDetails.size(); i++) +    for (size_t i = 0; i < m_symbolDetails.size(); i++)          Log(_T("\t")); -    Log(_T("%s\r\n"), symbolDetails.top().ToString().c_str()); +    Log(_T("%" PRSTRc "\r\n"), m_symbolDetails.top().ToString().c_str());  }  std::string SymbolDetail::ToString() diff --git a/src/common/Debugging/Windows/WheatyExceptionReport.h b/src/common/Debugging/Windows/WheatyExceptionReport.h index d154fce0d13..2ff30da91b9 100644 --- a/src/common/Debugging/Windows/WheatyExceptionReport.h +++ b/src/common/Debugging/Windows/WheatyExceptionReport.h @@ -328,20 +328,26 @@ class TC_COMMON_API WheatyExceptionReport      public:          WheatyExceptionReport(); +        WheatyExceptionReport(WheatyExceptionReport const&) = delete; +        WheatyExceptionReport(WheatyExceptionReport&&) = delete; +        WheatyExceptionReport& operator=(WheatyExceptionReport const&) = delete; +        WheatyExceptionReport& operator=(WheatyExceptionReport&&) = delete;          ~WheatyExceptionReport();          // entry point where control comes on an unhandled exception          static LONG WINAPI WheatyUnhandledExceptionFilter(              PEXCEPTION_POINTERS pExceptionInfo); +        LONG UnhandledExceptionFilterImpl(PEXCEPTION_POINTERS pExceptionInfo); +          static void __cdecl WheatyCrtHandler(wchar_t const* expression, wchar_t const* function, wchar_t const* file, unsigned int line, uintptr_t pReserved); -        static void printTracesForAllThreads(bool); +        void printTracesForAllThreads(bool bWriteVariables);      private:          // where report info is extracted and generated -        static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo); -        static void PrintSystemInfo(); -        static BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax); +        void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo); +        void PrintSystemInfo(); +        BOOL _GetWindowsVersion(TCHAR* szVersion, DWORD cntMax);          static BOOL _GetWindowsVersionFromWMI(TCHAR* szVersion, DWORD cntMax);          static BOOL _GetProcessorName(TCHAR* sProcessorName, DWORD maxcount); @@ -350,51 +356,51 @@ class TC_COMMON_API WheatyExceptionReport          static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len,              DWORD& section, DWORD_PTR& offset); -        static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle); +        void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle);          struct EnumerateSymbolsCallbackContext          {              LPSTACKFRAME64 sf;              PCONTEXT context; +            WheatyExceptionReport* report;          };          static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID); -        static bool FormatSymbolValue(PSYMBOL_INFO, EnumerateSymbolsCallbackContext*); +        bool FormatSymbolValue(PSYMBOL_INFO, EnumerateSymbolsCallbackContext*); -        static void DumpTypeIndex(DWORD64, DWORD, DWORD_PTR, bool &, char const*, char const*, bool, bool); +        void DumpTypeIndex(DWORD64, DWORD, DWORD_PTR, bool &, char const*, char const*, bool, bool);          static void FormatOutputValue(char * pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride = 0); -        static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase); +        BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase) const;          static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address); -        static int __cdecl Log(const TCHAR * format, ...); +        int Log(const TCHAR * format, ...); -        static bool StoreSymbol(DWORD type , DWORD_PTR offset); -        static void ClearSymbols(); +        bool StoreSymbol(DWORD type , DWORD_PTR offset); +        void ClearSymbols();          static Optional<DWORD_PTR> GetIntegerRegisterValue(PCONTEXT context, ULONG registerId);          // Variables used by the class -        static TCHAR m_szLogFileName[MAX_PATH]; -        static TCHAR m_szDumpFileName[MAX_PATH]; -        static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter; -        static _invalid_parameter_handler m_previousCrtHandler; -        static FILE* m_hReportFile; -        static HANDLE m_hDumpFile; -        static HANDLE m_hProcess; -        static SymbolPairs symbols; -        static std::stack<SymbolDetail> symbolDetails; -        static bool alreadyCrashed; -        static std::mutex alreadyCrashedLock; +        TCHAR m_logFileName[MAX_PATH]; +        TCHAR m_dumpFileName[MAX_PATH]; +        LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter; +        _invalid_parameter_handler m_previousCrtHandler; +        FILE* m_reportFile; +        HANDLE m_dumpFile; +        HANDLE m_process; +        SymbolPairs m_symbols; +        std::stack<SymbolDetail> m_symbolDetails; +        bool m_alreadyCrashed; +        std::mutex m_alreadyCrashedLock;          typedef NTSTATUS(NTAPI* pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation); -        static pRtlGetVersion RtlGetVersion; - -        static void PushSymbolDetail(); -        static void PopSymbolDetail(); -        static void PrintSymbolDetail(); +        pRtlGetVersion RtlGetVersion; +        void PushSymbolDetail(); +        void PopSymbolDetail(); +        void PrintSymbolDetail();  };  #define INIT_CRASH_HANDLER() \  | 
