Home | History | Annotate | Download | only in crash_reporting
      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