| 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 |