2 * Copyright (c) 2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 #pragma mark Assertions
26 static_assert(_OS_CRASH_LAST
< OS_CRASH_PORT_ARRAY_COUNT
,
27 "array not large enough");
29 #pragma mark Private Utilities
30 static thread_state_flavor_t
31 _exception_thread_state_flavor(void)
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__)
44 static exception_mask_t
45 _exception_mask(os_crash_flags_t flags
)
47 exception_mask_t mask
= 0;
48 if (flags
& OS_CRASH_FLAG_CRASH
) {
49 mask
|= EXC_MASK_CRASH
;
51 if (flags
& OS_CRASH_FLAG_GUARD
) {
52 mask
|= EXC_MASK_GUARD
;
54 if (flags
& OS_CRASH_FLAG_RESOURCE
) {
55 mask
|= EXC_MASK_RESOURCE
;
57 if (flags
& OS_CRASH_FLAG_CORPSE
) {
58 mask
|= EXC_MASK_CORPSE_NOTIFY
;
59 mask
&= (exception_mask_t
)(~EXC_MASK_CRASH
);
64 static exception_behavior_t
65 _exception_behavior(void)
67 return (EXCEPTION_STATE_IDENTITY
|MACH_EXCEPTION_CODES
);
71 _os_exception_port_set(os_crash_port_t
*ep
,
72 os_crash_type_t type
, mach_port_t p
)
74 kern_return_t kr
= KERN_FAILURE
;
79 kr
= mach_port_mod_refs(mach_task_self(), p
, MACH_PORT_RIGHT_SEND
, 1);
80 if (kr
== KERN_SUCCESS
) {
83 ep
->oep_port
= MACH_PORT_DEAD
;
89 os_crash_set_reporter_port(mach_port_t where
,
90 os_crash_flags_t flags
, mach_port_t p
)
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
;
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
);
102 if (flags
== OS_CRASH_FLAG_INIT
) {
106 if (where
== mach_host_self() || where
== host_priv
) {
107 kr
= host_set_exception_ports(where
, mask
, p
, bhvr
, flvr
);
109 kr
= task_set_exception_ports(where
, mask
, p
, bhvr
, flvr
);
116 os_crash_get_reporter_port_array(mach_port_t where
, os_crash_port_array_t array
)
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
127 | EXC_MASK_CORPSE_NOTIFY
;
130 mach_port_t host_priv
= MACH_PORT_NULL
;
132 (void)host_get_host_priv_port(mach_host_self(), &host_priv
);
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
);
138 kr
= task_get_exception_ports(where
, mask
,
139 masks
, &nmasks
, ports
, behaviors
, flavors
);
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
]);
152 if (masks
[i
] & EXC_MASK_GUARD
) {
153 _os_exception_port_set(&array
[j
], OS_CRASH_GUARD
, ports
[i
]);
156 if (masks
[i
] & EXC_MASK_RESOURCE
) {
157 _os_exception_port_set(&array
[j
], OS_CRASH_RESOURCE
, ports
[i
]);
160 if (masks
[i
] & EXC_MASK_CORPSE_NOTIFY
) {
161 _os_exception_port_set(&array
[j
], OS_CRASH_CORPSE
, ports
[i
]);
164 kr
= mach_port_deallocate(mach_task_self(), ports
[i
]);
165 os_assert_mach("deallocate port", kr
);
173 os_crash_port_array_deallocate(os_crash_port_array_t array
)
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
);
187 os_crash_spawnattr_set_reporter_port(posix_spawnattr_t
*psattr
,
188 os_crash_flags_t flags
, mach_port_t p
)
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();
195 if (!MACH_PORT_VALID(p
)) {
196 return KERN_INVALID_NAME
;
199 if (flags
== OS_CRASH_FLAG_INIT
) {
203 error
= posix_spawnattr_setexceptionports_np(psattr
, mask
, p
, bhvr
, flvr
);
204 os_assert_zero(error
);