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";
40 google_breakpad::CustomClientInfo
* GetCustomInfo() {
41 base::string16 process
= IsNonBrowserProcess() ? L
"renderer" : L
"browser";
43 wchar_t exe_path
[MAX_PATH
] = {};
44 base::string16 channel
;
45 if (GetModuleFileName(NULL
, exe_path
, arraysize(exe_path
)) &&
50 static google_breakpad::CustomInfoEntry
ver_entry(
51 kBreakpadVersionEntry
, TEXT(CHROME_VERSION_STRING
));
52 static google_breakpad::CustomInfoEntry
prod_entry(
53 kBreakpadProdEntry
, kBreakpadProductName
);
54 static google_breakpad::CustomInfoEntry
plat_entry(
55 kBreakpadPlatformEntry
, kBreakpadPlatformWin32
);
56 static google_breakpad::CustomInfoEntry
proc_entry(
57 kBreakpadProcessEntry
, process
.c_str());
58 static google_breakpad::CustomInfoEntry
channel_entry(
59 kBreakpadChannelEntry
, channel
.c_str());
60 static google_breakpad::CustomInfoEntry entries
[] = {
61 ver_entry
, prod_entry
, plat_entry
, proc_entry
, channel_entry
};
62 static google_breakpad::CustomClientInfo custom_info
= {
63 entries
, arraysize(entries
) };
67 base::string16
GetUserSidString() {
68 // Get the current token.
70 base::string16 user_sid
;
71 if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY
, &token
))
74 DWORD size
= sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
;
75 BYTE user_bytes
[sizeof(TOKEN_USER
) + SECURITY_MAX_SID_SIZE
] = {};
76 TOKEN_USER
* user
= reinterpret_cast<TOKEN_USER
*>(user_bytes
);
78 wchar_t* sid_string
= NULL
;
79 if (::GetTokenInformation(token
, TokenUser
, user
, size
, &size
) &&
81 ::ConvertSidToStringSid(user
->User
.Sid
, &sid_string
)) {
82 user_sid
= sid_string
;
83 ::LocalFree(sid_string
);
91 DWORD ret
= ::GetEnvironmentVariable(L
"CHROME_HEADLESS", NULL
, 0);
95 wchar_t* command_line
= ::GetCommandLine();
97 // Note: Since this is a pure substring search rather than a check for a
98 // switch, there is a small chance that this code will match things that the
99 // Chrome code (which executes a similar check) does not. However, as long as
100 // no other switches contain the string "noerrdialogs", it should not be an
102 return (command_line
&& wcsstr(command_line
, kNoErrorDialogs
));
107 int GenerateCrashDump(EXCEPTION_POINTERS
* exinfo
) {
108 DWORD code
= exinfo
->ExceptionRecord
->ExceptionCode
;
109 if (code
== EXCEPTION_BREAKPOINT
|| code
== EXCEPTION_SINGLE_STEP
)
110 return EXCEPTION_CONTINUE_SEARCH
;
112 if (g_elf_breakpad
!= NULL
)
113 g_elf_breakpad
->WriteMinidumpForException(exinfo
);
114 return EXCEPTION_CONTINUE_SEARCH
;
117 void InitializeCrashReporting() {
118 wchar_t exe_path
[MAX_PATH
] = {};
119 if (!::GetModuleFileName(NULL
, exe_path
, arraysize(exe_path
)))
122 // Disable the message box for assertions.
123 _CrtSetReportMode(_CRT_ASSERT
, 0);
125 // Get the alternate dump directory. We use the temp path.
126 // N.B. We don't use base::GetTempDir() here to avoid running more code then
127 // necessary before crashes can be properly reported.
128 wchar_t temp_directory
[MAX_PATH
+ 1] = {};
129 DWORD length
= GetTempPath(MAX_PATH
, temp_directory
);
133 // Minidump with stacks, PEB, TEBs and unloaded module list.
134 MINIDUMP_TYPE dump_type
= static_cast<MINIDUMP_TYPE
>(
135 MiniDumpWithProcessThreadData
| // Get PEB and TEB.
136 MiniDumpWithUnloadedModules
| // Get unloaded modules when available.
137 MiniDumpWithIndirectlyReferencedMemory
); // Get memory referenced by
140 #if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD)
141 bool is_official_chrome_build
= true;
143 bool is_official_chrome_build
= false;
146 base::string16 pipe_name
;
148 bool enabled_by_policy
= false;
149 bool use_policy
= ReportingIsEnforcedByPolicy(&enabled_by_policy
);
151 if (!use_policy
&& IsHeadless()) {
152 pipe_name
= kChromePipeName
;
153 } else if (use_policy
?
155 (is_official_chrome_build
&& AreUsageStatsEnabled(exe_path
))) {
156 // Build the pipe name. It can be one of:
157 // 32-bit system: \\.\pipe\GoogleCrashServices\S-1-5-18
158 // 32-bit user: \\.\pipe\GoogleCrashServices\<user SID>
159 // 64-bit system: \\.\pipe\GoogleCrashServices\S-1-5-18-x64
160 // 64-bit user: \\.\pipe\GoogleCrashServices\<user SID>-x64
161 base::string16 user_sid
= IsSystemInstall(exe_path
) ? kSystemPrincipalSid
:
163 if (user_sid
.empty())
166 pipe_name
= kGoogleUpdatePipeName
;
167 pipe_name
+= user_sid
;
170 pipe_name
+= L
"-x64";
173 // Either this is a Chromium build, reporting is disabled by policy or the
174 // user has not given consent.
178 g_elf_breakpad
= new google_breakpad::ExceptionHandler(
183 google_breakpad::ExceptionHandler::HANDLER_ALL
,
188 if (g_elf_breakpad
->IsOutOfProcess()) {
189 // Tells breakpad to handle breakpoint and single step exceptions.
190 g_elf_breakpad
->set_handle_debug_exceptions(true);