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