exception_handler.cc revision cb037254a19ee46b1bea0cfc64128b718924fbd3
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 30a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#include <mach/exc.h> 31a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#include <mach/mig.h> 325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include <pthread.h> 33094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#include <signal.h> 34f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#include <TargetConditionals.h> 355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 3645951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org#include <map> 3745951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org 385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include "client/mac/handler/exception_handler.h" 395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis#include "client/mac/handler/minidump_generator.h" 409be806efde6c55fbd7e9443d2700255835019a03ted.mielczarek#include "common/mac/macho_utilities.h" 41144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com#include "common/mac/scoped_task_suspend-inl.h" 42f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org#include "google_breakpad/common/minidump_exception_mac.h" 435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4445951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org#ifndef __EXCEPTIONS 4545951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org// This file uses C++ try/catch (but shouldn't). Duplicate the macros from 4645951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org// <c++/4.2.1/exception_defines.h> allowing this file to work properly with 4745951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org// exceptions disabled even when other C++ libraries are used. #undef the try 4845951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org// and catch macros first in case libstdc++ is in use and has already provided 4945951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org// its own definitions. 5045951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org#undef try 5145951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org#define try if (true) 5245951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org#undef catch 5345951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org#define catch(X) if (false) 5445951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org#endif // __EXCEPTIONS 5545951cc9403390df6b2db7a43cbf1eecedad1c78mark@chromium.org 5669d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#ifndef USE_PROTECTED_ALLOCATIONS 57f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#if TARGET_OS_IPHONE 58f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#define USE_PROTECTED_ALLOCATIONS 1 59f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#else 6069d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#define USE_PROTECTED_ALLOCATIONS 0 6169d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#endif 62f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#endif 6369d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker 6469d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker// If USE_PROTECTED_ALLOCATIONS is activated then the 6569d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker// gBreakpadAllocator needs to be setup in other code 6669d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker// ahead of time. Please see ProtectedMemoryAllocator.h 6769d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker// for more details. 6869d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#if USE_PROTECTED_ALLOCATIONS 6969d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker #include "protected_memory_allocator.h" 7069d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker extern ProtectedMemoryAllocator *gBreakpadAllocator; 7169d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#endif 7269d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker 73e5dc60822e5938fea2ae892ccddb906641ba174emmentovainamespace google_breakpad { 745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 75094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.orgstatic union { 76094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 77094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 78094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#endif 79094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org google_breakpad::ExceptionHandler *handler; 80094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org} gProtectedData; 81094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisusing std::map; 835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// These structures and techniques are illustrated in 855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Mac OS X Internals, Amit Singh, ch 9.7 865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionMessage { 875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_header_t header; 885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_body_t body; 895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_port_descriptor_t thread; 905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_port_descriptor_t task; 915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis NDR_record_t ndr; 925ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_type_t exception; 935ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_type_number_t code_count; 945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis integer_t code[EXCEPTION_CODE_MAX]; 955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis char padding[512]; 965ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}; 975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionParameters { 995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis ExceptionParameters() : count(0) {} 1005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_type_number_t count; 1015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_mask_t masks[EXC_TYPES_COUNT]; 1025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t ports[EXC_TYPES_COUNT]; 1035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_behavior_t behaviors[EXC_TYPES_COUNT]; 1045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis thread_state_flavor_t flavors[EXC_TYPES_COUNT]; 1055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}; 1065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionReplyMessage { 1085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_header_t header; 1095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis NDR_record_t ndr; 1105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t return_code; 1115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}; 1125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 113983264848d5372d8e64d62eb67f672c71e4b6470waylonis// Only catch these three exceptions. The other ones are nebulously defined 114983264848d5372d8e64d62eb67f672c71e4b6470waylonis// and may result in treating a non-fatal exception as fatal. 11532441cc0608ddaf81885d23acf63f4b53cb73744nealsidexception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS | 116649967cfd28116ad8a1ff3e84d86a1156b462536ladderbreakerEXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT; 1175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 118a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#if !TARGET_OS_IPHONE 119c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.orgextern "C" { 1205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Forward declarations for functions that need "C" style compilation 121c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org boolean_t exc_server(mach_msg_header_t* request, 122c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org mach_msg_header_t* reply); 1235ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 124ebebd0fcef7540fc51c23de50d45e79e260a30cbmmentovai // This symbol must be visible to dlsym() - see 125ebebd0fcef7540fc51c23de50d45e79e260a30cbmmentovai // http://code.google.com/p/google-breakpad/issues/detail?id=345 for details. 1265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t catch_exception_raise(mach_port_t target_port, 1275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t failed_thread, 1285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t task, 1295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_type_t exception, 1305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_data_t code, 131ebebd0fcef7540fc51c23de50d45e79e260a30cbmmentovai mach_msg_type_number_t code_count) 132ebebd0fcef7540fc51c23de50d45e79e260a30cbmmentovai __attribute__((visibility("default"))); 133a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org} 134a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#endif 135a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 136a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.orgkern_return_t ForwardException(mach_port_t task, 137a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_port_t failed_thread, 138a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_type_t exception, 139a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_data_t code, 140a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_type_number_t code_count); 141a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 142a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#if TARGET_OS_IPHONE 143a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org// Implementation is based on the implementation generated by mig. 144c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.orgboolean_t breakpad_exc_server(mach_msg_header_t* InHeadP, 145c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org mach_msg_header_t* OutHeadP) { 146c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_bits = 147c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0); 148c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port; 149c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org /* Minimal size: routine() will update it if different */ 150c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t); 151c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_local_port = MACH_PORT_NULL; 152c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_id = InHeadP->msgh_id + 100; 153a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 154a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org if (InHeadP->msgh_id != 2401) { 155c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org ((mig_reply_error_t*)OutHeadP)->NDR = NDR_record; 156c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org ((mig_reply_error_t*)OutHeadP)->RetCode = MIG_BAD_ID; 157a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return FALSE; 158a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } 159a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 160a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#ifdef __MigPackStructs 161a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#pragma pack(4) 162a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#endif 163a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org typedef struct { 164a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_header_t Head; 165a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org /* start of the kernel processed data */ 166a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_body_t msgh_body; 167a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_port_descriptor_t thread; 168a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_port_descriptor_t task; 169a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org /* end of the kernel processed data */ 170a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org NDR_record_t NDR; 171a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_type_t exception; 172a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_type_number_t codeCnt; 173a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org integer_t code[2]; 174a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_trailer_t trailer; 175a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } Request; 176a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 177a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org typedef struct { 178a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_header_t Head; 179a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org NDR_record_t NDR; 180a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org kern_return_t RetCode; 181a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } Reply; 182a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#ifdef __MigPackStructs 183a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#pragma pack() 184a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#endif 1855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 186c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org Request* In0P = (Request*)InHeadP; 187c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org Reply* OutP = (Reply*)OutHeadP; 188a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 189a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org if (In0P->task.name != mach_task_self()) { 190a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return FALSE; 191a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } 192a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org OutP->RetCode = ForwardException(In0P->task.name, 193a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org In0P->thread.name, 194a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org In0P->exception, 195a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org In0P->code, 196a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org In0P->codeCnt); 197a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org OutP->NDR = NDR_record; 198a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return TRUE; 199a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org} 200a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#else 201c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.orgboolean_t breakpad_exc_server(mach_msg_header_t* request, 202c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org mach_msg_header_t* reply) { 203a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return exc_server(request, reply); 20485534c2eaf59a8deb3394aab8df466e65c998752nealsid} 20585534c2eaf59a8deb3394aab8df466e65c998752nealsid 206a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org// Callback from exc_server() 207a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.orgkern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread, 208a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_port_t task, 209a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_type_t exception, 210a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_data_t code, 211a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_type_number_t code_count) { 212a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org if (task != mach_task_self()) { 213a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return KERN_FAILURE; 214a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } 215a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return ForwardException(task, failed_thread, exception, code, code_count); 216a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org} 217a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#endif 218a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 2195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisExceptionHandler::ExceptionHandler(const string &dump_path, 2205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis FilterCallback filter, 2215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MinidumpCallback callback, 222c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org void* callback_context, 223315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com bool install_handler, 224c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org const char* port_name) 2255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis : dump_path_(), 2265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis filter_(filter), 2275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis callback_(callback), 2285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis callback_context_(callback_context), 229de2fd15db9a480c807ba337690669538a97756a4ladderbreaker directCallback_(NULL), 2305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis handler_thread_(NULL), 23132441cc0608ddaf81885d23acf63f4b53cb73744nealsid handler_port_(MACH_PORT_NULL), 2325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_(NULL), 2335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis installed_exception_handler_(false), 2345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis is_in_teardown_(false), 2355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis last_minidump_write_result_(false), 2365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis use_minidump_write_mutex_(false) { 2375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // This will update to the ID and C-string pointers 2385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis set_dump_path(dump_path); 2395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MinidumpGenerator::GatherSystemInformation(); 240f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#if !TARGET_OS_IPHONE 241315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com if (port_name) 242315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com crash_generation_client_.reset(new CrashGenerationClient(port_name)); 243f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#endif 2445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis Setup(install_handler); 2455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 2465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 247de2fd15db9a480c807ba337690669538a97756a4ladderbreaker// special constructor if we want to bypass minidump writing and 248de2fd15db9a480c807ba337690669538a97756a4ladderbreaker// simply get a callback with the exception information 249de2fd15db9a480c807ba337690669538a97756a4ladderbreakerExceptionHandler::ExceptionHandler(DirectCallback callback, 250c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org void* callback_context, 251de2fd15db9a480c807ba337690669538a97756a4ladderbreaker bool install_handler) 252de2fd15db9a480c807ba337690669538a97756a4ladderbreaker : dump_path_(), 253de2fd15db9a480c807ba337690669538a97756a4ladderbreaker filter_(NULL), 254de2fd15db9a480c807ba337690669538a97756a4ladderbreaker callback_(NULL), 255de2fd15db9a480c807ba337690669538a97756a4ladderbreaker callback_context_(callback_context), 256de2fd15db9a480c807ba337690669538a97756a4ladderbreaker directCallback_(callback), 257de2fd15db9a480c807ba337690669538a97756a4ladderbreaker handler_thread_(NULL), 25832441cc0608ddaf81885d23acf63f4b53cb73744nealsid handler_port_(MACH_PORT_NULL), 259de2fd15db9a480c807ba337690669538a97756a4ladderbreaker previous_(NULL), 260de2fd15db9a480c807ba337690669538a97756a4ladderbreaker installed_exception_handler_(false), 261de2fd15db9a480c807ba337690669538a97756a4ladderbreaker is_in_teardown_(false), 262de2fd15db9a480c807ba337690669538a97756a4ladderbreaker last_minidump_write_result_(false), 263de2fd15db9a480c807ba337690669538a97756a4ladderbreaker use_minidump_write_mutex_(false) { 264de2fd15db9a480c807ba337690669538a97756a4ladderbreaker MinidumpGenerator::GatherSystemInformation(); 265de2fd15db9a480c807ba337690669538a97756a4ladderbreaker Setup(install_handler); 266de2fd15db9a480c807ba337690669538a97756a4ladderbreaker} 267de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 2685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisExceptionHandler::~ExceptionHandler() { 2695ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis Teardown(); 2705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 2715ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 2720d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.combool ExceptionHandler::WriteMinidump(bool write_exception_stream) { 2735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // If we're currently writing, just return 2745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (use_minidump_write_mutex_) 2755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 2765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 2775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis use_minidump_write_mutex_ = true; 2785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis last_minidump_write_result_ = false; 2795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 2805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Lock the mutex. Since we just created it, this will return immediately. 2815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (pthread_mutex_lock(&minidump_write_mutex_) == 0) { 2825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Send an empty message to the handle port so that a minidump will 2835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // be written 284cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com bool result = SendMessageToHandlerThread(write_exception_stream ? 285cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com kWriteDumpWithExceptionMessage : 286cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com kWriteDumpMessage); 287cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com if (!result) { 288cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com pthread_mutex_unlock(&minidump_write_mutex_); 289cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com return false; 290cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com } 2915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 2925ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Wait for the minidump writer to complete its writing. It will unlock 2935ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // the mutex when completed 2945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis pthread_mutex_lock(&minidump_write_mutex_); 2955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 29632441cc0608ddaf81885d23acf63f4b53cb73744nealsid 2975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis use_minidump_write_mutex_ = false; 2985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis UpdateNextID(); 2995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return last_minidump_write_result_; 3005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 3015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 3025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// static 3035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::WriteMinidump(const string &dump_path, 3040d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com bool write_exception_stream, 3055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MinidumpCallback callback, 306c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org void* callback_context) { 307315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com ExceptionHandler handler(dump_path, NULL, callback, callback_context, false, 308c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org NULL); 3090d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com return handler.WriteMinidump(write_exception_stream); 3105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 3115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 312144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com// static 313144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.combool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, 314c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org mach_port_t child_blamed_thread, 315c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org const string &dump_path, 316c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org MinidumpCallback callback, 317c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org void* callback_context) { 318144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com ScopedTaskSuspend suspend(child); 319144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com 320144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com MinidumpGenerator generator(child, MACH_PORT_NULL); 321144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com string dump_id; 322144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com string dump_filename = generator.UniqueNameInDirectory(dump_path, &dump_id); 323144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com 324144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com generator.SetExceptionInformation(EXC_BREAKPOINT, 325c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#if defined(__i386__) || defined(__x86_64__) 326c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org EXC_I386_BPT, 327c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#elif defined(__ppc__) || defined(__ppc64__) 328c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org EXC_PPC_BREAKPOINT, 329c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#elif defined(__arm__) 330c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org EXC_ARM_BREAKPOINT, 331144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com#else 3320d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com#error architecture not supported 333144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com#endif 334c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org 0, 335c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org child_blamed_thread); 336144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com bool result = generator.Write(dump_filename.c_str()); 337144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com 338144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com if (callback) { 339144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com return callback(dump_path.c_str(), dump_id.c_str(), 340c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org callback_context, result); 341144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com } 342144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com return result; 343144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com} 344144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com 3455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::WriteMinidumpWithException(int exception_type, 3465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis int exception_code, 34761e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek int exception_subcode, 348c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org ucontext_t* task_context, 3490d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com mach_port_t thread_name, 350094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org bool exit_after_write, 351094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org bool report_current_thread) { 3525ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool result = false; 3535ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 354de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (directCallback_) { 355de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (directCallback_(callback_context_, 356de2fd15db9a480c807ba337690669538a97756a4ladderbreaker exception_type, 357de2fd15db9a480c807ba337690669538a97756a4ladderbreaker exception_code, 35861e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek exception_subcode, 359de2fd15db9a480c807ba337690669538a97756a4ladderbreaker thread_name) ) { 3600d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (exit_after_write) 3613d55532df2ea6bc8809513e8add14fb84bc62a62ladderbreaker _exit(exception_type); 3625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 363f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#if !TARGET_OS_IPHONE 364315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com } else if (IsOutOfProcess()) { 365315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com if (exception_type && exception_code) { 366315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com // If this is a real exception, give the filter (if any) a chance to 367315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com // decide if this should be sent. 368315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com if (filter_ && !filter_(callback_context_)) 369c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org return false; 3700828a485edb601a80b6cc3b09396da72b05a635dted.mielczarek@gmail.com result = crash_generation_client_->RequestDumpForException( 371c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org exception_type, 372c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org exception_code, 373c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org exception_subcode, 374c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org thread_name); 3750828a485edb601a80b6cc3b09396da72b05a635dted.mielczarek@gmail.com if (result && exit_after_write) { 3760828a485edb601a80b6cc3b09396da72b05a635dted.mielczarek@gmail.com _exit(exception_type); 3770828a485edb601a80b6cc3b09396da72b05a635dted.mielczarek@gmail.com } 378315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com } 379f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#endif 380de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } else { 381de2fd15db9a480c807ba337690669538a97756a4ladderbreaker string minidump_id; 382de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 383de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // Putting the MinidumpGenerator in its own context will ensure that the 384de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // destructor is executed, closing the newly created minidump file. 385de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (!dump_path_.empty()) { 386094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org MinidumpGenerator md(mach_task_self(), 3876ed1918848372f789d4bda96657b7454c3f6c2c1mark@chromium.org report_current_thread ? MACH_PORT_NULL : 3886ed1918848372f789d4bda96657b7454c3f6c2c1mark@chromium.org mach_thread_self()); 38960a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org md.SetTaskContext(task_context); 390de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (exception_type && exception_code) { 391de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // If this is a real exception, give the filter (if any) a chance to 392315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com // decide if this should be sent. 393de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (filter_ && !filter_(callback_context_)) 394de2fd15db9a480c807ba337690669538a97756a4ladderbreaker return false; 395de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 39661e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek md.SetExceptionInformation(exception_type, exception_code, 39761e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek exception_subcode, thread_name); 398de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } 3995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 400de2fd15db9a480c807ba337690669538a97756a4ladderbreaker result = md.Write(next_minidump_path_c_); 401de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } 4025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 403de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // Call user specified callback (if any) 404de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (callback_) { 405de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // If the user callback returned true and we're handling an exception 406de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // (rather than just writing out the file), then we should exit without 407de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // forwarding the exception to the next handler. 40832441cc0608ddaf81885d23acf63f4b53cb73744nealsid if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, 409de2fd15db9a480c807ba337690669538a97756a4ladderbreaker result)) { 4100d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (exit_after_write) 4113d55532df2ea6bc8809513e8add14fb84bc62a62ladderbreaker _exit(exception_type); 412de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } 4135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 41532441cc0608ddaf81885d23acf63f4b53cb73744nealsid 4165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result; 4175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 4185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4195ac2b9a569890f165478f91670dcdd553ce2d10ewayloniskern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread, 4205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_type_t exception, 4215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_data_t code, 4225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_type_number_t code_count) { 423983264848d5372d8e64d62eb67f672c71e4b6470waylonis // At this time, we should have called Uninstall() on the exception handler 42432441cc0608ddaf81885d23acf63f4b53cb73744nealsid // so that the current exception ports are the ones that we should be 425983264848d5372d8e64d62eb67f672c71e4b6470waylonis // forwarding to. 426983264848d5372d8e64d62eb67f672c71e4b6470waylonis ExceptionParameters current; 42732441cc0608ddaf81885d23acf63f4b53cb73744nealsid 428983264848d5372d8e64d62eb67f672c71e4b6470waylonis current.count = EXC_TYPES_COUNT; 429983264848d5372d8e64d62eb67f672c71e4b6470waylonis mach_port_t current_task = mach_task_self(); 430890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org task_get_exception_ports(current_task, 431890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org s_exception_mask, 432890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org current.masks, 433890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org ¤t.count, 434890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org current.ports, 435890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org current.behaviors, 436890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org current.flavors); 43732441cc0608ddaf81885d23acf63f4b53cb73744nealsid 4385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Find the first exception handler that matches the exception 4395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis unsigned int found; 440983264848d5372d8e64d62eb67f672c71e4b6470waylonis for (found = 0; found < current.count; ++found) { 441983264848d5372d8e64d62eb67f672c71e4b6470waylonis if (current.masks[found] & (1 << exception)) { 4425ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis break; 4435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Nothing to forward 447983264848d5372d8e64d62eb67f672c71e4b6470waylonis if (found == current.count) { 4485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis fprintf(stderr, "** No previous ports for forwarding!! \n"); 4495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exit(KERN_FAILURE); 4505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 452983264848d5372d8e64d62eb67f672c71e4b6470waylonis mach_port_t target_port = current.ports[found]; 453983264848d5372d8e64d62eb67f672c71e4b6470waylonis exception_behavior_t target_behavior = current.behaviors[found]; 4545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 455890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org kern_return_t result; 4565ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis switch (target_behavior) { 4575ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis case EXCEPTION_DEFAULT: 4585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = exception_raise(target_port, failed_thread, task, exception, 4595ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis code, code_count); 4605ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis break; 4615ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis default: 463a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org fprintf(stderr, "** Unknown exception behavior: %d\n", target_behavior); 4645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = KERN_FAILURE; 4655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis break; 4665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4675ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result; 4695ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 4705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4715ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// static 472c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.orgvoid* ExceptionHandler::WaitForMessage(void* exception_handler_class) { 473c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org ExceptionHandler* self = 474c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org reinterpret_cast<ExceptionHandler*>(exception_handler_class); 4755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis ExceptionMessage receive; 4765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Wait for the exception info 4785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis while (1) { 4795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis receive.header.msgh_local_port = self->handler_port_; 4806e3869c19fbb94b739e45b495476ebdd925133eadmaclach receive.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(receive)); 4815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t result = mach_msg(&(receive.header), 4825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_RCV_MSG | MACH_RCV_LARGE, 0, 4836e3869c19fbb94b739e45b495476ebdd925133eadmaclach receive.header.msgh_size, 4846e3869c19fbb94b739e45b495476ebdd925133eadmaclach self->handler_port_, 4855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 48669d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker 48732441cc0608ddaf81885d23acf63f4b53cb73744nealsid 4885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result == KERN_SUCCESS) { 4895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Uninstall our handler so that we don't get in a loop if the process of 490600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // writing out a minidump causes an exception. However, if the exception 491600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // was caused by a fork'd process, don't uninstall things 4923a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid 4935ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // If the actual exception code is zero, then we're calling this handler 4945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // in a way that indicates that we want to either exit this thread or 4955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // generate a minidump 496530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // 497530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // While reporting, all threads (except this one) must be suspended 498530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // to avoid misleading stacks. If appropriate they will be resumed 499530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // afterwards. 5005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (!receive.exception) { 501cae59b4ae44ccc667be4c28710d167ad4dd9823bted.mielczarek@gmail.com // Don't touch self, since this message could have been sent 502cae59b4ae44ccc667be4c28710d167ad4dd9823bted.mielczarek@gmail.com // from its destructor. 5030d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (receive.header.msgh_id == kShutdownMessage) 5045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return NULL; 5055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 506530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker self->SuspendThreads(); 507530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 508d792274003fb0e7145161a290eff6d090a934bceladderbreaker#if USE_PROTECTED_ALLOCATIONS 50919b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 510d792274003fb0e7145161a290eff6d090a934bceladderbreaker gBreakpadAllocator->Unprotect(); 511d792274003fb0e7145161a290eff6d090a934bceladderbreaker#endif 512d792274003fb0e7145161a290eff6d090a934bceladderbreaker 5130d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com mach_port_t thread = MACH_PORT_NULL; 5140d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com int exception_type = 0; 5150d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com int exception_code = 0; 5160d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) { 5170d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com thread = receive.thread.name; 5180d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com exception_type = EXC_BREAKPOINT; 519c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#if defined(__i386__) || defined(__x86_64__) 5200d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com exception_code = EXC_I386_BPT; 521c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#elif defined(__ppc__) || defined(__ppc64__) 5220d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com exception_code = EXC_PPC_BREAKPOINT; 523c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#elif defined(__arm__) 524f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org exception_code = EXC_ARM_BREAKPOINT; 5250d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com#else 5260d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com#error architecture not supported 5270d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com#endif 5280d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com } 5290d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com 5305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Write out the dump and save the result for later retrieval 5315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis self->last_minidump_write_result_ = 5320d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com self->WriteMinidumpWithException(exception_type, exception_code, 53360a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org 0, NULL, thread, 534094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org false, false); 535d792274003fb0e7145161a290eff6d090a934bceladderbreaker 536d792274003fb0e7145161a290eff6d090a934bceladderbreaker#if USE_PROTECTED_ALLOCATIONS 53719b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 538d792274003fb0e7145161a290eff6d090a934bceladderbreaker gBreakpadAllocator->Protect(); 539d792274003fb0e7145161a290eff6d090a934bceladderbreaker#endif 540d792274003fb0e7145161a290eff6d090a934bceladderbreaker 541530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker self->ResumeThreads(); 542530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 5435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (self->use_minidump_write_mutex_) 5445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis pthread_mutex_unlock(&self->minidump_write_mutex_); 5455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } else { 546600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // When forking a child process with the exception handler installed, 547600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // if the child crashes, it will send the exception back to the parent 54832441cc0608ddaf81885d23acf63f4b53cb73744nealsid // process. The check for task == self_task() ensures that only 54932441cc0608ddaf81885d23acf63f4b53cb73744nealsid // exceptions that occur in the parent process are caught and 5503a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // processed. If the exception was not caused by this task, we 5513a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // still need to call into the exception server and have it return 552a880043030dc658b7ac88ef6f6db3b36a5595756qsr@chromium.org // KERN_FAILURE (see catch_exception_raise) in order for the kernel 5533a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // to move onto the host exception handler for the child task 554600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis if (receive.task.name == mach_task_self()) { 555530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker self->SuspendThreads(); 55632441cc0608ddaf81885d23acf63f4b53cb73744nealsid 557d792274003fb0e7145161a290eff6d090a934bceladderbreaker#if USE_PROTECTED_ALLOCATIONS 55819b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 559d792274003fb0e7145161a290eff6d090a934bceladderbreaker gBreakpadAllocator->Unprotect(); 560d792274003fb0e7145161a290eff6d090a934bceladderbreaker#endif 561d792274003fb0e7145161a290eff6d090a934bceladderbreaker 56261e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek int subcode = 0; 56361e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek if (receive.exception == EXC_BAD_ACCESS && receive.code_count > 1) 56461e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek subcode = receive.code[1]; 56532441cc0608ddaf81885d23acf63f4b53cb73744nealsid 56661e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek // Generate the minidump with the exception data. 56761e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek self->WriteMinidumpWithException(receive.exception, receive.code[0], 56860a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org subcode, NULL, receive.thread.name, 56960a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org true, false); 57061e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek 57193257311a12637bd8528171617cb9845c5abd36cmark@chromium.org#if USE_PROTECTED_ALLOCATIONS 57293257311a12637bd8528171617cb9845c5abd36cmark@chromium.org // This may have become protected again within 57393257311a12637bd8528171617cb9845c5abd36cmark@chromium.org // WriteMinidumpWithException, but it needs to be unprotected for 57493257311a12637bd8528171617cb9845c5abd36cmark@chromium.org // UninstallHandler. 57519b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 57693257311a12637bd8528171617cb9845c5abd36cmark@chromium.org gBreakpadAllocator->Unprotect(); 57793257311a12637bd8528171617cb9845c5abd36cmark@chromium.org#endif 57893257311a12637bd8528171617cb9845c5abd36cmark@chromium.org 57961e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek self->UninstallHandler(true); 580d792274003fb0e7145161a290eff6d090a934bceladderbreaker 581d792274003fb0e7145161a290eff6d090a934bceladderbreaker#if USE_PROTECTED_ALLOCATIONS 58219b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 583d792274003fb0e7145161a290eff6d090a934bceladderbreaker gBreakpadAllocator->Protect(); 584d792274003fb0e7145161a290eff6d090a934bceladderbreaker#endif 585600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis } 5863a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // Pass along the exception to the server, which will setup the 587a880043030dc658b7ac88ef6f6db3b36a5595756qsr@chromium.org // message and call catch_exception_raise() and put the return 5883a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // code into the reply. 5893a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid ExceptionReplyMessage reply; 590a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org if (!breakpad_exc_server(&receive.header, &reply.header)) 5913a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid exit(1); 5923a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid 5933a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // Send a reply and exit 594890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org mach_msg(&(reply.header), MACH_SEND_MSG, 595890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org reply.header.msgh_size, 0, MACH_PORT_NULL, 596890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 5975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 5985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 5995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 6005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 6015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return NULL; 6025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 6035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 604c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org// static 605094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.orgvoid ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { 60619b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 60719b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 60819b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org gBreakpadAllocator->Unprotect(); 60919b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org#endif 610f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org gProtectedData.handler->WriteMinidumpWithException( 611f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org EXC_SOFTWARE, 612f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org MD_EXCEPTION_CODE_MAC_ABORT, 613f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org 0, 61460a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org static_cast<ucontext_t*>(uc), 615f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org mach_thread_self(), 616f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org true, 617f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org true); 61819b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 61919b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 62019b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org gBreakpadAllocator->Protect(); 62119b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org#endif 622094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org} 623094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 6245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::InstallHandler() { 625094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org // If a handler is already installed, something is really wrong. 626094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org if (gProtectedData.handler != NULL) { 627094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org return false; 628094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org } 629094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#if TARGET_OS_IPHONE 630094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org if (!IsOutOfProcess()) { 631094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org struct sigaction sa; 632094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org memset(&sa, 0, sizeof(sa)); 633094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sigemptyset(&sa.sa_mask); 634094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sigaddset(&sa.sa_mask, SIGABRT); 635094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sa.sa_sigaction = ExceptionHandler::SignalHandler; 636094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sa.sa_flags = SA_SIGINFO; 637094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 638094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org scoped_ptr<struct sigaction> old(new struct sigaction); 639094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org if (sigaction(SIGABRT, &sa, old.get()) == -1) { 640094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org return false; 641094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org } 642094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org old_handler_.swap(old); 643094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org gProtectedData.handler = this; 644094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 645f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org assert(((size_t)(gProtectedData.protected_buffer) & PAGE_MASK) == 0); 646094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ); 647094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#endif 648094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org } 649094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#endif 650094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 651600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis try { 65269d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#if USE_PROTECTED_ALLOCATIONS 65369d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker previous_ = new (gBreakpadAllocator->Allocate(sizeof(ExceptionParameters)) ) 65432441cc0608ddaf81885d23acf63f4b53cb73744nealsid ExceptionParameters(); 65569d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#else 656600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis previous_ = new ExceptionParameters(); 65769d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#endif 658600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis } 659600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis catch (std::bad_alloc) { 660600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis return false; 661600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis } 662600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis 663600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // Save the current exception ports so that we can forward to them 6645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->count = EXC_TYPES_COUNT; 6655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t current_task = mach_task_self(); 66632441cc0608ddaf81885d23acf63f4b53cb73744nealsid kern_return_t result = task_get_exception_ports(current_task, 667983264848d5372d8e64d62eb67f672c71e4b6470waylonis s_exception_mask, 6685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->masks, 6695ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis &previous_->count, 6705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->ports, 6715ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->behaviors, 6725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->flavors); 67332441cc0608ddaf81885d23acf63f4b53cb73744nealsid 6745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Setup the exception ports on this task 6755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result == KERN_SUCCESS) 676983264848d5372d8e64d62eb67f672c71e4b6470waylonis result = task_set_exception_ports(current_task, s_exception_mask, 6775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis handler_port_, EXCEPTION_DEFAULT, 6785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis THREAD_STATE_NONE); 6795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 6805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis installed_exception_handler_ = (result == KERN_SUCCESS); 6815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 6825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return installed_exception_handler_; 6835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 6845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 685de2fd15db9a480c807ba337690669538a97756a4ladderbreakerbool ExceptionHandler::UninstallHandler(bool in_exception) { 6865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t result = KERN_SUCCESS; 68732441cc0608ddaf81885d23acf63f4b53cb73744nealsid 688094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org if (old_handler_.get()) { 689094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sigaction(SIGABRT, old_handler_.get(), NULL); 690094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 691094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org mprotect(gProtectedData.protected_buffer, PAGE_SIZE, 692094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org PROT_READ | PROT_WRITE); 693094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#endif 694094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org old_handler_.reset(); 695094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org gProtectedData.handler = NULL; 696094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org } 697094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 6985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (installed_exception_handler_) { 6995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t current_task = mach_task_self(); 70032441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Restore the previous ports 7025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis for (unsigned int i = 0; i < previous_->count; ++i) { 7035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = task_set_exception_ports(current_task, previous_->masks[i], 7045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->ports[i], 7055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->behaviors[i], 7065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->flavors[i]); 7075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result != KERN_SUCCESS) 7085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 71032441cc0608ddaf81885d23acf63f4b53cb73744nealsid 711de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // this delete should NOT happen if an exception just occurred! 712de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (!in_exception) { 71369d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#if USE_PROTECTED_ALLOCATIONS 71469d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker previous_->~ExceptionParameters(); 71569d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#else 71632441cc0608ddaf81885d23acf63f4b53cb73744nealsid delete previous_; 71769d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#endif 718de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } 71932441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7205ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_ = NULL; 7215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis installed_exception_handler_ = false; 7225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 72332441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result == KERN_SUCCESS; 7255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 7265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::Setup(bool install_handler) { 7285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (pthread_mutex_init(&minidump_write_mutex_, NULL)) 7295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Create a receive right 7325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t current_task = mach_task_self(); 7335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t result = mach_port_allocate(current_task, 7345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_PORT_RIGHT_RECEIVE, 7355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis &handler_port_); 7365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Add send right 7375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result == KERN_SUCCESS) 7385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = mach_port_insert_right(current_task, handler_port_, handler_port_, 7395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_MSG_TYPE_MAKE_SEND); 7405ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7415ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (install_handler && result == KERN_SUCCESS) 7425ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (!InstallHandler()) 7435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result == KERN_SUCCESS) { 746600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // Install the handler in its own thread, detached as we won't be joining. 747600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis pthread_attr_t attr; 748600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis pthread_attr_init(&attr); 749600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 75032441cc0608ddaf81885d23acf63f4b53cb73744nealsid int thread_create_result = pthread_create(&handler_thread_, &attr, 751600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis &WaitForMessage, this); 752600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis pthread_attr_destroy(&attr); 753600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS; 7545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 7555ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 756c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org return result == KERN_SUCCESS; 7575ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 7585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7595ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::Teardown() { 7605ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t result = KERN_SUCCESS; 7615ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis is_in_teardown_ = true; 7625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 763de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (!UninstallHandler(false)) 7645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 76532441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Send an empty message so that the handler_thread exits 7670d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (SendMessageToHandlerThread(kShutdownMessage)) { 7685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t current_task = mach_task_self(); 7695ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = mach_port_deallocate(current_task, handler_port_); 7705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result != KERN_SUCCESS) 7715ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } else { 7735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 77532441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis handler_thread_ = NULL; 777f760d649e534a0b610f36b3be65d84ed2f07f0a5mark@chromium.org handler_port_ = MACH_PORT_NULL; 7785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis pthread_mutex_destroy(&minidump_write_mutex_); 7795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result == KERN_SUCCESS; 7815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 7825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7830d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.combool ExceptionHandler::SendMessageToHandlerThread( 7840d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com HandlerThreadMessage message_id) { 7850d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com ExceptionMessage msg; 7860d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com memset(&msg, 0, sizeof(msg)); 7870d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_id = message_id; 7880d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (message_id == kWriteDumpMessage || 7890d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com message_id == kWriteDumpWithExceptionMessage) { 7900d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com // Include this thread's port. 7910d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.thread.name = mach_thread_self(); 7920d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.thread.disposition = MACH_MSG_TYPE_PORT_SEND; 7930d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.thread.type = MACH_MSG_PORT_DESCRIPTOR; 7940d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com } 7950d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_size = sizeof(msg) - sizeof(msg.padding); 7960d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_remote_port = handler_port_; 7970d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 7985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_MSG_TYPE_MAKE_SEND_ONCE); 7990d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com kern_return_t result = mach_msg(&(msg.header), 8005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_SEND_MSG | MACH_SEND_TIMEOUT, 8010d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_size, 0, 0, 8025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 8035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 8045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result == KERN_SUCCESS; 8055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 8065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 8075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisvoid ExceptionHandler::UpdateNextID() { 8085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis next_minidump_path_ = 8095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis (MinidumpGenerator::UniqueNameInDirectory(dump_path_, &next_minidump_id_)); 8105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 8115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis next_minidump_path_c_ = next_minidump_path_.c_str(); 8125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis next_minidump_id_c_ = next_minidump_id_.c_str(); 8135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 8145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 815530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreakerbool ExceptionHandler::SuspendThreads() { 816530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker thread_act_port_array_t threads_for_task; 817530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker mach_msg_type_number_t thread_count; 818530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 819530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (task_threads(mach_task_self(), &threads_for_task, &thread_count)) 820530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return false; 821530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 822530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // suspend all of the threads except for this one 823530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker for (unsigned int i = 0; i < thread_count; ++i) { 824530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (threads_for_task[i] != mach_thread_self()) { 825530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (thread_suspend(threads_for_task[i])) 826530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return false; 827530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker } 828530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker } 82932441cc0608ddaf81885d23acf63f4b53cb73744nealsid 830530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return true; 831530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker} 832530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 833530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreakerbool ExceptionHandler::ResumeThreads() { 834530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker thread_act_port_array_t threads_for_task; 835530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker mach_msg_type_number_t thread_count; 836530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 837530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (task_threads(mach_task_self(), &threads_for_task, &thread_count)) 838530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return false; 839530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 840530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // resume all of the threads except for this one 841530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker for (unsigned int i = 0; i < thread_count; ++i) { 842530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (threads_for_task[i] != mach_thread_self()) { 843530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (thread_resume(threads_for_task[i])) 844530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return false; 845530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker } 846530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker } 84732441cc0608ddaf81885d23acf63f4b53cb73744nealsid 848530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return true; 849530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker} 850530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 851e5dc60822e5938fea2ae892ccddb906641ba174emmentovai} // namespace google_breakpad 852