]> git.saurik.com Git - apple/libc.git/blob - libdarwin/exception.c
Libc-1272.250.1.tar.gz
[apple/libc.git] / libdarwin / exception.c
1 /*
2 * Copyright (c) 2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 #include "internal.h"
24
25 #pragma mark Assertions
26 static_assert(_OS_CRASH_LAST < OS_CRASH_PORT_ARRAY_COUNT,
27 "array not large enough");
28
29 #pragma mark Private Utilities
30 static thread_state_flavor_t
31 _exception_thread_state_flavor(void)
32 {
33 thread_state_flavor_t flavor = 0;
34 #if defined(__i386__) || defined(__x86_64__)
35 flavor = x86_THREAD_STATE;
36 #elif defined(__arm__) || defined(__arm64__)
37 flavor = ARM_THREAD_STATE;
38 #else // defined(__i386__) || defined(__x86_64__)
39 #error "unsupported architecture"
40 #endif // defined(__i386__) || defined(__x86_64__)
41 return flavor;
42 }
43
44 static exception_mask_t
45 _exception_mask(os_crash_flags_t flags)
46 {
47 exception_mask_t mask = 0;
48 if (flags & OS_CRASH_FLAG_CRASH) {
49 mask |= EXC_MASK_CRASH;
50 }
51 if (flags & OS_CRASH_FLAG_GUARD) {
52 mask |= EXC_MASK_GUARD;
53 }
54 if (flags & OS_CRASH_FLAG_RESOURCE) {
55 mask |= EXC_MASK_RESOURCE;
56 }
57 if (flags & OS_CRASH_FLAG_CORPSE) {
58 mask |= EXC_MASK_CORPSE_NOTIFY;
59 mask &= (exception_mask_t)(~EXC_MASK_CRASH);
60 }
61 return mask;
62 }
63
64 static exception_behavior_t
65 _exception_behavior(void)
66 {
67 return (EXCEPTION_STATE_IDENTITY|MACH_EXCEPTION_CODES);
68 }
69
70 static void
71 _os_exception_port_set(os_crash_port_t *ep,
72 os_crash_type_t type, mach_port_t p)
73 {
74 kern_return_t kr = KERN_FAILURE;
75
76 ep->oep_type = type;
77 ep->oep_port = p;
78
79 kr = mach_port_mod_refs(mach_task_self(), p, MACH_PORT_RIGHT_SEND, 1);
80 if (kr == KERN_SUCCESS) {
81 ep->oep_port = p;
82 } else {
83 ep->oep_port = MACH_PORT_DEAD;
84 }
85 }
86
87 #pragma mark API
88 kern_return_t
89 os_crash_set_reporter_port(mach_port_t where,
90 os_crash_flags_t flags, mach_port_t p)
91 {
92 kern_return_t kr = KERN_FAILURE;
93 exception_mask_t mask = _exception_mask(flags);
94 exception_behavior_t bhvr = _exception_behavior();
95 thread_state_flavor_t flvr = _exception_thread_state_flavor();
96 mach_port_t host_priv = MACH_PORT_NULL;
97
98 // If we're not privleged to get the host-privileged port, no big deal, then
99 // the comparison below will fail.
100 (void)host_get_host_priv_port(mach_host_self(), &host_priv);
101
102 if (flags == OS_CRASH_FLAG_INIT) {
103 return KERN_SUCCESS;
104 }
105
106 if (where == mach_host_self() || where == host_priv) {
107 kr = host_set_exception_ports(where, mask, p, bhvr, flvr);
108 } else {
109 kr = task_set_exception_ports(where, mask, p, bhvr, flvr);
110 }
111
112 return kr;
113 }
114
115 kern_return_t
116 os_crash_get_reporter_port_array(mach_port_t where, os_crash_port_array_t array)
117 {
118 kern_return_t kr = KERN_FAILURE;
119 exception_mask_t masks[EXC_TYPES_COUNT];
120 mach_msg_type_number_t nmasks = 0;
121 exception_port_t ports[EXC_TYPES_COUNT];
122 exception_behavior_t behaviors[EXC_TYPES_COUNT];
123 thread_state_flavor_t flavors[EXC_TYPES_COUNT];
124 exception_mask_t mask = EXC_MASK_CRASH
125 | EXC_MASK_GUARD
126 | EXC_MASK_RESOURCE
127 | EXC_MASK_CORPSE_NOTIFY;
128 size_t i = 0;
129 size_t j = 0;
130 mach_port_t host_priv = MACH_PORT_NULL;
131
132 (void)host_get_host_priv_port(mach_host_self(), &host_priv);
133
134 if (where == mach_host_self() || where == host_priv) {
135 kr = host_get_exception_ports(mach_host_self(), mask,
136 masks, &nmasks, ports, behaviors, flavors);
137 } else {
138 kr = task_get_exception_ports(where, mask,
139 masks, &nmasks, ports, behaviors, flavors);
140 }
141
142 if (kr) {
143 goto __out;
144 }
145
146 bzero(array, sizeof(array[0]) * OS_CRASH_PORT_ARRAY_COUNT);
147 for (i = 0; i < nmasks; i++) {
148 if (masks[i] & EXC_MASK_CRASH) {
149 _os_exception_port_set(&array[j], OS_CRASH_CRASH, ports[i]);
150 j++;
151 }
152 if (masks[i] & EXC_MASK_GUARD) {
153 _os_exception_port_set(&array[j], OS_CRASH_GUARD, ports[i]);
154 j++;
155 }
156 if (masks[i] & EXC_MASK_RESOURCE) {
157 _os_exception_port_set(&array[j], OS_CRASH_RESOURCE, ports[i]);
158 j++;
159 }
160 if (masks[i] & EXC_MASK_CORPSE_NOTIFY) {
161 _os_exception_port_set(&array[j], OS_CRASH_CORPSE, ports[i]);
162 j++;
163 }
164 kr = mach_port_deallocate(mach_task_self(), ports[i]);
165 os_assert_mach("deallocate port", kr);
166 }
167
168 __out:
169 return kr;
170 }
171
172 void
173 os_crash_port_array_deallocate(os_crash_port_array_t array)
174 {
175 size_t i = 0;
176
177 for (i = 0; i < 16; i++) {
178 if (MACH_PORT_VALID(array[i].oep_port)) {
179 kern_return_t kr = KERN_FAILURE;
180 kr = mach_port_deallocate(mach_task_self(), array[i].oep_port);
181 os_assert_mach("deallocate port", kr);
182 }
183 }
184 }
185
186 kern_return_t
187 os_crash_spawnattr_set_reporter_port(posix_spawnattr_t *psattr,
188 os_crash_flags_t flags, mach_port_t p)
189 {
190 int error = -1;
191 exception_mask_t mask = _exception_mask(flags);
192 exception_behavior_t bhvr = _exception_behavior();
193 thread_state_flavor_t flvr = _exception_thread_state_flavor();
194
195 if (!MACH_PORT_VALID(p)) {
196 return KERN_INVALID_NAME;
197 }
198
199 if (flags == OS_CRASH_FLAG_INIT) {
200 return KERN_SUCCESS;
201 }
202
203 error = posix_spawnattr_setexceptionports_np(psattr, mask, p, bhvr, flvr);
204 os_assert_zero(error);
205
206 return KERN_SUCCESS;
207 }