OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2012 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 // This module contains the necessary code to register the Breakpad exception | |
6 // handler. This implementation is based on Chrome/Chrome Frame crash reporting | |
7 // code. See: | |
8 // - src/chrome/app/breakpad_win.cc | |
9 // - src/chrome_frame/crash_server_init.cc | |
10 // - src/chrome/installer/setup/setup_main.cc | |
11 // - src/chrome_frame/crash_reporting/crash_report.cc | |
12 | |
13 #include "remoting/base/breakpad.h" | |
14 | |
15 #include <windows.h> | |
16 #include <string> | |
17 | |
18 #include "base/atomicops.h" | |
19 #include "base/logging.h" | |
20 #include "base/file_version_info.h" | |
21 #include "base/lazy_instance.h" | |
22 #include "base/memory/scoped_ptr.h" | |
23 #include "base/process_util.h" | |
24 #include "base/utf_string_conversions.h" | |
25 #include "base/win/wrapped_window_proc.h" | |
26 #include "breakpad/src/client/windows/handler/exception_handler.h" | |
27 | |
28 namespace remoting { | |
29 void InitializeCrashReportingForTest(const wchar_t* pipe_name); | |
30 } // namespace remoting | |
31 | |
32 namespace { | |
33 | |
34 const wchar_t kBreakpadProductName[] = L"Chromoting"; | |
35 const wchar_t kBreakpadVersionEntry[] = L"ver"; | |
36 const wchar_t kBreakpadVersionDefault[] = L"0.1.0.0"; | |
37 const wchar_t kBreakpadProdEntry[] = L"prod"; | |
38 const wchar_t kBreakpadPlatformEntry[] = L"plat"; | |
39 const wchar_t kBreakpadPlatformWin32[] = L"Win32"; | |
40 | |
41 // The protocol for connecting to the out-of-process Breakpad crash | |
42 // reporter is different for x86-32 and x86-64: the message sizes | |
43 // are different because the message struct contains a pointer. As | |
44 // a result, there are two different named pipes to connect to. The | |
45 // 64-bit one is distinguished with an "-x64" suffix. | |
46 #if defined(_WIN64) | |
47 const wchar_t kGoogleUpdatePipeName[] = | |
48 L"\\\\.\\pipe\\GoogleCrashServices\\S-1-5-18-x64"; | |
49 #else | |
50 const wchar_t kGoogleUpdatePipeName[] = | |
51 L"\\\\.\\pipe\\GoogleCrashServices\\S-1-5-18"; | |
52 #endif | |
53 | |
54 using base::subtle::AtomicWord; | |
55 using base::subtle::NoBarrier_CompareAndSwap; | |
56 | |
57 class BreakpadWin { | |
58 public: | |
59 BreakpadWin(); | |
60 ~BreakpadWin(); | |
61 | |
62 static BreakpadWin* GetInstance(); | |
63 | |
64 private: | |
65 // Returns the Custom information to be used for crash reporting. | |
66 google_breakpad::CustomClientInfo* GetCustomInfo(); | |
67 | |
68 // Checks whether crash dump collection is allowed by the user. | |
69 bool IsCrashReportingEnabled(); | |
70 | |
71 // This callback is executed when the process has crashed and *before* | |
72 // the crash dump is created. To prevent duplicate crash reports we | |
73 // make every thread calling this method, except the very first one, | |
74 // go to sleep. | |
75 static bool OnExceptionCallback(void* context, | |
76 EXCEPTION_POINTERS* exinfo, | |
77 MDRawAssertionInfo* assertion); | |
78 | |
79 // Crashes the process after generating a dump for the provided exception. | |
80 // Note that the crash reporter should be initialized before calling this | |
81 // function for it to do anything. | |
82 static int OnWindowProcedureException(EXCEPTION_POINTERS* exinfo); | |
83 | |
84 // Breakpad's exception handler. | |
85 scoped_ptr<google_breakpad::ExceptionHandler> breakpad_; | |
86 | |
87 // This flag is used to indicate that an exception is already being handled. | |
88 volatile AtomicWord handling_exception_; | |
89 | |
90 // The testing hook below allows overriding the crash server pipe name. | |
91 static const wchar_t* pipe_name_; | |
92 | |
93 friend void ::remoting::InitializeCrashReportingForTest(const wchar_t*); | |
94 | |
95 DISALLOW_COPY_AND_ASSIGN(BreakpadWin); | |
96 }; | |
97 | |
98 // |LazyInstance| is used to guarantee that the exception handler will be | |
99 // initialized exactly once. | |
100 // N.B. LazyInstance does not allow this to be a static member of the class. | |
101 static base::LazyInstance<BreakpadWin>::Leaky g_instance = | |
102 LAZY_INSTANCE_INITIALIZER; | |
103 | |
104 const wchar_t* BreakpadWin::pipe_name_ = kGoogleUpdatePipeName; | |
105 | |
106 BreakpadWin::BreakpadWin() : handling_exception_(0) { | |
107 // Disable the message box for assertions. | |
108 _CrtSetReportMode(_CRT_ASSERT, 0); | |
109 | |
110 // Get the alternate dump directory. We use the temp path. | |
111 // N.B. We don't use base::GetTempDir() here to avoid running more code then | |
112 // necessary before crashes can be properly reported. | |
113 wchar_t temp_directory[MAX_PATH + 1] = { 0 }; | |
114 DWORD length = GetTempPath(MAX_PATH, temp_directory); | |
115 if (length == 0) | |
116 return; | |
117 | |
118 // Minidump with stacks, PEB, TEB, unloaded module list and memory referenced | |
119 // from stack. | |
120 MINIDUMP_TYPE dump_type = static_cast<MINIDUMP_TYPE>( | |
121 MiniDumpWithProcessThreadData | | |
122 MiniDumpWithUnloadedModules | | |
123 MiniDumpWithIndirectlyReferencedMemory); | |
124 breakpad_.reset( | |
125 new google_breakpad::ExceptionHandler( | |
126 temp_directory, &OnExceptionCallback, NULL, NULL, | |
127 google_breakpad::ExceptionHandler::HANDLER_ALL, dump_type, | |
128 pipe_name_, GetCustomInfo())); | |
129 | |
130 if (breakpad_->IsOutOfProcess()) { | |
131 // Tells breakpad to handle breakpoint and single step exceptions. | |
132 breakpad_->set_handle_debug_exceptions(true); | |
133 } | |
134 | |
135 // Catch exceptions thrown from a window procedure. | |
136 base::win::WinProcExceptionFilter exception_filter = | |
137 base::win::SetWinProcExceptionFilter(&OnWindowProcedureException); | |
138 CHECK(!exception_filter); | |
139 } | |
140 | |
141 BreakpadWin::~BreakpadWin() { | |
142 // This object should be leaked so that crashes occurred during the process | |
143 // shutdown will be caught. | |
144 NOTREACHED(); | |
145 } | |
146 | |
147 // static | |
148 BreakpadWin* BreakpadWin::GetInstance() { | |
149 return &g_instance.Get(); | |
150 } | |
151 | |
152 // Returns the Custom information to be used for crash reporting. | |
153 google_breakpad::CustomClientInfo* BreakpadWin::GetCustomInfo() { | |
154 HMODULE binary = base::GetModuleFromAddress( | |
155 reinterpret_cast<void*>(&remoting::InitializeCrashReporting)); | |
156 scoped_ptr<FileVersionInfo> version_info( | |
157 FileVersionInfo::CreateFileVersionInfoForModule(binary)); | |
158 | |
159 std::wstring version; | |
160 if (version_info.get()) | |
161 version = UTF16ToWide(version_info->product_version()); | |
162 if (version.empty()) | |
163 version = kBreakpadVersionDefault; | |
164 | |
165 static google_breakpad::CustomInfoEntry ver_entry( | |
166 kBreakpadVersionEntry, version.c_str()); | |
167 static google_breakpad::CustomInfoEntry prod_entry( | |
168 kBreakpadProdEntry, kBreakpadProductName); | |
169 static google_breakpad::CustomInfoEntry plat_entry( | |
170 kBreakpadPlatformEntry, kBreakpadPlatformWin32); | |
171 static google_breakpad::CustomInfoEntry entries[] = { | |
172 ver_entry, prod_entry, plat_entry }; | |
173 static google_breakpad::CustomClientInfo custom_info = { | |
174 entries, arraysize(entries) }; | |
175 return &custom_info; | |
176 } | |
177 | |
178 // static | |
179 bool BreakpadWin::OnExceptionCallback(void* /* context */, | |
180 EXCEPTION_POINTERS* /* exinfo */, | |
181 MDRawAssertionInfo* /* assertion */) { | |
Peter Kasting
2012/06/15 21:19:30
Nit: Don't comment out the parameter names. MSVC
alexeypa (please no reviews)
2012/06/15 21:25:55
This is required by Google's C++ style guide: http
Peter Kasting
2012/06/15 21:33:01
True; however, the underlying thrust of that item
| |
182 BreakpadWin* self = BreakpadWin::GetInstance(); | |
Peter Kasting
2012/06/15 21:19:30
Nit: You may also inline this in the following lin
alexeypa (please no reviews)
2012/06/15 22:13:57
This makes the line longer 80 characters.
Peter Kasting
2012/06/16 01:56:42
Well, appropriate wrapping was assumed :)
In any
| |
183 if (NoBarrier_CompareAndSwap(&self->handling_exception_, 0, 1) != 0) { | |
184 // Capture every thread except the first one in the sleep. We don't | |
185 // want multiple threads to concurrently report exceptions. | |
186 ::Sleep(INFINITE); | |
187 } | |
188 return true; | |
189 } | |
190 | |
191 // static | |
192 int BreakpadWin::OnWindowProcedureException(EXCEPTION_POINTERS* exinfo) { | |
193 BreakpadWin* self = BreakpadWin::GetInstance(); | |
194 if (self->breakpad_.get() != NULL) { | |
195 self->breakpad_->WriteMinidumpForException(exinfo); | |
196 ::TerminateProcess(::GetCurrentProcess(), | |
Peter Kasting
2012/06/15 21:19:30
Nit: ::
alexeypa (please no reviews)
2012/06/15 22:13:57
Done.
| |
197 exinfo->ExceptionRecord->ExceptionCode); | |
198 } | |
199 return EXCEPTION_CONTINUE_SEARCH; | |
200 } | |
201 | |
202 } // namespace | |
203 | |
204 namespace remoting { | |
205 | |
206 void InitializeCrashReporting() { | |
207 // Touch the object to make sure it is initialized. | |
208 BreakpadWin::GetInstance(); | |
209 } | |
210 | |
211 void InitializeCrashReportingForTest(const wchar_t* pipe_name) { | |
212 BreakpadWin::pipe_name_ = pipe_name; | |
213 InitializeCrashReporting(); | |
214 } | |
215 | |
216 } // namespace remoting | |
OLD | NEW |