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