]> git.saurik.com Git - apple/libplatform.git/blame - private/os/crashlog_private.h
libplatform-254.40.4.tar.gz
[apple/libplatform.git] / private / os / crashlog_private.h
CommitLineData
442fbc9d
A
1/*
2 * Copyright (c) 2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21#ifndef __OS_CRASHLOG_PRIVATE__
22#define __OS_CRASHLOG_PRIVATE__
23
24#include <os/base_private.h>
25
26#if __has_include(<CrashReporterClient.h>)
27#include <CrashReporterClient.h>
28
29#if defined(__x86_64__)
30
31#define __os_set_crash_log_cause_and_message(ac, msg) \
32 ({ long _ac = (long)(ac); __asm__ ( \
33 "mov %[_msg], %[_cr_msg]\n\t" \
34 "mov %[_ac], %[_cr_ac]" \
35 : [_ac] "+&a" (_ac), \
36 [_cr_msg] "=m" (gCRAnnotations.message), \
37 [_cr_ac] "=m" (gCRAnnotations.abort_cause) \
38 : [_msg] "r" (("" msg)) \
39 ); })
40#define _os_set_crash_log_message(msg) \
41 ({ long _clbr; __asm__ ( \
42 "mov %[_msg], %[_cr_msg]" \
43 : "=&a" (_clbr), \
44 [_cr_msg] "=m" (gCRAnnotations.message) \
45 : [_msg] "r" (("" msg)) \
46 ); })
47
48#elif defined(__arm__)
49
50#define __os_set_crash_log_cause_and_message_impl(msg, ac_expr, set_cause, ...) \
51 ({ ac_expr; __asm__( \
52 "push {r9, r10}\n\t" \
53 \
54 "movw r9, :lower16:(%[_msg] - 1f - 4)\n\t" \
55 "movt r9, :upper16:(%[_msg] - 1f - 4)\n" \
56 "1:\n\t" \
57 "add r9, pc\n\t" \
58 \
59 "movw r10, :lower16:(3f - 2f - 4)\n\t" \
60 "movt r10, :upper16:(3f - 2f - 4)\n" \
61 "2:\n\t" \
62 "add r10, pc\n\t" \
63 "ldr r10, [r10]\n\t" \
64 \
65 "str r9, [r10, %[_msgo]]\n\t" \
66 "mov r9, #0\n\t" \
67 "str r9, [r10, %[_msgo] + 4]\n\t" \
68 set_cause \
69 "pop {r9, r10}\n\t" \
70 \
71 ".non_lazy_symbol_pointer\n" \
72 "3:\n\t" \
73 ".indirect_symbol _gCRAnnotations\n\t" \
74 ".long 0\n\t" \
75 ".previous" \
76 :: [_msgo] "i" (__builtin_offsetof(typeof(gCRAnnotations), message)), \
77 [_msg] "i" (("" msg)), \
78 ## __VA_ARGS__); })
79
80#define __os_set_crash_log_cause_and_message(ac, msg) \
81 __os_set_crash_log_cause_and_message_impl(msg, \
82 register long _ac asm("r8") = (long)(ac), \
83 "strd %[_ac], r9, [r10, %[_aco]]\n\t", \
84 [_aco] "i" (__builtin_offsetof(typeof(gCRAnnotations), abort_cause)), \
85 [_ac] "r" (_ac))
86#define _os_set_crash_log_message(msg) \
87 __os_set_crash_log_cause_and_message_impl(msg, (void)0, "")
88
89#elif defined(__arm64__)
90
91#define __os_set_crash_log_cause_and_message_impl(msg, ac_expr, set_cause, ...) \
92 ({ ac_expr; __asm__( \
93 "stp x20, x21, [sp, #-16]!\n\t" \
94 "adrp x20, %[_msg]@PAGE\n\t" \
95 "add x20, x20, %[_msg]@PAGEOFF\n\t" \
96 "adrp x21, %[_cr]@PAGE\n\t" \
97 "add x21, x21, %[_cr]@PAGEOFF\n\t" \
98 "str x20, [x21, %[_msgo]]\n\t" \
99 set_cause \
100 "ldp x20, x21, [sp], #16" \
101 :: [_cr] "i" (&gCRAnnotations), \
102 [_msgo] "i" (__builtin_offsetof(typeof(gCRAnnotations), message)), \
103 [_msg] "i" (("" msg)), \
104 ## __VA_ARGS__); })
105
106#define __os_set_crash_log_cast_ac(ac) \
107 _Generic(ac, \
108 const void *: (uint64_t)(uintptr_t)(ac), \
109 void *: (uint64_t)(uintptr_t)(ac), \
110 default: (uint64_t)(ac))
111
112#define __os_set_crash_log_cause_and_message(ac, msg) \
113 __os_set_crash_log_cause_and_message_impl(msg, \
114 register uint64_t _ac asm("x8") = __os_set_crash_log_cast_ac(ac), \
115 "str %[_ac], [x21, %[_aco]]\n\t", \
116 [_aco] "i" (__builtin_offsetof(typeof(gCRAnnotations), abort_cause)), \
117 [_ac] "r" (_ac))
118#define _os_set_crash_log_message(msg) \
119 __os_set_crash_log_cause_and_message_impl(msg, (void)0, "")
120
121#else
122#define __os_set_crash_log_cause_and_message(ac, msg) ({ \
123 gCRAnnotations.abort_cause = (uint64_t)(int64_t)(ac); \
124 CRSetCrashLogMessage(msg); \
125 })
126#define _os_set_crash_log_message(msg) CRSetCrashLogMessage(msg)
127#endif
128
129/*!
130 * @macro _os_set_crash_log_cause_and_message
131 *
132 * @brief
133 * Set an abort cause and message before likely crash.
134 *
135 * @discussion
136 * This macro is really meant to minimize register clobbering making sure that
137 * the context is minimally touched.
138 *
139 * - On Intel, %rax is used to store the abort cause
140 * - On arm and arm64, r8/x8 is used to store the abort cause, other registers
141 * are left untouched.
142 *
143 * An excellent way to use this macro is for example using a wrapper such
144 * as below:
145 *
146 * <code>
147 * OS_NOINLINE OS_NORETURN OS_COLD
148 * static void
149 * _my_type_corruption_abort(my_type_t object OS_UNUSED,
150 * my_other_type_t other OS_UNUSED, long code)
151 * {
152 * _os_set_crash_log_cause_and_message(code, "object is corrupt");
153 * __builtin_trap();
154 * }
155 * </code>
156 *
157 * That wrapper when used:
158 * - is understood as being unlikely and never inlined (OS_COLD OS_NOINLINE)
159 * - captures the address of @a object as well as the one of the companion
160 * object @a other in registers that are easy to introspect in crash traces
161 * - captures the abort cause / error code
162 *
163 * @param ac
164 * The abort cause to set. If it is statically provably 0, then it's ignored.
165 * If the argument type is narrower than long, then it is sign-extended to long.
166 *
167 * @param msg
168 * The static string message to set
169 */
170#define _os_set_crash_log_cause_and_message(ac, msg) \
171 __builtin_choose_expr(os_is_compile_time_constant(!(ac)), ({ \
172 if (ac) { \
173 __os_set_crash_log_cause_and_message(ac, msg); \
174 } else { \
175 _os_set_crash_log_message(msg); \
176 } }), __os_set_crash_log_cause_and_message(ac, msg))
177
178#define _os_set_crash_log_message_dynamic(msg) CRSetCrashLogMessage(msg)
179
180#else
181
182#define _os_set_crash_log_cause_and_message(ac, msg) ((void)(ac), (void)(msg))
183#define _os_set_crash_log_message(msg) ((void)(msg))
184#define _os_set_crash_log_message_dynamic(msg) ((void)(msg))
185
186#endif // __has_include(<CrashReporterClient.h>)
187
188/*!
189 * @macro OS_BUG_INTERNAL
190 *
191 * @brief
192 * Perform a register-preserving crash due to invalid library invariants.
193 *
194 * @param ac
195 * The abort cause to set (see _os_set_crash_log_cause_and_message).
196 *
197 * @param lib
198 * The name of the library.
199 *
200 * @param msg
201 * The static string message to append.
202 */
203#define OS_BUG_INTERNAL(ac, lib, msg) ({ \
204 _os_set_crash_log_cause_and_message(ac, "BUG IN " lib ": " msg); \
205 os_prevent_tail_call_optimization(); \
206 __builtin_trap(); \
207})
208
209/*!
210 * @macro OS_BUG_CLIENT
211 *
212 * @brief
213 * Perform a register-preserving crash due to an API misuse by a library client.
214 *
215 * @param ac
216 * The abort cause to set (see _os_set_crash_log_cause_and_message).
217 *
218 * @param lib
219 * The name of the library.
220 *
221 * @param msg
222 * The static string message to append.
223 */
224#define OS_BUG_CLIENT(ac, lib, msg) ({ \
225 _os_set_crash_log_cause_and_message(ac, "BUG IN CLIENT OF " lib ": " msg); \
226 os_prevent_tail_call_optimization(); \
227 __builtin_trap(); \
228})
229
230#endif // __OS_CRASHLOG_PRIVATE__