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 7789764a7a0b39c0bb6c9428e617eac248015d4e74qsr@chromium.org#if defined PAGE_MAX_SIZE 7889764a7a0b39c0bb6c9428e617eac248015d4e74qsr@chromium.org char protected_buffer[PAGE_MAX_SIZE] __attribute__((aligned(PAGE_MAX_SIZE))); 7989764a7a0b39c0bb6c9428e617eac248015d4e74qsr@chromium.org#else 80094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 8189764a7a0b39c0bb6c9428e617eac248015d4e74qsr@chromium.org#endif // defined PAGE_MAX_SIZE 8289764a7a0b39c0bb6c9428e617eac248015d4e74qsr@chromium.org#endif // USE_PROTECTED_ALLOCATIONS 83094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org google_breakpad::ExceptionHandler *handler; 84094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org} gProtectedData; 85094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisusing std::map; 875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// These structures and techniques are illustrated in 895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// Mac OS X Internals, Amit Singh, ch 9.7 905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionMessage { 915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_header_t header; 925ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_body_t body; 935ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_port_descriptor_t thread; 945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_port_descriptor_t task; 955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis NDR_record_t ndr; 965ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_type_t exception; 975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_type_number_t code_count; 985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis integer_t code[EXCEPTION_CODE_MAX]; 995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis char padding[512]; 1005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}; 1015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionParameters { 1035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis ExceptionParameters() : count(0) {} 1045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_type_number_t count; 1055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_mask_t masks[EXC_TYPES_COUNT]; 1065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t ports[EXC_TYPES_COUNT]; 1075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_behavior_t behaviors[EXC_TYPES_COUNT]; 1085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis thread_state_flavor_t flavors[EXC_TYPES_COUNT]; 1095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}; 1105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 1115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisstruct ExceptionReplyMessage { 1125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_header_t header; 1135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis NDR_record_t ndr; 1145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t return_code; 1155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis}; 1165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 117983264848d5372d8e64d62eb67f672c71e4b6470waylonis// Only catch these three exceptions. The other ones are nebulously defined 118983264848d5372d8e64d62eb67f672c71e4b6470waylonis// and may result in treating a non-fatal exception as fatal. 11932441cc0608ddaf81885d23acf63f4b53cb73744nealsidexception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS | 120649967cfd28116ad8a1ff3e84d86a1156b462536ladderbreakerEXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT; 1215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 122a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#if !TARGET_OS_IPHONE 123c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.orgextern "C" { 1245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Forward declarations for functions that need "C" style compilation 125c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org boolean_t exc_server(mach_msg_header_t* request, 126c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org mach_msg_header_t* reply); 1275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 128ebebd0fcef7540fc51c23de50d45e79e260a30cbmmentovai // This symbol must be visible to dlsym() - see 129ebebd0fcef7540fc51c23de50d45e79e260a30cbmmentovai // http://code.google.com/p/google-breakpad/issues/detail?id=345 for details. 1305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t catch_exception_raise(mach_port_t target_port, 1315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t failed_thread, 1325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t task, 1335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_type_t exception, 1345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_data_t code, 135ebebd0fcef7540fc51c23de50d45e79e260a30cbmmentovai mach_msg_type_number_t code_count) 136ebebd0fcef7540fc51c23de50d45e79e260a30cbmmentovai __attribute__((visibility("default"))); 137a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org} 138a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#endif 139a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 140a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.orgkern_return_t ForwardException(mach_port_t task, 141a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_port_t failed_thread, 142a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_type_t exception, 143a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_data_t code, 144a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_type_number_t code_count); 145a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 146a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#if TARGET_OS_IPHONE 147a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org// Implementation is based on the implementation generated by mig. 148c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.orgboolean_t breakpad_exc_server(mach_msg_header_t* InHeadP, 149c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org mach_msg_header_t* OutHeadP) { 150c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_bits = 151c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0); 152c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port; 153c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org /* Minimal size: routine() will update it if different */ 154c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t); 155c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_local_port = MACH_PORT_NULL; 156c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org OutHeadP->msgh_id = InHeadP->msgh_id + 100; 157a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 158a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org if (InHeadP->msgh_id != 2401) { 159c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org ((mig_reply_error_t*)OutHeadP)->NDR = NDR_record; 160c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org ((mig_reply_error_t*)OutHeadP)->RetCode = MIG_BAD_ID; 161a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return FALSE; 162a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } 163a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 164a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#ifdef __MigPackStructs 165a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#pragma pack(4) 166a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#endif 167a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org typedef struct { 168a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_header_t Head; 169a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org /* start of the kernel processed data */ 170a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_body_t msgh_body; 171a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_port_descriptor_t thread; 172a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_port_descriptor_t task; 173a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org /* end of the kernel processed data */ 174a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org NDR_record_t NDR; 175a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_type_t exception; 176a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_type_number_t codeCnt; 177a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org integer_t code[2]; 178a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_trailer_t trailer; 179a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } Request; 180a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 181a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org typedef struct { 182a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_header_t Head; 183a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org NDR_record_t NDR; 184a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org kern_return_t RetCode; 185a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } Reply; 186a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#ifdef __MigPackStructs 187a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#pragma pack() 188a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#endif 1895ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 190c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org Request* In0P = (Request*)InHeadP; 191c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org Reply* OutP = (Reply*)OutHeadP; 192a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 193a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org if (In0P->task.name != mach_task_self()) { 194a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return FALSE; 195a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } 196a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org OutP->RetCode = ForwardException(In0P->task.name, 197a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org In0P->thread.name, 198a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org In0P->exception, 199a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org In0P->code, 200a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org In0P->codeCnt); 201a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org OutP->NDR = NDR_record; 202a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return TRUE; 203a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org} 204a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#else 205c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.orgboolean_t breakpad_exc_server(mach_msg_header_t* request, 206c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org mach_msg_header_t* reply) { 207a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return exc_server(request, reply); 20885534c2eaf59a8deb3394aab8df466e65c998752nealsid} 20985534c2eaf59a8deb3394aab8df466e65c998752nealsid 210a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org// Callback from exc_server() 211a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.orgkern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread, 212a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_port_t task, 213a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_type_t exception, 214a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org exception_data_t code, 215a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org mach_msg_type_number_t code_count) { 216a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org if (task != mach_task_self()) { 217a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return KERN_FAILURE; 218a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org } 219a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org return ForwardException(task, failed_thread, exception, code, code_count); 220a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org} 221a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org#endif 222a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org 2235ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisExceptionHandler::ExceptionHandler(const string &dump_path, 2245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis FilterCallback filter, 2255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MinidumpCallback callback, 226c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org void* callback_context, 227315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com bool install_handler, 228c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org const char* port_name) 2295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis : dump_path_(), 2305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis filter_(filter), 2315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis callback_(callback), 2325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis callback_context_(callback_context), 233de2fd15db9a480c807ba337690669538a97756a4ladderbreaker directCallback_(NULL), 2345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis handler_thread_(NULL), 23532441cc0608ddaf81885d23acf63f4b53cb73744nealsid handler_port_(MACH_PORT_NULL), 2365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_(NULL), 2375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis installed_exception_handler_(false), 2385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis is_in_teardown_(false), 2395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis last_minidump_write_result_(false), 2405ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis use_minidump_write_mutex_(false) { 2415ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // This will update to the ID and C-string pointers 2425ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis set_dump_path(dump_path); 2435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MinidumpGenerator::GatherSystemInformation(); 244f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#if !TARGET_OS_IPHONE 245315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com if (port_name) 246315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com crash_generation_client_.reset(new CrashGenerationClient(port_name)); 247f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#endif 2485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis Setup(install_handler); 2495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 2505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 251de2fd15db9a480c807ba337690669538a97756a4ladderbreaker// special constructor if we want to bypass minidump writing and 252de2fd15db9a480c807ba337690669538a97756a4ladderbreaker// simply get a callback with the exception information 253de2fd15db9a480c807ba337690669538a97756a4ladderbreakerExceptionHandler::ExceptionHandler(DirectCallback callback, 254c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org void* callback_context, 255de2fd15db9a480c807ba337690669538a97756a4ladderbreaker bool install_handler) 256de2fd15db9a480c807ba337690669538a97756a4ladderbreaker : dump_path_(), 257de2fd15db9a480c807ba337690669538a97756a4ladderbreaker filter_(NULL), 258de2fd15db9a480c807ba337690669538a97756a4ladderbreaker callback_(NULL), 259de2fd15db9a480c807ba337690669538a97756a4ladderbreaker callback_context_(callback_context), 260de2fd15db9a480c807ba337690669538a97756a4ladderbreaker directCallback_(callback), 261de2fd15db9a480c807ba337690669538a97756a4ladderbreaker handler_thread_(NULL), 26232441cc0608ddaf81885d23acf63f4b53cb73744nealsid handler_port_(MACH_PORT_NULL), 263de2fd15db9a480c807ba337690669538a97756a4ladderbreaker previous_(NULL), 264de2fd15db9a480c807ba337690669538a97756a4ladderbreaker installed_exception_handler_(false), 265de2fd15db9a480c807ba337690669538a97756a4ladderbreaker is_in_teardown_(false), 266de2fd15db9a480c807ba337690669538a97756a4ladderbreaker last_minidump_write_result_(false), 267de2fd15db9a480c807ba337690669538a97756a4ladderbreaker use_minidump_write_mutex_(false) { 268de2fd15db9a480c807ba337690669538a97756a4ladderbreaker MinidumpGenerator::GatherSystemInformation(); 269de2fd15db9a480c807ba337690669538a97756a4ladderbreaker Setup(install_handler); 270de2fd15db9a480c807ba337690669538a97756a4ladderbreaker} 271de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 2725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisExceptionHandler::~ExceptionHandler() { 2735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis Teardown(); 2745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 2755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 2760d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.combool ExceptionHandler::WriteMinidump(bool write_exception_stream) { 2775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // If we're currently writing, just return 2785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (use_minidump_write_mutex_) 2795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 2805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 2815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis use_minidump_write_mutex_ = true; 2825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis last_minidump_write_result_ = false; 2835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 2845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Lock the mutex. Since we just created it, this will return immediately. 2855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (pthread_mutex_lock(&minidump_write_mutex_) == 0) { 2865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Send an empty message to the handle port so that a minidump will 2875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // be written 288cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com bool result = SendMessageToHandlerThread(write_exception_stream ? 289cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com kWriteDumpWithExceptionMessage : 290cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com kWriteDumpMessage); 291cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com if (!result) { 292cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com pthread_mutex_unlock(&minidump_write_mutex_); 293cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com return false; 294cb037254a19ee46b1bea0cfc64128b718924fbd3ted.mielczarek@gmail.com } 2955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 2965ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Wait for the minidump writer to complete its writing. It will unlock 2975ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // the mutex when completed 2985ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis pthread_mutex_lock(&minidump_write_mutex_); 2995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 30032441cc0608ddaf81885d23acf63f4b53cb73744nealsid 3015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis use_minidump_write_mutex_ = false; 3025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis UpdateNextID(); 3035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return last_minidump_write_result_; 3045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 3055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 3065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// static 3075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::WriteMinidump(const string &dump_path, 3080d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com bool write_exception_stream, 3095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MinidumpCallback callback, 310c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org void* callback_context) { 311315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com ExceptionHandler handler(dump_path, NULL, callback, callback_context, false, 312c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org NULL); 3130d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com return handler.WriteMinidump(write_exception_stream); 3145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 3155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 316144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com// static 317144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.combool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, 318c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org mach_port_t child_blamed_thread, 319c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org const string &dump_path, 320c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org MinidumpCallback callback, 321c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org void* callback_context) { 322144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com ScopedTaskSuspend suspend(child); 323144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com 324144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com MinidumpGenerator generator(child, MACH_PORT_NULL); 325144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com string dump_id; 326144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com string dump_filename = generator.UniqueNameInDirectory(dump_path, &dump_id); 327144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com 328144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com generator.SetExceptionInformation(EXC_BREAKPOINT, 329c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#if defined(__i386__) || defined(__x86_64__) 330c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org EXC_I386_BPT, 331c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#elif defined(__ppc__) || defined(__ppc64__) 332c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org EXC_PPC_BREAKPOINT, 3335c2892d9dec0a26b6e86d16fbc0c0a4d1a88410cmark@chromium.org#elif defined(__arm__) || defined(__aarch64__) 334c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org EXC_ARM_BREAKPOINT, 335144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com#else 3360d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com#error architecture not supported 337144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com#endif 338c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org 0, 339c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org child_blamed_thread); 340144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com bool result = generator.Write(dump_filename.c_str()); 341144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com 342144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com if (callback) { 343144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com return callback(dump_path.c_str(), dump_id.c_str(), 344c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org callback_context, result); 345144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com } 346144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com return result; 347144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com} 348144938cf22243407a56601bd5b75147f796a8424ted.mielczarek@gmail.com 349a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.orgbool ExceptionHandler::WriteMinidumpWithException( 350a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org int exception_type, 351a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org int exception_code, 352a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org int exception_subcode, 353a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org breakpad_ucontext_t* task_context, 354a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org mach_port_t thread_name, 355a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org bool exit_after_write, 356a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org bool report_current_thread) { 3575ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis bool result = false; 3585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 359de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (directCallback_) { 360de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (directCallback_(callback_context_, 361de2fd15db9a480c807ba337690669538a97756a4ladderbreaker exception_type, 362de2fd15db9a480c807ba337690669538a97756a4ladderbreaker exception_code, 36361e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek exception_subcode, 364de2fd15db9a480c807ba337690669538a97756a4ladderbreaker thread_name) ) { 3650d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (exit_after_write) 3663d55532df2ea6bc8809513e8add14fb84bc62a62ladderbreaker _exit(exception_type); 3675ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 368f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#if !TARGET_OS_IPHONE 369315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com } else if (IsOutOfProcess()) { 370315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com if (exception_type && exception_code) { 371315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com // If this is a real exception, give the filter (if any) a chance to 372315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com // decide if this should be sent. 373315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com if (filter_ && !filter_(callback_context_)) 374c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org return false; 3750828a485edb601a80b6cc3b09396da72b05a635dted.mielczarek@gmail.com result = crash_generation_client_->RequestDumpForException( 376c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org exception_type, 377c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org exception_code, 378c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org exception_subcode, 379c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org thread_name); 3800828a485edb601a80b6cc3b09396da72b05a635dted.mielczarek@gmail.com if (result && exit_after_write) { 3810828a485edb601a80b6cc3b09396da72b05a635dted.mielczarek@gmail.com _exit(exception_type); 3820828a485edb601a80b6cc3b09396da72b05a635dted.mielczarek@gmail.com } 383315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com } 384f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org#endif 385de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } else { 386de2fd15db9a480c807ba337690669538a97756a4ladderbreaker string minidump_id; 387de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 388de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // Putting the MinidumpGenerator in its own context will ensure that the 389de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // destructor is executed, closing the newly created minidump file. 390de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (!dump_path_.empty()) { 391094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org MinidumpGenerator md(mach_task_self(), 3926ed1918848372f789d4bda96657b7454c3f6c2c1mark@chromium.org report_current_thread ? MACH_PORT_NULL : 3936ed1918848372f789d4bda96657b7454c3f6c2c1mark@chromium.org mach_thread_self()); 39460a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org md.SetTaskContext(task_context); 395de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (exception_type && exception_code) { 396de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // If this is a real exception, give the filter (if any) a chance to 397315fd78199bc606ee02cb085dacadd58e0fc40c8ted.mielczarek@gmail.com // decide if this should be sent. 398de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (filter_ && !filter_(callback_context_)) 399de2fd15db9a480c807ba337690669538a97756a4ladderbreaker return false; 400de2fd15db9a480c807ba337690669538a97756a4ladderbreaker 40161e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek md.SetExceptionInformation(exception_type, exception_code, 40261e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek exception_subcode, thread_name); 403de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } 4045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 405de2fd15db9a480c807ba337690669538a97756a4ladderbreaker result = md.Write(next_minidump_path_c_); 406de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } 4075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 408de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // Call user specified callback (if any) 409de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (callback_) { 410de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // If the user callback returned true and we're handling an exception 411de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // (rather than just writing out the file), then we should exit without 412de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // forwarding the exception to the next handler. 41332441cc0608ddaf81885d23acf63f4b53cb73744nealsid if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, 414de2fd15db9a480c807ba337690669538a97756a4ladderbreaker result)) { 4150d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (exit_after_write) 4163d55532df2ea6bc8809513e8add14fb84bc62a62ladderbreaker _exit(exception_type); 417de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } 4185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4195ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 42032441cc0608ddaf81885d23acf63f4b53cb73744nealsid 4215ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result; 4225ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 4235ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4245ac2b9a569890f165478f91670dcdd553ce2d10ewayloniskern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread, 4255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_type_t exception, 4265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exception_data_t code, 4275ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_msg_type_number_t code_count) { 428983264848d5372d8e64d62eb67f672c71e4b6470waylonis // At this time, we should have called Uninstall() on the exception handler 42932441cc0608ddaf81885d23acf63f4b53cb73744nealsid // so that the current exception ports are the ones that we should be 430983264848d5372d8e64d62eb67f672c71e4b6470waylonis // forwarding to. 431983264848d5372d8e64d62eb67f672c71e4b6470waylonis ExceptionParameters current; 43232441cc0608ddaf81885d23acf63f4b53cb73744nealsid 433983264848d5372d8e64d62eb67f672c71e4b6470waylonis current.count = EXC_TYPES_COUNT; 434983264848d5372d8e64d62eb67f672c71e4b6470waylonis mach_port_t current_task = mach_task_self(); 435890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org task_get_exception_ports(current_task, 436890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org s_exception_mask, 437890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org current.masks, 438890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org ¤t.count, 439890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org current.ports, 440890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org current.behaviors, 441890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org current.flavors); 44232441cc0608ddaf81885d23acf63f4b53cb73744nealsid 4435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Find the first exception handler that matches the exception 4445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis unsigned int found; 445983264848d5372d8e64d62eb67f672c71e4b6470waylonis for (found = 0; found < current.count; ++found) { 446983264848d5372d8e64d62eb67f672c71e4b6470waylonis if (current.masks[found] & (1 << exception)) { 4475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis break; 4485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Nothing to forward 452983264848d5372d8e64d62eb67f672c71e4b6470waylonis if (found == current.count) { 4535ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis fprintf(stderr, "** No previous ports for forwarding!! \n"); 4545ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis exit(KERN_FAILURE); 4555ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4565ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 457983264848d5372d8e64d62eb67f672c71e4b6470waylonis mach_port_t target_port = current.ports[found]; 458983264848d5372d8e64d62eb67f672c71e4b6470waylonis exception_behavior_t target_behavior = current.behaviors[found]; 4595ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 460890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org kern_return_t result; 461a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org // TODO: Handle the case where |target_behavior| has MACH_EXCEPTION_CODES 462a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org // set. https://code.google.com/p/google-breakpad/issues/detail?id=551 4635ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis switch (target_behavior) { 4645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis case EXCEPTION_DEFAULT: 4655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = exception_raise(target_port, failed_thread, task, exception, 4665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis code, code_count); 4675ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis break; 4685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis default: 469a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org fprintf(stderr, "** Unknown exception behavior: %d\n", target_behavior); 4705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = KERN_FAILURE; 4715ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis break; 4725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 4735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result; 4755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 4765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis// static 478c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.orgvoid* ExceptionHandler::WaitForMessage(void* exception_handler_class) { 479c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org ExceptionHandler* self = 480c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org reinterpret_cast<ExceptionHandler*>(exception_handler_class); 4815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis ExceptionMessage receive; 4825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 4835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Wait for the exception info 4845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis while (1) { 4855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis receive.header.msgh_local_port = self->handler_port_; 4866e3869c19fbb94b739e45b495476ebdd925133eadmaclach receive.header.msgh_size = static_cast<mach_msg_size_t>(sizeof(receive)); 4875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t result = mach_msg(&(receive.header), 4885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_RCV_MSG | MACH_RCV_LARGE, 0, 4896e3869c19fbb94b739e45b495476ebdd925133eadmaclach receive.header.msgh_size, 4906e3869c19fbb94b739e45b495476ebdd925133eadmaclach self->handler_port_, 4915ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 49269d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker 49332441cc0608ddaf81885d23acf63f4b53cb73744nealsid 4945ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result == KERN_SUCCESS) { 4955ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Uninstall our handler so that we don't get in a loop if the process of 496600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // writing out a minidump causes an exception. However, if the exception 497600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // was caused by a fork'd process, don't uninstall things 4983a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid 4995ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // If the actual exception code is zero, then we're calling this handler 5005ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // in a way that indicates that we want to either exit this thread or 5015ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // generate a minidump 502530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // 503530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // While reporting, all threads (except this one) must be suspended 504530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // to avoid misleading stacks. If appropriate they will be resumed 505530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // afterwards. 5065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (!receive.exception) { 507cae59b4ae44ccc667be4c28710d167ad4dd9823bted.mielczarek@gmail.com // Don't touch self, since this message could have been sent 508cae59b4ae44ccc667be4c28710d167ad4dd9823bted.mielczarek@gmail.com // from its destructor. 5090d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (receive.header.msgh_id == kShutdownMessage) 5105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return NULL; 5115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 512530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker self->SuspendThreads(); 513530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 514d792274003fb0e7145161a290eff6d090a934bceladderbreaker#if USE_PROTECTED_ALLOCATIONS 51519b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 516d792274003fb0e7145161a290eff6d090a934bceladderbreaker gBreakpadAllocator->Unprotect(); 517d792274003fb0e7145161a290eff6d090a934bceladderbreaker#endif 518d792274003fb0e7145161a290eff6d090a934bceladderbreaker 5190d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com mach_port_t thread = MACH_PORT_NULL; 5200d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com int exception_type = 0; 5210d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com int exception_code = 0; 5220d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) { 5230d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com thread = receive.thread.name; 5240d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com exception_type = EXC_BREAKPOINT; 525c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#if defined(__i386__) || defined(__x86_64__) 5260d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com exception_code = EXC_I386_BPT; 527c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org#elif defined(__ppc__) || defined(__ppc64__) 5280d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com exception_code = EXC_PPC_BREAKPOINT; 5295c2892d9dec0a26b6e86d16fbc0c0a4d1a88410cmark@chromium.org#elif defined(__arm__) || defined(__aarch64__) 530f7b0f838d6a35ce130c41447e6da032447b5af05qsr@chromium.org exception_code = EXC_ARM_BREAKPOINT; 5310d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com#else 5320d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com#error architecture not supported 5330d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com#endif 5340d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com } 5350d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com 5365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Write out the dump and save the result for later retrieval 5375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis self->last_minidump_write_result_ = 5380d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com self->WriteMinidumpWithException(exception_type, exception_code, 53960a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org 0, NULL, thread, 540094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org false, false); 541d792274003fb0e7145161a290eff6d090a934bceladderbreaker 542d792274003fb0e7145161a290eff6d090a934bceladderbreaker#if USE_PROTECTED_ALLOCATIONS 54319b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 544d792274003fb0e7145161a290eff6d090a934bceladderbreaker gBreakpadAllocator->Protect(); 545d792274003fb0e7145161a290eff6d090a934bceladderbreaker#endif 546d792274003fb0e7145161a290eff6d090a934bceladderbreaker 547530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker self->ResumeThreads(); 548530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 5495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (self->use_minidump_write_mutex_) 5505ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis pthread_mutex_unlock(&self->minidump_write_mutex_); 5515ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } else { 552600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // When forking a child process with the exception handler installed, 553600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // if the child crashes, it will send the exception back to the parent 55432441cc0608ddaf81885d23acf63f4b53cb73744nealsid // process. The check for task == self_task() ensures that only 55532441cc0608ddaf81885d23acf63f4b53cb73744nealsid // exceptions that occur in the parent process are caught and 5563a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // processed. If the exception was not caused by this task, we 5573a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // still need to call into the exception server and have it return 558a880043030dc658b7ac88ef6f6db3b36a5595756qsr@chromium.org // KERN_FAILURE (see catch_exception_raise) in order for the kernel 5593a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // to move onto the host exception handler for the child task 560600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis if (receive.task.name == mach_task_self()) { 561530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker self->SuspendThreads(); 56232441cc0608ddaf81885d23acf63f4b53cb73744nealsid 563d792274003fb0e7145161a290eff6d090a934bceladderbreaker#if USE_PROTECTED_ALLOCATIONS 56419b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 565d792274003fb0e7145161a290eff6d090a934bceladderbreaker gBreakpadAllocator->Unprotect(); 566d792274003fb0e7145161a290eff6d090a934bceladderbreaker#endif 567d792274003fb0e7145161a290eff6d090a934bceladderbreaker 56861e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek int subcode = 0; 56961e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek if (receive.exception == EXC_BAD_ACCESS && receive.code_count > 1) 57061e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek subcode = receive.code[1]; 57132441cc0608ddaf81885d23acf63f4b53cb73744nealsid 57261e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek // Generate the minidump with the exception data. 57361e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek self->WriteMinidumpWithException(receive.exception, receive.code[0], 57460a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org subcode, NULL, receive.thread.name, 57560a69eecd7cf717a1819a1f75b4ef21a6b51c457qsr@chromium.org true, false); 57661e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek 57793257311a12637bd8528171617cb9845c5abd36cmark@chromium.org#if USE_PROTECTED_ALLOCATIONS 57893257311a12637bd8528171617cb9845c5abd36cmark@chromium.org // This may have become protected again within 57993257311a12637bd8528171617cb9845c5abd36cmark@chromium.org // WriteMinidumpWithException, but it needs to be unprotected for 58093257311a12637bd8528171617cb9845c5abd36cmark@chromium.org // UninstallHandler. 58119b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 58293257311a12637bd8528171617cb9845c5abd36cmark@chromium.org gBreakpadAllocator->Unprotect(); 58393257311a12637bd8528171617cb9845c5abd36cmark@chromium.org#endif 58493257311a12637bd8528171617cb9845c5abd36cmark@chromium.org 58561e88c7ad7eb072977b4d4d26bcf8929b75af2d4ted.mielczarek self->UninstallHandler(true); 586d792274003fb0e7145161a290eff6d090a934bceladderbreaker 587d792274003fb0e7145161a290eff6d090a934bceladderbreaker#if USE_PROTECTED_ALLOCATIONS 58819b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 589d792274003fb0e7145161a290eff6d090a934bceladderbreaker gBreakpadAllocator->Protect(); 590d792274003fb0e7145161a290eff6d090a934bceladderbreaker#endif 591600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis } 5923a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // Pass along the exception to the server, which will setup the 593a880043030dc658b7ac88ef6f6db3b36a5595756qsr@chromium.org // message and call catch_exception_raise() and put the return 5943a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // code into the reply. 5953a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid ExceptionReplyMessage reply; 596a8fd7b2f863ecc85740a1caa65ae3f5f1751738dqsr@chromium.org if (!breakpad_exc_server(&receive.header, &reply.header)) 5973a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid exit(1); 5983a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid 5993a283d8f8b3875dd080a59b421c2e036a8412ab2nealsid // Send a reply and exit 600890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org mach_msg(&(reply.header), MACH_SEND_MSG, 601890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org reply.header.msgh_size, 0, MACH_PORT_NULL, 602890831804748e74f2d023f0530971962cfa0c219qsr@chromium.org MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 6035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 6045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 6055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 6065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 6075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return NULL; 6085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 6095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 610c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org// static 611094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.orgvoid ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { 61219b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 61319b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 61419b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org gBreakpadAllocator->Unprotect(); 61519b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org#endif 616f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org gProtectedData.handler->WriteMinidumpWithException( 617f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org EXC_SOFTWARE, 618f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org MD_EXCEPTION_CODE_MAC_ABORT, 619f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org 0, 620a157c99f9fdfc5f5072db05a5075ae23fce43c88mark@chromium.org static_cast<breakpad_ucontext_t*>(uc), 621f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org mach_thread_self(), 622f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org true, 623f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org true); 62419b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 62519b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org if (gBreakpadAllocator) 62619b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org gBreakpadAllocator->Protect(); 62719b3243ca5a31bc4f6be23a65770a92614cf0dadqsr@chromium.org#endif 628094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org} 629094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 6305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::InstallHandler() { 631094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org // If a handler is already installed, something is really wrong. 632094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org if (gProtectedData.handler != NULL) { 633094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org return false; 634094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org } 635094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org if (!IsOutOfProcess()) { 636094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org struct sigaction sa; 637094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org memset(&sa, 0, sizeof(sa)); 638094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sigemptyset(&sa.sa_mask); 639094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sigaddset(&sa.sa_mask, SIGABRT); 640094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sa.sa_sigaction = ExceptionHandler::SignalHandler; 641094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sa.sa_flags = SA_SIGINFO; 642094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 643094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org scoped_ptr<struct sigaction> old(new struct sigaction); 644094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org if (sigaction(SIGABRT, &sa, old.get()) == -1) { 645094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org return false; 646094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org } 647094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org old_handler_.swap(old); 648094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org gProtectedData.handler = this; 649094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 650f0eb3f0038c8459517fe31703d0f58dcf9424a7cqsr@chromium.org assert(((size_t)(gProtectedData.protected_buffer) & PAGE_MASK) == 0); 651094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ); 652094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#endif 653094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org } 654094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 655600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis try { 65669d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#if USE_PROTECTED_ALLOCATIONS 65769d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker previous_ = new (gBreakpadAllocator->Allocate(sizeof(ExceptionParameters)) ) 65832441cc0608ddaf81885d23acf63f4b53cb73744nealsid ExceptionParameters(); 65969d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#else 660600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis previous_ = new ExceptionParameters(); 66169d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#endif 662600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis } 663600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis catch (std::bad_alloc) { 664600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis return false; 665600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis } 666600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis 667600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // Save the current exception ports so that we can forward to them 6685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->count = EXC_TYPES_COUNT; 6695ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t current_task = mach_task_self(); 67032441cc0608ddaf81885d23acf63f4b53cb73744nealsid kern_return_t result = task_get_exception_ports(current_task, 671983264848d5372d8e64d62eb67f672c71e4b6470waylonis s_exception_mask, 6725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->masks, 6735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis &previous_->count, 6745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->ports, 6755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->behaviors, 6765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->flavors); 67732441cc0608ddaf81885d23acf63f4b53cb73744nealsid 6785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Setup the exception ports on this task 6795ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result == KERN_SUCCESS) 680983264848d5372d8e64d62eb67f672c71e4b6470waylonis result = task_set_exception_ports(current_task, s_exception_mask, 6815ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis handler_port_, EXCEPTION_DEFAULT, 6825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis THREAD_STATE_NONE); 6835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 6845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis installed_exception_handler_ = (result == KERN_SUCCESS); 6855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 6865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return installed_exception_handler_; 6875ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 6885ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 689de2fd15db9a480c807ba337690669538a97756a4ladderbreakerbool ExceptionHandler::UninstallHandler(bool in_exception) { 6905ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t result = KERN_SUCCESS; 69132441cc0608ddaf81885d23acf63f4b53cb73744nealsid 692094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org if (old_handler_.get()) { 693094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org sigaction(SIGABRT, old_handler_.get(), NULL); 694094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#if USE_PROTECTED_ALLOCATIONS 695094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org mprotect(gProtectedData.protected_buffer, PAGE_SIZE, 696094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org PROT_READ | PROT_WRITE); 697094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org#endif 698094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org old_handler_.reset(); 699094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org gProtectedData.handler = NULL; 700094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org } 701094ca0f8a92d3f154fc78e31c2f6722b0785d5c5qsr@chromium.org 7025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (installed_exception_handler_) { 7035ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t current_task = mach_task_self(); 70432441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7055ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Restore the previous ports 7065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis for (unsigned int i = 0; i < previous_->count; ++i) { 7075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = task_set_exception_ports(current_task, previous_->masks[i], 7085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->ports[i], 7095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->behaviors[i], 7105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_->flavors[i]); 7115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result != KERN_SUCCESS) 7125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 71432441cc0608ddaf81885d23acf63f4b53cb73744nealsid 715de2fd15db9a480c807ba337690669538a97756a4ladderbreaker // this delete should NOT happen if an exception just occurred! 716de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (!in_exception) { 71769d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#if USE_PROTECTED_ALLOCATIONS 71869d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker previous_->~ExceptionParameters(); 71969d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#else 72032441cc0608ddaf81885d23acf63f4b53cb73744nealsid delete previous_; 72169d242245a1e60beeb0fae003cfebffeaa38cc6eladderbreaker#endif 722de2fd15db9a480c807ba337690669538a97756a4ladderbreaker } 72332441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7245ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis previous_ = NULL; 7255ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis installed_exception_handler_ = false; 7265ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 72732441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7285ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result == KERN_SUCCESS; 7295ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 7305ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7315ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::Setup(bool install_handler) { 7325ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (pthread_mutex_init(&minidump_write_mutex_, NULL)) 7335ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7345ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7355ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Create a receive right 7365ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t current_task = mach_task_self(); 7375ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t result = mach_port_allocate(current_task, 7385ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_PORT_RIGHT_RECEIVE, 7395ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis &handler_port_); 7405ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Add send right 7415ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result == KERN_SUCCESS) 7425ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = mach_port_insert_right(current_task, handler_port_, handler_port_, 7435ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_MSG_TYPE_MAKE_SEND); 7445ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7455ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (install_handler && result == KERN_SUCCESS) 7465ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (!InstallHandler()) 7475ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7485ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7495ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result == KERN_SUCCESS) { 750600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis // Install the handler in its own thread, detached as we won't be joining. 751600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis pthread_attr_t attr; 752600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis pthread_attr_init(&attr); 753600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 75432441cc0608ddaf81885d23acf63f4b53cb73744nealsid int thread_create_result = pthread_create(&handler_thread_, &attr, 755600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis &WaitForMessage, this); 756600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis pthread_attr_destroy(&attr); 757600e56bc39345e8fa38fa7d286e9f7382d75c2bfwaylonis result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS; 7585ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 7595ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 760c8be06b8e83b3bf6f17d690765cad1e8aebbb2e1thestig@chromium.org return result == KERN_SUCCESS; 7615ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 7625ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7635ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisbool ExceptionHandler::Teardown() { 7645ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis kern_return_t result = KERN_SUCCESS; 7655ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis is_in_teardown_ = true; 7665ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 767de2fd15db9a480c807ba337690669538a97756a4ladderbreaker if (!UninstallHandler(false)) 7685ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 76932441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7705ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis // Send an empty message so that the handler_thread exits 7710d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (SendMessageToHandlerThread(kShutdownMessage)) { 7725ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis mach_port_t current_task = mach_task_self(); 7735ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis result = mach_port_deallocate(current_task, handler_port_); 7745ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis if (result != KERN_SUCCESS) 7755ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7765ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } else { 7775ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return false; 7785ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis } 77932441cc0608ddaf81885d23acf63f4b53cb73744nealsid 7805ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis handler_thread_ = NULL; 781f760d649e534a0b610f36b3be65d84ed2f07f0a5mark@chromium.org handler_port_ = MACH_PORT_NULL; 7825ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis pthread_mutex_destroy(&minidump_write_mutex_); 7835ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7845ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result == KERN_SUCCESS; 7855ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 7865ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 7870d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.combool ExceptionHandler::SendMessageToHandlerThread( 7880d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com HandlerThreadMessage message_id) { 7890d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com ExceptionMessage msg; 7900d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com memset(&msg, 0, sizeof(msg)); 7910d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_id = message_id; 7920d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com if (message_id == kWriteDumpMessage || 7930d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com message_id == kWriteDumpWithExceptionMessage) { 7940d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com // Include this thread's port. 7950d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.thread.name = mach_thread_self(); 7960d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.thread.disposition = MACH_MSG_TYPE_PORT_SEND; 7970d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.thread.type = MACH_MSG_PORT_DESCRIPTOR; 7980d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com } 7990d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_size = sizeof(msg) - sizeof(msg.padding); 8000d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_remote_port = handler_port_; 8010d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 8025ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_MSG_TYPE_MAKE_SEND_ONCE); 8030d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com kern_return_t result = mach_msg(&(msg.header), 8045ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_SEND_MSG | MACH_SEND_TIMEOUT, 8050d9bd40775211c223c75543890d862135f677d67ted.mielczarek@gmail.com msg.header.msgh_size, 0, 0, 8065ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 8075ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 8085ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis return result == KERN_SUCCESS; 8095ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 8105ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 8115ac2b9a569890f165478f91670dcdd553ce2d10ewaylonisvoid ExceptionHandler::UpdateNextID() { 8125ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis next_minidump_path_ = 8135ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis (MinidumpGenerator::UniqueNameInDirectory(dump_path_, &next_minidump_id_)); 8145ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 8155ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis next_minidump_path_c_ = next_minidump_path_.c_str(); 8165ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis next_minidump_id_c_ = next_minidump_id_.c_str(); 8175ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis} 8185ac2b9a569890f165478f91670dcdd553ce2d10ewaylonis 819530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreakerbool ExceptionHandler::SuspendThreads() { 820530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker thread_act_port_array_t threads_for_task; 821530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker mach_msg_type_number_t thread_count; 822530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 823530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (task_threads(mach_task_self(), &threads_for_task, &thread_count)) 824530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return false; 825530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 826530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // suspend all of the threads except for this one 827530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker for (unsigned int i = 0; i < thread_count; ++i) { 828530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (threads_for_task[i] != mach_thread_self()) { 829530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (thread_suspend(threads_for_task[i])) 830530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return false; 831530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker } 832530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker } 83332441cc0608ddaf81885d23acf63f4b53cb73744nealsid 834530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return true; 835530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker} 836530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 837530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreakerbool ExceptionHandler::ResumeThreads() { 838530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker thread_act_port_array_t threads_for_task; 839530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker mach_msg_type_number_t thread_count; 840530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 841530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (task_threads(mach_task_self(), &threads_for_task, &thread_count)) 842530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return false; 843530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 844530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker // resume all of the threads except for this one 845530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker for (unsigned int i = 0; i < thread_count; ++i) { 846530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (threads_for_task[i] != mach_thread_self()) { 847530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker if (thread_resume(threads_for_task[i])) 848530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return false; 849530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker } 850530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker } 85132441cc0608ddaf81885d23acf63f4b53cb73744nealsid 852530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker return true; 853530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker} 854530a7ad99eba824dcca7fd300e85f1faa5828a3dladderbreaker 855e5dc60822e5938fea2ae892ccddb906641ba174emmentovai} // namespace google_breakpad 856