summaryrefslogtreecommitdiffstats
path: root/chrome/app/hard_error_handler_win.cc
blob: 92c168a8f28a9d083678dca6b34bae95592658dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/app/hard_error_handler_win.h"

#if defined(_WIN32_WINNT_WIN8) && _MSC_VER < 1700
// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h, and in
// delayimp.h previous to VS2012.
#undef FACILITY_VISUALCPP
#endif
#include <DelayIMP.h>
#include <winternl.h>

#include "base/basictypes.h"
#include "base/strings/string_util.h"
#include "components/breakpad/breakpad_client.h"

namespace {
const DWORD kExceptionModuleNotFound = VcppException(ERROR_SEVERITY_ERROR,
                                                     ERROR_MOD_NOT_FOUND);
const DWORD kExceptionEntryPtNotFound = VcppException(ERROR_SEVERITY_ERROR,
                                                      ERROR_PROC_NOT_FOUND);
// This is defined in <ntstatus.h> but we can't include this file here.
const DWORD FACILITY_GRAPHICS_KERNEL = 0x1E;
const DWORD NT_STATUS_ENTRYPOINT_NOT_FOUND = 0xC0000139;
const DWORD NT_STATUS_DLL_NOT_FOUND = 0xC0000135;

// We assume that exception codes are NT_STATUS codes.
DWORD FacilityFromException(DWORD exception_code) {
  return (exception_code >> 16) & 0x0FFF;
}

// This is not a generic function. It only works with some |nt_status| values.
// Check the strings here http://msdn.microsoft.com/en-us/library/cc704588.aspx
// before attempting to use this function.
void RaiseHardErrorMsg(long nt_status, const std::string& p1,
                                       const std::string& p2) {
  // If headless just exit silently.
  if (breakpad::GetBreakpadClient()->IsRunningUnattended())
    return;

  HMODULE ntdll = ::GetModuleHandleA("NTDLL.DLL");
  wchar_t* msg_template = NULL;
  size_t count = ::FormatMessage(
      FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS |
      FORMAT_MESSAGE_FROM_HMODULE,
      ntdll,
      nt_status,
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
      reinterpret_cast<wchar_t*>(&msg_template),
      0,
      NULL);

  if (!count)
    return;
  count += p1.size() + p2.size() + 1;
  string16 message;
  ::wsprintf(WriteInto(&message, count), msg_template, p1.c_str(), p2.c_str());
  // The MB_SERVICE_NOTIFICATION causes this message to be displayed by
  // csrss. This means that we are not creating windows or pumping WM messages
  // in this process.
  ::MessageBox(NULL, message.c_str(),
               L"chrome.exe",
               MB_OK | MB_SERVICE_NOTIFICATION);
  ::LocalFree(msg_template);
}

void ModuleNotFoundHardError(const EXCEPTION_RECORD* ex_record) {
  DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>(
      ex_record->ExceptionInformation[0]);
  if (!dli->szDll)
    return;
  RaiseHardErrorMsg(NT_STATUS_DLL_NOT_FOUND, dli->szDll, std::string());
}

void EntryPointNotFoundHardError(const EXCEPTION_RECORD* ex_record) {
  DelayLoadInfo* dli = reinterpret_cast<DelayLoadInfo*>(
      ex_record->ExceptionInformation[0]);
  if (!dli->dlp.fImportByName)
    return;
  if (!dli->dlp.szProcName)
    return;
  if (!dli->szDll)
    return;
  RaiseHardErrorMsg(NT_STATUS_ENTRYPOINT_NOT_FOUND,
      dli->dlp.szProcName, dli->szDll);
}

}  // namespace

bool HardErrorHandler(EXCEPTION_POINTERS* ex_info) {
  if (!ex_info)
    return false;
  if (!ex_info->ExceptionRecord)
    return false;

  long exception = ex_info->ExceptionRecord->ExceptionCode;
  if (exception == kExceptionModuleNotFound) {
    ModuleNotFoundHardError(ex_info->ExceptionRecord);
    return true;
  } else if (exception == kExceptionEntryPtNotFound) {
    EntryPointNotFoundHardError(ex_info->ExceptionRecord);
    return true;
  } else if (FacilityFromException(exception) == FACILITY_GRAPHICS_KERNEL) {
#if defined(USE_AURA)
    RaiseHardErrorMsg(exception, std::string(), std::string());
    return true;
#else
    return false;
#endif
  }
  return false;
}