home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 217 / DPCS0306DVD.ISO / Toolkit / Internet / FileZilla / Server / FileZilla_Server-0.9.11.exe / source / misc / ExceptionReport.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-13  |  20.2 KB  |  699 lines

  1. // FileZilla - a Windows ftp client
  2.  
  3. // Copyright (C) 2004 - Tim Kosse <tim.kosse@gmx.de>
  4.  
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9.  
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14.  
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. // OptionsTypePage.cpp: Implementierungsdatei
  20. //
  21.  
  22. #include "stdafx.h"
  23. #include <dbghelp.h>
  24. #include "ExceptionReport.h"
  25. #include "..\version.h"
  26. #include "ProcessorInfo.h"
  27. #include "WindowsVersion.h"
  28. #include "mailmsg.h"
  29. #include "Tlhelp32.h"
  30.  
  31. typedef BOOL
  32. (_stdcall *tSymFromAddr)(
  33.     IN  HANDLE            hProcess,
  34.     IN  DWORD64            Address,
  35.     OUT PDWORD64        Displacement,
  36.     IN OUT PSYMBOL_INFO    Symbol
  37.     );
  38.  
  39. typedef DWORD
  40. (_stdcall *tSymGetOptions)(
  41.     );
  42.  
  43. typedef DWORD
  44. (_stdcall *tSymSetOptions)(
  45.     IN DWORD   SymOptions
  46.     );
  47.  
  48. typedef BOOL
  49. (_stdcall *tSymCleanup)(
  50.     IN HANDLE hProcess
  51.     );
  52.  
  53. typedef BOOL
  54. (_stdcall *tSymInitialize)(
  55.     IN HANDLE    hProcess,
  56.     IN PSTR        UserSearchPath,
  57.     IN BOOL        fInvadeProcess
  58.     );
  59.  
  60. typedef BOOL
  61. (_stdcall *tSymGetLineFromAddr)(
  62.     IN  HANDLE                hProcess,
  63.     IN  DWORD                dwAddr,
  64.     OUT PDWORD                pdwDisplacement,
  65.     OUT PIMAGEHLP_LINE        Line
  66.     );
  67.  
  68. typedef BOOL
  69. (_stdcall *tStackWalk)(
  70.     DWORD                            MachineType,
  71.     HANDLE                            hProcess,
  72.     HANDLE                            hThread,
  73.     LPSTACKFRAME                    StackFrame,
  74.     PVOID                            ContextRecord,
  75.     PREAD_PROCESS_MEMORY_ROUTINE    ReadMemoryRoutine,
  76.     PFUNCTION_TABLE_ACCESS_ROUTINE    FunctionTableAccessRoutine,
  77.     PGET_MODULE_BASE_ROUTINE        GetModuleBaseRoutine,
  78.     PTRANSLATE_ADDRESS_ROUTINE        TranslateAddress
  79.     );
  80.  
  81. typedef PVOID
  82. (_stdcall *tSymFunctionTableAccess)(
  83.     HANDLE  hProcess,
  84.     DWORD   AddrBase
  85.     );
  86.  
  87. typedef DWORD
  88. (_stdcall *tSymGetModuleBase)(
  89.     IN  HANDLE              hProcess,
  90.     IN  DWORD               dwAddr
  91.     );
  92.  
  93. typedef BOOL
  94. (_stdcall *tMiniDumpWriteDump)(
  95.     HANDLE hProcess,
  96.     DWORD ProcessId,
  97.     HANDLE hFile,
  98.     MINIDUMP_TYPE DumpType,
  99.     PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
  100.     PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
  101.     PMINIDUMP_CALLBACK_INFORMATION CallbackParam
  102.     );
  103.  
  104. static tSymCleanup                pSymCleanup;
  105. static tSymInitialize            pSymInitialize;
  106. static tSymGetOptions            pSymGetOptions;
  107. static tSymSetOptions            pSymSetOptions;
  108. static tSymGetLineFromAddr        pSymGetLineFromAddr;
  109. static tSymFromAddr                pSymFromAddr;
  110. static tStackWalk                pStackWalk;
  111. static tSymFunctionTableAccess    pSymFunctionTableAccess;
  112. static tSymGetModuleBase        pSymGetModuleBase;
  113. static tMiniDumpWriteDump        pMiniDumpWriteDump;
  114.  
  115. // Global class instance
  116. // static CExceptionReport ExceptionReport;
  117.  
  118. LPTOP_LEVEL_EXCEPTION_FILTER CExceptionReport::m_previousExceptionFilter;
  119. TCHAR CExceptionReport::m_pLogFileName[MAX_PATH];
  120. HANDLE CExceptionReport::m_hReportFile;
  121. TCHAR CExceptionReport::m_pDmpFileName[MAX_PATH];
  122. HANDLE CExceptionReport::m_hDumpFile;
  123. BOOL CExceptionReport::m_bFirstRun;
  124.  
  125. CExceptionReport::CExceptionReport()
  126. {
  127.     m_bFirstRun = TRUE;
  128.  
  129.     m_previousExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);
  130.  
  131.     // Retrieve report/dump filenames
  132.     GetModuleFileName(0, m_pLogFileName, MAX_PATH);
  133.  
  134.     // Look for the '.' before the "EXE" extension.  Replace the extension
  135.     // with "RPT"
  136.     LPTSTR p = _tcsrchr(m_pLogFileName, _T('.'));
  137.     if (p)
  138.     {
  139.         p++;
  140.         *p = 0;
  141.         _tcscpy(m_pDmpFileName, m_pLogFileName);
  142.         _tcscpy(p, _T("rpt"));
  143.         _tcscat(m_pDmpFileName, _T("dmp"));
  144.     }
  145. }
  146.  
  147. CExceptionReport::~CExceptionReport()
  148. {
  149.     SetUnhandledExceptionFilter(m_previousExceptionFilter);
  150. }
  151.  
  152. LONG WINAPI CExceptionReport::UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
  153. {
  154.     if (!m_bFirstRun)
  155.     {
  156.         // Don't generate exception report twice
  157.         if (m_previousExceptionFilter)
  158.             return m_previousExceptionFilter(pExceptionInfo);
  159.         else
  160.             return EXCEPTION_CONTINUE_SEARCH;
  161.     }
  162.     else
  163.         m_bFirstRun = FALSE;
  164.  
  165.     // Suspend all threads to freeze the current state
  166.     SuspendThreads();
  167.     
  168.     HMODULE hDll = LoadLibrary(_T("dbghelp.dll"));
  169.     if (!hDll)
  170.     {
  171.         if (m_previousExceptionFilter)
  172.             return m_previousExceptionFilter(pExceptionInfo);
  173.         else
  174.             return EXCEPTION_CONTINUE_SEARCH;
  175.     }
  176.  
  177.     pSymCleanup                = (tSymCleanup)GetProcAddress(hDll, "SymCleanup");
  178.     pSymInitialize            = (tSymInitialize)GetProcAddress(hDll, "SymInitialize");
  179.     pSymGetOptions            = (tSymGetOptions)GetProcAddress(hDll, "SymGetOptions");
  180.     pSymSetOptions            = (tSymSetOptions)GetProcAddress(hDll, "SymSetOptions");
  181.     pSymGetLineFromAddr        = (tSymGetLineFromAddr)GetProcAddress(hDll, "SymGetLineFromAddr");
  182.     pSymFromAddr            = (tSymFromAddr)GetProcAddress(hDll, "SymFromAddr");
  183.     pStackWalk                = (tStackWalk)GetProcAddress(hDll, "StackWalk");
  184.     pSymFunctionTableAccess    = (tSymFunctionTableAccess)GetProcAddress(hDll, "SymFunctionTableAccess");
  185.     pSymGetModuleBase        = (tSymGetModuleBase)GetProcAddress(hDll, "SymGetModuleBase");
  186.     pMiniDumpWriteDump        = (tMiniDumpWriteDump)GetProcAddress(hDll, "MiniDumpWriteDump");
  187.  
  188.     if (!pSymCleanup            ||
  189.         !pSymInitialize            ||
  190.         !pSymGetOptions            ||
  191.         !pSymSetOptions            ||
  192.         !pSymGetLineFromAddr    ||
  193.         !pSymFromAddr            ||
  194.         !pStackWalk                ||
  195.         !pSymFunctionTableAccess||
  196.         !pSymGetModuleBase        ||
  197.         !pMiniDumpWriteDump)
  198.     {
  199.         FreeLibrary(hDll);
  200.         if (m_previousExceptionFilter)
  201.             return m_previousExceptionFilter(pExceptionInfo);
  202.         else
  203.             return EXCEPTION_CONTINUE_SEARCH;
  204.     }
  205.  
  206.     if (::MessageBox(NULL,
  207. _T("An unhandled exception has occurred in FileZilla Server\r\n\
  208. FileZilla Server has to be closed.\r\n\r\n\
  209. Would you like to generate an exception report?\r\n\
  210. The report contains all neccessary information about the exception,\r\n\
  211. including a call stack with function parameters and local variables.\r\n\r\n\
  212. If you're using the latest version of FileZilla Server, please send the generated exception record to the following mail address: Tim.Kosse@gmx.de\r\n\
  213. The report will be analyzed and the reason for this exception will be fixed in the next version of FileZilla Server.\r\n\r\n\
  214. Please note: It may be possible - though unlikely - that the exception report may contain personal and or confidential information. All exception reports will be processed higly confidential and solely to analyze the crash. The reports will be deleted immediately after processing.\r\n"),
  215.         _T("FileZilla Server - Unhandled exception"), MB_APPLMODAL | MB_YESNO | MB_ICONSTOP)==IDYES)
  216.     {
  217.         m_hReportFile = CreateFile(m_pLogFileName, GENERIC_WRITE,FILE_SHARE_READ,
  218.                                    0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0);
  219.     
  220.         m_hDumpFile = CreateFile(m_pDmpFileName, GENERIC_WRITE, FILE_SHARE_READ,
  221.                                  0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,    0);
  222.     
  223.         if (m_hReportFile == INVALID_HANDLE_VALUE)
  224.         {
  225.             TCHAR tmp[MAX_PATH];
  226.             _tcscpy(tmp, m_pLogFileName);
  227.             TCHAR *pos=_tcsrchr(tmp, '\\');
  228.             if (pos)
  229.             {
  230.                 pos++;
  231.                 _stprintf(m_pLogFileName, _T("c:\\%s"), pos);
  232.             }
  233.             else
  234.                 _stprintf(m_pLogFileName, _T("c:\\%s"), tmp);
  235.         
  236.             m_hReportFile = CreateFile(m_pLogFileName, GENERIC_WRITE,FILE_SHARE_READ,
  237.                                        0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0);
  238.         }
  239.         if (m_hDumpFile == INVALID_HANDLE_VALUE)
  240.         {
  241.             TCHAR tmp[MAX_PATH];
  242.             _tcscpy(tmp, m_pDmpFileName);
  243.             TCHAR *pos=_tcsrchr(tmp, '\\');
  244.             if (pos)
  245.             {
  246.                 pos++;
  247.                 _stprintf(m_pDmpFileName, _T("c:\\%s"), pos);
  248.             }
  249.             else
  250.                 _stprintf(m_pDmpFileName, _T("c:\\%s"), tmp);
  251.         
  252.             m_hDumpFile = CreateFile(m_pDmpFileName, GENERIC_WRITE, FILE_SHARE_READ,
  253.                                      0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,    0);
  254.         }
  255.  
  256.         int nError=0;
  257.         if (m_hReportFile == INVALID_HANDLE_VALUE && INVALID_HANDLE_VALUE)
  258.             nError = GetLastError();
  259.         else
  260.         {
  261. #ifdef TRY
  262.             TRY
  263. #endif
  264.             {
  265.                 if (m_hReportFile != INVALID_HANDLE_VALUE)
  266.                     CreateReport(pExceptionInfo);
  267.     
  268.                 CloseHandle(m_hReportFile);
  269.             }
  270. #ifdef TRY
  271.             CATCH_ALL(e);
  272.             {
  273.                 nError = GetLastError();
  274.                 CloseHandle(m_hReportFile);
  275.             }
  276.             END_CATCH_ALL
  277.  
  278.             TRY
  279. #endif
  280.             {
  281.                 if (m_hDumpFile != INVALID_HANDLE_VALUE)
  282.                     writeMiniDump(pExceptionInfo);
  283.  
  284.                 CloseHandle(m_hDumpFile);
  285.                 nError = 0;
  286.             }
  287. #ifdef TRY
  288.             CATCH_ALL(e);
  289.             {
  290.                 CloseHandle(m_hDumpFile);
  291.             }
  292.             END_CATCH_ALL
  293. #endif
  294.         }
  295.  
  296.         if (nError)
  297.         {
  298.         
  299.             TCHAR tmp[1000];
  300.             _stprintf(tmp, _T("Unable to create exception report, error code %d."), nError);
  301.             MessageBox(0, tmp, _T("FileZilla Server - Unhandled eception"), MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  302.         }
  303.         else
  304.         {
  305.             sendMail();
  306.  
  307.             TCHAR tmp[1000];
  308.             _stprintf(tmp, _T("The exception report has been saved to \"%s\" and \"%s\".\n\
  309. Please make sure that you are using the latest version of FileZilla Server.\n\
  310. You can download the latest version from http://sourceforge.net/projects/filezilla/.\n\
  311. If you do use the latest version, please send the exception report to Tim.Kosse@gmx.de along with a brief explanation what you did before FileZilla Server crashed."), m_pLogFileName, m_pDmpFileName);
  312.             MessageBox(0, tmp, _T("FileZilla Server - Unhandled eception"), MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  313.  
  314.             FreeLibrary(hDll);
  315.             return EXCEPTION_CONTINUE_SEARCH;
  316.         }
  317.     }
  318.     FreeLibrary(hDll);
  319.     if (m_previousExceptionFilter)
  320.         return m_previousExceptionFilter(pExceptionInfo);
  321.     else
  322.         return EXCEPTION_CONTINUE_SEARCH;
  323.  
  324. }
  325.  
  326. void CExceptionReport::CreateReport(PEXCEPTION_POINTERS pExceptionInfo)
  327. {
  328.     // Start out with a banner
  329.     AddToReport("Exception report created by ");
  330.     AddToReport(GetVersionString());
  331.     AddToReport("\r\n===================================================\r\n\r\n");
  332.     AddToReport("System details:\r\n");
  333.     AddToReport("---------------\r\n\r\nOperating System:      ");
  334.     
  335.     TCHAR buffer[200];
  336.     if (DisplaySystemVersion(buffer))
  337.     {
  338.         AddToReport(buffer);
  339.         AddToReport("\r\n");
  340.     }
  341.     else
  342.         AddToReport("Could not get OS version\r\n");
  343.     
  344.     CProcessorInfo pi;
  345.     CMemoryInfo mi;
  346.     AddToReport("Processor Information: ");
  347.     AddToReport(pi.GetProcessorName());
  348.     AddToReport("\r\nMemory Information:    ");
  349.     AddToReport(mi.GetMemoryInfo());
  350.     
  351.     PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
  352.  
  353.     // Print fault type
  354.     AddToReport("\r\nException Details:\r\n------------------\r\n\r\nException code: ");
  355.     AddToReportHex(pExceptionRecord->ExceptionCode, 8);
  356.     AddToReport(" ");
  357.     AddToReport(GetExceptionString(pExceptionRecord->ExceptionCode));
  358.     
  359.     // Add fault address and module
  360.     TCHAR szModule[MAX_PATH];
  361.     memset(szModule, 0, MAX_PATH);
  362.     DWORD dwSection, dwOffset;
  363.     GetAddrDetails(pExceptionRecord->ExceptionAddress,
  364.                       szModule,
  365.                       sizeof(szModule),
  366.                       dwSection, dwOffset);
  367.  
  368.     AddToReport("\r\nFault address:  ");
  369.     AddToReportHex((int)pExceptionRecord->ExceptionAddress, 8);
  370.     AddToReport(" ");
  371.     AddToReportHex(dwSection, 2);
  372.     AddToReport(":");
  373.     AddToReportHex(dwOffset, 8);
  374.     AddToReport(" ");
  375.     AddToReport(szModule);
  376.     AddToReport("\r\n");
  377.  
  378.     // Set up the symbol engine.
  379.     DWORD dwOptions = pSymGetOptions() ;
  380.  
  381.     // Turn on line loading and deferred loading.
  382.     pSymSetOptions(dwOptions | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
  383.  
  384.     PCONTEXT pContext = pExceptionInfo->ContextRecord;
  385.  
  386.     // Initialize DbgHelp
  387.     if (!pSymInitialize(GetCurrentProcess(), 0, TRUE))
  388.         return;
  389.  
  390.     StackWalk(*pContext);
  391.  
  392.     pSymCleanup(GetCurrentProcess());
  393. }
  394.  
  395. LPTSTR CExceptionReport::GetExceptionString(DWORD dwCode)
  396. {
  397.     #define EXCEPTION(x) case EXCEPTION_##x: return _T(#x);
  398.  
  399.     switch (dwCode)
  400.     {
  401.         EXCEPTION(ACCESS_VIOLATION)
  402.         EXCEPTION(DATATYPE_MISALIGNMENT)
  403.         EXCEPTION(BREAKPOINT)
  404.         EXCEPTION(SINGLE_STEP)
  405.         EXCEPTION(ARRAY_BOUNDS_EXCEEDED)
  406.         EXCEPTION(FLT_DENORMAL_OPERAND)
  407.         EXCEPTION(FLT_DIVIDE_BY_ZERO)
  408.         EXCEPTION(FLT_INEXACT_RESULT)
  409.         EXCEPTION(FLT_INVALID_OPERATION)
  410.         EXCEPTION(FLT_OVERFLOW)
  411.         EXCEPTION(FLT_STACK_CHECK)
  412.         EXCEPTION(FLT_UNDERFLOW)
  413.         EXCEPTION(INT_DIVIDE_BY_ZERO)
  414.         EXCEPTION(INT_OVERFLOW)
  415.         EXCEPTION(PRIV_INSTRUCTION)
  416.         EXCEPTION(IN_PAGE_ERROR)
  417.         EXCEPTION(ILLEGAL_INSTRUCTION)
  418.         EXCEPTION(NONCONTINUABLE_EXCEPTION)
  419.         EXCEPTION(STACK_OVERFLOW)
  420.         EXCEPTION(INVALID_DISPOSITION)
  421.         EXCEPTION(GUARD_PAGE)
  422.         EXCEPTION(INVALID_HANDLE)
  423.     }
  424.  
  425.     // Try to get descripbion of unknown exceptions
  426.     static TCHAR buffer[512] = {0};
  427.  
  428.     FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
  429.                   GetModuleHandle(_T("NTDLL.DLL")),
  430.                   dwCode, 0, buffer, sizeof(buffer), 0);
  431.  
  432.     return buffer;
  433. }
  434.  
  435. void CExceptionReport::StackWalk(CONTEXT Context)
  436. {
  437.     USES_CONVERSION;
  438.     AddToReport("\r\nCall stack:\r\n-----------\r\n\r\n");
  439.     AddToReport("Address   Frame     Function            SourceFile\r\n");
  440.     
  441.     DWORD dwMachineType = 0;
  442.  
  443.     STACKFRAME sf;
  444.     memset(&sf, 0, sizeof(sf));
  445.  
  446. #ifdef _M_IX86
  447.     // Initialize the STACKFRAME structure for the first call.  This is only
  448.     // necessary for Intel CPUs, and isn't mentioned in the documentation.
  449.     sf.AddrPC.Offset    = Context.Eip;
  450.     sf.AddrPC.Mode        = AddrModeFlat;
  451.     sf.AddrStack.Offset    = Context.Esp;
  452.     sf.AddrStack.Mode    = AddrModeFlat;
  453.     sf.AddrFrame.Offset    = Context.Ebp;
  454.     sf.AddrFrame.Mode    = AddrModeFlat;
  455.  
  456.     dwMachineType = IMAGE_FILE_MACHINE_I386;
  457. #endif
  458.  
  459.     while (TRUE)
  460.     {
  461.         // Get next stack frame
  462.         if (!pStackWalk(dwMachineType, GetCurrentProcess(), GetCurrentThread(),
  463.                         &sf, &Context, 0, 
  464.                         pSymFunctionTableAccess, pSymGetModuleBase,    0))
  465.             break;
  466.  
  467.         if (!sf.AddrFrame.Offset)
  468.             break; //Invalid frame
  469.  
  470.         AddToReportHex(sf.AddrPC.Offset, 8);
  471.         AddToReport("  ");
  472.         AddToReportHex(sf.AddrFrame.Offset, 8);
  473.         AddToReport("  ");
  474.         
  475.         // Get function name for stack frame entry
  476.         BYTE symbolBuffer[ sizeof(SYMBOL_INFO) + 1024 ];
  477.         PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
  478.         pSymbol->SizeOfStruct = sizeof(symbolBuffer);
  479.         pSymbol->MaxNameLen = 1024;
  480.                     
  481.         DWORD64 symDisplacement = 0;    // Displacement of the input address,
  482.                                         // relative to the start of the symbol
  483.  
  484.         if (pSymFromAddr(GetCurrentProcess(), sf.AddrPC.Offset, &symDisplacement, pSymbol))
  485.         {
  486.             AddToReport(pSymbol->Name);
  487.             AddToReport("+");
  488.             AddToReportHex(symDisplacement);
  489.         }
  490.         else    // No symbol found.  Print out the logical address instead.
  491.         {
  492.             TCHAR szModule[MAX_PATH] = _T("");
  493.             DWORD section = 0, offset = 0;
  494.  
  495.             GetAddrDetails((PVOID)sf.AddrPC.Offset,
  496.                                 szModule, sizeof(szModule), section, offset);
  497.  
  498.             AddToReportHex(section, 4);
  499.             AddToReport(":");
  500.             AddToReportHex(offset, 8);
  501.             AddToReport(" ");
  502.             AddToReport(szModule);
  503.         }
  504.  
  505.         // Get the source line for this stack frame entry
  506.         IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };
  507.         DWORD dwLineDisplacement;
  508.         if (pSymGetLineFromAddr(GetCurrentProcess(), sf.AddrPC.Offset,
  509.                                 &dwLineDisplacement, &lineInfo))
  510.         {
  511.             AddToReport("  ");
  512.             AddToReport(lineInfo.FileName);
  513.             AddToReport(" line ");
  514.             AddToReport(lineInfo.LineNumber);
  515.         }
  516.  
  517.         AddToReport("\r\n");
  518.     }
  519.  
  520. }
  521.  
  522. bool CExceptionReport::writeMiniDump(PEXCEPTION_POINTERS pExceptionInfo)
  523. {
  524.     // Write the minidump to the file
  525.     MINIDUMP_EXCEPTION_INFORMATION eInfo;
  526.     eInfo.ThreadId = GetCurrentThreadId();
  527.     eInfo.ExceptionPointers = pExceptionInfo;
  528.     eInfo.ClientPointers = FALSE;
  529.  
  530.     MINIDUMP_CALLBACK_INFORMATION cbMiniDump;
  531.     cbMiniDump.CallbackRoutine = 0;
  532.     cbMiniDump.CallbackParam = 0;
  533.  
  534.  
  535.     pMiniDumpWriteDump(
  536.         GetCurrentProcess(),
  537.         GetCurrentProcessId(),
  538.         m_hDumpFile,
  539.         MiniDumpNormal,
  540.         pExceptionInfo ? &eInfo : NULL,
  541.         NULL,
  542.         &cbMiniDump);
  543.  
  544.     // Close file
  545.     CloseHandle(m_hDumpFile);
  546.  
  547.     return true;
  548. }
  549.  
  550. int CExceptionReport::sendMail()
  551. {
  552.     CMailMsg mail;
  553.  
  554.     mail.SetTo(_T("tim.kosse@gmx.de"), _T("Tim Kosse"));
  555.  
  556.     TCHAR str[4096];
  557.     _stprintf(str, _T("Exception report created by %s\r\n\r\n"), (LPCTSTR)GetVersionString());
  558.     mail.SetSubject(str);
  559.  
  560.     mail.SetMessage(_T("Enter your comments here, what did you do with FileZilla Server before it crashed?"));
  561.  
  562.     mail.AddAttachment(m_pLogFileName, _T("FileZillaServer.rpt"));
  563.     mail.AddAttachment(m_pDmpFileName, _T("FileZillaServer.dmp"));
  564.  
  565.     return mail.Send();
  566. }
  567.  
  568. void CExceptionReport::SuspendThreads()
  569. {
  570.     // Try to get OpenThread and Thread32* function from kernel32.dll, since it's not available on Win95/98
  571.     typedef HANDLE (WINAPI *tOpenThread)    (DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
  572.     typedef BOOL (WINAPI *tThread32First)    (HANDLE hSnapshot, LPTHREADENTRY32 lpte);
  573.     typedef BOOL (WINAPI *tThread32Next)    (HANDLE hSnapshot, LPTHREADENTRY32 lpte);
  574.     typedef HANDLE (WINAPI *tCreateToolhelp32Snapshot)    (DWORD dwFlags, DWORD th32ProcessID);
  575.  
  576.     HMODULE hKernel32Dll = LoadLibrary(_T("kernel32.dll"));
  577.     if (!hKernel32Dll)
  578.         return;
  579.     tOpenThread        pOpenThread        = (tOpenThread)        GetProcAddress(hKernel32Dll, "OpenThread");
  580.     tThread32First    pThread32First    = (tThread32First)    GetProcAddress(hKernel32Dll, "Thread32First");
  581.     tThread32Next    pThread32Next    = (tThread32Next)    GetProcAddress(hKernel32Dll, "Thread32Next");
  582.     tCreateToolhelp32Snapshot pCreateToolhelp32Snapshot    = (tCreateToolhelp32Snapshot)    GetProcAddress(hKernel32Dll, "CreateToolhelp32Snapshot");
  583.     if (!pOpenThread    ||
  584.         !pThread32First    ||
  585.         !pThread32Next    ||
  586.         !pCreateToolhelp32Snapshot)
  587.     {
  588.         CloseHandle(hKernel32Dll);
  589.         return;
  590.     }
  591.  
  592.     HANDLE hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
  593.  
  594.     // Get information about own process/thread
  595.     DWORD ownProcessId = GetCurrentProcessId();
  596.     DWORD ownThreadId = GetCurrentThreadId();
  597.  
  598.     // Enumerate threads
  599.     THREADENTRY32 entry;
  600.     entry.dwSize = sizeof(THREADENTRY32);
  601.     BOOL bNext = pThread32First(hSnapshot, &entry);
  602.     while (bNext)
  603.     {
  604.         if (entry.th32OwnerProcessID == ownProcessId &&
  605.             entry.th32ThreadID != ownThreadId)
  606.         {
  607.             // Suspen threads of own process
  608.             HANDLE hThread = pOpenThread(THREAD_SUSPEND_RESUME, FALSE, entry.th32ThreadID);
  609.             if (hThread)
  610.                 SuspendThread(hThread);
  611.         }
  612.         bNext = pThread32Next(hSnapshot, &entry);
  613.     }
  614.     CloseHandle(hKernel32Dll);
  615. }
  616.  
  617. void CExceptionReport::AddToReport(const char * pText)
  618. {
  619.     DWORD bytesWritten = 0;
  620.     WriteFile(m_hReportFile, pText, strlen(pText), &bytesWritten, 0);
  621. }
  622.  
  623. void CExceptionReport::AddToReport(const WCHAR * pText)
  624. {
  625.     USES_CONVERSION;
  626.     AddToReport(W2A(pText));
  627. }
  628.  
  629. void CExceptionReport::AddToReport(int number)
  630. {
  631.     char buffer[sizeof(int) * 4];
  632.     sprintf(buffer, "%d", number);
  633.     AddToReport(buffer);
  634. }
  635.  
  636. void CExceptionReport::AddToReportHex(_int64 number, int minDigits /*=0*/)
  637. {
  638.     char buffer[sizeof(_int64) * 2 + 1];
  639.     if (!minDigits)
  640.         sprintf(buffer, "%I64X", number);
  641.     else
  642.     {
  643.         char fmt[10];
  644.         sprintf(fmt, "%%0%dI64X", minDigits);
  645.         sprintf(buffer, fmt, number);
  646.     }
  647.     AddToReport(buffer);
  648. }
  649.  
  650. BOOL CExceptionReport::GetAddrDetails(PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD& offset)
  651. {
  652.     // Get details about an address: Module name, section and offet
  653.     
  654.     // Get information about the provided address
  655.     MEMORY_BASIC_INFORMATION mbi;
  656.     if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
  657.         return FALSE;
  658.  
  659.     // Get module
  660.     DWORD hMod = (DWORD)mbi.AllocationBase;
  661.     if (!GetModuleFileName((HMODULE)hMod, szModule, len))
  662.         return FALSE;
  663.  
  664.     
  665.     // Get DOS header of module
  666.     PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod;
  667.  
  668.     // Advance to PE header and get the section information
  669.     PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(hMod + pDosHeader->e_lfanew);
  670.     PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeader);
  671.  
  672.     // Get module load address
  673.     DWORD lAddr = (DWORD)addr - hMod; 
  674.  
  675.     // Search for a section which contains the address
  676.     for (unsigned int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
  677.     {
  678.         // Calculate section start and end addresses
  679.         DWORD startAddr = pSection->VirtualAddress;
  680.         DWORD endAddr = startAddr;
  681.         if (pSection->SizeOfRawData > pSection->Misc.VirtualSize)
  682.             endAddr += pSection->SizeOfRawData;
  683.         else
  684.             pSection->Misc.VirtualSize;
  685.  
  686.         // Look if provided address is between startAddr and endAddr
  687.         if (lAddr >= startAddr && lAddr <= endAddr)
  688.         {
  689.             // We've found the section, set section index and offset
  690.             section = i+1;
  691.             offset = lAddr - startAddr;
  692.             return TRUE;
  693.         }
  694.         pSection++;
  695.     }
  696.  
  697.     // Section not found, very strange
  698.     return FALSE;
  699. }