1 // Copyright (c) 2011 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 // crash_report.cc : Implementation crash reporting. 6 #include "chrome_frame/crash_reporting/crash_report.h" 7 8 #include "base/basictypes.h" 9 #include "base/synchronization/lock.h" 10 #include "breakpad/src/client/windows/handler/exception_handler.h" 11 #include "chrome_frame/crash_reporting/crash_metrics.h" 12 13 // TODO(joshia): factor out common code with chrome used for crash reporting 14 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; 15 16 // This lock protects against concurrent access to g_breakpad. 17 static base::Lock g_breakpad_lock; 18 static google_breakpad::ExceptionHandler* g_breakpad = NULL; 19 20 // These minidump flag combinations have been tested safe against the 21 // DbgHelp.dll version that ships with Windows XP SP2. 22 const MINIDUMP_TYPE kSmallDumpType = static_cast<MINIDUMP_TYPE>( 23 MiniDumpWithProcessThreadData | // Get PEB and TEB. 24 MiniDumpWithUnloadedModules); // Get unloaded modules when available. 25 26 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( 27 MiniDumpWithProcessThreadData | // Get PEB and TEB. 28 MiniDumpWithUnloadedModules | // Get unloaded modules when available. 29 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. 30 31 // Large dump with all process memory. 32 const MINIDUMP_TYPE kFullDumpType = static_cast<MINIDUMP_TYPE>( 33 MiniDumpWithFullMemory | // Full memory from process. 34 MiniDumpWithProcessThreadData | // Get PEB and TEB. 35 MiniDumpWithHandleData | // Get all handle information. 36 MiniDumpWithUnloadedModules); // Get unloaded modules when available. 37 38 #pragma code_seg(push, ".text$va") 39 static void veh_segment_start() {} 40 #pragma code_seg(pop) 41 42 #pragma code_seg(push, ".text$vz") 43 static void veh_segment_end() {} 44 #pragma code_seg(pop) 45 46 // Place code in .text$veh_m. 47 #pragma code_seg(push, ".text$vm") 48 #include "chrome_frame/crash_reporting/vectored_handler-impl.h" 49 50 class CrashHandler { 51 public: 52 CrashHandler() : veh_id_(NULL), handler_(&crash_api_) {} 53 54 // Note that breakpad_lock is used to protect accesses to breakpad and must 55 // be held when Init() is called. 56 bool Init(google_breakpad::ExceptionHandler* breakpad, 57 base::Lock* breakpad_lock); 58 59 void Shutdown(); 60 private: 61 VectoredHandlerT<CrashHandlerTraits> handler_; 62 CrashHandlerTraits crash_api_; 63 void* veh_id_; 64 65 static LONG WINAPI VectoredHandlerEntryPoint(EXCEPTION_POINTERS* exptrs); 66 }; 67 68 static CrashHandler g_crash_handler; 69 70 // Turn off FPO optimization, so ::RtlCaptureStackBackTrace returns sane result. 71 #pragma optimize("y", off) 72 LONG WINAPI CrashHandler::VectoredHandlerEntryPoint( 73 EXCEPTION_POINTERS* exptrs) { 74 return g_crash_handler.handler_.Handler(exptrs); 75 } 76 #pragma optimize("y", on) 77 78 #pragma code_seg(pop) 79 80 bool CrashHandler::Init(google_breakpad::ExceptionHandler* breakpad, 81 base::Lock* breakpad_lock) { 82 DCHECK(breakpad); 83 DCHECK(breakpad_lock); 84 breakpad_lock->AssertAcquired(); 85 86 if (veh_id_) 87 return true; 88 89 crash_api_.Init(&veh_segment_start, &veh_segment_end, 90 &WriteMinidumpForException); 91 92 void* id = ::AddVectoredExceptionHandler(FALSE, &VectoredHandlerEntryPoint); 93 if (id != NULL) { 94 veh_id_ = id; 95 return true; 96 } else { 97 crash_api_.Shutdown(); 98 return false; 99 } 100 } 101 102 void CrashHandler::Shutdown() { 103 if (veh_id_) { 104 ::RemoveVectoredExceptionHandler(veh_id_); 105 veh_id_ = NULL; 106 } 107 108 crash_api_.Shutdown(); 109 } 110 111 std::wstring GetCrashServerPipeName(const std::wstring& user_sid) { 112 std::wstring pipe_name = kGoogleUpdatePipeName; 113 pipe_name += user_sid; 114 return pipe_name; 115 } 116 117 bool InitializeVectoredCrashReportingWithPipeName( 118 bool full_dump, 119 const wchar_t* pipe_name, 120 const std::wstring& dump_path, 121 google_breakpad::CustomClientInfo* client_info) { 122 base::AutoLock lock(g_breakpad_lock); 123 if (g_breakpad) 124 return true; 125 126 if (dump_path.empty()) { 127 return false; 128 } 129 130 // TODO(siggi): Consider switching to kSmallerDumpType post-beta. 131 MINIDUMP_TYPE dump_type = full_dump ? kFullDumpType : kLargerDumpType; 132 g_breakpad = new google_breakpad::ExceptionHandler( 133 dump_path, NULL, NULL, NULL, 134 google_breakpad::ExceptionHandler::HANDLER_INVALID_PARAMETER | 135 google_breakpad::ExceptionHandler::HANDLER_PURECALL, dump_type, 136 pipe_name, client_info); 137 138 if (!g_breakpad) 139 return false; 140 141 if (!g_crash_handler.Init(g_breakpad, &g_breakpad_lock)) { 142 delete g_breakpad; 143 g_breakpad = NULL; 144 return false; 145 } 146 147 return true; 148 } 149 150 bool InitializeVectoredCrashReporting( 151 bool full_dump, 152 const wchar_t* user_sid, 153 const std::wstring& dump_path, 154 google_breakpad::CustomClientInfo* client_info) { 155 DCHECK(user_sid); 156 DCHECK(client_info); 157 158 std::wstring pipe_name = GetCrashServerPipeName(user_sid); 159 160 return InitializeVectoredCrashReportingWithPipeName(full_dump, 161 pipe_name.c_str(), 162 dump_path, 163 client_info); 164 } 165 166 bool ShutdownVectoredCrashReporting() { 167 g_crash_handler.Shutdown(); 168 base::AutoLock lock(g_breakpad_lock); 169 delete g_breakpad; 170 g_breakpad = NULL; 171 return true; 172 } 173 174 bool WriteMinidumpForException(EXCEPTION_POINTERS* p) { 175 base::AutoLock lock(g_breakpad_lock); 176 CrashMetricsReporter::GetInstance()->IncrementMetric( 177 CrashMetricsReporter::CRASH_COUNT); 178 bool success = false; 179 if (g_breakpad) { 180 success = g_breakpad->WriteMinidumpForException(p); 181 } 182 return success; 183 } 184