OLD | NEW |
(Empty) | |
| 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 "util/mach/exception_ports.h" |
| 16 |
| 17 #include "base/logging.h" |
| 18 #include "base/mac/mach_logging.h" |
| 19 |
| 20 namespace crashpad { |
| 21 |
| 22 ExceptionPorts::ExceptionPorts(TargetType target_type, mach_port_t target_port) |
| 23 : target_port_(target_port), dealloc_target_port_(false) { |
| 24 switch (target_type) { |
| 25 case kTargetTypeHost: |
| 26 get_exception_ports_ = host_get_exception_ports; |
| 27 set_exception_ports_ = host_set_exception_ports; |
| 28 target_name_ = "host"; |
| 29 if (target_port_ == MACH_PORT_NULL) { |
| 30 target_port_ = mach_host_self(); |
| 31 dealloc_target_port_ = true; |
| 32 } |
| 33 break; |
| 34 |
| 35 case kTargetTypeTask: |
| 36 get_exception_ports_ = task_get_exception_ports; |
| 37 set_exception_ports_ = task_set_exception_ports; |
| 38 target_name_ = "task"; |
| 39 if (target_port_ == MACH_PORT_NULL) { |
| 40 target_port_ = mach_task_self(); |
| 41 // Don’t deallocate mach_task_self(). |
| 42 } |
| 43 break; |
| 44 |
| 45 case kTargetTypeThread: |
| 46 get_exception_ports_ = thread_get_exception_ports; |
| 47 set_exception_ports_ = thread_set_exception_ports; |
| 48 target_name_ = "thread"; |
| 49 if (target_port_ == MACH_PORT_NULL) { |
| 50 target_port_ = mach_thread_self(); |
| 51 dealloc_target_port_ = true; |
| 52 } |
| 53 break; |
| 54 |
| 55 default: |
| 56 NOTREACHED(); |
| 57 get_exception_ports_ = NULL; |
| 58 set_exception_ports_ = NULL; |
| 59 target_name_ = NULL; |
| 60 target_port_ = MACH_PORT_NULL; |
| 61 break; |
| 62 } |
| 63 } |
| 64 |
| 65 ExceptionPorts::~ExceptionPorts() { |
| 66 if (dealloc_target_port_) { |
| 67 kern_return_t kr = mach_port_deallocate(mach_task_self(), target_port_); |
| 68 MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_port_deallocate"; |
| 69 } |
| 70 } |
| 71 |
| 72 bool ExceptionPorts::GetExceptionPorts( |
| 73 exception_mask_t mask, |
| 74 std::vector<ExceptionHandler>* handlers) const { |
| 75 // <mach/mach_types.defs> says that these arrays have room for 32 elements, |
| 76 // despite EXC_TYPES_COUNT only being as low as 11 (in the 10.6 SDK), and |
| 77 // later operating system versions have defined more exception types. The |
| 78 // generated task_get_exception_ports() in taskUser.c expects there to be room |
| 79 // for 32. |
| 80 const int kMaxPorts = 32; |
| 81 |
| 82 // task_get_exception_ports() doesn’t actually use the initial value of |
| 83 // handler_count, but 10.9.4 |
| 84 // xnu-2422.110.17/osfmk/man/task_get_exception_ports.html says it does. Humor |
| 85 // the documentation. |
| 86 mach_msg_type_number_t handler_count = kMaxPorts; |
| 87 |
| 88 exception_mask_t masks[kMaxPorts]; |
| 89 exception_handler_t ports[kMaxPorts]; |
| 90 exception_behavior_t behaviors[kMaxPorts]; |
| 91 thread_state_flavor_t flavors[kMaxPorts]; |
| 92 |
| 93 kern_return_t kr = get_exception_ports_( |
| 94 target_port_, mask, masks, &handler_count, ports, behaviors, flavors); |
| 95 if (kr != KERN_SUCCESS) { |
| 96 MACH_LOG(ERROR, kr) << TargetTypeName() << "_get_exception_ports"; |
| 97 return false; |
| 98 } |
| 99 |
| 100 handlers->clear(); |
| 101 for (mach_msg_type_number_t index = 0; index < handler_count; ++index) { |
| 102 ExceptionHandler handler; |
| 103 handler.mask = masks[index]; |
| 104 handler.port = ports[index]; |
| 105 handler.behavior = behaviors[index]; |
| 106 handler.flavor = flavors[index]; |
| 107 handlers->push_back(handler); |
| 108 } |
| 109 |
| 110 return true; |
| 111 } |
| 112 |
| 113 bool ExceptionPorts::SetExceptionPort(exception_mask_t mask, |
| 114 exception_handler_t port, |
| 115 exception_behavior_t behavior, |
| 116 thread_state_flavor_t flavor) const { |
| 117 kern_return_t kr = |
| 118 set_exception_ports_(target_port_, mask, port, behavior, flavor); |
| 119 if (kr != KERN_SUCCESS) { |
| 120 MACH_LOG(ERROR, kr) << TargetTypeName() << "_set_exception_ports"; |
| 121 return false; |
| 122 } |
| 123 |
| 124 return true; |
| 125 } |
| 126 |
| 127 const char* ExceptionPorts::TargetTypeName() const { |
| 128 return target_name_; |
| 129 } |
| 130 |
| 131 } // namespace crashpad |
OLD | NEW |