⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 excepthandler.cpp

📁 CExceptionLogger
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    }
    if (pExceptionInfo->ExceptionRecord->NumberParameters > 1)
      Log(_T("Access Violation Address: 0x%08X\r\n"), pExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
  }

  //Is the exception continuable
  if (pExceptionInfo->ExceptionRecord->ExceptionFlags == 0)
    Log(_T("Exception is continuable\r\n"));
  else
    Log(_T("Exception is noncontinuable\r\n"));

  //Log where the fault occurred
  DWORD dwOffset;
  char pszSectionName[IMAGE_SIZEOF_SHORT_NAME+1];
  if (GetAddressDetails(pExceptionInfo->ExceptionRecord->ExceptionAddress, m_szTempFileName, dwOffset, pszSectionName))
    Log(_T("Exception Address Details: 0x%08X [%hs]:0x%08X %s\r\n"), pExceptionInfo->ExceptionRecord->ExceptionAddress, pszSectionName, dwOffset, m_szTempFileName);
  else
  {
    //Fall back to just reporting the linear faulting address, rather than the additional details
    Log(_T("Exception Address Details: 0x%08X [UNKNOWN]\r\n"), pExceptionInfo->ExceptionRecord->ExceptionAddress);
  }

  //Write out the full path to the process which is affected
  GetModuleFileName(NULL, m_szTempFileName, _MAX_PATH);
  Log(_T("Process Path: %s\r\n"), m_szTempFileName);

  //Get the current working directory
  GetCurrentDirectory(_MAX_PATH, m_szTempFileName);
  Log(_T("Current Directory: %s\r\n"), m_szTempFileName);

  //Get the current working directory
  Log(_T("Command Line: %s\r\n"), GetCommandLine());

  //Write out the Process and Thread ID 
  DWORD dwProcessID = GetCurrentProcessId();
  Log(_T("Process ID: 0x%08X\r\n"), dwProcessID);
  Log(_T("Thread ID where exception has occurred: 0x%08X\r\n"), GetCurrentThreadId());

  //Initialize DBGHELP
  HANDLE hProcess = GetCurrentProcess();
  BOOL bInitDBGHelp = SymInitialize(hProcess, NULL, TRUE);
  if (!bInitDBGHelp)
    Log(_T(" Failed to initialize Debug Help Library, Error:%d\r\n"), GetLastError());
  SymSetOptions(SYMOPT_DEFERRED_LOADS);

  //Log details on each module in this process
  HANDLE hToolHelp32Snap = INVALID_HANDLE_VALUE;
  if (_ExceptionLoggerData.m_lpfnCreateToolhelp32Snapshot)
  {
    hToolHelp32Snap = _ExceptionLoggerData.m_lpfnCreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
    if (hToolHelp32Snap != INVALID_HANDLE_VALUE) 
    {
      //Log all the threads in the current process 
      Log(_T("\r\nThreads:\r\n"));

      //Fill in the size of the structure before using it. 
      THREADENTRY32 te32;; 
      te32.dwSize = sizeof(THREADENTRY32); 

      //Walk the thread snapshot to find all threads of the process. 
      //If the thread belongs to the process, add its information 
      //to the display list.
      if (_ExceptionLoggerData.m_lpfnThread32First(hToolHelp32Snap, &te32)) 
      { 
        do 
        { 
          if (te32.th32OwnerProcessID == dwProcessID) 
          {
            Log(_T("  Thread ID: 0x%08X\r\n"), te32.th32ThreadID);
            Log(_T("  Priority Level: %d\r\n"), te32.tpBasePri);
            Log(_T("  Delta Priority: %d\r\n"), te32.tpDeltaPri);
            Log(_T("  References: %d\r\n"), te32.cntUsage);

            //Write out some detailed info on each thread (over and above what ToolHelp32 gives you)
            HANDLE hThread = _ExceptionLoggerData.m_lpfnOpenThread ? _ExceptionLoggerData.m_lpfnOpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID) : NULL;
            if (hThread)
            {
              FILETIME ct;
              FILETIME et;
              FILETIME kt;
              FILETIME ut;
              if (GetThreadTimes(hThread, &ct, &et, &kt, &ut))
              {
                SYSTEMTIME st;
                FileTimeToSystemTime(&ct, &st);
                Log(_T("  Creation Time: %02d:%02d:%02d.%03d %d/%d/%d (D/M/Y)\r\n"), st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, st.wDay, st.wMonth, st.wYear);
                unsigned __int64 TimeTaken;
                TimeTaken = (((unsigned __int64)kt.dwHighDateTime) << 32);
                TimeTaken += kt.dwLowDateTime;
                Log(_T("  Kernel Time (Seconds): %I64u\r\n"), TimeTaken/10000000);
                TimeTaken = (((unsigned __int64)ut.dwHighDateTime) << 32);
                TimeTaken += ut.dwLowDateTime;
                Log(_T("  User Time: (Seconds) %I64u\r\n"), TimeTaken/10000000);
              }
              CloseHandle(hThread);
            }
            Log(_T("\r\n"));
          }
        } 
        while (_ExceptionLoggerData.m_lpfnThread32Next(hToolHelp32Snap, &te32)); 
      } 
      else
        Log(_T(" Failed in call to Thread32First, Error:%d\r\n"), GetLastError());

      //Log all the modules in the current process 
      Log(_T("Modules:\r\n"));

      //Fill in the size of the structure before using it. 
      MODULEENTRY32 me32;
      me32.dwSize = sizeof(MODULEENTRY32); 

      //Walk the thread snapshot to find all threads of the process. 
      //If the thread belongs to the process, add its information 
      //to the display list.
      if (_ExceptionLoggerData.m_lpfnModule32First(hToolHelp32Snap, &me32)) 
      { 
        do 
        { 
          if (me32.th32ProcessID == dwProcessID)
          {
            Log(_T(" Name: %s\r\n"), me32.szModule);
            Log(_T(" Path: %s\r\n"), me32.szExePath);
            Log(_T(" Global Usage Count: %d\r\n"), me32.GlblcntUsage);
            Log(_T(" Process Usage Count: %d\r\n"), me32.ProccntUsage);
            Log(_T(" HMODULE: %08X\r\n"), me32.modBaseAddr);
            Log(_T(" Size: %d\r\n"), me32.modBaseSize);

            //Also display all the symbols for this module
            if (bInitDBGHelp)
            {
              //display all the global variables
              Log(_T("Variables for this Module\r\n"));
              SymEnumSymbols(hProcess, (ULONG64)me32.modBaseAddr, 0, EnumSymbols, 0);
              Log(_T("\r\n"));
            }
          }
        } 
        while (_ExceptionLoggerData.m_lpfnModule32Next(hToolHelp32Snap, &me32)); 
      } 
      else
        Log(_T(" Failed in call to Module32First, Error:%d\r\n"), GetLastError());

      //close the handle now that we are finished with it
      CloseHandle(hToolHelp32Snap); 
    }
    else
      Log(_T(" Failed in call to CreateToolhelp32Snapshot, Error:%d\r\n"), GetLastError());
  }
  else
    Log(_T("Threads / Modules: ToolHelp32 dll not availble, Cannot enumerate threads or modules\r\n"));

  //Next thing to log is the i86 Registers
  Log(_T("\r\nRegisters:\r\n EAX    %08X\r\n"), pExceptionInfo->ContextRecord->Eax);
  Log(_T(" EBX    %08X\r\n"), pExceptionInfo->ContextRecord->Ebx);
  Log(_T(" ECX    %08X\r\n"), pExceptionInfo->ContextRecord->Ecx);
  Log(_T(" EDX    %08X\r\n"), pExceptionInfo->ContextRecord->Edx);
  Log(_T(" ESI    %08X\r\n"), pExceptionInfo->ContextRecord->Esi);
  Log(_T(" EDI    %08X\r\n"), pExceptionInfo->ContextRecord->Edi);
  Log(_T(" CS:EIP %08X:%08X\r\n"), pExceptionInfo->ContextRecord->SegCs, pExceptionInfo->ContextRecord->Eip);
  Log(_T(" SS:ESP %08X:%08X\r\n"), pExceptionInfo->ContextRecord->SegSs, pExceptionInfo->ContextRecord->Esp);
  Log(_T(" EBP    %08X\r\n"), pExceptionInfo->ContextRecord->SegSs, pExceptionInfo->ContextRecord->Ebp);
  Log(_T(" DS     %08X\r\n"), pExceptionInfo->ContextRecord->SegDs);
  Log(_T(" ES     %08X\r\n"), pExceptionInfo->ContextRecord->SegEs);
  Log(_T(" FS     %08X\r\n"), pExceptionInfo->ContextRecord->SegFs);
  Log(_T(" GS     %08X\r\n"), pExceptionInfo->ContextRecord->SegGs);
  Log(_T(" Flags  %08X\r\n"), pExceptionInfo->ContextRecord->EFlags);

  //Next do the call stack
  Log(_T("\r\nCall Stack:\r\n"));
  LogStack(pExceptionInfo->ContextRecord, hProcess);

  //Cleanup our usage of DBGHELP
  SymCleanup(hProcess);
}

//A Helper function to allow use to do sprintf style logging to the crash log file.
//Please note that the file will be Unicode if you build using UNICODE.
int CExceptionLogger::Log(const TCHAR* format, ...)
{
  //Generate the line
  va_list args;
  va_start(args, format);
  int nLen = _vstprintf(m_szTempLogLine, format, args); //Note that we are using the C runtime here!!
  va_end(args);

  //write the line to disk
  DWORD dwWritten = 0;
  WriteFile(m_hLogFile, m_szTempLogLine, nLen*sizeof(TCHAR), &dwWritten, NULL);
  return nLen;
}

//Coverts a linear address to a module, section, offset, name of section
BOOL CExceptionLogger::GetAddressDetails(void* pAddress, LPTSTR pszModule, DWORD& dwOffset, char* pszSectionName)
{
  //First thing to do is we need to get the base address in memory (i.e. a HINSTANCE) from pAddress
  MEMORY_BASIC_INFORMATION MemInfo;
  if (!VirtualQuery(pAddress, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
    return FALSE;

  //From the HINSTANCE we can get the module name
  HMODULE hModule = (HMODULE) MemInfo.AllocationBase;
  if (!GetModuleFileName(hModule, pszModule, _MAX_PATH))
    return FALSE;

  //Now do our in memory traversal of the PE image to loop across the sections in that image
  PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER) hModule;
  PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS) (((BYTE*)pDosHeader) + pDosHeader->e_lfanew);
  PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader);

  //Express the "pAddress" parameter as an "RVA"
  DWORD dwRVAAddress = (DWORD) ((BYTE*)pAddress - (BYTE*)MemInfo.AllocationBase); 

  //Loop across the sections to find the one which contains our faulting address
  for (WORD i=0; i<pNTHeader->FileHeader.NumberOfSections; i++, pSection++)
  {
    DWORD dwSectionStart = pSection->VirtualAddress;
    DWORD dwSectionEnd = dwSectionStart + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);

    //Is the "pAddress" parameter (expressed as a RVA) inside this section?
    if ((dwRVAAddress >= dwSectionStart) && (dwRVAAddress <= dwSectionEnd))
    {
      dwOffset = dwRVAAddress - dwSectionStart;
      CopyMemory(pszSectionName, pSection->Name, IMAGE_SIZEOF_SHORT_NAME);
      pszSectionName[IMAGE_SIZEOF_SHORT_NAME] = NULL; //Don't forget to NULL terminate the Section name
      return TRUE;
    }
  }

  //Got here, then return failure
  return FALSE;
}

void CExceptionLogger::LogStack(CONTEXT* pContext, HANDLE hProcess)
{
  //Variables required inside the loop
  HANDLE hThread = GetCurrentThread();

  //Initialize the STACKFRAME variable to start walking the stack from
  STACKFRAME sf;
  ZeroMemory(&sf, sizeof(STACKFRAME));
  sf.AddrPC.Offset    = pContext->Eip;
  sf.AddrPC.Mode      = AddrModeFlat;
  sf.AddrStack.Offset = pContext->Esp;
  sf.AddrStack.Mode   = AddrModeFlat;
  sf.AddrFrame.Offset = pContext->Ebp;
  sf.AddrFrame.Mode   = AddrModeFlat;

  //Now let's walk the walk
  BOOL bContinue = TRUE;
  while (bContinue)
  {
    if (StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &sf, 
                   pContext, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
    {
      DWORD dwOffset;
      char pszSectionName[IMAGE_SIZEOF_SHORT_NAME+1];
      if (GetAddressDetails((PVOID)sf.AddrPC.Offset, m_szTempFileName, dwOffset, pszSectionName))
        Log(_T(" 0x%08X [%hs]:0x%08X %s"), sf.AddrPC.Offset, pszSectionName, dwOffset, m_szTempFileName);
      else
      {
        //Fall back to just reporting the linear faulting address, rather than the additional details
        Log(_T(" 0x%08X [UNKNOWN]"), sf.AddrPC.Offset);
      }

      //Get the Symbol Info for the offending address
      SYMBOL_INFO* pSymbolInfo = (SYMBOL_INFO*) m_bySymbolInfo;
      pSymbolInfo->SizeOfStruct = sizeof(m_bySymbolInfo);
      pSymbolInfo->MaxNameLen = 1024;
      DWORD64 SymbolOffset;
      if (SymFromAddr(hProcess, sf.AddrPC.Offset, &SymbolOffset, pSymbolInfo))
        Log(_T(" %hs+%I64X"), pSymbolInfo->Name, SymbolOffset);

      //Get the source line if we can
      IMAGEHLP_LINE LineInfo;
      LineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE);
      DWORD dwLineDisplacement;
      if (SymGetLineFromAddr(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &LineInfo))
        Log(_T(" %hs line %u"), LineInfo.FileName, LineInfo.LineNumber);

      //Write out the variables at this stack frame
      Log(_T("\r\n  Variables\r\n"));
      IMAGEHLP_STACK_FRAME imageHelpStackFrame;
      imageHelpStackFrame.InstructionOffset = sf.AddrPC.Offset;
      SymSetContext(hProcess, &imageHelpStackFrame, 0);
      SymEnumSymbols(hProcess, 0, 0, EnumSymbols, &sf);

      //Start the next stack frame log on a new line
      Log(_T("\r\n"));
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -