| // Copyright 2014 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/mac/process_snapshot_mac.h" |
| |
| #include <utility> |
| |
| #include "base/logging.h" |
| #include "util/misc/tri_state.h" |
| |
| namespace crashpad { |
| |
| ProcessSnapshotMac::ProcessSnapshotMac() |
| : ProcessSnapshot(), |
| system_(), |
| threads_(), |
| modules_(), |
| exception_(), |
| process_reader_(), |
| report_id_(), |
| client_id_(), |
| annotations_simple_map_(), |
| snapshot_time_(), |
| initialized_() { |
| } |
| |
| ProcessSnapshotMac::~ProcessSnapshotMac() { |
| } |
| |
| bool ProcessSnapshotMac::Initialize(task_t task) { |
| INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
| |
| if (gettimeofday(&snapshot_time_, nullptr) != 0) { |
| PLOG(ERROR) << "gettimeofday"; |
| return false; |
| } |
| |
| if (!process_reader_.Initialize(task)) { |
| return false; |
| } |
| |
| system_.Initialize(&process_reader_, &snapshot_time_); |
| |
| InitializeThreads(); |
| InitializeModules(); |
| |
| INITIALIZATION_STATE_SET_VALID(initialized_); |
| return true; |
| } |
| |
| bool ProcessSnapshotMac::InitializeException( |
| exception_behavior_t behavior, |
| thread_t exception_thread, |
| exception_type_t exception, |
| const mach_exception_data_type_t* code, |
| mach_msg_type_number_t code_count, |
| thread_state_flavor_t flavor, |
| ConstThreadState state, |
| mach_msg_type_number_t state_count) { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| DCHECK(!exception_); |
| |
| exception_.reset(new internal::ExceptionSnapshotMac()); |
| if (!exception_->Initialize(&process_reader_, |
| behavior, |
| exception_thread, |
| exception, |
| code, |
| code_count, |
| flavor, |
| state, |
| state_count)) { |
| exception_.reset(); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void ProcessSnapshotMac::GetCrashpadOptions( |
| CrashpadInfoClientOptions* options) { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| |
| CrashpadInfoClientOptions local_options; |
| |
| for (const auto& module : modules_) { |
| CrashpadInfoClientOptions module_options; |
| module->GetCrashpadOptions(&module_options); |
| |
| if (local_options.crashpad_handler_behavior == TriState::kUnset) { |
| local_options.crashpad_handler_behavior = |
| module_options.crashpad_handler_behavior; |
| } |
| if (local_options.system_crash_reporter_forwarding == TriState::kUnset) { |
| local_options.system_crash_reporter_forwarding = |
| module_options.system_crash_reporter_forwarding; |
| } |
| if (local_options.gather_indirectly_referenced_memory == TriState::kUnset) { |
| local_options.gather_indirectly_referenced_memory = |
| module_options.gather_indirectly_referenced_memory; |
| local_options.indirectly_referenced_memory_cap = |
| module_options.indirectly_referenced_memory_cap; |
| } |
| |
| // If non-default values have been found for all options, the loop can end |
| // early. |
| if (local_options.crashpad_handler_behavior != TriState::kUnset && |
| local_options.system_crash_reporter_forwarding != TriState::kUnset && |
| local_options.gather_indirectly_referenced_memory != TriState::kUnset) { |
| break; |
| } |
| } |
| |
| *options = local_options; |
| } |
| |
| pid_t ProcessSnapshotMac::ProcessID() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return process_reader_.ProcessID(); |
| } |
| |
| pid_t ProcessSnapshotMac::ParentProcessID() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return process_reader_.ParentProcessID(); |
| } |
| |
| void ProcessSnapshotMac::SnapshotTime(timeval* snapshot_time) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| *snapshot_time = snapshot_time_; |
| } |
| |
| void ProcessSnapshotMac::ProcessStartTime(timeval* start_time) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| process_reader_.StartTime(start_time); |
| } |
| |
| void ProcessSnapshotMac::ProcessCPUTimes(timeval* user_time, |
| timeval* system_time) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| process_reader_.CPUTimes(user_time, system_time); |
| } |
| |
| void ProcessSnapshotMac::ReportID(UUID* report_id) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| *report_id = report_id_; |
| } |
| |
| void ProcessSnapshotMac::ClientID(UUID* client_id) const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| *client_id = client_id_; |
| } |
| |
| const std::map<std::string, std::string>& |
| ProcessSnapshotMac::AnnotationsSimpleMap() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return annotations_simple_map_; |
| } |
| |
| const SystemSnapshot* ProcessSnapshotMac::System() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return &system_; |
| } |
| |
| std::vector<const ThreadSnapshot*> ProcessSnapshotMac::Threads() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| std::vector<const ThreadSnapshot*> threads; |
| for (const auto& thread : threads_) { |
| threads.push_back(thread.get()); |
| } |
| return threads; |
| } |
| |
| std::vector<const ModuleSnapshot*> ProcessSnapshotMac::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> ProcessSnapshotMac::UnloadedModules() |
| const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return std::vector<UnloadedModuleSnapshot>(); |
| } |
| |
| const ExceptionSnapshot* ProcessSnapshotMac::Exception() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return exception_.get(); |
| } |
| |
| std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotMac::MemoryMap() |
| const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return std::vector<const MemoryMapRegionSnapshot*>(); |
| } |
| |
| std::vector<HandleSnapshot> ProcessSnapshotMac::Handles() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return std::vector<HandleSnapshot>(); |
| } |
| |
| std::vector<const MemorySnapshot*> ProcessSnapshotMac::ExtraMemory() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return std::vector<const MemorySnapshot*>(); |
| } |
| |
| const ProcessMemory* ProcessSnapshotMac::Memory() const { |
| INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
| return process_reader_.Memory(); |
| } |
| |
| void ProcessSnapshotMac::InitializeThreads() { |
| const std::vector<ProcessReaderMac::Thread>& process_reader_threads = |
| process_reader_.Threads(); |
| for (const ProcessReaderMac::Thread& process_reader_thread : |
| process_reader_threads) { |
| auto thread = std::make_unique<internal::ThreadSnapshotMac>(); |
| if (thread->Initialize(&process_reader_, process_reader_thread)) { |
| threads_.push_back(std::move(thread)); |
| } |
| } |
| } |
| |
| void ProcessSnapshotMac::InitializeModules() { |
| const std::vector<ProcessReaderMac::Module>& process_reader_modules = |
| process_reader_.Modules(); |
| for (const ProcessReaderMac::Module& process_reader_module : |
| process_reader_modules) { |
| auto module = std::make_unique<internal::ModuleSnapshotMac>(); |
| if (module->Initialize(&process_reader_, process_reader_module)) { |
| modules_.push_back(std::move(module)); |
| } |
| } |
| } |
| |
| } // namespace crashpad |