summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm')
-rw-r--r--toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm362
1 files changed, 0 insertions, 362 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm b/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm
deleted file mode 100644
index dc6f48086..000000000
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm
+++ /dev/null
@@ -1,362 +0,0 @@
-// 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
-