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