Home | History | Annotate | Download | only in app
      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