OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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_types.h" |
| 16 |
| 17 #include <Availability.h> |
| 18 #include <AvailabilityMacros.h> |
| 19 #include <dlfcn.h> |
| 20 #include <errno.h> |
| 21 #include <libproc.h> |
| 22 #include <kern/exc_resource.h> |
| 23 |
| 24 #include "base/logging.h" |
| 25 #include "base/mac/mach_logging.h" |
| 26 #include "util/mac/mac_util.h" |
| 27 |
| 28 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 |
| 29 |
| 30 extern "C" { |
| 31 |
| 32 // proc_get_wakemon_params() is present in the Mac OS X 10.9 SDK, but no |
| 33 // declaration is provided. This provides a declaration and marks it for weak |
| 34 // import if the deployment target is below 10.9. |
| 35 int proc_get_wakemon_params(pid_t pid, int* rate_hz, int* flags) |
| 36 __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0); |
| 37 |
| 38 } // extern "C" |
| 39 |
| 40 #else |
| 41 |
| 42 namespace { |
| 43 |
| 44 using ProcGetWakemonParamsType = int (*)(pid_t, int*, int*); |
| 45 |
| 46 // The SDK doesn’t have proc_get_wakemon_params() to link against, even with |
| 47 // weak import. This function returns a function pointer to it if it exists at |
| 48 // runtime, or nullptr if it doesn’t. proc_get_wakemon_params() is looked up in |
| 49 // the same module that provides proc_pidinfo(). |
| 50 ProcGetWakemonParamsType GetProcGetWakemonParams() { |
| 51 Dl_info dl_info; |
| 52 if (!dladdr(reinterpret_cast<void*>(proc_pidinfo), &dl_info)) { |
| 53 return nullptr; |
| 54 } |
| 55 |
| 56 void* dl_handle = |
| 57 dlopen(dl_info.dli_fname, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); |
| 58 if (!dl_handle) { |
| 59 return nullptr; |
| 60 } |
| 61 |
| 62 ProcGetWakemonParamsType proc_get_wakemon_params = |
| 63 reinterpret_cast<ProcGetWakemonParamsType>( |
| 64 dlsym(dl_handle, "proc_get_wakemon_params")); |
| 65 return proc_get_wakemon_params; |
| 66 } |
| 67 |
| 68 } // namespace |
| 69 |
| 70 #endif |
| 71 |
| 72 namespace { |
| 73 |
| 74 // Wraps proc_get_wakemon_params(), calling it if the system provides it. It’s |
| 75 // present on Mac OS X 10.9 and later. If it’s not available, sets errno to |
| 76 // ENOSYS and returns -1. |
| 77 int ProcGetWakemonParams(pid_t pid, int* rate_hz, int* flags) { |
| 78 #if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9 |
| 79 // proc_get_wakemon_params() isn’t in the SDK. Look it up dynamically. |
| 80 static ProcGetWakemonParamsType proc_get_wakemon_params = |
| 81 GetProcGetWakemonParams(); |
| 82 #endif |
| 83 |
| 84 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9 |
| 85 // proc_get_wakemon_params() is definitely available if the deployment target |
| 86 // is 10.9 or newer. |
| 87 if (!proc_get_wakemon_params) { |
| 88 errno = ENOSYS; |
| 89 return -1; |
| 90 } |
| 91 #endif |
| 92 |
| 93 return proc_get_wakemon_params(pid, rate_hz, flags); |
| 94 } |
| 95 |
| 96 } // namespace |
| 97 |
| 98 namespace crashpad { |
| 99 |
| 100 exception_type_t ExcCrashRecoverOriginalException( |
| 101 mach_exception_code_t code_0, |
| 102 mach_exception_code_t* original_code_0, |
| 103 int* signal) { |
| 104 // 10.9.4 xnu-2422.110.17/bsd/kern/kern_exit.c proc_prepareexit() sets code[0] |
| 105 // based on the signal value, original exception type, and low 20 bits of the |
| 106 // original code[0] before calling xnu-2422.110.17/osfmk/kern/exception.c |
| 107 // task_exception_notify() to raise an EXC_CRASH. |
| 108 // |
| 109 // The list of core-generating signals (as used in proc_prepareexit()’s call |
| 110 // to hassigprop()) is in 10.9.4 xnu-2422.110.17/bsd/sys/signalvar.h sigprop: |
| 111 // entires with SA_CORE are in the set. These signals are SIGQUIT, SIGILL, |
| 112 // SIGTRAP, SIGABRT, SIGEMT, SIGFPE, SIGBUS, SIGSEGV, and SIGSYS. Processes |
| 113 // killed for code-signing reasons will be killed by SIGKILL and are also |
| 114 // eligible for EXC_CRASH handling, but processes killed by SIGKILL for other |
| 115 // reasons are not. |
| 116 if (signal) { |
| 117 *signal = (code_0 >> 24) & 0xff; |
| 118 } |
| 119 |
| 120 if (original_code_0) { |
| 121 *original_code_0 = code_0 & 0xfffff; |
| 122 } |
| 123 |
| 124 return (code_0 >> 20) & 0xf; |
| 125 } |
| 126 |
| 127 bool IsExceptionNonfatalResource(exception_type_t exception, |
| 128 mach_exception_code_t code_0, |
| 129 pid_t pid) { |
| 130 if (exception != EXC_RESOURCE) { |
| 131 return false; |
| 132 } |
| 133 |
| 134 const int resource_type = EXC_RESOURCE_DECODE_RESOURCE_TYPE(code_0); |
| 135 const int resource_flavor = EXC_RESOURCE_DECODE_FLAVOR(code_0); |
| 136 |
| 137 if (resource_type == RESOURCE_TYPE_CPU && |
| 138 (resource_flavor == FLAVOR_CPU_MONITOR || |
| 139 resource_flavor == FLAVOR_CPU_MONITOR_FATAL)) { |
| 140 // These exceptions may be fatal. They are not fatal by default at task |
| 141 // creation but can be made fatal by calling proc_rlimit_control() with |
| 142 // RLIMIT_CPU_USAGE_MONITOR as the second argument and CPUMON_MAKE_FATAL set |
| 143 // in the flags. |
| 144 if (MacOSXMinorVersion() >= 10) { |
| 145 // In Mac OS X 10.10, the exception code indicates whether the exception |
| 146 // is fatal. See 10.10 xnu-2782.1.97/osfmk/kern/thread.c |
| 147 // THIS_THREAD_IS_CONSUMING_TOO_MUCH_CPU__SENDING_EXC_RESOURCE(). |
| 148 return resource_flavor == FLAVOR_CPU_MONITOR; |
| 149 } |
| 150 |
| 151 // In Mac OS X 10.9, there’s no way to determine whether the exception is |
| 152 // fatal. Unlike RESOURCE_TYPE_WAKEUPS below, there’s no way to determine |
| 153 // this outside the kernel. proc_rlimit_control()’s RLIMIT_CPU_USAGE_MONITOR |
| 154 // is the only interface to modify CPUMON_MAKE_FATAL, but it’s only able to |
| 155 // set this bit, not obtain its current value. |
| 156 // |
| 157 // Default to assuming that these exceptions are nonfatal. They are nonfatal |
| 158 // by default and no users of proc_rlimit_control() were found on 10.9.5 |
| 159 // 13F1066 in /System and /usr outside of Metadata.framework and associated |
| 160 // tools. |
| 161 return true; |
| 162 } |
| 163 |
| 164 if (resource_type == RESOURCE_TYPE_WAKEUPS && |
| 165 resource_flavor == FLAVOR_WAKEUPS_MONITOR) { |
| 166 // These exceptions may be fatal. They are not fatal by default at task |
| 167 // creation, but can be made fatal by calling proc_rlimit_control() with |
| 168 // RLIMIT_WAKEUPS_MONITOR as the second argument and WAKEMON_MAKE_FATAL set |
| 169 // in the flags. |
| 170 // |
| 171 // proc_get_wakemon_params() (which calls |
| 172 // through to proc_rlimit_control() with RLIMIT_WAKEUPS_MONITOR) determines |
| 173 // whether these exceptions are fatal. See 10.10 |
| 174 // xnu-2782.1.97/osfmk/kern/task.c |
| 175 // THIS_PROCESS_IS_CAUSING_TOO_MANY_WAKEUPS__SENDING_EXC_RESOURCE(). |
| 176 // |
| 177 // If proc_get_wakemon_params() fails, default to assuming that these |
| 178 // exceptions are nonfatal. They are nonfatal by default and no users of |
| 179 // proc_rlimit_control() were found on 10.9.5 13F1066 in /System and /usr |
| 180 // outside of Metadata.framework and associated tools. |
| 181 int wm_rate; |
| 182 int wm_flags; |
| 183 int rv = ProcGetWakemonParams(pid, &wm_rate, &wm_flags); |
| 184 if (rv < 0) { |
| 185 PLOG(WARNING) << "ProcGetWakemonParams"; |
| 186 return true; |
| 187 } |
| 188 |
| 189 return !(wm_flags & WAKEMON_MAKE_FATAL); |
| 190 } |
| 191 |
| 192 if (resource_type == RESOURCE_TYPE_MEMORY && |
| 193 resource_flavor == FLAVOR_HIGH_WATERMARK) { |
| 194 // These exceptions are never fatal. See 10.10 |
| 195 // xnu-2782.1.97/osfmk/kern/task.c |
| 196 // THIS_PROCESS_CROSSED_HIGH_WATERMARK__SENDING_EXC_RESOURCE(). |
| 197 return true; |
| 198 } |
| 199 |
| 200 // Treat unknown exceptions as fatal. This is the conservative approach: it |
| 201 // may result in more crash reports being generated, but the type-flavor |
| 202 // combinations can be evaluated to determine appropriate handling. |
| 203 LOG(WARNING) << "unknown resource type " << resource_type << " flavor " |
| 204 << resource_flavor; |
| 205 return false; |
| 206 } |
| 207 |
| 208 } // namespace crashpad |
OLD | NEW |