1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "components/crash/app/hard_error_handler_win.h" 6 7 #if defined(_WIN32_WINNT_WIN8) && _MSC_VER < 1700 8 // The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h, and in 9 // delayimp.h previous to VS2012. 10 #undef FACILITY_VISUALCPP 11 #endif 12 #include <DelayIMP.h> 13 #include <winternl.h> 14 15 #include "base/basictypes.h" 16 #include "base/strings/string_util.h" 17 #include "components/crash/app/crash_reporter_client.h" 18 19 namespace breakpad { 20 21 using crash_reporter::GetCrashReporterClient; 22 23 namespace { 24 const DWORD kExceptionModuleNotFound = VcppException(ERROR_SEVERITY_ERROR, 25 ERROR_MOD_NOT_FOUND); 26 const DWORD kExceptionEntryPtNotFound = VcppException(ERROR_SEVERITY_ERROR, 27 ERROR_PROC_NOT_FOUND); 28 // This is defined in <ntstatus.h> but we can't include this file here. 29 const DWORD FACILITY_GRAPHICS_KERNEL = 0x1E; 30 const DWORD NT_STATUS_ENTRYPOINT_NOT_FOUND = 0xC0000139; 31 const DWORD NT_STATUS_DLL_NOT_FOUND = 0xC0000135; 32 33 // We assume that exception codes are NT_STATUS codes. 34 DWORD FacilityFromException(DWORD exception_code) { 35 return (exception_code >> 16) & 0x0FFF; 36 } 37 38 // This is not a generic function. It only works with some |nt_status| values. 39 // Check the strings here http://msdn.microsoft.com/en-us/library/cc704588.aspx 40 // before attempting to use this function. 41 void RaiseHardErrorMsg(long nt_status, const std::string& p1, 42 const std::string& p2) { 43 // If headless just exit silently. 44 if (GetCrashReporterClient()->IsRunningUnattended()) 45 return; 46 47 HMODULE ntdll = ::GetModuleHandleA("NTDLL.DLL"); 48 wchar_t* msg_template = NULL; 49 size_t count = ::FormatMessage( 50 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | 51 FORMAT_MESSAGE_FROM_HMODULE, 52 ntdll, 53 nt_status, 54 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 55 reinterpret_cast<wchar_t*>(&msg_template), 56 0, 57 NULL); 58 59 if (!count) 60 return; 61 count += p1.size() + p2.size() + 1; 62 base::string16 message; 63 ::wsprintf(WriteInto(&message, count), msg_template, p1.c_str(), p2.c_str()); 64 // The MB_SERVICE_NOTIFICATION causes this message to be displayed by 65 // csrss. This means that we are not creating windows or pumping WM messages 66 // in this process. 67 ::MessageBox(NULL, message.c_str(), 68 L"chrome.exe", 69 MB_OK | MB_SERVICE_NOTIFICATION); 70 ::LocalFree(msg_template); 71 } 72 73 void ModuleNotFoundHardError(const EXCEPTION_RECORD* ex_record) { 74 DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>( 75 ex_record->ExceptionInformation[0]); 76 if (!dli->szDll) 77 return; 78 RaiseHardErrorMsg(NT_STATUS_DLL_NOT_FOUND, dli->szDll, std::string()); 79 } 80 81 void EntryPointNotFoundHardError(const EXCEPTION_RECORD* ex_record) { 82 DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>( 83 ex_record->ExceptionInformation[0]); 84 if (!dli->dlp.fImportByName) 85 return; 86 if (!dli->dlp.szProcName) 87 return; 88 if (!dli->szDll) 89 return; 90 RaiseHardErrorMsg(NT_STATUS_ENTRYPOINT_NOT_FOUND, 91 dli->dlp.szProcName, dli->szDll); 92 } 93 94 } // namespace 95 96 bool HardErrorHandler(EXCEPTION_POINTERS* ex_info) { 97 if (!ex_info) 98 return false; 99 if (!ex_info->ExceptionRecord) 100 return false; 101 102 long exception = ex_info->ExceptionRecord->ExceptionCode; 103 if (exception == kExceptionModuleNotFound) { 104 ModuleNotFoundHardError(ex_info->ExceptionRecord); 105 return true; 106 } else if (exception == kExceptionEntryPtNotFound) { 107 EntryPointNotFoundHardError(ex_info->ExceptionRecord); 108 return true; 109 } else if (FacilityFromException(exception) == FACILITY_GRAPHICS_KERNEL) { 110 #if defined(USE_AURA) 111 RaiseHardErrorMsg(exception, std::string(), std::string()); 112 return true; 113 #else 114 return false; 115 #endif 116 } 117 return false; 118 } 119 120 } // namespace breakpad 121