OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006, Google Inc. | |
2 // All rights reserved. | |
3 // | |
4 // Redistribution and use in source and binary forms, with or without | |
5 // modification, are permitted provided that the following conditions are | |
6 // met: | |
7 // | |
8 // * Redistributions of source code must retain the above copyright | |
9 // notice, this list of conditions and the following disclaimer. | |
10 // * Redistributions in binary form must reproduce the above | |
11 // copyright notice, this list of conditions and the following disclaimer | |
12 // in the documentation and/or other materials provided with the | |
13 // distribution. | |
14 // * Neither the name of Google Inc. nor the names of its | |
15 // contributors may be used to endorse or promote products derived from | |
16 // this software without specific prior written permission. | |
17 // | |
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 | |
30 #include <ObjBase.h> | |
31 | |
32 #include <algorithm> | |
33 #include <cassert> | |
34 #include <cstdio> | |
35 | |
36 #include "common/windows/string_utils-inl.h" | |
37 | |
38 #include "client/windows/common/ipc_protocol.h" | |
39 #include "client/windows/handler/exception_handler.h" | |
40 #include "common/windows/guid_string.h" | |
41 | |
42 typedef VOID (WINAPI *RtlCaptureContextPtr) (PCONTEXT pContextRecord); | |
43 | |
44 namespace google_breakpad { | |
45 | |
46 static const int kWaitForHandlerThreadMs = 60000; | |
47 static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024; | |
48 | |
49 // This is passed as the context to the MinidumpWriteDump callback. | |
50 typedef struct { | |
51 ULONG64 memory_base; | |
52 ULONG memory_size; | |
53 bool finished; | |
54 } MinidumpCallbackContext; | |
55 | |
56 vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL; | |
57 LONG ExceptionHandler::handler_stack_index_ = 0; | |
58 CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_; | |
59 volatile LONG ExceptionHandler::instance_count_ = 0; | |
60 | |
61 ExceptionHandler::ExceptionHandler(const wstring& dump_path, | |
62 FilterCallback filter, | |
63 MinidumpCallback callback, | |
64 void* callback_context, | |
65 int handler_types, | |
66 MINIDUMP_TYPE dump_type, | |
67 const wchar_t* pipe_name, | |
68 const CustomClientInfo* custom_info) { | |
69 Initialize(dump_path, | |
70 filter, | |
71 callback, | |
72 callback_context, | |
73 handler_types, | |
74 dump_type, | |
75 pipe_name, | |
76 custom_info); | |
77 } | |
78 | |
79 ExceptionHandler::ExceptionHandler(const wstring &dump_path, | |
80 FilterCallback filter, | |
81 MinidumpCallback callback, | |
82 void* callback_context, | |
83 int handler_types) { | |
84 Initialize(dump_path, | |
85 filter, | |
86 callback, | |
87 callback_context, | |
88 handler_types, | |
89 MiniDumpNormal, | |
90 NULL, | |
91 NULL); | |
92 } | |
93 | |
94 void ExceptionHandler::Initialize(const wstring& dump_path, | |
95 FilterCallback filter, | |
96 MinidumpCallback callback, | |
97 void* callback_context, | |
98 int handler_types, | |
99 MINIDUMP_TYPE dump_type, | |
100 const wchar_t* pipe_name, | |
101 const CustomClientInfo* custom_info) { | |
102 LONG instance_count = InterlockedIncrement(&instance_count_); | |
103 filter_ = filter; | |
104 callback_ = callback; | |
105 callback_context_ = callback_context; | |
106 dump_path_c_ = NULL; | |
107 next_minidump_id_c_ = NULL; | |
108 next_minidump_path_c_ = NULL; | |
109 dbghelp_module_ = NULL; | |
110 minidump_write_dump_ = NULL; | |
111 dump_type_ = dump_type; | |
112 rpcrt4_module_ = NULL; | |
113 uuid_create_ = NULL; | |
114 handler_types_ = handler_types; | |
115 previous_filter_ = NULL; | |
116 #if _MSC_VER >= 1400 // MSVC 2005/8 | |
117 previous_iph_ = NULL; | |
118 #endif // _MSC_VER >= 1400 | |
119 previous_pch_ = NULL; | |
120 handler_thread_ = NULL; | |
121 is_shutdown_ = false; | |
122 handler_start_semaphore_ = NULL; | |
123 handler_finish_semaphore_ = NULL; | |
124 requesting_thread_id_ = 0; | |
125 exception_info_ = NULL; | |
126 assertion_ = NULL; | |
127 handler_return_value_ = false; | |
128 handle_debug_exceptions_ = false; | |
129 | |
130 // Attempt to use out-of-process if user has specified pipe name. | |
131 if (pipe_name != NULL) { | |
132 scoped_ptr<CrashGenerationClient> client( | |
133 new CrashGenerationClient(pipe_name, | |
134 dump_type_, | |
135 custom_info)); | |
136 | |
137 // If successful in registering with the monitoring process, | |
138 // there is no need to setup in-process crash generation. | |
139 if (client->Register()) { | |
140 crash_generation_client_.reset(client.release()); | |
141 } | |
142 } | |
143 | |
144 if (!IsOutOfProcess()) { | |
145 // Either client did not ask for out-of-process crash generation | |
146 // or registration with the server process failed. In either case, | |
147 // setup to do in-process crash generation. | |
148 | |
149 // Set synchronization primitives and the handler thread. Each | |
150 // ExceptionHandler object gets its own handler thread because that's the | |
151 // only way to reliably guarantee sufficient stack space in an exception, | |
152 // and it allows an easy way to get a snapshot of the requesting thread's | |
153 // context outside of an exception. | |
154 InitializeCriticalSection(&handler_critical_section_); | |
155 handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); | |
156 assert(handler_start_semaphore_ != NULL); | |
157 | |
158 handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); | |
159 assert(handler_finish_semaphore_ != NULL); | |
160 | |
161 // Don't attempt to create the thread if we could not create the semaphores. | |
162 if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) { | |
163 DWORD thread_id; | |
164 handler_thread_ = CreateThread(NULL, // lpThreadAttributes | |
165 kExceptionHandlerThreadInitialStackSize, | |
166 ExceptionHandlerThreadMain, | |
167 this, // lpParameter | |
168 0, // dwCreationFlags | |
169 &thread_id); | |
170 assert(handler_thread_ != NULL); | |
171 } | |
172 | |
173 dbghelp_module_ = LoadLibrary(L"dbghelp.dll"); | |
174 if (dbghelp_module_) { | |
175 minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>( | |
176 GetProcAddress(dbghelp_module_, "MiniDumpWriteDump")); | |
177 } | |
178 | |
179 // Load this library dynamically to not affect existing projects. Most | |
180 // projects don't link against this directly, it's usually dynamically | |
181 // loaded by dependent code. | |
182 rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll"); | |
183 if (rpcrt4_module_) { | |
184 uuid_create_ = reinterpret_cast<UuidCreate_type>( | |
185 GetProcAddress(rpcrt4_module_, "UuidCreate")); | |
186 } | |
187 | |
188 // set_dump_path calls UpdateNextID. This sets up all of the path and id | |
189 // strings, and their equivalent c_str pointers. | |
190 set_dump_path(dump_path); | |
191 } | |
192 | |
193 // There is a race condition here. If the first instance has not yet | |
194 // initialized the critical section, the second (and later) instances may | |
195 // try to use uninitialized critical section object. The feature of multiple | |
196 // instances in one module is not used much, so leave it as is for now. | |
197 // One way to solve this in the current design (that is, keeping the static | |
198 // handler stack) is to use spin locks with volatile bools to synchronize | |
199 // the handler stack. This works only if the compiler guarantees to generate | |
200 // cache coherent code for volatile. | |
201 // TODO(munjal): Fix this in a better way by changing the design if possible. | |
202 | |
203 // Lazy initialization of the handler_stack_critical_section_ | |
204 if (instance_count == 1) { | |
205 InitializeCriticalSection(&handler_stack_critical_section_); | |
206 } | |
207 | |
208 if (handler_types != HANDLER_NONE) { | |
209 EnterCriticalSection(&handler_stack_critical_section_); | |
210 | |
211 // The first time an ExceptionHandler that installs a handler is | |
212 // created, set up the handler stack. | |
213 if (!handler_stack_) { | |
214 handler_stack_ = new vector<ExceptionHandler*>(); | |
215 } | |
216 handler_stack_->push_back(this); | |
217 | |
218 if (handler_types & HANDLER_EXCEPTION) | |
219 previous_filter_ = SetUnhandledExceptionFilter(HandleException); | |
220 | |
221 #if _MSC_VER >= 1400 // MSVC 2005/8 | |
222 if (handler_types & HANDLER_INVALID_PARAMETER) | |
223 previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter); | |
224 #endif // _MSC_VER >= 1400 | |
225 | |
226 if (handler_types & HANDLER_PURECALL) | |
227 previous_pch_ = _set_purecall_handler(HandlePureVirtualCall); | |
228 | |
229 LeaveCriticalSection(&handler_stack_critical_section_); | |
230 } | |
231 } | |
232 | |
233 ExceptionHandler::~ExceptionHandler() { | |
234 if (dbghelp_module_) { | |
235 FreeLibrary(dbghelp_module_); | |
236 } | |
237 | |
238 if (rpcrt4_module_) { | |
239 FreeLibrary(rpcrt4_module_); | |
240 } | |
241 | |
242 if (handler_types_ != HANDLER_NONE) { | |
243 EnterCriticalSection(&handler_stack_critical_section_); | |
244 | |
245 if (handler_types_ & HANDLER_EXCEPTION) | |
246 SetUnhandledExceptionFilter(previous_filter_); | |
247 | |
248 #if _MSC_VER >= 1400 // MSVC 2005/8 | |
249 if (handler_types_ & HANDLER_INVALID_PARAMETER) | |
250 _set_invalid_parameter_handler(previous_iph_); | |
251 #endif // _MSC_VER >= 1400 | |
252 | |
253 if (handler_types_ & HANDLER_PURECALL) | |
254 _set_purecall_handler(previous_pch_); | |
255 | |
256 if (handler_stack_->back() == this) { | |
257 handler_stack_->pop_back(); | |
258 } else { | |
259 // TODO(mmentovai): use advapi32!ReportEvent to log the warning to the | |
260 // system's application event log. | |
261 fprintf(stderr, "warning: removing Breakpad handler out of order\n"); | |
262 vector<ExceptionHandler*>::iterator iterator = handler_stack_->begin(); | |
263 while (iterator != handler_stack_->end()) { | |
264 if (*iterator == this) { | |
265 iterator = handler_stack_->erase(iterator); | |
266 } else { | |
267 ++iterator; | |
268 } | |
269 } | |
270 } | |
271 | |
272 if (handler_stack_->empty()) { | |
273 // When destroying the last ExceptionHandler that installed a handler, | |
274 // clean up the handler stack. | |
275 delete handler_stack_; | |
276 handler_stack_ = NULL; | |
277 } | |
278 | |
279 LeaveCriticalSection(&handler_stack_critical_section_); | |
280 } | |
281 | |
282 // Some of the objects were only initialized if out of process | |
283 // registration was not done. | |
284 if (!IsOutOfProcess()) { | |
285 #ifdef BREAKPAD_NO_TERMINATE_THREAD | |
286 // Clean up the handler thread and synchronization primitives. The handler | |
287 // thread is either waiting on the semaphore to handle a crash or it is | |
288 // handling a crash. Coming out of the wait is fast but wait more in the | |
289 // eventuality a crash is handled. This compilation option results in a | |
290 // deadlock if the exception handler is destroyed while executing code | |
291 // inside DllMain. | |
292 is_shutdown_ = true; | |
293 ReleaseSemaphore(handler_start_semaphore_, 1, NULL); | |
294 WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs); | |
295 #else | |
296 TerminateThread(handler_thread_, 1); | |
297 #endif // BREAKPAD_NO_TERMINATE_THREAD | |
298 | |
299 CloseHandle(handler_thread_); | |
300 handler_thread_ = NULL; | |
301 DeleteCriticalSection(&handler_critical_section_); | |
302 CloseHandle(handler_start_semaphore_); | |
303 CloseHandle(handler_finish_semaphore_); | |
304 } | |
305 | |
306 // There is a race condition in the code below: if this instance is | |
307 // deleting the static critical section and a new instance of the class | |
308 // is created, then there is a possibility that the critical section be | |
309 // initialized while the same critical section is being deleted. Given the | |
310 // usage pattern for the code, this race condition is unlikely to hit, but it | |
311 // is a race condition nonetheless. | |
312 if (InterlockedDecrement(&instance_count_) == 0) { | |
313 DeleteCriticalSection(&handler_stack_critical_section_); | |
314 } | |
315 } | |
316 | |
317 // static | |
318 DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { | |
319 ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter); | |
320 assert(self); | |
321 assert(self->handler_start_semaphore_ != NULL); | |
322 assert(self->handler_finish_semaphore_ != NULL); | |
323 | |
324 while (true) { | |
325 if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) == | |
326 WAIT_OBJECT_0) { | |
327 // Perform the requested action. | |
328 if (self->is_shutdown_) { | |
329 // The instance of the exception handler is being destroyed. | |
330 break; | |
331 } else { | |
332 self->handler_return_value_ = | |
333 self->WriteMinidumpWithException(self->requesting_thread_id_, | |
334 self->exception_info_, | |
335 self->assertion_); | |
336 } | |
337 | |
338 // Allow the requesting thread to proceed. | |
339 ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL); | |
340 } | |
341 } | |
342 | |
343 // This statement is not reached when the thread is unconditionally | |
344 // terminated by the ExceptionHandler destructor. | |
345 return 0; | |
346 } | |
347 | |
348 // HandleException and HandleInvalidParameter must create an | |
349 // AutoExceptionHandler object to maintain static state and to determine which | |
350 // ExceptionHandler instance to use. The constructor locates the correct | |
351 // instance, and makes it available through get_handler(). The destructor | |
352 // restores the state in effect prior to allocating the AutoExceptionHandler. | |
353 class AutoExceptionHandler { | |
354 public: | |
355 AutoExceptionHandler() { | |
356 // Increment handler_stack_index_ so that if another Breakpad handler is | |
357 // registered using this same HandleException function, and it needs to be | |
358 // called while this handler is running (either because this handler | |
359 // declines to handle the exception, or an exception occurs during | |
360 // handling), HandleException will find the appropriate ExceptionHandler | |
361 // object in handler_stack_ to deliver the exception to. | |
362 // | |
363 // Because handler_stack_ is addressed in reverse (as |size - index|), | |
364 // preincrementing handler_stack_index_ avoids needing to subtract 1 from | |
365 // the argument to |at|. | |
366 // | |
367 // The index is maintained instead of popping elements off of the handler | |
368 // stack and pushing them at the end of this method. This avoids ruining | |
369 // the order of elements in the stack in the event that some other thread | |
370 // decides to manipulate the handler stack (such as creating a new | |
371 // ExceptionHandler object) while an exception is being handled. | |
372 EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_); | |
373 handler_ = ExceptionHandler::handler_stack_->at( | |
374 ExceptionHandler::handler_stack_->size() - | |
375 ++ExceptionHandler::handler_stack_index_); | |
376 | |
377 // In case another exception occurs while this handler is doing its thing, | |
378 // it should be delivered to the previous filter. | |
379 SetUnhandledExceptionFilter(handler_->previous_filter_); | |
380 #if _MSC_VER >= 1400 // MSVC 2005/8 | |
381 _set_invalid_parameter_handler(handler_->previous_iph_); | |
382 #endif // _MSC_VER >= 1400 | |
383 _set_purecall_handler(handler_->previous_pch_); | |
384 } | |
385 | |
386 ~AutoExceptionHandler() { | |
387 // Put things back the way they were before entering this handler. | |
388 SetUnhandledExceptionFilter(ExceptionHandler::HandleException); | |
389 #if _MSC_VER >= 1400 // MSVC 2005/8 | |
390 _set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter); | |
391 #endif // _MSC_VER >= 1400 | |
392 _set_purecall_handler(ExceptionHandler::HandlePureVirtualCall); | |
393 | |
394 --ExceptionHandler::handler_stack_index_; | |
395 LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_); | |
396 } | |
397 | |
398 ExceptionHandler* get_handler() const { return handler_; } | |
399 | |
400 private: | |
401 ExceptionHandler* handler_; | |
402 }; | |
403 | |
404 // static | |
405 LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) { | |
406 AutoExceptionHandler auto_exception_handler; | |
407 ExceptionHandler* current_handler = auto_exception_handler.get_handler(); | |
408 | |
409 // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions. This | |
410 // logic will short-circuit before calling WriteMinidumpOnHandlerThread, | |
411 // allowing something else to handle the breakpoint without incurring the | |
412 // overhead transitioning to and from the handler thread. This behavior | |
413 // can be overridden by calling ExceptionHandler::set_handle_debug_exceptions. | |
414 DWORD code = exinfo->ExceptionRecord->ExceptionCode; | |
415 LONG action; | |
416 bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) || | |
417 (code == EXCEPTION_SINGLE_STEP); | |
418 | |
419 bool success = false; | |
420 | |
421 if (!is_debug_exception || | |
422 current_handler->get_handle_debug_exceptions()) { | |
423 // If out-of-proc crash handler client is available, we have to use that | |
424 // to generate dump and we cannot fall back on in-proc dump generation | |
425 // because we never prepared for an in-proc dump generation | |
426 | |
427 // In case of out-of-process dump generation, directly call | |
428 // WriteMinidumpWithException since there is no separate thread running. | |
429 if (current_handler->IsOutOfProcess()) { | |
430 success = current_handler->WriteMinidumpWithException( | |
431 GetCurrentThreadId(), | |
432 exinfo, | |
433 NULL); | |
434 } else { | |
435 success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL); | |
436 } | |
437 } | |
438 | |
439 // The handler fully handled the exception. Returning | |
440 // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually | |
441 // results in the application being terminated. | |
442 // | |
443 // Note: If the application was launched from within the Cygwin | |
444 // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the | |
445 // application to be restarted. | |
446 if (success) { | |
447 action = EXCEPTION_EXECUTE_HANDLER; | |
448 } else { | |
449 // There was an exception, it was a breakpoint or something else ignored | |
450 // above, or it was passed to the handler, which decided not to handle it. | |
451 // This could be because the filter callback didn't want it, because | |
452 // minidump writing failed for some reason, or because the post-minidump | |
453 // callback function indicated failure. Give the previous handler a | |
454 // chance to do something with the exception. If there is no previous | |
455 // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger | |
456 // or native "crashed" dialog to handle the exception. | |
457 if (current_handler->previous_filter_) { | |
458 action = current_handler->previous_filter_(exinfo); | |
459 } else { | |
460 action = EXCEPTION_CONTINUE_SEARCH; | |
461 } | |
462 } | |
463 | |
464 return action; | |
465 } | |
466 | |
467 #if _MSC_VER >= 1400 // MSVC 2005/8 | |
468 // static | |
469 void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression, | |
470 const wchar_t* function, | |
471 const wchar_t* file, | |
472 unsigned int line, | |
473 uintptr_t reserved) { | |
474 // This is an invalid parameter, not an exception. It's safe to play with | |
475 // sprintf here. | |
476 AutoExceptionHandler auto_exception_handler; | |
477 ExceptionHandler* current_handler = auto_exception_handler.get_handler(); | |
478 | |
479 MDRawAssertionInfo assertion; | |
480 memset(&assertion, 0, sizeof(assertion)); | |
481 _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression), | |
482 sizeof(assertion.expression) / sizeof(assertion.expression[0]), | |
483 _TRUNCATE, L"%s", expression); | |
484 _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function), | |
485 sizeof(assertion.function) / sizeof(assertion.function[0]), | |
486 _TRUNCATE, L"%s", function); | |
487 _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file), | |
488 sizeof(assertion.file) / sizeof(assertion.file[0]), | |
489 _TRUNCATE, L"%s", file); | |
490 assertion.line = line; | |
491 assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER; | |
492 | |
493 // Make up an exception record for the current thread and CPU context | |
494 // to make it possible for the crash processor to classify these | |
495 // as do regular crashes, and to make it humane for developers to | |
496 // analyze them. | |
497 EXCEPTION_RECORD exception_record = {}; | |
498 CONTEXT exception_context = {}; | |
499 EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; | |
500 | |
501 EXCEPTION_POINTERS* exinfo = NULL; | |
502 | |
503 RtlCaptureContextPtr fnRtlCaptureContext = (RtlCaptureContextPtr) | |
504 GetProcAddress(GetModuleHandleW(L"kernel32"), "RtlCaptureContext"); | |
505 if (fnRtlCaptureContext) { | |
506 fnRtlCaptureContext(&exception_context); | |
507 | |
508 exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; | |
509 | |
510 // We store pointers to the the expression and function strings, | |
511 // and the line as exception parameters to make them easy to | |
512 // access by the developer on the far side. | |
513 exception_record.NumberParameters = 3; | |
514 exception_record.ExceptionInformation[0] = | |
515 reinterpret_cast<ULONG_PTR>(&assertion.expression); | |
516 exception_record.ExceptionInformation[1] = | |
517 reinterpret_cast<ULONG_PTR>(&assertion.file); | |
518 exception_record.ExceptionInformation[2] = assertion.line; | |
519 | |
520 exinfo = &exception_ptrs; | |
521 } | |
522 | |
523 bool success = false; | |
524 // In case of out-of-process dump generation, directly call | |
525 // WriteMinidumpWithException since there is no separate thread running. | |
526 if (current_handler->IsOutOfProcess()) { | |
527 success = current_handler->WriteMinidumpWithException( | |
528 GetCurrentThreadId(), | |
529 exinfo, | |
530 &assertion); | |
531 } else { | |
532 success = current_handler->WriteMinidumpOnHandlerThread(exinfo, | |
533 &assertion); | |
534 } | |
535 | |
536 if (!success) { | |
537 if (current_handler->previous_iph_) { | |
538 // The handler didn't fully handle the exception. Give it to the | |
539 // previous invalid parameter handler. | |
540 current_handler->previous_iph_(expression, | |
541 function, | |
542 file, | |
543 line, | |
544 reserved); | |
545 } else { | |
546 // If there's no previous handler, pass the exception back in to the | |
547 // invalid parameter handler's core. That's the routine that called this | |
548 // function, but now, since this function is no longer registered (and in | |
549 // fact, no function at all is registered), this will result in the | |
550 // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson. | |
551 // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes | |
552 // more information through. In non-debug builds, it is not available, | |
553 // so fall back to using _invalid_parameter_noinfo. See invarg.c in the | |
554 // CRT source. | |
555 #ifdef _DEBUG | |
556 _invalid_parameter(expression, function, file, line, reserved); | |
557 #else // _DEBUG | |
558 _invalid_parameter_noinfo(); | |
559 #endif // _DEBUG | |
560 } | |
561 } | |
562 | |
563 // The handler either took care of the invalid parameter problem itself, | |
564 // or passed it on to another handler. "Swallow" it by exiting, paralleling | |
565 // the behavior of "swallowing" exceptions. | |
566 exit(0); | |
567 } | |
568 #endif // _MSC_VER >= 1400 | |
569 | |
570 // static | |
571 void ExceptionHandler::HandlePureVirtualCall() { | |
572 // This is an pure virtual function call, not an exception. It's safe to | |
573 // play with sprintf here. | |
574 AutoExceptionHandler auto_exception_handler; | |
575 ExceptionHandler* current_handler = auto_exception_handler.get_handler(); | |
576 | |
577 MDRawAssertionInfo assertion; | |
578 memset(&assertion, 0, sizeof(assertion)); | |
579 assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL; | |
580 | |
581 // Make up an exception record for the current thread and CPU context | |
582 // to make it possible for the crash processor to classify these | |
583 // as do regular crashes, and to make it humane for developers to | |
584 // analyze them. | |
585 EXCEPTION_RECORD exception_record = {}; | |
586 CONTEXT exception_context = {}; | |
587 EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; | |
588 | |
589 EXCEPTION_POINTERS* exinfo = NULL; | |
590 | |
591 RtlCaptureContextPtr fnRtlCaptureContext = (RtlCaptureContextPtr) | |
592 GetProcAddress(GetModuleHandleW(L"kernel32"), "RtlCaptureContext"); | |
593 if (fnRtlCaptureContext) { | |
594 fnRtlCaptureContext(&exception_context); | |
595 | |
596 exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; | |
597 | |
598 // We store pointers to the the expression and function strings, | |
599 // and the line as exception parameters to make them easy to | |
600 // access by the developer on the far side. | |
601 exception_record.NumberParameters = 3; | |
602 exception_record.ExceptionInformation[0] = | |
603 reinterpret_cast<ULONG_PTR>(&assertion.expression); | |
604 exception_record.ExceptionInformation[1] = | |
605 reinterpret_cast<ULONG_PTR>(&assertion.file); | |
606 exception_record.ExceptionInformation[2] = assertion.line; | |
607 | |
608 exinfo = &exception_ptrs; | |
609 } | |
610 | |
611 bool success = false; | |
612 // In case of out-of-process dump generation, directly call | |
613 // WriteMinidumpWithException since there is no separate thread running. | |
614 | |
615 if (current_handler->IsOutOfProcess()) { | |
616 success = current_handler->WriteMinidumpWithException( | |
617 GetCurrentThreadId(), | |
618 exinfo, | |
619 &assertion); | |
620 } else { | |
621 success = current_handler->WriteMinidumpOnHandlerThread(exinfo, | |
622 &assertion); | |
623 } | |
624 | |
625 if (!success) { | |
626 if (current_handler->previous_pch_) { | |
627 // The handler didn't fully handle the exception. Give it to the | |
628 // previous purecall handler. | |
629 current_handler->previous_pch_(); | |
630 } else { | |
631 // If there's no previous handler, return and let _purecall handle it. | |
632 // This will just put up an assertion dialog. | |
633 return; | |
634 } | |
635 } | |
636 | |
637 // The handler either took care of the invalid parameter problem itself, | |
638 // or passed it on to another handler. "Swallow" it by exiting, paralleling | |
639 // the behavior of "swallowing" exceptions. | |
640 exit(0); | |
641 } | |
642 | |
643 bool ExceptionHandler::WriteMinidumpOnHandlerThread( | |
644 EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) { | |
645 EnterCriticalSection(&handler_critical_section_); | |
646 | |
647 // There isn't much we can do if the handler thread | |
648 // was not successfully created. | |
649 if (handler_thread_ == NULL) { | |
650 LeaveCriticalSection(&handler_critical_section_); | |
651 return false; | |
652 } | |
653 | |
654 // The handler thread should only be created when the semaphores are valid. | |
655 assert(handler_start_semaphore_ != NULL); | |
656 assert(handler_finish_semaphore_ != NULL); | |
657 | |
658 // Set up data to be passed in to the handler thread. | |
659 requesting_thread_id_ = GetCurrentThreadId(); | |
660 exception_info_ = exinfo; | |
661 assertion_ = assertion; | |
662 | |
663 // This causes the handler thread to call WriteMinidumpWithException. | |
664 ReleaseSemaphore(handler_start_semaphore_, 1, NULL); | |
665 | |
666 // Wait until WriteMinidumpWithException is done and collect its return value. | |
667 WaitForSingleObject(handler_finish_semaphore_, INFINITE); | |
668 bool status = handler_return_value_; | |
669 | |
670 // Clean up. | |
671 requesting_thread_id_ = 0; | |
672 exception_info_ = NULL; | |
673 assertion_ = NULL; | |
674 | |
675 LeaveCriticalSection(&handler_critical_section_); | |
676 | |
677 return status; | |
678 } | |
679 | |
680 bool ExceptionHandler::WriteMinidump() { | |
681 return WriteMinidumpForException(NULL); | |
682 } | |
683 | |
684 bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) { | |
685 // In case of out-of-process dump generation, directly call | |
686 // WriteMinidumpWithException since there is no separate thread running. | |
687 if (IsOutOfProcess()) { | |
688 return WriteMinidumpWithException(GetCurrentThreadId(), | |
689 exinfo, | |
690 NULL); | |
691 } | |
692 | |
693 bool success = WriteMinidumpOnHandlerThread(exinfo, NULL); | |
694 UpdateNextID(); | |
695 return success; | |
696 } | |
697 | |
698 // static | |
699 bool ExceptionHandler::WriteMinidump(const wstring &dump_path, | |
700 MinidumpCallback callback, | |
701 void* callback_context) { | |
702 ExceptionHandler handler(dump_path, NULL, callback, callback_context, | |
703 HANDLER_NONE); | |
704 return handler.WriteMinidump(); | |
705 } | |
706 | |
707 bool ExceptionHandler::WriteMinidumpWithException( | |
708 DWORD requesting_thread_id, | |
709 EXCEPTION_POINTERS* exinfo, | |
710 MDRawAssertionInfo* assertion) { | |
711 // Give user code a chance to approve or prevent writing a minidump. If the | |
712 // filter returns false, don't handle the exception at all. If this method | |
713 // was called as a result of an exception, returning false will cause | |
714 // HandleException to call any previous handler or return | |
715 // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear | |
716 // as though this handler were not present at all. | |
717 if (filter_ && !filter_(callback_context_, exinfo, assertion)) { | |
718 return false; | |
719 } | |
720 | |
721 bool success = false; | |
722 if (IsOutOfProcess()) { | |
723 success = crash_generation_client_->RequestDump(exinfo, assertion); | |
724 } else { | |
725 if (minidump_write_dump_) { | |
726 HANDLE dump_file = CreateFile(next_minidump_path_c_, | |
727 GENERIC_WRITE, | |
728 0, // no sharing | |
729 NULL, | |
730 CREATE_NEW, // fail if exists | |
731 FILE_ATTRIBUTE_NORMAL, | |
732 NULL); | |
733 if (dump_file != INVALID_HANDLE_VALUE) { | |
734 MINIDUMP_EXCEPTION_INFORMATION except_info; | |
735 except_info.ThreadId = requesting_thread_id; | |
736 except_info.ExceptionPointers = exinfo; | |
737 except_info.ClientPointers = FALSE; | |
738 | |
739 // Add an MDRawBreakpadInfo stream to the minidump, to provide | |
740 // additional information about the exception handler to the Breakpad | |
741 // processor. The information will help the processor determine which | |
742 // threads are relevant. The Breakpad processor does not require this | |
743 // information but can function better with Breakpad-generated dumps | |
744 // when it is present. The native debugger is not harmed by the | |
745 // presence of this information. | |
746 MDRawBreakpadInfo breakpad_info; | |
747 breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | | |
748 MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; | |
749 breakpad_info.dump_thread_id = GetCurrentThreadId(); | |
750 breakpad_info.requesting_thread_id = requesting_thread_id; | |
751 | |
752 // Leave room in user_stream_array for a possible assertion info stream. | |
753 MINIDUMP_USER_STREAM user_stream_array[2]; | |
754 user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM; | |
755 user_stream_array[0].BufferSize = sizeof(breakpad_info); | |
756 user_stream_array[0].Buffer = &breakpad_info; | |
757 | |
758 MINIDUMP_USER_STREAM_INFORMATION user_streams; | |
759 user_streams.UserStreamCount = 1; | |
760 user_streams.UserStreamArray = user_stream_array; | |
761 | |
762 if (assertion) { | |
763 user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM; | |
764 user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo); | |
765 user_stream_array[1].Buffer = assertion; | |
766 ++user_streams.UserStreamCount; | |
767 } | |
768 | |
769 MINIDUMP_CALLBACK_INFORMATION callback; | |
770 MinidumpCallbackContext context; | |
771 MINIDUMP_CALLBACK_INFORMATION* callback_pointer = NULL; | |
772 // Older versions of DbgHelp.dll don't correctly put the memory around | |
773 // the faulting instruction pointer into the minidump. This | |
774 // callback will ensure that it gets included. | |
775 if (exinfo) { | |
776 // Find a memory region of 256 bytes centered on the | |
777 // faulting instruction pointer. | |
778 const ULONG64 instruction_pointer = | |
779 #if defined(_M_IX86) | |
780 exinfo->ContextRecord->Eip; | |
781 #elif defined(_M_AMD64) | |
782 exinfo->ContextRecord->Rip; | |
783 #else | |
784 #error Unsupported platform | |
785 #endif | |
786 | |
787 MEMORY_BASIC_INFORMATION info; | |
788 if (VirtualQuery(reinterpret_cast<LPCVOID>(instruction_pointer), | |
789 &info, | |
790 sizeof(MEMORY_BASIC_INFORMATION)) != 0 && | |
791 info.State == MEM_COMMIT) { | |
792 // Attempt to get 128 bytes before and after the instruction | |
793 // pointer, but settle for whatever's available up to the | |
794 // boundaries of the memory region. | |
795 const ULONG64 kIPMemorySize = 256; | |
796 context.memory_base = | |
797 (std::max)(reinterpret_cast<ULONG64>(info.BaseAddress), | |
798 instruction_pointer - (kIPMemorySize / 2)); | |
799 ULONG64 end_of_range = | |
800 (std::min)(instruction_pointer + (kIPMemorySize / 2), | |
801 reinterpret_cast<ULONG64>(info.BaseAddress) | |
802 + info.RegionSize); | |
803 context.memory_size = | |
804 static_cast<ULONG>(end_of_range - context.memory_base); | |
805 | |
806 context.finished = false; | |
807 callback.CallbackRoutine = MinidumpWriteDumpCallback; | |
808 callback.CallbackParam = reinterpret_cast<void*>(&context); | |
809 callback_pointer = &callback; | |
810 } | |
811 } | |
812 | |
813 // The explicit comparison to TRUE avoids a warning (C4800). | |
814 success = (minidump_write_dump_(GetCurrentProcess(), | |
815 GetCurrentProcessId(), | |
816 dump_file, | |
817 dump_type_, | |
818 exinfo ? &except_info : NULL, | |
819 &user_streams, | |
820 callback_pointer) == TRUE); | |
821 | |
822 CloseHandle(dump_file); | |
823 } | |
824 } | |
825 } | |
826 | |
827 if (callback_) { | |
828 // TODO(munjal): In case of out-of-process dump generation, both | |
829 // dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process | |
830 // scenario, the server process ends up creating the dump path and dump | |
831 // id so they are not known to the client. | |
832 success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_, | |
833 exinfo, assertion, success); | |
834 } | |
835 | |
836 return success; | |
837 } | |
838 | |
839 // static | |
840 BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback( | |
841 PVOID context, | |
842 const PMINIDUMP_CALLBACK_INPUT callback_input, | |
843 PMINIDUMP_CALLBACK_OUTPUT callback_output) { | |
844 switch (callback_input->CallbackType) { | |
845 case MemoryCallback: { | |
846 MinidumpCallbackContext* callback_context = | |
847 reinterpret_cast<MinidumpCallbackContext*>(context); | |
848 if (callback_context->finished) | |
849 return FALSE; | |
850 | |
851 // Include the specified memory region. | |
852 callback_output->MemoryBase = callback_context->memory_base; | |
853 callback_output->MemorySize = callback_context->memory_size; | |
854 callback_context->finished = true; | |
855 return TRUE; | |
856 } | |
857 | |
858 // Include all modules. | |
859 case IncludeModuleCallback: | |
860 case ModuleCallback: | |
861 return TRUE; | |
862 | |
863 // Include all threads. | |
864 case IncludeThreadCallback: | |
865 case ThreadCallback: | |
866 return TRUE; | |
867 | |
868 // Stop receiving cancel callbacks. | |
869 case CancelCallback: | |
870 callback_output->CheckCancel = FALSE; | |
871 callback_output->Cancel = FALSE; | |
872 return TRUE; | |
873 } | |
874 // Ignore other callback types. | |
875 return FALSE; | |
876 } | |
877 | |
878 void ExceptionHandler::UpdateNextID() { | |
879 assert(uuid_create_); | |
880 UUID id = {0}; | |
881 if (uuid_create_) { | |
882 uuid_create_(&id); | |
883 } | |
884 next_minidump_id_ = GUIDString::GUIDToWString(&id); | |
885 next_minidump_id_c_ = next_minidump_id_.c_str(); | |
886 | |
887 wchar_t minidump_path[MAX_PATH]; | |
888 swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp", | |
889 dump_path_c_, next_minidump_id_c_); | |
890 | |
891 // remove when VC++7.1 is no longer supported | |
892 minidump_path[MAX_PATH - 1] = L'\0'; | |
893 | |
894 next_minidump_path_ = minidump_path; | |
895 next_minidump_path_c_ = next_minidump_path_.c_str(); | |
896 } | |
897 | |
898 } // namespace google_breakpad | |
OLD | NEW |