Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(127)

Side by Side Diff: components/breakpad/app/breakpad_win.cc

Issue 302033002: Refactor the breakpad Windows key/value stash, step one. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase to ToT. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698