]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===-- asan_mac.cc -------------------------------------------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file is a part of AddressSanitizer, an address sanity checker. | |
11 | // | |
12 | // Mac-specific details. | |
13 | //===----------------------------------------------------------------------===// | |
14 | ||
15 | #include "sanitizer_common/sanitizer_platform.h" | |
16 | #if SANITIZER_MAC | |
17 | ||
18 | #include "asan_interceptors.h" | |
19 | #include "asan_internal.h" | |
20 | #include "asan_mapping.h" | |
21 | #include "asan_stack.h" | |
22 | #include "asan_thread.h" | |
23 | #include "sanitizer_common/sanitizer_atomic.h" | |
24 | #include "sanitizer_common/sanitizer_libc.h" | |
25 | #include "sanitizer_common/sanitizer_mac.h" | |
26 | ||
5bcae85e | 27 | #include <dlfcn.h> |
92a42be0 SL |
28 | #include <fcntl.h> |
29 | #include <libkern/OSAtomic.h> | |
1a4d82fc | 30 | #include <mach-o/dyld.h> |
5bcae85e | 31 | #include <mach-o/getsect.h> |
1a4d82fc | 32 | #include <mach-o/loader.h> |
92a42be0 SL |
33 | #include <pthread.h> |
34 | #include <stdlib.h> // for free() | |
1a4d82fc JJ |
35 | #include <sys/mman.h> |
36 | #include <sys/resource.h> | |
37 | #include <sys/sysctl.h> | |
38 | #include <sys/ucontext.h> | |
1a4d82fc | 39 | #include <unistd.h> |
1a4d82fc | 40 | |
5bcae85e SL |
41 | // from <crt_externs.h>, but we don't have that file on iOS |
42 | extern "C" { | |
43 | extern char ***_NSGetArgv(void); | |
44 | extern char ***_NSGetEnviron(void); | |
45 | } | |
46 | ||
1a4d82fc JJ |
47 | namespace __asan { |
48 | ||
92a42be0 | 49 | void InitializePlatformInterceptors() {} |
5bcae85e | 50 | void InitializePlatformExceptionHandlers() {} |
1a4d82fc JJ |
51 | |
52 | bool PlatformHasDifferentMemcpyAndMemmove() { | |
53 | // On OS X 10.7 memcpy() and memmove() are both resolved | |
54 | // into memmove$VARIANT$sse42. | |
3157f602 | 55 | // See also https://github.com/google/sanitizers/issues/34. |
1a4d82fc JJ |
56 | // TODO(glider): need to check dynamically that memcpy() and memmove() are |
57 | // actually the same function. | |
58 | return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; | |
59 | } | |
60 | ||
1a4d82fc JJ |
61 | // No-op. Mac does not support static linkage anyway. |
62 | void *AsanDoesNotSupportStaticLinkage() { | |
63 | return 0; | |
64 | } | |
65 | ||
66 | // No-op. Mac does not support static linkage anyway. | |
67 | void AsanCheckDynamicRTPrereqs() {} | |
68 | ||
69 | // No-op. Mac does not support static linkage anyway. | |
70 | void AsanCheckIncompatibleRT() {} | |
71 | ||
5bcae85e SL |
72 | void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { |
73 | // Find the Mach-O header for the image containing the needle | |
74 | Dl_info info; | |
75 | int err = dladdr(needle, &info); | |
76 | if (err == 0) return; | |
77 | ||
78 | #if __LP64__ | |
79 | const struct mach_header_64 *mh = (struct mach_header_64 *)info.dli_fbase; | |
80 | #else | |
81 | const struct mach_header *mh = (struct mach_header *)info.dli_fbase; | |
82 | #endif | |
83 | ||
84 | // Look up the __asan_globals section in that image and register its globals | |
85 | unsigned long size = 0; | |
86 | __asan_global *globals = (__asan_global *)getsectiondata( | |
87 | mh, | |
88 | "__DATA", "__asan_globals", | |
89 | &size); | |
90 | ||
91 | if (!globals) return; | |
92 | if (size % sizeof(__asan_global) != 0) return; | |
93 | op(globals, size / sizeof(__asan_global)); | |
94 | } | |
95 | ||
1a4d82fc JJ |
96 | void ReadContextStack(void *context, uptr *stack, uptr *ssize) { |
97 | UNIMPLEMENTED(); | |
98 | } | |
99 | ||
100 | // Support for the following functions from libdispatch on Mac OS: | |
101 | // dispatch_async_f() | |
102 | // dispatch_async() | |
103 | // dispatch_sync_f() | |
104 | // dispatch_sync() | |
105 | // dispatch_after_f() | |
106 | // dispatch_after() | |
107 | // dispatch_group_async_f() | |
108 | // dispatch_group_async() | |
109 | // TODO(glider): libdispatch API contains other functions that we don't support | |
110 | // yet. | |
111 | // | |
112 | // dispatch_sync() and dispatch_sync_f() are synchronous, although chances are | |
113 | // they can cause jobs to run on a thread different from the current one. | |
114 | // TODO(glider): if so, we need a test for this (otherwise we should remove | |
115 | // them). | |
116 | // | |
117 | // The following functions use dispatch_barrier_async_f() (which isn't a library | |
118 | // function but is exported) and are thus supported: | |
119 | // dispatch_source_set_cancel_handler_f() | |
120 | // dispatch_source_set_cancel_handler() | |
121 | // dispatch_source_set_event_handler_f() | |
122 | // dispatch_source_set_event_handler() | |
123 | // | |
124 | // The reference manual for Grand Central Dispatch is available at | |
125 | // http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html | |
126 | // The implementation details are at | |
127 | // http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c | |
128 | ||
129 | typedef void* dispatch_group_t; | |
130 | typedef void* dispatch_queue_t; | |
131 | typedef void* dispatch_source_t; | |
132 | typedef u64 dispatch_time_t; | |
133 | typedef void (*dispatch_function_t)(void *block); | |
134 | typedef void* (*worker_t)(void *block); | |
135 | ||
136 | // A wrapper for the ObjC blocks used to support libdispatch. | |
137 | typedef struct { | |
138 | void *block; | |
139 | dispatch_function_t func; | |
140 | u32 parent_tid; | |
141 | } asan_block_context_t; | |
142 | ||
143 | ALWAYS_INLINE | |
144 | void asan_register_worker_thread(int parent_tid, StackTrace *stack) { | |
145 | AsanThread *t = GetCurrentThread(); | |
146 | if (!t) { | |
92a42be0 SL |
147 | t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr, |
148 | parent_tid, stack, /* detached */ true); | |
1a4d82fc JJ |
149 | t->Init(); |
150 | asanThreadRegistry().StartThread(t->tid(), 0, 0); | |
151 | SetCurrentThread(t); | |
152 | } | |
153 | } | |
154 | ||
155 | // For use by only those functions that allocated the context via | |
156 | // alloc_asan_context(). | |
157 | extern "C" | |
158 | void asan_dispatch_call_block_and_release(void *block) { | |
159 | GET_STACK_TRACE_THREAD; | |
160 | asan_block_context_t *context = (asan_block_context_t*)block; | |
161 | VReport(2, | |
162 | "asan_dispatch_call_block_and_release(): " | |
163 | "context: %p, pthread_self: %p\n", | |
164 | block, pthread_self()); | |
165 | asan_register_worker_thread(context->parent_tid, &stack); | |
166 | // Call the original dispatcher for the block. | |
167 | context->func(context->block); | |
168 | asan_free(context, &stack, FROM_MALLOC); | |
169 | } | |
170 | ||
171 | } // namespace __asan | |
172 | ||
173 | using namespace __asan; // NOLINT | |
174 | ||
175 | // Wrap |ctxt| and |func| into an asan_block_context_t. | |
176 | // The caller retains control of the allocated context. | |
177 | extern "C" | |
178 | asan_block_context_t *alloc_asan_context(void *ctxt, dispatch_function_t func, | |
92a42be0 | 179 | BufferedStackTrace *stack) { |
1a4d82fc JJ |
180 | asan_block_context_t *asan_ctxt = |
181 | (asan_block_context_t*) asan_malloc(sizeof(asan_block_context_t), stack); | |
182 | asan_ctxt->block = ctxt; | |
183 | asan_ctxt->func = func; | |
184 | asan_ctxt->parent_tid = GetCurrentTidOrInvalid(); | |
185 | return asan_ctxt; | |
186 | } | |
187 | ||
188 | // Define interceptor for dispatch_*_f function with the three most common | |
189 | // parameters: dispatch_queue_t, context, dispatch_function_t. | |
190 | #define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \ | |
191 | INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \ | |
192 | dispatch_function_t func) { \ | |
193 | GET_STACK_TRACE_THREAD; \ | |
194 | asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); \ | |
92a42be0 | 195 | if (Verbosity() >= 2) { \ |
1a4d82fc JJ |
196 | Report(#dispatch_x_f "(): context: %p, pthread_self: %p\n", \ |
197 | asan_ctxt, pthread_self()); \ | |
198 | PRINT_CURRENT_STACK(); \ | |
199 | } \ | |
200 | return REAL(dispatch_x_f)(dq, (void*)asan_ctxt, \ | |
201 | asan_dispatch_call_block_and_release); \ | |
202 | } | |
203 | ||
204 | INTERCEPT_DISPATCH_X_F_3(dispatch_async_f) | |
205 | INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f) | |
206 | INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f) | |
207 | ||
208 | INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, | |
209 | dispatch_queue_t dq, void *ctxt, | |
210 | dispatch_function_t func) { | |
211 | GET_STACK_TRACE_THREAD; | |
212 | asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); | |
92a42be0 | 213 | if (Verbosity() >= 2) { |
1a4d82fc JJ |
214 | Report("dispatch_after_f: %p\n", asan_ctxt); |
215 | PRINT_CURRENT_STACK(); | |
216 | } | |
217 | return REAL(dispatch_after_f)(when, dq, (void*)asan_ctxt, | |
218 | asan_dispatch_call_block_and_release); | |
219 | } | |
220 | ||
221 | INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group, | |
222 | dispatch_queue_t dq, void *ctxt, | |
223 | dispatch_function_t func) { | |
224 | GET_STACK_TRACE_THREAD; | |
225 | asan_block_context_t *asan_ctxt = alloc_asan_context(ctxt, func, &stack); | |
92a42be0 | 226 | if (Verbosity() >= 2) { |
1a4d82fc JJ |
227 | Report("dispatch_group_async_f(): context: %p, pthread_self: %p\n", |
228 | asan_ctxt, pthread_self()); | |
229 | PRINT_CURRENT_STACK(); | |
230 | } | |
231 | REAL(dispatch_group_async_f)(group, dq, (void*)asan_ctxt, | |
232 | asan_dispatch_call_block_and_release); | |
233 | } | |
234 | ||
235 | #if !defined(MISSING_BLOCKS_SUPPORT) | |
236 | extern "C" { | |
237 | void dispatch_async(dispatch_queue_t dq, void(^work)(void)); | |
238 | void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq, | |
239 | void(^work)(void)); | |
240 | void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, | |
241 | void(^work)(void)); | |
242 | void dispatch_source_set_cancel_handler(dispatch_source_t ds, | |
243 | void(^work)(void)); | |
244 | void dispatch_source_set_event_handler(dispatch_source_t ds, void(^work)(void)); | |
245 | } | |
246 | ||
247 | #define GET_ASAN_BLOCK(work) \ | |
248 | void (^asan_block)(void); \ | |
249 | int parent_tid = GetCurrentTidOrInvalid(); \ | |
250 | asan_block = ^(void) { \ | |
251 | GET_STACK_TRACE_THREAD; \ | |
252 | asan_register_worker_thread(parent_tid, &stack); \ | |
253 | work(); \ | |
254 | } | |
255 | ||
256 | INTERCEPTOR(void, dispatch_async, | |
257 | dispatch_queue_t dq, void(^work)(void)) { | |
92a42be0 | 258 | ENABLE_FRAME_POINTER; |
1a4d82fc JJ |
259 | GET_ASAN_BLOCK(work); |
260 | REAL(dispatch_async)(dq, asan_block); | |
261 | } | |
262 | ||
263 | INTERCEPTOR(void, dispatch_group_async, | |
264 | dispatch_group_t dg, dispatch_queue_t dq, void(^work)(void)) { | |
92a42be0 | 265 | ENABLE_FRAME_POINTER; |
1a4d82fc JJ |
266 | GET_ASAN_BLOCK(work); |
267 | REAL(dispatch_group_async)(dg, dq, asan_block); | |
268 | } | |
269 | ||
270 | INTERCEPTOR(void, dispatch_after, | |
271 | dispatch_time_t when, dispatch_queue_t queue, void(^work)(void)) { | |
92a42be0 | 272 | ENABLE_FRAME_POINTER; |
1a4d82fc JJ |
273 | GET_ASAN_BLOCK(work); |
274 | REAL(dispatch_after)(when, queue, asan_block); | |
275 | } | |
276 | ||
277 | INTERCEPTOR(void, dispatch_source_set_cancel_handler, | |
278 | dispatch_source_t ds, void(^work)(void)) { | |
92a42be0 SL |
279 | if (!work) { |
280 | REAL(dispatch_source_set_cancel_handler)(ds, work); | |
281 | return; | |
282 | } | |
283 | ENABLE_FRAME_POINTER; | |
1a4d82fc JJ |
284 | GET_ASAN_BLOCK(work); |
285 | REAL(dispatch_source_set_cancel_handler)(ds, asan_block); | |
286 | } | |
287 | ||
288 | INTERCEPTOR(void, dispatch_source_set_event_handler, | |
289 | dispatch_source_t ds, void(^work)(void)) { | |
92a42be0 | 290 | ENABLE_FRAME_POINTER; |
1a4d82fc JJ |
291 | GET_ASAN_BLOCK(work); |
292 | REAL(dispatch_source_set_event_handler)(ds, asan_block); | |
293 | } | |
294 | #endif | |
295 | ||
296 | #endif // SANITIZER_MAC |