aboutsummaryrefslogtreecommitdiff
path: root/src/client/mac/handler
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/mac/handler')
-rw-r--r--src/client/mac/handler/exception_handler.cc75
-rw-r--r--src/client/mac/handler/exception_handler.h37
2 files changed, 79 insertions, 33 deletions
diff --git a/src/client/mac/handler/exception_handler.cc b/src/client/mac/handler/exception_handler.cc
index b9f84b48..28d6ad64 100644
--- a/src/client/mac/handler/exception_handler.cc
+++ b/src/client/mac/handler/exception_handler.cc
@@ -53,9 +53,6 @@ namespace google_breakpad {
using std::map;
-// Message ID telling the handler thread to quit.
-static const mach_msg_id_t kQuitMessage = 1;
-
// These structures and techniques are illustrated in
// Mac OS X Internals, Amit Singh, ch 9.7
struct ExceptionMessage {
@@ -272,7 +269,7 @@ ExceptionHandler::~ExceptionHandler() {
Teardown();
}
-bool ExceptionHandler::WriteMinidump() {
+bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {
// If we're currently writing, just return
if (use_minidump_write_mutex_)
return false;
@@ -284,7 +281,9 @@ bool ExceptionHandler::WriteMinidump() {
if (pthread_mutex_lock(&minidump_write_mutex_) == 0) {
// Send an empty message to the handle port so that a minidump will
// be written
- SendEmptyMachMessage(false);
+ SendMessageToHandlerThread(write_exception_stream ?
+ kWriteDumpWithExceptionMessage :
+ kWriteDumpMessage);
// Wait for the minidump writer to complete its writing. It will unlock
// the mutex when completed
@@ -298,11 +297,12 @@ bool ExceptionHandler::WriteMinidump() {
// static
bool ExceptionHandler::WriteMinidump(const string &dump_path,
+ bool write_exception_stream,
MinidumpCallback callback,
void *callback_context) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false,
NULL);
- return handler.WriteMinidump();
+ return handler.WriteMinidump(write_exception_stream);
}
// static
@@ -323,7 +323,7 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
#elif defined (__ppc__) || defined (__ppc64__)
EXC_PPC_BREAKPOINT,
#else
- #error architecture not supported
+#error architecture not supported
#endif
0,
child_blamed_thread);
@@ -339,7 +339,8 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
int exception_code,
int exception_subcode,
- mach_port_t thread_name) {
+ mach_port_t thread_name,
+ bool exit_after_write) {
bool result = false;
if (directCallback_) {
@@ -348,7 +349,7 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
exception_code,
exception_subcode,
thread_name) ) {
- if (exception_type && exception_code)
+ if (exit_after_write)
_exit(exception_type);
}
} else if (IsOutOfProcess()) {
@@ -390,7 +391,7 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
// forwarding the exception to the next handler.
if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
result)) {
- if (exception_type && exception_code)
+ if (exit_after_write)
_exit(exception_type);
}
}
@@ -527,7 +528,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
if (!receive.exception) {
// Don't touch self, since this message could have been sent
// from its destructor.
- if (receive.header.msgh_id == kQuitMessage)
+ if (receive.header.msgh_id == kShutdownMessage)
return NULL;
self->SuspendThreads();
@@ -537,11 +538,26 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
gBreakpadAllocator->Unprotect();
#endif
+ mach_port_t thread = MACH_PORT_NULL;
+ int exception_type = 0;
+ int exception_code = 0;
+ if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) {
+ thread = receive.thread.name;
+ exception_type = EXC_BREAKPOINT;
+#if defined (__i386__) || defined(__x86_64__)
+ exception_code = EXC_I386_BPT;
+#elif defined (__ppc__) || defined (__ppc64__)
+ exception_code = EXC_PPC_BREAKPOINT;
+#else
+#error architecture not supported
+#endif
+ }
+
// Write out the dump and save the result for later retrieval
self->last_minidump_write_result_ =
- self->WriteMinidumpWithException(0, 0, 0, 0);
-
- self->UninstallHandler(false);
+ self->WriteMinidumpWithException(exception_type, exception_code,
+ 0, thread,
+ false);
#if USE_PROTECTED_ALLOCATIONS
if(gBreakpadAllocator)
@@ -575,7 +591,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
// Generate the minidump with the exception data.
self->WriteMinidumpWithException(receive.exception, receive.code[0],
- subcode, receive.thread.name);
+ subcode, receive.thread.name, true);
self->UninstallHandler(true);
@@ -710,7 +726,7 @@ bool ExceptionHandler::Teardown() {
return false;
// Send an empty message so that the handler_thread exits
- if (SendEmptyMachMessage(true)) {
+ if (SendMessageToHandlerThread(kShutdownMessage)) {
mach_port_t current_task = mach_task_self();
result = mach_port_deallocate(current_task, handler_port_);
if (result != KERN_SUCCESS)
@@ -726,18 +742,25 @@ bool ExceptionHandler::Teardown() {
return result == KERN_SUCCESS;
}
-bool ExceptionHandler::SendEmptyMachMessage(bool quit) {
- ExceptionMessage empty;
- memset(&empty, 0, sizeof(empty));
- if (quit)
- empty.header.msgh_id = kQuitMessage;
- empty.header.msgh_size = sizeof(empty) - sizeof(empty.padding);
- empty.header.msgh_remote_port = handler_port_;
- empty.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
+bool ExceptionHandler::SendMessageToHandlerThread(
+ HandlerThreadMessage message_id) {
+ ExceptionMessage msg;
+ memset(&msg, 0, sizeof(msg));
+ msg.header.msgh_id = message_id;
+ if (message_id == kWriteDumpMessage ||
+ message_id == kWriteDumpWithExceptionMessage) {
+ // Include this thread's port.
+ msg.thread.name = mach_thread_self();
+ msg.thread.disposition = MACH_MSG_TYPE_PORT_SEND;
+ msg.thread.type = MACH_MSG_PORT_DESCRIPTOR;
+ }
+ msg.header.msgh_size = sizeof(msg) - sizeof(msg.padding);
+ msg.header.msgh_remote_port = handler_port_;
+ msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
MACH_MSG_TYPE_MAKE_SEND_ONCE);
- kern_return_t result = mach_msg(&(empty.header),
+ kern_return_t result = mach_msg(&(msg.header),
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
- empty.header.msgh_size, 0, 0,
+ msg.header.msgh_size, 0, 0,
MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
return result == KERN_SUCCESS;
diff --git a/src/client/mac/handler/exception_handler.h b/src/client/mac/handler/exception_handler.h
index 182faa9d..172dc358 100644
--- a/src/client/mac/handler/exception_handler.h
+++ b/src/client/mac/handler/exception_handler.h
@@ -49,6 +49,16 @@ using std::string;
struct ExceptionParameters;
+enum HandlerThreadMessage {
+ // Message ID telling the handler thread to write a dump.
+ kWriteDumpMessage = 0,
+ // Message ID telling the handler thread to write a dump and include
+ // an exception stream.
+ kWriteDumpWithExceptionMessage = 1,
+ // Message ID telling the handler thread to quit.
+ kShutdownMessage = 2
+};
+
class ExceptionHandler {
public:
// A callback function to run before Breakpad performs any substantial
@@ -114,11 +124,22 @@ class ExceptionHandler {
// Writes a minidump immediately. This can be used to capture the
// execution state independently of a crash. Returns true on success.
- bool WriteMinidump();
+ bool WriteMinidump() {
+ return WriteMinidump(false);
+ }
+
+ bool WriteMinidump(bool write_exception_stream);
// Convenience form of WriteMinidump which does not require an
// ExceptionHandler instance.
static bool WriteMinidump(const string &dump_path, MinidumpCallback callback,
+ void *callback_context) {
+ return WriteMinidump(dump_path, false, callback, callback_context);
+ }
+
+ static bool WriteMinidump(const string &dump_path,
+ bool write_exception_stream,
+ MinidumpCallback callback,
void *callback_context);
// Write a minidump of child immediately. This can be used to capture
@@ -149,14 +170,16 @@ class ExceptionHandler {
// thread
bool Teardown();
- // Send an "empty" mach message to the exception handler. Return true on
- // success, false otherwise. If quit is true, the handler thread should
- // simply quit.
- bool SendEmptyMachMessage(bool quit);
+ // Send a mach message to the exception handler. Return true on
+ // success, false otherwise.
+ bool SendMessageToHandlerThread(HandlerThreadMessage message_id);
// All minidump writing goes through this one routine
- bool WriteMinidumpWithException(int exception_type, int exception_code,
- int exception_subcode, mach_port_t thread_name);
+ bool WriteMinidumpWithException(int exception_type,
+ int exception_code,
+ int exception_subcode,
+ mach_port_t thread_name,
+ bool exit_after_write);
// When installed, this static function will be call from a newly created
// pthread with |this| as the argument