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