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

Side by Side Diff: third_party/crashpad/crashpad/client/crashpad_client_win.cc

Issue 1921833002: Update Crashpad to 00d458adaf3868999eeab5341fce5bedb81d17a1 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: win fixes Created 4 years, 7 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
OLDNEW
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 10 matching lines...) Expand all
21 #include <memory> 21 #include <memory>
22 22
23 #include "base/atomicops.h" 23 #include "base/atomicops.h"
24 #include "base/logging.h" 24 #include "base/logging.h"
25 #include "base/scoped_generic.h" 25 #include "base/scoped_generic.h"
26 #include "base/strings/string16.h" 26 #include "base/strings/string16.h"
27 #include "base/strings/stringprintf.h" 27 #include "base/strings/stringprintf.h"
28 #include "base/strings/utf_string_conversions.h" 28 #include "base/strings/utf_string_conversions.h"
29 #include "base/synchronization/lock.h" 29 #include "base/synchronization/lock.h"
30 #include "util/file/file_io.h" 30 #include "util/file/file_io.h"
31 #include "util/win/address_types.h"
31 #include "util/win/command_line.h" 32 #include "util/win/command_line.h"
32 #include "util/win/critical_section_with_debug_info.h" 33 #include "util/win/critical_section_with_debug_info.h"
33 #include "util/win/get_function.h" 34 #include "util/win/get_function.h"
34 #include "util/win/handle.h" 35 #include "util/win/handle.h"
36 #include "util/win/nt_internals.h"
37 #include "util/win/ntstatus_logging.h"
38 #include "util/win/process_info.h"
35 #include "util/win/registration_protocol_win.h" 39 #include "util/win/registration_protocol_win.h"
36 #include "util/win/scoped_handle.h" 40 #include "util/win/scoped_handle.h"
41 #include "util/win/scoped_process_suspend.h"
37 42
38 namespace { 43 namespace {
39 44
40 // This handle is never closed. This is used to signal to the server that a dump 45 // This handle is never closed. This is used to signal to the server that a dump
41 // should be taken in the event of a crash. 46 // should be taken in the event of a crash.
42 HANDLE g_signal_exception = INVALID_HANDLE_VALUE; 47 HANDLE g_signal_exception = INVALID_HANDLE_VALUE;
43 48
44 // Where we store the exception information that the crash handler reads. 49 // Where we store the exception information that the crash handler reads.
45 crashpad::ExceptionInformation g_crash_exception_information; 50 crashpad::ExceptionInformation g_crash_exception_information;
46 51
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 // There doesn't seem to be any documentation of this, but if there's a handle 166 // There doesn't seem to be any documentation of this, but if there's a handle
162 // duplicated in this list, CreateProcess() fails with 167 // duplicated in this list, CreateProcess() fails with
163 // ERROR_INVALID_PARAMETER. 168 // ERROR_INVALID_PARAMETER.
164 if (IsInheritableHandle(handle) && 169 if (IsInheritableHandle(handle) &&
165 std::find(handle_list->begin(), handle_list->end(), handle) == 170 std::find(handle_list->begin(), handle_list->end(), handle) ==
166 handle_list->end()) { 171 handle_list->end()) {
167 handle_list->push_back(handle); 172 handle_list->push_back(handle);
168 } 173 }
169 } 174 }
170 175
176 void AddUint32(std::vector<unsigned char>* data_vector, uint32_t data) {
177 data_vector->push_back(static_cast<unsigned char>(data & 0xff));
178 data_vector->push_back(static_cast<unsigned char>((data & 0xff00) >> 8));
179 data_vector->push_back(static_cast<unsigned char>((data & 0xff0000) >> 16));
180 data_vector->push_back(static_cast<unsigned char>((data & 0xff000000) >> 24));
181 }
182
183 void AddUint64(std::vector<unsigned char>* data_vector, uint64_t data) {
184 AddUint32(data_vector, static_cast<uint32_t>(data & 0xffffffffULL));
185 AddUint32(data_vector,
186 static_cast<uint32_t>((data & 0xffffffff00000000ULL) >> 32));
187 }
188
171 } // namespace 189 } // namespace
172 190
173 namespace crashpad { 191 namespace crashpad {
174 192
175 CrashpadClient::CrashpadClient() 193 CrashpadClient::CrashpadClient()
176 : ipc_pipe_() { 194 : ipc_pipe_() {
177 } 195 }
178 196
179 CrashpadClient::~CrashpadClient() { 197 CrashpadClient::~CrashpadClient() {
180 } 198 }
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 473
456 bool set_event_result = !!SetEvent(g_signal_non_crash_dump); 474 bool set_event_result = !!SetEvent(g_signal_non_crash_dump);
457 PLOG_IF(ERROR, !set_event_result) << "SetEvent"; 475 PLOG_IF(ERROR, !set_event_result) << "SetEvent";
458 476
459 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE); 477 DWORD wfso_result = WaitForSingleObject(g_non_crash_dump_done, INFINITE);
460 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject"; 478 PLOG_IF(ERROR, wfso_result != WAIT_OBJECT_0) << "WaitForSingleObject";
461 } 479 }
462 480
463 // static 481 // static
464 void CrashpadClient::DumpAndCrash(EXCEPTION_POINTERS* exception_pointers) { 482 void CrashpadClient::DumpAndCrash(EXCEPTION_POINTERS* exception_pointers) {
483 if (g_signal_exception == INVALID_HANDLE_VALUE) {
484 LOG(ERROR) << "haven't called UseHandler()";
485 return;
486 }
487
465 UnhandledExceptionHandler(exception_pointers); 488 UnhandledExceptionHandler(exception_pointers);
466 } 489 }
467 490
491 bool CrashpadClient::DumpAndCrashTargetProcess(HANDLE process,
492 HANDLE blame_thread,
493 DWORD exception_code) const {
494 // Confirm we're on Vista or later.
495 const DWORD version = GetVersion();
496 const DWORD major_version = LOBYTE(LOWORD(version));
497 if (major_version < 6) {
498 LOG(ERROR) << "unavailable before Vista";
499 return false;
500 }
501
502 // Confirm that our bitness is the same as the process we're crashing.
503 ProcessInfo process_info;
504 if (!process_info.Initialize(process)) {
505 LOG(ERROR) << "ProcessInfo::Initialize";
506 return false;
507 }
508 #if defined(ARCH_CPU_64_BITS)
509 if (!process_info.Is64Bit()) {
510 LOG(ERROR) << "DumpAndCrashTargetProcess currently not supported x64->x86";
511 return false;
512 }
513 #endif // ARCH_CPU_64_BITS
514
515 ScopedProcessSuspend suspend(process);
516
517 // If no thread handle was provided, or the thread has already exited, we pass
518 // 0 to the handler, which indicates no fake exception record to be created.
519 DWORD thread_id = 0;
520 if (blame_thread) {
521 // Now that we've suspended the process, if our thread hasn't exited, we
522 // know we're relatively safe to pass the thread id through.
523 if (WaitForSingleObject(blame_thread, 0) == WAIT_TIMEOUT) {
524 static const auto get_thread_id =
525 GET_FUNCTION_REQUIRED(L"kernel32.dll", ::GetThreadId);
526 thread_id = get_thread_id(blame_thread);
527 }
528 }
529
530 const size_t kInjectBufferSize = 4 * 1024;
531 WinVMAddress inject_memory =
532 reinterpret_cast<WinVMAddress>(VirtualAllocEx(process,
533 nullptr,
534 kInjectBufferSize,
535 MEM_RESERVE | MEM_COMMIT,
536 PAGE_READWRITE));
537 if (!inject_memory) {
538 PLOG(ERROR) << "VirtualAllocEx";
539 return false;
540 }
541
542 // Because we're the same bitness as our target, we can rely kernel32 being
543 // loaded at the same address in our process as the target, and just look up
544 // its address here.
545 WinVMAddress raise_exception_address =
546 reinterpret_cast<WinVMAddress>(&RaiseException);
547
548 WinVMAddress code_entry_point = 0;
549 std::vector<unsigned char> data_to_write;
550 if (process_info.Is64Bit()) {
551 // Data written is first, the data for the 4th argument (lpArguments) to
552 // RaiseException(). A two element array:
553 //
554 // DWORD64: thread_id
555 // DWORD64: exception_code
556 //
557 // Following that, code which sets the arguments to RaiseException() and
558 // then calls it:
559 //
560 // mov r9, <data_array_address>
561 // mov r8d, 2 ; nNumberOfArguments
562 // mov edx, 1 ; dwExceptionFlags = EXCEPTION_NONCONTINUABLE
563 // mov ecx, 0xcca11ed ; dwExceptionCode, interpreted specially by the
564 // ; handler.
565 // jmp <address_of_RaiseException>
566 //
567 // Note that the first three arguments to RaiseException() are DWORDs even
568 // on x64, so only the 4th argument (a pointer) is a full-width register.
569 //
570 // We also don't need to set up a stack or use call, since the only
571 // registers modified are volatile ones, and we can just jmp straight to
572 // RaiseException().
573
574 // The data array.
575 AddUint64(&data_to_write, thread_id);
576 AddUint64(&data_to_write, exception_code);
577
578 // The thread entry point.
579 code_entry_point = inject_memory + data_to_write.size();
580
581 // r9 = pointer to data.
582 data_to_write.push_back(0x49);
583 data_to_write.push_back(0xb9);
584 AddUint64(&data_to_write, inject_memory);
585
586 // r8d = 2 for nNumberOfArguments.
587 data_to_write.push_back(0x41);
588 data_to_write.push_back(0xb8);
589 AddUint32(&data_to_write, 2);
590
591 // edx = 1 for dwExceptionFlags.
592 data_to_write.push_back(0xba);
593 AddUint32(&data_to_write, 1);
594
595 // ecx = kTriggeredExceptionCode for dwExceptionCode.
596 data_to_write.push_back(0xb9);
597 AddUint32(&data_to_write, kTriggeredExceptionCode);
598
599 // jmp to RaiseException() via rax.
600 data_to_write.push_back(0x48); // mov rax, imm.
601 data_to_write.push_back(0xb8);
602 AddUint64(&data_to_write, raise_exception_address);
603 data_to_write.push_back(0xff); // jmp rax.
604 data_to_write.push_back(0xe0);
605 } else {
606 // Data written is first, the data for the 4th argument (lpArguments) to
607 // RaiseException(). A two element array:
608 //
609 // DWORD: thread_id
610 // DWORD: exception_code
611 //
612 // Following that, code which pushes our arguments to RaiseException() and
613 // then calls it:
614 //
615 // push <data_array_address>
616 // push 2 ; nNumberOfArguments
617 // push 1 ; dwExceptionFlags = EXCEPTION_NONCONTINUABLE
618 // push 0xcca11ed ; dwExceptionCode, interpreted specially by the handler.
619 // call <address_of_RaiseException>
620 // ud2 ; Generate invalid opcode to make sure we still crash if we return
621 // ; for some reason.
622 //
623 // No need to clean up the stack, as RaiseException() is __stdcall.
624
625 // The data array.
626 AddUint32(&data_to_write, thread_id);
627 AddUint32(&data_to_write, exception_code);
628
629 // The thread entry point.
630 code_entry_point = inject_memory + data_to_write.size();
631
632 // Push data address.
633 data_to_write.push_back(0x68);
634 AddUint32(&data_to_write, static_cast<uint32_t>(inject_memory));
635
636 // Push 2 for nNumberOfArguments.
637 data_to_write.push_back(0x6a);
638 data_to_write.push_back(2);
639
640 // Push 1 for dwExceptionCode.
641 data_to_write.push_back(0x6a);
642 data_to_write.push_back(1);
643
644 // Push dwExceptionFlags.
645 data_to_write.push_back(0x68);
646 AddUint32(&data_to_write, kTriggeredExceptionCode);
647
648 // Relative call to RaiseException().
649 int64_t relative_address_to_raise_exception =
650 raise_exception_address - (inject_memory + data_to_write.size() + 5);
651 data_to_write.push_back(0xe8);
652 AddUint32(&data_to_write,
653 static_cast<uint32_t>(relative_address_to_raise_exception));
654
655 // ud2.
656 data_to_write.push_back(0x0f);
657 data_to_write.push_back(0x0b);
658 }
659
660 DCHECK_LT(data_to_write.size(), kInjectBufferSize);
661
662 SIZE_T bytes_written;
663 if (!WriteProcessMemory(process,
664 reinterpret_cast<void*>(inject_memory),
665 data_to_write.data(),
666 data_to_write.size(),
667 &bytes_written)) {
668 PLOG(ERROR) << "WriteProcessMemory";
669 return false;
670 }
671
672 if (bytes_written != data_to_write.size()) {
673 LOG(ERROR) << "WriteProcessMemory unexpected number of bytes";
674 return false;
675 }
676
677 if (!FlushInstructionCache(
678 process, reinterpret_cast<void*>(inject_memory), bytes_written)) {
679 PLOG(ERROR) << "FlushInstructionCache";
680 return false;
681 }
682
683 DWORD old_protect;
684 if (!VirtualProtectEx(process,
685 reinterpret_cast<void*>(inject_memory),
686 kInjectBufferSize,
687 PAGE_EXECUTE_READ,
688 &old_protect)) {
689 PLOG(ERROR) << "VirtualProtectEx";
690 return false;
691 }
692
693 // Cause an exception in the target process by creating a thread which calls
694 // RaiseException with our arguments above. Note that we cannot get away with
695 // using DebugBreakProcess() (nothing happens unless a debugger is attached)
696 // and we cannot get away with CreateRemoteThread() because it doesn't work if
697 // the target is hung waiting for the loader lock. We use NtCreateThreadEx()
698 // with the SKIP_THREAD_ATTACH flag, which skips various notifications,
699 // letting this cause an exception, even when the target is stuck in the
700 // loader lock.
701 HANDLE injected_thread;
702 const size_t kStackSize = 0x4000; // This is what DebugBreakProcess() uses.
703 NTSTATUS status = NtCreateThreadEx(&injected_thread,
704 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
705 nullptr,
706 process,
707 reinterpret_cast<void*>(code_entry_point),
708 nullptr,
709 THREAD_CREATE_FLAGS_SKIP_THREAD_ATTACH,
710 0,
711 kStackSize,
712 0,
713 nullptr);
714 if (!NT_SUCCESS(status)) {
715 NTSTATUS_LOG(ERROR, status) << "NtCreateThreadEx";
716 return false;
717 }
718
719 bool result = true;
720 if (WaitForSingleObject(injected_thread, 60 * 1000) != WAIT_OBJECT_0) {
721 PLOG(ERROR) << "WaitForSingleObject";
722 result = false;
723 }
724
725 status = NtClose(injected_thread);
726 if (!NT_SUCCESS(status)) {
727 NTSTATUS_LOG(ERROR, status) << "NtClose";
728 result = false;
729 }
730
731 return result;
732 }
733
468 } // namespace crashpad 734 } // namespace crashpad
OLDNEW
« no previous file with comments | « third_party/crashpad/crashpad/client/crashpad_client.h ('k') | third_party/crashpad/crashpad/client/crashpad_info.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698