1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "snapshot/mac/process_snapshot_mac.h"
16 
17 #include <utility>
18 
19 #include "base/logging.h"
20 #include "util/misc/tri_state.h"
21 
22 namespace crashpad {
23 
ProcessSnapshotMac()24 ProcessSnapshotMac::ProcessSnapshotMac()
25     : ProcessSnapshot(),
26       system_(),
27       threads_(),
28       modules_(),
29       exception_(),
30       process_reader_(),
31       report_id_(),
32       client_id_(),
33       annotations_simple_map_(),
34       snapshot_time_(),
35       initialized_() {
36 }
37 
~ProcessSnapshotMac()38 ProcessSnapshotMac::~ProcessSnapshotMac() {
39 }
40 
Initialize(task_t task)41 bool ProcessSnapshotMac::Initialize(task_t task) {
42   INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
43 
44   if (gettimeofday(&snapshot_time_, nullptr) != 0) {
45     PLOG(ERROR) << "gettimeofday";
46     return false;
47   }
48 
49   if (!process_reader_.Initialize(task)) {
50     return false;
51   }
52 
53   system_.Initialize(&process_reader_, &snapshot_time_);
54 
55   InitializeThreads();
56   InitializeModules();
57 
58   INITIALIZATION_STATE_SET_VALID(initialized_);
59   return true;
60 }
61 
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)62 bool ProcessSnapshotMac::InitializeException(
63     exception_behavior_t behavior,
64     thread_t exception_thread,
65     exception_type_t exception,
66     const mach_exception_data_type_t* code,
67     mach_msg_type_number_t code_count,
68     thread_state_flavor_t flavor,
69     ConstThreadState state,
70     mach_msg_type_number_t state_count) {
71   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
72   DCHECK(!exception_);
73 
74   exception_.reset(new internal::ExceptionSnapshotMac());
75   if (!exception_->Initialize(&process_reader_,
76                               behavior,
77                               exception_thread,
78                               exception,
79                               code,
80                               code_count,
81                               flavor,
82                               state,
83                               state_count)) {
84     exception_.reset();
85     return false;
86   }
87 
88   return true;
89 }
90 
GetCrashpadOptions(CrashpadInfoClientOptions * options)91 void ProcessSnapshotMac::GetCrashpadOptions(
92     CrashpadInfoClientOptions* options) {
93   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
94 
95   CrashpadInfoClientOptions local_options;
96 
97   for (const auto& module : modules_) {
98     CrashpadInfoClientOptions module_options;
99     module->GetCrashpadOptions(&module_options);
100 
101     if (local_options.crashpad_handler_behavior == TriState::kUnset) {
102       local_options.crashpad_handler_behavior =
103           module_options.crashpad_handler_behavior;
104     }
105     if (local_options.system_crash_reporter_forwarding == TriState::kUnset) {
106       local_options.system_crash_reporter_forwarding =
107           module_options.system_crash_reporter_forwarding;
108     }
109     if (local_options.gather_indirectly_referenced_memory == TriState::kUnset) {
110       local_options.gather_indirectly_referenced_memory =
111           module_options.gather_indirectly_referenced_memory;
112       local_options.indirectly_referenced_memory_cap =
113           module_options.indirectly_referenced_memory_cap;
114     }
115 
116     // If non-default values have been found for all options, the loop can end
117     // early.
118     if (local_options.crashpad_handler_behavior != TriState::kUnset &&
119         local_options.system_crash_reporter_forwarding != TriState::kUnset &&
120         local_options.gather_indirectly_referenced_memory != TriState::kUnset) {
121       break;
122     }
123   }
124 
125   *options = local_options;
126 }
127 
ProcessID() const128 pid_t ProcessSnapshotMac::ProcessID() const {
129   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
130   return process_reader_.ProcessID();
131 }
132 
ParentProcessID() const133 pid_t ProcessSnapshotMac::ParentProcessID() const {
134   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
135   return process_reader_.ParentProcessID();
136 }
137 
SnapshotTime(timeval * snapshot_time) const138 void ProcessSnapshotMac::SnapshotTime(timeval* snapshot_time) const {
139   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
140   *snapshot_time = snapshot_time_;
141 }
142 
ProcessStartTime(timeval * start_time) const143 void ProcessSnapshotMac::ProcessStartTime(timeval* start_time) const {
144   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
145   process_reader_.StartTime(start_time);
146 }
147 
ProcessCPUTimes(timeval * user_time,timeval * system_time) const148 void ProcessSnapshotMac::ProcessCPUTimes(timeval* user_time,
149                                          timeval* system_time) const {
150   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
151   process_reader_.CPUTimes(user_time, system_time);
152 }
153 
ReportID(UUID * report_id) const154 void ProcessSnapshotMac::ReportID(UUID* report_id) const {
155   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
156   *report_id = report_id_;
157 }
158 
ClientID(UUID * client_id) const159 void ProcessSnapshotMac::ClientID(UUID* client_id) const {
160   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
161   *client_id = client_id_;
162 }
163 
164 const std::map<std::string, std::string>&
AnnotationsSimpleMap() const165 ProcessSnapshotMac::AnnotationsSimpleMap() const {
166   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
167   return annotations_simple_map_;
168 }
169 
System() const170 const SystemSnapshot* ProcessSnapshotMac::System() const {
171   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
172   return &system_;
173 }
174 
Threads() const175 std::vector<const ThreadSnapshot*> ProcessSnapshotMac::Threads() const {
176   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
177   std::vector<const ThreadSnapshot*> threads;
178   for (const auto& thread : threads_) {
179     threads.push_back(thread.get());
180   }
181   return threads;
182 }
183 
Modules() const184 std::vector<const ModuleSnapshot*> ProcessSnapshotMac::Modules() const {
185   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
186   std::vector<const ModuleSnapshot*> modules;
187   for (const auto& module : modules_) {
188     modules.push_back(module.get());
189   }
190   return modules;
191 }
192 
UnloadedModules() const193 std::vector<UnloadedModuleSnapshot> ProcessSnapshotMac::UnloadedModules()
194     const {
195   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
196   return std::vector<UnloadedModuleSnapshot>();
197 }
198 
Exception() const199 const ExceptionSnapshot* ProcessSnapshotMac::Exception() const {
200   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
201   return exception_.get();
202 }
203 
MemoryMap() const204 std::vector<const MemoryMapRegionSnapshot*> ProcessSnapshotMac::MemoryMap()
205     const {
206   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
207   return std::vector<const MemoryMapRegionSnapshot*>();
208 }
209 
Handles() const210 std::vector<HandleSnapshot> ProcessSnapshotMac::Handles() const {
211   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
212   return std::vector<HandleSnapshot>();
213 }
214 
ExtraMemory() const215 std::vector<const MemorySnapshot*> ProcessSnapshotMac::ExtraMemory() const {
216   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
217   return std::vector<const MemorySnapshot*>();
218 }
219 
Memory() const220 const ProcessMemory* ProcessSnapshotMac::Memory() const {
221   INITIALIZATION_STATE_DCHECK_VALID(initialized_);
222   return process_reader_.Memory();
223 }
224 
InitializeThreads()225 void ProcessSnapshotMac::InitializeThreads() {
226   const std::vector<ProcessReaderMac::Thread>& process_reader_threads =
227       process_reader_.Threads();
228   for (const ProcessReaderMac::Thread& process_reader_thread :
229        process_reader_threads) {
230     auto thread = std::make_unique<internal::ThreadSnapshotMac>();
231     if (thread->Initialize(&process_reader_, process_reader_thread)) {
232       threads_.push_back(std::move(thread));
233     }
234   }
235 }
236 
InitializeModules()237 void ProcessSnapshotMac::InitializeModules() {
238   const std::vector<ProcessReaderMac::Module>& process_reader_modules =
239       process_reader_.Modules();
240   for (const ProcessReaderMac::Module& process_reader_module :
241        process_reader_modules) {
242     auto module = std::make_unique<internal::ModuleSnapshotMac>();
243     if (module->Initialize(&process_reader_, process_reader_module)) {
244       modules_.push_back(std::move(module));
245     }
246   }
247 }
248 
249 }  // namespace crashpad
250