/thirdparty/breakpad/client/mac/crash_generation/crash_generation_server.cc
C++ | 160 lines | 106 code | 21 blank | 33 comment | 22 complexity | 58cc655ea9a0a3cfcf676a8a280cc5bf MD5 | raw file
1// Copyright (c) 2010 Google Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions are 6// met: 7// 8// * Redistributions of source code must retain the above copyright 9// notice, this list of conditions and the following disclaimer. 10// * Redistributions in binary form must reproduce the above 11// copyright notice, this list of conditions and the following disclaimer 12// in the documentation and/or other materials provided with the 13// distribution. 14// * Neither the name of Google Inc. nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30#include "client/mac/crash_generation/crash_generation_server.h" 31 32#include "client/mac/crash_generation/client_info.h" 33#include "client/mac/handler/minidump_generator.h" 34#include "common/mac/scoped_task_suspend-inl.h" 35 36namespace google_breakpad { 37 38CrashGenerationServer::CrashGenerationServer( 39 const char *mach_port_name, 40 OnClientDumpRequestCallback dump_callback, 41 void *dump_context, 42 OnClientExitingCallback exit_callback, 43 void *exit_context, 44 bool generate_dumps, 45 const std::string &dump_path) 46 : dump_callback_(dump_callback), 47 dump_context_(dump_context), 48 exit_callback_(exit_callback), 49 exit_context_(exit_context), 50 generate_dumps_(generate_dumps), 51 dump_dir_(dump_path.empty() ? "/tmp" : dump_path), 52 started_(false), 53 receive_port_(mach_port_name), 54 mach_port_name_(mach_port_name) { 55} 56 57CrashGenerationServer::~CrashGenerationServer() { 58 if (started_) 59 Stop(); 60} 61 62bool CrashGenerationServer::Start() { 63 int thread_create_result = pthread_create(&server_thread_, NULL, 64 &WaitForMessages, this); 65 started_ = thread_create_result == 0; 66 return started_; 67} 68 69bool CrashGenerationServer::Stop() { 70 if (!started_) 71 return false; 72 73 // Send a quit message to the background thread, and then join it. 74 MachPortSender sender(mach_port_name_.c_str()); 75 MachSendMessage quit_message(kQuitMessage); 76 const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000; 77 kern_return_t result = sender.SendMessage(quit_message, kSendTimeoutMs); 78 if (result == KERN_SUCCESS) { 79 int thread_join_result = pthread_join(server_thread_, NULL); 80 started_ = thread_join_result != 0; 81 } 82 83 return !started_; 84} 85 86// static 87void *CrashGenerationServer::WaitForMessages(void *server) { 88 CrashGenerationServer *self = 89 reinterpret_cast<CrashGenerationServer*>(server); 90 while (self->WaitForOneMessage()) {} 91 return NULL; 92} 93 94bool CrashGenerationServer::WaitForOneMessage() { 95 MachReceiveMessage message; 96 kern_return_t result = receive_port_.WaitForMessage(&message, 97 MACH_MSG_TIMEOUT_NONE); 98 if (result == KERN_SUCCESS) { 99 switch (message.GetMessageID()) { 100 case kDumpRequestMessage: { 101 ExceptionInfo &info = (ExceptionInfo &)*message.GetData(); 102 103 mach_port_t remote_task = message.GetTranslatedPort(0); 104 mach_port_t crashing_thread = message.GetTranslatedPort(1); 105 mach_port_t handler_thread = message.GetTranslatedPort(2); 106 mach_port_t ack_port = message.GetTranslatedPort(3); 107 pid_t remote_pid = -1; 108 pid_for_task(remote_task, &remote_pid); 109 ClientInfo client(remote_pid); 110 111 bool result; 112 std::string dump_path; 113 if (generate_dumps_) { 114 ScopedTaskSuspend suspend(remote_task); 115 116 MinidumpGenerator generator(remote_task, handler_thread); 117 dump_path = generator.UniqueNameInDirectory(dump_dir_, NULL); 118 119 if (info.exception_type && info.exception_code) { 120 generator.SetExceptionInformation(info.exception_type, 121 info.exception_code, 122 info.exception_subcode, 123 crashing_thread); 124 } 125 result = generator.Write(dump_path.c_str()); 126 } else { 127 result = true; 128 } 129 130 if (result && dump_callback_) { 131 dump_callback_(dump_context_, client, dump_path); 132 } 133 134 // TODO(ted): support a way for the client to send additional data, 135 // perhaps with a callback so users of the server can read the data 136 // themselves? 137 138 if (ack_port != MACH_PORT_DEAD && ack_port != MACH_PORT_NULL) { 139 MachPortSender sender(ack_port); 140 MachSendMessage ack_message(kAcknowledgementMessage); 141 const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000; 142 143 sender.SendMessage(ack_message, kSendTimeoutMs); 144 } 145 146 if (exit_callback_) { 147 exit_callback_(exit_context_, client); 148 } 149 break; 150 } 151 case kQuitMessage: 152 return false; 153 } 154 } else { // result != KERN_SUCCESS 155 return false; 156 } 157 return true; 158} 159 160} // namespace google_breakpad