源代码地址
http://www.koders.com/cpp/fid0D70CAB44456E71247468C98A1D01A2F758153FE.aspx?s=md5
.h
1 // FileZilla - a Windows ftp client 2 3 // Copyright (C) 2004 - Tim Kosse <[email protected]> 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 #pragma once 23 24 class CExceptionReport 25 { 26 public: 27 CExceptionReport(); 28 ~CExceptionReport(); 29 30 static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo); 31 32 private: 33 static void CreateReport(PEXCEPTION_POINTERS pExceptionInfo); 34 35 static void StackWalk(CONTEXT Context); 36 static BOOL GetAddrDetails(PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD& offset); 37 static bool writeMiniDump(PEXCEPTION_POINTERS pExceptionInfo); 38 static LPTSTR GetExceptionString(DWORD dwCode); 39 40 static int sendMail(); 41 static void SuspendThreads(); 42 43 static void AddToReport(const WCHAR * pText); 44 static void AddToReport(const char * pText); 45 static void AddToReport(int number); 46 static void AddToReportHex(_int64 number, int minDigits = 0); 47 48 static LPTOP_LEVEL_EXCEPTION_FILTER m_previousExceptionFilter; 49 static TCHAR m_pLogFileName[MAX_PATH]; 50 static HANDLE m_hReportFile; 51 static TCHAR m_pDmpFileName[MAX_PATH]; 52 static HANDLE m_hDumpFile; 53 54 static BOOL m_bFirstRun; 55 }; 56 57 58 extern CExceptionReport ExceptionReport; //global instance of class
http://www.koders.com/cpp/fidFDBB1BB2C131F08BC93D5A3E6C9F8C772340A919.aspx?s=md5
CPP
1 // FileZilla - a Windows ftp client 2 3 // Copyright (C) 2004 - Tim Kosse <[email protected]> 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: [email protected]\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 [email protected] 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("[email protected]"), _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 }