Commit 94a3832f authored by Joshua Peraza's avatar Joshua Peraza Committed by Commit Bot

Update Crashpad to 1d75af9bf5918fa1c365a4ac696f038e6028a30b

7500e2ef452a linux: add fallback-modes for memfd_create
e1b3bd11cd08 Add support for Hygon Dhyana CPU
42da41d24a21 Targets iPhone 8 when running tests
209124197145 Roll crashpad/third_party/mini_chromium/mini_chromium/
             f8f1182ad..c426ff98e (3 commits)
b109e4ce3897 [ios] Bring up first draft process and module snapshot
1d75af9bf591 Fix bad iOS module casting

Change-Id: I1f447aeefeb1769bb9d56bcc7339b3e5794544af
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2099300
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
Auto-Submit: Joshua Peraza <jperaza@chromium.org>
Reviewed-by: default avatarMark Mentovai <mark@chromium.org>
Cr-Commit-Position: refs/heads/master@{#749451}
parent c6b1ae00
......@@ -2,7 +2,7 @@ Name: Crashpad
Short Name: crashpad
URL: https://crashpad.chromium.org/
Version: unknown
Revision: 3c573b54ae138c81c0224f22b38f5d439b56f9a1
Revision: 1d75af9bf5918fa1c365a4ac696f038e6028a30b
License: Apache 2.0
License File: crashpad/LICENSE
Security Critical: yes
......
......@@ -36,12 +36,12 @@ config("disable_ubsan") {
if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
test("crashpad_tests") {
deps = [
"client:client_test",
"test:gmock_main",
"test:test_test",
]
if (!crashpad_is_ios) {
deps += [
"client:client_test",
"handler:handler_test",
"minidump:minidump_test",
"snapshot:snapshot_test",
......@@ -138,9 +138,7 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
}
package("crashpad_database_util") {
deps = [
"tools:crashpad_database_util",
]
deps = [ "tools:crashpad_database_util" ]
binaries = [
{
......@@ -156,9 +154,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
"client:client_test",
"test:gmock_main",
]
if (crashpad_is_ios) {
deps -= [ "client:client_test" ]
}
}
test("crashpad_handler_test") {
......@@ -212,8 +207,6 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) {
if (crashpad_is_ios) {
group("ios_xcuitests") {
testonly = true
deps = [
"test/ios:all_tests",
]
deps = [ "test/ios:all_tests" ]
}
}
......@@ -42,7 +42,7 @@ deps = {
'7bde79cc274d06451bf65ae82c012a5d3e476b5a',
'crashpad/third_party/mini_chromium/mini_chromium':
Var('chromium_git') + '/chromium/mini_chromium@' +
'f8f1182adb804675b2aa4fb3ce03f6f884fae474',
'c426ff98e1d9e9d59777fe8b883a5c0ceeca9ca3',
'crashpad/third_party/libfuzzer/src':
Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' +
'fda403cf93ecb8792cb1d061564d89a6553ca020',
......
......@@ -437,7 +437,7 @@ def _RunOnFuchsiaTarget(binary_dir, test, device_name, extra_command_line):
def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False):
"""Runs the given iOS |test| app on iPhone X with the default OS version."""
"""Runs the given iOS |test| app on iPhone 8 with the default OS version."""
def xctest(binary_dir, test):
"""Returns a dict containing the xctestrun data needed to run an
......@@ -496,7 +496,7 @@ def _RunOnIOSTarget(binary_dir, test, is_xcuitest=False):
subprocess.check_call(['xcodebuild', 'test-without-building',
'-xctestrun', xctestrun_path, '-destination',
'platform=iOS Simulator,name=iPhone X'])
'platform=iOS Simulator,name=iPhone 8'])
# This script is primarily used from the waterfall so that the list of tests
# that are run is maintained in-tree, rather than in a separate infrastructure
......
......@@ -93,6 +93,11 @@ static_library("client") {
cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union
}
# TODO(justincohen): Temporary dependency to bring up the iOS client.
if (crashpad_is_ios) {
deps += [ "../snapshot" ]
}
if (crashpad_is_linux || crashpad_is_android) {
deps += [ "../third_party/lss" ]
}
......@@ -126,6 +131,17 @@ source_set("client_test") {
sources += [ "crashpad_client_win_test.cc" ]
}
if (crashpad_is_ios) {
sources += [ "crashpad_client_ios_test.cc" ]
sources -= [
"annotation_list_test.cc",
"annotation_test.cc",
"crash_report_database_test.cc",
"prune_crash_reports_test.cc",
"settings_test.cc",
]
}
if (crashpad_is_linux || crashpad_is_android) {
sources += [ "crashpad_client_linux_test.cc" ]
}
......
......@@ -436,6 +436,13 @@ class CrashpadClient {
//! TODO(justincohen): This method will need to take database, metrics_dir,
//! url and annotations eventually.
bool StartCrashpadInProcessHandler();
// TODO(justincohen): This method is purely for bringing up iOS interfaces.
//! \brief Requests that the handler capture a dump even though there hasn't
//! been a crash.
//!
//! A handler must have already been installed before calling this method.
static void DumpWithoutCrash();
#endif
#if defined(OS_MACOSX) || DOXYGEN
......
......@@ -19,6 +19,7 @@
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "client/client_argv_handling.h"
#include "snapshot/ios/process_snapshot_ios.h"
#include "util/posix/signals.h"
namespace crashpad {
......@@ -39,13 +40,21 @@ class SignalHandler {
HandleSignal, 0, &old_actions_, unhandled_signals);
}
void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
// TODO(justincohen): This is incomplete.
ProcessSnapshotIOS process_snapshot;
process_snapshot.Initialize();
}
private:
SignalHandler() = default;
// The base implementation for all signal handlers, suitable for calling
// directly to simulate signal delivery.
void HandleCrash(int signo, siginfo_t* siginfo, void* context) {
// Do Something.
void HandleCrashAndReraiseSignal(int signo,
siginfo_t* siginfo,
void* context) {
HandleCrash(signo, siginfo, context);
// Always call system handler.
Signals::RestoreHandlerAndReraiseSignalOnReturn(
......@@ -54,7 +63,7 @@ class SignalHandler {
// The signal handler installed at OS-level.
static void HandleSignal(int signo, siginfo_t* siginfo, void* context) {
Get()->HandleCrash(signo, siginfo, context);
Get()->HandleCrashAndReraiseSignal(signo, siginfo, context);
}
Signals::OldActions old_actions_ = {};
......@@ -72,4 +81,11 @@ bool CrashpadClient::StartCrashpadInProcessHandler() {
return SignalHandler::Get()->Install(nullptr);
}
// static
void CrashpadClient::DumpWithoutCrash() {
DCHECK(SignalHandler::Get());
siginfo_t siginfo = {};
SignalHandler::Get()->HandleCrash(siginfo.si_signo, &siginfo, nullptr);
}
} // namespace crashpad
// 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 "client/crashpad_client.h"
#include "gtest/gtest.h"
namespace crashpad {
namespace test {
namespace {
// TODO(justincohen): This is a placeholder.
TEST(CrashpadIOSClient, DumpWithoutCrash) {
crashpad::CrashpadClient client;
client.StartCrashpadInProcessHandler();
client.DumpWithoutCrash();
}
} // namespace
} // namespace test
} // namespace crashpad
......@@ -214,7 +214,7 @@ union __attribute__((packed, aligned(4))) CPU_INFORMATION {
//! `cpuid 0x80000001` `edx`.
//!
//! This field is only valid if #VendorId identifies the CPU vendor as
//! “AuthenticAMD”.
//! “AuthenticAMD” or "HygonGenuine".
uint32_t AMDExtendedCpuFeatures;
} X86CpuInfo;
......
......@@ -225,7 +225,7 @@ bool CrosCrashReportExceptionHandler::HandleExceptionWithConnection(
AddUserExtensionStreams(user_stream_data_sources_, snapshot, &minidump);
FileWriter file_writer;
if (!file_writer.OpenMemfd(base::FilePath("/tmp/minidump"))) {
if (!file_writer.OpenMemfd(base::FilePath("minidump"))) {
Metrics::ExceptionCaptureResult(Metrics::CaptureResult::kOpenMemfdFailed);
return false;
}
......
......@@ -151,7 +151,7 @@ void MinidumpSystemInfoWriter::InitializeFromSnapshot(
SetCPUX86VersionAndFeatures(system_snapshot->CPUX86Signature(),
system_snapshot->CPUX86Features() & 0xffffffff);
if (cpu_vendor == "AuthenticAMD") {
if (cpu_vendor == "AuthenticAMD" || cpu_vendor == "HygonGenuine") {
SetCPUX86AMDExtendedFeatures(
system_snapshot->CPUX86ExtendedFeatures() & 0xffffffff);
}
......
......@@ -108,6 +108,15 @@ static_library("snapshot") {
]
}
if (crashpad_is_ios) {
sources += [
"ios/module_snapshot_ios.cc",
"ios/module_snapshot_ios.h",
"ios/process_snapshot_ios.cc",
"ios/process_snapshot_ios.h",
]
}
if (crashpad_is_linux || crashpad_is_android) {
set_sources_assignment_filter([])
sources += [
......@@ -230,6 +239,10 @@ static_library("snapshot") {
"../util",
]
if (crashpad_is_ios) {
deps -= [ "../client" ]
}
if (crashpad_is_win) {
cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union
libs = [ "powrprof.lib" ]
......
// 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/module_snapshot_ios.h"
#include <mach-o/loader.h>
#include <mach/mach.h>
#include "base/files/file_path.h"
#include "base/mac/mach_logging.h"
#include "util/misc/from_pointer_cast.h"
#include "util/misc/uuid.h"
namespace crashpad {
namespace internal {
ModuleSnapshotIOS::ModuleSnapshotIOS()
: ModuleSnapshot(),
name_(),
address_(0),
size_(0),
timestamp_(0),
dylib_version_(0),
source_version_(0),
filetype_(0),
initialized_() {}
ModuleSnapshotIOS::~ModuleSnapshotIOS() {}
// static.
const dyld_all_image_infos* ModuleSnapshotIOS::DyldAllImageInfo() {
task_dyld_info_data_t dyld_info;
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
kern_return_t kr = task_info(mach_task_self(),
TASK_DYLD_INFO,
reinterpret_cast<task_info_t>(&dyld_info),
&count);
if (kr != KERN_SUCCESS) {
MACH_LOG(WARNING, kr) << "task_info";
return 0;
}
return reinterpret_cast<dyld_all_image_infos*>(dyld_info.all_image_info_addr);
}
bool ModuleSnapshotIOS::InitializeDyld(const dyld_all_image_infos* images) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
name_ = images->dyldPath;
address_ = FromPointerCast<uint64_t>(images->dyldImageLoadAddress);
return FinishInitialization();
}
bool ModuleSnapshotIOS::Initialize(const dyld_image_info* image) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
name_ = image->imageFilePath;
address_ = FromPointerCast<uint64_t>(image->imageLoadAddress);
timestamp_ = image->imageFileModDate;
return FinishInitialization();
}
bool ModuleSnapshotIOS::FinishInitialization() {
#ifndef ARCH_CPU_64_BITS
#error Only 64-bit Mach-O is supported
#endif
DCHECK(address_);
const mach_header_64* header =
reinterpret_cast<const mach_header_64*>(address_);
const load_command* command =
reinterpret_cast<const load_command*>(header + 1);
// Make sure that the basic load command structure doesn’t overflow the
// space allotted for load commands, as well as iterating through ncmds.
for (uint32_t cmd_index = 0, cumulative_cmd_size = 0;
cmd_index <= header->ncmds && cumulative_cmd_size < header->sizeofcmds;
++cmd_index, cumulative_cmd_size += command->cmdsize) {
if (command->cmd == LC_SEGMENT_64) {
const segment_command_64* segment =
reinterpret_cast<const segment_command_64*>(command);
if (strcmp(segment->segname, SEG_TEXT) == 0) {
size_ = segment->vmsize;
}
} else if (command->cmd == LC_ID_DYLIB) {
const dylib_command* dylib =
reinterpret_cast<const dylib_command*>(command);
dylib_version_ = dylib->dylib.current_version;
} else if (command->cmd == LC_SOURCE_VERSION) {
const source_version_command* source_version =
reinterpret_cast<const source_version_command*>(command);
source_version_ = source_version->version;
} else if (command->cmd == LC_UUID) {
const uuid_command* uuid = reinterpret_cast<const uuid_command*>(command);
uuid_.InitializeFromBytes(uuid->uuid);
}
command = reinterpret_cast<const load_command*>(
reinterpret_cast<const uint8_t*>(command) + command->cmdsize);
// TODO(justincohen): Warn-able things:
// - Bad Mach-O magic (and give up trying to process the module)
// - Unrecognized Mach-O type
// - No SEG_TEXT
// - More than one SEG_TEXT
// - More than one LC_ID_DYLIB, LC_SOURCE_VERSION, or LC_UUID
// - No LC_ID_DYLIB in a dylib file
// - LC_ID_DYLIB in a non-dylib file
// And more optional:
// - Missing LC_UUID (although it leaves us with a big "?")
// - Missing LC_SOURCE_VERSION.
}
filetype_ = header->filetype;
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
std::string ModuleSnapshotIOS::Name() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return name_;
}
uint64_t ModuleSnapshotIOS::Address() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return address_;
}
uint64_t ModuleSnapshotIOS::Size() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return size_;
}
time_t ModuleSnapshotIOS::Timestamp() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return timestamp_;
}
void ModuleSnapshotIOS::FileVersion(uint16_t* version_0,
uint16_t* version_1,
uint16_t* version_2,
uint16_t* version_3) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
if (filetype_ == MH_DYLIB) {
*version_0 = (dylib_version_ & 0xffff0000) >> 16;
*version_1 = (dylib_version_ & 0x0000ff00) >> 8;
*version_2 = (dylib_version_ & 0x000000ff);
*version_3 = 0;
} else {
*version_0 = 0;
*version_1 = 0;
*version_2 = 0;
*version_3 = 0;
}
}
void ModuleSnapshotIOS::SourceVersion(uint16_t* version_0,
uint16_t* version_1,
uint16_t* version_2,
uint16_t* version_3) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
*version_0 = (source_version_ & 0xffff000000000000u) >> 48;
*version_1 = (source_version_ & 0x0000ffff00000000u) >> 32;
*version_2 = (source_version_ & 0x00000000ffff0000u) >> 16;
*version_3 = source_version_ & 0x000000000000ffffu;
}
ModuleSnapshot::ModuleType ModuleSnapshotIOS::GetModuleType() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
switch (filetype_) {
case MH_EXECUTE:
return kModuleTypeExecutable;
case MH_DYLIB:
return kModuleTypeSharedLibrary;
case MH_DYLINKER:
return kModuleTypeDynamicLoader;
case MH_BUNDLE:
return kModuleTypeLoadableModule;
default:
return kModuleTypeUnknown;
}
}
void ModuleSnapshotIOS::UUIDAndAge(crashpad::UUID* uuid, uint32_t* age) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
*uuid = uuid_;
*age = 0;
}
std::string ModuleSnapshotIOS::DebugFileName() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return base::FilePath(Name()).BaseName().value();
}
std::vector<uint8_t> ModuleSnapshotIOS::BuildID() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<uint8_t>();
}
std::vector<std::string> ModuleSnapshotIOS::AnnotationsVector() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<std::string>();
}
std::map<std::string, std::string> ModuleSnapshotIOS::AnnotationsSimpleMap()
const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::map<std::string, std::string>();
}
std::vector<AnnotationSnapshot> ModuleSnapshotIOS::AnnotationObjects() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<AnnotationSnapshot>();
}
std::set<CheckedRange<uint64_t>> ModuleSnapshotIOS::ExtraMemoryRanges() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::set<CheckedRange<uint64_t>>();
}
std::vector<const UserMinidumpStream*>
ModuleSnapshotIOS::CustomMinidumpStreams() const {
return std::vector<const UserMinidumpStream*>();
}
} // namespace internal
} // namespace crashpad
// 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_MODULE_SNAPSHOT_IOS_H_
#define CRASHPAD_SNAPSHOT_IOS_MODULE_SNAPSHOT_IOS_H_
#include <mach-o/dyld_images.h>
#include <stdint.h>
#include <sys/types.h>
#include <map>
#include <string>
#include <vector>
#include "base/macros.h"
#include "client/crashpad_info.h"
#include "snapshot/crashpad_info_client_options.h"
#include "snapshot/module_snapshot.h"
#include "util/misc/initialization_state_dcheck.h"
namespace crashpad {
namespace internal {
//! \brief A ModuleSnapshot of a code module (binary image) loaded into a
//! running (or crashed) process on an iOS system.
class ModuleSnapshotIOS final : public ModuleSnapshot {
public:
ModuleSnapshotIOS();
~ModuleSnapshotIOS() override;
// TODO(justincohen): This function is temporary, and will be broken into two
// parts. One to do an in-process dump of all the relevant information, and
// two to initialize the snapshot after the in-process dump is loaded.
//! \brief Initializes the object.
//!
//! \param[in] image The mach-o image to be loaded.
//!
//! \return `true` if the snapshot could be created.
bool Initialize(const dyld_image_info* image);
// TODO(justincohen): This function is temporary, and will be broken into two
// parts. One to do an in-process dump of all the relevant information, and
// two to initialize the snapshot after the in-process dump is loaded.
//! \brief Initializes the object specifically for the dyld module.
//!
//! \param[in] images The structure containing the necessary dyld information.
//!
//! \return `true` if the snapshot could be created.
bool InitializeDyld(const dyld_all_image_infos* images);
//! \brief Returns options from the module’s CrashpadInfo structure.
//!
//! \param[out] options Options set in the module’s CrashpadInfo structure.
void GetCrashpadOptions(CrashpadInfoClientOptions* options);
static const dyld_all_image_infos* DyldAllImageInfo();
// ModuleSnapshot:
std::string Name() const override;
uint64_t Address() const override;
uint64_t Size() const override;
time_t Timestamp() const override;
void FileVersion(uint16_t* version_0,
uint16_t* version_1,
uint16_t* version_2,
uint16_t* version_3) const override;
void SourceVersion(uint16_t* version_0,
uint16_t* version_1,
uint16_t* version_2,
uint16_t* version_3) const override;
ModuleType GetModuleType() const override;
void UUIDAndAge(UUID* uuid, uint32_t* age) const override;
std::string DebugFileName() const override;
std::vector<uint8_t> BuildID() const override;
std::vector<std::string> AnnotationsVector() const override;
std::map<std::string, std::string> AnnotationsSimpleMap() const override;
std::vector<AnnotationSnapshot> AnnotationObjects() const override;
std::set<CheckedRange<uint64_t>> ExtraMemoryRanges() const override;
std::vector<const UserMinidumpStream*> CustomMinidumpStreams() const override;
private:
// Gather the the module information based off of a mach_header_64 |address_|.
bool FinishInitialization();
std::string name_;
uint64_t address_;
uint64_t size_;
time_t timestamp_;
uint32_t dylib_version_;
uint64_t source_version_;
uint32_t filetype_;
UUID uuid_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ModuleSnapshotIOS);
};
} // namespace internal
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_IOS_MODULE_SNAPSHOT_IOS_H_
// 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/process_snapshot_ios.h"
#include <mach-o/loader.h>
#include <mach/mach.h>
#include <utility>
#include "base/logging.h"
#include "base/mac/mach_logging.h"
namespace crashpad {
ProcessSnapshotIOS::ProcessSnapshotIOS()
: ProcessSnapshot(),
modules_(),
report_id_(),
client_id_(),
annotations_simple_map_(),
snapshot_time_(),
initialized_() {}
ProcessSnapshotIOS::~ProcessSnapshotIOS() {}
bool ProcessSnapshotIOS::Initialize() {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
if (gettimeofday(&snapshot_time_, nullptr) != 0) {
PLOG(ERROR) << "gettimeofday";
return false;
}
InitializeModules();
INITIALIZATION_STATE_SET_VALID(initialized_);
return true;
}
pid_t ProcessSnapshotIOS::ProcessID() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return getpid();
}
pid_t ProcessSnapshotIOS::ParentProcessID() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return 0;
}
void ProcessSnapshotIOS::SnapshotTime(timeval* snapshot_time) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
*snapshot_time = snapshot_time_;
}
void ProcessSnapshotIOS::ProcessStartTime(timeval* start_time) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
}
void ProcessSnapshotIOS::ProcessCPUTimes(timeval* user_time,
timeval* system_time) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
}
void ProcessSnapshotIOS::ReportID(UUID* report_id) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
*report_id = report_id_;
}
void ProcessSnapshotIOS::ClientID(UUID* client_id) const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
*client_id = client_id_;
}
const std::map<std::string, std::string>&
ProcessSnapshotIOS::AnnotationsSimpleMap() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return annotations_simple_map_;
}
const SystemSnapshot* ProcessSnapshotIOS::System() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return nullptr;
}
std::vector<const ThreadSnapshot*> ProcessSnapshotIOS::Threads() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<const ThreadSnapshot*>();
}
std::vector<const ModuleSnapshot*> ProcessSnapshotIOS::Modules() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
std::vector<const ModuleSnapshot*> modules;
for (const auto& module : modules_) {
modules.push_back(module.get());
}
return modules;
}
std::vector<UnloadedModuleSnapshot> ProcessSnapshotIOS::UnloadedModules()
const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<UnloadedModuleSnapshot>();
}
const ExceptionSnapshot* ProcessSnapshotIOS::Exception() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return nullptr;
}
std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotIOS::MemoryMap()
const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<const MemoryMapRegionSnapshot*>();
}
std::vector<HandleSnapshot> ProcessSnapshotIOS::Handles() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<HandleSnapshot>();
}
std::vector<const MemorySnapshot*> ProcessSnapshotIOS::ExtraMemory() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return std::vector<const MemorySnapshot*>();
}
const ProcessMemory* ProcessSnapshotIOS::Memory() const {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
return nullptr;
}
void ProcessSnapshotIOS::InitializeModules() {
const dyld_all_image_infos* image_infos =
internal::ModuleSnapshotIOS::DyldAllImageInfo();
uint32_t image_count = image_infos->infoArrayCount;
const dyld_image_info* image_array = image_infos->infoArray;
for (uint32_t image_index = 0; image_index < image_count; ++image_index) {
const dyld_image_info* image = &image_array[image_index];
auto module = std::make_unique<internal::ModuleSnapshotIOS>();
if (module->Initialize(image)) {
modules_.push_back(std::move(module));
}
}
auto module = std::make_unique<internal::ModuleSnapshotIOS>();
if (module->InitializeDyld(image_infos)) {
modules_.push_back(std::move(module));
}
}
} // namespace crashpad
// 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_PROCESS_SNAPSHOT_IOS_H_
#define CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_
#include <vector>
#include "snapshot/ios/module_snapshot_ios.h"
#include "snapshot/process_snapshot.h"
#include "snapshot/unloaded_module_snapshot.h"
namespace crashpad {
//! \brief A ProcessSnapshot of a running (or crashed) process running on a
//! iphoneOS system.
class ProcessSnapshotIOS final : public ProcessSnapshot {
public:
ProcessSnapshotIOS();
~ProcessSnapshotIOS() override;
//! \brief Initializes the object.
//!
//! \return `true` if the snapshot could be created, `false` otherwise with
//! an appropriate message logged.
bool Initialize();
// ProcessSnapshot:
pid_t ProcessID() const override;
pid_t ParentProcessID() const override;
void SnapshotTime(timeval* snapshot_time) const override;
void ProcessStartTime(timeval* start_time) const override;
void ProcessCPUTimes(timeval* user_time, timeval* system_time) const override;
void ReportID(UUID* report_id) const override;
void ClientID(UUID* client_id) const override;
const std::map<std::string, std::string>& AnnotationsSimpleMap()
const override;
const SystemSnapshot* System() const override;
std::vector<const ThreadSnapshot*> Threads() const override;
std::vector<const ModuleSnapshot*> Modules() const override;
std::vector<UnloadedModuleSnapshot> UnloadedModules() const override;
const ExceptionSnapshot* Exception() const override;
std::vector<const MemoryMapRegionSnapshot*> MemoryMap() const override;
std::vector<HandleSnapshot> Handles() const override;
std::vector<const MemorySnapshot*> ExtraMemory() const override;
const ProcessMemory* Memory() const override;
private:
// Initializes modules_ on behalf of Initialize().
void InitializeModules();
std::vector<std::unique_ptr<internal::ModuleSnapshotIOS>> modules_;
UUID report_id_;
UUID client_id_;
std::map<std::string, std::string> annotations_simple_map_;
timeval snapshot_time_;
InitializationStateDcheck initialized_;
DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotIOS);
};
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_IOS_PROCESS_SNAPSHOT_IOS_H_
......@@ -77,7 +77,8 @@ TEST(SystemSnapshotLinux, Basic) {
EXPECT_PRED1(
[](std::string vendor) {
return vendor == "GenuineIntel" || vendor == "AuthenticAMD";
return vendor == "GenuineIntel" || vendor == "AuthenticAMD" ||
vendor == "HygonGenuine";
},
system.CPUVendor());
......
......@@ -399,16 +399,27 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path,
FilePermissions permissions);
#if defined(OS_LINUX)
//! \brief Wraps memfd_create(), logging an error if the operation fails.
//! Unlike other file open operations, this doesn't set `O_CLOEXEC`.
//! \brief Opens an in-memory file for input and output.
//!
//! \return The newly opened FileHandle, or an invalid FileHandle on failure.
//! This function first attempts to open the file with `memfd_create()`. If
//! `memfd_create()` isn't supported by the kernel, this function next attempts
//! to open a file using `O_TMPFILE`. If `O_TMPFILE` isn't supported, this
//! function finally falls back to creating a file with a randomized name in
//! `/tmp` and immediately `unlink()`ing it.
//!
//! Unlike other file open operations, this function doesn't set `O_CLOEXEC`.
//!
//! \param name A name associated with the file. This name does not indicate any
//! exact path and may not be used at all, depending on the strategy used to
//! create the file. The name should not contain any '/' characters.
//! \return The newly opened FileHandle, or an invalid FileHandle on failure,
//! with a message logged.
//!
//! \sa ScopedFileHandle
//! \sa LoggingOpenFileForRead
//! \sa LoggingOpenFileForWrite
//! \sa LoggingOpenFileForReadAndWrite
FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path);
FileHandle LoggingOpenMemoryFileForReadAndWrite(const base::FilePath& name);
#endif // OS_LINUX
//! \brief Wraps OpenFileForReadAndWrite(), logging an error if the operation
......
......@@ -14,6 +14,7 @@
#include "util/file/file_io.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/file.h>
#include <sys/mman.h>
......@@ -26,7 +27,9 @@
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "util/misc/random_string.h"
namespace crashpad {
......@@ -98,13 +101,6 @@ FileHandle OpenFileForOutput(int rdwr_or_wronly,
flags,
permissions == FilePermissions::kWorldReadable ? 0644 : 0600));
}
#if defined(OS_LINUX)
FileHandle OpenMemFileForOutput(const base::FilePath& path) {
return HANDLE_EINTR(memfd_create(path.value().c_str(), 0));
}
#endif
} // namespace
namespace internal {
......@@ -157,10 +153,49 @@ FileHandle LoggingOpenFileForWrite(const base::FilePath& path,
}
#if defined(OS_LINUX)
FileHandle LoggingOpenMemFileForWrite(const base::FilePath& path) {
FileHandle fd = OpenMemFileForOutput(path);
PLOG_IF(ERROR, fd < 0) << "memfd_create " << path.value();
return fd;
FileHandle LoggingOpenMemoryFileForReadAndWrite(const base::FilePath& name) {
DCHECK(name.value().find('/') == std::string::npos);
int result = HANDLE_EINTR(memfd_create(name.value().c_str(), 0));
if (result >= 0 || errno != ENOSYS) {
PLOG_IF(ERROR, result < 0) << "memfd_create";
return result;
}
const char* tmp = getenv("TMPDIR");
tmp = tmp ? tmp : "/tmp";
result = HANDLE_EINTR(open(tmp, O_RDWR | O_EXCL | O_TMPFILE, 0600));
if (result >= 0 ||
// These are the expected possible error codes indicating that O_TMPFILE
// doesn't have kernel or filesystem support. O_TMPFILE was added in Linux
// 3.11. Experimentation confirms that at least Linux 2.6.29 and Linux
// 3.10 set errno to EISDIR. EOPNOTSUPP is returned when the filesystem
// doesn't support O_TMPFILE. The man pages also mention ENOENT as an
// error code to check, but the language implies it would only occur when
// |tmp| is also an invalid directory. EINVAL is mentioned as a possible
// error code for any invalid values in flags, but O_TMPFILE isn't
// mentioned explicitly in this context and hasn't been observed in
// practice.
(errno != EISDIR && errno != EOPNOTSUPP)) {
PLOG_IF(ERROR, result < 0) << "open";
return result;
}
std::string path = base::StringPrintf("%s/%s.%d.%s",
tmp,
name.value().c_str(),
getpid(),
RandomString().c_str());
result = HANDLE_EINTR(open(path.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600));
if (result < 0) {
PLOG(ERROR) << "open";
return result;
}
if (unlink(path.c_str()) != 0) {
PLOG(WARNING) << "unlink";
}
return result;
}
#endif
......
......@@ -473,6 +473,23 @@ TEST(FileIO, LoggingOpenFileForReadAndWrite) {
TestOpenFileForWrite(LoggingOpenFileForReadAndWrite);
}
#if defined(OS_LINUX)
TEST(FileIO, LoggingOpenMemoryFileForReadAndWrite) {
ScopedFileHandle handle(
LoggingOpenMemoryFileForReadAndWrite(base::FilePath("memfile")));
ASSERT_TRUE(handle.is_valid());
static constexpr char kTestData[] = "somedata";
ASSERT_TRUE(LoggingWriteFile(handle.get(), kTestData, sizeof(kTestData)));
ASSERT_EQ(LoggingSeekFile(handle.get(), 0, SEEK_SET), 0);
char buffer[sizeof(kTestData)];
ASSERT_TRUE(LoggingReadFileExactly(handle.get(), buffer, sizeof(buffer)));
EXPECT_EQ(memcmp(buffer, kTestData, sizeof(buffer)), 0);
}
#endif // OS_LINUX
enum class ReadOrWrite : bool {
kRead,
kWrite,
......
......@@ -174,7 +174,7 @@ bool FileWriter::Open(const base::FilePath& path,
#if defined(OS_LINUX)
bool FileWriter::OpenMemfd(const base::FilePath& path) {
CHECK(!file_.is_valid());
file_.reset(LoggingOpenMemFileForWrite(path));
file_.reset(LoggingOpenMemoryFileForReadAndWrite(path));
if (!file_.is_valid()) {
return false;
}
......
......@@ -132,7 +132,7 @@ class FileWriter : public FileWriterInterface {
FilePermissions permissions);
#if defined(OS_LINUX)
//! \brief Wraps LoggingOpenMemFileForWrite().
//! \brief Wraps LoggingOpenMemoryFileForWrite().
//!
//! \return `true` if the operation succeeded, `false` if it failed, with an
//! error message logged.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment