Index: third_party/crashpad/crashpad/handler/win/crash_other_program.cc |
diff --git a/third_party/crashpad/crashpad/handler/win/crash_other_program.cc b/third_party/crashpad/crashpad/handler/win/crash_other_program.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..db532bb5722c22de29ec2443e6ee26b0ac52df2c |
--- /dev/null |
+++ b/third_party/crashpad/crashpad/handler/win/crash_other_program.cc |
@@ -0,0 +1,120 @@ |
+// Copyright 2016 The Crashpad Authors. All rights reserved. |
+// |
+// Licensed under the Apache License, Version 2.0 (the "License"); |
+// you may not use this file except in compliance with the License. |
+// You may obtain a copy of the License at |
+// |
+// http://www.apache.org/licenses/LICENSE-2.0 |
+// |
+// Unless required by applicable law or agreed to in writing, software |
+// distributed under the License is distributed on an "AS IS" BASIS, |
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+// See the License for the specific language governing permissions and |
+// limitations under the License. |
+ |
+#include <stdlib.h> |
+#include <windows.h> |
+#include <tlhelp32.h> |
+ |
+#include "base/files/file_path.h" |
+#include "base/logging.h" |
+#include "client/crashpad_client.h" |
+#include "test/paths.h" |
+#include "test/win/child_launcher.h" |
+#include "util/file/file_io.h" |
+#include "util/win/scoped_handle.h" |
+#include "util/win/xp_compat.h" |
+ |
+namespace crashpad { |
+namespace test { |
+namespace { |
+ |
+bool CrashAndDumpTarget(const CrashpadClient& client, HANDLE process) { |
+ DWORD target_pid = GetProcessId(process); |
+ |
+ HANDLE thread_snap_raw = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
+ if (thread_snap_raw == INVALID_HANDLE_VALUE) { |
+ LOG(ERROR) << "CreateToolhelp32Snapshot"; |
+ return false; |
+ } |
+ ScopedFileHANDLE thread_snap(thread_snap_raw); |
+ |
+ THREADENTRY32 te32; |
+ te32.dwSize = sizeof(THREADENTRY32); |
+ if (!Thread32First(thread_snap.get(), &te32)) { |
+ LOG(ERROR) << "Thread32First"; |
+ return false; |
+ } |
+ |
+ int thread_count = 0; |
+ do { |
+ if (te32.th32OwnerProcessID == target_pid) { |
+ thread_count++; |
+ if (thread_count == 2) { |
+ // Nominate this lucky thread as our blamee, and dump it. This will be |
+ // "Thread1" in the child. |
+ ScopedKernelHANDLE thread( |
+ OpenThread(kXPThreadAllAccess, false, te32.th32ThreadID)); |
+ if (!client.DumpAndCrashTargetProcess( |
+ process, thread.get(), 0xdeadbea7)) { |
+ LOG(ERROR) << "DumpAndCrashTargetProcess failed"; |
+ return false; |
+ } |
+ return true; |
+ } |
+ } |
+ } while (Thread32Next(thread_snap.get(), &te32)); |
+ |
+ return false; |
+} |
+ |
+int CrashOtherProgram(int argc, wchar_t* argv[]) { |
+ CrashpadClient client; |
+ |
+ if (argc == 2 || argc == 3) { |
+ if (!client.SetHandlerIPCPipe(argv[1])) { |
+ LOG(ERROR) << "SetHandler"; |
+ return EXIT_FAILURE; |
+ } |
+ } else { |
+ fprintf(stderr, "Usage: %ls <server_pipe_name> [noexception]\n", argv[0]); |
+ return EXIT_FAILURE; |
+ } |
+ |
+ if (!client.UseHandler()) { |
+ LOG(ERROR) << "UseHandler"; |
+ return EXIT_FAILURE; |
+ } |
+ |
+ // Launch another process that hangs. |
+ base::FilePath test_executable = Paths::Executable(); |
+ std::wstring child_test_executable = |
+ test_executable.DirName().Append(L"hanging_program.exe").value(); |
+ ChildLauncher child(child_test_executable, argv[1]); |
+ child.Start(); |
+ |
+ // Wait until it's ready. |
+ char c; |
+ if (!LoggingReadFile(child.stdout_read_handle(), &c, sizeof(c)) || c != ' ') { |
+ LOG(ERROR) << "failed child communication"; |
+ return EXIT_FAILURE; |
+ } |
+ |
+ if (argc == 3 && wcscmp(argv[2], L"noexception") == 0) { |
+ client.DumpAndCrashTargetProcess(child.process_handle(), 0, 0); |
+ return EXIT_SUCCESS; |
+ } else { |
+ if (CrashAndDumpTarget(client, child.process_handle())) |
+ return EXIT_SUCCESS; |
+ } |
+ |
+ return EXIT_FAILURE; |
+} |
+ |
+} // namespace |
+} // namespace test |
+} // namespace crashpad |
+ |
+int wmain(int argc, wchar_t* argv[]) { |
+ return crashpad::test::CrashOtherProgram(argc, argv); |
+} |