[ios] Bring up first draft system snapshot and iOS data collector.
Gather most of the necessary information for the system snapshot.
Note that:
- The 'capture' portion of this CL will be moved out of the snapshot
interface and into a separate in-process dump to disk location.
- All of the pointer dereferences need to be wrapped in vm_read.
- The read-fast-and-dump logic in thread_snapshot may end up in a
different file completely, but until we pick a
serialization/deserialization method, keep it as-is.
Bug: crashpad:31
Change-Id: Iac82491fdb4a823163f02149f52a1e18e26fa9de
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2090173
Commit-Queue: Justin Cohen <justincohen@chromium.org>
Reviewed-by: Mark Mentovai <mark@chromium.org>
diff --git a/client/BUILD.gn b/client/BUILD.gn
index 476ceb2..dfdb335 100644
--- a/client/BUILD.gn
+++ b/client/BUILD.gn
@@ -44,7 +44,10 @@
}
if (crashpad_is_ios) {
- sources += [ "crashpad_client_ios.cc" ]
+ sources += [
+ "crash_report_database_mac.mm",
+ "crashpad_client_ios.cc",
+ ]
}
if (crashpad_is_linux || crashpad_is_android) {
@@ -95,7 +98,10 @@
# TODO(justincohen): Temporary dependency to bring up the iOS client.
if (crashpad_is_ios) {
- deps += [ "../snapshot" ]
+ deps += [
+ "../minidump",
+ "../snapshot",
+ ]
}
if (crashpad_is_linux || crashpad_is_android) {
diff --git a/client/crashpad_client_ios.cc b/client/crashpad_client_ios.cc
index 8e3fafa..9f63a91 100644
--- a/client/crashpad_client_ios.cc
+++ b/client/crashpad_client_ios.cc
@@ -20,6 +20,7 @@
#include "base/strings/stringprintf.h"
#include "client/client_argv_handling.h"
#include "snapshot/ios/process_snapshot_ios.h"
+#include "util/ios/ios_system_data_collector.h"
#include "util/posix/signals.h"
namespace crashpad {
@@ -43,7 +44,7 @@
void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
// TODO(justincohen): This is incomplete.
ProcessSnapshotIOS process_snapshot;
- process_snapshot.Initialize();
+ process_snapshot.Initialize(system_data);
}
private:
@@ -68,6 +69,9 @@
Signals::OldActions old_actions_ = {};
+ // Collect some system data before the signal handler is triggered.
+ IOSSystemDataCollector system_data;
+
DISALLOW_COPY_AND_ASSIGN(SignalHandler);
};
diff --git a/minidump/minidump_extensions.h b/minidump/minidump_extensions.h
index 9332f96..97276d5 100644
--- a/minidump/minidump_extensions.h
+++ b/minidump/minidump_extensions.h
@@ -242,7 +242,7 @@
kMinidumpOSMacOSX = 0x8101,
//! \brief iOS, Darwin for mobile devices.
- kMinidumpOSiOS = 0x8102,
+ kMinidumpOSIOS = 0x8102,
//! \brief Linux, not including Android.
kMinidumpOSLinux = 0x8201,
@@ -264,7 +264,6 @@
kMinidumpOSUnknown = 0xffffffff,
};
-
//! \brief A list of ::RVA pointers.
struct ALIGNAS(4) PACKED MinidumpRVAList {
//! \brief The number of children present in the #children array.
diff --git a/minidump/minidump_system_info_writer.cc b/minidump/minidump_system_info_writer.cc
index 06aeecd..7b4b49d 100644
--- a/minidump/minidump_system_info_writer.cc
+++ b/minidump/minidump_system_info_writer.cc
@@ -176,6 +176,9 @@
case SystemSnapshot::kOperatingSystemFuchsia:
operating_system = kMinidumpOSFuchsia;
break;
+ case SystemSnapshot::kOperatingSystemIOS:
+ operating_system = kMinidumpOSIOS;
+ break;
default:
NOTREACHED();
operating_system = kMinidumpOSUnknown;
diff --git a/snapshot/BUILD.gn b/snapshot/BUILD.gn
index 0a118d0..8f67a00 100644
--- a/snapshot/BUILD.gn
+++ b/snapshot/BUILD.gn
@@ -119,6 +119,8 @@
"ios/module_snapshot_ios.h",
"ios/process_snapshot_ios.cc",
"ios/process_snapshot_ios.h",
+ "ios/system_snapshot_ios.cc",
+ "ios/system_snapshot_ios.h",
"ios/thread_snapshot_ios.cc",
"ios/thread_snapshot_ios.h",
"mac/cpu_context_mac.cc",
diff --git a/snapshot/ios/process_snapshot_ios.cc b/snapshot/ios/process_snapshot_ios.cc
index 27f9de4..8decea7 100644
--- a/snapshot/ios/process_snapshot_ios.cc
+++ b/snapshot/ios/process_snapshot_ios.cc
@@ -17,15 +17,29 @@
#include <mach-o/loader.h>
#include <mach/mach.h>
-#include <utility>
-
#include "base/logging.h"
#include "base/mac/mach_logging.h"
+#include "base/stl_util.h"
+
+namespace {
+
+void MachTimeValueToTimeval(const time_value& mach, timeval* tv) {
+ tv->tv_sec = mach.seconds;
+ tv->tv_usec = mach.microseconds;
+}
+
+} // namespace
namespace crashpad {
ProcessSnapshotIOS::ProcessSnapshotIOS()
: ProcessSnapshot(),
+ kern_proc_info_(),
+ basic_info_user_time_(),
+ basic_info_system_time_(),
+ thread_times_user_time_(),
+ thread_times_system_time_(),
+ system_(),
threads_(),
modules_(),
report_id_(),
@@ -36,14 +50,50 @@
ProcessSnapshotIOS::~ProcessSnapshotIOS() {}
-bool ProcessSnapshotIOS::Initialize() {
+bool ProcessSnapshotIOS::Initialize(const IOSSystemDataCollector& system_data) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+ // Used by pid, parent pid and snapshot time.
+ int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
+ size_t len = sizeof(kern_proc_info_);
+ if (sysctl(mib, base::size(mib), &kern_proc_info_, &len, nullptr, 0)) {
+ PLOG(ERROR) << "sysctl";
+ return false;
+ }
+
+ // Used by user time and system time.
+ task_basic_info_64 task_basic_info;
+ mach_msg_type_number_t task_basic_info_count = TASK_BASIC_INFO_64_COUNT;
+ kern_return_t kr = task_info(mach_task_self(),
+ TASK_BASIC_INFO_64,
+ reinterpret_cast<task_info_t>(&task_basic_info),
+ &task_basic_info_count);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(WARNING, kr) << "task_info TASK_BASIC_INFO_64";
+ return false;
+ }
+
+ task_thread_times_info_data_t task_thread_times;
+ mach_msg_type_number_t task_thread_times_count = TASK_THREAD_TIMES_INFO_COUNT;
+ kr = task_info(mach_task_self(),
+ TASK_THREAD_TIMES_INFO,
+ reinterpret_cast<task_info_t>(&task_thread_times),
+ &task_thread_times_count);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(WARNING, kr) << "task_info TASK_THREAD_TIMES";
+ }
+
+ basic_info_user_time_ = task_basic_info.user_time;
+ basic_info_system_time_ = task_basic_info.system_time;
+ thread_times_user_time_ = task_thread_times.user_time;
+ thread_times_system_time_ = task_thread_times.system_time;
+
if (gettimeofday(&snapshot_time_, nullptr) != 0) {
PLOG(ERROR) << "gettimeofday";
return false;
}
+ system_.Initialize(system_data);
InitializeThreads();
InitializeModules();
@@ -53,12 +103,12 @@
pid_t ProcessSnapshotIOS::ProcessID() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return getpid();
+ return kern_proc_info_.kp_proc.p_pid;
}
pid_t ProcessSnapshotIOS::ParentProcessID() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return 0;
+ return kern_proc_info_.kp_eproc.e_ppid;
}
void ProcessSnapshotIOS::SnapshotTime(timeval* snapshot_time) const {
@@ -68,11 +118,28 @@
void ProcessSnapshotIOS::ProcessStartTime(timeval* start_time) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ *start_time = kern_proc_info_.kp_proc.p_starttime;
}
void ProcessSnapshotIOS::ProcessCPUTimes(timeval* user_time,
timeval* system_time) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
+ // Calculate user and system time the same way the kernel does for
+ // getrusage(). See 10.15.0 xnu-6153.11.26/bsd/kern/kern_resource.c calcru().
+ timerclear(user_time);
+ timerclear(system_time);
+
+ MachTimeValueToTimeval(basic_info_user_time_, user_time);
+ MachTimeValueToTimeval(basic_info_system_time_, system_time);
+
+ timeval thread_user_time;
+ MachTimeValueToTimeval(thread_times_user_time_, &thread_user_time);
+ timeval thread_system_time;
+ MachTimeValueToTimeval(thread_times_system_time_, &thread_system_time);
+
+ timeradd(user_time, &thread_user_time, user_time);
+ timeradd(system_time, &thread_system_time, system_time);
}
void ProcessSnapshotIOS::ReportID(UUID* report_id) const {
@@ -93,7 +160,7 @@
const SystemSnapshot* ProcessSnapshotIOS::System() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
- return nullptr;
+ return &system_;
}
std::vector<const ThreadSnapshot*> ProcessSnapshotIOS::Threads() const {
diff --git a/snapshot/ios/process_snapshot_ios.h b/snapshot/ios/process_snapshot_ios.h
index 19d43b2..28b6761 100644
--- a/snapshot/ios/process_snapshot_ios.h
+++ b/snapshot/ios/process_snapshot_ios.h
@@ -15,9 +15,12 @@
#ifndef CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_
#define CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_
+#include <sys/sysctl.h>
+
#include <vector>
#include "snapshot/ios/module_snapshot_ios.h"
+#include "snapshot/ios/system_snapshot_ios.h"
#include "snapshot/ios/thread_snapshot_ios.h"
#include "snapshot/process_snapshot.h"
#include "snapshot/thread_snapshot.h"
@@ -34,9 +37,25 @@
//! \brief Initializes the object.
//!
+ //! \param[in] system_data A class containing various system data points.
+ //!
//! \return `true` if the snapshot could be created, `false` otherwise with
//! an appropriate message logged.
- bool Initialize();
+ bool Initialize(const IOSSystemDataCollector& system_data);
+
+ //! \brief Sets the value to be returned by ClientID().
+ //!
+ //! On iOS, the client ID is under the control of the snapshot producer,
+ //! which may call this method to set the client ID. If this is not done,
+ //! ClientID() will return an identifier consisting entirely of zeroes.
+ void SetClientID(const UUID& client_id) { client_id_ = client_id; }
+
+ //! \brief Sets the value to be returned by ReportID().
+ //!
+ //! On iOS, the crash report ID is under the control of the snapshot
+ //! producer, which may call this method to set the report ID. If this is not
+ //! done, ReportID() will return an identifier consisting entirely of zeroes.
+ void SetReportID(const UUID& report_id) { report_id_ = report_id; }
// ProcessSnapshot:
pid_t ProcessID() const override;
@@ -65,6 +84,12 @@
// Initializes threads_ on behalf of Initialize().
void InitializeThreads();
+ kinfo_proc kern_proc_info_;
+ time_value_t basic_info_user_time_;
+ time_value_t basic_info_system_time_;
+ time_value_t thread_times_user_time_;
+ time_value_t thread_times_system_time_;
+ internal::SystemSnapshotIOS system_;
std::vector<std::unique_ptr<internal::ThreadSnapshotIOS>> threads_;
std::vector<std::unique_ptr<internal::ModuleSnapshotIOS>> modules_;
UUID report_id_;
diff --git a/snapshot/ios/system_snapshot_ios.cc b/snapshot/ios/system_snapshot_ios.cc
new file mode 100644
index 0000000..57c686e
--- /dev/null
+++ b/snapshot/ios/system_snapshot_ios.cc
@@ -0,0 +1,224 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/ios/system_snapshot_ios.h"
+
+#include <mach/mach.h>
+#include <stddef.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "snapshot/cpu_context.h"
+#include "snapshot/posix/timezone.h"
+#include "util/mac/mac_util.h"
+#include "util/numeric/in_range_cast.h"
+
+namespace crashpad {
+
+namespace internal {
+
+SystemSnapshotIOS::SystemSnapshotIOS()
+ : SystemSnapshot(),
+ os_version_build_(),
+ machine_description_(),
+ os_version_major_(0),
+ os_version_minor_(0),
+ os_version_bugfix_(0),
+ active_(0),
+ inactive_(0),
+ wired_(0),
+ free_(0),
+ cpu_count_(0),
+ cpu_vendor_(),
+ dst_status_(),
+ standard_offset_seconds_(0),
+ daylight_offset_seconds_(0),
+ standard_name_(),
+ daylight_name_(),
+ initialized_() {}
+
+SystemSnapshotIOS::~SystemSnapshotIOS() {}
+
+void SystemSnapshotIOS::Initialize(const IOSSystemDataCollector& system_data) {
+ INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+
+ system_data.OSVersion(&os_version_major_,
+ &os_version_minor_,
+ &os_version_bugfix_,
+ &os_version_build_);
+ machine_description_ = system_data.MachineDescription();
+ cpu_count_ = system_data.ProcessorCount();
+ cpu_vendor_ = system_data.CPUVendor();
+ if (system_data.HasDaylightSavingTime()) {
+ dst_status_ = system_data.IsDaylightSavingTime()
+ ? SystemSnapshot::kObservingDaylightSavingTime
+ : SystemSnapshot::kObservingStandardTime;
+ } else {
+ dst_status_ = SystemSnapshot::kDoesNotObserveDaylightSavingTime;
+ }
+ standard_offset_seconds_ = system_data.StandardOffsetSeconds();
+ daylight_offset_seconds_ = system_data.DaylightOffsetSeconds();
+ standard_name_ = system_data.StandardName();
+ daylight_name_ = system_data.DaylightName();
+
+ // Currently unused by minidump.
+ vm_size_t page_size;
+ host_page_size(mach_host_self(), &page_size);
+ mach_msg_type_number_t host_size =
+ sizeof(vm_statistics_data_t) / sizeof(integer_t);
+ vm_statistics_data_t vm_stat;
+ kern_return_t kr = host_statistics(mach_host_self(),
+ HOST_VM_INFO,
+ reinterpret_cast<host_info_t>(&vm_stat),
+ &host_size);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(WARNING, kr) << "host_statistics";
+ }
+ active_ = vm_stat.active_count * page_size;
+ inactive_ = vm_stat.inactive_count * page_size;
+ wired_ = vm_stat.wire_count * page_size;
+ free_ = vm_stat.free_count * page_size;
+
+ INITIALIZATION_STATE_SET_VALID(initialized_);
+}
+
+CPUArchitecture SystemSnapshotIOS::GetCPUArchitecture() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+#if defined(ARCH_CPU_X86_64)
+ return kCPUArchitectureX86_64;
+#elif defined(ARCH_CPU_ARM64)
+ return kCPUArchitectureARM64;
+#endif
+}
+
+uint32_t SystemSnapshotIOS::CPURevision() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ // TODO(justincohen): sysctlbyname machdep.cpu.* returns -1 on iOS/ARM64, but
+ // consider recording this for X86_64 only.
+ return 0;
+}
+
+uint8_t SystemSnapshotIOS::CPUCount() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return cpu_count_;
+}
+
+std::string SystemSnapshotIOS::CPUVendor() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return cpu_vendor_;
+}
+
+void SystemSnapshotIOS::CPUFrequency(uint64_t* current_hz,
+ uint64_t* max_hz) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ // TODO(justincohen): sysctlbyname hw.cpufrequency returns -1 on iOS/ARM64,
+ // but consider recording this for X86_64 only.
+ *current_hz = 0;
+ *max_hz = 0;
+}
+
+uint32_t SystemSnapshotIOS::CPUX86Signature() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ // TODO(justincohen): Consider recording this for X86_64 only.
+ return 0;
+}
+
+uint64_t SystemSnapshotIOS::CPUX86Features() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ // TODO(justincohen): Consider recording this for X86_64 only.
+ return 0;
+}
+
+uint64_t SystemSnapshotIOS::CPUX86ExtendedFeatures() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ // TODO(justincohen): Consider recording this for X86_64 only.
+ return 0;
+}
+
+uint32_t SystemSnapshotIOS::CPUX86Leaf7Features() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ // TODO(justincohen): Consider recording this for X86_64 only.
+ return 0;
+}
+
+bool SystemSnapshotIOS::CPUX86SupportsDAZ() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ // TODO(justincohen): Consider recording this for X86_64 only.
+ return false;
+}
+
+SystemSnapshot::OperatingSystem SystemSnapshotIOS::GetOperatingSystem() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return kOperatingSystemIOS;
+}
+
+bool SystemSnapshotIOS::OSServer() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return false;
+}
+
+void SystemSnapshotIOS::OSVersion(int* major,
+ int* minor,
+ int* bugfix,
+ std::string* build) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ *major = os_version_major_;
+ *minor = os_version_minor_;
+ *bugfix = os_version_bugfix_;
+ build->assign(os_version_build_);
+}
+
+std::string SystemSnapshotIOS::OSVersionFull() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return base::StringPrintf("%d.%d.%d %s",
+ os_version_major_,
+ os_version_minor_,
+ os_version_bugfix_,
+ os_version_build_.c_str());
+}
+
+std::string SystemSnapshotIOS::MachineDescription() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ return machine_description_;
+}
+
+bool SystemSnapshotIOS::NXEnabled() const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ // TODO(justincohen): Consider using kern.nx when available (pre-iOS 13,
+ // pre-OS X 10.15). Otherwise the bit is always enabled.
+ return true;
+}
+
+void SystemSnapshotIOS::TimeZone(DaylightSavingTimeStatus* dst_status,
+ int* standard_offset_seconds,
+ int* daylight_offset_seconds,
+ std::string* standard_name,
+ std::string* daylight_name) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+ *dst_status = dst_status_;
+ *standard_offset_seconds = standard_offset_seconds_;
+ *daylight_offset_seconds = daylight_offset_seconds_;
+ standard_name->assign(standard_name_);
+ daylight_name->assign(daylight_name_);
+}
+
+} // namespace internal
+} // namespace crashpad
diff --git a/snapshot/ios/system_snapshot_ios.h b/snapshot/ios/system_snapshot_ios.h
new file mode 100644
index 0000000..a38de4e
--- /dev/null
+++ b/snapshot/ios/system_snapshot_ios.h
@@ -0,0 +1,94 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_SNAPSHOT_IOS_SYSTEM_SNAPSHOT_IOS_H_
+#define CRASHPAD_SNAPSHOT_IOS_SYSTEM_SNAPSHOT_IOS_H_
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "snapshot/system_snapshot.h"
+#include "util/ios/ios_system_data_collector.h"
+#include "util/misc/initialization_state_dcheck.h"
+
+namespace crashpad {
+
+namespace internal {
+
+//! \brief A SystemSnapshot of the running system, when the system runs iOS.
+class SystemSnapshotIOS final : public SystemSnapshot {
+ public:
+ SystemSnapshotIOS();
+ ~SystemSnapshotIOS() override;
+
+ //! \brief Initializes the object.
+ //!
+ //! \param[in] system_data A class containing various system data points.
+ void Initialize(const IOSSystemDataCollector& system_data);
+
+ // SystemSnapshot:
+
+ CPUArchitecture GetCPUArchitecture() const override;
+ uint32_t CPURevision() const override;
+ uint8_t CPUCount() const override;
+ std::string CPUVendor() const override;
+ void CPUFrequency(uint64_t* current_hz, uint64_t* max_hz) const override;
+ uint32_t CPUX86Signature() const override;
+ uint64_t CPUX86Features() const override;
+ uint64_t CPUX86ExtendedFeatures() const override;
+ uint32_t CPUX86Leaf7Features() const override;
+ bool CPUX86SupportsDAZ() const override;
+ OperatingSystem GetOperatingSystem() const override;
+ bool OSServer() const override;
+ void OSVersion(int* major,
+ int* minor,
+ int* bugfix,
+ std::string* build) const override;
+ std::string OSVersionFull() const override;
+ bool NXEnabled() const override;
+ std::string MachineDescription() const override;
+ void TimeZone(DaylightSavingTimeStatus* dst_status,
+ int* standard_offset_seconds,
+ int* daylight_offset_seconds,
+ std::string* standard_name,
+ std::string* daylight_name) const override;
+
+ private:
+ std::string os_version_build_;
+ std::string machine_description_;
+ int os_version_major_;
+ int os_version_minor_;
+ int os_version_bugfix_;
+ uint64_t active_;
+ uint64_t inactive_;
+ uint64_t wired_;
+ uint64_t free_;
+ int cpu_count_;
+ std::string cpu_vendor_;
+ DaylightSavingTimeStatus dst_status_;
+ int standard_offset_seconds_;
+ int daylight_offset_seconds_;
+ std::string standard_name_;
+ std::string daylight_name_;
+ InitializationStateDcheck initialized_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemSnapshotIOS);
+};
+
+} // namespace internal
+} // namespace crashpad
+
+#endif // CRASHPAD_SNAPSHOT_IOS_SYSTEM_SNAPSHOT_IOS_H_
diff --git a/snapshot/system_snapshot.h b/snapshot/system_snapshot.h
index a363c0c..d78cc23 100644
--- a/snapshot/system_snapshot.h
+++ b/snapshot/system_snapshot.h
@@ -50,6 +50,9 @@
//! \brief Fuchsia.
kOperatingSystemFuchsia,
+
+ //! \brief iOS.
+ kOperatingSystemIOS,
};
//! \brief A system’s daylight saving time status.
diff --git a/util/BUILD.gn b/util/BUILD.gn
index bd0d242..ab0fe35 100644
--- a/util/BUILD.gn
+++ b/util/BUILD.gn
@@ -17,6 +17,9 @@
if (crashpad_is_in_chromium) {
import("//build/config/sanitizers/sanitizers.gni")
+
+ # Prevent Chromium source assignment filters from being inherited.
+ set_sources_assignment_filter([])
}
if (crashpad_is_mac) {
@@ -241,6 +244,15 @@
}
}
+ if (crashpad_is_ios) {
+ sources += [
+ "ios/ios_system_data_collector.h",
+ "ios/ios_system_data_collector.mm",
+ "mac/xattr.cc",
+ "mac/xattr.h",
+ ]
+ }
+
if (crashpad_is_mac) {
sources += [
"mac/checked_mach_address_range.h",
@@ -313,7 +325,6 @@
}
if (crashpad_is_linux || crashpad_is_android) {
- set_sources_assignment_filter([])
sources += [
"linux/address_types.h",
"linux/auxiliary_vector.cc",
@@ -661,7 +672,6 @@
}
if (crashpad_is_linux || crashpad_is_android) {
- set_sources_assignment_filter([])
sources += [
"linux/auxiliary_vector_test.cc",
"linux/memory_map_test.cc",
diff --git a/util/ios/ios_system_data_collector.h b/util/ios/ios_system_data_collector.h
new file mode 100644
index 0000000..45837c6
--- /dev/null
+++ b/util/ios/ios_system_data_collector.h
@@ -0,0 +1,81 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_UTIL_IOS_IOS_SYSTEM_DATA_COLLECTOR_H_
+#define CRASHPAD_UTIL_IOS_IOS_SYSTEM_DATA_COLLECTOR_H_
+
+#import <CoreFoundation/CoreFoundation.h>
+
+#include <string>
+
+namespace crashpad {
+
+//! \brief Used to collect system level data before a crash occurs.
+class IOSSystemDataCollector {
+ public:
+ IOSSystemDataCollector();
+ ~IOSSystemDataCollector();
+
+ void OSVersion(int* major, int* minor, int* bugfix, std::string* build) const;
+ std::string MachineDescription() const { return machine_description_; }
+ int ProcessorCount() const { return processor_count_; }
+ std::string CPUVendor() const { return cpu_vendor_; }
+ bool HasDaylightSavingTime() const { return has_next_daylight_saving_time_; }
+ bool IsDaylightSavingTime() const { return is_daylight_saving_time_; }
+ int StandardOffsetSeconds() const { return standard_offset_seconds_; }
+ int DaylightOffsetSeconds() const { return daylight_offset_seconds_; }
+ std::string StandardName() const { return standard_name_; }
+ std::string DaylightName() const { return daylight_name_; }
+
+ // Currently unused by minidump.
+ int Orientation() const { return orientation_; }
+
+ private:
+ // Notification handlers.
+ void InstallHandlers();
+ static void SystemTimeZoneDidChangeNotificationHandler(
+ CFNotificationCenterRef center,
+ void* observer,
+ CFStringRef name,
+ const void* object,
+ CFDictionaryRef userInfo);
+ void SystemTimeZoneDidChangeNotification();
+
+ static void OrientationDidChangeNotificationHandler(
+ CFNotificationCenterRef center,
+ void* observer,
+ CFStringRef name,
+ const void* object,
+ CFDictionaryRef userInfo);
+ void OrientationDidChangeNotification();
+
+ int major_version_;
+ int minor_version_;
+ int patch_version_;
+ std::string build_;
+ std::string machine_description_;
+ int orientation_;
+ int processor_count_;
+ std::string cpu_vendor_;
+ bool has_next_daylight_saving_time_;
+ bool is_daylight_saving_time_;
+ int standard_offset_seconds_;
+ int daylight_offset_seconds_;
+ std::string standard_name_;
+ std::string daylight_name_;
+};
+
+} // namespace crashpad
+
+#endif // CRASHPAD_UTIL_IOS_IOS_SYSTEM_DATA_COLLECTOR_H_
diff --git a/util/ios/ios_system_data_collector.mm b/util/ios/ios_system_data_collector.mm
new file mode 100644
index 0000000..ca6e91b
--- /dev/null
+++ b/util/ios/ios_system_data_collector.mm
@@ -0,0 +1,202 @@
+// Copyright 2020 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/ios/ios_system_data_collector.h"
+
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+
+#import <Foundation/Foundation.h>
+#include <TargetConditionals.h>
+#import <UIKit/UIKit.h>
+
+#include "base/mac/mach_logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "build/build_config.h"
+
+namespace {
+
+std::string ReadStringSysctlByName(const char* name) {
+ size_t buf_len;
+ if (sysctlbyname(name, nullptr, &buf_len, nullptr, 0) != 0) {
+ PLOG(WARNING) << "sysctlbyname (size) " << name;
+ return std::string();
+ }
+
+ if (buf_len == 0) {
+ return std::string();
+ }
+
+ std::string value(buf_len - 1, '\0');
+ if (sysctlbyname(name, &value[0], &buf_len, nullptr, 0) != 0) {
+ PLOG(WARNING) << "sysctlbyname " << name;
+ return std::string();
+ }
+
+ return value;
+}
+
+} // namespace
+
+namespace crashpad {
+
+IOSSystemDataCollector::IOSSystemDataCollector()
+ : major_version_(0),
+ minor_version_(0),
+ patch_version_(0),
+ build_(),
+ machine_description_(),
+ orientation_(0),
+ processor_count_(0),
+ cpu_vendor_(),
+ has_next_daylight_saving_time_(false),
+ is_daylight_saving_time_(false),
+ standard_offset_seconds_(0),
+ daylight_offset_seconds_(0),
+ standard_name_(),
+ daylight_name_() {
+ NSOperatingSystemVersion version =
+ [[NSProcessInfo processInfo] operatingSystemVersion];
+ major_version_ = base::saturated_cast<int>(version.majorVersion);
+ minor_version_ = base::saturated_cast<int>(version.minorVersion);
+ patch_version_ = base::saturated_cast<int>(version.patchVersion);
+ processor_count_ =
+ base::saturated_cast<int>([[NSProcessInfo processInfo] processorCount]);
+ build_ = ReadStringSysctlByName("kern.osversion");
+
+#if defined(ARCH_CPU_X86_64)
+ cpu_vendor_ = ReadStringSysctlByName("machdep.cpu.vendor");
+#endif
+
+#if TARGET_OS_SIMULATOR
+ // TODO(justincohen): Consider adding board and model information to
+ // |machine_description| as well (similar to MacModelAndBoard in
+ // util/mac/mac_util.cc).
+ switch (UI_USER_INTERFACE_IDIOM()) {
+ case UIUserInterfaceIdiomPhone:
+ machine_description_ = "iOS Simulator (iPhone)";
+ break;
+ case UIUserInterfaceIdiomPad:
+ machine_description_ = "iOS Simulator (iPad)";
+ break;
+ default:
+ machine_description_ = "iOS Simulator (Unknown)";
+ break;
+ }
+#elif TARGET_OS_IPHONE
+ utsname uts;
+ if (uname(&uts) == 0) {
+ machine_description_ = uts.machine;
+ }
+#else
+#error "Unexpected target type OS."
+#endif
+
+ InstallHandlers();
+}
+
+IOSSystemDataCollector::~IOSSystemDataCollector() {
+ CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetLocalCenter(),
+ this);
+}
+
+void IOSSystemDataCollector::OSVersion(int* major,
+ int* minor,
+ int* bugfix,
+ std::string* build) const {
+ *major = major_version_;
+ *minor = minor_version_;
+ *bugfix = patch_version_;
+ build->assign(build_);
+}
+
+void IOSSystemDataCollector::InstallHandlers() {
+ // Timezone.
+ CFNotificationCenterAddObserver(
+ CFNotificationCenterGetLocalCenter(),
+ this,
+ IOSSystemDataCollector::SystemTimeZoneDidChangeNotificationHandler,
+ reinterpret_cast<CFStringRef>(NSSystemTimeZoneDidChangeNotification),
+ nullptr,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+ SystemTimeZoneDidChangeNotification();
+
+ // Orientation.
+ CFNotificationCenterAddObserver(
+ CFNotificationCenterGetLocalCenter(),
+ this,
+ IOSSystemDataCollector::OrientationDidChangeNotificationHandler,
+ reinterpret_cast<CFStringRef>(UIDeviceOrientationDidChangeNotification),
+ nullptr,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+ OrientationDidChangeNotification();
+}
+
+// static
+void IOSSystemDataCollector::SystemTimeZoneDidChangeNotificationHandler(
+ CFNotificationCenterRef center,
+ void* observer,
+ CFStringRef name,
+ const void* object,
+ CFDictionaryRef userInfo) {
+ static_cast<IOSSystemDataCollector*>(observer)
+ ->SystemTimeZoneDidChangeNotification();
+}
+
+void IOSSystemDataCollector::SystemTimeZoneDidChangeNotification() {
+ NSTimeZone* time_zone = NSTimeZone.localTimeZone;
+ NSDate* transition =
+ [time_zone nextDaylightSavingTimeTransitionAfterDate:[NSDate date]];
+ if (transition == nil) {
+ has_next_daylight_saving_time_ = false;
+ daylight_name_ = [[time_zone abbreviation] UTF8String];
+ standard_name_ = daylight_name_;
+ } else if (time_zone.isDaylightSavingTime) {
+ has_next_daylight_saving_time_ = true;
+ is_daylight_saving_time_ = true;
+ daylight_offset_seconds_ =
+ base::saturated_cast<int>([time_zone secondsFromGMT]);
+ standard_offset_seconds_ =
+ base::saturated_cast<int>([time_zone secondsFromGMTForDate:transition]);
+ daylight_name_ = [[time_zone abbreviation] UTF8String];
+ standard_name_ = [[time_zone abbreviationForDate:transition] UTF8String];
+ } else {
+ has_next_daylight_saving_time_ = true;
+ is_daylight_saving_time_ = false;
+ standard_name_ = [[time_zone abbreviation] UTF8String];
+ daylight_name_ = [[time_zone abbreviationForDate:transition] UTF8String];
+ standard_offset_seconds_ =
+ base::saturated_cast<int>([time_zone secondsFromGMT]);
+ daylight_offset_seconds_ =
+ base::saturated_cast<int>([time_zone secondsFromGMTForDate:transition]);
+ }
+}
+
+// static
+void IOSSystemDataCollector::OrientationDidChangeNotificationHandler(
+ CFNotificationCenterRef center,
+ void* observer,
+ CFStringRef name,
+ const void* object,
+ CFDictionaryRef userInfo) {
+ static_cast<IOSSystemDataCollector*>(observer)
+ ->OrientationDidChangeNotification();
+}
+
+void IOSSystemDataCollector::OrientationDidChangeNotification() {
+ orientation_ =
+ base::saturated_cast<int>([[UIDevice currentDevice] orientation]);
+}
+
+} // namespace crashpad