summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '3rdParty/Breakpad/src/client/mac/crash_generation')
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.h83
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.mm167
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.h162
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.mm362
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/InspectorMain.mm65
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/client_info.h47
-rw-r--r--3rdParty/Breakpad/src/client/mac/crash_generation/crash_generation_server.cc166
7 files changed, 1052 insertions, 0 deletions
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.h b/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.h
new file mode 100644
index 0000000..5662e8b
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Utility class that can persist a SimpleStringDictionary to disk.
+
+#import <Foundation/Foundation.h>
+
+#include "common/simple_string_dictionary.h"
+
+namespace google_breakpad {
+
+BOOL EnsureDirectoryPathExists(NSString *dirPath);
+
+//=============================================================================
+class ConfigFile {
+ public:
+ ConfigFile() {
+ config_file_ = -1;
+ config_file_path_[0] = 0;
+ has_created_file_ = false;
+ };
+
+ ~ConfigFile() {
+ };
+
+ void WriteFile(const char* directory,
+ const SimpleStringDictionary *configurationParameters,
+ const char *dump_dir,
+ const char *minidump_id);
+
+ const char *GetFilePath() { return config_file_path_; }
+
+ void Unlink() {
+ if (config_file_ != -1)
+ unlink(config_file_path_);
+
+ config_file_ = -1;
+ }
+
+ private:
+ BOOL WriteData(const void *data, size_t length);
+
+ BOOL AppendConfigData(const char *key,
+ const void *data,
+ size_t length);
+
+ BOOL AppendConfigString(const char *key,
+ const char *value);
+
+ BOOL AppendCrashTimeParameters(const char *processStartTimeString);
+
+ int config_file_; // descriptor for config file
+ char config_file_path_[PATH_MAX]; // Path to configuration file
+ bool has_created_file_;
+};
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.mm b/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.mm
new file mode 100644
index 0000000..acab7de
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/ConfigFile.mm
@@ -0,0 +1,167 @@
+// Copyright (c) 2011, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Utility class that can persist a SimpleStringDictionary to disk.
+
+#import "client/mac/crash_generation/ConfigFile.h"
+
+#import <Foundation/Foundation.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#import "client/apple/Framework/BreakpadDefines.h"
+#import "common/mac/GTMDefines.h"
+
+
+namespace google_breakpad {
+
+//=============================================================================
+BOOL EnsureDirectoryPathExists(NSString *dirPath) {
+ NSFileManager *mgr = [NSFileManager defaultManager];
+
+ NSDictionary *attrs =
+ [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedLong:0750]
+ forKey:NSFilePosixPermissions];
+
+ return [mgr createDirectoryAtPath:dirPath
+ withIntermediateDirectories:YES
+ attributes:attrs
+ error:nil];
+}
+
+//=============================================================================
+BOOL ConfigFile::WriteData(const void *data, size_t length) {
+ size_t result = write(config_file_, data, length);
+
+ return result == length;
+}
+
+//=============================================================================
+BOOL ConfigFile::AppendConfigData(const char *key,
+ const void *data, size_t length) {
+ assert(config_file_ != -1);
+
+ if (!key) {
+ return NO;
+ }
+
+ if (!data) {
+ return NO;
+ }
+
+ // Write the key, \n, length of data (ascii integer), \n, data
+ char buffer[16];
+ char nl = '\n';
+ BOOL result = WriteData(key, strlen(key));
+
+ snprintf(buffer, sizeof(buffer) - 1, "\n%lu\n", length);
+ result &= WriteData(buffer, strlen(buffer));
+ result &= WriteData(data, length);
+ result &= WriteData(&nl, 1);
+ return result;
+}
+
+//=============================================================================
+BOOL ConfigFile::AppendConfigString(const char *key,
+ const char *value) {
+ return AppendConfigData(key, value, strlen(value));
+}
+
+//=============================================================================
+BOOL ConfigFile::AppendCrashTimeParameters(const char *processStartTimeString) {
+ // Set process uptime parameter
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ char processUptimeString[32], processCrashtimeString[32];
+ // Set up time if we've received the start time.
+ if (processStartTimeString) {
+ time_t processStartTime = strtol(processStartTimeString, NULL, 10);
+ time_t processUptime = tv.tv_sec - processStartTime;
+ // Store the uptime in milliseconds.
+ sprintf(processUptimeString, "%llu",
+ static_cast<unsigned long long int>(processUptime) * 1000);
+ if (!AppendConfigString(BREAKPAD_PROCESS_UP_TIME, processUptimeString))
+ return false;
+ }
+
+ sprintf(processCrashtimeString, "%zd", tv.tv_sec);
+ return AppendConfigString(BREAKPAD_PROCESS_CRASH_TIME,
+ processCrashtimeString);
+}
+
+//=============================================================================
+void ConfigFile::WriteFile(const char* directory,
+ const SimpleStringDictionary *configurationParameters,
+ const char *dump_dir,
+ const char *minidump_id) {
+
+ assert(config_file_ == -1);
+
+ // Open and write out configuration file preamble
+ if (directory) {
+ snprintf(config_file_path_, sizeof(config_file_path_), "%s/Config-XXXXXX",
+ directory);
+ } else {
+ strlcpy(config_file_path_, "/tmp/Config-XXXXXX",
+ sizeof(config_file_path_));
+ }
+ config_file_ = mkstemp(config_file_path_);
+
+ if (config_file_ == -1) {
+ return;
+ }
+
+ has_created_file_ = true;
+
+ // Add the minidump dir
+ AppendConfigString(kReporterMinidumpDirectoryKey, dump_dir);
+ AppendConfigString(kReporterMinidumpIDKey, minidump_id);
+
+ // Write out the configuration parameters
+ BOOL result = YES;
+ const SimpleStringDictionary &dictionary = *configurationParameters;
+
+ const SimpleStringDictionary::Entry *entry = NULL;
+ SimpleStringDictionary::Iterator iter(dictionary);
+
+ while ((entry = iter.Next())) {
+ result = AppendConfigString(entry->key, entry->value);
+
+ if (!result)
+ break;
+ }
+ AppendCrashTimeParameters(
+ configurationParameters->GetValueForKey(BREAKPAD_PROCESS_START_TIME));
+
+ close(config_file_);
+ config_file_ = -1;
+}
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.h b/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.h
new file mode 100644
index 0000000..6712355
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.h
@@ -0,0 +1,162 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Interface file between the Breakpad.framework and
+// the Inspector process.
+
+#include "common/simple_string_dictionary.h"
+
+#import <Foundation/Foundation.h>
+#include <mach/mach.h>
+
+#import "client/mac/crash_generation/ConfigFile.h"
+#import "client/mac/handler/minidump_generator.h"
+
+
+// Types of mach messsages (message IDs)
+enum {
+ kMsgType_InspectorInitialInfo = 0, // data is InspectorInfo
+ kMsgType_InspectorKeyValuePair = 1, // data is KeyValueMessageData
+ kMsgType_InspectorAcknowledgement = 2 // no data sent
+};
+
+// Initial information sent from the crashed process by
+// Breakpad.framework to the Inspector process
+// The mach message with this struct as data will also include
+// several descriptors for sending mach port rights to the crashed
+// task, etc.
+struct InspectorInfo {
+ int exception_type;
+ int exception_code;
+ int exception_subcode;
+ unsigned int parameter_count; // key-value pairs
+};
+
+// Key/value message data to be sent to the Inspector
+struct KeyValueMessageData {
+ public:
+ KeyValueMessageData() {}
+ explicit KeyValueMessageData(
+ const google_breakpad::SimpleStringDictionary::Entry &inEntry) {
+ strlcpy(key, inEntry.key, sizeof(key) );
+ strlcpy(value, inEntry.value, sizeof(value) );
+ }
+
+ char key[google_breakpad::SimpleStringDictionary::key_size];
+ char value[google_breakpad::SimpleStringDictionary::value_size];
+};
+
+using std::string;
+using google_breakpad::MinidumpGenerator;
+
+namespace google_breakpad {
+
+//=============================================================================
+class MinidumpLocation {
+ public:
+ MinidumpLocation(NSString *minidumpDir) {
+ // Ensure that the path exists. Fallback to /tmp if unable to locate path.
+ assert(minidumpDir);
+ if (!EnsureDirectoryPathExists(minidumpDir)) {
+ minidumpDir = @"/tmp";
+ }
+
+ strlcpy(minidump_dir_path_, [minidumpDir fileSystemRepresentation],
+ sizeof(minidump_dir_path_));
+
+ // now generate a unique ID
+ string dump_path(minidump_dir_path_);
+ string next_minidump_id;
+
+ string next_minidump_path_ =
+ (MinidumpGenerator::UniqueNameInDirectory(dump_path, &next_minidump_id));
+
+ strlcpy(minidump_id_, next_minidump_id.c_str(), sizeof(minidump_id_));
+ };
+
+ const char *GetPath() { return minidump_dir_path_; }
+ const char *GetID() { return minidump_id_; }
+
+ private:
+ char minidump_dir_path_[PATH_MAX]; // Path to minidump directory
+ char minidump_id_[128];
+};
+
+//=============================================================================
+class Inspector {
+ public:
+ Inspector() {};
+
+ // given a bootstrap service name, receives mach messages
+ // from a crashed process, then inspects it, creates a minidump file
+ // and asks the user if he wants to upload it to a server.
+ void Inspect(const char *receive_port_name);
+
+ private:
+ // The Inspector is invoked with its bootstrap port set to the bootstrap
+ // subset established in OnDemandServer.mm OnDemandServer::Initialize.
+ // For proper communication with the system, the sender (which will inherit
+ // the Inspector's bootstrap port) needs the per-session bootstrap namespace
+ // available directly in its bootstrap port. OnDemandServer stashed this
+ // port into the subset namespace under a special name. ResetBootstrapPort
+ // recovers this port and switches this task to use it as its own bootstrap
+ // (ensuring that children like the sender will inherit it), and saves the
+ // subset in bootstrap_subset_port_ for use by ServiceCheckIn and
+ // ServiceCheckOut.
+ kern_return_t ResetBootstrapPort();
+
+ kern_return_t ServiceCheckIn(const char *receive_port_name);
+ kern_return_t ServiceCheckOut(const char *receive_port_name);
+
+ kern_return_t ReadMessages();
+
+ bool InspectTask();
+ kern_return_t SendAcknowledgement();
+
+ // The bootstrap port in which the inspector is registered and into which it
+ // must check in.
+ mach_port_t bootstrap_subset_port_;
+
+ mach_port_t service_rcv_port_;
+
+ int exception_type_;
+ int exception_code_;
+ int exception_subcode_;
+ mach_port_t remote_task_;
+ mach_port_t crashing_thread_;
+ mach_port_t handler_thread_;
+ mach_port_t ack_port_;
+
+ SimpleStringDictionary config_params_;
+
+ ConfigFile config_file_;
+};
+
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.mm b/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.mm
new file mode 100644
index 0000000..dc6f480
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/Inspector.mm
@@ -0,0 +1,362 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Utility that can inspect another process and write a crash dump
+
+#include <cstdio>
+#include <iostream>
+#include <servers/bootstrap.h>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+
+#import "client/mac/crash_generation/Inspector.h"
+
+#import "client/mac/Framework/Breakpad.h"
+#import "client/mac/handler/minidump_generator.h"
+
+#import "common/mac/MachIPC.h"
+#include "common/mac/bootstrap_compat.h"
+#include "common/mac/launch_reporter.h"
+
+#import "GTMDefines.h"
+
+#import <Foundation/Foundation.h>
+
+namespace google_breakpad {
+
+//=============================================================================
+void Inspector::Inspect(const char *receive_port_name) {
+ kern_return_t result = ResetBootstrapPort();
+ if (result != KERN_SUCCESS) {
+ return;
+ }
+
+ result = ServiceCheckIn(receive_port_name);
+
+ if (result == KERN_SUCCESS) {
+ result = ReadMessages();
+
+ if (result == KERN_SUCCESS) {
+ // Inspect the task and write a minidump file.
+ bool wrote_minidump = InspectTask();
+
+ // Send acknowledgement to the crashed process that the inspection
+ // has finished. It will then be able to cleanly exit.
+ // The return value is ignored because failure isn't fatal. If the process
+ // didn't get the message there's nothing we can do, and we still want to
+ // send the report.
+ SendAcknowledgement();
+
+ if (wrote_minidump) {
+ // Ask the user if he wants to upload the crash report to a server,
+ // and do so if he agrees.
+ LaunchReporter(
+ config_params_.GetValueForKey(BREAKPAD_REPORTER_EXE_LOCATION),
+ config_file_.GetFilePath());
+ } else {
+ fprintf(stderr, "Inspection of crashed process failed\n");
+ }
+
+ // Now that we're done reading messages, cleanup the service, but only
+ // if there was an actual exception
+ // Otherwise, it means the dump was generated on demand and the process
+ // lives on, and we might be needed again in the future.
+ if (exception_code_) {
+ ServiceCheckOut(receive_port_name);
+ }
+ } else {
+ PRINT_MACH_RESULT(result, "Inspector: WaitForMessage()");
+ }
+ }
+}
+
+//=============================================================================
+kern_return_t Inspector::ResetBootstrapPort() {
+ // A reasonable default, in case anything fails.
+ bootstrap_subset_port_ = bootstrap_port;
+
+ mach_port_t self_task = mach_task_self();
+
+ kern_return_t kr = task_get_bootstrap_port(self_task,
+ &bootstrap_subset_port_);
+ if (kr != KERN_SUCCESS) {
+ NSLog(@"ResetBootstrapPort: task_get_bootstrap_port failed: %s (%d)",
+ mach_error_string(kr), kr);
+ return kr;
+ }
+
+ mach_port_t bootstrap_parent_port;
+ kr = bootstrap_look_up(bootstrap_subset_port_,
+ const_cast<char*>(BREAKPAD_BOOTSTRAP_PARENT_PORT),
+ &bootstrap_parent_port);
+ if (kr != BOOTSTRAP_SUCCESS) {
+ NSLog(@"ResetBootstrapPort: bootstrap_look_up failed: %s (%d)",
+#if defined(MAC_OS_X_VERSION_10_5) && \
+ MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ bootstrap_strerror(kr),
+#else
+ mach_error_string(kr),
+#endif
+ kr);
+ return kr;
+ }
+
+ kr = task_set_bootstrap_port(self_task, bootstrap_parent_port);
+ if (kr != KERN_SUCCESS) {
+ NSLog(@"ResetBootstrapPort: task_set_bootstrap_port failed: %s (%d)",
+ mach_error_string(kr), kr);
+ return kr;
+ }
+
+ // Some things access the bootstrap port through this global variable
+ // instead of calling task_get_bootstrap_port.
+ bootstrap_port = bootstrap_parent_port;
+
+ return KERN_SUCCESS;
+}
+
+//=============================================================================
+kern_return_t Inspector::ServiceCheckIn(const char *receive_port_name) {
+ // We need to get the mach port representing this service, so we can
+ // get information from the crashed process.
+ kern_return_t kr = bootstrap_check_in(bootstrap_subset_port_,
+ (char*)receive_port_name,
+ &service_rcv_port_);
+
+ if (kr != KERN_SUCCESS) {
+#if VERBOSE
+ PRINT_MACH_RESULT(kr, "Inspector: bootstrap_check_in()");
+#endif
+ }
+
+ return kr;
+}
+
+//=============================================================================
+kern_return_t Inspector::ServiceCheckOut(const char *receive_port_name) {
+ // We're done receiving mach messages from the crashed process,
+ // so clean up a bit.
+ kern_return_t kr;
+
+ // DO NOT use mach_port_deallocate() here -- it will fail and the
+ // following bootstrap_register() will also fail leaving our service
+ // name hanging around forever (until reboot)
+ kr = mach_port_destroy(mach_task_self(), service_rcv_port_);
+
+ if (kr != KERN_SUCCESS) {
+ PRINT_MACH_RESULT(kr,
+ "Inspector: UNREGISTERING: service_rcv_port mach_port_deallocate()");
+ return kr;
+ }
+
+ // Unregister the service associated with the receive port.
+ kr = breakpad::BootstrapRegister(bootstrap_subset_port_,
+ (char*)receive_port_name,
+ MACH_PORT_NULL);
+
+ if (kr != KERN_SUCCESS) {
+ PRINT_MACH_RESULT(kr, "Inspector: UNREGISTERING: bootstrap_register()");
+ }
+
+ return kr;
+}
+
+//=============================================================================
+kern_return_t Inspector::ReadMessages() {
+ // Wait for an initial message from the crashed process containing basic
+ // information about the crash.
+ ReceivePort receive_port(service_rcv_port_);
+
+ MachReceiveMessage message;
+ kern_return_t result = receive_port.WaitForMessage(&message, 1000);
+
+ if (result == KERN_SUCCESS) {
+ InspectorInfo &info = (InspectorInfo &)*message.GetData();
+ exception_type_ = info.exception_type;
+ exception_code_ = info.exception_code;
+ exception_subcode_ = info.exception_subcode;
+
+#if VERBOSE
+ printf("message ID = %d\n", message.GetMessageID());
+#endif
+
+ remote_task_ = message.GetTranslatedPort(0);
+ crashing_thread_ = message.GetTranslatedPort(1);
+ handler_thread_ = message.GetTranslatedPort(2);
+ ack_port_ = message.GetTranslatedPort(3);
+
+#if VERBOSE
+ printf("exception_type = %d\n", exception_type_);
+ printf("exception_code = %d\n", exception_code_);
+ printf("exception_subcode = %d\n", exception_subcode_);
+ printf("remote_task = %d\n", remote_task_);
+ printf("crashing_thread = %d\n", crashing_thread_);
+ printf("handler_thread = %d\n", handler_thread_);
+ printf("ack_port_ = %d\n", ack_port_);
+ printf("parameter count = %d\n", info.parameter_count);
+#endif
+
+ // In certain situations where multiple crash requests come
+ // through quickly, we can end up with the mach IPC messages not
+ // coming through correctly. Since we don't know what parameters
+ // we've missed, we can't do much besides abort the crash dump
+ // situation in this case.
+ unsigned int parameters_read = 0;
+ // The initial message contains the number of key value pairs that
+ // we are expected to read.
+ // Read each key/value pair, one mach message per key/value pair.
+ for (unsigned int i = 0; i < info.parameter_count; ++i) {
+ MachReceiveMessage parameter_message;
+ result = receive_port.WaitForMessage(&parameter_message, 1000);
+
+ if(result == KERN_SUCCESS) {
+ KeyValueMessageData &key_value_data =
+ (KeyValueMessageData&)*parameter_message.GetData();
+ // If we get a blank key, make sure we don't increment the
+ // parameter count; in some cases (notably on-demand generation
+ // many times in a short period of time) caused the Mach IPC
+ // messages to not come through correctly.
+ if (strlen(key_value_data.key) == 0) {
+ continue;
+ }
+ parameters_read++;
+
+ config_params_.SetKeyValue(key_value_data.key, key_value_data.value);
+ } else {
+ PRINT_MACH_RESULT(result, "Inspector: key/value message");
+ break;
+ }
+ }
+ if (parameters_read != info.parameter_count) {
+ return KERN_FAILURE;
+ }
+ }
+
+ return result;
+}
+
+//=============================================================================
+bool Inspector::InspectTask() {
+ // keep the task quiet while we're looking at it
+ task_suspend(remote_task_);
+
+ NSString *minidumpDir;
+
+ const char *minidumpDirectory =
+ config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
+
+ // If the client app has not specified a minidump directory,
+ // use a default of Library/<kDefaultLibrarySubdirectory>/<Product Name>
+ if (!minidumpDirectory || 0 == strlen(minidumpDirectory)) {
+ NSArray *libraryDirectories =
+ NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
+ NSUserDomainMask,
+ YES);
+
+ NSString *applicationSupportDirectory =
+ [libraryDirectories objectAtIndex:0];
+ NSString *library_subdirectory = [NSString
+ stringWithUTF8String:kDefaultLibrarySubdirectory];
+ NSString *breakpad_product = [NSString
+ stringWithUTF8String:config_params_.GetValueForKey(BREAKPAD_PRODUCT)];
+
+ NSArray *path_components = [NSArray
+ arrayWithObjects:applicationSupportDirectory,
+ library_subdirectory,
+ breakpad_product,
+ nil];
+
+ minidumpDir = [NSString pathWithComponents:path_components];
+ } else {
+ minidumpDir = [[NSString stringWithUTF8String:minidumpDirectory]
+ stringByExpandingTildeInPath];
+ }
+
+ MinidumpLocation minidumpLocation(minidumpDir);
+
+ // Obscure bug alert:
+ // Don't use [NSString stringWithFormat] to build up the path here since it
+ // assumes system encoding and in RTL locales will prepend an LTR override
+ // character for paths beginning with '/' which fileSystemRepresentation does
+ // not remove. Filed as rdar://6889706 .
+ NSString *path_ns = [NSString
+ stringWithUTF8String:minidumpLocation.GetPath()];
+ NSString *pathid_ns = [NSString
+ stringWithUTF8String:minidumpLocation.GetID()];
+ NSString *minidumpPath = [path_ns stringByAppendingPathComponent:pathid_ns];
+ minidumpPath = [minidumpPath
+ stringByAppendingPathExtension:@"dmp"];
+
+ config_file_.WriteFile( 0,
+ &config_params_,
+ minidumpLocation.GetPath(),
+ minidumpLocation.GetID());
+
+
+ MinidumpGenerator generator(remote_task_, handler_thread_);
+
+ if (exception_type_ && exception_code_) {
+ generator.SetExceptionInformation(exception_type_,
+ exception_code_,
+ exception_subcode_,
+ crashing_thread_);
+ }
+
+
+ bool result = generator.Write([minidumpPath fileSystemRepresentation]);
+
+ // let the task continue
+ task_resume(remote_task_);
+
+ return result;
+}
+
+//=============================================================================
+// The crashed task needs to be told that the inspection has finished.
+// It will wait on a mach port (with timeout) until we send acknowledgement.
+kern_return_t Inspector::SendAcknowledgement() {
+ if (ack_port_ != MACH_PORT_DEAD) {
+ MachPortSender sender(ack_port_);
+ MachSendMessage ack_message(kMsgType_InspectorAcknowledgement);
+
+ kern_return_t result = sender.SendMessage(ack_message, 2000);
+
+#if VERBOSE
+ PRINT_MACH_RESULT(result, "Inspector: sent acknowledgement");
+#endif
+
+ return result;
+ }
+
+ return KERN_INVALID_NAME;
+}
+
+} // namespace google_breakpad
+
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/InspectorMain.mm b/3rdParty/Breakpad/src/client/mac/crash_generation/InspectorMain.mm
new file mode 100644
index 0000000..137c6a1
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/InspectorMain.mm
@@ -0,0 +1,65 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Main driver for Inspector
+
+#import "client/mac/crash_generation/Inspector.h"
+#import <Cocoa/Cocoa.h>
+
+namespace google_breakpad {
+
+//=============================================================================
+extern "C" {
+
+int main(int argc, char *const argv[]) {
+#if DEBUG
+ // Since we're launched on-demand, this is necessary to see debugging
+ // output in the console window.
+ freopen("/dev/console", "w", stdout);
+ freopen("/dev/console", "w", stderr);
+#endif
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ if (argc != 2) {
+ exit(0);
+ }
+ // Our first command-line argument contains the name of the service
+ // that we're providing.
+ google_breakpad::Inspector inspector;
+ inspector.Inspect(argv[1]);
+
+ [pool release];
+
+ return 0;
+}
+
+} // extern "C"
+
+} // namespace google_breakpad
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/client_info.h b/3rdParty/Breakpad/src/client/mac/crash_generation/client_info.h
new file mode 100644
index 0000000..a3a95dc
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/client_info.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_
+#define CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_
+
+namespace google_breakpad {
+
+class ClientInfo {
+ public:
+ explicit ClientInfo(pid_t pid) : pid_(pid) {}
+
+ pid_t pid() const { return pid_; }
+
+ private:
+ pid_t pid_;
+};
+
+} // namespace google_breakpad
+
+#endif // CLIENT_MAC_CRASH_GENERATION_CLIENT_INFO_H_
diff --git a/3rdParty/Breakpad/src/client/mac/crash_generation/crash_generation_server.cc b/3rdParty/Breakpad/src/client/mac/crash_generation/crash_generation_server.cc
new file mode 100644
index 0000000..451e8d9
--- /dev/null
+++ b/3rdParty/Breakpad/src/client/mac/crash_generation/crash_generation_server.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2010 Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "client/mac/crash_generation/crash_generation_server.h"
+
+#include <pthread.h>
+
+#include "client/mac/crash_generation/client_info.h"
+#include "client/mac/handler/minidump_generator.h"
+#include "common/mac/scoped_task_suspend-inl.h"
+
+namespace google_breakpad {
+
+CrashGenerationServer::CrashGenerationServer(
+ const char *mach_port_name,
+ FilterCallback filter,
+ void *filter_context,
+ OnClientDumpRequestCallback dump_callback,
+ void *dump_context,
+ OnClientExitingCallback exit_callback,
+ void *exit_context,
+ bool generate_dumps,
+ const std::string &dump_path)
+ : filter_(filter),
+ filter_context_(filter_context),
+ dump_callback_(dump_callback),
+ dump_context_(dump_context),
+ exit_callback_(exit_callback),
+ exit_context_(exit_context),
+ generate_dumps_(generate_dumps),
+ dump_dir_(dump_path.empty() ? "/tmp" : dump_path),
+ started_(false),
+ receive_port_(mach_port_name),
+ mach_port_name_(mach_port_name) {
+}
+
+CrashGenerationServer::~CrashGenerationServer() {
+ if (started_)
+ Stop();
+}
+
+bool CrashGenerationServer::Start() {
+ int thread_create_result = pthread_create(&server_thread_, NULL,
+ &WaitForMessages, this);
+ started_ = thread_create_result == 0;
+ return started_;
+}
+
+bool CrashGenerationServer::Stop() {
+ if (!started_)
+ return false;
+
+ // Send a quit message to the background thread, and then join it.
+ MachPortSender sender(mach_port_name_.c_str());
+ MachSendMessage quit_message(kQuitMessage);
+ const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
+ kern_return_t result = sender.SendMessage(quit_message, kSendTimeoutMs);
+ if (result == KERN_SUCCESS) {
+ int thread_join_result = pthread_join(server_thread_, NULL);
+ started_ = thread_join_result != 0;
+ }
+
+ return !started_;
+}
+
+// static
+void *CrashGenerationServer::WaitForMessages(void *server) {
+ CrashGenerationServer *self =
+ reinterpret_cast<CrashGenerationServer*>(server);
+ while (self->WaitForOneMessage()) {}
+ return NULL;
+}
+
+bool CrashGenerationServer::WaitForOneMessage() {
+ MachReceiveMessage message;
+ kern_return_t result = receive_port_.WaitForMessage(&message,
+ MACH_MSG_TIMEOUT_NONE);
+ if (result == KERN_SUCCESS) {
+ switch (message.GetMessageID()) {
+ case kDumpRequestMessage: {
+ ExceptionInfo &info = (ExceptionInfo &)*message.GetData();
+
+ mach_port_t remote_task = message.GetTranslatedPort(0);
+ mach_port_t crashing_thread = message.GetTranslatedPort(1);
+ mach_port_t handler_thread = message.GetTranslatedPort(2);
+ mach_port_t ack_port = message.GetTranslatedPort(3);
+ pid_t remote_pid = -1;
+ pid_for_task(remote_task, &remote_pid);
+ ClientInfo client(remote_pid);
+
+ bool result;
+ std::string dump_path;
+ if (generate_dumps_ && (!filter_ || filter_(filter_context_))) {
+ ScopedTaskSuspend suspend(remote_task);
+
+ MinidumpGenerator generator(remote_task, handler_thread);
+ dump_path = generator.UniqueNameInDirectory(dump_dir_, NULL);
+
+ if (info.exception_type && info.exception_code) {
+ generator.SetExceptionInformation(info.exception_type,
+ info.exception_code,
+ info.exception_subcode,
+ crashing_thread);
+ }
+ result = generator.Write(dump_path.c_str());
+ } else {
+ result = true;
+ }
+
+ if (result && dump_callback_) {
+ dump_callback_(dump_context_, client, dump_path);
+ }
+
+ // TODO(ted): support a way for the client to send additional data,
+ // perhaps with a callback so users of the server can read the data
+ // themselves?
+
+ if (ack_port != MACH_PORT_DEAD && ack_port != MACH_PORT_NULL) {
+ MachPortSender sender(ack_port);
+ MachSendMessage ack_message(kAcknowledgementMessage);
+ const mach_msg_timeout_t kSendTimeoutMs = 2 * 1000;
+
+ sender.SendMessage(ack_message, kSendTimeoutMs);
+ }
+
+ if (exit_callback_) {
+ exit_callback_(exit_context_, client);
+ }
+ break;
+ }
+ case kQuitMessage:
+ return false;
+ }
+ } else { // result != KERN_SUCCESS
+ return false;
+ }
+ return true;
+}
+
+} // namespace google_breakpad