exception_handler.cc revision 600e56bc39345e8fa38fa7d286e9f7382d75c2bf
15ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Copyright (c) 2006, Google Inc.
25ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// All rights reserved.
35ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis//
45ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Redistribution and use in source and binary forms, with or without
55ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// modification, are permitted provided that the following conditions are
65ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// met:
75ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis//
85ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis//     * Redistributions of source code must retain the above copyright
95ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// notice, this list of conditions and the following disclaimer.
105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis//     * Redistributions in binary form must reproduce the above
115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// copyright notice, this list of conditions and the following disclaimer
125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// in the documentation and/or other materials provided with the
135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// distribution.
145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis//     * Neither the name of Google Inc. nor the names of its
155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// contributors may be used to endorse or promote products derived from
165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// this software without specific prior written permission.
175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis//
185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include <map>
315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include <pthread.h>
325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include "client/mac/handler/exception_handler.h"
345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include "client/mac/handler/minidump_generator.h"
355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisnamespace google_airbag {
375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisusing std::map;
395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
405ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// These structures and techniques are illustrated in
415ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Mac OS X Internals, Amit Singh, ch 9.7
425ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionMessage {
435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_msg_header_t           header;
445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_msg_body_t             body;
455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_msg_port_descriptor_t  thread;
465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_msg_port_descriptor_t  task;
475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  NDR_record_t                ndr;
485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  exception_type_t            exception;
495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_msg_type_number_t      code_count;
505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  integer_t                   code[EXCEPTION_CODE_MAX];
515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  char                        padding[512];
525ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis};
535ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionParameters {
555ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  ExceptionParameters() : count(0) {}
565ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_msg_type_number_t count;
575ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  exception_mask_t masks[EXC_TYPES_COUNT];
585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_port_t ports[EXC_TYPES_COUNT];
595ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  exception_behavior_t behaviors[EXC_TYPES_COUNT];
605ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  thread_state_flavor_t flavors[EXC_TYPES_COUNT];
615ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis};
625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
635ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionReplyMessage {
645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_msg_header_t  header;
655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  NDR_record_t       ndr;
665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t      return_code;
675ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis};
685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
695ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Each thread needs to keep track of its ExceptionParameters.  Since the time
705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// that they are needed is when calling through exc_server(), we have no way
715ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// of retrieving the values from the class.  Therefore, we'll create a map
725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// that will allows storage per thread.
735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstatic map<pthread_t, ExceptionParameters *> *s_exception_parameter_map = NULL;
745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisextern "C"
765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis{
775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Forward declarations for functions that need "C" style compilation
785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  boolean_t exc_server(mach_msg_header_t *request,
795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                       mach_msg_header_t *reply);
805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t catch_exception_raise(mach_port_t target_port,
825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                      mach_port_t failed_thread,
835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                      mach_port_t task,
845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                      exception_type_t exception,
855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                      exception_data_t code,
865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                      mach_msg_type_number_t code_count);
875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t ForwardException(mach_port_t task,
895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                 mach_port_t failed_thread,
905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                 exception_type_t exception,
915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                 exception_data_t code,
925ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                 mach_msg_type_number_t code_count);
935ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t exception_raise(mach_port_t target_port,
955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                mach_port_t failed_thread,
965ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                mach_port_t task,
975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                exception_type_t exception,
985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                exception_data_t exception_code,
995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                mach_msg_type_number_t exception_code_count);
1005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t
1025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    exception_raise_state(mach_port_t target_port,
1035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          mach_port_t failed_thread,
1045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          mach_port_t task,
1055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          exception_type_t exception,
1065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          exception_data_t exception_code,
1075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          mach_msg_type_number_t code_count,
1085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          thread_state_flavor_t *target_flavor,
1095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          thread_state_t thread_state,
1105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          mach_msg_type_number_t thread_state_count,
1115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          thread_state_t thread_state,
1125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                          mach_msg_type_number_t *thread_state_count);
1135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t
1155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    exception_raise_state_identity(mach_port_t target_port,
1165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   mach_port_t failed_thread,
1175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   mach_port_t task,
1185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   exception_type_t exception,
1195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   exception_data_t exception_code,
1205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   mach_msg_type_number_t exception_code_count,
1215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   thread_state_flavor_t *target_flavor,
1225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   thread_state_t thread_state,
1235ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   mach_msg_type_number_t thread_state_count,
1245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   thread_state_t thread_state,
1255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   mach_msg_type_number_t *thread_state_count);
1265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
1275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisExceptionHandler::ExceptionHandler(const string &dump_path,
1295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   FilterCallback filter,
1305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   MinidumpCallback callback,
1315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   void *callback_context,
1325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                   bool install_handler)
1335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    : dump_path_(),
1345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      filter_(filter),
1355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      callback_(callback),
1365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      callback_context_(callback_context),
1375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      handler_thread_(NULL),
1385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      handler_port_(0),
1395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      previous_(NULL),
1405ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      installed_exception_handler_(false),
1415ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      is_in_teardown_(false),
1425ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      last_minidump_write_result_(false),
1435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      use_minidump_write_mutex_(false) {
1445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // This will update to the ID and C-string pointers
1455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  set_dump_path(dump_path);
1465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  MinidumpGenerator::GatherSystemInformation();
1475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  Setup(install_handler);
1485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
1495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisExceptionHandler::~ExceptionHandler() {
1515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  Teardown();
1525ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
1535ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::WriteMinidump() {
1555ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // If we're currently writing, just return
1565ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (use_minidump_write_mutex_)
1575ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    return false;
1585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1595ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  use_minidump_write_mutex_ = true;
1605ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  last_minidump_write_result_ = false;
1615ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Lock the mutex.  Since we just created it, this will return immediately.
1635ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (pthread_mutex_lock(&minidump_write_mutex_) == 0) {
1645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    // Send an empty message to the handle port so that a minidump will
1655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    // be written
1665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    SendEmptyMachMessage();
1675ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    // Wait for the minidump writer to complete its writing.  It will unlock
1695ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    // the mutex when completed
1705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    pthread_mutex_lock(&minidump_write_mutex_);
1715ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
1725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  use_minidump_write_mutex_ = false;
1745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  UpdateNextID();
1755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return last_minidump_write_result_;
1765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
1775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// static
1795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::WriteMinidump(const string &dump_path,
1805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                     MinidumpCallback callback,
1815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                     void *callback_context) {
1825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  ExceptionHandler handler(dump_path, NULL, callback, callback_context, false);
1835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return handler.WriteMinidump();
1845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
1855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::WriteMinidumpWithException(int exception_type,
1875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                  int exception_code,
1885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                  mach_port_t thread_name) {
1895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  bool result = false;
1905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  string minidump_id;
1915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
1925ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Putting the MinidumpGenerator in its own context will ensure that the
1935ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // destructor is executed, closing the newly created minidump file.
1945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (!dump_path_.empty()) {
1955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    MinidumpGenerator md;
1965ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    if (exception_type && exception_code) {
1975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      // If this is a real exception, give the filter (if any) a chance to
1985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      // decided if this should be sent
1995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      if (filter_ && !filter_(callback_context_))
2005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        return false;
2015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      md.SetExceptionInformation(exception_type, exception_code, thread_name);
2035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    }
2045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    result = md.Write(next_minidump_path_c_);
2065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
2075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Call user specified callback (if any)
2095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (callback_) {
2105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    // If the user callback returned true and we're handling an exception
2115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    // (rather than just writing out the file), then we should exit without
2125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    // forwarding the exception to the next handler.
2135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
2145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                  result)) {
2155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      if (exception_type && exception_code)
2165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        exit(exception_type);
2175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    }
2185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
2195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return result;
2215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
2225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2235ac2b9a569890f165478f91670dcdd553ce2d10ewayloniskern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
2245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                               exception_type_t exception,
2255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                               exception_data_t code,
2265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                               mach_msg_type_number_t code_count) {
227600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  map<pthread_t, ExceptionParameters *>::iterator previous_location =
228600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    s_exception_parameter_map->find(pthread_self());
2295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // If we don't have the previous data, we need to just exit
231600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  if (previous_location == (*s_exception_parameter_map).end())
2325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    exit(exception);
2335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
234600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  ExceptionParameters *previous = (*previous_location).second;
235600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis
2365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Find the first exception handler that matches the exception
2375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  unsigned int found;
2385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  for (found = 0; found < previous->count; ++found) {
2395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    if (previous->masks[found] & (1 << exception)) {
2405ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      break;
2415ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    }
2425ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
2435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Nothing to forward
2455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (found == previous->count) {
2465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    fprintf(stderr, "** No previous ports for forwarding!! \n");
2475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    exit(KERN_FAILURE);
2485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
2495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_port_t target_port = previous->ports[found];
2515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  exception_behavior_t target_behavior = previous->behaviors[found];
2525ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  thread_state_flavor_t target_flavor = previous->flavors[found];
2535ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t result;
2545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2555ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
2565ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  thread_state_data_t thread_state;
2575ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  switch (target_behavior) {
2585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    case EXCEPTION_DEFAULT:
2595ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      result = exception_raise(target_port, failed_thread, task, exception,
2605ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                               code, code_count);
2615ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      break;
2625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2635ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    case EXCEPTION_STATE:
2645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      result = thread_get_state(failed_thread, target_flavor, thread_state,
2655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                &thread_state_count);
2665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      if (result == KERN_SUCCESS)
2675ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        result = exception_raise_state(target_port, failed_thread, task,
2685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                       exception, code,
2695ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                       code_count, &target_flavor,
2705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                       thread_state, thread_state_count,
2715ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                       thread_state, &thread_state_count);
2725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      if (result == KERN_SUCCESS)
2735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        result = thread_set_state(failed_thread, target_flavor, thread_state,
2745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                  thread_state_count);
2755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      break;
2765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    case EXCEPTION_STATE_IDENTITY:
2785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      result = thread_get_state(failed_thread, target_flavor, thread_state,
2795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                &thread_state_count);
2805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      if (result == KERN_SUCCESS)
2815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        result = exception_raise_state_identity(target_port, failed_thread,
2825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                task, exception, code,
2835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                code_count, &target_flavor,
2845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                thread_state,
2855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                thread_state_count,
2865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                thread_state,
2875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                &thread_state_count);
2885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      if (result == KERN_SUCCESS)
2895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        result = thread_set_state(failed_thread, target_flavor, thread_state,
2905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                  thread_state_count);
2915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      break;
2925ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2935ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    default:
2945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      result = KERN_FAILURE;
2955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      break;
2965ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
2975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
2985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return result;
2995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
3005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Callback from exc_server()
3025ac2b9a569890f165478f91670dcdd553ce2d10ewayloniskern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
3035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                    mach_port_t task,
3045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                    exception_type_t exception,
3055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                    exception_data_t code,
3065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                    mach_msg_type_number_t code_count) {
3075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return ForwardException(task, failed_thread, exception, code, code_count);
3085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
3095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// static
3115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisvoid *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
3125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  ExceptionHandler *self =
3135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    reinterpret_cast<ExceptionHandler *>(exception_handler_class);
3145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  ExceptionMessage receive;
3155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Save a pointer to our instance so that it will be available in the
3175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // routines that are called from exc_server();
318600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  if (!s_exception_parameter_map) {
319600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    try {
320600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis      s_exception_parameter_map = new map<pthread_t, ExceptionParameters *>;
321600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    }
322600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    catch (std::bad_alloc) {
323600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis      return NULL;
324600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    }
325600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  }
3265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  (*s_exception_parameter_map)[pthread_self()] = self->previous_;
3285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Wait for the exception info
3305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  while (1) {
3315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    receive.header.msgh_local_port = self->handler_port_;
3325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    receive.header.msgh_size = sizeof(receive);
3335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    kern_return_t result = mach_msg(&(receive.header),
3345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                    MACH_RCV_MSG | MACH_RCV_LARGE, 0,
3355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                    sizeof(receive), self->handler_port_,
3365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                    MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
3375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    if (result == KERN_SUCCESS) {
3395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      // Uninstall our handler so that we don't get in a loop if the process of
340600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis      // writing out a minidump causes an exception.  However, if the exception
341600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis      // was caused by a fork'd process, don't uninstall things
342600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis      if (receive.task.name == mach_task_self())
343600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        self->UninstallHandler();
3445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      // If the actual exception code is zero, then we're calling this handler
3465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      // in a way that indicates that we want to either exit this thread or
3475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      // generate a minidump
3485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      if (!receive.exception) {
3495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        if (self->is_in_teardown_)
3505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis          return NULL;
3515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3525ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        // Write out the dump and save the result for later retrieval
3535ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        self->last_minidump_write_result_ =
3545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis          self->WriteMinidumpWithException(0, 0, 0);
3555ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        if (self->use_minidump_write_mutex_)
3565ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis          pthread_mutex_unlock(&self->minidump_write_mutex_);
3575ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      } else {
358600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        // When forking a child process with the exception handler installed,
359600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        // if the child crashes, it will send the exception back to the parent
360600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        // process.  The check for task == self_task() ensures that only
361600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        // exceptions that occur in the parent process are caught and
362600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        // processed.
363600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        if (receive.task.name == mach_task_self()) {
364600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis
365600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          // Generate the minidump with the exception data.
366600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          self->WriteMinidumpWithException(receive.exception, receive.code[0],
367600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis                                           receive.thread.name);
368600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis
369600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          // Pass along the exception to the server, which will setup the
370600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          // message and call catch_exception_raise() and put the KERN_SUCCESS
371600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          // into the reply.
372600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          ExceptionReplyMessage reply;
373600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          if (!exc_server(&receive.header, &reply.header))
374600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis            exit(1);
375600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis
376600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          // Send a reply and exit
377600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          result = mach_msg(&(reply.header), MACH_SEND_MSG,
378600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis                            reply.header.msgh_size, 0, MACH_PORT_NULL,
379600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis                            MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
380600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        } else {
381600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis          // An exception occurred in a child process
382600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis        }
3835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      }
3845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    }
3855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
3865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return NULL;
3885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
3895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
3905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::InstallHandler() {
391600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  // Only catch these three exceptions.  The other ones are nebulously defined
392600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  // and may result in treating a non-fatal exception as fatal.
393600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS |
394600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC;
3955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
396600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  try {
397600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    previous_ = new ExceptionParameters();
398600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  }
399600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  catch (std::bad_alloc) {
400600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    return false;
401600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  }
402600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis
403600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis  // Save the current exception ports so that we can forward to them
4045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  previous_->count = EXC_TYPES_COUNT;
4055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_port_t current_task = mach_task_self();
4065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t result = task_get_exception_ports(current_task, exception_mask,
4075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                  previous_->masks,
4085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                  &previous_->count,
4095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                  previous_->ports,
4105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                  previous_->behaviors,
4115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                                  previous_->flavors);
4125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Setup the exception ports on this task
4145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (result == KERN_SUCCESS)
4155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    result = task_set_exception_ports(current_task, exception_mask,
4165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                      handler_port_, EXCEPTION_DEFAULT,
4175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                      THREAD_STATE_NONE);
4185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  installed_exception_handler_ = (result == KERN_SUCCESS);
4205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return installed_exception_handler_;
4225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
4235ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::UninstallHandler() {
4255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t result = KERN_SUCCESS;
4265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (installed_exception_handler_) {
4285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    mach_port_t current_task = mach_task_self();
4295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    // Restore the previous ports
4315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    for (unsigned int i = 0; i < previous_->count; ++i) {
4325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis       result = task_set_exception_ports(current_task, previous_->masks[i],
4335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                        previous_->ports[i],
4345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                        previous_->behaviors[i],
4355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                        previous_->flavors[i]);
4365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      if (result != KERN_SUCCESS)
4375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis        return false;
4385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    }
4395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4405ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    delete previous_;
4415ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    previous_ = NULL;
4425ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    installed_exception_handler_ = false;
4435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
4445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return result == KERN_SUCCESS;
4465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
4475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::Setup(bool install_handler) {
4495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (pthread_mutex_init(&minidump_write_mutex_, NULL))
4505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    return false;
4515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4525ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Create a receive right
4535ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  mach_port_t current_task = mach_task_self();
4545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t result = mach_port_allocate(current_task,
4555ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                            MACH_PORT_RIGHT_RECEIVE,
4565ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                            &handler_port_);
4575ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Add send right
4585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (result == KERN_SUCCESS)
4595ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    result = mach_port_insert_right(current_task, handler_port_, handler_port_,
4605ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                    MACH_MSG_TYPE_MAKE_SEND);
4615ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (install_handler && result == KERN_SUCCESS)
4635ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    if (!InstallHandler())
4645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      return false;
4655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (result == KERN_SUCCESS) {
467600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    // Install the handler in its own thread, detached as we won't be joining.
468600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    pthread_attr_t attr;
469600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    pthread_attr_init(&attr);
470600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
471600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    int thread_create_result = pthread_create(&handler_thread_, &attr,
472600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis                                              &WaitForMessage, this);
473600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    pthread_attr_destroy(&attr);
474600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis    result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS;
4755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
4765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return result == KERN_SUCCESS ? true : false;
4785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
4795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::Teardown() {
4815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t result = KERN_SUCCESS;
4825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  is_in_teardown_ = true;
4835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (!UninstallHandler())
4855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    return false;
4865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  // Send an empty message so that the handler_thread exits
4885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (SendEmptyMachMessage()) {
4895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    mach_port_t current_task = mach_task_self();
4905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    result = mach_port_deallocate(current_task, handler_port_);
4915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    if (result != KERN_SUCCESS)
4925ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis      return false;
4935ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  } else {
4945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    return false;
4955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  }
4965ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  if (s_exception_parameter_map)
4975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    s_exception_parameter_map->erase(handler_thread_);
4985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
4995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  handler_thread_ = NULL;
5005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  handler_port_ = NULL;
5015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  pthread_mutex_destroy(&minidump_write_mutex_);
5025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
5035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return result == KERN_SUCCESS;
5045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
5055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
5065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::SendEmptyMachMessage() {
5075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  ExceptionMessage empty;
5085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  memset(&empty, 0, sizeof(empty));
5095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  empty.header.msgh_size = sizeof(empty) - sizeof(empty.padding);
5105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  empty.header.msgh_remote_port = handler_port_;
5115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  empty.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
5125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                          MACH_MSG_TYPE_MAKE_SEND_ONCE);
5135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  kern_return_t result = mach_msg(&(empty.header),
5145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                  MACH_SEND_MSG | MACH_SEND_TIMEOUT,
5155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                  empty.header.msgh_size, 0, 0,
5165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis                                  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
5175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
5185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  return result == KERN_SUCCESS;
5195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
5205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
5215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisvoid ExceptionHandler::UpdateNextID() {
5225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  next_minidump_path_ =
5235ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis    (MinidumpGenerator::UniqueNameInDirectory(dump_path_, &next_minidump_id_));
5245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
5255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  next_minidump_path_c_ = next_minidump_path_.c_str();
5265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis  next_minidump_id_c_ = next_minidump_id_.c_str();
5275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}
5285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis
5295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}  // namespace google_airbag
530