| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/crash/content/app/crashpad.h" | 5 #include "components/crash/content/app/crashpad.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/environment.h" | 9 #include "base/environment.h" |
| 10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| 11 #include "base/numerics/safe_conversions.h" | 11 #include "base/numerics/safe_conversions.h" |
| 12 #include "base/path_service.h" | |
| 13 #include "base/strings/string16.h" | 12 #include "base/strings/string16.h" |
| 14 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
| 15 #include "base/strings/utf_string_conversions.h" | 14 #include "base/strings/utf_string_conversions.h" |
| 16 #include "build/build_config.h" | 15 #include "build/build_config.h" |
| 17 #include "components/crash/content/app/crash_reporter_client.h" | 16 #include "components/crash/content/app/crash_reporter_client.h" |
| 18 #include "components/crash/content/app/crash_switches.h" | 17 #include "components/crash/content/app/crash_switches.h" |
| 19 #include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.
h" | 18 #include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.
h" |
| 20 #include "third_party/crashpad/crashpad/client/crashpad_client.h" | 19 #include "third_party/crashpad/crashpad/client/crashpad_client.h" |
| 21 #include "third_party/crashpad/crashpad/client/crashpad_info.h" | 20 #include "third_party/crashpad/crashpad/client/crashpad_info.h" |
| 22 #include "third_party/crashpad/crashpad/client/simulate_crash_win.h" | 21 #include "third_party/crashpad/crashpad/client/simulate_crash_win.h" |
| 23 | 22 |
| 24 namespace crash_reporter { | 23 namespace crash_reporter { |
| 25 namespace internal { | 24 namespace internal { |
| 26 | 25 |
| 27 namespace { | 26 namespace { |
| 28 | 27 |
| 29 base::LazyInstance<crashpad::CrashpadClient>::Leaky g_crashpad_client = | 28 base::LazyInstance<crashpad::CrashpadClient>::Leaky g_crashpad_client = |
| 30 LAZY_INSTANCE_INITIALIZER; | 29 LAZY_INSTANCE_INITIALIZER; |
| 31 | 30 |
| 32 } // namespace | 31 } // namespace |
| 33 | 32 |
| 34 void GetPlatformCrashpadAnnotations( | 33 void GetPlatformCrashpadAnnotations( |
| 35 std::map<std::string, std::string>* annotations) { | 34 std::map<std::string, std::string>* annotations) { |
| 36 CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); | 35 CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); |
| 37 base::FilePath exe_file; | 36 wchar_t exe_file[MAX_PATH] = {}; |
| 38 CHECK(PathService::Get(base::FILE_EXE, &exe_file)); | 37 CHECK(::GetModuleFileName(nullptr, exe_file, arraysize(exe_file))); |
| 39 base::string16 product_name, version, special_build, channel_name; | 38 base::string16 product_name, version, special_build, channel_name; |
| 40 crash_reporter_client->GetProductNameAndVersion( | 39 crash_reporter_client->GetProductNameAndVersion( |
| 41 exe_file.value(), &product_name, &version, &special_build, | 40 exe_file, &product_name, &version, &special_build, &channel_name); |
| 42 &channel_name); | |
| 43 (*annotations)["prod"] = base::UTF16ToUTF8(product_name); | 41 (*annotations)["prod"] = base::UTF16ToUTF8(product_name); |
| 44 (*annotations)["ver"] = base::UTF16ToUTF8(version); | 42 (*annotations)["ver"] = base::UTF16ToUTF8(version); |
| 45 (*annotations)["channel"] = base::UTF16ToUTF8(channel_name); | 43 (*annotations)["channel"] = base::UTF16ToUTF8(channel_name); |
| 46 if (!special_build.empty()) | 44 if (!special_build.empty()) |
| 47 (*annotations)["special"] = base::UTF16ToUTF8(special_build); | 45 (*annotations)["special"] = base::UTF16ToUTF8(special_build); |
| 48 #if defined(ARCH_CPU_X86) | 46 #if defined(ARCH_CPU_X86) |
| 49 (*annotations)["plat"] = std::string("Win32"); | 47 (*annotations)["plat"] = std::string("Win32"); |
| 50 #elif defined(ARCH_CPU_X86_64) | 48 #elif defined(ARCH_CPU_X86_64) |
| 51 (*annotations)["plat"] = std::string("Win64"); | 49 (*annotations)["plat"] = std::string("Win64"); |
| 52 #endif | 50 #endif |
| 53 } | 51 } |
| 54 | 52 |
| 55 base::FilePath PlatformCrashpadInitialization(bool initial_client, | 53 base::FilePath PlatformCrashpadInitialization(bool initial_client, |
| 56 bool browser_process, | 54 bool browser_process, |
| 57 bool embedded_handler) { | 55 bool embedded_handler) { |
| 58 base::FilePath database_path; // Only valid in the browser process. | 56 base::FilePath database_path; // Only valid in the browser process. |
| 59 bool result; | 57 bool result = false; |
| 60 | 58 |
| 61 const char kPipeNameVar[] = "CHROME_CRASHPAD_PIPE_NAME"; | 59 const char kPipeNameVar[] = "CHROME_CRASHPAD_PIPE_NAME"; |
| 62 const char kServerUrlVar[] = "CHROME_CRASHPAD_SERVER_URL"; | 60 const char kServerUrlVar[] = "CHROME_CRASHPAD_SERVER_URL"; |
| 63 std::unique_ptr<base::Environment> env(base::Environment::Create()); | 61 std::unique_ptr<base::Environment> env(base::Environment::Create()); |
| 64 | |
| 65 if (initial_client) { | 62 if (initial_client) { |
| 66 CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); | 63 CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); |
| 67 | 64 |
| 68 base::string16 database_path_str; | 65 base::string16 database_path_str; |
| 69 if (crash_reporter_client->GetCrashDumpLocation(&database_path_str)) | 66 if (crash_reporter_client->GetCrashDumpLocation(&database_path_str)) |
| 70 database_path = base::FilePath(database_path_str); | 67 database_path = base::FilePath(database_path_str); |
| 71 | 68 |
| 72 std::map<std::string, std::string> process_annotations; | 69 std::map<std::string, std::string> process_annotations; |
| 73 GetPlatformCrashpadAnnotations(&process_annotations); | 70 GetPlatformCrashpadAnnotations(&process_annotations); |
| 74 | 71 |
| 75 #if defined(GOOGLE_CHROME_BUILD) | 72 #if defined(GOOGLE_CHROME_BUILD) |
| 76 std::string url = "https://clients2.google.com/cr/report"; | 73 std::string url = "https://clients2.google.com/cr/report"; |
| 77 #else | 74 #else |
| 78 std::string url; | 75 std::string url; |
| 79 #endif | 76 #endif |
| 80 | 77 |
| 81 // Allow the crash server to be overridden for testing. If the variable | 78 // Allow the crash server to be overridden for testing. If the variable |
| 82 // isn't present in the environment then the default URL will remain. | 79 // isn't present in the environment then the default URL will remain. |
| 83 env->GetVar(kServerUrlVar, &url); | 80 env->GetVar(kServerUrlVar, &url); |
| 84 | 81 |
| 85 base::FilePath exe_file; | 82 wchar_t exe_file_path[MAX_PATH] = {}; |
| 86 CHECK(PathService::Get(base::FILE_EXE, &exe_file)); | 83 CHECK( |
| 84 ::GetModuleFileName(nullptr, exe_file_path, arraysize(exe_file_path))); |
| 85 |
| 86 base::FilePath exe_file(exe_file_path); |
| 87 | 87 |
| 88 bool is_per_user_install = | 88 bool is_per_user_install = |
| 89 crash_reporter_client->GetIsPerUserInstall(exe_file.value()); | 89 crash_reporter_client->GetIsPerUserInstall(exe_file.value()); |
| 90 if (crash_reporter_client->GetShouldDumpLargerDumps(is_per_user_install)) { | 90 if (crash_reporter_client->GetShouldDumpLargerDumps(is_per_user_install)) { |
| 91 const uint32_t kIndirectMemoryLimit = 4 * 1024 * 1024; | 91 const uint32_t kIndirectMemoryLimit = 4 * 1024 * 1024; |
| 92 crashpad::CrashpadInfo::GetCrashpadInfo() | 92 crashpad::CrashpadInfo::GetCrashpadInfo() |
| 93 ->set_gather_indirectly_referenced_memory( | 93 ->set_gather_indirectly_referenced_memory( |
| 94 crashpad::TriState::kEnabled, kIndirectMemoryLimit); | 94 crashpad::TriState::kEnabled, kIndirectMemoryLimit); |
| 95 } | 95 } |
| 96 | 96 |
| 97 // If the handler is embedded in the binary (e.g. chrome, setup), we | 97 // If the handler is embedded in the binary (e.g. chrome, setup), we |
| 98 // reinvoke it with --type=crashpad-handler. Otherwise, we use the | 98 // reinvoke it with --type=crashpad-handler. Otherwise, we use the |
| 99 // standalone crashpad_handler.exe (for tests, etc.). | 99 // standalone crashpad_handler.exe (for tests, etc.). |
| 100 std::vector<std::string> arguments; | 100 std::vector<std::string> arguments; |
| 101 if (embedded_handler) { | 101 if (embedded_handler) { |
| 102 arguments.push_back(std::string("--type=") + switches::kCrashpadHandler); | 102 arguments.push_back(std::string("--type=") + switches::kCrashpadHandler); |
| 103 | 103 // The prefetch argument added here has to be documented in |
| 104 if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument) { | 104 // chrome_switches.cc, below the kPrefetchArgument* constants. A |
| 105 // The prefetch argument added here has to be documented in | 105 // constant can't be used here because crashpad can't depend on Chrome. |
| 106 // chrome_switches.cc, below the kPrefetchArgument* constants. A | 106 arguments.push_back("/prefetch:7"); |
| 107 // constant can't be used here because crashpad can't depend on Chrome. | |
| 108 arguments.push_back("/prefetch:7"); | |
| 109 } | |
| 110 } else { | 107 } else { |
| 111 base::FilePath exe_dir = exe_file.DirName(); | 108 base::FilePath exe_dir = exe_file.DirName(); |
| 112 exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe")); | 109 exe_file = exe_dir.Append(FILE_PATH_LITERAL("crashpad_handler.exe")); |
| 113 } | 110 } |
| 114 | |
| 115 // TODO(scottmg): See https://crashpad.chromium.org/bug/23. | 111 // TODO(scottmg): See https://crashpad.chromium.org/bug/23. |
| 116 arguments.push_back("--no-rate-limit"); | 112 arguments.push_back("--no-rate-limit"); |
| 117 | 113 |
| 118 result = g_crashpad_client.Get().StartHandler( | 114 result = g_crashpad_client.Get().StartHandler( |
| 119 exe_file, database_path, url, process_annotations, arguments, false); | 115 exe_file, database_path, url, process_annotations, arguments, false); |
| 120 | 116 |
| 121 // If we're the browser, push the pipe name into the environment so child | 117 // If we're the browser, push the pipe name into the environment so child |
| 122 // processes can connect to it. If we inherited another crashpad_handler's | 118 // processes can connect to it. If we inherited another crashpad_handler's |
| 123 // pipe name, we'll overwrite it here. | 119 // pipe name, we'll overwrite it here. |
| 124 env->SetVar(kPipeNameVar, | 120 env->SetVar(kPipeNameVar, |
| 125 base::UTF16ToUTF8(g_crashpad_client.Get().GetHandlerIPCPipe())); | 121 base::UTF16ToUTF8(g_crashpad_client.Get().GetHandlerIPCPipe())); |
| 126 } else { | 122 } else { |
| 127 std::string pipe_name_utf8; | 123 std::string pipe_name_utf8; |
| 128 result = env->GetVar(kPipeNameVar, &pipe_name_utf8); | 124 result = env->GetVar(kPipeNameVar, &pipe_name_utf8); |
| 129 if (result) { | 125 if (result) { |
| 130 result = g_crashpad_client.Get().SetHandlerIPCPipe( | 126 result = g_crashpad_client.Get().SetHandlerIPCPipe( |
| 131 base::UTF8ToUTF16(pipe_name_utf8)); | 127 base::UTF8ToUTF16(pipe_name_utf8)); |
| 132 } | 128 } |
| 133 } | 129 } |
| 134 | 130 |
| 135 if (result) { | 131 if (result) { |
| 136 result = g_crashpad_client.Get().UseHandler(); | 132 result = g_crashpad_client.Get().UseHandler(); |
| 137 } | 133 } |
| 138 | |
| 139 return database_path; | 134 return database_path; |
| 140 } | 135 } |
| 141 | 136 |
| 142 // TODO(scottmg): http://crbug.com/546288 These exported functions are for | 137 // TODO(scottmg): http://crbug.com/546288 These exported functions are for |
| 143 // compatibility with how Breakpad worked, but it seems like there's no need to | 138 // compatibility with how Breakpad worked, but it seems like there's no need to |
| 144 // do the CreateRemoteThread() dance with a minor extension of the Crashpad API | 139 // do the CreateRemoteThread() dance with a minor extension of the Crashpad API |
| 145 // (to just pass the pid we want a dump for). We should add that and then modify | 140 // (to just pass the pid we want a dump for). We should add that and then modify |
| 146 // hang_crash_dump_win.cc to work in a more direct manner. | 141 // hang_crash_dump_win.cc to work in a more direct manner. |
| 147 | 142 |
| 148 // Used for dumping a process state when there is no crash. | 143 // Used for dumping a process state when there is no crash. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 int __declspec(dllexport) CrashForException( | 191 int __declspec(dllexport) CrashForException( |
| 197 EXCEPTION_POINTERS* info) { | 192 EXCEPTION_POINTERS* info) { |
| 198 crash_reporter::internal::g_crashpad_client.Get().DumpAndCrash(info); | 193 crash_reporter::internal::g_crashpad_client.Get().DumpAndCrash(info); |
| 199 return EXCEPTION_CONTINUE_SEARCH; | 194 return EXCEPTION_CONTINUE_SEARCH; |
| 200 } | 195 } |
| 201 | 196 |
| 202 // Injects a thread into a remote process to dump state when there is no crash. | 197 // Injects a thread into a remote process to dump state when there is no crash. |
| 203 HANDLE __declspec(dllexport) __cdecl InjectDumpProcessWithoutCrash( | 198 HANDLE __declspec(dllexport) __cdecl InjectDumpProcessWithoutCrash( |
| 204 HANDLE process) { | 199 HANDLE process) { |
| 205 return CreateRemoteThread( | 200 return CreateRemoteThread( |
| 206 process, NULL, 0, crash_reporter::internal::DumpProcessWithoutCrashThread, | 201 process, nullptr, 0, |
| 207 0, 0, NULL); | 202 crash_reporter::internal::DumpProcessWithoutCrashThread, 0, 0, nullptr); |
| 208 } | 203 } |
| 209 | 204 |
| 210 HANDLE __declspec(dllexport) __cdecl InjectDumpForHangDebugging( | 205 HANDLE __declspec(dllexport) __cdecl InjectDumpForHangDebugging( |
| 211 HANDLE process) { | 206 HANDLE process) { |
| 212 return CreateRemoteThread( | 207 return CreateRemoteThread( |
| 213 process, NULL, 0, crash_reporter::internal::DumpForHangDebuggingThread, 0, | 208 process, nullptr, 0, crash_reporter::internal::DumpForHangDebuggingThread, |
| 214 0, NULL); | 209 0, 0, nullptr); |
| 215 } | 210 } |
| 216 | 211 |
| 217 #if defined(ARCH_CPU_X86_64) | 212 #if defined(ARCH_CPU_X86_64) |
| 218 | 213 |
| 219 static int CrashForExceptionInNonABICompliantCodeRange( | 214 static int CrashForExceptionInNonABICompliantCodeRange( |
| 220 PEXCEPTION_RECORD ExceptionRecord, | 215 PEXCEPTION_RECORD ExceptionRecord, |
| 221 ULONG64 EstablisherFrame, | 216 ULONG64 EstablisherFrame, |
| 222 PCONTEXT ContextRecord, | 217 PCONTEXT ContextRecord, |
| 223 PDISPATCHER_CONTEXT DispatcherContext) { | 218 PDISPATCHER_CONTEXT DispatcherContext) { |
| 224 EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord }; | 219 EXCEPTION_POINTERS info = { ExceptionRecord, ContextRecord }; |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 void __declspec(dllexport) __cdecl UnregisterNonABICompliantCodeRange( | 286 void __declspec(dllexport) __cdecl UnregisterNonABICompliantCodeRange( |
| 292 void* start) { | 287 void* start) { |
| 293 ExceptionHandlerRecord* record = | 288 ExceptionHandlerRecord* record = |
| 294 reinterpret_cast<ExceptionHandlerRecord*>(start); | 289 reinterpret_cast<ExceptionHandlerRecord*>(start); |
| 295 | 290 |
| 296 CHECK(RtlDeleteFunctionTable(&record->runtime_function)); | 291 CHECK(RtlDeleteFunctionTable(&record->runtime_function)); |
| 297 } | 292 } |
| 298 #endif // ARCH_CPU_X86_64 | 293 #endif // ARCH_CPU_X86_64 |
| 299 | 294 |
| 300 } // extern "C" | 295 } // extern "C" |
| OLD | NEW |