OLD | NEW |
1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 // allows us to walk the list at crash time to gather data for !locks. A | 361 // allows us to walk the list at crash time to gather data for !locks. A |
362 // debugger would instead inspect ntdll!RtlCriticalSectionList to get the head | 362 // debugger would instead inspect ntdll!RtlCriticalSectionList to get the head |
363 // of the list. But that is not an exported symbol, so on an arbitrary client | 363 // of the list. But that is not an exported symbol, so on an arbitrary client |
364 // machine, we don't have a way of getting that pointer. | 364 // machine, we don't have a way of getting that pointer. |
365 if (InitializeCriticalSectionWithDebugInfoIfPossible( | 365 if (InitializeCriticalSectionWithDebugInfoIfPossible( |
366 &g_critical_section_with_debug_info)) { | 366 &g_critical_section_with_debug_info)) { |
367 message.registration.critical_section_address = | 367 message.registration.critical_section_address = |
368 reinterpret_cast<WinVMAddress>(&g_critical_section_with_debug_info); | 368 reinterpret_cast<WinVMAddress>(&g_critical_section_with_debug_info); |
369 } | 369 } |
370 | 370 |
371 ServerToClientMessage response = {0}; | 371 ServerToClientMessage response = {}; |
372 | 372 |
373 if (!SendToCrashHandlerServer(ipc_pipe_, message, &response)) { | 373 if (!SendToCrashHandlerServer(ipc_pipe_, message, &response)) { |
374 return false; | 374 return false; |
375 } | 375 } |
376 | 376 |
377 // The server returns these already duplicated to be valid in this process. | 377 // The server returns these already duplicated to be valid in this process. |
378 g_signal_exception = | 378 g_signal_exception = |
379 IntToHandle(response.registration.request_crash_dump_event); | 379 IntToHandle(response.registration.request_crash_dump_event); |
380 g_signal_non_crash_dump = | 380 g_signal_non_crash_dump = |
381 IntToHandle(response.registration.request_non_crash_dump_event); | 381 IntToHandle(response.registration.request_non_crash_dump_event); |
(...skipping 19 matching lines...) Expand all Loading... |
401 // In the non-crashing case, we aren't concerned about avoiding calls into | 401 // In the non-crashing case, we aren't concerned about avoiding calls into |
402 // Win32 APIs, so just use regular locking here in case of multiple threads | 402 // Win32 APIs, so just use regular locking here in case of multiple threads |
403 // calling this function. If a crash occurs while we're in here, the worst | 403 // calling this function. If a crash occurs while we're in here, the worst |
404 // that can happen is that the server captures a partial dump for this path | 404 // that can happen is that the server captures a partial dump for this path |
405 // because on the other thread gathering a crash dump, it TerminateProcess()d, | 405 // because on the other thread gathering a crash dump, it TerminateProcess()d, |
406 // causing this one to abort. | 406 // causing this one to abort. |
407 base::AutoLock lock(*g_non_crash_dump_lock); | 407 base::AutoLock lock(*g_non_crash_dump_lock); |
408 | 408 |
409 // Create a fake EXCEPTION_POINTERS to give the handler something to work | 409 // Create a fake EXCEPTION_POINTERS to give the handler something to work |
410 // with. | 410 // with. |
411 EXCEPTION_POINTERS exception_pointers = {0}; | 411 EXCEPTION_POINTERS exception_pointers = {}; |
412 | 412 |
413 // This is logically const, but EXCEPTION_POINTERS does not declare it as | 413 // This is logically const, but EXCEPTION_POINTERS does not declare it as |
414 // const, so we have to cast that away from the argument. | 414 // const, so we have to cast that away from the argument. |
415 exception_pointers.ContextRecord = const_cast<CONTEXT*>(&context); | 415 exception_pointers.ContextRecord = const_cast<CONTEXT*>(&context); |
416 | 416 |
417 // We include a fake exception and use a code of '0x517a7ed' (something like | 417 // We include a fake exception and use a code of '0x517a7ed' (something like |
418 // "simulated") so that it's relatively obvious in windbg that it's not | 418 // "simulated") so that it's relatively obvious in windbg that it's not |
419 // actually an exception. Most values in | 419 // actually an exception. Most values in |
420 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx have | 420 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082.aspx have |
421 // some of the top nibble set, so we make sure to pick a value that doesn't, | 421 // some of the top nibble set, so we make sure to pick a value that doesn't, |
422 // so as to be unlikely to conflict. | 422 // so as to be unlikely to conflict. |
423 const uint32_t kSimulatedExceptionCode = 0x517a7ed; | 423 const uint32_t kSimulatedExceptionCode = 0x517a7ed; |
424 EXCEPTION_RECORD record = {0}; | 424 EXCEPTION_RECORD record = {}; |
425 record.ExceptionCode = kSimulatedExceptionCode; | 425 record.ExceptionCode = kSimulatedExceptionCode; |
426 #if defined(ARCH_CPU_64_BITS) | 426 #if defined(ARCH_CPU_64_BITS) |
427 record.ExceptionAddress = reinterpret_cast<void*>(context.Rip); | 427 record.ExceptionAddress = reinterpret_cast<void*>(context.Rip); |
428 #else | 428 #else |
429 record.ExceptionAddress = reinterpret_cast<void*>(context.Eip); | 429 record.ExceptionAddress = reinterpret_cast<void*>(context.Eip); |
430 #endif // ARCH_CPU_64_BITS | 430 #endif // ARCH_CPU_64_BITS |
431 | 431 |
432 exception_pointers.ExceptionRecord = &record; | 432 exception_pointers.ExceptionRecord = &record; |
433 | 433 |
434 g_non_crash_exception_information.thread_id = GetCurrentThreadId(); | 434 g_non_crash_exception_information.thread_id = GetCurrentThreadId(); |
435 g_non_crash_exception_information.exception_pointers = | 435 g_non_crash_exception_information.exception_pointers = |
436 reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); | 436 reinterpret_cast<crashpad::WinVMAddress>(&exception_pointers); |
437 | 437 |
438 bool set_event_result = !!SetEvent(g_signal_non_crash_dump); | 438 bool set_event_result = !!SetEvent(g_signal_non_crash_dump); |
439 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; | 439 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; |
440 | 440 |
441 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); | 441 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); |
442 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; | 442 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; |
443 } | 443 } |
444 | 444 |
445 // static | 445 // static |
446 void CrashpadClient::DumpAndCrash(EXCEPTION_POINTERS* exception_pointers) { | 446 void CrashpadClient::DumpAndCrash(EXCEPTION_POINTERS* exception_pointers) { |
447 UnhandledExceptionHandler(exception_pointers); | 447 UnhandledExceptionHandler(exception_pointers); |
448 } | 448 } |
449 | 449 |
450 } // namespace crashpad | 450 } // namespace crashpad |
OLD | NEW |