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 |