1 // Copyright 2014 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.
5 // This module contains the necessary code to register the Breakpad exception
6 // handler. This implementation is based on Chrome's crash reporting code.
8 #include "chrome_elf/breakpad.h"
12 #include "base/macros.h"
13 #include "breakpad/src/client/windows/handler/exception_handler.h"
14 #include "chrome_elf/chrome_elf_util.h"
15 #include "version.h" // NOLINT
17 google_breakpad::ExceptionHandler
* g_elf_breakpad
= NULL
;
21 const wchar_t kBreakpadProductName
[] = L
"Chrome";
22 const wchar_t kBreakpadVersionEntry
[] = L
"ver";
23 const wchar_t kBreakpadProdEntry
[] = L
"prod";
24 const wchar_t kBreakpadPlatformEntry
[] = L
"plat";
25 const wchar_t kBreakpadPlatformWin32
[] = L
"Win32";
26 const wchar_t kBreakpadProcessEntry
[] = L
"ptype";
27 const wchar_t kBreakpadChannelEntry
[] = L
"channel";
29 // The protocol for connecting to the out-of-process Breakpad crash
30 // reporter is different for x86-32 and x86-64: the message sizes
31 // are different because the message struct contains a pointer. As
32 // a result, there are two different named pipes to connect to. The
33 // 64-bit one is distinguished with an "-x64" suffix.
34 const wchar_t kChromePipeName
[] = L
"\\\\.\\pipe\\ChromeCrashServices\\";
35 const wchar_t kGoogleUpdatePipeName
[] = L
"\\\\.\\pipe\\GoogleCrashServices\\";
36 const wchar_t kSystemPrincipalSid
[] = L
"S-1-5-18";
38 const wchar_t kNoErrorDialogs
[] = L
"noerrdialogs";
39 const wchar_t kChromeHeadless
[] = L
"CHROME_HEADLESS";
41 google_breakpad::CustomClientInfo
* GetCustomInfo() {
42 base::string16 process
= IsNonBrowserProcess() ? L
"renderer" : L
"browser";
44 wchar_t exe_path
[MAX_PATH
] = {};
45 base::string16 channel
;
46 if (GetModuleFileName(NULL
, exe_path
, arraysize(exe_path
)) &&
51 static google_breakpad::CustomInfoEntry
ver_entry(
52 kBreakpadVersionEntry
, TEXT(CHROME_VERSION_STRING
));
53 static google_breakpad::CustomInfoEntry
prod_entry(
54 kBreakpadProdEntry
, kBreakpadProductName
);
55 static google_breakpad::CustomInfoEntry
plat_entry(
56 kBreakpadPlatformEntry
, kBreakpadPlatformWin32
);
57 static google_breakpad::CustomInfoEntry
proc_entry(
58 kBreakpadProcessEntry
, process
.c_str());
59 static google_breakpad::CustomInfoEntry
channel_entry(
60 kBreakpadChannelEntry
, channel
.c_str());
61 static google_breakpad::CustomInfoEntry entries
[] = {
62 ver_entry
, prod_entry
, plat_entry
, proc_entry
, channel_entry
};
63 static google_breakpad::CustomClientInfo custom_info
= {
64 entries
, arraysize(entries
) };
68 base::string16
GetUserSidString() {
69 // Get the current token.
71 base::string16 user_sid
;
72 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY
, &token
))
75 DWORD size
= sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
;
76 BYTE user_bytes
[sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
] = {};
77 TOKEN_USER
* user
= reinterpret_cast<TOKEN_USER
*>(user_bytes
);
79 wchar_t* sid_string
= NULL
;
80 if (::GetTokenInformation(token
, TokenUser
, user
, size
, &size
) &&
82 ::ConvertSidToStringSid(user
->User
.Sid
, &sid_string
)) {
83 user_sid
= sid_string
;
84 ::LocalFree(sid_string
);
92 DWORD ret
= ::GetEnvironmentVariable(L
"CHROME_HEADLESS", NULL
, 0);
96 wchar_t* command_line
= ::GetCommandLine();
98 // Note: Since this is a pure substring search rather than a check for a
99 // switch, there is a small chance that this code will match things that the
100 // Chrome code (which executes a similar check) does not. However, as long as
101 // no other switches contain the string "noerrdialogs", it should not be an
103 return (command_line
&& wcsstr(command_line
, kNoErrorDialogs
));
108 int GenerateCrashDump(EXCEPTION_POINTERS
* exinfo
) {
109 DWORD code
= exinfo
->ExceptionRecord
->ExceptionCode
;
110 if (code
== EXCEPTION_BREAKPOINT
|| code
== EXCEPTION_SINGLE_STEP
)
111 return EXCEPTION_CONTINUE_SEARCH
;
113 if (g_elf_breakpad
!= NULL
)
114 g_elf_breakpad
->WriteMinidumpForException(exinfo
);
115 return EXCEPTION_CONTINUE_SEARCH
;
118 void InitializeCrashReporting() {
119 wchar_t exe_path
[MAX_PATH
] = {};
120 if (!::GetModuleFileName(NULL
, exe_path
, arraysize(exe_path
)))
123 // Disable the message box for assertions.
124 _CrtSetReportMode(_CRT_ASSERT
, 0);
126 // Get the alternate dump directory. We use the temp path.
127 // N.B. We don't use base::GetTempDir() here to avoid running more code then
128 // necessary before crashes can be properly reported.
129 wchar_t temp_directory
[MAX_PATH
+ 1] = {};
130 DWORD length
= GetTempPath(MAX_PATH
, temp_directory
);
134 // Minidump with stacks, PEB, TEBs and unloaded module list.
135 MINIDUMP_TYPE dump_type
= static_cast<MINIDUMP_TYPE
>(
136 MiniDumpWithProcessThreadData
| // Get PEB and TEB.
137 MiniDumpWithUnloadedModules
| // Get unloaded modules when available.
138 MiniDumpWithIndirectlyReferencedMemory
); // Get memory referenced by
141 #if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD)
142 bool is_official_chrome_build
= true;
144 bool is_official_chrome_build
= false;
147 base::string16 pipe_name
;
149 bool enabled_by_policy
= false;
150 bool use_policy
= ReportingIsEnforcedByPolicy(&enabled_by_policy
);
152 if (!use_policy
&& IsHeadless()) {
153 pipe_name
= kChromePipeName
;
154 } else if (use_policy
?
156 (is_official_chrome_build
&& AreUsageStatsEnabled(exe_path
))) {
157 // Build the pipe name. It can be one of:
158 // 32-bit system: \\.\pipe\GoogleCrashServices\S-1-5-18
159 // 32-bit user: \\.\pipe\GoogleCrashServices\<user SID>
160 // 64-bit system: \\.\pipe\GoogleCrashServices\S-1-5-18-x64
161 // 64-bit user: \\.\pipe\GoogleCrashServices\<user SID>-x64
162 base::string16 user_sid
= IsSystemInstall(exe_path
) ? kSystemPrincipalSid
:
164 if (user_sid
.empty())
167 pipe_name
= kGoogleUpdatePipeName
;
168 pipe_name
+= user_sid
;
171 pipe_name
+= L
"-x64";
174 // Either this is a Chromium build, reporting is disabled by policy or the
175 // user has not given consent.
179 g_elf_breakpad
= new google_breakpad::ExceptionHandler(
184 google_breakpad::ExceptionHandler::HANDLER_ALL
,
189 if (g_elf_breakpad
->IsOutOfProcess()) {
190 // Tells breakpad to handle breakpoint and single step exceptions.
191 g_elf_breakpad
->set_handle_debug_exceptions(true);