OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 } | 62 } |
63 | 63 |
64 ++*depth; | 64 ++*depth; |
65 } | 65 } |
66 } | 66 } |
67 | 67 |
68 } // namespace | 68 } // namespace |
69 | 69 |
70 namespace crashpad { | 70 namespace crashpad { |
71 | 71 |
72 ProcessReaderThread::ProcessReaderThread() | 72 ProcessReader::Thread::Thread() |
73 : thread_context(), | 73 : thread_context(), |
74 float_context(), | 74 float_context(), |
75 debug_context(), | 75 debug_context(), |
76 id(0), | 76 id(0), |
77 stack_region_address(0), | 77 stack_region_address(0), |
78 stack_region_size(0), | 78 stack_region_size(0), |
79 thread_specific_data_address(0), | 79 thread_specific_data_address(0), |
80 port(MACH_PORT_NULL), | 80 port(MACH_PORT_NULL), |
81 suspend_count(0), | 81 suspend_count(0), |
82 priority(0) { | 82 priority(0) { |
83 } | 83 } |
84 | 84 |
85 ProcessReaderModule::ProcessReaderModule() : name(), address(0), timestamp(0) { | 85 ProcessReader::Module::Module() : name(), address(0), timestamp(0) { |
86 } | 86 } |
87 | 87 |
88 ProcessReaderModule::~ProcessReaderModule() { | 88 ProcessReader::Module::~Module() { |
89 } | 89 } |
90 | 90 |
91 ProcessReader::ProcessReader() | 91 ProcessReader::ProcessReader() |
92 : kern_proc_info_(), | 92 : kern_proc_info_(), |
93 threads_(), | 93 threads_(), |
94 modules_(), | 94 modules_(), |
95 task_memory_(), | 95 task_memory_(), |
96 task_(MACH_PORT_NULL), | 96 task_(MACH_PORT_NULL), |
97 initialized_(), | 97 initialized_(), |
98 is_64_bit_(false), | 98 is_64_bit_(false), |
99 initialized_threads_(false), | 99 initialized_threads_(false), |
100 initialized_modules_(false) { | 100 initialized_modules_(false) { |
101 } | 101 } |
102 | 102 |
103 ProcessReader::~ProcessReader() { | 103 ProcessReader::~ProcessReader() { |
104 for (const ProcessReaderThread& thread : threads_) { | 104 for (const Thread& thread : threads_) { |
105 kern_return_t kr = mach_port_deallocate(mach_task_self(), thread.port); | 105 kern_return_t kr = mach_port_deallocate(mach_task_self(), thread.port); |
106 MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; | 106 MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; |
107 } | 107 } |
108 } | 108 } |
109 | 109 |
110 bool ProcessReader::Initialize(mach_port_t task) { | 110 bool ProcessReader::Initialize(mach_port_t task) { |
111 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); | 111 INITIALIZATION_STATE_SET_INITIALIZING(initialized_); |
112 | 112 |
113 pid_t pid; | 113 pid_t pid; |
114 kern_return_t kr = pid_for_task(task, &pid); | 114 kern_return_t kr = pid_for_task(task, &pid); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
179 MachTimeValueToTimeval(task_thread_times.user_time, &thread_user_time); | 179 MachTimeValueToTimeval(task_thread_times.user_time, &thread_user_time); |
180 timeval thread_system_time; | 180 timeval thread_system_time; |
181 MachTimeValueToTimeval(task_thread_times.system_time, &thread_system_time); | 181 MachTimeValueToTimeval(task_thread_times.system_time, &thread_system_time); |
182 | 182 |
183 timeradd(user_time, &thread_user_time, user_time); | 183 timeradd(user_time, &thread_user_time, user_time); |
184 timeradd(system_time, &thread_system_time, system_time); | 184 timeradd(system_time, &thread_system_time, system_time); |
185 | 185 |
186 return true; | 186 return true; |
187 } | 187 } |
188 | 188 |
189 const std::vector<ProcessReaderThread>& ProcessReader::Threads() { | 189 const std::vector<ProcessReader::Thread>& ProcessReader::Threads() { |
190 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 190 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
191 | 191 |
192 if (!initialized_threads_) { | 192 if (!initialized_threads_) { |
193 InitializeThreads(); | 193 InitializeThreads(); |
194 } | 194 } |
195 | 195 |
196 return threads_; | 196 return threads_; |
197 } | 197 } |
198 | 198 |
199 const std::vector<ProcessReaderModule>& ProcessReader::Modules() { | 199 const std::vector<ProcessReader::Module>& ProcessReader::Modules() { |
200 INITIALIZATION_STATE_DCHECK_VALID(initialized_); | 200 INITIALIZATION_STATE_DCHECK_VALID(initialized_); |
201 | 201 |
202 if (!initialized_modules_) { | 202 if (!initialized_modules_) { |
203 InitializeModules(); | 203 InitializeModules(); |
204 } | 204 } |
205 | 205 |
206 return modules_; | 206 return modules_; |
207 } | 207 } |
208 | 208 |
209 void ProcessReader::InitializeThreads() { | 209 void ProcessReader::InitializeThreads() { |
(...skipping 14 matching lines...) Expand all Loading... |
224 // by anything until they’re added to |threads_| by the loop below. Any early | 224 // by anything until they’re added to |threads_| by the loop below. Any early |
225 // return (or exception) that happens between here and the completion of the | 225 // return (or exception) that happens between here and the completion of the |
226 // loop below will leak thread port send rights. | 226 // loop below will leak thread port send rights. |
227 ScopedForbidReturn threads_need_owners; | 227 ScopedForbidReturn threads_need_owners; |
228 | 228 |
229 base::mac::ScopedMachVM threads_vm( | 229 base::mac::ScopedMachVM threads_vm( |
230 reinterpret_cast<vm_address_t>(threads), | 230 reinterpret_cast<vm_address_t>(threads), |
231 mach_vm_round_page(thread_count * sizeof(*threads))); | 231 mach_vm_round_page(thread_count * sizeof(*threads))); |
232 | 232 |
233 for (size_t index = 0; index < thread_count; ++index) { | 233 for (size_t index = 0; index < thread_count; ++index) { |
234 ProcessReaderThread thread; | 234 Thread thread; |
235 thread.port = threads[index]; | 235 thread.port = threads[index]; |
236 | 236 |
237 #if defined(ARCH_CPU_X86_FAMILY) | 237 #if defined(ARCH_CPU_X86_FAMILY) |
238 const thread_state_flavor_t kThreadStateFlavor = | 238 const thread_state_flavor_t kThreadStateFlavor = |
239 Is64Bit() ? x86_THREAD_STATE64 : x86_THREAD_STATE32; | 239 Is64Bit() ? x86_THREAD_STATE64 : x86_THREAD_STATE32; |
240 mach_msg_type_number_t thread_state_count = | 240 mach_msg_type_number_t thread_state_count = |
241 Is64Bit() ? x86_THREAD_STATE64_COUNT : x86_THREAD_STATE32_COUNT; | 241 Is64Bit() ? x86_THREAD_STATE64_COUNT : x86_THREAD_STATE32_COUNT; |
242 | 242 |
243 // TODO(mark): Use the AVX variants instead of the FLOAT variants? They’re | 243 // TODO(mark): Use the AVX variants instead of the FLOAT variants? They’re |
244 // supported on 10.6 and later. | 244 // supported on 10.6 and later. |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 if (!process_types::dyld_image_info::ReadArrayInto(this, | 403 if (!process_types::dyld_image_info::ReadArrayInto(this, |
404 all_image_infos.infoArray, | 404 all_image_infos.infoArray, |
405 image_info_vector.size(), | 405 image_info_vector.size(), |
406 &image_info_vector[0])) { | 406 &image_info_vector[0])) { |
407 LOG(WARNING) << "could not read dyld_image_info array"; | 407 LOG(WARNING) << "could not read dyld_image_info array"; |
408 return; | 408 return; |
409 } | 409 } |
410 | 410 |
411 bool found_dyld = false; | 411 bool found_dyld = false; |
412 for (const process_types::dyld_image_info& image_info : image_info_vector) { | 412 for (const process_types::dyld_image_info& image_info : image_info_vector) { |
413 ProcessReaderModule module; | 413 Module module; |
414 module.address = image_info.imageLoadAddress; | 414 module.address = image_info.imageLoadAddress; |
415 module.timestamp = image_info.imageFileModDate; | 415 module.timestamp = image_info.imageFileModDate; |
416 if (!task_memory_->ReadCString(image_info.imageFilePath, &module.name)) { | 416 if (!task_memory_->ReadCString(image_info.imageFilePath, &module.name)) { |
417 LOG(WARNING) << "could not read dyld_image_info::imageFilePath"; | 417 LOG(WARNING) << "could not read dyld_image_info::imageFilePath"; |
418 // Proceed anyway with an empty module name. | 418 // Proceed anyway with an empty module name. |
419 } | 419 } |
420 | 420 |
421 modules_.push_back(module); | 421 modules_.push_back(module); |
422 | 422 |
423 if (all_image_infos.version >= 2 && all_image_infos.dyldImageLoadAddress && | 423 if (all_image_infos.version >= 2 && all_image_infos.dyldImageLoadAddress && |
(...skipping 12 matching lines...) Expand all Loading... |
436 // that dyld records the timestamps of other modules when they’re loaded. (The | 436 // that dyld records the timestamps of other modules when they’re loaded. (The |
437 // timestamp for the main executable is also not reported and appears as 0 | 437 // timestamp for the main executable is also not reported and appears as 0 |
438 // even when accessed via dyld APIs, because it’s loaded by the kernel, not by | 438 // even when accessed via dyld APIs, because it’s loaded by the kernel, not by |
439 // dyld.) | 439 // dyld.) |
440 // | 440 // |
441 // The name can be determined, but it’s not as simple as hardcoding the | 441 // The name can be determined, but it’s not as simple as hardcoding the |
442 // default "/usr/lib/dyld" because an executable could have specified anything | 442 // default "/usr/lib/dyld" because an executable could have specified anything |
443 // in its LC_LOAD_DYLINKER command. | 443 // in its LC_LOAD_DYLINKER command. |
444 if (!found_dyld && all_image_infos.version >= 2 && | 444 if (!found_dyld && all_image_infos.version >= 2 && |
445 all_image_infos.dyldImageLoadAddress) { | 445 all_image_infos.dyldImageLoadAddress) { |
446 ProcessReaderModule module; | 446 Module module; |
447 module.address = all_image_infos.dyldImageLoadAddress; | 447 module.address = all_image_infos.dyldImageLoadAddress; |
448 module.timestamp = 0; | 448 module.timestamp = 0; |
449 | 449 |
450 // Examine the executable’s LC_LOAD_DYLINKER load command to find the path | 450 // Examine the executable’s LC_LOAD_DYLINKER load command to find the path |
451 // used to load dyld. | 451 // used to load dyld. |
452 MachOImageReader executable; | 452 MachOImageReader executable; |
453 if (all_image_infos.infoArrayCount >= 1 && | 453 if (all_image_infos.infoArrayCount >= 1 && |
454 executable.Initialize(this, modules_[0].address, modules_[0].name) && | 454 executable.Initialize(this, modules_[0].address, modules_[0].name) && |
455 executable.FileType() == MH_EXECUTE && | 455 executable.FileType() == MH_EXECUTE && |
456 !executable.DylinkerName().empty()) { | 456 !executable.DylinkerName().empty()) { |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 // The red zone would go lower into another region in memory, but no | 634 // The red zone would go lower into another region in memory, but no |
635 // region was found. Memory can only be captured to an address as low as | 635 // region was found. Memory can only be captured to an address as low as |
636 // the base address of the region already found. | 636 // the base address of the region already found. |
637 *start_address = *region_base; | 637 *start_address = *region_base; |
638 } | 638 } |
639 } | 639 } |
640 #endif | 640 #endif |
641 } | 641 } |
642 | 642 |
643 } // namespace crashpad | 643 } // namespace crashpad |
OLD | NEW |