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/breakpad_win.h"
      6 
      7 #include <windows.h>
      8 #include <shellapi.h>
      9 #include <tchar.h>
     10 #include <userenv.h>
     11 #include <winnt.h>
     12 
     13 #include <algorithm>
     14 #include <map>
     15 #include <vector>
     16 
     17 #include "base/base_switches.h"
     18 #include "base/basictypes.h"
     19 #include "base/command_line.h"
     20 #include "base/debug/crash_logging.h"
     21 #include "base/debug/dump_without_crashing.h"
     22 #include "base/environment.h"
     23 #include "base/memory/scoped_ptr.h"
     24 #include "base/strings/string16.h"
     25 #include "base/strings/string_split.h"
     26 #include "base/strings/string_util.h"
     27 #include "base/strings/stringprintf.h"
     28 #include "base/strings/utf_string_conversions.h"
     29 #include "base/synchronization/lock.h"
     30 #include "base/win/metro.h"
     31 #include "base/win/pe_image.h"
     32 #include "base/win/registry.h"
     33 #include "base/win/win_util.h"
     34 #include "breakpad/src/client/windows/handler/exception_handler.h"
     35 #include "components/crash/app/crash_keys_win.h"
     36 #include "components/crash/app/crash_reporter_client.h"
     37 #include "components/crash/app/hard_error_handler_win.h"
     38 #include "content/public/common/result_codes.h"
     39 #include "sandbox/win/src/nt_internals.h"
     40 #include "sandbox/win/src/sidestep/preamble_patcher.h"
     41 
     42 // userenv.dll is required for GetProfileType().
     43 #pragma comment(lib, "userenv.lib")
     44 
     45 #pragma intrinsic(_AddressOfReturnAddress)
     46 #pragma intrinsic(_ReturnAddress)
     47 
     48 namespace breakpad {
     49 
     50 using crash_reporter::GetCrashReporterClient;
     51 
     52 namespace {
     53 
     54 // Minidump with stacks, PEB, TEB, and unloaded module list.
     55 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>(
     56     MiniDumpWithProcessThreadData |  // Get PEB and TEB.
     57     MiniDumpWithUnloadedModules);  // Get unloaded modules when available.
     58 
     59 // Minidump with all of the above, plus memory referenced from stack.
     60 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>(
     61     MiniDumpWithProcessThreadData |  // Get PEB and TEB.
     62     MiniDumpWithUnloadedModules |  // Get unloaded modules when available.
     63     MiniDumpWithIndirectlyReferencedMemory);  // Get memory referenced by stack.
     64 
     65 // Large dump with all process memory.
     66 const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>(
     67     MiniDumpWithFullMemory |  // Full memory from process.
     68     MiniDumpWithProcessThreadData |  // Get PEB and TEB.
     69     MiniDumpWithHandleData |  // Get all handle information.
     70     MiniDumpWithUnloadedModules);  // Get unloaded modules when available.
     71 
     72 const char kPipeNameVar[] = "CHROME_BREAKPAD_PIPE_NAME";
     73 
     74 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\";
     75 const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
     76 
     77 // This is the well known SID for the system principal.
     78 const wchar_t kSystemPrincipalSid[] =L"S-1-5-18";
     79 
     80 google_breakpad::ExceptionHandler* g_breakpad = NULL;
     81 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL;
     82 
     83 EXCEPTION_POINTERS g_surrogate_exception_pointers = {0};
     84 EXCEPTION_RECORD g_surrogate_exception_record = {0};
     85 CONTEXT g_surrogate_context = {0};
     86 
     87 typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
     88                                                  NTSTATUS ExitStatus);
     89 char* g_real_terminate_process_stub = NULL;
     90 
     91 }  // namespace
     92 
     93 // Dumps the current process memory.
     94 extern "C" void __declspec(dllexport) __cdecl DumpProcess() {
     95   if (g_breakpad) {
     96     g_breakpad->WriteMinidump();
     97   }
     98 }
     99 
    100 // Used for dumping a process state when there is no crash.
    101 extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() {
    102   if (g_dumphandler_no_crash) {
    103     g_dumphandler_no_crash->WriteMinidump();
    104   }
    105 }
    106 
    107 namespace {
    108 
    109 // We need to prevent ICF from folding DumpForHangDebuggingThread() and
    110 // DumpProcessWithoutCrashThread() together, since that makes them
    111 // indistinguishable in crash dumps. We do this by making the function
    112 // bodies unique, and prevent optimization from shuffling things around.
    113 MSVC_DISABLE_OPTIMIZE()
    114 MSVC_PUSH_DISABLE_WARNING(4748)
    115 
    116 DWORD WINAPI DumpProcessWithoutCrashThread(void*) {
    117   DumpProcessWithoutCrash();
    118   return 0;
    119 }
    120 
    121 // The following two functions do exactly the same thing as the two above. But
    122 // we want the signatures to be different so that we can easily track them in
    123 // crash reports.
    124 // TODO(yzshen): Remove when enough information is collected and the hang rate
    125 // of pepper/renderer processes is reduced.
    126 DWORD WINAPI DumpForHangDebuggingThread(void*) {
    127   DumpProcessWithoutCrash();
    128   VLOG(1) << "dumped for hang debugging";
    129   return 0;
    130 }
    131 
    132 MSVC_POP_WARNING()
    133 MSVC_ENABLE_OPTIMIZE()
    134 
    135 }  // namespace
    136 
    137 // Injects a thread into a remote process to dump state when there is no crash.
    138 extern "C" HANDLE __declspec(dllexport) __cdecl
    139 InjectDumpProcessWithoutCrash(HANDLE process) {
    140   return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread,
    141                             0, 0, NULL);
    142 }
    143 
    144 extern "C" HANDLE __declspec(dllexport) __cdecl
    145 InjectDumpForHangDebugging(HANDLE process) {
    146   return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread,
    147                             0, 0, NULL);
    148 }
    149 
    150 // Returns a string containing a list of all modifiers for the loaded profile.
    151 std::wstring GetProfileType() {
    152   std::wstring profile_type;
    153   DWORD profile_bits = 0;
    154   if (::GetProfileType(&profile_bits)) {
    155     static const struct {
    156       DWORD bit;
    157       const wchar_t* name;
    158     } kBitNames[] = {
    159       { PT_MANDATORY, L"mandatory" },
    160       { PT_ROAMING, L"roaming" },
    161       { PT_TEMPORARY, L"temporary" },
    162     };
    163     for (size_t i = 0; i < arraysize(kBitNames); ++i) {
    164       const DWORD this_bit = kBitNames[i].bit;
    165       if ((profile_bits & this_bit) != 0) {
    166         profile_type.append(kBitNames[i].name);
    167         profile_bits &= ~this_bit;
    168         if (profile_bits != 0)
    169           profile_type.append(L", ");
    170       }
    171     }
    172   } else {
    173     DWORD last_error = ::GetLastError();
    174     base::SStringPrintf(&profile_type, L"error %u", last_error);
    175   }
    176   return profile_type;
    177 }
    178 
    179 namespace {
    180 
    181 // This callback is used when we want to get a dump without crashing the
    182 // process.
    183 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*,
    184                                  EXCEPTION_POINTERS* ex_info,
    185                                  MDRawAssertionInfo*, bool) {
    186   return true;
    187 }
    188 
    189 // This callback is executed when the browser process has crashed, after
    190 // the crash dump has been created. We need to minimize the amount of work
    191 // done here since we have potentially corrupted process. Our job is to
    192 // spawn another instance of chrome which will show a 'chrome has crashed'
    193 // dialog. This code needs to live in the exe and thus has no access to
    194 // facilities such as the i18n helpers.
    195 bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*,
    196                       EXCEPTION_POINTERS* ex_info,
    197                       MDRawAssertionInfo*, bool) {
    198   // Check if the exception is one of the kind which would not be solved
    199   // by simply restarting chrome. In this case we show a message box with
    200   // and exit silently. Remember that chrome is in a crashed state so we
    201   // can't show our own UI from this process.
    202   if (HardErrorHandler(ex_info))
    203     return true;
    204 
    205   if (!GetCrashReporterClient()->AboutToRestart())
    206     return true;
    207 
    208   // Now we just start chrome browser with the same command line.
    209   STARTUPINFOW si = {sizeof(si)};
    210   PROCESS_INFORMATION pi;
    211   if (::CreateProcessW(NULL, ::GetCommandLineW(), NULL, NULL, FALSE,
    212                        CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) {
    213     ::CloseHandle(pi.hProcess);
    214     ::CloseHandle(pi.hThread);
    215   }
    216   // After this return we will be terminated. The actual return value is
    217   // not used at all.
    218   return true;
    219 }
    220 
    221 // flag to indicate that we are already handling an exception.
    222 volatile LONG handling_exception = 0;
    223 
    224 // This callback is used when there is no crash. Note: Unlike the
    225 // |FilterCallback| below this does not do dupe detection. It is upto the caller
    226 // to implement it.
    227 bool FilterCallbackWhenNoCrash(
    228     void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
    229   GetCrashReporterClient()->RecordCrashDumpAttempt(false);
    230   return true;
    231 }
    232 
    233 // This callback is executed when the Chrome process has crashed and *before*
    234 // the crash dump is created. To prevent duplicate crash reports we
    235 // make every thread calling this method, except the very first one,
    236 // go to sleep.
    237 bool FilterCallback(void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
    238   // Capture every thread except the first one in the sleep. We don't
    239   // want multiple threads to concurrently report exceptions.
    240   if (::InterlockedCompareExchange(&handling_exception, 1, 0) == 1) {
    241     ::Sleep(INFINITE);
    242   }
    243   GetCrashReporterClient()->RecordCrashDumpAttempt(true);
    244   return true;
    245 }
    246 
    247 // Previous unhandled filter. Will be called if not null when we
    248 // intercept a crash.
    249 LPTOP_LEVEL_EXCEPTION_FILTER previous_filter = NULL;
    250 
    251 // Exception filter used when breakpad is not enabled. We just display
    252 // the "Do you want to restart" message and then we call the previous filter.
    253 long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) {
    254   DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
    255 
    256   if (previous_filter)
    257     return previous_filter(info);
    258 
    259   return EXCEPTION_EXECUTE_HANDLER;
    260 }
    261 
    262 // Exception filter for the service process used when breakpad is not enabled.
    263 // We just display the "Do you want to restart" message and then die
    264 // (without calling the previous filter).
    265 long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) {
    266   DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
    267   return EXCEPTION_EXECUTE_HANDLER;
    268 }
    269 
    270 }  // namespace
    271 
    272 // NOTE: This function is used by SyzyASAN to annotate crash reports. If you
    273 // change the name or signature of this function you will break SyzyASAN
    274 // instrumented releases of Chrome. Please contact syzygy-team (at) chromium.org
    275 // before doing so!
    276 extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl(
    277     const wchar_t* key, const wchar_t* value) {
    278   CrashKeysWin* keeper = CrashKeysWin::keeper();
    279   if (!keeper)
    280     return;
    281 
    282   // TODO(siggi): This doesn't look quite right - there's NULL deref potential
    283   //    here, and an implicit std::wstring conversion. Fixme.
    284   keeper->SetCrashKeyValue(key, value);
    285 }
    286 
    287 extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl(
    288     const wchar_t* key) {
    289   CrashKeysWin* keeper = CrashKeysWin::keeper();
    290   if (!keeper)
    291     return;
    292 
    293   // TODO(siggi): This doesn't look quite right - there's NULL deref potential
    294   //    here, and an implicit std::wstring conversion. Fixme.
    295   keeper->ClearCrashKeyValue(key);
    296 }
    297 
    298 static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
    299                                   UINT flags, bool* exit_now) {
    300   // We wrap the call to MessageBoxW with a SEH handler because it some
    301   // machines with CursorXP, PeaDict or with FontExplorer installed it crashes
    302   // uncontrollably here. Being this a best effort deal we better go away.
    303   __try {
    304     *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags));
    305   } __except(EXCEPTION_EXECUTE_HANDLER) {
    306     // Its not safe to continue executing, exit silently here.
    307     ::TerminateProcess(::GetCurrentProcess(),
    308                        GetCrashReporterClient()->GetResultCodeRespawnFailed());
    309   }
    310 
    311   return true;
    312 }
    313 
    314 // This function is executed by the child process that DumpDoneCallback()
    315 // spawned and basically just shows the 'chrome has crashed' dialog if
    316 // the CHROME_CRASHED environment variable is present.
    317 bool ShowRestartDialogIfCrashed(bool* exit_now) {
    318   // If we are being launched in metro mode don't try to show the dialog.
    319   if (base::win::IsMetroProcess())
    320     return false;
    321 
    322   base::string16 message;
    323   base::string16 title;
    324   bool is_rtl_locale;
    325   if (!GetCrashReporterClient()->ShouldShowRestartDialog(
    326           &title, &message, &is_rtl_locale)) {
    327     return false;
    328   }
    329 
    330   // If the UI layout is right-to-left, we need to pass the appropriate MB_XXX
    331   // flags so that an RTL message box is displayed.
    332   UINT flags = MB_OKCANCEL | MB_ICONWARNING;
    333   if (is_rtl_locale)
    334     flags |= MB_RIGHT | MB_RTLREADING;
    335 
    336   return WrapMessageBoxWithSEH(message.c_str(), title.c_str(), flags, exit_now);
    337 }
    338 
    339 // Crashes the process after generating a dump for the provided exception. Note
    340 // that the crash reporter should be initialized before calling this function
    341 // for it to do anything.
    342 // NOTE: This function is used by SyzyASAN to invoke a crash. If you change the
    343 // the name or signature of this function you will break SyzyASAN instrumented
    344 // releases of Chrome. Please contact syzygy-team (at) chromium.org before doing so!
    345 extern "C" int __declspec(dllexport) CrashForException(
    346     EXCEPTION_POINTERS* info) {
    347   if (g_breakpad) {
    348     g_breakpad->WriteMinidumpForException(info);
    349     // Patched stub exists based on conditions (See InitCrashReporter).
    350     // As a side note this function also gets called from
    351     // WindowProcExceptionFilter.
    352     if (g_real_terminate_process_stub == NULL) {
    353       ::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
    354     } else {
    355       NtTerminateProcessPtr real_terminate_proc =
    356           reinterpret_cast<NtTerminateProcessPtr>(
    357               static_cast<char*>(g_real_terminate_process_stub));
    358       real_terminate_proc(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
    359     }
    360   }
    361   return EXCEPTION_CONTINUE_SEARCH;
    362 }
    363 
    364 static NTSTATUS WINAPI HookNtTerminateProcess(HANDLE ProcessHandle,
    365                                               NTSTATUS ExitStatus) {
    366   if (g_breakpad &&
    367       (ProcessHandle == ::GetCurrentProcess() || ProcessHandle == NULL)) {
    368     NT_TIB* tib = reinterpret_cast<NT_TIB*>(NtCurrentTeb());
    369     void* address_on_stack = _AddressOfReturnAddress();
    370     if (address_on_stack < tib->StackLimit ||
    371         address_on_stack > tib->StackBase) {
    372       g_surrogate_exception_record.ExceptionAddress = _ReturnAddress();
    373       g_surrogate_exception_record.ExceptionCode = DBG_TERMINATE_PROCESS;
    374       g_surrogate_exception_record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
    375       CrashForException(&g_surrogate_exception_pointers);
    376     }
    377   }
    378 
    379   NtTerminateProcessPtr real_proc =
    380       reinterpret_cast<NtTerminateProcessPtr>(
    381           static_cast<char*>(g_real_terminate_process_stub));
    382   return real_proc(ProcessHandle, ExitStatus);
    383 }
    384 
    385 static void InitTerminateProcessHooks() {
    386   NtTerminateProcessPtr terminate_process_func_address =
    387       reinterpret_cast<NtTerminateProcessPtr>(::GetProcAddress(
    388           ::GetModuleHandle(L"ntdll.dll"), "NtTerminateProcess"));
    389   if (terminate_process_func_address == NULL)
    390     return;
    391 
    392   DWORD old_protect = 0;
    393   if (!::VirtualProtect(terminate_process_func_address, 5,
    394                         PAGE_EXECUTE_READWRITE, &old_protect))
    395     return;
    396 
    397   g_real_terminate_process_stub = reinterpret_cast<char*>(VirtualAllocEx(
    398       ::GetCurrentProcess(), NULL, sidestep::kMaxPreambleStubSize,
    399       MEM_COMMIT, PAGE_EXECUTE_READWRITE));
    400   if (g_real_terminate_process_stub == NULL)
    401     return;
    402 
    403   g_surrogate_exception_pointers.ContextRecord = &g_surrogate_context;
    404   g_surrogate_exception_pointers.ExceptionRecord =
    405       &g_surrogate_exception_record;
    406 
    407   sidestep::SideStepError patch_result =
    408       sidestep::PreamblePatcher::Patch(
    409           terminate_process_func_address, HookNtTerminateProcess,
    410           g_real_terminate_process_stub, sidestep::kMaxPreambleStubSize);
    411   if (patch_result != sidestep::SIDESTEP_SUCCESS) {
    412     CHECK(::VirtualFreeEx(::GetCurrentProcess(), g_real_terminate_process_stub,
    413                     0, MEM_RELEASE));
    414     CHECK(::VirtualProtect(terminate_process_func_address, 5, old_protect,
    415                            &old_protect));
    416     return;
    417   }
    418 
    419   DWORD dummy = 0;
    420   CHECK(::VirtualProtect(terminate_process_func_address,
    421                          5,
    422                          old_protect,
    423                          &dummy));
    424   CHECK(::VirtualProtect(g_real_terminate_process_stub,
    425                          sidestep::kMaxPreambleStubSize,
    426                          old_protect,
    427                          &old_protect));
    428 }
    429 
    430 static void InitPipeNameEnvVar(bool is_per_user_install) {
    431   scoped_ptr<base::Environment> env(base::Environment::Create());
    432   if (env->HasVar(kPipeNameVar)) {
    433     // The Breakpad pipe name is already configured: nothing to do.
    434     return;
    435   }
    436 
    437   // Check whether configuration management controls crash reporting.
    438   bool crash_reporting_enabled = true;
    439   bool controlled_by_policy =
    440       GetCrashReporterClient()->ReportingIsEnforcedByPolicy(
    441           &crash_reporting_enabled);
    442 
    443   const CommandLine& command = *CommandLine::ForCurrentProcess();
    444   bool use_crash_service = !controlled_by_policy &&
    445                            (command.HasSwitch(switches::kNoErrorDialogs) ||
    446                             GetCrashReporterClient()->IsRunningUnattended());
    447 
    448   std::wstring pipe_name;
    449   if (use_crash_service) {
    450     // Crash reporting is done by crash_service.exe.
    451     pipe_name = kChromePipeName;
    452   } else {
    453     // We want to use the Google Update crash reporting. We need to check if the
    454     // user allows it first (in case the administrator didn't already decide
    455     // via policy).
    456     if (!controlled_by_policy)
    457       crash_reporting_enabled =
    458           GetCrashReporterClient()->GetCollectStatsConsent();
    459 
    460     if (!crash_reporting_enabled) {
    461       // Crash reporting is disabled, don't set the environment variable.
    462       return;
    463     }
    464 
    465     // Build the pipe name. It can be either:
    466     // System-wide install: "NamedPipe\GoogleCrashServices\S-1-5-18"
    467     // Per-user install: "NamedPipe\GoogleCrashServices\<user SID>"
    468     std::wstring user_sid;
    469     if (is_per_user_install) {
    470       if (!base::win::GetUserSidString(&user_sid)) {
    471         return;
    472       }
    473     } else {
    474       user_sid = kSystemPrincipalSid;
    475     }
    476 
    477     pipe_name = kGoogleUpdatePipeName;
    478     pipe_name += user_sid;
    479   }
    480   env->SetVar(kPipeNameVar, base::UTF16ToASCII(pipe_name));
    481 }
    482 
    483 void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) {
    484   previous_filter = SetUnhandledExceptionFilter(filter);
    485 }
    486 
    487 void InitCrashReporter(const std::string& process_type_switch) {
    488   const CommandLine& command = *CommandLine::ForCurrentProcess();
    489   if (command.HasSwitch(switches::kDisableBreakpad))
    490     return;
    491 
    492   // Disable the message box for assertions.
    493   _CrtSetReportMode(_CRT_ASSERT, 0);
    494 
    495   std::wstring process_type = base::ASCIIToWide(process_type_switch);
    496   if (process_type.empty())
    497     process_type = L"browser";
    498 
    499   wchar_t exe_path[MAX_PATH];
    500   exe_path[0] = 0;
    501   GetModuleFileNameW(NULL, exe_path, MAX_PATH);
    502 
    503   bool is_per_user_install =
    504       GetCrashReporterClient()->GetIsPerUserInstall(base::FilePath(exe_path));
    505 
    506   // This is intentionally leaked.
    507   CrashKeysWin* keeper = new CrashKeysWin();
    508 
    509   google_breakpad::CustomClientInfo* custom_info =
    510       keeper->GetCustomInfo(exe_path, process_type,
    511                             GetProfileType(), CommandLine::ForCurrentProcess(),
    512                             GetCrashReporterClient());
    513 
    514   google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL;
    515   LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL;
    516   // We install the post-dump callback only for the browser and service
    517   // processes. It spawns a new browser/service process.
    518   if (process_type == L"browser") {
    519     callback = &DumpDoneCallback;
    520     default_filter = &ChromeExceptionFilter;
    521   } else if (process_type == L"service") {
    522     callback = &DumpDoneCallback;
    523     default_filter = &ServiceExceptionFilter;
    524   }
    525 
    526   if (process_type == L"browser") {
    527     InitPipeNameEnvVar(is_per_user_install);
    528     GetCrashReporterClient()->InitBrowserCrashDumpsRegKey();
    529   }
    530 
    531   scoped_ptr<base::Environment> env(base::Environment::Create());
    532   std::string pipe_name_ascii;
    533   if (!env->GetVar(kPipeNameVar, &pipe_name_ascii)) {
    534     // Breakpad is not enabled.  Configuration is managed or the user
    535     // did not allow Google Update to send crashes.  We need to use
    536     // our default crash handler instead, but only for the
    537     // browser/service processes.
    538     if (default_filter)
    539       InitDefaultCrashCallback(default_filter);
    540     return;
    541   }
    542   std::wstring pipe_name = base::ASCIIToWide(pipe_name_ascii);
    543 
    544 #ifdef _WIN64
    545   // The protocol for connecting to the out-of-process Breakpad crash
    546   // reporter is different for x86-32 and x86-64: the message sizes
    547   // are different because the message struct contains a pointer.  As
    548   // a result, there are two different named pipes to connect to.  The
    549   // 64-bit one is distinguished with an "-x64" suffix.
    550   pipe_name += L"-x64";
    551 #endif
    552 
    553   // Get the alternate dump directory. We use the temp path.
    554   wchar_t temp_dir[MAX_PATH] = {0};
    555   ::GetTempPathW(MAX_PATH, temp_dir);
    556 
    557   MINIDUMP_TYPE dump_type = kSmallDumpType;
    558   // Capture full memory if explicitly instructed to.
    559   if (command.HasSwitch(switches::kFullMemoryCrashReport))
    560     dump_type = kFullDumpType;
    561   else if (GetCrashReporterClient()->GetShouldDumpLargerDumps(
    562                is_per_user_install))
    563     dump_type = kLargerDumpType;
    564 
    565   g_breakpad = new google_breakpad::ExceptionHandler(temp_dir, &FilterCallback,
    566                    callback, NULL,
    567                    google_breakpad::ExceptionHandler::HANDLER_ALL,
    568                    dump_type, pipe_name.c_str(), custom_info);
    569 
    570   // Now initialize the non crash dump handler.
    571   g_dumphandler_no_crash = new google_breakpad::ExceptionHandler(temp_dir,
    572       &FilterCallbackWhenNoCrash,
    573       &DumpDoneCallbackWhenNoCrash,
    574       NULL,
    575       // Set the handler to none so this handler would not be added to
    576       // |handler_stack_| in |ExceptionHandler| which is a list of exception
    577       // handlers.
    578       google_breakpad::ExceptionHandler::HANDLER_NONE,
    579       dump_type, pipe_name.c_str(), custom_info);
    580 
    581   // Set the DumpWithoutCrashingFunction for this instance of base.lib.  Other
    582   // executable images linked with base should set this again for
    583   // DumpWithoutCrashing to function correctly.
    584   // See chrome_main.cc for example.
    585   base::debug::SetDumpWithoutCrashingFunction(&DumpProcessWithoutCrash);
    586 
    587   if (g_breakpad->IsOutOfProcess()) {
    588     // Tells breakpad to handle breakpoint and single step exceptions.
    589     // This might break JIT debuggers, but at least it will always
    590     // generate a crashdump for these exceptions.
    591     g_breakpad->set_handle_debug_exceptions(true);
    592 
    593 #ifndef _WIN64
    594     if (process_type != L"browser" &&
    595         !GetCrashReporterClient()->IsRunningUnattended()) {
    596       // Initialize the hook TerminateProcess to catch unexpected exits.
    597       InitTerminateProcessHooks();
    598     }
    599 #endif
    600   }
    601 }
    602 
    603 // If the user has disabled crash reporting uploads and restarted Chrome, the
    604 // restarted instance will still contain the pipe environment variable, which
    605 // will allow the restarted process to still upload crash reports. This function
    606 // clears the environment variable, so that the restarted Chrome, which inherits
    607 // its environment from the current Chrome, will no longer contain the variable.
    608 extern "C" void __declspec(dllexport) __cdecl
    609       ClearBreakpadPipeEnvironmentVariable() {
    610   scoped_ptr<base::Environment> env(base::Environment::Create());
    611   env->UnSetVar(kPipeNameVar);
    612 }
    613 
    614 }  // namespace breakpad
    615