OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/breakpad/app/breakpad_win.h" | 5 #include "components/breakpad/app/breakpad_win.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <shellapi.h> | 8 #include <shellapi.h> |
9 #include <tchar.h> | 9 #include <tchar.h> |
10 #include <userenv.h> | 10 #include <userenv.h> |
11 #include <winnt.h> | 11 #include <winnt.h> |
12 | 12 |
13 #include <algorithm> | 13 #include <algorithm> |
| 14 #include <map> |
14 #include <vector> | 15 #include <vector> |
15 | 16 |
16 #include "base/base_switches.h" | 17 #include "base/base_switches.h" |
17 #include "base/basictypes.h" | 18 #include "base/basictypes.h" |
18 #include "base/command_line.h" | 19 #include "base/command_line.h" |
19 #include "base/debug/crash_logging.h" | 20 #include "base/debug/crash_logging.h" |
20 #include "base/debug/dump_without_crashing.h" | 21 #include "base/debug/dump_without_crashing.h" |
21 #include "base/environment.h" | 22 #include "base/environment.h" |
22 #include "base/memory/scoped_ptr.h" | 23 #include "base/memory/scoped_ptr.h" |
23 #include "base/strings/string16.h" | 24 #include "base/strings/string16.h" |
(...skipping 14 matching lines...) Expand all Loading... |
38 #include "sandbox/win/src/sidestep/preamble_patcher.h" | 39 #include "sandbox/win/src/sidestep/preamble_patcher.h" |
39 | 40 |
40 // userenv.dll is required for GetProfileType(). | 41 // userenv.dll is required for GetProfileType(). |
41 #pragma comment(lib, "userenv.lib") | 42 #pragma comment(lib, "userenv.lib") |
42 | 43 |
43 #pragma intrinsic(_AddressOfReturnAddress) | 44 #pragma intrinsic(_AddressOfReturnAddress) |
44 #pragma intrinsic(_ReturnAddress) | 45 #pragma intrinsic(_ReturnAddress) |
45 | 46 |
46 namespace breakpad { | 47 namespace breakpad { |
47 | 48 |
48 std::vector<google_breakpad::CustomInfoEntry>* g_custom_entries = NULL; | 49 // Manages the breakpad key/value pair stash, there may only be one instance |
49 bool g_deferred_crash_uploads = false; | 50 // of this class per process at one time. |
| 51 class CrashKeysWin { |
| 52 public: |
| 53 CrashKeysWin(); |
| 54 ~CrashKeysWin(); |
| 55 |
| 56 // May only be called once. |
| 57 google_breakpad::CustomClientInfo* |
| 58 GetCustomInfo(const std::wstring& exe_path, const std::wstring& type); |
| 59 |
| 60 void SetCrashKeyValue(const std::wstring& key, const std::wstring& value); |
| 61 void ClearCrashKeyValue(const std::wstring& key); |
| 62 |
| 63 static CrashKeysWin* keeper() { return keeper_; } |
| 64 |
| 65 private: |
| 66 // One-time initialization of private key/value pairs. |
| 67 void SetPluginPath(const std::wstring& path); |
| 68 void SetBreakpadDumpPath(); |
| 69 |
| 70 // Must not be resized after GetCustomInfo is invoked. |
| 71 std::vector<google_breakpad::CustomInfoEntry> custom_entries_; |
| 72 |
| 73 typedef std::map<std::wstring, google_breakpad::CustomInfoEntry*> |
| 74 DynamicEntriesMap; |
| 75 base::Lock lock_; |
| 76 // Keeps track of the next index for a new dynamic entry. |
| 77 size_t dynamic_keys_offset_; // Under lock_. |
| 78 // Maintains key->entry information for dynamic key/value entries |
| 79 // in custom_entries_. |
| 80 DynamicEntriesMap dynamic_entries_; // Under lock_. |
| 81 |
| 82 // Stores the sole instance of this class allowed per process. |
| 83 static CrashKeysWin* keeper_; |
| 84 }; |
| 85 |
| 86 CrashKeysWin* CrashKeysWin::keeper_; |
| 87 |
| 88 CrashKeysWin::CrashKeysWin() : dynamic_keys_offset_(0) { |
| 89 DCHECK_EQ(static_cast<CrashKeysWin*>(NULL), keeper_); |
| 90 keeper_ = this; |
| 91 } |
| 92 |
| 93 CrashKeysWin::~CrashKeysWin() { |
| 94 DCHECK_EQ(this, keeper_); |
| 95 keeper_ = NULL; |
| 96 } |
50 | 97 |
51 namespace { | 98 namespace { |
52 | 99 |
53 // Minidump with stacks, PEB, TEB, and unloaded module list. | 100 // Minidump with stacks, PEB, TEB, and unloaded module list. |
54 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>( | 101 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>( |
55 MiniDumpWithProcessThreadData | // Get PEB and TEB. | 102 MiniDumpWithProcessThreadData | // Get PEB and TEB. |
56 MiniDumpWithUnloadedModules); // Get unloaded modules when available. | 103 MiniDumpWithUnloadedModules); // Get unloaded modules when available. |
57 | 104 |
58 // Minidump with all of the above, plus memory referenced from stack. | 105 // Minidump with all of the above, plus memory referenced from stack. |
59 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( | 106 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( |
(...skipping 20 matching lines...) Expand all Loading... |
80 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL; | 127 google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL; |
81 | 128 |
82 EXCEPTION_POINTERS g_surrogate_exception_pointers = {0}; | 129 EXCEPTION_POINTERS g_surrogate_exception_pointers = {0}; |
83 EXCEPTION_RECORD g_surrogate_exception_record = {0}; | 130 EXCEPTION_RECORD g_surrogate_exception_record = {0}; |
84 CONTEXT g_surrogate_context = {0}; | 131 CONTEXT g_surrogate_context = {0}; |
85 | 132 |
86 typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle, | 133 typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle, |
87 NTSTATUS ExitStatus); | 134 NTSTATUS ExitStatus); |
88 char* g_real_terminate_process_stub = NULL; | 135 char* g_real_terminate_process_stub = NULL; |
89 | 136 |
90 base::Lock* g_dynamic_entries_lock = NULL; | |
91 // Under *g_dynamic_entries_lock. | |
92 size_t g_dynamic_keys_offset = 0; | |
93 typedef std::map<std::wstring, google_breakpad::CustomInfoEntry*> | |
94 DynamicEntriesMap; | |
95 // Under *g_dynamic_entries_lock. | |
96 DynamicEntriesMap* g_dynamic_entries = NULL; | |
97 | 137 |
98 // Allow for 256 dynamic entries in addition to the fixed set of entries | 138 // Allow for 256 dynamic entries in addition to the fixed set of entries |
99 // set up in this file. | 139 // set up in this file. |
100 const size_t kMaxDynamicEntries = 256; | 140 const size_t kMaxDynamicEntries = 256; |
101 | 141 |
102 // Maximum length for plugin path to include in plugin crash reports. | 142 // Maximum length for plugin path to include in plugin crash reports. |
103 const size_t kMaxPluginPathLength = 256; | 143 const size_t kMaxPluginPathLength = 256; |
104 | 144 |
| 145 } // namespace |
| 146 |
105 // Dumps the current process memory. | 147 // Dumps the current process memory. |
106 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { | 148 extern "C" void __declspec(dllexport) __cdecl DumpProcess() { |
107 if (g_breakpad) { | 149 if (g_breakpad) { |
108 g_breakpad->WriteMinidump(); | 150 g_breakpad->WriteMinidump(); |
109 } | 151 } |
110 } | 152 } |
111 | 153 |
112 // Used for dumping a process state when there is no crash. | 154 // Used for dumping a process state when there is no crash. |
113 extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() { | 155 extern "C" void __declspec(dllexport) __cdecl DumpProcessWithoutCrash() { |
114 if (g_dumphandler_no_crash) { | 156 if (g_dumphandler_no_crash) { |
115 g_dumphandler_no_crash->WriteMinidump(); | 157 g_dumphandler_no_crash->WriteMinidump(); |
116 } | 158 } |
117 } | 159 } |
118 | 160 |
| 161 namespace { |
| 162 |
119 // We need to prevent ICF from folding DumpForHangDebuggingThread() and | 163 // We need to prevent ICF from folding DumpForHangDebuggingThread() and |
120 // DumpProcessWithoutCrashThread() together, since that makes them | 164 // DumpProcessWithoutCrashThread() together, since that makes them |
121 // indistinguishable in crash dumps. We do this by making the function | 165 // indistinguishable in crash dumps. We do this by making the function |
122 // bodies unique, and prevent optimization from shuffling things around. | 166 // bodies unique, and prevent optimization from shuffling things around. |
123 MSVC_DISABLE_OPTIMIZE() | 167 MSVC_DISABLE_OPTIMIZE() |
124 MSVC_PUSH_DISABLE_WARNING(4748) | 168 MSVC_PUSH_DISABLE_WARNING(4748) |
125 | 169 |
126 DWORD WINAPI DumpProcessWithoutCrashThread(void*) { | 170 DWORD WINAPI DumpProcessWithoutCrashThread(void*) { |
127 DumpProcessWithoutCrash(); | 171 DumpProcessWithoutCrash(); |
128 return 0; | 172 return 0; |
129 } | 173 } |
130 | 174 |
131 // The following two functions do exactly the same thing as the two above. But | 175 // The following two functions do exactly the same thing as the two above. But |
132 // we want the signatures to be different so that we can easily track them in | 176 // we want the signatures to be different so that we can easily track them in |
133 // crash reports. | 177 // crash reports. |
134 // TODO(yzshen): Remove when enough information is collected and the hang rate | 178 // TODO(yzshen): Remove when enough information is collected and the hang rate |
135 // of pepper/renderer processes is reduced. | 179 // of pepper/renderer processes is reduced. |
136 DWORD WINAPI DumpForHangDebuggingThread(void*) { | 180 DWORD WINAPI DumpForHangDebuggingThread(void*) { |
137 DumpProcessWithoutCrash(); | 181 DumpProcessWithoutCrash(); |
138 VLOG(1) << "dumped for hang debugging"; | 182 VLOG(1) << "dumped for hang debugging"; |
139 return 0; | 183 return 0; |
140 } | 184 } |
141 | 185 |
142 MSVC_POP_WARNING() | 186 MSVC_POP_WARNING() |
143 MSVC_ENABLE_OPTIMIZE() | 187 MSVC_ENABLE_OPTIMIZE() |
144 | 188 |
| 189 } // namespace |
| 190 |
145 // Injects a thread into a remote process to dump state when there is no crash. | 191 // Injects a thread into a remote process to dump state when there is no crash. |
146 extern "C" HANDLE __declspec(dllexport) __cdecl | 192 extern "C" HANDLE __declspec(dllexport) __cdecl |
147 InjectDumpProcessWithoutCrash(HANDLE process) { | 193 InjectDumpProcessWithoutCrash(HANDLE process) { |
148 return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread, | 194 return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread, |
149 0, 0, NULL); | 195 0, 0, NULL); |
150 } | 196 } |
151 | 197 |
152 extern "C" HANDLE __declspec(dllexport) __cdecl | 198 extern "C" HANDLE __declspec(dllexport) __cdecl |
153 InjectDumpForHangDebugging(HANDLE process) { | 199 InjectDumpForHangDebugging(HANDLE process) { |
154 return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread, | 200 return CreateRemoteThread(process, NULL, 0, DumpForHangDebuggingThread, |
155 0, 0, NULL); | 201 0, 0, NULL); |
156 } | 202 } |
157 | 203 |
158 // Appends the plugin path to |g_custom_entries|. | 204 // Appends the plugin path to |g_custom_entries|. |
159 void SetPluginPath(const std::wstring& path) { | 205 void CrashKeysWin::SetPluginPath(const std::wstring& path) { |
160 DCHECK(g_custom_entries); | |
161 | |
162 if (path.size() > kMaxPluginPathLength) { | 206 if (path.size() > kMaxPluginPathLength) { |
163 // If the path is too long, truncate from the start rather than the end, | 207 // If the path is too long, truncate from the start rather than the end, |
164 // since we want to be able to recover the DLL name. | 208 // since we want to be able to recover the DLL name. |
165 SetPluginPath(path.substr(path.size() - kMaxPluginPathLength)); | 209 SetPluginPath(path.substr(path.size() - kMaxPluginPathLength)); |
166 return; | 210 return; |
167 } | 211 } |
168 | 212 |
169 // The chunk size without terminator. | 213 // The chunk size without terminator. |
170 const size_t kChunkSize = static_cast<size_t>( | 214 const size_t kChunkSize = static_cast<size_t>( |
171 google_breakpad::CustomInfoEntry::kValueMaxLength - 1); | 215 google_breakpad::CustomInfoEntry::kValueMaxLength - 1); |
172 | 216 |
173 int chunk_index = 0; | 217 int chunk_index = 0; |
174 size_t chunk_start = 0; // Current position inside |path| | 218 size_t chunk_start = 0; // Current position inside |path| |
175 | 219 |
176 for (chunk_start = 0; chunk_start < path.size(); chunk_index++) { | 220 for (chunk_start = 0; chunk_start < path.size(); chunk_index++) { |
177 size_t chunk_length = std::min(kChunkSize, path.size() - chunk_start); | 221 size_t chunk_length = std::min(kChunkSize, path.size() - chunk_start); |
178 | 222 |
179 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 223 custom_entries_.push_back(google_breakpad::CustomInfoEntry( |
180 base::StringPrintf(L"plugin-path-chunk-%i", chunk_index + 1).c_str(), | 224 base::StringPrintf(L"plugin-path-chunk-%i", chunk_index + 1).c_str(), |
181 path.substr(chunk_start, chunk_length).c_str())); | 225 path.substr(chunk_start, chunk_length).c_str())); |
182 | 226 |
183 chunk_start += chunk_length; | 227 chunk_start += chunk_length; |
184 } | 228 } |
185 } | 229 } |
186 | 230 |
187 // Appends the breakpad dump path to |g_custom_entries|. | 231 // Appends the breakpad dump path to |g_custom_entries|. |
188 void SetBreakpadDumpPath() { | 232 void CrashKeysWin::SetBreakpadDumpPath() { |
189 DCHECK(g_custom_entries); | |
190 base::FilePath crash_dumps_dir_path; | 233 base::FilePath crash_dumps_dir_path; |
191 if (GetBreakpadClient()->GetAlternativeCrashDumpLocation( | 234 if (GetBreakpadClient()->GetAlternativeCrashDumpLocation( |
192 &crash_dumps_dir_path)) { | 235 &crash_dumps_dir_path)) { |
193 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 236 custom_entries_.push_back(google_breakpad::CustomInfoEntry( |
194 L"breakpad-dump-location", crash_dumps_dir_path.value().c_str())); | 237 L"breakpad-dump-location", crash_dumps_dir_path.value().c_str())); |
195 } | 238 } |
196 } | 239 } |
197 | 240 |
198 // Returns a string containing a list of all modifiers for the loaded profile. | 241 // Returns a string containing a list of all modifiers for the loaded profile. |
199 std::wstring GetProfileType() { | 242 std::wstring GetProfileType() { |
200 std::wstring profile_type; | 243 std::wstring profile_type; |
201 DWORD profile_bits = 0; | 244 DWORD profile_bits = 0; |
202 if (::GetProfileType(&profile_bits)) { | 245 if (::GetProfileType(&profile_bits)) { |
203 static const struct { | 246 static const struct { |
(...skipping 15 matching lines...) Expand all Loading... |
219 } | 262 } |
220 } else { | 263 } else { |
221 DWORD last_error = ::GetLastError(); | 264 DWORD last_error = ::GetLastError(); |
222 base::SStringPrintf(&profile_type, L"error %u", last_error); | 265 base::SStringPrintf(&profile_type, L"error %u", last_error); |
223 } | 266 } |
224 return profile_type; | 267 return profile_type; |
225 } | 268 } |
226 | 269 |
227 // Returns the custom info structure based on the dll in parameter and the | 270 // Returns the custom info structure based on the dll in parameter and the |
228 // process type. | 271 // process type. |
229 google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path, | 272 google_breakpad::CustomClientInfo* |
230 const std::wstring& type) { | 273 CrashKeysWin::GetCustomInfo(const std::wstring& exe_path, |
| 274 const std::wstring& type) { |
231 base::string16 version, product; | 275 base::string16 version, product; |
232 base::string16 special_build; | 276 base::string16 special_build; |
233 base::string16 channel_name; | 277 base::string16 channel_name; |
234 GetBreakpadClient()->GetProductNameAndVersion( | 278 GetBreakpadClient()->GetProductNameAndVersion( |
235 base::FilePath(exe_path), | 279 base::FilePath(exe_path), |
236 &product, | 280 &product, |
237 &version, | 281 &version, |
238 &special_build, | 282 &special_build, |
239 &channel_name); | 283 &channel_name); |
240 | 284 |
241 // We only expect this method to be called once per process. | 285 // We only expect this method to be called once per process. |
242 DCHECK(!g_custom_entries); | 286 // Common enties |
243 g_custom_entries = new std::vector<google_breakpad::CustomInfoEntry>; | 287 custom_entries_.push_back( |
244 | |
245 // Common g_custom_entries. | |
246 g_custom_entries->push_back( | |
247 google_breakpad::CustomInfoEntry(L"ver", | 288 google_breakpad::CustomInfoEntry(L"ver", |
248 base::UTF16ToWide(version).c_str())); | 289 base::UTF16ToWide(version).c_str())); |
249 g_custom_entries->push_back( | 290 custom_entries_.push_back( |
250 google_breakpad::CustomInfoEntry(L"prod", | 291 google_breakpad::CustomInfoEntry(L"prod", |
251 base::UTF16ToWide(product).c_str())); | 292 base::UTF16ToWide(product).c_str())); |
252 g_custom_entries->push_back( | 293 custom_entries_.push_back( |
253 google_breakpad::CustomInfoEntry(L"plat", L"Win32")); | 294 google_breakpad::CustomInfoEntry(L"plat", L"Win32")); |
254 g_custom_entries->push_back( | 295 custom_entries_.push_back( |
255 google_breakpad::CustomInfoEntry(L"ptype", type.c_str())); | 296 google_breakpad::CustomInfoEntry(L"ptype", type.c_str())); |
256 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 297 custom_entries_.push_back(google_breakpad::CustomInfoEntry( |
257 L"pid", base::StringPrintf(L"%d", ::GetCurrentProcessId()).c_str())); | 298 L"pid", base::StringPrintf(L"%d", ::GetCurrentProcessId()).c_str())); |
258 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 299 custom_entries_.push_back(google_breakpad::CustomInfoEntry( |
259 L"channel", base::UTF16ToWide(channel_name).c_str())); | 300 L"channel", base::UTF16ToWide(channel_name).c_str())); |
260 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 301 custom_entries_.push_back(google_breakpad::CustomInfoEntry( |
261 L"profile-type", GetProfileType().c_str())); | 302 L"profile-type", GetProfileType().c_str())); |
262 | 303 |
263 if (g_deferred_crash_uploads) | |
264 g_custom_entries->push_back( | |
265 google_breakpad::CustomInfoEntry(L"deferred-upload", L"true")); | |
266 | |
267 if (!special_build.empty()) | 304 if (!special_build.empty()) |
268 g_custom_entries->push_back(google_breakpad::CustomInfoEntry( | 305 custom_entries_.push_back(google_breakpad::CustomInfoEntry( |
269 L"special", base::UTF16ToWide(special_build).c_str())); | 306 L"special", base::UTF16ToWide(special_build).c_str())); |
270 | 307 |
271 if (type == L"plugin" || type == L"ppapi") { | 308 if (type == L"plugin" || type == L"ppapi") { |
272 std::wstring plugin_path = | 309 std::wstring plugin_path = |
273 CommandLine::ForCurrentProcess()->GetSwitchValueNative("plugin-path"); | 310 CommandLine::ForCurrentProcess()->GetSwitchValueNative("plugin-path"); |
274 if (!plugin_path.empty()) | 311 if (!plugin_path.empty()) |
275 SetPluginPath(plugin_path); | 312 SetPluginPath(plugin_path); |
276 } | 313 } |
277 | 314 |
278 // Check whether configuration management controls crash reporting. | 315 // Check whether configuration management controls crash reporting. |
279 bool crash_reporting_enabled = true; | 316 bool crash_reporting_enabled = true; |
280 bool controlled_by_policy = GetBreakpadClient()->ReportingIsEnforcedByPolicy( | 317 bool controlled_by_policy = GetBreakpadClient()->ReportingIsEnforcedByPolicy( |
281 &crash_reporting_enabled); | 318 &crash_reporting_enabled); |
282 const CommandLine& command = *CommandLine::ForCurrentProcess(); | 319 const CommandLine& command = *CommandLine::ForCurrentProcess(); |
283 bool use_crash_service = | 320 bool use_crash_service = |
284 !controlled_by_policy && (command.HasSwitch(switches::kNoErrorDialogs) || | 321 !controlled_by_policy && (command.HasSwitch(switches::kNoErrorDialogs) || |
285 GetBreakpadClient()->IsRunningUnattended()); | 322 GetBreakpadClient()->IsRunningUnattended()); |
286 if (use_crash_service) | 323 if (use_crash_service) |
287 SetBreakpadDumpPath(); | 324 SetBreakpadDumpPath(); |
288 | 325 |
289 // Create space for dynamic ad-hoc keys. The names and values are set using | 326 // Create space for dynamic ad-hoc keys. The names and values are set using |
290 // the API defined in base/debug/crash_logging.h. | 327 // the API defined in base/debug/crash_logging.h. |
291 g_dynamic_keys_offset = g_custom_entries->size(); | 328 dynamic_keys_offset_ = custom_entries_.size(); |
292 for (size_t i = 0; i < kMaxDynamicEntries; ++i) { | 329 for (size_t i = 0; i < kMaxDynamicEntries; ++i) { |
293 // The names will be mutated as they are set. Un-numbered since these are | 330 // The names will be mutated as they are set. Un-numbered since these are |
294 // merely placeholders. The name cannot be empty because Breakpad's | 331 // merely placeholders. The name cannot be empty because Breakpad's |
295 // HTTPUpload will interpret that as an invalid parameter. | 332 // HTTPUpload will interpret that as an invalid parameter. |
296 g_custom_entries->push_back( | 333 custom_entries_.push_back( |
297 google_breakpad::CustomInfoEntry(L"unspecified-crash-key", L"")); | 334 google_breakpad::CustomInfoEntry(L"unspecified-crash-key", L"")); |
298 } | 335 } |
299 | 336 |
300 g_dynamic_entries_lock = new base::Lock; | |
301 g_dynamic_entries = new DynamicEntriesMap; | |
302 | |
303 static google_breakpad::CustomClientInfo custom_client_info; | 337 static google_breakpad::CustomClientInfo custom_client_info; |
304 custom_client_info.entries = &g_custom_entries->front(); | 338 custom_client_info.entries = &custom_entries_.front(); |
305 custom_client_info.count = g_custom_entries->size(); | 339 custom_client_info.count = custom_entries_.size(); |
306 | 340 |
307 return &custom_client_info; | 341 return &custom_client_info; |
308 } | 342 } |
309 | 343 |
| 344 namespace { |
| 345 |
310 // This callback is used when we want to get a dump without crashing the | 346 // This callback is used when we want to get a dump without crashing the |
311 // process. | 347 // process. |
312 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, | 348 bool DumpDoneCallbackWhenNoCrash(const wchar_t*, const wchar_t*, void*, |
313 EXCEPTION_POINTERS* ex_info, | 349 EXCEPTION_POINTERS* ex_info, |
314 MDRawAssertionInfo*, bool) { | 350 MDRawAssertionInfo*, bool) { |
315 return true; | 351 return true; |
316 } | 352 } |
317 | 353 |
318 // This callback is executed when the browser process has crashed, after | 354 // This callback is executed when the browser process has crashed, after |
319 // the crash dump has been created. We need to minimize the amount of work | 355 // the crash dump has been created. We need to minimize the amount of work |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 } | 425 } |
390 | 426 |
391 // Exception filter for the service process used when breakpad is not enabled. | 427 // Exception filter for the service process used when breakpad is not enabled. |
392 // We just display the "Do you want to restart" message and then die | 428 // We just display the "Do you want to restart" message and then die |
393 // (without calling the previous filter). | 429 // (without calling the previous filter). |
394 long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) { | 430 long WINAPI ServiceExceptionFilter(EXCEPTION_POINTERS* info) { |
395 DumpDoneCallback(NULL, NULL, NULL, info, NULL, false); | 431 DumpDoneCallback(NULL, NULL, NULL, info, NULL, false); |
396 return EXCEPTION_EXECUTE_HANDLER; | 432 return EXCEPTION_EXECUTE_HANDLER; |
397 } | 433 } |
398 | 434 |
399 // NOTE: This function is used by SyzyASAN to annotate crash reports. If you | 435 } // namespace |
400 // change the name or signature of this function you will break SyzyASAN | |
401 // instrumented releases of Chrome. Please contact syzygy-team@chromium.org | |
402 // before doing so! | |
403 extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl( | |
404 const wchar_t* key, const wchar_t* value) { | |
405 if (!g_dynamic_entries) | |
406 return; | |
407 | 436 |
| 437 void CrashKeysWin::SetCrashKeyValue( |
| 438 const std::wstring& key, const std::wstring& value) { |
408 // CustomInfoEntry limits the length of key and value. If they exceed | 439 // CustomInfoEntry limits the length of key and value. If they exceed |
409 // their maximum length the underlying string handling functions raise | 440 // their maximum length the underlying string handling functions raise |
410 // an exception and prematurely trigger a crash. Truncate here. | 441 // an exception and prematurely trigger a crash. Truncate here. |
411 std::wstring safe_key(std::wstring(key).substr( | 442 std::wstring safe_key(std::wstring(key).substr( |
412 0, google_breakpad::CustomInfoEntry::kNameMaxLength - 1)); | 443 0, google_breakpad::CustomInfoEntry::kNameMaxLength - 1)); |
413 std::wstring safe_value(std::wstring(value).substr( | 444 std::wstring safe_value(std::wstring(value).substr( |
414 0, google_breakpad::CustomInfoEntry::kValueMaxLength - 1)); | 445 0, google_breakpad::CustomInfoEntry::kValueMaxLength - 1)); |
415 | 446 |
416 // If we already have a value for this key, update it; otherwise, insert | 447 // If we already have a value for this key, update it; otherwise, insert |
417 // the new value if we have not exhausted the pre-allocated slots for dynamic | 448 // the new value if we have not exhausted the pre-allocated slots for dynamic |
418 // entries. | 449 // entries. |
419 DCHECK(g_dynamic_entries_lock); | 450 base::AutoLock lock(lock_); |
420 base::AutoLock lock(*g_dynamic_entries_lock); | |
421 | 451 |
422 DynamicEntriesMap::iterator it = g_dynamic_entries->find(safe_key); | 452 DynamicEntriesMap::iterator it = dynamic_entries_.find(safe_key); |
423 google_breakpad::CustomInfoEntry* entry = NULL; | 453 google_breakpad::CustomInfoEntry* entry = NULL; |
424 if (it == g_dynamic_entries->end()) { | 454 if (it == dynamic_entries_.end()) { |
425 if (g_dynamic_entries->size() >= kMaxDynamicEntries) | 455 if (dynamic_entries_.size() >= kMaxDynamicEntries) |
426 return; | 456 return; |
427 entry = &(*g_custom_entries)[g_dynamic_keys_offset++]; | 457 entry = &custom_entries_[dynamic_keys_offset_++]; |
428 g_dynamic_entries->insert(std::make_pair(safe_key, entry)); | 458 dynamic_entries_.insert(std::make_pair(safe_key, entry)); |
429 } else { | 459 } else { |
430 entry = it->second; | 460 entry = it->second; |
431 } | 461 } |
432 | 462 |
433 entry->set(safe_key.data(), safe_value.data()); | 463 entry->set(safe_key.data(), safe_value.data()); |
434 } | 464 } |
435 | 465 |
436 extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl( | 466 // NOTE: This function is used by SyzyASAN to annotate crash reports. If you |
437 const wchar_t* key) { | 467 // change the name or signature of this function you will break SyzyASAN |
438 if (!g_dynamic_entries) | 468 // instrumented releases of Chrome. Please contact syzygy-team@chromium.org |
| 469 // before doing so! |
| 470 extern "C" void __declspec(dllexport) __cdecl SetCrashKeyValueImpl( |
| 471 const wchar_t* key, const wchar_t* value) { |
| 472 CrashKeysWin* keeper = CrashKeysWin::keeper(); |
| 473 if (!keeper) |
439 return; | 474 return; |
440 | 475 |
441 DCHECK(g_dynamic_entries_lock); | 476 // TODO(siggi): This doesn't look quite right - there's NULL deref potential |
442 base::AutoLock lock(*g_dynamic_entries_lock); | 477 // here, and an implicit std::wstring conversion. Fixme. |
| 478 keeper->SetCrashKeyValue(key, value); |
| 479 } |
| 480 |
| 481 void CrashKeysWin::ClearCrashKeyValue(const std::wstring& key) { |
| 482 base::AutoLock lock(lock_); |
443 | 483 |
444 std::wstring key_string(key); | 484 std::wstring key_string(key); |
445 DynamicEntriesMap::iterator it = g_dynamic_entries->find(key_string); | 485 DynamicEntriesMap::iterator it = dynamic_entries_.find(key_string); |
446 if (it == g_dynamic_entries->end()) | 486 if (it == dynamic_entries_.end()) |
447 return; | 487 return; |
448 | 488 |
449 it->second->set_value(NULL); | 489 it->second->set_value(NULL); |
450 } | 490 } |
451 | 491 |
452 } // namespace | 492 extern "C" void __declspec(dllexport) __cdecl ClearCrashKeyValueImpl( |
| 493 const wchar_t* key) { |
| 494 CrashKeysWin* keeper = CrashKeysWin::keeper(); |
| 495 if (!keeper) |
| 496 return; |
| 497 |
| 498 // TODO(siggi): This doesn't look quite right - there's NULL deref potential |
| 499 // here, and an implicit std::wstring conversion. Fixme. |
| 500 keeper->ClearCrashKeyValue(key); |
| 501 } |
453 | 502 |
454 static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption, | 503 static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption, |
455 UINT flags, bool* exit_now) { | 504 UINT flags, bool* exit_now) { |
456 // We wrap the call to MessageBoxW with a SEH handler because it some | 505 // We wrap the call to MessageBoxW with a SEH handler because it some |
457 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes | 506 // machines with CursorXP, PeaDict or with FontExplorer installed it crashes |
458 // uncontrollably here. Being this a best effort deal we better go away. | 507 // uncontrollably here. Being this a best effort deal we better go away. |
459 __try { | 508 __try { |
460 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags)); | 509 *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags)); |
461 } __except(EXCEPTION_EXECUTE_HANDLER) { | 510 } __except(EXCEPTION_EXECUTE_HANDLER) { |
462 // Its not safe to continue executing, exit silently here. | 511 // Its not safe to continue executing, exit silently here. |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 if (process_type.empty()) | 702 if (process_type.empty()) |
654 process_type = L"browser"; | 703 process_type = L"browser"; |
655 | 704 |
656 wchar_t exe_path[MAX_PATH]; | 705 wchar_t exe_path[MAX_PATH]; |
657 exe_path[0] = 0; | 706 exe_path[0] = 0; |
658 GetModuleFileNameW(NULL, exe_path, MAX_PATH); | 707 GetModuleFileNameW(NULL, exe_path, MAX_PATH); |
659 | 708 |
660 bool is_per_user_install = | 709 bool is_per_user_install = |
661 GetBreakpadClient()->GetIsPerUserInstall(base::FilePath(exe_path)); | 710 GetBreakpadClient()->GetIsPerUserInstall(base::FilePath(exe_path)); |
662 | 711 |
| 712 // This is intentionally leaked. |
| 713 CrashKeysWin* keeper = new CrashKeysWin(); |
| 714 |
663 google_breakpad::CustomClientInfo* custom_info = | 715 google_breakpad::CustomClientInfo* custom_info = |
664 GetCustomInfo(exe_path, process_type); | 716 keeper->GetCustomInfo(exe_path, process_type); |
665 | 717 |
666 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; | 718 google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL; |
667 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; | 719 LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL; |
668 // We install the post-dump callback only for the browser and service | 720 // We install the post-dump callback only for the browser and service |
669 // processes. It spawns a new browser/service process. | 721 // processes. It spawns a new browser/service process. |
670 if (process_type == L"browser") { | 722 if (process_type == L"browser") { |
671 callback = &DumpDoneCallback; | 723 callback = &DumpDoneCallback; |
672 default_filter = &ChromeExceptionFilter; | 724 default_filter = &ChromeExceptionFilter; |
673 } else if (process_type == L"service") { | 725 } else if (process_type == L"service") { |
674 callback = &DumpDoneCallback; | 726 callback = &DumpDoneCallback; |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
741 if (process_type != L"browser" && | 793 if (process_type != L"browser" && |
742 !GetBreakpadClient()->IsRunningUnattended()) { | 794 !GetBreakpadClient()->IsRunningUnattended()) { |
743 // Initialize the hook TerminateProcess to catch unexpected exits. | 795 // Initialize the hook TerminateProcess to catch unexpected exits. |
744 InitTerminateProcessHooks(); | 796 InitTerminateProcessHooks(); |
745 } | 797 } |
746 #endif | 798 #endif |
747 } | 799 } |
748 } | 800 } |
749 | 801 |
750 } // namespace breakpad | 802 } // namespace breakpad |
OLD | NEW |