18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/crash/app/breakpad_win.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <shellapi.h>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <tchar.h>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <userenv.h>
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <winnt.h>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include <map>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base_switches.h"
188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/basictypes.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/crash_logging.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/debug/dump_without_crashing.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_split.h"
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
29010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/synchronization/lock.h"
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/win/metro.h"
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/win/pe_image.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/registry.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/win_util.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "breakpad/src/client/windows/handler/exception_handler.h"
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/crash/app/crash_keys_win.h"
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/crash/app/crash_reporter_client.h"
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "components/crash/app/hard_error_handler_win.h"
38a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "content/public/common/result_codes.h"
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "sandbox/win/src/nt_internals.h"
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "sandbox/win/src/sidestep/preamble_patcher.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// userenv.dll is required for GetProfileType().
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(lib, "userenv.lib")
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#pragma intrinsic(_AddressOfReturnAddress)
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#pragma intrinsic(_ReturnAddress)
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace breakpad {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing crash_reporter::GetCrashReporterClient;
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Minidump with stacks, PEB, TEB, and unloaded module list.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithProcessThreadData |  // Get PEB and TEB.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithUnloadedModules);  // Get unloaded modules when available.
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Minidump with all of the above, plus memory referenced from stack.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithProcessThreadData |  // Get PEB and TEB.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithUnloadedModules |  // Get unloaded modules when available.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithIndirectlyReferencedMemory);  // Get memory referenced by stack.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Large dump with all process memory.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithFullMemory |  // Full memory from process.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithProcessThreadData |  // Get PEB and TEB.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithHandleData |  // Get all handle information.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MiniDumpWithUnloadedModules);  // Get unloaded modules when available.
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPipeNameVar[] = "CHROME_BREAKPAD_PIPE_NAME";
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This is the well known SID for the system principal.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kSystemPrincipalSid[] =L"S-1-5-18";
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)google_breakpad::ExceptionHandler* g_breakpad = NULL;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL;
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)EXCEPTION_POINTERS g_surrogate_exception_pointers = {0};
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)EXCEPTION_RECORD g_surrogate_exception_record = {0};
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)CONTEXT g_surrogate_context = {0};
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 NTSTATUS ExitStatus);
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)char* g_real_terminate_process_stub = NULL;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace
9246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Dumps the current process memory.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void __declspec(dllexport) __cdecl DumpProcess() {
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (g_breakpad) {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_breakpad->WriteMinidump();
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used for dumping a process state when there is no crash.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_dumphandler_no_crash) {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_dumphandler_no_crash->WriteMinidump();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
10846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We need to prevent ICF from folding DumpForHangDebuggingThread() and
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DumpProcessWithoutCrashThread() together, since that makes them
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// indistinguishable in crash dumps. We do this by making the function
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// bodies unique, and prevent optimization from shuffling things around.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MSVC_DISABLE_OPTIMIZE()
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MSVC_PUSH_DISABLE_WARNING(4748)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORD WINAPI DumpProcessWithoutCrashThread(void*) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DumpProcessWithoutCrash();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The following two functions do exactly the same thing as the two above. But
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we want the signatures to be different so that we can easily track them in
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// crash reports.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(yzshen): Remove when enough information is collected and the hang rate
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of pepper/renderer processes is reduced.
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DWORD WINAPI DumpForHangDebuggingThread(void*) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DumpProcessWithoutCrash();
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  VLOG(1) << "dumped for hang debugging";
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MSVC_POP_WARNING()
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MSVC_ENABLE_OPTIMIZE()
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
13546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace
13646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Injects a thread into a remote process to dump state when there is no crash.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" HANDLE __declspec(dllexport) __cdecl
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InjectDumpProcessWithoutCrash(HANDLE process) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread,
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            0, 0, NULL);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" HANDLE __declspec(dllexport) __cdecl
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InjectDumpForHangDebugging(HANDLE process) {
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            0, 0, NULL);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a string containing a list of all modifiers for the loaded profile.
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::wstring GetProfileType() {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring profile_type;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD profile_bits = 0;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::GetProfileType(&profile_bits)) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const struct {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DWORD bit;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const wchar_t* name;
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } kBitNames[] = {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { PT_MANDATORY, L"mandatory" },
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { PT_ROAMING, L"roaming" },
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      { PT_TEMPORARY, L"temporary" },
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    };
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < arraysize(kBitNames); ++i) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const DWORD this_bit = kBitNames[i].bit;
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((profile_bits & this_bit) != 0) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        profile_type.append(kBitNames[i].name);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        profile_bits &= ~this_bit;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (profile_bits != 0)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          profile_type.append(L", ");
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD last_error = ::GetLastError();
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SStringPrintf(&profile_type, L"error %u", last_error);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return profile_type;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
17946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)namespace {
18046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This callback is used when we want to get a dump without crashing the
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// process.
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 EXCEPTION_POINTERS* ex_info,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 MDRawAssertionInfo*, bool) {
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This callback is executed when the browser process has crashed, after
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the crash dump has been created. We need to minimize the amount of work
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// done here since we have potentially corrupted process. Our job is to
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// spawn another instance of chrome which will show a 'chrome has crashed'
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// dialog. This code needs to live in the exe and thus has no access to
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// facilities such as the i18n helpers.
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      EXCEPTION_POINTERS* ex_info,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      MDRawAssertionInfo*, bool) {
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Check if the exception is one of the kind which would not be solved
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // by simply restarting chrome. In this case we show a message box with
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // and exit silently. Remember that chrome is in a crashed state so we
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // can't show our own UI from this process.
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (HardErrorHandler(ex_info))
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!GetCrashReporterClient()->AboutToRestart())
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now we just start chrome browser with the same command line.
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STARTUPINFOW si = {sizeof(si)};
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PROCESS_INFORMATION pi;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::CreateProcessW(NULL, ::GetCommandLineW(), NULL, NULL, FALSE,
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) {
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::CloseHandle(pi.hProcess);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::CloseHandle(pi.hThread);
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // After this return we will be terminated. The actual return value is
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // not used at all.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// flag to indicate that we are already handling an exception.
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)volatile LONG handling_exception = 0;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This callback is used when there is no crash. Note: Unlike the
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |FilterCallback| below this does not do dupe detection. It is upto the caller
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to implement it.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FilterCallbackWhenNoCrash(
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetCrashReporterClient()->RecordCrashDumpAttempt(false);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This callback is executed when the Chrome process has crashed and *before*
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the crash dump is created. To prevent duplicate crash reports we
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// make every thread calling this method, except the very first one,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// go to sleep.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool FilterCallback(void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Capture every thread except the first one in the sleep. We don't
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // want multiple threads to concurrently report exceptions.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (::InterlockedCompareExchange(&handling_exception, 1, 0) == 1) {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::Sleep(INFINITE);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetCrashReporterClient()->RecordCrashDumpAttempt(true);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Previous unhandled filter. Will be called if not null when we
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// intercept a crash.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LPTOP_LEVEL_EXCEPTION_FILTER previous_filter = NULL;
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Exception filter used when breakpad is not enabled. We just display
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the "Do you want to restart" message and then we call the previous filter.
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) {
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (previous_filter)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return previous_filter(info);
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EXCEPTION_EXECUTE_HANDLER;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Exception filter for the service process used when breakpad is not enabled.
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We just display the "Do you want to restart" message and then die
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (without calling the previous filter).
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) {
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EXCEPTION_EXECUTE_HANDLER;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}  // namespace
2711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
27246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// NOTE: This function is used by SyzyASAN to annotate crash reports. If you
27346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// change the name or signature of this function you will break SyzyASAN
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// instrumented releases of Chrome. Please contact syzygy-team@chromium.org
27546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// before doing so!
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(
27746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const wchar_t* key, const wchar_t* value) {
27846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  CrashKeysWin* keeper = CrashKeysWin::keeper();
27946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!keeper)
2801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
2811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(siggi): This doesn't look quite right - there's NULL deref potential
28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  //    here, and an implicit std::wstring conversion. Fixme.
28446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  keeper->SetCrashKeyValue(key, value);
28546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
28646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
28746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(
28846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const wchar_t* key) {
28946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  CrashKeysWin* keeper = CrashKeysWin::keeper();
29046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!keeper)
29146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
29246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
29346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // TODO(siggi): This doesn't look quite right - there's NULL deref potential
29446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  //    here, and an implicit std::wstring conversion. Fixme.
29546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  keeper->ClearCrashKeyValue(key);
29646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
298010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
299010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                  UINT flags, bool* exit_now) {
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We wrap the call to MessageBoxW with a SEH handler because it some
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // machines with CursorXP, PeaDict or with FontExplorer installed it crashes
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // uncontrollably here. Being this a best effort deal we better go away.
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  __try {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags));
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } __except(EXCEPTION_EXECUTE_HANDLER) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Its not safe to continue executing, exit silently here.
3078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    ::TerminateProcess(::GetCurrentProcess(),
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                       GetCrashReporterClient()->GetResultCodeRespawnFailed());
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function is executed by the child process that DumpDoneCallback()
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// spawned and basically just shows the 'chrome has crashed' dialog if
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the CHROME_CRASHED environment variable is present.
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ShowRestartDialogIfCrashed(bool* exit_now) {
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // If we are being launched in metro mode don't try to show the dialog.
319868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (base::win::IsMetroProcess())
320868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return false;
321868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
322ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::string16 message;
323ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  base::string16 title;
324ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  bool is_rtl_locale;
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!GetCrashReporterClient()->ShouldShowRestartDialog(
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          &title, &message, &is_rtl_locale)) {
327ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    return false;
328ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  }
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // flags so that an RTL message box is displayed.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UINT flags = MB_OKCANCEL | MB_ICONWARNING;
333ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (is_rtl_locale)
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    flags |= MB_RIGHT | MB_RTLREADING;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
33646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  return WrapMessageBoxWithSEH(message.c_str(), title.c_str(), flags, exit_now);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Crashes the process after generating a dump for the provided exception. Note
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// that the crash reporter should be initialized before calling this function
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for it to do anything.
3423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// NOTE: This function is used by SyzyASAN to invoke a crash. If you change the
3433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// the name or signature of this function you will break SyzyASAN instrumented
3443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)// releases of Chrome. Please contact syzygy-team@chromium.org before doing so!
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" int __declspec(dllexport) CrashForException(
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EXCEPTION_POINTERS* info) {
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_breakpad) {
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_breakpad->WriteMinidumpForException(info);
349868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Patched stub exists based on conditions (See InitCrashReporter).
350868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // As a side note this function also gets called from
351868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // WindowProcExceptionFilter.
352868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (g_real_terminate_process_stub == NULL) {
353868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      ::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    } else {
355868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      NtTerminateProcessPtr real_terminate_proc =
356868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          reinterpret_cast<NtTerminateProcessPtr>(
357868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              static_cast<char*>(g_real_terminate_process_stub));
358868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
359868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return EXCEPTION_CONTINUE_SEARCH;
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
364010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)static NTSTATUS WINAPI HookNtTerminateProcess(HANDLE ProcessHandle,
365010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                              NTSTATUS ExitStatus) {
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (g_breakpad &&
367c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (ProcessHandle == ::GetCurrentProcess() || ProcessHandle == NULL)) {
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    NT_TIB* tib = reinterpret_cast<NT_TIB*>(NtCurrentTeb());
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    void* address_on_stack = _AddressOfReturnAddress();
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (address_on_stack < tib->StackLimit ||
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        address_on_stack > tib->StackBase) {
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      g_surrogate_exception_record.ExceptionAddress = _ReturnAddress();
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      g_surrogate_exception_record.ExceptionCode = DBG_TERMINATE_PROCESS;
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      g_surrogate_exception_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CrashForException(&g_surrogate_exception_pointers);
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
378c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
379c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  NtTerminateProcessPtr real_proc =
380c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      reinterpret_cast<NtTerminateProcessPtr>(
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          static_cast<char*>(g_real_terminate_process_stub));
382c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return real_proc(ProcessHandle, ExitStatus);
383c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
384c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
385c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)static void InitTerminateProcessHooks() {
386c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  NtTerminateProcessPtr terminate_process_func_address =
387c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      reinterpret_cast<NtTerminateProcessPtr>(::GetProcAddress(
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          ::GetModuleHandle(L"ntdll.dll"), "NtTerminateProcess"));
389c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (terminate_process_func_address == NULL)
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
391c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
392c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DWORD old_protect = 0;
393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!::VirtualProtect(terminate_process_func_address, 5,
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        PAGE_EXECUTE_READWRITE, &old_protect))
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
396c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
397c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  g_real_terminate_process_stub = reinterpret_cast<char*>(VirtualAllocEx(
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      ::GetCurrentProcess(), NULL, sidestep::kMaxPreambleStubSize,
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      MEM_COMMIT, PAGE_EXECUTE_READWRITE));
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (g_real_terminate_process_stub == NULL)
401c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
402c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
403c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  g_surrogate_exception_pointers.ContextRecord = &g_surrogate_context;
404c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  g_surrogate_exception_pointers.ExceptionRecord =
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      &g_surrogate_exception_record;
406c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
407c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  sidestep::SideStepError patch_result =
408c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      sidestep::PreamblePatcher::Patch(
409c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          terminate_process_func_address, HookNtTerminateProcess,
410c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          g_real_terminate_process_stub, sidestep::kMaxPreambleStubSize);
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (patch_result != sidestep::SIDESTEP_SUCCESS) {
412c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CHECK(::VirtualFreeEx(::GetCurrentProcess(), g_real_terminate_process_stub,
413c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    0, MEM_RELEASE));
414c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    CHECK(::VirtualProtect(terminate_process_func_address, 5, old_protect,
415c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           &old_protect));
416c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return;
417c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DWORD dummy = 0;
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(::VirtualProtect(terminate_process_func_address,
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         5,
422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         old_protect,
423c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         &dummy));
424c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(::VirtualProtect(g_real_terminate_process_stub,
425c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         sidestep::kMaxPreambleStubSize,
426c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         old_protect,
427c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                         &old_protect));
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
429c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void InitPipeNameEnvVar(bool is_per_user_install) {
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Environment> env(base::Environment::Create());
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (env->HasVar(kPipeNameVar)) {
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The Breakpad pipe name is already configured: nothing to do.
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Check whether configuration management controls crash reporting.
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool crash_reporting_enabled = true;
4391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool controlled_by_policy =
4401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GetCrashReporterClient()->ReportingIsEnforcedByPolicy(
4411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          &crash_reporting_enabled);
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& command = *CommandLine::ForCurrentProcess();
4441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool use_crash_service = !controlled_by_policy &&
4451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           (command.HasSwitch(switches::kNoErrorDialogs) ||
4461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            GetCrashReporterClient()->IsRunningUnattended());
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::wstring pipe_name;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (use_crash_service) {
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Crash reporting is done by crash_service.exe.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pipe_name = kChromePipeName;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We want to use the Google Update crash reporting. We need to check if the
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // user allows it first (in case the administrator didn't already decide
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // via policy).
4568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    if (!controlled_by_policy)
4571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      crash_reporting_enabled =
4581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GetCrashReporterClient()->GetCollectStatsConsent();
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!crash_reporting_enabled) {
461cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // Crash reporting is disabled, don't set the environment variable.
462cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return;
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Build the pipe name. It can be either:
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18"
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>"
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::wstring user_sid;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (is_per_user_install) {
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!base::win::GetUserSidString(&user_sid)) {
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_sid = kSystemPrincipalSid;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pipe_name = kGoogleUpdatePipeName;
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pipe_name += user_sid;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
480a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  env->SetVar(kPipeNameVar, base::UTF16ToASCII(pipe_name));
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
4848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  previous_filter = SetUnhandledExceptionFilter(filter);
4858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}
4868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void InitCrashReporter(const std::string& process_type_switch) {
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const CommandLine& command = *CommandLine::ForCurrentProcess();
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (command.HasSwitch(switches::kDisableBreakpad))
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Disable the message box for assertions.
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  _CrtSetReportMode(_CRT_ASSERT, 0);
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::wstring process_type = base::ASCIIToWide(process_type_switch);
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_type.empty())
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    process_type = L"browser";
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t exe_path[MAX_PATH];
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  exe_path[0] = 0;
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetModuleFileNameW(NULL, exe_path, MAX_PATH);
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  bool is_per_user_install =
5041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GetCrashReporterClient()->GetIsPerUserInstall(base::FilePath(exe_path));
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
50646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // This is intentionally leaked.
50746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  CrashKeysWin* keeper = new CrashKeysWin();
50846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  google_breakpad::CustomClientInfo* custom_info =
510f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      keeper->GetCustomInfo(exe_path, process_type,
511f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                            GetProfileType(), CommandLine::ForCurrentProcess(),
5121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            GetCrashReporterClient());
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL;
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We install the post-dump callback only for the browser and service
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // processes. It spawns a new browser/service process.
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_type == L"browser") {
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback = &DumpDoneCallback;
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_filter = &ChromeExceptionFilter;
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (process_type == L"service") {
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback = &DumpDoneCallback;
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default_filter = &ServiceExceptionFilter;
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (process_type == L"browser") {
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    InitPipeNameEnvVar(is_per_user_install);
5281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    GetCrashReporterClient()->InitBrowserCrashDumpsRegKey();
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<base::Environment> env(base::Environment::Create());
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string pipe_name_ascii;
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!env->GetVar(kPipeNameVar, &pipe_name_ascii)) {
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Breakpad is not enabled.  Configuration is managed or the user
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // did not allow Google Update to send crashes.  We need to use
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // our default crash handler instead, but only for the
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // browser/service processes.
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (default_filter)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      InitDefaultCrashCallback(default_filter);
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::wstring pipe_name = base::ASCIIToWide(pipe_name_ascii);
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef _WIN64
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The protocol for connecting to the out-of-process Breakpad crash
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // reporter is different for x86-32 and x86-64: the message sizes
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are different because the message struct contains a pointer.  As
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a result, there are two different named pipes to connect to.  The
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // 64-bit one is distinguished with an "-x64" suffix.
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pipe_name += L"-x64";
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the alternate dump directory. We use the temp path.
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wchar_t temp_dir[MAX_PATH] = {0};
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ::GetTempPathW(MAX_PATH, temp_dir);
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MINIDUMP_TYPE dump_type = kSmallDumpType;
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Capture full memory if explicitly instructed to.
559a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  if (command.HasSwitch(switches::kFullMemoryCrashReport))
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dump_type = kFullDumpType;
5611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  else if (GetCrashReporterClient()->GetShouldDumpLargerDumps(
5621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               is_per_user_install))
563a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    dump_type = kLargerDumpType;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_breakpad = new google_breakpad::ExceptionHandler(temp_dir, &FilterCallback,
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   callback, NULL,
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   google_breakpad::ExceptionHandler::HANDLER_ALL,
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   dump_type, pipe_name.c_str(), custom_info);
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now initialize the non crash dump handler.
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_dumphandler_no_crash = new google_breakpad::ExceptionHandler(temp_dir,
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &FilterCallbackWhenNoCrash,
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &DumpDoneCallbackWhenNoCrash,
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL,
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // Set the handler to none so this handler would not be added to
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // |handler_stack_| in |ExceptionHandler| which is a list of exception
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // handlers.
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      google_breakpad::ExceptionHandler::HANDLER_NONE,
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      dump_type, pipe_name.c_str(), custom_info);
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Set the DumpWithoutCrashingFunction for this instance of base.lib.  Other
5825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // executable images linked with base should set this again for
5835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // DumpWithoutCrashing to function correctly.
5845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // See chrome_main.cc for example.
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::debug::SetDumpWithoutCrashingFunction(&DumpProcessWithoutCrash);
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (g_breakpad->IsOutOfProcess()) {
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Tells breakpad to handle breakpoint and single step exceptions.
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This might break JIT debuggers, but at least it will always
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // generate a crashdump for these exceptions.
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_breakpad->set_handle_debug_exceptions(true);
592c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
593c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#ifndef _WIN64
594ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    if (process_type != L"browser" &&
5951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        !GetCrashReporterClient()->IsRunningUnattended()) {
596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      // Initialize the hook TerminateProcess to catch unexpected exits.
597c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      InitTerminateProcessHooks();
598c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
599c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#endif
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// If the user has disabled crash reporting uploads and restarted Chrome, the
6045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// restarted instance will still contain the pipe environment variable, which
6055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// will allow the restarted process to still upload crash reports. This function
6065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// clears the environment variable, so that the restarted Chrome, which inherits
6075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// its environment from the current Chrome, will no longer contain the variable.
6085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)extern "C" void __declspec(dllexport) __cdecl
6095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ClearBreakpadPipeEnvironmentVariable() {
6105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<base::Environment> env(base::Environment::Create());
6115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  env->UnSetVar(kPipeNameVar);
6125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
6135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
6148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)}  // namespace breakpad
615