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                           &current.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