OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "chrome_elf/crash/crash_helper.h" | |
6 | |
7 #include <assert.h> | |
8 #include <windows.h> | |
9 | |
10 #include <algorithm> | |
11 #include <string> | |
12 #include <vector> | |
13 | |
14 #include "chrome/app/chrome_crash_reporter_client_win.h" | |
15 #include "chrome_elf/hook_util/hook_util.h" | |
16 #include "components/crash/content/app/crashpad.h" | |
17 #include "components/crash/core/common/crash_keys.h" | |
18 #include "third_party/crashpad/crashpad/client/crashpad_client.h" | |
19 | |
20 namespace { | |
21 | |
22 // Gets the exe name from the full path of the exe. | |
23 std::wstring GetExeName() { | |
24 std::wstring file_name; | |
25 file_name.resize(MAX_PATH); | |
26 if (!::GetModuleFileNameW(nullptr, &file_name[0], MAX_PATH)) { | |
27 assert(false); | |
28 return std::wstring(); | |
29 } | |
30 size_t last_slash_pos = file_name.find_last_of(L'\\'); | |
31 if (last_slash_pos != std::wstring::npos) { | |
32 file_name = file_name.substr(last_slash_pos + 1, | |
33 file_name.length() - last_slash_pos); | |
34 } | |
35 std::transform(file_name.begin(), file_name.end(), file_name.begin(), | |
36 ::tolower); | |
37 return file_name; | |
38 } | |
39 | |
40 // Global pointer to a vector of crash reports. | |
41 // This structure will be initialized in InitializeCrashReportingForProcess() | |
42 // and cleaned up in DllDetachCrashReportingCleanup(). | |
43 std::vector<crash_reporter::Report>* g_crash_reports = nullptr; | |
44 | |
45 // chrome_elf loads early in the process and initializes Crashpad. That in turn | |
46 // uses the SetUnhandledExceptionFilter API to set a top level exception | |
47 // handler for the process. When the process eventually initializes, CRT sets | |
48 // an exception handler which calls TerminateProcess which effectively bypasses | |
49 // us. Ideally we want to be at the top of the unhandled exception filter | |
50 // chain. However we don't have a good way of intercepting the | |
51 // SetUnhandledExceptionFilter API in the sandbox. EAT patching kernel32 or | |
52 // kernelbase should ideally work. However the kernel32 kernelbase dlls are | |
53 // prebound which causes EAT patching to not work. Sidestep works. However it | |
54 // is only supported for 32 bit. For now we use IAT patching for the | |
55 // executable. | |
56 // TODO(ananta). | |
57 // Check if it is possible to fix EAT patching or use sidestep patching for | |
58 // 32 bit and 64 bit for this purpose. | |
59 elf_hook::IATHook g_set_unhandled_exception_filter; | |
robertshield
2016/08/03 04:52:45
Technically this violates https://google.github.io
penny
2016/08/04 18:55:35
I fully agree. I was planning to change this to b
| |
60 | |
61 // Hook function, which ignores the request to set an unhandled-exception | |
62 // filter. | |
63 LPTOP_LEVEL_EXCEPTION_FILTER WINAPI | |
64 SetUnhandledExceptionFilterPatch(LPTOP_LEVEL_EXCEPTION_FILTER filter) { | |
65 // Don't set the exception filter. Please see above for comments. | |
66 return nullptr; | |
67 } | |
68 | |
69 } // namespace | |
70 | |
71 //------------------------------------------------------------------------------ | |
72 // Public chrome_elf crash APIs | |
73 //------------------------------------------------------------------------------ | |
74 | |
75 namespace elf_crash { | |
76 | |
77 // NOTE: This function will be called from DllMain during DLL_PROCESS_ATTACH | |
78 // (while we have the loader lock), so do not misbehave. | |
79 void InitializeCrashReporting() { | |
80 // We want to initialize crash reporting only in chrome.exe | |
81 if (GetExeName() != L"chrome.exe") { | |
82 #ifdef _DEBUG | |
83 assert(false); | |
84 #endif // _DEBUG | |
85 return; | |
86 } | |
87 | |
88 #ifdef _DEBUG | |
89 assert(g_crash_reports == nullptr); | |
90 #endif // _DEBUG | |
91 // No global objects with destructors, so using a global pointer. | |
92 // DllMain on detach will clean this up. | |
93 g_crash_reports = new std::vector<crash_reporter::Report>; | |
94 | |
95 ChromeCrashReporterClient::InitializeCrashReportingForProcess(); | |
96 } | |
97 | |
98 // NOTE: This function will be called from DllMain during DLL_PROCESS_DETACH | |
99 // (while we have the loader lock), so do not misbehave. | |
100 void ShutdownCrashReporting() { | |
101 if (g_crash_reports != nullptr) { | |
102 g_crash_reports->clear(); | |
103 delete g_crash_reports; | |
104 } | |
105 } | |
106 | |
107 // Please refer to the comment on g_set_unhandled_exception_filter for more | |
108 // information about why we intercept the SetUnhandledExceptionFilter API. | |
109 void DisableSetUnhandledExceptionFilter() { | |
110 if (g_set_unhandled_exception_filter.Hook( | |
111 GetModuleHandle(nullptr), "kernel32.dll", | |
112 "SetUnhandledExceptionFilter", | |
113 SetUnhandledExceptionFilterPatch) != NO_ERROR) { | |
114 #ifdef _DEBUG | |
115 assert(false); | |
116 #endif //_DEBUG | |
117 } | |
118 } | |
119 | |
120 int GenerateCrashDump(EXCEPTION_POINTERS* exception_pointers) { | |
121 crashpad::CrashpadClient::DumpWithoutCrash( | |
122 *(exception_pointers->ContextRecord)); | |
123 return EXCEPTION_CONTINUE_SEARCH; | |
124 } | |
125 | |
126 } // namespace elf_crash | |
127 | |
128 //------------------------------------------------------------------------------ | |
129 // Exported crash APIs for the rest of the process. | |
130 //------------------------------------------------------------------------------ | |
131 | |
132 // This helper is invoked by code in chrome.dll to retrieve the crash reports. | |
133 // See CrashUploadListCrashpad. Note that we do not pass a std::vector here, | |
134 // because we do not want to allocate/free in different modules. The returned | |
135 // pointer is read-only. | |
136 extern "C" __declspec(dllexport) void GetCrashReportsImpl( | |
robertshield
2016/08/03 04:52:45
Thinking about lifecycle here, it is important to
penny
2016/08/04 18:55:35
Done.
| |
137 const crash_reporter::Report** reports, | |
138 size_t* report_count) { | |
139 crash_reporter::GetReports(g_crash_reports); | |
140 *reports = g_crash_reports->data(); | |
141 *report_count = g_crash_reports->size(); | |
142 } | |
143 | |
144 // This helper is invoked by debugging code in chrome to register the client | |
145 // id. | |
146 extern "C" __declspec(dllexport) void SetMetricsClientId( | |
147 const char* client_id) { | |
148 if (client_id) | |
149 crash_keys::SetMetricsClientIdFromGUID(client_id); | |
150 } | |
OLD | NEW |