toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2006, Google Inc.
     2 // All rights reserved.
     3 //
     4 // Redistribution and use in source and binary forms, with or without
     5 // modification, are permitted provided that the following conditions are
     6 // met:
     7 //
     8 //     * Redistributions of source code must retain the above copyright
     9 // notice, this list of conditions and the following disclaimer.
    10 //     * Redistributions in binary form must reproduce the above
    11 // copyright notice, this list of conditions and the following disclaimer
    12 // in the documentation and/or other materials provided with the
    13 // distribution.
    14 //     * Neither the name of Google Inc. nor the names of its
    15 // contributors may be used to endorse or promote products derived from
    16 // this software without specific prior written permission.
    17 //
    18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    30 #include <ObjBase.h>
    32 #include <algorithm>
    33 #include <cassert>
    34 #include <cstdio>
    36 #include "common/windows/string_utils-inl.h"
    38 #include "client/windows/common/ipc_protocol.h"
    39 #include "client/windows/handler/exception_handler.h"
    40 #include "common/windows/guid_string.h"
    42 namespace google_breakpad {
    44 static const int kWaitForHandlerThreadMs = 60000;
    45 static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;
    47 // As documented on MSDN, on failure SuspendThread returns (DWORD) -1
    48 static const DWORD kFailedToSuspendThread = static_cast<DWORD>(-1);
    50 // This is passed as the context to the MinidumpWriteDump callback.
    51 typedef struct {
    52   AppMemoryList::const_iterator iter;
    53   AppMemoryList::const_iterator end;
    54 } MinidumpCallbackContext;
    56 vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
    57 LONG ExceptionHandler::handler_stack_index_ = 0;
    58 CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
    59 volatile LONG ExceptionHandler::instance_count_ = 0;
    61 ExceptionHandler::ExceptionHandler(const wstring& dump_path,
    62                                    FilterCallback filter,
    63                                    MinidumpCallback callback,
    64                                    void* callback_context,
    65                                    int handler_types,
    66                                    MINIDUMP_TYPE dump_type,
    67                                    const wchar_t* pipe_name,
    68                                    const CustomClientInfo* custom_info) {
    69   Initialize(dump_path,
    70              filter,
    71              callback,
    72              callback_context,
    73              handler_types,
    74              dump_type,
    75              pipe_name,
    76              NULL,
    77              custom_info);
    78 }
    80 ExceptionHandler::ExceptionHandler(const wstring& dump_path,
    81                                    FilterCallback filter,
    82                                    MinidumpCallback callback,
    83                                    void* callback_context,
    84                                    int handler_types,
    85                                    MINIDUMP_TYPE dump_type,
    86                                    HANDLE pipe_handle,
    87                                    const CustomClientInfo* custom_info) {
    88   Initialize(dump_path,
    89              filter,
    90              callback,
    91              callback_context,
    92              handler_types,
    93              dump_type,
    94              NULL,
    95              pipe_handle,
    96              custom_info);
    97 }  
    99 ExceptionHandler::ExceptionHandler(const wstring &dump_path,
   100                                    FilterCallback filter,
   101                                    MinidumpCallback callback,
   102                                    void* callback_context,
   103                                    int handler_types) {
   104   Initialize(dump_path,
   105              filter,
   106              callback,
   107              callback_context,
   108              handler_types,
   109              MiniDumpNormal,
   110              NULL,
   111              NULL,
   112              NULL);
   113 }
   115 void ExceptionHandler::Initialize(const wstring& dump_path,
   116                                   FilterCallback filter,
   117                                   MinidumpCallback callback,
   118                                   void* callback_context,
   119                                   int handler_types,
   120                                   MINIDUMP_TYPE dump_type,
   121                                   const wchar_t* pipe_name,
   122                                   HANDLE pipe_handle,
   123                                   const CustomClientInfo* custom_info) {
   124   LONG instance_count = InterlockedIncrement(&instance_count_);
   125   filter_ = filter;
   126   callback_ = callback;
   127   callback_context_ = callback_context;
   128   dump_path_c_ = NULL;
   129   next_minidump_id_c_ = NULL;
   130   next_minidump_path_c_ = NULL;
   131   dbghelp_module_ = NULL;
   132   minidump_write_dump_ = NULL;
   133   dump_type_ = dump_type;
   134   rpcrt4_module_ = NULL;
   135   uuid_create_ = NULL;
   136   handler_types_ = handler_types;
   137   previous_filter_ = NULL;
   138 #if _MSC_VER >= 1400  // MSVC 2005/8
   139   previous_iph_ = NULL;
   140 #endif  // _MSC_VER >= 1400
   141   previous_pch_ = NULL;
   142   handler_thread_ = NULL;
   143   is_shutdown_ = false;
   144   handler_start_semaphore_ = NULL;
   145   handler_finish_semaphore_ = NULL;
   146   requesting_thread_id_ = 0;
   147   exception_info_ = NULL;
   148   assertion_ = NULL;
   149   handler_return_value_ = false;
   150   handle_debug_exceptions_ = false;
   152   // Attempt to use out-of-process if user has specified a pipe.
   153   if (pipe_name != NULL || pipe_handle != NULL) {
   154     assert(!(pipe_name && pipe_handle));
   156     scoped_ptr<CrashGenerationClient> client;
   157     if (pipe_name) {
   158       client.reset(
   159         new CrashGenerationClient(pipe_name,
   160                                   dump_type_,
   161                                   custom_info));
   162     } else {
   163       client.reset(
   164         new CrashGenerationClient(pipe_handle,
   165                                   dump_type_,
   166                                   custom_info));
   167     }
   169     // If successful in registering with the monitoring process,
   170     // there is no need to setup in-process crash generation.
   171     if (client->Register()) {
   172       crash_generation_client_.reset(client.release());
   173     }
   174   }
   176   if (!IsOutOfProcess()) {
   177     // Either client did not ask for out-of-process crash generation
   178     // or registration with the server process failed. In either case,
   179     // setup to do in-process crash generation.
   181     // Set synchronization primitives and the handler thread.  Each
   182     // ExceptionHandler object gets its own handler thread because that's the
   183     // only way to reliably guarantee sufficient stack space in an exception,
   184     // and it allows an easy way to get a snapshot of the requesting thread's
   185     // context outside of an exception.
   186     InitializeCriticalSection(&handler_critical_section_);
   187     handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
   188     assert(handler_start_semaphore_ != NULL);
   190     handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
   191     assert(handler_finish_semaphore_ != NULL);
   193     // Don't attempt to create the thread if we could not create the semaphores.
   194     if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) {
   195       DWORD thread_id;
   196       handler_thread_ = CreateThread(NULL,         // lpThreadAttributes
   197                                      kExceptionHandlerThreadInitialStackSize,
   198                                      ExceptionHandlerThreadMain,
   199                                      this,         // lpParameter
   200                                      0,            // dwCreationFlags
   201                                      &thread_id);
   202       assert(handler_thread_ != NULL);
   203     }
   205     dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
   206     if (dbghelp_module_) {
   207       minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>(
   208           GetProcAddress(dbghelp_module_, "MiniDumpWriteDump"));
   209     }
   211     // Load this library dynamically to not affect existing projects.  Most
   212     // projects don't link against this directly, it's usually dynamically
   213     // loaded by dependent code.
   214     rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll");
   215     if (rpcrt4_module_) {
   216       uuid_create_ = reinterpret_cast<UuidCreate_type>(
   217           GetProcAddress(rpcrt4_module_, "UuidCreate"));
   218     }
   220     // set_dump_path calls UpdateNextID.  This sets up all of the path and id
   221     // strings, and their equivalent c_str pointers.
   222     set_dump_path(dump_path);
   223   }
   225   // Reserve one element for the instruction memory
   226   AppMemory instruction_memory;
   227   instruction_memory.ptr = NULL;
   228   instruction_memory.length = 0;
   229   app_memory_info_.push_back(instruction_memory);
   231   // There is a race condition here. If the first instance has not yet
   232   // initialized the critical section, the second (and later) instances may
   233   // try to use uninitialized critical section object. The feature of multiple
   234   // instances in one module is not used much, so leave it as is for now.
   235   // One way to solve this in the current design (that is, keeping the static
   236   // handler stack) is to use spin locks with volatile bools to synchronize
   237   // the handler stack. This works only if the compiler guarantees to generate
   238   // cache coherent code for volatile.
   239   // TODO(munjal): Fix this in a better way by changing the design if possible.
   241   // Lazy initialization of the handler_stack_critical_section_
   242   if (instance_count == 1) {
   243     InitializeCriticalSection(&handler_stack_critical_section_);
   244   }
   246   if (handler_types != HANDLER_NONE) {
   247     EnterCriticalSection(&handler_stack_critical_section_);
   249     // The first time an ExceptionHandler that installs a handler is
   250     // created, set up the handler stack.
   251     if (!handler_stack_) {
   252       handler_stack_ = new vector<ExceptionHandler*>();
   253     }
   254     handler_stack_->push_back(this);
   256     if (handler_types & HANDLER_EXCEPTION)
   257       previous_filter_ = SetUnhandledExceptionFilter(HandleException);
   259 #if _MSC_VER >= 1400  // MSVC 2005/8
   260     if (handler_types & HANDLER_INVALID_PARAMETER)
   261       previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter);
   262 #endif  // _MSC_VER >= 1400
   264     if (handler_types & HANDLER_PURECALL)
   265       previous_pch_ = _set_purecall_handler(HandlePureVirtualCall);
   267     LeaveCriticalSection(&handler_stack_critical_section_);
   268   }
   269 }
   271 ExceptionHandler::~ExceptionHandler() {
   272   if (dbghelp_module_) {
   273     FreeLibrary(dbghelp_module_);
   274   }
   276   if (rpcrt4_module_) {
   277     FreeLibrary(rpcrt4_module_);
   278   }
   280   if (handler_types_ != HANDLER_NONE) {
   281     EnterCriticalSection(&handler_stack_critical_section_);
   283     if (handler_types_ & HANDLER_EXCEPTION)
   284       SetUnhandledExceptionFilter(previous_filter_);
   286 #if _MSC_VER >= 1400  // MSVC 2005/8
   287     if (handler_types_ & HANDLER_INVALID_PARAMETER)
   288       _set_invalid_parameter_handler(previous_iph_);
   289 #endif  // _MSC_VER >= 1400
   291     if (handler_types_ & HANDLER_PURECALL)
   292       _set_purecall_handler(previous_pch_);
   294     if (handler_stack_->back() == this) {
   295       handler_stack_->pop_back();
   296     } else {
   297       // TODO(mmentovai): use advapi32!ReportEvent to log the warning to the
   298       // system's application event log.
   299       fprintf(stderr, "warning: removing Breakpad handler out of order\n");
   300       vector<ExceptionHandler*>::iterator iterator = handler_stack_->begin();
   301       while (iterator != handler_stack_->end()) {
   302         if (*iterator == this) {
   303           iterator = handler_stack_->erase(iterator);
   304         } else {
   305           ++iterator;
   306         }
   307       }
   308     }
   310     if (handler_stack_->empty()) {
   311       // When destroying the last ExceptionHandler that installed a handler,
   312       // clean up the handler stack.
   313       delete handler_stack_;
   314       handler_stack_ = NULL;
   315     }
   317     LeaveCriticalSection(&handler_stack_critical_section_);
   318   }
   320   // Some of the objects were only initialized if out of process
   321   // registration was not done.
   322   if (!IsOutOfProcess()) {
   323 #ifdef BREAKPAD_NO_TERMINATE_THREAD
   324     // Clean up the handler thread and synchronization primitives. The handler
   325     // thread is either waiting on the semaphore to handle a crash or it is
   326     // handling a crash. Coming out of the wait is fast but wait more in the
   327     // eventuality a crash is handled.  This compilation option results in a
   328     // deadlock if the exception handler is destroyed while executing code
   329     // inside DllMain.
   330     is_shutdown_ = true;
   331     ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
   332     WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);
   333 #else
   334     TerminateThread(handler_thread_, 1);
   335 #endif  // BREAKPAD_NO_TERMINATE_THREAD
   337     CloseHandle(handler_thread_);
   338     handler_thread_ = NULL;
   339     DeleteCriticalSection(&handler_critical_section_);
   340     CloseHandle(handler_start_semaphore_);
   341     CloseHandle(handler_finish_semaphore_);
   342   }
   344   // There is a race condition in the code below: if this instance is
   345   // deleting the static critical section and a new instance of the class
   346   // is created, then there is a possibility that the critical section be
   347   // initialized while the same critical section is being deleted. Given the
   348   // usage pattern for the code, this race condition is unlikely to hit, but it
   349   // is a race condition nonetheless.
   350   if (InterlockedDecrement(&instance_count_) == 0) {
   351     DeleteCriticalSection(&handler_stack_critical_section_);
   352   }
   353 }
   355 bool ExceptionHandler::RequestUpload(DWORD crash_id) {
   356   return crash_generation_client_->RequestUpload(crash_id);
   357 }
   359 // static
   360 DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) {
   361   ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter);
   362   assert(self);
   363   assert(self->handler_start_semaphore_ != NULL);
   364   assert(self->handler_finish_semaphore_ != NULL);
   366   while (true) {
   367     if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) ==
   368         WAIT_OBJECT_0) {
   369       // Perform the requested action.
   370       if (self->is_shutdown_) {
   371         // The instance of the exception handler is being destroyed.
   372         break;
   373       } else {
   374         self->handler_return_value_ =
   375             self->WriteMinidumpWithException(self->requesting_thread_id_,
   376                                              self->exception_info_,
   377                                              self->assertion_);
   378       }
   380       // Allow the requesting thread to proceed.
   381       ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL);
   382     }
   383   }
   385   // This statement is not reached when the thread is unconditionally
   386   // terminated by the ExceptionHandler destructor.
   387   return 0;
   388 }
   390 // HandleException and HandleInvalidParameter must create an
   391 // AutoExceptionHandler object to maintain static state and to determine which
   392 // ExceptionHandler instance to use.  The constructor locates the correct
   393 // instance, and makes it available through get_handler().  The destructor
   394 // restores the state in effect prior to allocating the AutoExceptionHandler.
   395 class AutoExceptionHandler {
   396  public:
   397   AutoExceptionHandler() {
   398     // Increment handler_stack_index_ so that if another Breakpad handler is
   399     // registered using this same HandleException function, and it needs to be
   400     // called while this handler is running (either because this handler
   401     // declines to handle the exception, or an exception occurs during
   402     // handling), HandleException will find the appropriate ExceptionHandler
   403     // object in handler_stack_ to deliver the exception to.
   404     //
   405     // Because handler_stack_ is addressed in reverse (as |size - index|),
   406     // preincrementing handler_stack_index_ avoids needing to subtract 1 from
   407     // the argument to |at|.
   408     //
   409     // The index is maintained instead of popping elements off of the handler
   410     // stack and pushing them at the end of this method.  This avoids ruining
   411     // the order of elements in the stack in the event that some other thread
   412     // decides to manipulate the handler stack (such as creating a new
   413     // ExceptionHandler object) while an exception is being handled.
   414     EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
   415     handler_ = ExceptionHandler::handler_stack_->at(
   416         ExceptionHandler::handler_stack_->size() -
   417         ++ExceptionHandler::handler_stack_index_);
   419     // In case another exception occurs while this handler is doing its thing,
   420     // it should be delivered to the previous filter.
   421     SetUnhandledExceptionFilter(handler_->previous_filter_);
   422 #if _MSC_VER >= 1400  // MSVC 2005/8
   423     _set_invalid_parameter_handler(handler_->previous_iph_);
   424 #endif  // _MSC_VER >= 1400
   425     _set_purecall_handler(handler_->previous_pch_);
   426   }
   428   ~AutoExceptionHandler() {
   429     // Put things back the way they were before entering this handler.
   430     SetUnhandledExceptionFilter(ExceptionHandler::HandleException);
   431 #if _MSC_VER >= 1400  // MSVC 2005/8
   432     _set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter);
   433 #endif  // _MSC_VER >= 1400
   434     _set_purecall_handler(ExceptionHandler::HandlePureVirtualCall);
   436     --ExceptionHandler::handler_stack_index_;
   437     LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
   438   }
   440   ExceptionHandler* get_handler() const { return handler_; }
   442  private:
   443   ExceptionHandler* handler_;
   444 };
   446 // static
   447 LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) {
   448   AutoExceptionHandler auto_exception_handler;
   449   ExceptionHandler* current_handler = auto_exception_handler.get_handler();
   451   // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions.  This
   452   // logic will short-circuit before calling WriteMinidumpOnHandlerThread,
   453   // allowing something else to handle the breakpoint without incurring the
   454   // overhead transitioning to and from the handler thread.  This behavior
   455   // can be overridden by calling ExceptionHandler::set_handle_debug_exceptions.
   456   DWORD code = exinfo->ExceptionRecord->ExceptionCode;
   457   LONG action;
   458   bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) ||
   459                             (code == EXCEPTION_SINGLE_STEP);
   461   bool success = false;
   463   if (!is_debug_exception ||
   464       current_handler->get_handle_debug_exceptions()) {
   465     // If out-of-proc crash handler client is available, we have to use that
   466     // to generate dump and we cannot fall back on in-proc dump generation
   467     // because we never prepared for an in-proc dump generation
   469     // In case of out-of-process dump generation, directly call
   470     // WriteMinidumpWithException since there is no separate thread running.
   471     if (current_handler->IsOutOfProcess()) {
   472       success = current_handler->WriteMinidumpWithException(
   473           GetCurrentThreadId(),
   474           exinfo,
   475           NULL);
   476     } else {
   477       success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL);
   478     }
   479   }
   481   // The handler fully handled the exception.  Returning
   482   // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually
   483   // results in the application being terminated.
   484   //
   485   // Note: If the application was launched from within the Cygwin
   486   // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the
   487   // application to be restarted.
   488   if (success) {
   489     action = EXCEPTION_EXECUTE_HANDLER;
   490   } else {
   491     // There was an exception, it was a breakpoint or something else ignored
   492     // above, or it was passed to the handler, which decided not to handle it.
   493     // This could be because the filter callback didn't want it, because
   494     // minidump writing failed for some reason, or because the post-minidump
   495     // callback function indicated failure.  Give the previous handler a
   496     // chance to do something with the exception.  If there is no previous
   497     // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger
   498     // or native "crashed" dialog to handle the exception.
   499     if (current_handler->previous_filter_) {
   500       action = current_handler->previous_filter_(exinfo);
   501     } else {
   502       action = EXCEPTION_CONTINUE_SEARCH;
   503     }
   504   }
   506   return action;
   507 }
   509 #if _MSC_VER >= 1400  // MSVC 2005/8
   510 // static
   511 void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression,
   512                                               const wchar_t* function,
   513                                               const wchar_t* file,
   514                                               unsigned int line,
   515                                               uintptr_t reserved) {
   516   // This is an invalid parameter, not an exception.  It's safe to play with
   517   // sprintf here.
   518   AutoExceptionHandler auto_exception_handler;
   519   ExceptionHandler* current_handler = auto_exception_handler.get_handler();
   521   MDRawAssertionInfo assertion;
   522   memset(&assertion, 0, sizeof(assertion));
   523   _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression),
   524                sizeof(assertion.expression) / sizeof(assertion.expression[0]),
   525                _TRUNCATE, L"%s", expression);
   526   _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function),
   527                sizeof(assertion.function) / sizeof(assertion.function[0]),
   528                _TRUNCATE, L"%s", function);
   529   _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file),
   530                sizeof(assertion.file) / sizeof(assertion.file[0]),
   531                _TRUNCATE, L"%s", file);
   532   assertion.line = line;
   533   assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;
   535   // Make up an exception record for the current thread and CPU context
   536   // to make it possible for the crash processor to classify these
   537   // as do regular crashes, and to make it humane for developers to
   538   // analyze them.
   539   EXCEPTION_RECORD exception_record = {};
   540   CONTEXT exception_context = {};
   541   EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };
   543   ::RtlCaptureContext(&exception_context);
   545   exception_record.ExceptionCode = STATUS_INVALID_PARAMETER;
   547   // We store pointers to the the expression and function strings,
   548   // and the line as exception parameters to make them easy to
   549   // access by the developer on the far side.
   550   exception_record.NumberParameters = 3;
   551   exception_record.ExceptionInformation[0] =
   552       reinterpret_cast<ULONG_PTR>(&assertion.expression);
   553   exception_record.ExceptionInformation[1] =
   554       reinterpret_cast<ULONG_PTR>(&assertion.file);
   555   exception_record.ExceptionInformation[2] = assertion.line;
   557   bool success = false;
   558   // In case of out-of-process dump generation, directly call
   559   // WriteMinidumpWithException since there is no separate thread running.
   560   if (current_handler->IsOutOfProcess()) {
   561     success = current_handler->WriteMinidumpWithException(
   562         GetCurrentThreadId(),
   563         &exception_ptrs,
   564         &assertion);
   565   } else {
   566     success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs,
   567                                                             &assertion);
   568   }
   570   if (!success) {
   571     if (current_handler->previous_iph_) {
   572       // The handler didn't fully handle the exception.  Give it to the
   573       // previous invalid parameter handler.
   574       current_handler->previous_iph_(expression,
   575                                      function,
   576                                      file,
   577                                      line,
   578                                      reserved);
   579     } else {
   580       // If there's no previous handler, pass the exception back in to the
   581       // invalid parameter handler's core.  That's the routine that called this
   582       // function, but now, since this function is no longer registered (and in
   583       // fact, no function at all is registered), this will result in the
   584       // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson.
   585       // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes
   586       // more information through.  In non-debug builds, it is not available,
   587       // so fall back to using _invalid_parameter_noinfo.  See invarg.c in the
   588       // CRT source.
   589 #ifdef _DEBUG
   590       _invalid_parameter(expression, function, file, line, reserved);
   591 #else  // _DEBUG
   592       _invalid_parameter_noinfo();
   593 #endif  // _DEBUG
   594     }
   595   }
   597   // The handler either took care of the invalid parameter problem itself,
   598   // or passed it on to another handler.  "Swallow" it by exiting, paralleling
   599   // the behavior of "swallowing" exceptions.
   600   exit(0);
   601 }
   602 #endif  // _MSC_VER >= 1400
   604 // static
   605 void ExceptionHandler::HandlePureVirtualCall() {
   606   // This is an pure virtual function call, not an exception.  It's safe to
   607   // play with sprintf here.
   608   AutoExceptionHandler auto_exception_handler;
   609   ExceptionHandler* current_handler = auto_exception_handler.get_handler();
   611   MDRawAssertionInfo assertion;
   612   memset(&assertion, 0, sizeof(assertion));
   613   assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL;
   615   // Make up an exception record for the current thread and CPU context
   616   // to make it possible for the crash processor to classify these
   617   // as do regular crashes, and to make it humane for developers to
   618   // analyze them.
   619   EXCEPTION_RECORD exception_record = {};
   620   CONTEXT exception_context = {};
   621   EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };
   623   ::RtlCaptureContext(&exception_context);
   625   exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
   627   // We store pointers to the the expression and function strings,
   628   // and the line as exception parameters to make them easy to
   629   // access by the developer on the far side.
   630   exception_record.NumberParameters = 3;
   631   exception_record.ExceptionInformation[0] =
   632       reinterpret_cast<ULONG_PTR>(&assertion.expression);
   633   exception_record.ExceptionInformation[1] =
   634       reinterpret_cast<ULONG_PTR>(&assertion.file);
   635   exception_record.ExceptionInformation[2] = assertion.line;
   637   bool success = false;
   638   // In case of out-of-process dump generation, directly call
   639   // WriteMinidumpWithException since there is no separate thread running.
   641   if (current_handler->IsOutOfProcess()) {
   642     success = current_handler->WriteMinidumpWithException(
   643         GetCurrentThreadId(),
   644         &exception_ptrs,
   645         &assertion);
   646   } else {
   647     success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs,
   648                                                             &assertion);
   649   }
   651   if (!success) {
   652     if (current_handler->previous_pch_) {
   653       // The handler didn't fully handle the exception.  Give it to the
   654       // previous purecall handler.
   655       current_handler->previous_pch_();
   656     } else {
   657       // If there's no previous handler, return and let _purecall handle it.
   658       // This will just put up an assertion dialog.
   659       return;
   660     }
   661   }
   663   // The handler either took care of the invalid parameter problem itself,
   664   // or passed it on to another handler.  "Swallow" it by exiting, paralleling
   665   // the behavior of "swallowing" exceptions.
   666   exit(0);
   667 }
   669 bool ExceptionHandler::WriteMinidumpOnHandlerThread(
   670     EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) {
   671   EnterCriticalSection(&handler_critical_section_);
   673   // There isn't much we can do if the handler thread
   674   // was not successfully created.
   675   if (handler_thread_ == NULL) {
   676     LeaveCriticalSection(&handler_critical_section_);
   677     return false;
   678   }
   680   // The handler thread should only be created when the semaphores are valid.
   681   assert(handler_start_semaphore_ != NULL);
   682   assert(handler_finish_semaphore_ != NULL);
   684   // Set up data to be passed in to the handler thread.
   685   requesting_thread_id_ = GetCurrentThreadId();
   686   exception_info_ = exinfo;
   687   assertion_ = assertion;
   689   // This causes the handler thread to call WriteMinidumpWithException.
   690   ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
   692   // Wait until WriteMinidumpWithException is done and collect its return value.
   693   WaitForSingleObject(handler_finish_semaphore_, INFINITE);
   694   bool status = handler_return_value_;
   696   // Clean up.
   697   requesting_thread_id_ = 0;
   698   exception_info_ = NULL;
   699   assertion_ = NULL;
   701   LeaveCriticalSection(&handler_critical_section_);
   703   return status;
   704 }
   706 bool ExceptionHandler::WriteMinidump() {
   707   // Make up an exception record for the current thread and CPU context
   708   // to make it possible for the crash processor to classify these
   709   // as do regular crashes, and to make it humane for developers to
   710   // analyze them.
   711   EXCEPTION_RECORD exception_record = {};
   712   CONTEXT exception_context = {};
   713   EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };
   715   ::RtlCaptureContext(&exception_context);
   716   exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
   718   return WriteMinidumpForException(&exception_ptrs);
   719 }
   721 bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) {
   722   // In case of out-of-process dump generation, directly call
   723   // WriteMinidumpWithException since there is no separate thread running.
   724   if (IsOutOfProcess()) {
   725     return WriteMinidumpWithException(GetCurrentThreadId(),
   726                                       exinfo,
   727                                       NULL);
   728   }
   730   bool success = WriteMinidumpOnHandlerThread(exinfo, NULL);
   731   UpdateNextID();
   732   return success;
   733 }
   735 // static
   736 bool ExceptionHandler::WriteMinidump(const wstring &dump_path,
   737                                      MinidumpCallback callback,
   738                                      void* callback_context) {
   739   ExceptionHandler handler(dump_path, NULL, callback, callback_context,
   740                            HANDLER_NONE);
   741   return handler.WriteMinidump();
   742 }
   744 // static
   745 bool ExceptionHandler::WriteMinidumpForChild(HANDLE child,
   746                                              DWORD child_blamed_thread,
   747                                              const wstring& dump_path,
   748                                              MinidumpCallback callback,
   749                                              void* callback_context) {
   750   EXCEPTION_RECORD ex;
   751   CONTEXT ctx;
   752   EXCEPTION_POINTERS exinfo = { NULL, NULL };
   753   DWORD last_suspend_count = kFailedToSuspendThread;
   754   HANDLE child_thread_handle = OpenThread(THREAD_GET_CONTEXT |
   755                                           THREAD_QUERY_INFORMATION |
   756                                           THREAD_SUSPEND_RESUME,
   757                                           FALSE,
   758                                           child_blamed_thread);
   759   // This thread may have died already, so not opening the handle is a
   760   // non-fatal error.
   761   if (child_thread_handle != NULL) {
   762     last_suspend_count = SuspendThread(child_thread_handle);
   763     if (last_suspend_count != kFailedToSuspendThread) {
   764       ctx.ContextFlags = CONTEXT_ALL;
   765       if (GetThreadContext(child_thread_handle, &ctx)) {
   766         memset(&ex, 0, sizeof(ex));
   767         ex.ExceptionCode = EXCEPTION_BREAKPOINT;
   768 #if defined(_M_IX86)
   769         ex.ExceptionAddress = reinterpret_cast<PVOID>(ctx.Eip);
   770 #elif defined(_M_X64)
   771         ex.ExceptionAddress = reinterpret_cast<PVOID>(ctx.Rip);
   772 #endif
   773         exinfo.ExceptionRecord = &ex;
   774         exinfo.ContextRecord = &ctx;
   775       }
   776     }
   777   }
   779   ExceptionHandler handler(dump_path, NULL, callback, callback_context,
   780                            HANDLER_NONE);
   781   bool success = handler.WriteMinidumpWithExceptionForProcess(
   782       child_blamed_thread,
   783       exinfo.ExceptionRecord ? &exinfo : NULL,
   784       NULL, child, false);
   786   if (last_suspend_count != kFailedToSuspendThread) {
   787     ResumeThread(child_thread_handle);
   788   }
   790   CloseHandle(child_thread_handle);
   792   if (callback) {
   793     success = callback(handler.dump_path_c_, handler.next_minidump_id_c_,
   794                        callback_context, NULL, NULL, success);
   795   }
   797   return success;
   798 }
   800 bool ExceptionHandler::WriteMinidumpWithException(
   801     DWORD requesting_thread_id,
   802     EXCEPTION_POINTERS* exinfo,
   803     MDRawAssertionInfo* assertion) {
   804   // Give user code a chance to approve or prevent writing a minidump.  If the
   805   // filter returns false, don't handle the exception at all.  If this method
   806   // was called as a result of an exception, returning false will cause
   807   // HandleException to call any previous handler or return
   808   // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear
   809   // as though this handler were not present at all.
   810   if (filter_ && !filter_(callback_context_, exinfo, assertion)) {
   811     return false;
   812   }
   814   bool success = false;
   815   if (IsOutOfProcess()) {
   816     success = crash_generation_client_->RequestDump(exinfo, assertion);
   817   } else {
   818     success = WriteMinidumpWithExceptionForProcess(requesting_thread_id,
   819                                                    exinfo,
   820                                                    assertion,
   821                                                    GetCurrentProcess(),
   822                                                    true);
   823   }
   825   if (callback_) {
   826     // TODO(munjal): In case of out-of-process dump generation, both
   827     // dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process
   828     // scenario, the server process ends up creating the dump path and dump
   829     // id so they are not known to the client.
   830     success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
   831                         exinfo, assertion, success);
   832   }
   834   return success;
   835 }
   837 // static
   838 BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback(
   839     PVOID context,
   840     const PMINIDUMP_CALLBACK_INPUT callback_input,
   841     PMINIDUMP_CALLBACK_OUTPUT callback_output) {
   842   switch (callback_input->CallbackType) {
   843   case MemoryCallback: {
   844     MinidumpCallbackContext* callback_context =
   845         reinterpret_cast<MinidumpCallbackContext*>(context);
   846     if (callback_context->iter == callback_context->end)
   847       return FALSE;
   849     // Include the specified memory region.
   850     callback_output->MemoryBase = callback_context->iter->ptr;
   851     callback_output->MemorySize = callback_context->iter->length;
   852     callback_context->iter++;
   853     return TRUE;
   854   }
   856     // Include all modules.
   857   case IncludeModuleCallback:
   858   case ModuleCallback:
   859     return TRUE;
   861     // Include all threads.
   862   case IncludeThreadCallback:
   863   case ThreadCallback:
   864     return TRUE;
   866     // Stop receiving cancel callbacks.
   867   case CancelCallback:
   868     callback_output->CheckCancel = FALSE;
   869     callback_output->Cancel = FALSE;
   870     return TRUE;
   871   }
   872   // Ignore other callback types.
   873   return FALSE;
   874 }
   876 bool ExceptionHandler::WriteMinidumpWithExceptionForProcess(
   877     DWORD requesting_thread_id,
   878     EXCEPTION_POINTERS* exinfo,
   879     MDRawAssertionInfo* assertion,
   880     HANDLE process,
   881     bool write_requester_stream) {
   882   bool success = false;
   883   if (minidump_write_dump_) {
   884     HANDLE dump_file = CreateFile(next_minidump_path_c_,
   885                                   GENERIC_WRITE,
   886                                   0,  // no sharing
   887                                   NULL,
   888                                   CREATE_NEW,  // fail if exists
   889                                   FILE_ATTRIBUTE_NORMAL,
   890                                   NULL);
   891     if (dump_file != INVALID_HANDLE_VALUE) {
   892       MINIDUMP_EXCEPTION_INFORMATION except_info;
   893       except_info.ThreadId = requesting_thread_id;
   894       except_info.ExceptionPointers = exinfo;
   895       except_info.ClientPointers = FALSE;
   897       // Leave room in user_stream_array for possible breakpad and
   898       // assertion info streams.
   899       MINIDUMP_USER_STREAM user_stream_array[2];
   900       MINIDUMP_USER_STREAM_INFORMATION user_streams;
   901       user_streams.UserStreamCount = 0;
   902       user_streams.UserStreamArray = user_stream_array;
   904       if (write_requester_stream) {
   905         // Add an MDRawBreakpadInfo stream to the minidump, to provide
   906         // additional information about the exception handler to the Breakpad
   907         // processor. The information will help the processor determine which
   908         // threads are relevant.  The Breakpad processor does not require this
   909         // information but can function better with Breakpad-generated dumps
   910         // when it is present. The native debugger is not harmed by the
   911         // presence of this information.
   912         MDRawBreakpadInfo breakpad_info;
   913         breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
   914                                  MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
   915         breakpad_info.dump_thread_id = GetCurrentThreadId();
   916         breakpad_info.requesting_thread_id = requesting_thread_id;
   918         int index = user_streams.UserStreamCount;
   919         user_stream_array[index].Type = MD_BREAKPAD_INFO_STREAM;
   920         user_stream_array[index].BufferSize = sizeof(breakpad_info);
   921         user_stream_array[index].Buffer = &breakpad_info;
   922         ++user_streams.UserStreamCount;
   923       }
   925       if (assertion) {
   926         int index = user_streams.UserStreamCount;
   927         user_stream_array[index].Type = MD_ASSERTION_INFO_STREAM;
   928         user_stream_array[index].BufferSize = sizeof(MDRawAssertionInfo);
   929         user_stream_array[index].Buffer = assertion;
   930         ++user_streams.UserStreamCount;
   931       }
   933       // Older versions of DbgHelp.dll don't correctly put the memory around
   934       // the faulting instruction pointer into the minidump. This
   935       // callback will ensure that it gets included.
   936       if (exinfo) {
   937         // Find a memory region of 256 bytes centered on the
   938         // faulting instruction pointer.
   939         const ULONG64 instruction_pointer =
   940 #if defined(_M_IX86)
   941           exinfo->ContextRecord->Eip;
   942 #elif defined(_M_AMD64)
   943         exinfo->ContextRecord->Rip;
   944 #else
   945 #error Unsupported platform
   946 #endif
   948         MEMORY_BASIC_INFORMATION info;
   949         if (VirtualQueryEx(process,
   950                            reinterpret_cast<LPCVOID>(instruction_pointer),
   951                            &info,
   952                            sizeof(MEMORY_BASIC_INFORMATION)) != 0 &&
   953             info.State == MEM_COMMIT) {
   954           // Attempt to get 128 bytes before and after the instruction
   955           // pointer, but settle for whatever's available up to the
   956           // boundaries of the memory region.
   957           const ULONG64 kIPMemorySize = 256;
   958           ULONG64 base =
   959             (std::max)(reinterpret_cast<ULONG64>(info.BaseAddress),
   960                        instruction_pointer - (kIPMemorySize / 2));
   961           ULONG64 end_of_range =
   962             (std::min)(instruction_pointer + (kIPMemorySize / 2),
   963                        reinterpret_cast<ULONG64>(info.BaseAddress)
   964                        + info.RegionSize);
   965           ULONG size = static_cast<ULONG>(end_of_range - base);
   967           AppMemory& elt = app_memory_info_.front();
   968           elt.ptr = base;
   969           elt.length = size;
   970         }
   971       }
   973       MinidumpCallbackContext context;
   974       context.iter = app_memory_info_.begin();
   975       context.end = app_memory_info_.end();
   977       // Skip the reserved element if there was no instruction memory
   978       if (context.iter->ptr == 0) {
   979         context.iter++;
   980       }
   982       MINIDUMP_CALLBACK_INFORMATION callback;
   983       callback.CallbackRoutine = MinidumpWriteDumpCallback;
   984       callback.CallbackParam = reinterpret_cast<void*>(&context);
   986       // The explicit comparison to TRUE avoids a warning (C4800).
   987       success = (minidump_write_dump_(process,
   988                                       GetProcessId(process),
   989                                       dump_file,
   990                                       dump_type_,
   991                                       exinfo ? &except_info : NULL,
   992                                       &user_streams,
   993                                       &callback) == TRUE);
   995       CloseHandle(dump_file);
   996     }
   997   }
   999   return success;
  1002 void ExceptionHandler::UpdateNextID() {
  1003   assert(uuid_create_);
  1004   UUID id = {0};
  1005   if (uuid_create_) {
  1006     uuid_create_(&id);
  1008   next_minidump_id_ = GUIDString::GUIDToWString(&id);
  1009   next_minidump_id_c_ = next_minidump_id_.c_str();
  1011   wchar_t minidump_path[MAX_PATH];
  1012   swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp",
  1013            dump_path_c_, next_minidump_id_c_);
  1015   // remove when VC++7.1 is no longer supported
  1016   minidump_path[MAX_PATH - 1] = L'\0';
  1018   next_minidump_path_ = minidump_path;
  1019   next_minidump_path_c_ = next_minidump_path_.c_str();
  1022 void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) {
  1023   AppMemoryList::iterator iter =
  1024     std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr);
  1025   if (iter != app_memory_info_.end()) {
  1026     // Don't allow registering the same pointer twice.
  1027     return;
  1030   AppMemory app_memory;
  1031   app_memory.ptr = reinterpret_cast<ULONG64>(ptr);
  1032   app_memory.length = static_cast<ULONG>(length);
  1033   app_memory_info_.push_back(app_memory);
  1036 void ExceptionHandler::UnregisterAppMemory(void* ptr) {
  1037   AppMemoryList::iterator iter =
  1038     std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr);
  1039   if (iter != app_memory_info_.end()) {
  1040     app_memory_info_.erase(iter);
  1044 }  // namespace google_breakpad

mercurial