]>
Commit | Line | Data |
---|---|---|
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__ |