diff options
| author | Tobias Markmann <tm@ayena.de> | 2018-03-20 13:12:10 (GMT) | 
|---|---|---|
| committer | Tobias Markmann <tm@ayena.de> | 2018-03-20 14:48:04 (GMT) | 
| commit | f2c2c7d035029fb9615b42c18ccea83e8e705b10 (patch) | |
| tree | 2f56fb77de0f366528395f21732d418f016f63b5 /3rdParty/Breakpad/src/client/mac | |
| parent | 44581c5285d13c0ec715b35ddc79177e5ebeef39 (diff) | |
| parent | 5ba3f18ad8efa040d49f36d83ec2e7891a9add9f (diff) | |
| download | swift-swift-5.0alpha2.zip swift-swift-5.0alpha2.tar.bz2  | |
Merge branch 'swift-4.x'swift-5.0alpha2
* swift-4.x: (44 commits)
Test-Information:
Builds on macOS 10.13.3 with clang trunk.
Change-Id: If50381f103b0ad18d038b920d3d43537642141cb
Diffstat (limited to '3rdParty/Breakpad/src/client/mac')
18 files changed, 1672 insertions, 187 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(¶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 + 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 diff --git a/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc b/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc index b50aa03..3492b82 100644 --- a/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc +++ b/3rdParty/Breakpad/src/client/mac/handler/breakpad_nlist_64.cc @@ -202,17 +202,6 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,    if (CFSwapInt32BigToHost(*((uint32_t *)&buf)) == FAT_MAGIC ||        /* The following is the big-endian ppc64 check */        *((unsigned int *)&buf) == FAT_MAGIC) { -    /* Get host info */ -    host_t host = mach_host_self(); -    unsigned i = HOST_BASIC_INFO_COUNT; -    struct host_basic_info hbi; -    kern_return_t kr; -    if ((kr = host_info(host, HOST_BASIC_INFO, -                        (host_info_t)(&hbi), &i)) != KERN_SUCCESS) { -      return -1; -    } -    mach_port_deallocate(mach_task_self(), host); -      /* Read in the fat header */      struct fat_header fh;      if (lseek(fd, 0, SEEK_SET) == -1) { @@ -281,7 +270,7 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,    off_t sa;  /* symbol address */    off_t ss;  /* start of strings */ -  register register_t n; +  register_t n;    if (*((unsigned int *)&buf) == magic) {      if (lseek(fd, arch_offset, SEEK_SET) == -1) {        return -1; @@ -354,14 +343,14 @@ int __breakpad_fdnlist(int fd, nlist_type *list, const char **symbolNames,    // and look for a match    while (n) {      nlist_type space[BUFSIZ/sizeof (nlist_type)]; -    register register_t m = sizeof (space); +    register_t m = sizeof (space);      if (n < m)        m = n;      if (read(fd, (char *)space, m) != m)        break;      n -= m; -    long savpos = lseek(fd, 0, SEEK_CUR); +    off_t savpos = lseek(fd, 0, SEEK_CUR);      if (savpos == -1) {        return -1;      } diff --git a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc index ef5743c..cdba6df 100644 --- a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc +++ b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.cc @@ -41,6 +41,7 @@ extern "C" { // needed to compile on Leopard  #include <mach/task_info.h>  #include <sys/sysctl.h>  #include <TargetConditionals.h> +#include <unistd.h>  #include <algorithm>  #include <string> @@ -261,8 +262,8 @@ bool FindTextSection(DynamicImage& image) {              reinterpret_cast<const mach_segment_command_type *>(cmd);          if (!strcmp(seg->segname, "__TEXT")) { -          image.vmaddr_ = seg->vmaddr; -          image.vmsize_ = seg->vmsize; +          image.vmaddr_ = static_cast<mach_vm_address_t>(seg->vmaddr); +          image.vmsize_ = static_cast<mach_vm_size_t>(seg->vmsize);            image.slide_ = 0;            if (seg->fileoff == 0 && seg->filesize != 0) { @@ -363,7 +364,7 @@ static uint64_t LookupSymbol(const char* symbol_name,    return list.n_value;  } -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6  static bool HasTaskDyldInfo() {    return true;  } @@ -380,13 +381,9 @@ static SInt32 GetOSVersion() {  }  static bool HasTaskDyldInfo() { -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6 -  return true; -#else    return GetOSVersion() >= 0x1060; -#endif  } -#endif  // TARGET_OS_IPHONE +#endif  // TARGET_OS_IPHONE || MAC_OS_X_VERSION_MIN_REQUIRED >= 10_6  uint64_t DynamicImages::GetDyldAllImageInfosPointer() {    if (HasTaskDyldInfo()) { @@ -475,8 +472,6 @@ void ReadImageInfo(DynamicImages& images,                           mach_header_bytes) != KERN_SUCCESS)          continue; -      header = reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]); -        // Read the file name from the task's memory space.        string file_path;        if (info.file_path_) { @@ -492,7 +487,7 @@ void ReadImageInfo(DynamicImages& images,                                     header_size,                                     info.load_address_,                                     file_path, -                                   info.file_mod_date_, +                                   static_cast<uintptr_t>(info.file_mod_date_),                                     images.task_,                                     images.cpu_type_); @@ -568,7 +563,7 @@ cpu_type_t DynamicImages::DetermineTaskCPUType(task_t task) {      cpu_type_t cpu_type;      size_t cpuTypeSize = sizeof(cpu_type); -    sysctl(mib, mibLen, &cpu_type, &cpuTypeSize, 0, 0); +    sysctl(mib, static_cast<u_int>(mibLen), &cpu_type, &cpuTypeSize, 0, 0);      return cpu_type;    } diff --git a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h index d039eda..6514790 100644 --- a/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h +++ b/3rdParty/Breakpad/src/client/mac/handler/dynamic_images.h @@ -285,6 +285,8 @@ class DynamicImages {      return CPU_TYPE_POWERPC64;  #elif defined(__arm__)      return CPU_TYPE_ARM; +#elif defined(__aarch64__) +    return CPU_TYPE_ARM64;  #else  #error "GetNativeCPUType not implemented for this architecture"  #endif diff --git a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc index 4043019..2a19d46 100644 --- a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc +++ b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.cc @@ -27,19 +27,32 @@  // (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 <map>  #include <mach/exc.h>  #include <mach/mig.h>  #include <pthread.h>  #include <signal.h>  #include <TargetConditionals.h> +#include <map> +  #include "client/mac/handler/exception_handler.h"  #include "client/mac/handler/minidump_generator.h"  #include "common/mac/macho_utilities.h"  #include "common/mac/scoped_task_suspend-inl.h"  #include "google_breakpad/common/minidump_exception_mac.h" +#ifndef __EXCEPTIONS +// This file uses C++ try/catch (but shouldn't). Duplicate the macros from +// <c++/4.2.1/exception_defines.h> allowing this file to work properly with +// exceptions disabled even when other C++ libraries are used. #undef the try +// and catch macros first in case libstdc++ is in use and has already provided +// its own definitions. +#undef try +#define try       if (true) +#undef catch +#define catch(X)  if (false) +#endif  // __EXCEPTIONS +  #ifndef USE_PROTECTED_ALLOCATIONS  #if TARGET_OS_IPHONE  #define USE_PROTECTED_ALLOCATIONS 1 @@ -61,8 +74,12 @@ namespace google_breakpad {  static union {  #if USE_PROTECTED_ALLOCATIONS +#if defined PAGE_MAX_SIZE +  char protected_buffer[PAGE_MAX_SIZE] __attribute__((aligned(PAGE_MAX_SIZE))); +#else    char protected_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); -#endif +#endif  // defined PAGE_MAX_SIZE +#endif  // USE_PROTECTED_ALLOCATIONS    google_breakpad::ExceptionHandler *handler;  } gProtectedData; @@ -103,14 +120,13 @@ exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS |  EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT;  #if !TARGET_OS_IPHONE -extern "C" -{ +extern "C" {    // Forward declarations for functions that need "C" style compilation -  boolean_t exc_server(mach_msg_header_t *request, -                       mach_msg_header_t *reply); +  boolean_t exc_server(mach_msg_header_t* request, +                       mach_msg_header_t* reply);    // This symbol must be visible to dlsym() - see -  // http://code.google.com/p/google-breakpad/issues/detail?id=345 for details. +  // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=345 for details.    kern_return_t catch_exception_raise(mach_port_t target_port,                                        mach_port_t failed_thread,                                        mach_port_t task, @@ -129,19 +145,19 @@ kern_return_t ForwardException(mach_port_t task,  #if TARGET_OS_IPHONE  // Implementation is based on the implementation generated by mig. -boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP, -                              mach_msg_header_t *OutHeadP) { -   OutHeadP->msgh_bits = -       MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0); -   OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port; -   /* Minimal size: routine() will update it if different */ -   OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t); -   OutHeadP->msgh_local_port = MACH_PORT_NULL; -   OutHeadP->msgh_id = InHeadP->msgh_id + 100; +boolean_t breakpad_exc_server(mach_msg_header_t* InHeadP, +                              mach_msg_header_t* OutHeadP) { +  OutHeadP->msgh_bits = +      MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0); +  OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port; +  /* Minimal size: routine() will update it if different */ +  OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t); +  OutHeadP->msgh_local_port = MACH_PORT_NULL; +  OutHeadP->msgh_id = InHeadP->msgh_id + 100;    if (InHeadP->msgh_id != 2401) { -    ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record; -    ((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID; +    ((mig_reply_error_t*)OutHeadP)->NDR = NDR_record; +    ((mig_reply_error_t*)OutHeadP)->RetCode = MIG_BAD_ID;      return FALSE;    } @@ -171,8 +187,8 @@ boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,  #pragma pack()  #endif -  Request *In0P = (Request *)InHeadP; -  Reply *OutP = (Reply *)OutHeadP; +  Request* In0P = (Request*)InHeadP; +  Reply* OutP = (Reply*)OutHeadP;    if (In0P->task.name != mach_task_self()) {      return FALSE; @@ -186,8 +202,8 @@ boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,    return TRUE;  }  #else -boolean_t breakpad_exc_server(mach_msg_header_t *request, -                              mach_msg_header_t *reply) { +boolean_t breakpad_exc_server(mach_msg_header_t* request, +                              mach_msg_header_t* reply) {    return exc_server(request, reply);  } @@ -207,9 +223,9 @@ kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,  ExceptionHandler::ExceptionHandler(const string &dump_path,                                     FilterCallback filter,                                     MinidumpCallback callback, -                                   void *callback_context, +                                   void* callback_context,                                     bool install_handler, -                                   const char *port_name) +                                   const char* port_name)      : dump_path_(),        filter_(filter),        callback_(callback), @@ -235,7 +251,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,  // special constructor if we want to bypass minidump writing and  // simply get a callback with the exception information  ExceptionHandler::ExceptionHandler(DirectCallback callback, -                                   void *callback_context, +                                   void* callback_context,                                     bool install_handler)      : dump_path_(),        filter_(NULL), @@ -269,9 +285,13 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {    if (pthread_mutex_lock(&minidump_write_mutex_) == 0) {      // Send an empty message to the handle port so that a minidump will      // be written -    SendMessageToHandlerThread(write_exception_stream ? -                                   kWriteDumpWithExceptionMessage : -                                   kWriteDumpMessage); +    bool result = SendMessageToHandlerThread(write_exception_stream ? +                                               kWriteDumpWithExceptionMessage : +                                               kWriteDumpMessage); +    if (!result) { +      pthread_mutex_unlock(&minidump_write_mutex_); +      return false; +    }      // Wait for the minidump writer to complete its writing.  It will unlock      // the mutex when completed @@ -287,18 +307,18 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {  bool ExceptionHandler::WriteMinidump(const string &dump_path,                                       bool write_exception_stream,                                       MinidumpCallback callback, -                                     void *callback_context) { +                                     void* callback_context) {    ExceptionHandler handler(dump_path, NULL, callback, callback_context, false, -			   NULL); +                           NULL);    return handler.WriteMinidump(write_exception_stream);  }  // static  bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child, -					     mach_port_t child_blamed_thread, -					     const string &dump_path, -					     MinidumpCallback callback, -					     void *callback_context) { +                                             mach_port_t child_blamed_thread, +                                             const string &dump_path, +                                             MinidumpCallback callback, +                                             void* callback_context) {    ScopedTaskSuspend suspend(child);    MinidumpGenerator generator(child, MACH_PORT_NULL); @@ -306,34 +326,41 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,    string dump_filename = generator.UniqueNameInDirectory(dump_path, &dump_id);    generator.SetExceptionInformation(EXC_BREAKPOINT, -#if defined (__i386__) || defined(__x86_64__) -				    EXC_I386_BPT, -#elif defined (__ppc__) || defined (__ppc64__) -				    EXC_PPC_BREAKPOINT, -#elif defined (__arm__) -				    EXC_ARM_BREAKPOINT, +#if defined(__i386__) || defined(__x86_64__) +                                    EXC_I386_BPT, +#elif defined(__ppc__) || defined(__ppc64__) +                                    EXC_PPC_BREAKPOINT, +#elif defined(__arm__) || defined(__aarch64__) +                                    EXC_ARM_BREAKPOINT,  #else  #error architecture not supported  #endif -				    0, -				    child_blamed_thread); +                                    0, +                                    child_blamed_thread);    bool result = generator.Write(dump_filename.c_str());    if (callback) {      return callback(dump_path.c_str(), dump_id.c_str(), -		    callback_context, result); +                    callback_context, result);    }    return result;  } -bool ExceptionHandler::WriteMinidumpWithException(int exception_type, -                                                  int exception_code, -                                                  int exception_subcode, -                                                  mach_port_t thread_name, -                                                  bool exit_after_write, -                                                  bool report_current_thread) { +bool ExceptionHandler::WriteMinidumpWithException( +    int exception_type, +    int exception_code, +    int exception_subcode, +    breakpad_ucontext_t* task_context, +    mach_port_t thread_name, +    bool exit_after_write, +    bool report_current_thread) {    bool result = false; +#if TARGET_OS_IPHONE +  // _exit() should never be called on iOS. +  exit_after_write = false; +#endif +    if (directCallback_) {      if (directCallback_(callback_context_,                          exception_type, @@ -349,12 +376,15 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,        // If this is a real exception, give the filter (if any) a chance to        // decide if this should be sent.        if (filter_ && !filter_(callback_context_)) -	return false; -      return crash_generation_client_->RequestDumpForException( -	         exception_type, -		 exception_code, -		 exception_subcode, -		 thread_name); +        return false; +      result = crash_generation_client_->RequestDumpForException( +          exception_type, +          exception_code, +          exception_subcode, +          thread_name); +      if (result && exit_after_write) { +        _exit(exception_type); +      }      }  #endif    } else { @@ -366,6 +396,7 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,        MinidumpGenerator md(mach_task_self(),                             report_current_thread ? MACH_PORT_NULL :                                                     mach_thread_self()); +      md.SetTaskContext(task_context);        if (exception_type && exception_code) {          // If this is a real exception, give the filter (if any) a chance to          // decide if this should be sent. @@ -432,12 +463,13 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,    exception_behavior_t target_behavior = current.behaviors[found];    kern_return_t result; +  // TODO: Handle the case where |target_behavior| has MACH_EXCEPTION_CODES +  // set. https://bugs.chromium.org/p/google-breakpad/issues/detail?id=551    switch (target_behavior) {      case EXCEPTION_DEFAULT:        result = exception_raise(target_port, failed_thread, task, exception,                                 code, code_count);        break; -      default:        fprintf(stderr, "** Unknown exception behavior: %d\n", target_behavior);        result = KERN_FAILURE; @@ -448,9 +480,9 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,  }  // static -void *ExceptionHandler::WaitForMessage(void *exception_handler_class) { -  ExceptionHandler *self = -    reinterpret_cast<ExceptionHandler *>(exception_handler_class); +void* ExceptionHandler::WaitForMessage(void* exception_handler_class) { +  ExceptionHandler* self = +    reinterpret_cast<ExceptionHandler*>(exception_handler_class);    ExceptionMessage receive;    // Wait for the exception info @@ -495,11 +527,11 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {          if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) {            thread = receive.thread.name;            exception_type = EXC_BREAKPOINT; -#if defined (__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__)            exception_code = EXC_I386_BPT; -#elif defined (__ppc__) || defined (__ppc64__) +#elif defined(__ppc__) || defined(__ppc64__)            exception_code = EXC_PPC_BREAKPOINT; -#elif defined (__arm__) +#elif defined(__arm__) || defined(__aarch64__)            exception_code = EXC_ARM_BREAKPOINT;  #else  #error architecture not supported @@ -509,7 +541,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {          // Write out the dump and save the result for later retrieval          self->last_minidump_write_result_ =            self->WriteMinidumpWithException(exception_type, exception_code, -                                           0, thread, +                                           0, NULL, thread,                                             false, false);  #if USE_PROTECTED_ALLOCATIONS @@ -544,8 +576,8 @@ 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, true, -                                         false); +                                         subcode, NULL, receive.thread.name, +                                         true, false);  #if USE_PROTECTED_ALLOCATIONS          // This may have become protected again within @@ -580,7 +612,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {    return NULL;  } -//static +// static  void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {  #if USE_PROTECTED_ALLOCATIONS    if (gBreakpadAllocator) @@ -590,6 +622,7 @@ void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {        EXC_SOFTWARE,        MD_EXCEPTION_CODE_MAC_ABORT,        0, +      static_cast<breakpad_ucontext_t*>(uc),        mach_thread_self(),        true,        true); @@ -604,7 +637,6 @@ bool ExceptionHandler::InstallHandler() {    if (gProtectedData.handler != NULL) {      return false;    } -#if TARGET_OS_IPHONE    if (!IsOutOfProcess()) {      struct sigaction sa;      memset(&sa, 0, sizeof(sa)); @@ -624,7 +656,6 @@ bool ExceptionHandler::InstallHandler() {      mprotect(gProtectedData.protected_buffer, PAGE_SIZE, PROT_READ);  #endif    } -#endif    try {  #if USE_PROTECTED_ALLOCATIONS @@ -633,7 +664,6 @@ bool ExceptionHandler::InstallHandler() {  #else      previous_ = new ExceptionParameters();  #endif -    }    catch (std::bad_alloc) {      return false; @@ -732,7 +762,7 @@ bool ExceptionHandler::Setup(bool install_handler) {      result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS;    } -  return result == KERN_SUCCESS ? true : false; +  return result == KERN_SUCCESS;  }  bool ExceptionHandler::Teardown() { diff --git a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h index ec09134..f1d9ae9 100644 --- a/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h +++ b/3rdParty/Breakpad/src/client/mac/handler/exception_handler.h @@ -41,7 +41,8 @@  #include <string> -#include "processor/scoped_ptr.h" +#include "client/mac/handler/ucontext_compat.h" +#include "common/scoped_ptr.h"  #if !TARGET_OS_IPHONE  #include "client/mac/crash_generation/crash_generation_client.h" @@ -182,10 +183,13 @@ class ExceptionHandler {    // success, false otherwise.    bool SendMessageToHandlerThread(HandlerThreadMessage message_id); -  // All minidump writing goes through this one routine +  // All minidump writing goes through this one routine. +  // |task_context| can be NULL. If not, it will be used to retrieve the +  // context of the current thread, instead of using |thread_get_state|.    bool WriteMinidumpWithException(int exception_type,                                    int exception_code,                                    int exception_subcode, +                                  breakpad_ucontext_t *task_context,                                    mach_port_t thread_name,                                    bool exit_after_write,                                    bool report_current_thread); diff --git a/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h b/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h index e0459be..9e9028b 100644 --- a/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h +++ b/3rdParty/Breakpad/src/client/mac/handler/mach_vm_compat.h @@ -32,15 +32,14 @@  #include <TargetConditionals.h> -// On iOS 5, mach/mach_vm.h is not supported anymore. As the architecture is 32 -// bits, we can use the simple vm_ functions instead of the mach_vm_ ones. +// On iOS 5 and higher, mach/mach_vm.h is not supported. Use the corresponding +// vm_map functions instead.  #if TARGET_OS_IPHONE  #include <mach/vm_map.h>  #define mach_vm_address_t vm_address_t  #define mach_vm_deallocate vm_deallocate  #define mach_vm_read vm_read -#define mach_vm_region vm_region -#define mach_vm_region_recurse vm_region_recurse +#define mach_vm_region_recurse vm_region_recurse_64  #define mach_vm_size_t vm_size_t  #else  #include <mach/mach_vm.h> diff --git a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc index b1d429c..48cd2e9 100644 --- a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc +++ b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.cc @@ -31,6 +31,7 @@  #include <cstdio>  #include <mach/host_info.h> +#include <mach/machine.h>  #include <mach/vm_statistics.h>  #include <mach-o/dyld.h>  #include <mach-o/loader.h> @@ -41,7 +42,7 @@  #include "client/mac/handler/minidump_generator.h" -#ifdef HAS_ARM_SUPPORT +#if defined(HAS_ARM_SUPPORT) || defined(HAS_ARM64_SUPPORT)  #include <mach/arm/thread_status.h>  #endif  #ifdef HAS_PPC_SUPPORT @@ -61,7 +62,7 @@ using MacStringUtils::IntegerValueAtIndex;  namespace google_breakpad { -#if __LP64__ +#if defined(__LP64__) && __LP64__  #define LC_SEGMENT_ARCH LC_SEGMENT_64  #else  #define LC_SEGMENT_ARCH LC_SEGMENT @@ -77,6 +78,7 @@ MinidumpGenerator::MinidumpGenerator()        crashing_task_(mach_task_self()),        handler_thread_(mach_thread_self()),        cpu_type_(DynamicImages::GetNativeCPUType()), +      task_context_(NULL),        dynamic_images_(NULL),        memory_blocks_(&allocator_) {    GatherSystemInformation(); @@ -94,6 +96,7 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task,        crashing_task_(crashing_task),        handler_thread_(handler_thread),        cpu_type_(DynamicImages::GetNativeCPUType()), +      task_context_(NULL),        dynamic_images_(NULL),        memory_blocks_(&allocator_) {    if (crashing_task != mach_task_self()) { @@ -130,25 +133,47 @@ void MinidumpGenerator::GatherSystemInformation() {                                    vers_path,                                    kCFURLPOSIXPathStyle,                                    false); -  CFDataRef data; -  SInt32 error; -  CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL, -                                           &error); - +  CFReadStreamRef read_stream = CFReadStreamCreateWithFile(NULL, sys_vers); +  CFRelease(sys_vers); +  if (!read_stream) { +    return; +  } +  if (!CFReadStreamOpen(read_stream)) { +    CFRelease(read_stream); +    return; +  } +  CFMutableDataRef data = NULL; +  while (true) { +    // Actual data file tests: Mac at 480 bytes and iOS at 413 bytes. +    const CFIndex kMaxBufferLength = 1024; +    UInt8 data_bytes[kMaxBufferLength]; +    CFIndex num_bytes_read = +      CFReadStreamRead(read_stream, data_bytes, kMaxBufferLength); +    if (num_bytes_read < 0) { +      if (data) { +        CFRelease(data); +        data = NULL; +      } +      break; +    } else if (num_bytes_read == 0) { +      break; +    } else if (!data) { +      data = CFDataCreateMutable(NULL, 0); +    } +    CFDataAppendBytes(data, data_bytes, num_bytes_read); +  } +  CFReadStreamClose(read_stream); +  CFRelease(read_stream);    if (!data) { -    CFRelease(sys_vers);      return;    } - -  CFDictionaryRef list = static_cast<CFDictionaryRef> -    (CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, -                                     NULL)); +  CFDictionaryRef list = +      static_cast<CFDictionaryRef>(CFPropertyListCreateWithData( +          NULL, data, kCFPropertyListImmutable, NULL, NULL)); +  CFRelease(data);    if (!list) { -    CFRelease(sys_vers); -    CFRelease(data);      return;    } -    CFStringRef build_version = static_cast<CFStringRef>      (CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));    CFStringRef product_version = static_cast<CFStringRef> @@ -157,8 +182,6 @@ void MinidumpGenerator::GatherSystemInformation() {    string product_str = ConvertToString(product_version);    CFRelease(list); -  CFRelease(sys_vers); -  CFRelease(data);    strlcpy(build_string_, build_str.c_str(), sizeof(build_string_)); @@ -168,6 +191,10 @@ void MinidumpGenerator::GatherSystemInformation() {    os_build_number_ = IntegerValueAtIndex(product_str, 2);  } +void MinidumpGenerator::SetTaskContext(breakpad_ucontext_t *task_context) { +  task_context_ = task_context; +} +  string MinidumpGenerator::UniqueNameInDirectory(const string &dir,                                                  string *unique_name) {    CFUUIDRef uuid = CFUUIDCreate(NULL); @@ -288,7 +315,7 @@ size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) {        mach_vm_address_t proposed_next_region_base = next_region_base;        mach_vm_size_t next_region_size;        nesting_level = 0; -      mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; +      info_count = VM_REGION_SUBMAP_INFO_COUNT_64;        result = mach_vm_region_recurse(crashing_task_, &next_region_base,                                        &next_region_size, &nesting_level,                                        region_info, &info_count); @@ -362,6 +389,10 @@ bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,      case CPU_TYPE_ARM:        return WriteStackARM(state, stack_location);  #endif +#ifdef HAS_ARM64_SUPPORT +    case CPU_TYPE_ARM64: +      return WriteStackARM64(state, stack_location); +#endif  #ifdef HAS_PPC_SUPPORT      case CPU_TYPE_POWERPC:        return WriteStackPPC(state, stack_location); @@ -386,6 +417,10 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,      case CPU_TYPE_ARM:        return WriteContextARM(state, register_location);  #endif +#ifdef HAS_ARM64_SUPPORT +    case CPU_TYPE_ARM64: +      return WriteContextARM64(state, register_location); +#endif  #ifdef HAS_PPC_SUPPORT      case CPU_TYPE_POWERPC:        return WriteContextPPC(state, register_location); @@ -403,13 +438,17 @@ bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,    }  } -u_int64_t MinidumpGenerator::CurrentPCForStack( +uint64_t MinidumpGenerator::CurrentPCForStack(      breakpad_thread_state_data_t state) {    switch (cpu_type_) {  #ifdef HAS_ARM_SUPPORT      case CPU_TYPE_ARM:        return CurrentPCForStackARM(state);  #endif +#ifdef HAS_ARM64_SUPPORT +    case CPU_TYPE_ARM64: +      return CurrentPCForStackARM64(state); +#endif  #ifdef HAS_PPC_SUPPORT      case CPU_TYPE_POWERPC:        return CurrentPCForStackPPC(state); @@ -423,7 +462,7 @@ u_int64_t MinidumpGenerator::CurrentPCForStack(        return CurrentPCForStackX86_64(state);  #endif      default: -      assert("Unknown CPU type!"); +      assert(0 && "Unknown CPU type!");        return 0;    }  } @@ -437,7 +476,7 @@ bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state,    return WriteStackFromStartAddress(start_addr, stack_location);  } -u_int64_t +uint64_t  MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) {    arm_thread_state_t *machine_state =        reinterpret_cast<arm_thread_state_t *>(state); @@ -479,7 +518,82 @@ bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state,    AddGPR(10);    AddGPR(11);    AddGPR(12); -#undef AddReg +#undef AddGPR + +  return true; +} +#endif + +#ifdef HAS_ARM64_SUPPORT +bool MinidumpGenerator::WriteStackARM64(breakpad_thread_state_data_t state, +                                        MDMemoryDescriptor *stack_location) { +  arm_thread_state64_t *machine_state = +      reinterpret_cast<arm_thread_state64_t *>(state); +  mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp); +  return WriteStackFromStartAddress(start_addr, stack_location); +} + +uint64_t +MinidumpGenerator::CurrentPCForStackARM64(breakpad_thread_state_data_t state) { +  arm_thread_state64_t *machine_state = +      reinterpret_cast<arm_thread_state64_t *>(state); + +  return REGISTER_FROM_THREADSTATE(machine_state, pc); +} + +bool +MinidumpGenerator::WriteContextARM64(breakpad_thread_state_data_t state, +                                     MDLocationDescriptor *register_location) +{ +  TypedMDRVA<MDRawContextARM64> context(&writer_); +  arm_thread_state64_t *machine_state = +      reinterpret_cast<arm_thread_state64_t *>(state); + +  if (!context.Allocate()) +    return false; + +  *register_location = context.location(); +  MDRawContextARM64 *context_ptr = context.get(); +  context_ptr->context_flags = MD_CONTEXT_ARM64_FULL; + +#define AddGPR(a) context_ptr->iregs[a] = \ +    REGISTER_FROM_THREADSTATE(machine_state, x[a]) + +  context_ptr->iregs[29] = REGISTER_FROM_THREADSTATE(machine_state, fp); +  context_ptr->iregs[30] = REGISTER_FROM_THREADSTATE(machine_state, lr); +  context_ptr->iregs[31] = REGISTER_FROM_THREADSTATE(machine_state, sp); +  context_ptr->iregs[32] = REGISTER_FROM_THREADSTATE(machine_state, pc); +  context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr); + +  AddGPR(0); +  AddGPR(1); +  AddGPR(2); +  AddGPR(3); +  AddGPR(4); +  AddGPR(5); +  AddGPR(6); +  AddGPR(7); +  AddGPR(8); +  AddGPR(9); +  AddGPR(10); +  AddGPR(11); +  AddGPR(12); +  AddGPR(13); +  AddGPR(14); +  AddGPR(15); +  AddGPR(16); +  AddGPR(17); +  AddGPR(18); +  AddGPR(19); +  AddGPR(20); +  AddGPR(21); +  AddGPR(22); +  AddGPR(23); +  AddGPR(24); +  AddGPR(25); +  AddGPR(26); +  AddGPR(27); +  AddGPR(28);  #undef AddGPR    return true; @@ -503,7 +617,7 @@ bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state,    return WriteStackFromStartAddress(start_addr, stack_location);  } -u_int64_t +uint64_t  MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {    ppc_thread_state_t *machine_state =        reinterpret_cast<ppc_thread_state_t *>(state); @@ -511,7 +625,7 @@ MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {    return REGISTER_FROM_THREADSTATE(machine_state, srr0);  } -u_int64_t +uint64_t  MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) {    ppc_thread_state64_t *machine_state =        reinterpret_cast<ppc_thread_state64_t *>(state); @@ -533,8 +647,11 @@ bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state,    MDRawContextPPC *context_ptr = context.get();    context_ptr->context_flags = MD_CONTEXT_PPC_BASE; -#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) -#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a) +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ +    REGISTER_FROM_THREADSTATE(machine_state, a)) +#define AddGPR(a) context_ptr->gpr[a] = \ +    static_cast<__typeof__(context_ptr->a)>( \ +    REGISTER_FROM_THREADSTATE(machine_state, r ## a)    AddReg(srr0);    AddReg(cr); @@ -596,8 +713,11 @@ bool MinidumpGenerator::WriteContextPPC64(    MDRawContextPPC64 *context_ptr = context.get();    context_ptr->context_flags = MD_CONTEXT_PPC_BASE; -#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) -#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a) +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ +    REGISTER_FROM_THREADSTATE(machine_state, a)) +#define AddGPR(a) context_ptr->gpr[a] = \ +    static_cast<__typeof__(context_ptr->a)>( \ +    REGISTER_FROM_THREADSTATE(machine_state, r ## a)    AddReg(srr0);    AddReg(cr); @@ -661,11 +781,12 @@ bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state,    x86_thread_state64_t *machine_state =        reinterpret_cast<x86_thread_state64_t *>(state); -  mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, rsp); +  mach_vm_address_t start_addr = static_cast<mach_vm_address_t>( +      REGISTER_FROM_THREADSTATE(machine_state, rsp));    return WriteStackFromStartAddress(start_addr, stack_location);  } -u_int64_t +uint64_t  MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {    i386_thread_state_t *machine_state =        reinterpret_cast<i386_thread_state_t *>(state); @@ -673,7 +794,7 @@ MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {    return REGISTER_FROM_THREADSTATE(machine_state, eip);  } -u_int64_t +uint64_t  MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) {    x86_thread_state64_t *machine_state =        reinterpret_cast<x86_thread_state64_t *>(state); @@ -694,7 +815,8 @@ bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state,    *register_location = context.location();    MDRawContextX86 *context_ptr = context.get(); -#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ +    REGISTER_FROM_THREADSTATE(machine_state, a))    context_ptr->context_flags = MD_CONTEXT_X86;    AddReg(eax); @@ -733,7 +855,8 @@ bool MinidumpGenerator::WriteContextX86_64(    *register_location = context.location();    MDRawContextAMD64 *context_ptr = context.get(); -#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a) +#define AddReg(a) context_ptr->a = static_cast<__typeof__(context_ptr->a)>( \ +    REGISTER_FROM_THREADSTATE(machine_state, a))    context_ptr->context_flags = MD_CONTEXT_AMD64;    AddReg(rax); @@ -757,7 +880,7 @@ bool MinidumpGenerator::WriteContextX86_64(    // not used in the flags register.  Since the minidump format    // specifies 32 bits for the flags register, we can truncate safely    // with no loss. -  context_ptr->eflags = static_cast<u_int32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags)); +  context_ptr->eflags = static_cast<uint32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags));    AddReg(cs);    AddReg(fs);    AddReg(gs); @@ -770,6 +893,40 @@ bool MinidumpGenerator::WriteContextX86_64(  bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,                                         thread_state_t state,                                         mach_msg_type_number_t *count) { +  if (task_context_ && target_thread == mach_thread_self()) { +    switch (cpu_type_) { +#ifdef HAS_ARM_SUPPORT +      case CPU_TYPE_ARM: +        size_t final_size = +            std::min(static_cast<size_t>(*count), sizeof(arm_thread_state_t)); +        memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); +        *count = static_cast<mach_msg_type_number_t>(final_size); +        return true; +#endif +#ifdef HAS_ARM64_SUPPORT +      case CPU_TYPE_ARM64: { +        size_t final_size = +            std::min(static_cast<size_t>(*count), sizeof(arm_thread_state64_t)); +        memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); +        *count = static_cast<mach_msg_type_number_t>(final_size); +        return true; +      } +#endif +#ifdef HAS_X86_SUPPORT +    case CPU_TYPE_I386: +    case CPU_TYPE_X86_64: { +        size_t state_size = cpu_type_ == CPU_TYPE_I386 ? +            sizeof(i386_thread_state_t) : sizeof(x86_thread_state64_t); +        size_t final_size = +            std::min(static_cast<size_t>(*count), state_size); +        memcpy(state, &task_context_->breakpad_uc_mcontext->__ss, final_size); +        *count = static_cast<mach_msg_type_number_t>(final_size); +        return true; +      } +#endif +    } +  } +    thread_state_flavor_t flavor;    switch (cpu_type_) {  #ifdef HAS_ARM_SUPPORT @@ -777,6 +934,11 @@ bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,        flavor = ARM_THREAD_STATE;        break;  #endif +#ifdef HAS_ARM64_SUPPORT +    case CPU_TYPE_ARM64: +      flavor = ARM_THREAD_STATE64; +      break; +#endif  #ifdef HAS_PPC_SUPPORT      case CPU_TYPE_POWERPC:        flavor = PPC_THREAD_STATE; @@ -878,26 +1040,25 @@ bool MinidumpGenerator::WriteMemoryListStream(      mach_msg_type_number_t stateCount        = static_cast<mach_msg_type_number_t>(sizeof(state)); -    if (thread_get_state(exception_thread_, -                         BREAKPAD_MACHINE_THREAD_STATE, -                         state, -                         &stateCount) == KERN_SUCCESS) { -      u_int64_t ip = CurrentPCForStack(state); +    if (GetThreadState(exception_thread_, state, &stateCount)) { +      uint64_t ip = CurrentPCForStack(state);        // Bound it to the upper and lower bounds of the region        // it's contained within. If it's not in a known memory region,        // don't bother trying to write it. -      mach_vm_address_t addr = ip; +      mach_vm_address_t addr = static_cast<vm_address_t>(ip);        mach_vm_size_t size;        natural_t nesting_level = 0;        vm_region_submap_info_64 info;        mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64; +      vm_region_recurse_info_t recurse_info; +      recurse_info = reinterpret_cast<vm_region_recurse_info_t>(&info);        kern_return_t ret =          mach_vm_region_recurse(crashing_task_,                                 &addr,                                 &size,                                 &nesting_level, -                               (vm_region_recurse_info_t)&info, +                               recurse_info,                                 &info_count);        if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) {          // Try to get 128 bytes before and after the IP, but @@ -908,8 +1069,9 @@ bool MinidumpGenerator::WriteMemoryListStream(          uintptr_t end_of_range =             std::min(uintptr_t(ip + (kIPMemorySize / 2)),                     uintptr_t(addr + size)); -        ip_memory_d.memory.data_size = -          end_of_range - ip_memory_d.start_of_memory_range; +        uintptr_t range_diff = end_of_range - +            static_cast<uintptr_t>(ip_memory_d.start_of_memory_range); +        ip_memory_d.memory.data_size = static_cast<uint32_t>(range_diff);          have_ip_memory = true;          // This needs to get appended to the list even though          // the memory bytes aren't filled in yet so the entire @@ -921,7 +1083,7 @@ bool MinidumpGenerator::WriteMemoryListStream(    }    // Now fill in the memory list and write it. -  unsigned memory_count = memory_blocks_.size(); +  size_t memory_count = memory_blocks_.size();    if (!list.AllocateObjectAndArray(memory_count,                                     sizeof(MDMemoryDescriptor)))      return false; @@ -929,7 +1091,7 @@ bool MinidumpGenerator::WriteMemoryListStream(    memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM;    memory_list_stream->location = list.location(); -  list.get()->number_of_memory_ranges = memory_count; +  list.get()->number_of_memory_ranges = static_cast<uint32_t>(memory_count);    unsigned int i;    for (i = 0; i < memory_count; ++i) { @@ -1027,6 +1189,11 @@ bool MinidumpGenerator::WriteSystemInfoStream(        info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM;        break;  #endif +#ifdef HAS_ARM64_SUPPORT +    case CPU_TYPE_ARM64: +      info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM64; +      break; +#endif  #ifdef HAS_PPC_SUPPORT      case CPU_TYPE_POWERPC:      case CPU_TYPE_POWERPC64: @@ -1078,9 +1245,9 @@ bool MinidumpGenerator::WriteSystemInfoStream(        info_ptr->processor_level =          (info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8;        // 0xMMSS (Model, Stepping) -      info_ptr->processor_revision = -        (info_ptr->cpu.x86_cpu_info.version_information & 0xF) | -        ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4); +      info_ptr->processor_revision = static_cast<uint16_t>( +          (info_ptr->cpu.x86_cpu_info.version_information & 0xF) | +          ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4));        // decode extended model info        if (info_ptr->processor_level == 0xF || @@ -1103,7 +1270,7 @@ bool MinidumpGenerator::WriteSystemInfoStream(        break;    } -  info_ptr->number_of_processors = number_of_processors; +  info_ptr->number_of_processors = static_cast<uint8_t>(number_of_processors);  #if TARGET_OS_IPHONE    info_ptr->platform_id = MD_OS_IOS;  #else @@ -1142,13 +1309,13 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,        return false;      module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide(); -    module->size_of_image = static_cast<u_int32_t>(image->GetVMSize()); +    module->size_of_image = static_cast<uint32_t>(image->GetVMSize());      module->module_name_rva = string_location.rva;      // We'll skip the executable module, because they don't have      // LC_ID_DYLIB load commands, and the crash processing server gets      // version information from the Plist file, anyway. -    if (index != (uint32_t)FindExecutableModule()) { +    if (index != static_cast<uint32_t>(FindExecutableModule())) {        module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE;        module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION;        // Convert MAC dylib version format, which is a 32 bit number, to the @@ -1208,7 +1375,7 @@ bool MinidumpGenerator::WriteModuleStream(unsigned int index,              return false;            module->base_of_image = seg->vmaddr + slide; -          module->size_of_image = static_cast<u_int32_t>(seg->vmsize); +          module->size_of_image = static_cast<uint32_t>(seg->vmsize);            module->module_name_rva = string_location.rva;            bool in_memory = false; @@ -1267,7 +1434,7 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,    size_t module_name_length = strlen(module_name); -  if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t))) +  if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(uint8_t)))      return false;    if (!cv.CopyIndexAfterObject(0, module_name, module_name_length)) @@ -1285,22 +1452,27 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,      MacFileUtilities::MachoID macho(module_path,          reinterpret_cast<void *>(module->base_of_image),          static_cast<size_t>(module->size_of_image)); -    result = macho.UUIDCommand(cpu_type, identifier); +    result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);      if (!result) -      result = macho.MD5(cpu_type, identifier); +      result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);    }    if (!result) {       FileID file_id(module_path); -     result = file_id.MachoIdentifier(cpu_type, identifier); +     result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE, +                                      identifier);    }    if (result) { -    cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 | -      (uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 | -      (uint32_t)identifier[3]; -    cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5]; -    cv_ptr->signature.data3 = (uint32_t)identifier[6] << 8 | identifier[7]; +    cv_ptr->signature.data1 = +        static_cast<uint32_t>(identifier[0]) << 24 | +        static_cast<uint32_t>(identifier[1]) << 16 | +        static_cast<uint32_t>(identifier[2]) << 8 | +        static_cast<uint32_t>(identifier[3]); +    cv_ptr->signature.data2 = +        static_cast<uint16_t>(identifier[4] << 8) | identifier[5]; +    cv_ptr->signature.data3 = +        static_cast<uint16_t>(identifier[6] << 8) | identifier[7];      cv_ptr->signature.data4[0] = identifier[8];      cv_ptr->signature.data4[1] = identifier[9];      cv_ptr->signature.data4[2] = identifier[10]; @@ -1318,8 +1490,8 @@ bool MinidumpGenerator::WriteModuleListStream(      MDRawDirectory *module_list_stream) {    TypedMDRVA<MDRawModuleList> list(&writer_); -  size_t image_count = dynamic_images_ ? -      static_cast<size_t>(dynamic_images_->GetImageCount()) : +  uint32_t image_count = dynamic_images_ ? +      dynamic_images_->GetImageCount() :        _dyld_image_count();    if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE)) @@ -1327,22 +1499,22 @@ bool MinidumpGenerator::WriteModuleListStream(    module_list_stream->stream_type = MD_MODULE_LIST_STREAM;    module_list_stream->location = list.location(); -  list.get()->number_of_modules = image_count; +  list.get()->number_of_modules = static_cast<uint32_t>(image_count);    // Write out the executable module as the first one    MDRawModule module; -  size_t executableIndex = FindExecutableModule(); +  uint32_t executableIndex = FindExecutableModule(); -  if (!WriteModuleStream(executableIndex, &module)) { +  if (!WriteModuleStream(static_cast<unsigned>(executableIndex), &module)) {      return false;    }    list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE);    int destinationIndex = 1;  // Write all other modules after this one -  for (size_t i = 0; i < image_count; ++i) { +  for (uint32_t i = 0; i < image_count; ++i) {      if (i != executableIndex) { -      if (!WriteModuleStream(i, &module)) { +      if (!WriteModuleStream(static_cast<unsigned>(i), &module)) {          return false;        } @@ -1363,7 +1535,7 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {    misc_info_stream->location = info.location();    MDRawMiscInfo *info_ptr = info.get(); -  info_ptr->size_of_info = static_cast<u_int32_t>(sizeof(MDRawMiscInfo)); +  info_ptr->size_of_info = static_cast<uint32_t>(sizeof(MDRawMiscInfo));    info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID |      MD_MISCINFO_FLAGS1_PROCESS_TIMES |      MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO; @@ -1376,18 +1548,18 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {    if (getrusage(RUSAGE_SELF, &usage) != -1) {      // Omit the fractional time since the MDRawMiscInfo only wants seconds      info_ptr->process_user_time = -        static_cast<u_int32_t>(usage.ru_utime.tv_sec); +        static_cast<uint32_t>(usage.ru_utime.tv_sec);      info_ptr->process_kernel_time = -        static_cast<u_int32_t>(usage.ru_stime.tv_sec); +        static_cast<uint32_t>(usage.ru_stime.tv_sec);    }    int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,                   static_cast<int>(info_ptr->process_id) }; -  u_int mibsize = static_cast<u_int>(sizeof(mib) / sizeof(mib[0])); +  uint mibsize = static_cast<uint>(sizeof(mib) / sizeof(mib[0]));    struct kinfo_proc proc;    size_t size = sizeof(proc);    if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) {      info_ptr->process_create_time = -        static_cast<u_int32_t>(proc.kp_proc.p_starttime.tv_sec); +        static_cast<uint32_t>(proc.kp_proc.p_starttime.tv_sec);    }    // Speed @@ -1395,11 +1567,11 @@ bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {    const uint64_t kOneMillion = 1000 * 1000;    size = sizeof(speed);    sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0); -  info_ptr->processor_max_mhz = static_cast<u_int32_t>(speed / kOneMillion); -  info_ptr->processor_mhz_limit = static_cast<u_int32_t>(speed / kOneMillion); +  info_ptr->processor_max_mhz = static_cast<uint32_t>(speed / kOneMillion); +  info_ptr->processor_mhz_limit = static_cast<uint32_t>(speed / kOneMillion);    size = sizeof(speed);    sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0); -  info_ptr->processor_current_mhz = static_cast<u_int32_t>(speed / kOneMillion); +  info_ptr->processor_current_mhz = static_cast<uint32_t>(speed / kOneMillion);    return true;  } diff --git a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h index 8394ce6..4e4b4a6 100644 --- a/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h +++ b/3rdParty/Breakpad/src/client/mac/handler/minidump_generator.h @@ -37,6 +37,7 @@  #include <string> +#include "client/mac/handler/ucontext_compat.h"  #include "client/minidump_file_writer.h"  #include "common/memory.h"  #include "common/mac/macho_utilities.h" @@ -49,7 +50,9 @@    #define HAS_PPC_SUPPORT  #endif  #if defined(__arm__) -  #define HAS_ARM_SUPPORT +#define HAS_ARM_SUPPORT +#elif defined(__aarch64__) +#define HAS_ARM64_SUPPORT  #elif defined(__i386__) || defined(__x86_64__)    #define HAS_X86_SUPPORT  #endif @@ -102,6 +105,11 @@ class MinidumpGenerator {      exception_thread_ = thread_name;    } +  // Specify the task context. If |task_context| is not NULL, it will be used +  // to retrieve the context of the current thread, instead of using +  // |thread_get_state|. +  void SetTaskContext(breakpad_ucontext_t *task_context); +    // Gather system information.  This should be call at least once before using    // the MinidumpGenerator class.    static void GatherSystemInformation(); @@ -125,7 +133,7 @@ class MinidumpGenerator {    bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream);    // Helpers -  u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state); +  uint64_t CurrentPCForStack(breakpad_thread_state_data_t state);    bool GetThreadState(thread_act_t target_thread, thread_state_t state,                        mach_msg_type_number_t *count);    bool WriteStackFromStartAddress(mach_vm_address_t start_addr, @@ -146,31 +154,38 @@ class MinidumpGenerator {                       MDMemoryDescriptor *stack_location);    bool WriteContextARM(breakpad_thread_state_data_t state,                         MDLocationDescriptor *register_location); -  u_int64_t CurrentPCForStackARM(breakpad_thread_state_data_t state); +  uint64_t CurrentPCForStackARM(breakpad_thread_state_data_t state); +#endif +#ifdef HAS_ARM64_SUPPORT +  bool WriteStackARM64(breakpad_thread_state_data_t state, +                       MDMemoryDescriptor *stack_location); +  bool WriteContextARM64(breakpad_thread_state_data_t state, +                         MDLocationDescriptor *register_location); +  uint64_t CurrentPCForStackARM64(breakpad_thread_state_data_t state);  #endif  #ifdef HAS_PPC_SUPPORT    bool WriteStackPPC(breakpad_thread_state_data_t state,                       MDMemoryDescriptor *stack_location);    bool WriteContextPPC(breakpad_thread_state_data_t state,                         MDLocationDescriptor *register_location); -  u_int64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state); +  uint64_t CurrentPCForStackPPC(breakpad_thread_state_data_t state);    bool WriteStackPPC64(breakpad_thread_state_data_t state,                         MDMemoryDescriptor *stack_location);    bool WriteContextPPC64(breakpad_thread_state_data_t state,                         MDLocationDescriptor *register_location); -  u_int64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state); +  uint64_t CurrentPCForStackPPC64(breakpad_thread_state_data_t state);  #endif  #ifdef HAS_X86_SUPPORT    bool WriteStackX86(breakpad_thread_state_data_t state,                         MDMemoryDescriptor *stack_location);    bool WriteContextX86(breakpad_thread_state_data_t state,                         MDLocationDescriptor *register_location); -  u_int64_t CurrentPCForStackX86(breakpad_thread_state_data_t state); +  uint64_t CurrentPCForStackX86(breakpad_thread_state_data_t state);    bool WriteStackX86_64(breakpad_thread_state_data_t state,                          MDMemoryDescriptor *stack_location);    bool WriteContextX86_64(breakpad_thread_state_data_t state,                            MDLocationDescriptor *register_location); -  u_int64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state); +  uint64_t CurrentPCForStackX86_64(breakpad_thread_state_data_t state);  #endif    // disallow copy ctor and operator= @@ -192,13 +207,16 @@ class MinidumpGenerator {    // CPU type of the task being dumped.    cpu_type_t cpu_type_; -   +    // System information    static char build_string_[16];    static int os_major_version_;    static int os_minor_version_;    static int os_build_number_; -   + +  // Context of the task to dump. +  breakpad_ucontext_t *task_context_; +    // Information about dynamically loaded code    DynamicImages *dynamic_images_; diff --git a/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc new file mode 100644 index 0000000..6142ad1 --- /dev/null +++ b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.cc @@ -0,0 +1,92 @@ +// Copyright (c) 2006, 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. +// +// ProtectedMemoryAllocator +// +// See the header file for documentation + +#include "protected_memory_allocator.h" +#include <assert.h> + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ProtectedMemoryAllocator::ProtectedMemoryAllocator(vm_size_t pool_size)  +  : pool_size_(pool_size), +    next_alloc_offset_(0), +    valid_(false) { +   +  kern_return_t result = vm_allocate(mach_task_self(), +                                     &base_address_, +                                     pool_size, +                                     TRUE +                                     ); +   +  valid_ = (result == KERN_SUCCESS); +  assert(valid_); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +ProtectedMemoryAllocator::~ProtectedMemoryAllocator() { +  vm_deallocate(mach_task_self(), +                base_address_, +                pool_size_ +                ); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +char *ProtectedMemoryAllocator::Allocate(vm_size_t bytes) { +  if (valid_ && next_alloc_offset_ + bytes <= pool_size_) { +    char *p = (char*)base_address_ + next_alloc_offset_; +    next_alloc_offset_ += bytes; +    return p; +  } +   +  return NULL;  // ran out of memory in our allocation block +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +kern_return_t  ProtectedMemoryAllocator::Protect() { +  kern_return_t result = vm_protect(mach_task_self(), +                                    base_address_, +                                    pool_size_, +                                    FALSE, +                                    VM_PROT_READ); +   +  return result; +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +kern_return_t  ProtectedMemoryAllocator::Unprotect() { +  kern_return_t result = vm_protect(mach_task_self(), +                                    base_address_, +                                    pool_size_, +                                    FALSE, +                                    VM_PROT_READ | VM_PROT_WRITE); +   +  return result; +} diff --git a/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h new file mode 100644 index 0000000..7e188db --- /dev/null +++ b/3rdParty/Breakpad/src/client/mac/handler/protected_memory_allocator.h @@ -0,0 +1,85 @@ +// Copyright (c) 2006, 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. +// +// ProtectedMemoryAllocator +// +// A very simple allocator class which allows allocation, but not deallocation. +// The allocations can be made read-only with the Protect() method. +// This class is NOT useful as a general-purpose memory allocation system, +// since it does not allow deallocation.  It is useful to use for a group +// of allocations which are created in the same time-frame and destroyed +// in the same time-frame.  It is useful for making allocations of memory +// which will not need to change often once initialized.  This memory can then +// be protected from memory smashers by calling the Protect() method. + +#ifndef PROTECTED_MEMORY_ALLOCATOR_H__ +#define PROTECTED_MEMORY_ALLOCATOR_H__ + +#include <mach/mach.h> + +// +class ProtectedMemoryAllocator { + public: +  ProtectedMemoryAllocator(vm_size_t pool_size);   +  ~ProtectedMemoryAllocator(); +   +  // Returns a pointer to an allocation of size n within the pool. +  // Fails by returning NULL is no more space is available. +  // Please note that the pointers returned from this method should not +  // be freed in any way (for example by calling free() on them ). +  char *         Allocate(vm_size_t n); +   +  // Returns the base address of the allocation pool. +  char *         GetBaseAddress() { return (char*)base_address_; } + +  // Returns the size of the allocation pool, including allocated +  // plus free space. +  vm_size_t      GetTotalSize() { return pool_size_; } + +  // Returns the number of bytes already allocated in the pool. +  vm_size_t      GetAllocatedSize() { return next_alloc_offset_; } + +  // Returns the number of bytes available for allocation. +  vm_size_t      GetFreeSize() { return pool_size_ - next_alloc_offset_; } +   +  // Makes the entire allocation pool read-only including, of course, +  // all allocations made from the pool. +  kern_return_t  Protect();   + +  // Makes the entire allocation pool read/write. +  kern_return_t  Unprotect();   +   + private: +  vm_size_t      pool_size_; +  vm_address_t   base_address_; +  vm_size_t      next_alloc_offset_; +  bool           valid_; +}; + +#endif // PROTECTED_MEMORY_ALLOCATOR_H__ diff --git a/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h b/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h new file mode 100644 index 0000000..1e4b752 --- /dev/null +++ b/3rdParty/Breakpad/src/client/mac/handler/ucontext_compat.h @@ -0,0 +1,47 @@ +// Copyright 2013 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_HANDLER_UCONTEXT_COMPAT_H_ +#define CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_ + +#include <sys/ucontext.h> + +// The purpose of this file is to work around the fact that ucontext_t's +// uc_mcontext member is an mcontext_t rather than an mcontext64_t on ARM64. +#if defined(__aarch64__) +// <sys/ucontext.h> doesn't include the below file. +#include <sys/_types/_ucontext64.h> +typedef ucontext64_t breakpad_ucontext_t; +#define breakpad_uc_mcontext uc_mcontext64 +#else +typedef ucontext_t breakpad_ucontext_t; +#define breakpad_uc_mcontext uc_mcontext +#endif  // defined(__aarch64__) + +#endif  // CLIENT_MAC_HANDLER_UCONTEXT_COMPAT_H_  | 
 Swift