TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
WheatyExceptionReport Class Reference

#include <WheatyExceptionReport.h>

Public Member Functions

 WheatyExceptionReport ()
 
 ~WheatyExceptionReport ()
 

Static Public Member Functions

static LONG WINAPI WheatyUnhandledExceptionFilter (PEXCEPTION_POINTERS pExceptionInfo)
 
static void printTracesForAllThreads (bool)
 

Private Types

typedef NTSTATUS(NTAPI * pRtlGetVersion )(PRTL_OSVERSIONINFOW lpVersionInformation)
 

Static Private Member Functions

static void GenerateExceptionReport (PEXCEPTION_POINTERS pExceptionInfo)
 
static void PrintSystemInfo ()
 
static BOOL _GetWindowsVersion (TCHAR *szVersion, DWORD cntMax)
 
static BOOL _GetProcessorName (TCHAR *sProcessorName, DWORD maxcount)
 
static LPTSTR GetExceptionString (DWORD dwCode)
 
static BOOL GetLogicalAddress (PVOID addr, PTSTR szModule, DWORD len, DWORD &section, DWORD_PTR &offset)
 
static void WriteStackDetails (PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle)
 
static BOOL CALLBACK EnumerateSymbolsCallback (PSYMBOL_INFO, ULONG, PVOID)
 
static bool FormatSymbolValue (PSYMBOL_INFO, STACKFRAME64 *, char *pszBuffer, unsigned cbBuffer)
 
static char * DumpTypeIndex (char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char *, char *, 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)
 
static DWORD_PTR DereferenceUnsafePointer (DWORD_PTR address)
 
static int __cdecl _tprintf (const TCHAR *format,...)
 
static int __cdecl stackprintf (const TCHAR *format, va_list argptr)
 
static int __cdecl heapprintf (const TCHAR *format, va_list argptr)
 
static bool StoreSymbol (DWORD type, DWORD_PTR offset)
 
static void ClearSymbols ()
 
static char * PushSymbolDetail (char *pszCurrBuffer)
 
static char * PopSymbolDetail (char *pszCurrBuffer)
 
static char * PrintSymbolDetail (char *pszCurrBuffer)
 

Static Private Attributes

static TCHAR m_szLogFileName [MAX_PATH]
 
static TCHAR m_szDumpFileName [MAX_PATH]
 
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter
 
static HANDLE m_hReportFile
 
static HANDLE m_hDumpFile
 
static HANDLE m_hProcess
 
static SymbolPairs symbols
 
static std::stack< SymbolDetailsymbolDetails
 
static bool stackOverflowException
 
static bool alreadyCrashed
 
static std::mutex alreadyCrashedLock
 
static pRtlGetVersion RtlGetVersion
 

Member Typedef Documentation

typedef NTSTATUS(NTAPI* WheatyExceptionReport::pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation)
private

Constructor & Destructor Documentation

WheatyExceptionReport::WheatyExceptionReport ( )
75 {
76  // Install the unhandled exception filter function
77  m_previousFilter = SetUnhandledExceptionFilter(WheatyUnhandledExceptionFilter);
78  m_hProcess = GetCurrentProcess();
79  stackOverflowException = false;
80  alreadyCrashed = false;
81  RtlGetVersion = (pRtlGetVersion)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "RtlGetVersion");
82  if (!IsDebuggerPresent())
83  {
84  _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
85  _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
86  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
87  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
88  }
89 }
static HANDLE m_hProcess
Definition: WheatyExceptionReport.h:196
static pRtlGetVersion RtlGetVersion
Definition: WheatyExceptionReport.h:203
static LONG WINAPI WheatyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
Definition: WheatyExceptionReport.cpp:104
static bool stackOverflowException
Definition: WheatyExceptionReport.h:199
#define _T(x)
Definition: CascPort.h:171
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter
Definition: WheatyExceptionReport.h:193
static bool alreadyCrashed
Definition: WheatyExceptionReport.h:200
NTSTATUS(NTAPI * pRtlGetVersion)(PRTL_OSVERSIONINFOW lpVersionInformation)
Definition: WheatyExceptionReport.h:202

+ Here is the call graph for this function:

WheatyExceptionReport::~WheatyExceptionReport ( )
95 {
96  if (m_previousFilter)
97  SetUnhandledExceptionFilter(m_previousFilter);
98  ClearSymbols();
99 }
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter
Definition: WheatyExceptionReport.h:193
static void ClearSymbols()
Definition: WheatyExceptionReport.cpp:1423

+ Here is the call graph for this function:

Member Function Documentation

BOOL WheatyExceptionReport::_GetProcessorName ( TCHAR sProcessorName,
DWORD  maxcount 
)
staticprivate
187 {
188  if (!sProcessorName)
189  return FALSE;
190 
191  HKEY hKey;
192  LONG lRet;
193  lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
194  0, KEY_QUERY_VALUE, &hKey);
195  if (lRet != ERROR_SUCCESS)
196  return FALSE;
197  TCHAR szTmp[2048];
198  DWORD cntBytes = sizeof(szTmp);
199  lRet = ::RegQueryValueEx(hKey, _T("ProcessorNameString"), NULL, NULL,
200  (LPBYTE)szTmp, &cntBytes);
201  if (lRet != ERROR_SUCCESS)
202  return FALSE;
203  ::RegCloseKey(hKey);
204  sProcessorName[0] = '\0';
205  // Skip spaces
206  TCHAR* psz = szTmp;
207  while (iswspace(*psz))
208  ++psz;
209  _tcsncpy(sProcessorName, psz, maxcount);
210  return TRUE;
211 }
arena_t NULL
Definition: jemalloc_internal.h:624
char TCHAR
Definition: CascPort.h:148
int LONG
Definition: CascPort.h:138
BYTE * LPBYTE
Definition: CascPort.h:152
static bool iswspace(int ch)
Definition: stringutils.cpp:34
#define _T(x)
Definition: CascPort.h:171
unsigned int DWORD
Definition: CascPort.h:139
#define ERROR_SUCCESS
Definition: CascPort.h:204

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

BOOL WheatyExceptionReport::_GetWindowsVersion ( TCHAR szVersion,
DWORD  cntMax 
)
staticprivate
226 {
227  // Try calling GetVersionEx using the OSVERSIONINFOEX structure.
228  // If that fails, try using the OSVERSIONINFO structure.
229  RTL_OSVERSIONINFOEXW osvi = { 0 };
230  osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
231  NTSTATUS bVersionEx = RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi);
232  if (bVersionEx < 0)
233  {
234  osvi.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOW);
235  if (!RtlGetVersion((PRTL_OSVERSIONINFOW)&osvi))
236  return FALSE;
237  }
238  *szVersion = _T('\0');
239 
240  TCHAR szCSDVersion[256];
241  ToTchar(osvi.szCSDVersion, szCSDVersion, std::is_same<TCHAR, char>::type());
242 
243  TCHAR wszTmp[128];
244  switch (osvi.dwPlatformId)
245  {
246  // Windows NT product family.
247  case VER_PLATFORM_WIN32_NT:
248  {
249  #if WINVER < 0x0500
250  BYTE suiteMask = osvi.wReserved[0];
251  BYTE productType = osvi.wReserved[1];
252  #else
253  WORD suiteMask = osvi.wSuiteMask;
254  BYTE productType = osvi.wProductType;
255  #endif // WINVER < 0x0500
256 
257  // Test for the specific product family.
258  if (osvi.dwMajorVersion == 10)
259  {
260  if (productType == VER_NT_WORKSTATION)
261  _tcsncat(szVersion, _T("Windows 10 "), cntMax);
262  else
263  _tcsncat(szVersion, _T("Windows Server 2016 "), cntMax);
264  }
265  else if (osvi.dwMajorVersion == 6)
266  {
267  if (productType == VER_NT_WORKSTATION)
268  {
269  if (osvi.dwMinorVersion == 3)
270  _tcsncat(szVersion, _T("Windows 8.1 "), cntMax);
271  else if (osvi.dwMinorVersion == 2)
272  _tcsncat(szVersion, _T("Windows 8 "), cntMax);
273  else if (osvi.dwMinorVersion == 1)
274  _tcsncat(szVersion, _T("Windows 7 "), cntMax);
275  else
276  _tcsncat(szVersion, _T("Windows Vista "), cntMax);
277  }
278  else if (osvi.dwMinorVersion == 3)
279  _tcsncat(szVersion, _T("Windows Server 2012 R2 "), cntMax);
280  else if (osvi.dwMinorVersion == 2)
281  _tcsncat(szVersion, _T("Windows Server 2012 "), cntMax);
282  else if (osvi.dwMinorVersion == 1)
283  _tcsncat(szVersion, _T("Windows Server 2008 R2 "), cntMax);
284  else
285  _tcsncat(szVersion, _T("Windows Server 2008 "), cntMax);
286  }
287  else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
288  _tcsncat(szVersion, _T("Microsoft Windows Server 2003 "), cntMax);
289  else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
290  _tcsncat(szVersion, _T("Microsoft Windows XP "), cntMax);
291  else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
292  _tcsncat(szVersion, _T("Microsoft Windows 2000 "), cntMax);
293  else if (osvi.dwMajorVersion <= 4)
294  _tcsncat(szVersion, _T("Microsoft Windows NT "), cntMax);
295 
296  // Test for specific product on Windows NT 4.0 SP6 and later.
297  if (bVersionEx >= 0)
298  {
299  // Test for the workstation type.
300  if (productType == VER_NT_WORKSTATION)
301  {
302  if (osvi.dwMajorVersion == 4)
303  _tcsncat(szVersion, _T("Workstation 4.0 "), cntMax);
304  else if (suiteMask & VER_SUITE_PERSONAL)
305  _tcsncat(szVersion, _T("Home Edition "), cntMax);
306  else if (suiteMask & VER_SUITE_EMBEDDEDNT)
307  _tcsncat(szVersion, _T("Embedded "), cntMax);
308  else
309  _tcsncat(szVersion, _T("Professional "), cntMax);
310  }
311  // Test for the server type.
312  else if (productType == VER_NT_SERVER)
313  {
314  if (osvi.dwMajorVersion == 6 || osvi.dwMajorVersion == 10)
315  {
316  if (suiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED)
317  _tcsncat(szVersion, _T("Essentials "), cntMax);
318  else if (suiteMask & VER_SUITE_DATACENTER)
319  _tcsncat(szVersion, _T("Datacenter "), cntMax);
320  else if (suiteMask & VER_SUITE_ENTERPRISE)
321  _tcsncat(szVersion, _T("Enterprise "), cntMax);
322  else
323  _tcsncat(szVersion, _T("Standard "), cntMax);
324  }
325  else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
326  {
327  if (suiteMask & VER_SUITE_DATACENTER)
328  _tcsncat(szVersion, _T("Datacenter Edition "), cntMax);
329  else if (suiteMask & VER_SUITE_ENTERPRISE)
330  _tcsncat(szVersion, _T("Enterprise Edition "), cntMax);
331  else if (suiteMask == VER_SUITE_BLADE)
332  _tcsncat(szVersion, _T("Web Edition "), cntMax);
333  else
334  _tcsncat(szVersion, _T("Standard Edition "), cntMax);
335  }
336  else if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
337  {
338  if (suiteMask & VER_SUITE_DATACENTER)
339  _tcsncat(szVersion, _T("Datacenter Server "), cntMax);
340  else if (suiteMask & VER_SUITE_ENTERPRISE)
341  _tcsncat(szVersion, _T("Advanced Server "), cntMax);
342  else
343  _tcsncat(szVersion, _T("Server "), cntMax);
344  }
345  else // Windows NT 4.0
346  {
347  if (suiteMask & VER_SUITE_ENTERPRISE)
348  _tcsncat(szVersion, _T("Server 4.0, Enterprise Edition "), cntMax);
349  else
350  _tcsncat(szVersion, _T("Server 4.0 "), cntMax);
351  }
352  }
353  }
354 
355  // Display service pack (if any) and build number.
356  if (osvi.dwMajorVersion == 4 && _tcsicmp(szCSDVersion, _T("Service Pack 6")) == 0)
357  {
358  HKEY hKey;
359  LONG lRet;
360 
361  // Test for SP6 versus SP6a.
362  lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix\\Q246009"), 0, KEY_QUERY_VALUE, &hKey);
363  if (lRet == ERROR_SUCCESS)
364  {
365  _stprintf(wszTmp, _T("Service Pack 6a (Version %d.%d, Build %d)"),
366  osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
367  _tcsncat(szVersion, wszTmp, cntMax);
368  }
369  else // Windows NT 4.0 prior to SP6a
370  {
371  _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
372  szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
373  _tcsncat(szVersion, wszTmp, cntMax);
374  }
375  ::RegCloseKey(hKey);
376  }
377  else // Windows NT 3.51 and earlier or Windows 2000 and later
378  {
379  if (!_tcslen(szCSDVersion))
380  _stprintf(wszTmp, _T("(Version %d.%d, Build %d)"),
381  osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
382  else
383  _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
384  szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
385  _tcsncat(szVersion, wszTmp, cntMax);
386  }
387  break;
388  }
389  default:
390  _stprintf(wszTmp, _T("%s (Version %d.%d, Build %d)"),
391  szCSDVersion, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber & 0xFFFF);
392  _tcsncat(szVersion, wszTmp, cntMax);
393  break;
394  }
395 
396  return TRUE;
397 }
static pRtlGetVersion RtlGetVersion
Definition: WheatyExceptionReport.h:203
char TCHAR
Definition: CascPort.h:148
int LONG
Definition: CascPort.h:138
#define _T(x)
Definition: CascPort.h:171
#define _tcslen
Definition: CascPort.h:172
void ToTchar(wchar_t const *src, TCHAR(&dst)[size], std::true_type)
Definition: WheatyExceptionReport.cpp:214
#define _tcsicmp
Definition: CascPort.h:187
unsigned char BYTE
Definition: CascPort.h:136
#define _stprintf
Definition: CascPort.h:181
#define ERROR_SUCCESS
Definition: CascPort.h:204

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int __cdecl WheatyExceptionReport::_tprintf ( const TCHAR format,
  ... 
)
staticprivate
1376 {
1377  int retValue;
1378  va_list argptr;
1379  va_start(argptr, format);
1381  {
1382  retValue = heapprintf(format, argptr);
1383  va_end(argptr);
1384  }
1385  else
1386  {
1387  retValue = stackprintf(format, argptr);
1388  va_end(argptr);
1389  }
1390 
1391  return retValue;
1392 }
void format(BasicFormatter< Char > &f, const Char *&format_str, const T &value)
Definition: format.h:2963
static bool stackOverflowException
Definition: WheatyExceptionReport.h:199
static int __cdecl heapprintf(const TCHAR *format, va_list argptr)
Definition: WheatyExceptionReport.cpp:1406
static int __cdecl stackprintf(const TCHAR *format, va_list argptr)
Definition: WheatyExceptionReport.cpp:1394

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WheatyExceptionReport::ClearSymbols ( )
staticprivate
1424 {
1425  symbols.clear();
1426  while (!symbolDetails.empty())
1427  symbolDetails.pop();
1428 }
static std::stack< SymbolDetail > symbolDetails
Definition: WheatyExceptionReport.h:198
static SymbolPairs symbols
Definition: WheatyExceptionReport.h:197

+ Here is the caller graph for this function:

DWORD_PTR WheatyExceptionReport::DereferenceUnsafePointer ( DWORD_PTR  address)
staticprivate
1360 {
1361  __try
1362  {
1363  return *(PDWORD_PTR)address;
1364  }
1365  __except (EXCEPTION_EXECUTE_HANDLER)
1366  {
1367  return DWORD_PTR(-1);
1368  }
1369 }
unsigned long DWORD_PTR
Definition: CascPort.h:140

+ Here is the caller graph for this function:

char * WheatyExceptionReport::DumpTypeIndex ( char *  pszCurrBuffer,
DWORD64  modBase,
DWORD  dwTypeIndex,
unsigned  nestingLevel,
DWORD_PTR  offset,
bool bHandled,
const char *  Name,
char *  ,
bool  newSymbol,
bool  logChildren 
)
staticprivate
944 {
945  bHandled = false;
946 
947  if (newSymbol)
948  pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
949 
950  DWORD typeTag;
951  if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMTAG, &typeTag))
952  return pszCurrBuffer;
953 
954  // Get the name of the symbol. This will either be a Type name (if a UDT),
955  // or the structure member name.
956  WCHAR * pwszTypeName;
957  if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_SYMNAME,
958  &pwszTypeName))
959  {
960  // handle special cases
961  if (wcscmp(pwszTypeName, L"std::basic_string<char,std::char_traits<char>,std::allocator<char> >") == 0)
962  {
963  LocalFree(pwszTypeName);
964  symbolDetails.top().Type = "std::string";
965  char buffer[50];
966  FormatOutputValue(buffer, btStdString, 0, (PVOID)offset, sizeof(buffer));
967  symbolDetails.top().Value = buffer;
968  if (Name != NULL && Name[0] != '\0')
969  symbolDetails.top().Name = Name;
970  bHandled = true;
971  return pszCurrBuffer;
972  }
973 
974  char buffer[200];
975  wcstombs(buffer, pwszTypeName, sizeof(buffer));
976  buffer[199] = '\0';
977  if (Name != NULL && Name[0] != '\0')
978  {
979  symbolDetails.top().Type = buffer;
980  symbolDetails.top().Name = Name;
981  }
982  else if (buffer[0] != '\0')
983  symbolDetails.top().Name = buffer;
984 
985  LocalFree(pwszTypeName);
986  }
987  else if (Name != NULL && Name[0] != '\0')
988  symbolDetails.top().Name = Name;
989 
990  if (!StoreSymbol(dwTypeIndex, offset))
991  {
992  // Skip printing address and base class if it has been printed already
993  if (typeTag == SymTagBaseClass)
994  bHandled = true;
995  return pszCurrBuffer;
996  }
997 
998  DWORD innerTypeID;
999  switch (typeTag)
1000  {
1001  case SymTagPointerType:
1002  if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1003  {
1004  if (Name != NULL && Name[0] != '\0')
1005  symbolDetails.top().Name = Name;
1006 
1007  BOOL isReference;
1008  SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_IS_REFERENCE, &isReference);
1009 
1010  char addressStr[40];
1011  memset(addressStr, 0, sizeof(addressStr));
1012 
1013  if (isReference)
1014  symbolDetails.top().Suffix += "&";
1015  else
1016  symbolDetails.top().Suffix += "*";
1017 
1018  // Try to dereference the pointer in a try/except block since it might be invalid
1019  DWORD_PTR address = DereferenceUnsafePointer(offset);
1020 
1021  char buffer[50];
1022  FormatOutputValue(buffer, btVoid, sizeof(PVOID), (PVOID)offset, sizeof(buffer));
1023  symbolDetails.top().Value = buffer;
1024 
1025  if (nestingLevel >= WER_MAX_NESTING_LEVEL)
1026  logChildren = false;
1027 
1028  // no need to log any children since the address is invalid anyway
1029  if (address == NULL || address == DWORD_PTR(-1))
1030  logChildren = false;
1031 
1032  pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
1033  address, bHandled, Name, addressStr, false, logChildren);
1034 
1035  if (!bHandled)
1036  {
1037  BasicType basicType = GetBasicType(dwTypeIndex, modBase);
1038  if (symbolDetails.top().Type.empty())
1039  symbolDetails.top().Type = rgBaseType[basicType];
1040 
1041  if (address == NULL)
1042  symbolDetails.top().Value = "NULL";
1043  else if (address == DWORD_PTR(-1))
1044  symbolDetails.top().Value = "<Unable to read memory>";
1045  else
1046  {
1047  // Get the size of the child member
1048  ULONG64 length;
1049  SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
1050  char buffer2[50];
1051  FormatOutputValue(buffer2, basicType, length, (PVOID)address, sizeof(buffer));
1052  symbolDetails.top().Value = buffer2;
1053  }
1054  bHandled = true;
1055  return pszCurrBuffer;
1056  }
1057  else if (address == NULL)
1058  symbolDetails.top().Value = "NULL";
1059  else if (address == DWORD_PTR(-1))
1060  {
1061  symbolDetails.top().Value = "<Unable to read memory>";
1062  bHandled = true;
1063  return pszCurrBuffer;
1064  }
1065  }
1066  break;
1067  case SymTagData:
1068  if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1069  {
1070  DWORD innerTypeTag;
1071  if (!SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_SYMTAG, &innerTypeTag))
1072  break;
1073 
1074  switch (innerTypeTag)
1075  {
1076  case SymTagUDT:
1077  if (nestingLevel >= WER_MAX_NESTING_LEVEL)
1078  logChildren = false;
1079  pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
1080  offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
1081  break;
1082  case SymTagPointerType:
1083  if (Name != NULL && Name[0] != '\0')
1084  symbolDetails.top().Name = Name;
1085  pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
1086  offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
1087  break;
1088  case SymTagArrayType:
1089  pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
1090  offset, bHandled, symbolDetails.top().Name.c_str(), "", false, logChildren);
1091  break;
1092  default:
1093  break;
1094  }
1095  }
1096  break;
1097  case SymTagArrayType:
1098  if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_TYPEID, &innerTypeID))
1099  {
1100  symbolDetails.top().HasChildren = true;
1101 
1102  BasicType basicType = btNoType;
1103  pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase, innerTypeID, nestingLevel + 1,
1104  offset, bHandled, Name, "", false, false);
1105 
1106  // Set Value back to an empty string since the Array object itself has no value, only its elements have
1107  symbolDetails.top().Value.clear();
1108 
1109  DWORD elementsCount;
1110  if (SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_COUNT, &elementsCount))
1111  symbolDetails.top().Suffix += "[" + std::to_string(elementsCount) + "]";
1112  else
1113  symbolDetails.top().Suffix += "[<unknown count>]";
1114 
1115  if (!bHandled)
1116  {
1117  basicType = GetBasicType(dwTypeIndex, modBase);
1118  if (symbolDetails.top().Type.empty())
1119  symbolDetails.top().Type = rgBaseType[basicType];
1120  bHandled = true;
1121  }
1122 
1123  // Get the size of the child member
1124  ULONG64 length;
1125  SymGetTypeInfo(m_hProcess, modBase, innerTypeID, TI_GET_LENGTH, &length);
1126 
1127  char buffer[50];
1128  switch (basicType)
1129  {
1130  case btChar:
1131  case btStdString:
1132  FormatOutputValue(buffer, basicType, length, (PVOID)offset, sizeof(buffer), elementsCount);
1133  symbolDetails.top().Value = buffer;
1134  break;
1135  default:
1136  for (DWORD index = 0; index < elementsCount && index < WER_MAX_ARRAY_ELEMENTS_COUNT; index++)
1137  {
1138  pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
1139  symbolDetails.top().Suffix += "[" + std::to_string(index) + "]";
1140  FormatOutputValue(buffer, basicType, length, (PVOID)(offset + length * index), sizeof(buffer));
1141  symbolDetails.top().Value = buffer;
1142  pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
1143  }
1144  break;
1145  }
1146 
1147  return pszCurrBuffer;
1148  }
1149  break;
1150  case SymTagBaseType:
1151  break;
1152  case SymTagEnum:
1153  return pszCurrBuffer;
1154  default:
1155  break;
1156  }
1157 
1158  // Determine how many children this type has.
1159  DWORD dwChildrenCount = 0;
1160  SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
1161 
1162  if (!dwChildrenCount) // If no children, we're done
1163  return pszCurrBuffer;
1164 
1165  // Prepare to get an array of "TypeIds", representing each of the children.
1166  // SymGetTypeInfo(TI_FINDCHILDREN) expects more memory than just a
1167  // TI_FINDCHILDREN_PARAMS struct has. Use derivation to accomplish this.
1168  struct FINDCHILDREN : TI_FINDCHILDREN_PARAMS
1169  {
1170  ULONG MoreChildIds[1024*2];
1171  FINDCHILDREN(){Count = sizeof(MoreChildIds) / sizeof(MoreChildIds[0]);}
1172  } children;
1173 
1174  children.Count = dwChildrenCount;
1175  children.Start= 0;
1176 
1177  // Get the array of TypeIds, one for each child type
1178  if (!SymGetTypeInfo(m_hProcess, modBase, dwTypeIndex, TI_FINDCHILDREN,
1179  &children))
1180  {
1181  return pszCurrBuffer;
1182  }
1183 
1184  // Iterate through each of the children
1185  for (unsigned i = 0; i < dwChildrenCount; i++)
1186  {
1187  DWORD symTag;
1188  SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_SYMTAG, &symTag);
1189 
1190  if (symTag == SymTagFunction ||
1191  symTag == SymTagEnum ||
1192  symTag == SymTagTypedef ||
1193  symTag == SymTagVTable)
1194  continue;
1195 
1196  // Ignore static fields
1197  DWORD dataKind;
1198  SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i], TI_GET_DATAKIND, &dataKind);
1199  if (dataKind == DataIsStaticLocal ||
1200  dataKind == DataIsGlobal ||
1201  dataKind == DataIsStaticMember)
1202  continue;
1203 
1204 
1205  symbolDetails.top().HasChildren = true;
1206  if (!logChildren)
1207  {
1208  bHandled = false;
1209  return pszCurrBuffer;
1210  }
1211 
1212  // Recurse for each of the child types
1213  bool bHandled2;
1214  BasicType basicType = GetBasicType(children.ChildId[i], modBase);
1215 
1216  // Get the offset of the child member, relative to its parent
1217  DWORD dwMemberOffset;
1218  SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i],
1219  TI_GET_OFFSET, &dwMemberOffset);
1220 
1221  // Calculate the address of the member
1222  DWORD_PTR dwFinalOffset = offset + dwMemberOffset;
1223 
1224  pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, modBase,
1225  children.ChildId[i], nestingLevel+1,
1226  dwFinalOffset, bHandled2, ""/*Name */, "", true, true);
1227 
1228  // If the child wasn't a UDT, format it appropriately
1229  if (!bHandled2)
1230  {
1231  if (symbolDetails.top().Type.empty())
1232  symbolDetails.top().Type = rgBaseType[basicType];
1233 
1234  // Get the real "TypeId" of the child. We need this for the
1235  // SymGetTypeInfo(TI_GET_TYPEID) call below.
1236  DWORD typeId;
1237  SymGetTypeInfo(m_hProcess, modBase, children.ChildId[i],
1238  TI_GET_TYPEID, &typeId);
1239 
1240  // Get the size of the child member
1241  ULONG64 length;
1242  SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_LENGTH, &length);
1243 
1244  char buffer[50];
1245  FormatOutputValue(buffer, basicType, length, (PVOID)dwFinalOffset, sizeof(buffer));
1246  symbolDetails.top().Value = buffer;
1247  }
1248 
1249  pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
1250  }
1251 
1252  bHandled = true;
1253  return pszCurrBuffer;
1254 }
static HANDLE m_hProcess
Definition: WheatyExceptionReport.h:196
const char *const rgBaseType[]
Definition: WheatyExceptionReport.h:58
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase)
Definition: WheatyExceptionReport.cpp:1335
static std::stack< SymbolDetail > symbolDetails
Definition: WheatyExceptionReport.h:198
#define WER_MAX_ARRAY_ELEMENTS_COUNT
Definition: WheatyExceptionReport.h:15
arena_t NULL
Definition: jemalloc_internal.h:624
Definition: WheatyExceptionReport.h:52
static void FormatOutputValue(char *pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride=0)
Definition: WheatyExceptionReport.cpp:1256
Definition: WheatyExceptionReport.h:48
BasicType
Definition: WheatyExceptionReport.h:19
Definition: WheatyExceptionReport.h:54
static char * PopSymbolDetail(char *pszCurrBuffer)
Definition: WheatyExceptionReport.cpp:1438
unsigned long DWORD_PTR
Definition: CascPort.h:140
Definition: WheatyExceptionReport.h:41
Definition: WheatyExceptionReport.h:23
unsigned int DWORD
Definition: CascPort.h:139
#define ULONG64
Definition: stdsoap2.h:921
float length(float v)
Definition: vectorMath.h:208
Definition: WheatyExceptionReport.h:22
static bool StoreSymbol(DWORD type, DWORD_PTR offset)
Definition: WheatyExceptionReport.cpp:1418
#define WER_MAX_NESTING_LEVEL
Definition: WheatyExceptionReport.h:16
Definition: WheatyExceptionReport.h:21
static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char *, char *, bool, bool)
Definition: WheatyExceptionReport.cpp:933
static DWORD_PTR DereferenceUnsafePointer(DWORD_PTR address)
Definition: WheatyExceptionReport.cpp:1359
static char * PushSymbolDetail(char *pszCurrBuffer)
Definition: WheatyExceptionReport.cpp:1430

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

BOOL CALLBACK WheatyExceptionReport::EnumerateSymbolsCallback ( PSYMBOL_INFO  pSymInfo,
ULONG  ,
PVOID  UserContext 
)
staticprivate
830 {
831 
832  char szBuffer[WER_LARGE_BUFFER_SIZE];
833  memset(szBuffer, 0, sizeof(szBuffer));
834 
835  __try
836  {
837  ClearSymbols();
838  if (FormatSymbolValue(pSymInfo, (STACKFRAME64*)UserContext,
839  szBuffer, sizeof(szBuffer)))
840  _tprintf(_T("%s"), szBuffer);
841  }
842  __except (EXCEPTION_EXECUTE_HANDLER)
843  {
844  _tprintf(_T("punting on symbol %s, partial output:\r\n"), pSymInfo->Name);
845  if (szBuffer[0] != '\0')
846  _tprintf(_T("%s"), szBuffer);
847  }
848 
849  return TRUE;
850 }
#define _T(x)
Definition: CascPort.h:171
static void ClearSymbols()
Definition: WheatyExceptionReport.cpp:1423
static bool FormatSymbolValue(PSYMBOL_INFO, STACKFRAME64 *, char *pszBuffer, unsigned cbBuffer)
Definition: WheatyExceptionReport.cpp:857
static int __cdecl _tprintf(const TCHAR *format,...)
Definition: WheatyExceptionReport.cpp:1375
#define WER_LARGE_BUFFER_SIZE
Definition: WheatyExceptionReport.h:17

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WheatyExceptionReport::FormatOutputValue ( char *  pszCurrBuffer,
BasicType  basicType,
DWORD64  length,
PVOID  pAddress,
size_t  bufferSize,
size_t  countOverride = 0 
)
staticprivate
1262 {
1263  __try
1264  {
1265  switch (basicType)
1266  {
1267  case btChar:
1268  {
1269  // Special case handling for char[] type
1270  if (countOverride != 0)
1271  length = countOverride;
1272  else
1273  length = strlen((char*)pAddress);
1274  if (length > bufferSize - 6)
1275  pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), (char*)pAddress);
1276  else
1277  pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s\"", (DWORD)length, (char*)pAddress);
1278  break;
1279  }
1280  case btStdString:
1281  {
1282  std::string* value = static_cast<std::string*>(pAddress);
1283  if (value->length() > bufferSize - 6)
1284  pszCurrBuffer += sprintf(pszCurrBuffer, "\"%.*s...\"", (DWORD)(bufferSize - 6), value->c_str());
1285  else
1286  pszCurrBuffer += sprintf(pszCurrBuffer, "\"%s\"", value->c_str());
1287  break;
1288  }
1289  default:
1290  // Format appropriately (assuming it's a 1, 2, or 4 bytes (!!!)
1291  if (length == 1)
1292  pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PBYTE)pAddress);
1293  else if (length == 2)
1294  pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PWORD)pAddress);
1295  else if (length == 4)
1296  {
1297  if (basicType == btFloat)
1298  pszCurrBuffer += sprintf(pszCurrBuffer, "%f", *(PFLOAT)pAddress);
1299  else
1300  pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", *(PDWORD)pAddress);
1301  }
1302  else if (length == 8)
1303  {
1304  if (basicType == btFloat)
1305  {
1306  pszCurrBuffer += sprintf(pszCurrBuffer, "%f",
1307  *(double *)pAddress);
1308  }
1309  else
1310  pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X",
1311  *(DWORD64*)pAddress);
1312  }
1313  else
1314  {
1315  #if _WIN64
1316  pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X", (DWORD64)pAddress);
1317  #else
1318  pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X", (DWORD)pAddress);
1319  #endif
1320  }
1321  break;
1322  }
1323  }
1324  __except (EXCEPTION_EXECUTE_HANDLER)
1325  {
1326 #if _WIN64
1327  pszCurrBuffer += sprintf(pszCurrBuffer, "0x%I64X <Unable to read memory>", (DWORD64)pAddress);
1328 #else
1329  pszCurrBuffer += sprintf(pszCurrBuffer, "0x%X <Unable to read memory>", (DWORD)pAddress);
1330 #endif
1331  }
1332 }
DWORD * PDWORD
Definition: CascPort.h:151
const size_t bufferSize
Definition: RASession.h:31
Definition: WheatyExceptionReport.h:27
std::string sprintf(CStringRef format, ArgList args)
Definition: format.h:3096
Definition: WheatyExceptionReport.h:41
Definition: WheatyExceptionReport.h:23
unsigned int DWORD
Definition: CascPort.h:139
float length(float v)
Definition: vectorMath.h:208
const FieldDescriptor value
Definition: descriptor.h:1522

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool WheatyExceptionReport::FormatSymbolValue ( PSYMBOL_INFO  pSym,
STACKFRAME64 *  sf,
char *  pszBuffer,
unsigned  cbBuffer 
)
staticprivate
862 {
863  char * pszCurrBuffer = pszBuffer;
864 
865  // If it's a function, don't do anything.
866  if (pSym->Tag == SymTagFunction) // SymTagFunction from CVCONST.H from the DIA SDK
867  return false;
868 
869  DWORD_PTR pVariable = 0; // Will point to the variable's data in memory
870 
871  if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGRELATIVE)
872  {
873  // if (pSym->Register == 8) // EBP is the value 8 (in DBGHELP 5.1)
874  { // This may change!!!
875 #ifdef _M_IX86
876  pVariable = sf->AddrFrame.Offset;
877 #elif _M_X64
878  pVariable = sf->AddrStack.Offset;
879 #endif
880  pVariable += (DWORD_PTR)pSym->Address;
881  }
882  // else
883  // return false;
884  }
885  else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_REGISTER)
886  return false; // Don't try to report register variable
887  else
888  {
889  pVariable = (DWORD_PTR)pSym->Address; // It must be a global variable
890  }
891 
892  pszCurrBuffer = PushSymbolDetail(pszCurrBuffer);
893 
894  // Indicate if the variable is a local or parameter
895  if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_PARAMETER)
896  symbolDetails.top().Prefix = "Parameter ";
897  else if (pSym->Flags & IMAGEHLP_SYMBOL_INFO_LOCAL)
898  symbolDetails.top().Prefix = "Local ";
899 
900  // Determine if the variable is a user defined type (UDT). IF so, bHandled
901  // will return true.
902  bool bHandled;
903  pszCurrBuffer = DumpTypeIndex(pszCurrBuffer, pSym->ModBase, pSym->TypeIndex,
904  0, pVariable, bHandled, pSym->Name, "", false, true);
905 
906  if (!bHandled)
907  {
908  // The symbol wasn't a UDT, so do basic, stupid formatting of the
909  // variable. Based on the size, we're assuming it's a char, WORD, or
910  // DWORD.
911  BasicType basicType = GetBasicType(pSym->TypeIndex, pSym->ModBase);
912  if (symbolDetails.top().Type.empty())
913  symbolDetails.top().Type = rgBaseType[basicType];
914 
915  // Emit the variable name
916  if (pSym->Name[0] != '\0')
917  symbolDetails.top().Name = pSym->Name;
918 
919  char buffer[50];
920  FormatOutputValue(buffer, basicType, pSym->Size, (PVOID)pVariable, sizeof(buffer));
921  symbolDetails.top().Value = buffer;
922  }
923 
924  pszCurrBuffer = PopSymbolDetail(pszCurrBuffer);
925  return true;
926 }
const char *const rgBaseType[]
Definition: WheatyExceptionReport.h:58
static BasicType GetBasicType(DWORD typeIndex, DWORD64 modBase)
Definition: WheatyExceptionReport.cpp:1335
static std::stack< SymbolDetail > symbolDetails
Definition: WheatyExceptionReport.h:198
static void FormatOutputValue(char *pszCurrBuffer, BasicType basicType, DWORD64 length, PVOID pAddress, size_t bufferSize, size_t countOverride=0)
Definition: WheatyExceptionReport.cpp:1256
BasicType
Definition: WheatyExceptionReport.h:19
static char * PopSymbolDetail(char *pszCurrBuffer)
Definition: WheatyExceptionReport.cpp:1438
unsigned long DWORD_PTR
Definition: CascPort.h:140
static char * DumpTypeIndex(char *, DWORD64, DWORD, unsigned, DWORD_PTR, bool &, const char *, char *, bool, bool)
Definition: WheatyExceptionReport.cpp:933
static char * PushSymbolDetail(char *pszCurrBuffer)
Definition: WheatyExceptionReport.cpp:1430

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WheatyExceptionReport::GenerateExceptionReport ( PEXCEPTION_POINTERS  pExceptionInfo)
staticprivate
475 {
476  __try
477  {
478  SYSTEMTIME systime;
479  GetLocalTime(&systime);
480 
481  // Start out with a banner
482  _tprintf(_T("Revision: %s\r\n"), GitRevision::GetFullVersion());
483  _tprintf(_T("Date %u:%u:%u. Time %u:%u \r\n"), systime.wDay, systime.wMonth, systime.wYear, systime.wHour, systime.wMinute);
484  PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
485 
486  PrintSystemInfo();
487  // First print information about the type of fault
488  _tprintf(_T("\r\n//=====================================================\r\n"));
489  _tprintf(_T("Exception code: %08X %s\r\n"),
490  pExceptionRecord->ExceptionCode,
491  GetExceptionString(pExceptionRecord->ExceptionCode));
492 
493  // Now print information about where the fault occured
494  TCHAR szFaultingModule[MAX_PATH];
495  DWORD section;
496  DWORD_PTR offset;
497  GetLogicalAddress(pExceptionRecord->ExceptionAddress,
498  szFaultingModule,
499  sizeof(szFaultingModule),
500  section, offset);
501 
502 #ifdef _M_IX86
503  _tprintf(_T("Fault address: %08X %02X:%08X %s\r\n"),
504  pExceptionRecord->ExceptionAddress,
505  section, offset, szFaultingModule);
506 #endif
507 #ifdef _M_X64
508  _tprintf(_T("Fault address: %016I64X %02X:%016I64X %s\r\n"),
509  pExceptionRecord->ExceptionAddress,
510  section, offset, szFaultingModule);
511 #endif
512 
513  PCONTEXT pCtx = pExceptionInfo->ContextRecord;
514 
515  // Show the registers
516 #ifdef _M_IX86 // X86 Only!
517  _tprintf(_T("\r\nRegisters:\r\n"));
518 
519  _tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
520  , pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
521  pCtx->Esi, pCtx->Edi);
522 
523  _tprintf(_T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip);
524  _tprintf(_T("SS:ESP:%04X:%08X EBP:%08X\r\n"),
525  pCtx->SegSs, pCtx->Esp, pCtx->Ebp);
526  _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
527  pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
528  _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
529 #endif
530 
531 #ifdef _M_X64
532  _tprintf(_T("\r\nRegisters:\r\n"));
533  _tprintf(_T("RAX:%016I64X\r\nRBX:%016I64X\r\nRCX:%016I64X\r\nRDX:%016I64X\r\nRSI:%016I64X\r\nRDI:%016I64X\r\n")
534  _T("R8: %016I64X\r\nR9: %016I64X\r\nR10:%016I64X\r\nR11:%016I64X\r\nR12:%016I64X\r\nR13:%016I64X\r\nR14:%016I64X\r\nR15:%016I64X\r\n")
535  , pCtx->Rax, pCtx->Rbx, pCtx->Rcx, pCtx->Rdx,
536  pCtx->Rsi, pCtx->Rdi, pCtx->R9, pCtx->R10, pCtx->R11, pCtx->R12, pCtx->R13, pCtx->R14, pCtx->R15);
537  _tprintf(_T("CS:RIP:%04X:%016I64X\r\n"), pCtx->SegCs, pCtx->Rip);
538  _tprintf(_T("SS:RSP:%04X:%016X RBP:%08X\r\n"),
539  pCtx->SegSs, pCtx->Rsp, pCtx->Rbp);
540  _tprintf(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
541  pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
542  _tprintf(_T("Flags:%08X\r\n"), pCtx->EFlags);
543 #endif
544 
545  SymSetOptions(SYMOPT_DEFERRED_LOADS);
546 
547  // Initialize DbgHelp
548  if (!SymInitialize(GetCurrentProcess(), 0, TRUE))
549  {
550  _tprintf(_T("\n\rCRITICAL ERROR.\n\r Couldn't initialize the symbol handler for process.\n\rError [%s].\n\r\n\r"),
552  }
553 
554  CONTEXT trashableContext = *pCtx;
555 
556  WriteStackDetails(&trashableContext, false, NULL);
558 
559  // #ifdef _M_IX86 // X86 Only!
560 
561  _tprintf(_T("========================\r\n"));
562  _tprintf(_T("Local Variables And Parameters\r\n"));
563 
564  trashableContext = *pCtx;
565  WriteStackDetails(&trashableContext, true, NULL);
567 
568  /*_tprintf(_T("========================\r\n"));
569  _tprintf(_T("Global Variables\r\n"));
570 
571  SymEnumSymbols(GetCurrentProcess(),
572  (UINT_PTR)GetModuleHandle(szFaultingModule),
573  0, EnumerateSymbolsCallback, 0);*/
574  // #endif // X86 Only!
575 
576  SymCleanup(GetCurrentProcess());
577 
578  _tprintf(_T("\r\n"));
579  }
580  __except (EXCEPTION_EXECUTE_HANDLER)
581  {
582  _tprintf(_T("Error writing the crash log\r\n"));
583  }
584 }
static LPTSTR GetExceptionString(DWORD dwCode)
Definition: WheatyExceptionReport.cpp:590
static void PrintSystemInfo()
Definition: WheatyExceptionReport.cpp:399
static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, DWORD &section, DWORD_PTR &offset)
Definition: WheatyExceptionReport.cpp:639
#define MAX_PATH
Definition: CascPort.h:160
arena_t NULL
Definition: jemalloc_internal.h:624
TC_COMMON_API char const * GetFullVersion()
Definition: GitRevision.cpp:51
char TCHAR
Definition: CascPort.h:148
#define _T(x)
Definition: CascPort.h:171
unsigned long DWORD_PTR
Definition: CascPort.h:140
static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle)
Definition: WheatyExceptionReport.cpp:704
unsigned int DWORD
Definition: CascPort.h:139
static void printTracesForAllThreads(bool)
Definition: WheatyExceptionReport.cpp:423
int GetLastError()
Definition: Common.cpp:70
static int __cdecl _tprintf(const TCHAR *format,...)
Definition: WheatyExceptionReport.cpp:1375
LPTSTR ErrorMessage(DWORD dw)
Definition: WheatyExceptionReport.cpp:28

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

BasicType WheatyExceptionReport::GetBasicType ( DWORD  typeIndex,
DWORD64  modBase 
)
staticprivate
1336 {
1337  BasicType basicType;
1338  if (SymGetTypeInfo(m_hProcess, modBase, typeIndex,
1339  TI_GET_BASETYPE, &basicType))
1340  {
1341  return basicType;
1342  }
1343 
1344  // Get the real "TypeId" of the child. We need this for the
1345  // SymGetTypeInfo(TI_GET_TYPEID) call below.
1346  DWORD typeId;
1347  if (SymGetTypeInfo(m_hProcess, modBase, typeIndex, TI_GET_TYPEID, &typeId))
1348  {
1349  if (SymGetTypeInfo(m_hProcess, modBase, typeId, TI_GET_BASETYPE,
1350  &basicType))
1351  {
1352  return basicType;
1353  }
1354  }
1355 
1356  return btNoType;
1357 }
static HANDLE m_hProcess
Definition: WheatyExceptionReport.h:196
BasicType
Definition: WheatyExceptionReport.h:19
unsigned int DWORD
Definition: CascPort.h:139
Definition: WheatyExceptionReport.h:21

+ Here is the caller graph for this function:

LPTSTR WheatyExceptionReport::GetExceptionString ( DWORD  dwCode)
staticprivate
591 {
592  #define EXCEPTION(x) case EXCEPTION_##x: return _T(#x);
593 
594  switch (dwCode)
595  {
596  EXCEPTION(ACCESS_VIOLATION)
597  EXCEPTION(DATATYPE_MISALIGNMENT)
598  EXCEPTION(BREAKPOINT)
599  EXCEPTION(SINGLE_STEP)
600  EXCEPTION(ARRAY_BOUNDS_EXCEEDED)
601  EXCEPTION(FLT_DENORMAL_OPERAND)
602  EXCEPTION(FLT_DIVIDE_BY_ZERO)
603  EXCEPTION(FLT_INEXACT_RESULT)
604  EXCEPTION(FLT_INVALID_OPERATION)
605  EXCEPTION(FLT_OVERFLOW)
606  EXCEPTION(FLT_STACK_CHECK)
607  EXCEPTION(FLT_UNDERFLOW)
608  EXCEPTION(INT_DIVIDE_BY_ZERO)
609  EXCEPTION(INT_OVERFLOW)
610  EXCEPTION(PRIV_INSTRUCTION)
611  EXCEPTION(IN_PAGE_ERROR)
612  EXCEPTION(ILLEGAL_INSTRUCTION)
613  EXCEPTION(NONCONTINUABLE_EXCEPTION)
614  EXCEPTION(STACK_OVERFLOW)
615  EXCEPTION(INVALID_DISPOSITION)
616  EXCEPTION(GUARD_PAGE)
617  EXCEPTION(INVALID_HANDLE)
618  }
619 
620  // If not one of the "known" exceptions, try to get the string
621  // from NTDLL.DLL's message table.
622 
623  static TCHAR szBuffer[512] = { 0 };
624 
625  FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
626  GetModuleHandle(_T("NTDLL.DLL")),
627  dwCode, 0, szBuffer, sizeof(szBuffer), 0);
628 
629  return szBuffer;
630 }
char TCHAR
Definition: CascPort.h:148
#define _T(x)
Definition: CascPort.h:171
#define EXCEPTION(x)

+ Here is the caller graph for this function:

BOOL WheatyExceptionReport::GetLogicalAddress ( PVOID  addr,
PTSTR  szModule,
DWORD  len,
DWORD section,
DWORD_PTR offset 
)
staticprivate
641 {
642  MEMORY_BASIC_INFORMATION mbi;
643 
644  if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
645  return FALSE;
646 
647  DWORD_PTR hMod = (DWORD_PTR)mbi.AllocationBase;
648 
649  if (!hMod)
650  return FALSE;
651 
652  if (!GetModuleFileName((HMODULE)hMod, szModule, len))
653  return FALSE;
654 
655  // Point to the DOS header in memory
656  PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
657 
658  // From the DOS header, find the NT (PE) header
659  PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + DWORD_PTR(pDosHdr->e_lfanew));
660 
661  PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHdr);
662 
663  DWORD_PTR rva = (DWORD_PTR)addr - hMod; // RVA is offset from module load address
664 
665  // Iterate through the section table, looking for the one that encompasses
666  // the linear address.
667  for (unsigned i = 0;
668  i < pNtHdr->FileHeader.NumberOfSections;
669  i++, pSection++)
670  {
671  DWORD_PTR sectionStart = pSection->VirtualAddress;
672  DWORD_PTR sectionEnd = sectionStart
673  + DWORD_PTR(std::max(pSection->SizeOfRawData, pSection->Misc.VirtualSize));
674 
675  // Is the address in this section???
676  if ((rva >= sectionStart) && (rva <= sectionEnd))
677  {
678  // Yes, address is in the section. Calculate section and offset,
679  // and store in the "section" & "offset" params, which were
680  // passed by reference.
681  section = i+1;
682  offset = rva - sectionStart;
683  return TRUE;
684  }
685  }
686 
687  return FALSE; // Should never get here!
688 }
T max(const T &x, const T &y)
Definition: g3dmath.h:320
unsigned long DWORD_PTR
Definition: CascPort.h:140

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int __cdecl WheatyExceptionReport::heapprintf ( const TCHAR format,
va_list  argptr 
)
staticprivate
1407 {
1408  int retValue;
1409  DWORD cbWritten;
1410  TCHAR* szBuff = (TCHAR*)malloc(sizeof(TCHAR) * WER_LARGE_BUFFER_SIZE);
1411  retValue = vsprintf(szBuff, format, argptr);
1412  WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0);
1413  free(szBuff);
1414 
1415  return retValue;
1416 }
void format(BasicFormatter< Char > &f, const Char *&format_str, const T &value)
Definition: format.h:2963
char TCHAR
Definition: CascPort.h:148
static HANDLE m_hReportFile
Definition: WheatyExceptionReport.h:194
unsigned int DWORD
Definition: CascPort.h:139
#define WER_LARGE_BUFFER_SIZE
Definition: WheatyExceptionReport.h:17

+ Here is the caller graph for this function:

char * WheatyExceptionReport::PopSymbolDetail ( char *  pszCurrBuffer)
staticprivate
1439 {
1440  pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer);
1441  symbolDetails.pop();
1442  return pszCurrBuffer;
1443 }
static char * PrintSymbolDetail(char *pszCurrBuffer)
Definition: WheatyExceptionReport.cpp:1445
static std::stack< SymbolDetail > symbolDetails
Definition: WheatyExceptionReport.h:198

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

char * WheatyExceptionReport::PrintSymbolDetail ( char *  pszCurrBuffer)
staticprivate
1446 {
1447  if (symbolDetails.empty())
1448  return pszCurrBuffer;
1449 
1450  // Don't log anything if has been logged already or if it's empty
1451  if (symbolDetails.top().Logged || symbolDetails.top().empty())
1452  return pszCurrBuffer;
1453 
1454  // Add appropriate indentation level (since this routine is recursive)
1455  for (size_t i = 0; i < symbolDetails.size(); i++)
1456  pszCurrBuffer += sprintf(pszCurrBuffer, "\t");
1457 
1458  pszCurrBuffer += sprintf(pszCurrBuffer, "%s\r\n", symbolDetails.top().ToString().c_str());
1459 
1460  return pszCurrBuffer;
1461 }
static std::stack< SymbolDetail > symbolDetails
Definition: WheatyExceptionReport.h:198
std::string sprintf(CStringRef format, ArgList args)
Definition: format.h:3096

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WheatyExceptionReport::PrintSystemInfo ( )
staticprivate
400 {
401  SYSTEM_INFO SystemInfo;
402  ::GetSystemInfo(&SystemInfo);
403 
404  MEMORYSTATUS MemoryStatus;
405  MemoryStatus.dwLength = sizeof (MEMORYSTATUS);
406  ::GlobalMemoryStatus(&MemoryStatus);
407  TCHAR sString[1024];
408  _tprintf(_T("//=====================================================\r\n"));
409  if (_GetProcessorName(sString, countof(sString)))
410  _tprintf(_T("*** Hardware ***\r\nProcessor: %s\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"),
411  sString, SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400);
412  else
413  _tprintf(_T("*** Hardware ***\r\nProcessor: <unknown>\r\nNumber Of Processors: %d\r\nPhysical Memory: %d KB (Available: %d KB)\r\nCommit Charge Limit: %d KB\r\n"),
414  SystemInfo.dwNumberOfProcessors, MemoryStatus.dwTotalPhys/0x400, MemoryStatus.dwAvailPhys/0x400, MemoryStatus.dwTotalPageFile/0x400);
415 
416  if (_GetWindowsVersion(sString, countof(sString)))
417  _tprintf(_T("\r\n*** Operation System ***\r\n%s\r\n"), sString);
418  else
419  _tprintf(_T("\r\n*** Operation System:\r\n<unknown>\r\n"));
420 }
static BOOL _GetProcessorName(TCHAR *sProcessorName, DWORD maxcount)
Definition: WheatyExceptionReport.cpp:186
char TCHAR
Definition: CascPort.h:148
#define _T(x)
Definition: CascPort.h:171
static BOOL _GetWindowsVersion(TCHAR *szVersion, DWORD cntMax)
Definition: WheatyExceptionReport.cpp:225
static int __cdecl _tprintf(const TCHAR *format,...)
Definition: WheatyExceptionReport.cpp:1375
#define countof
Definition: WheatyExceptionReport.h:13

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WheatyExceptionReport::printTracesForAllThreads ( bool  bWriteVariables)
static
424 {
425  THREADENTRY32 te32;
426 
427  DWORD dwOwnerPID = GetCurrentProcessId();
428  m_hProcess = GetCurrentProcess();
429  // Take a snapshot of all running threads
430  HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
431  if (hThreadSnap == INVALID_HANDLE_VALUE)
432  return;
433 
434  // Fill in the size of the structure before using it.
435  te32.dwSize = sizeof(THREADENTRY32);
436 
437  // Retrieve information about the first thread,
438  // and exit if unsuccessful
439  if (!Thread32First(hThreadSnap, &te32))
440  {
441  CloseHandle(hThreadSnap); // Must clean up the
442  // snapshot object!
443  return;
444  }
445 
446  // Now walk the thread list of the system,
447  // and display information about each thread
448  // associated with the specified process
449  do
450  {
451  if (te32.th32OwnerProcessID == dwOwnerPID)
452  {
453  CONTEXT context;
454  context.ContextFlags = 0xffffffff;
455  HANDLE threadHandle = OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, false, te32.th32ThreadID);
456  if (threadHandle)
457  {
458  if (GetThreadContext(threadHandle, &context))
459  WriteStackDetails(&context, bWriteVariables, threadHandle);
460  CloseHandle(threadHandle);
461  }
462  }
463  } while (Thread32Next(hThreadSnap, &te32));
464 
465 // Don't forget to clean up the snapshot object.
466  CloseHandle(hThreadSnap);
467 }
static HANDLE m_hProcess
Definition: WheatyExceptionReport.h:196
void * HANDLE
Definition: CascPort.h:146
static void WriteStackDetails(PCONTEXT pContext, bool bWriteVariables, HANDLE pThreadHandle)
Definition: WheatyExceptionReport.cpp:704
unsigned int DWORD
Definition: CascPort.h:139
#define INVALID_HANDLE_VALUE
Definition: CascPort.h:169

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

char * WheatyExceptionReport::PushSymbolDetail ( char *  pszCurrBuffer)
staticprivate
1431 {
1432  // Log current symbol and then add another to the stack to keep the hierarchy format
1433  pszCurrBuffer = PrintSymbolDetail(pszCurrBuffer);
1434  symbolDetails.emplace();
1435  return pszCurrBuffer;
1436 }
static char * PrintSymbolDetail(char *pszCurrBuffer)
Definition: WheatyExceptionReport.cpp:1445
static std::stack< SymbolDetail > symbolDetails
Definition: WheatyExceptionReport.h:198

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int __cdecl WheatyExceptionReport::stackprintf ( const TCHAR format,
va_list  argptr 
)
staticprivate
1395 {
1396  int retValue;
1397  DWORD cbWritten;
1398 
1399  TCHAR szBuff[WER_LARGE_BUFFER_SIZE];
1400  retValue = vsprintf(szBuff, format, argptr);
1401  WriteFile(m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0);
1402 
1403  return retValue;
1404 }
void format(BasicFormatter< Char > &f, const Char *&format_str, const T &value)
Definition: format.h:2963
char TCHAR
Definition: CascPort.h:148
static HANDLE m_hReportFile
Definition: WheatyExceptionReport.h:194
unsigned int DWORD
Definition: CascPort.h:139
#define WER_LARGE_BUFFER_SIZE
Definition: WheatyExceptionReport.h:17

+ Here is the caller graph for this function:

bool WheatyExceptionReport::StoreSymbol ( DWORD  type,
DWORD_PTR  offset 
)
staticprivate
1419 {
1420  return symbols.insert(SymbolPair(type, offset)).second;
1421 }
static SymbolPairs symbols
Definition: WheatyExceptionReport.h:197
Definition: WheatyExceptionReport.h:94

+ Here is the caller graph for this function:

LONG WINAPI WheatyExceptionReport::WheatyUnhandledExceptionFilter ( PEXCEPTION_POINTERS  pExceptionInfo)
static
106 {
107  std::unique_lock<std::mutex> guard(alreadyCrashedLock);
108  // Handle only 1 exception in the whole process lifetime
109  if (alreadyCrashed)
110  return EXCEPTION_EXECUTE_HANDLER;
111 
112  alreadyCrashed = true;
113 
114  if (pExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW)
115  stackOverflowException = true;
116 
117  TCHAR module_folder_name[MAX_PATH];
118  GetModuleFileName(0, module_folder_name, MAX_PATH);
119  TCHAR* pos = _tcsrchr(module_folder_name, '\\');
120  if (!pos)
121  return 0;
122  pos[0] = '\0';
123  ++pos;
124 
125  TCHAR crash_folder_path[MAX_PATH];
126  sprintf(crash_folder_path, "%s\\%s", module_folder_name, CrashFolder);
127  if (!CreateDirectory(crash_folder_path, NULL))
128  {
130  return 0;
131  }
132 
133  SYSTEMTIME systime;
134  GetLocalTime(&systime);
135  sprintf(m_szDumpFileName, "%s\\%s_%s_[%u-%u_%u-%u-%u].dmp",
136  crash_folder_path, GitRevision::GetHash(), pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond);
137 
138  sprintf(m_szLogFileName, "%s\\%s_%s_[%u-%u_%u-%u-%u].txt",
139  crash_folder_path, GitRevision::GetHash(), pos, systime.wDay, systime.wMonth, systime.wHour, systime.wMinute, systime.wSecond);
140 
141  m_hDumpFile = CreateFile(m_szDumpFileName,
142  GENERIC_WRITE,
143  0,
144  0,
145  OPEN_ALWAYS,
146  FILE_FLAG_WRITE_THROUGH,
147  0);
148 
149  m_hReportFile = CreateFile(m_szLogFileName,
150  GENERIC_WRITE,
151  0,
152  0,
153  OPEN_ALWAYS,
154  FILE_FLAG_WRITE_THROUGH,
155  0);
156 
157  if (m_hDumpFile)
158  {
159  MINIDUMP_EXCEPTION_INFORMATION info;
160  info.ClientPointers = FALSE;
161  info.ExceptionPointers = pExceptionInfo;
162  info.ThreadId = GetCurrentThreadId();
163 
164  MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
165  m_hDumpFile, MiniDumpWithIndirectlyReferencedMemory, &info, 0, 0);
166 
167  CloseHandle(m_hDumpFile);
168  }
169 
170  if (m_hReportFile)
171  {
172  SetFilePointer(m_hReportFile, 0, 0, FILE_END);
173 
174  GenerateExceptionReport(pExceptionInfo);
175 
176  CloseHandle(m_hReportFile);
177  m_hReportFile = 0;
178  }
179 
180  if (m_previousFilter)
181  return m_previousFilter(pExceptionInfo);
182  else
183  return EXCEPTION_EXECUTE_HANDLER/*EXCEPTION_CONTINUE_SEARCH*/;
184 }
#define FILE_END
Definition: CascPort.h:167
static void GenerateExceptionReport(PEXCEPTION_POINTERS pExceptionInfo)
Definition: WheatyExceptionReport.cpp:473
#define MAX_PATH
Definition: CascPort.h:160
arena_t NULL
Definition: jemalloc_internal.h:624
char TCHAR
Definition: CascPort.h:148
static TCHAR m_szLogFileName[MAX_PATH]
Definition: WheatyExceptionReport.h:191
static bool stackOverflowException
Definition: WheatyExceptionReport.h:199
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter
Definition: WheatyExceptionReport.h:193
std::string sprintf(CStringRef format, ArgList args)
Definition: format.h:3096
#define CrashFolder
Definition: WheatyExceptionReport.cpp:25
static HANDLE m_hReportFile
Definition: WheatyExceptionReport.h:194
static bool alreadyCrashed
Definition: WheatyExceptionReport.h:200
int GetLastError()
Definition: Common.cpp:70
#define ERROR_ALREADY_EXISTS
Definition: CascPort.h:212
TC_COMMON_API char const * GetHash()
Definition: GitRevision.cpp:4
static TCHAR m_szDumpFileName[MAX_PATH]
Definition: WheatyExceptionReport.h:192
static std::mutex alreadyCrashedLock
Definition: WheatyExceptionReport.h:201
static HANDLE m_hDumpFile
Definition: WheatyExceptionReport.h:195
#define _tcsrchr
Definition: CascPort.h:176

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void WheatyExceptionReport::WriteStackDetails ( PCONTEXT  pContext,
bool  bWriteVariables,
HANDLE  pThreadHandle 
)
staticprivate
707 {
708  _tprintf(_T("\r\nCall stack:\r\n"));
709 
710  _tprintf(_T("Address Frame Function SourceFile\r\n"));
711 
712  DWORD dwMachineType = 0;
713  // Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
714 
715  STACKFRAME64 sf;
716  memset(&sf, 0, sizeof(sf));
717 
718  #ifdef _M_IX86
719  // Initialize the STACKFRAME structure for the first call. This is only
720  // necessary for Intel CPUs, and isn't mentioned in the documentation.
721  sf.AddrPC.Offset = pContext->Eip;
722  sf.AddrPC.Mode = AddrModeFlat;
723  sf.AddrStack.Offset = pContext->Esp;
724  sf.AddrStack.Mode = AddrModeFlat;
725  sf.AddrFrame.Offset = pContext->Ebp;
726  sf.AddrFrame.Mode = AddrModeFlat;
727 
728  dwMachineType = IMAGE_FILE_MACHINE_I386;
729  #endif
730 
731 #ifdef _M_X64
732  sf.AddrPC.Offset = pContext->Rip;
733  sf.AddrPC.Mode = AddrModeFlat;
734  sf.AddrStack.Offset = pContext->Rsp;
735  sf.AddrStack.Mode = AddrModeFlat;
736  sf.AddrFrame.Offset = pContext->Rbp;
737  sf.AddrFrame.Mode = AddrModeFlat;
738  dwMachineType = IMAGE_FILE_MACHINE_AMD64;
739 #endif
740 
741  for (;;)
742  {
743  // Get the next stack frame
744  if (! StackWalk64(dwMachineType,
745  m_hProcess,
746  pThreadHandle != NULL ? pThreadHandle : GetCurrentThread(),
747  &sf,
748  pContext,
749  0,
750  SymFunctionTableAccess64,
751  SymGetModuleBase64,
752  0))
753  break;
754  if (0 == sf.AddrFrame.Offset) // Basic sanity check to make sure
755  break; // the frame is OK. Bail if not.
756 #ifdef _M_IX86
757  _tprintf(_T("%08X %08X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
758 #endif
759 #ifdef _M_X64
760  _tprintf(_T("%016I64X %016I64X "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
761 #endif
762 
763  DWORD64 symDisplacement = 0; // Displacement of the input address,
764  // relative to the start of the symbol
765 
766  // Get the name of the function for this stack frame entry
767  CSymbolInfoPackage sip;
768  if (SymFromAddr(
769  m_hProcess, // Process handle of the current process
770  sf.AddrPC.Offset, // Symbol address
771  &symDisplacement, // Address of the variable that will receive the displacement
772  &sip.si)) // Address of the SYMBOL_INFO structure (inside "sip" object)
773  {
774  _tprintf(_T("%hs+%I64X"), sip.si.Name, symDisplacement);
775 
776  }
777  else // No symbol found. Print out the logical address instead.
778  {
779  TCHAR szModule[MAX_PATH] = _T("");
780  DWORD section = 0;
781  DWORD_PTR offset = 0;
782 
783  GetLogicalAddress((PVOID)sf.AddrPC.Offset,
784  szModule, sizeof(szModule), section, offset);
785 #ifdef _M_IX86
786  _tprintf(_T("%04X:%08X %s"), section, offset, szModule);
787 #endif
788 #ifdef _M_X64
789  _tprintf(_T("%04X:%016I64X %s"), section, offset, szModule);
790 #endif
791  }
792 
793  // Get the source line for this stack frame entry
794  IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };
795  DWORD dwLineDisplacement;
796  if (SymGetLineFromAddr64(m_hProcess, sf.AddrPC.Offset,
797  &dwLineDisplacement, &lineInfo))
798  {
799  _tprintf(_T(" %s line %u"), lineInfo.FileName, lineInfo.LineNumber);
800  }
801 
802  _tprintf(_T("\r\n"));
803 
804  // Write out the variables, if desired
805  if (bWriteVariables)
806  {
807  // Use SymSetContext to get just the locals/params for this frame
808  IMAGEHLP_STACK_FRAME imagehlpStackFrame;
809  imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
810  SymSetContext(m_hProcess, &imagehlpStackFrame, 0);
811 
812  // Enumerate the locals/parameters
813  SymEnumSymbols(m_hProcess, 0, 0, EnumerateSymbolsCallback, &sf);
814 
815  _tprintf(_T("\r\n"));
816  }
817  }
818 
819 }
static HANDLE m_hProcess
Definition: WheatyExceptionReport.h:196
static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO, ULONG, PVOID)
Definition: WheatyExceptionReport.cpp:826
static BOOL GetLogicalAddress(PVOID addr, PTSTR szModule, DWORD len, DWORD &section, DWORD_PTR &offset)
Definition: WheatyExceptionReport.cpp:639
#define MAX_PATH
Definition: CascPort.h:160
arena_t NULL
Definition: jemalloc_internal.h:624
Definition: WheatyExceptionReport.cpp:692
char TCHAR
Definition: CascPort.h:148
#define _T(x)
Definition: CascPort.h:171
unsigned long DWORD_PTR
Definition: CascPort.h:140
unsigned int DWORD
Definition: CascPort.h:139
static int __cdecl _tprintf(const TCHAR *format,...)
Definition: WheatyExceptionReport.cpp:1375

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Member Data Documentation

bool WheatyExceptionReport::alreadyCrashed
staticprivate
std::mutex WheatyExceptionReport::alreadyCrashedLock
staticprivate
HANDLE WheatyExceptionReport::m_hDumpFile
staticprivate
HANDLE WheatyExceptionReport::m_hProcess
staticprivate
HANDLE WheatyExceptionReport::m_hReportFile
staticprivate
LPTOP_LEVEL_EXCEPTION_FILTER WheatyExceptionReport::m_previousFilter
staticprivate
TCHAR WheatyExceptionReport::m_szDumpFileName
staticprivate
TCHAR WheatyExceptionReport::m_szLogFileName
staticprivate
WheatyExceptionReport::pRtlGetVersion WheatyExceptionReport::RtlGetVersion
staticprivate
bool WheatyExceptionReport::stackOverflowException
staticprivate
std::stack< SymbolDetail > WheatyExceptionReport::symbolDetails
staticprivate
SymbolPairs WheatyExceptionReport::symbols
staticprivate

The documentation for this class was generated from the following files: