|
| 1 | +// Copyright (c) 2009 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 "chrome/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/breakpad/breakpad_client.h" |
| 18 | + |
| 19 | +namespace { |
| 20 | +const DWORD kExceptionModuleNotFound = VcppException(ERROR_SEVERITY_ERROR, |
| 21 | + ERROR_MOD_NOT_FOUND); |
| 22 | +const DWORD kExceptionEntryPtNotFound = VcppException(ERROR_SEVERITY_ERROR, |
| 23 | + ERROR_PROC_NOT_FOUND); |
| 24 | +// This is defined in <ntstatus.h> but we can't include this file here. |
| 25 | +const DWORD FACILITY_GRAPHICS_KERNEL = 0x1E; |
| 26 | +const DWORD NT_STATUS_ENTRYPOINT_NOT_FOUND = 0xC0000139; |
| 27 | +const DWORD NT_STATUS_DLL_NOT_FOUND = 0xC0000135; |
| 28 | + |
| 29 | +// We assume that exception codes are NT_STATUS codes. |
| 30 | +DWORD FacilityFromException(DWORD exception_code) { |
| 31 | + return (exception_code >> 16) & 0x0FFF; |
| 32 | +} |
| 33 | + |
| 34 | +// This is not a generic function. It only works with some |nt_status| values. |
| 35 | +// Check the strings here http://msdn.microsoft.com/en-us/library/cc704588.aspx |
| 36 | +// before attempting to use this function. |
| 37 | +void RaiseHardErrorMsg(long nt_status, const std::string& p1, |
| 38 | + const std::string& p2) { |
| 39 | + // If headless just exit silently. |
| 40 | + if (breakpad::GetBreakpadClient()->IsRunningUnattended()) |
| 41 | + return; |
| 42 | + |
| 43 | + HMODULE ntdll = ::GetModuleHandleA("NTDLL.DLL"); |
| 44 | + wchar_t* msg_template = NULL; |
| 45 | + size_t count = ::FormatMessage( |
| 46 | + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | |
| 47 | + FORMAT_MESSAGE_FROM_HMODULE, |
| 48 | + ntdll, |
| 49 | + nt_status, |
| 50 | + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), |
| 51 | + reinterpret_cast<wchar_t*>(&msg_template), |
| 52 | + 0, |
| 53 | + NULL); |
| 54 | + |
| 55 | + if (!count) |
| 56 | + return; |
| 57 | + count += p1.size() + p2.size() + 1; |
| 58 | + string16 message; |
| 59 | + ::wsprintf(WriteInto(&message, count), msg_template, p1.c_str(), p2.c_str()); |
| 60 | + // The MB_SERVICE_NOTIFICATION causes this message to be displayed by |
| 61 | + // csrss. This means that we are not creating windows or pumping WM messages |
| 62 | + // in this process. |
| 63 | + ::MessageBox(NULL, message.c_str(), |
| 64 | + L"chrome.exe", |
| 65 | + MB_OK | MB_SERVICE_NOTIFICATION); |
| 66 | + ::LocalFree(msg_template); |
| 67 | +} |
| 68 | + |
| 69 | +void ModuleNotFoundHardError(const EXCEPTION_RECORD* ex_record) { |
| 70 | + DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>( |
| 71 | + ex_record->ExceptionInformation[0]); |
| 72 | + if (!dli->szDll) |
| 73 | + return; |
| 74 | + RaiseHardErrorMsg(NT_STATUS_DLL_NOT_FOUND, dli->szDll, std::string()); |
| 75 | +} |
| 76 | + |
| 77 | +void EntryPointNotFoundHardError(const EXCEPTION_RECORD* ex_record) { |
| 78 | + DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>( |
| 79 | + ex_record->ExceptionInformation[0]); |
| 80 | + if (!dli->dlp.fImportByName) |
| 81 | + return; |
| 82 | + if (!dli->dlp.szProcName) |
| 83 | + return; |
| 84 | + if (!dli->szDll) |
| 85 | + return; |
| 86 | + RaiseHardErrorMsg(NT_STATUS_ENTRYPOINT_NOT_FOUND, |
| 87 | + dli->dlp.szProcName, dli->szDll); |
| 88 | +} |
| 89 | + |
| 90 | +} // namespace |
| 91 | + |
| 92 | +bool HardErrorHandler(EXCEPTION_POINTERS* ex_info) { |
| 93 | + if (!ex_info) |
| 94 | + return false; |
| 95 | + if (!ex_info->ExceptionRecord) |
| 96 | + return false; |
| 97 | + |
| 98 | + long exception = ex_info->ExceptionRecord->ExceptionCode; |
| 99 | + if (exception == kExceptionModuleNotFound) { |
| 100 | + ModuleNotFoundHardError(ex_info->ExceptionRecord); |
| 101 | + return true; |
| 102 | + } else if (exception == kExceptionEntryPtNotFound) { |
| 103 | + EntryPointNotFoundHardError(ex_info->ExceptionRecord); |
| 104 | + return true; |
| 105 | + } else if (FacilityFromException(exception) == FACILITY_GRAPHICS_KERNEL) { |
| 106 | +#if defined(USE_AURA) |
| 107 | + RaiseHardErrorMsg(exception, std::string(), std::string()); |
| 108 | + return true; |
| 109 | +#else |
| 110 | + return false; |
| 111 | +#endif |
| 112 | + } |
| 113 | + return false; |
| 114 | +} |
0 commit comments