diff options
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.mm | 362 |
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(¶meter_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 - |