1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ProcessRedirect.h"
9 #include "mozilla/Maybe.h"
11 #include "HashTable.h"
13 #include "MemorySnapshot.h"
14 #include "ProcessRecordReplay.h"
15 #include "ProcessRewind.h"
16 #include "base/eintr_wrapper.h"
22 #include <bsm/audit.h>
23 #include <bsm/audit_session.h>
24 #include <mach/clock.h>
25 #include <mach/mach.h>
26 #include <mach/mach_time.h>
27 #include <mach/mach_vm.h>
28 #include <mach/vm_map.h>
30 #include <sys/event.h>
32 #include <sys/mount.h>
33 #include <sys/param.h>
38 #include <Carbon/Carbon.h>
39 #include <SystemConfiguration/SystemConfiguration.h>
40 #include <objc/objc-runtime.h>
43 namespace recordreplay
{
45 // Specify every function that is being redirected. MACRO is invoked with the
46 // function's name, followed by any hooks associated with the redirection for
47 // saving its output or adding a preamble.
48 #define FOR_EACH_REDIRECTION(MACRO) \
49 /* System call wrappers */ \
50 MACRO(kevent, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<3, 4, struct kevent>>) \
51 MACRO(kevent64, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<3, 4, struct kevent64_s>>) \
52 MACRO(mprotect, nullptr, Preamble_mprotect) \
53 MACRO(mmap, nullptr, Preamble_mmap) \
54 MACRO(munmap, nullptr, Preamble_munmap) \
55 MACRO(read, RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>) \
56 MACRO(__read_nocancel, RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>) \
57 MACRO(pread, RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>) \
58 MACRO(write, RR_SaveRvalHadErrorNegative) \
59 MACRO(__write_nocancel, RR_SaveRvalHadErrorNegative) \
60 MACRO(open, RR_SaveRvalHadErrorNegative) \
61 MACRO(__open_nocancel, RR_SaveRvalHadErrorNegative) \
62 MACRO(recv, RR_SaveRvalHadErrorNegative<RR_WriteBufferViaRval<1, 2>>) \
63 MACRO(recvmsg, RR_SaveRvalHadErrorNegative<RR_recvmsg>) \
64 MACRO(sendmsg, RR_SaveRvalHadErrorNegative) \
65 MACRO(shm_open, RR_SaveRvalHadErrorNegative) \
66 MACRO(socket, RR_SaveRvalHadErrorNegative) \
67 MACRO(kqueue, RR_SaveRvalHadErrorNegative) \
68 MACRO(pipe, RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, 2 * sizeof(int)>>) \
69 MACRO(close, RR_SaveRvalHadErrorNegative) \
70 MACRO(__close_nocancel, RR_SaveRvalHadErrorNegative) \
71 MACRO(mkdir, RR_SaveRvalHadErrorNegative) \
72 MACRO(dup, RR_SaveRvalHadErrorNegative) \
73 MACRO(access, RR_SaveRvalHadErrorNegative) \
74 MACRO(lseek, RR_SaveRvalHadErrorNegative) \
75 MACRO(socketpair, RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<3, 2 * sizeof(int)>>) \
76 MACRO(fileport_makeport, \
77 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(size_t)>>) \
78 MACRO(getsockopt, RR_SaveRvalHadErrorNegative<RR_getsockopt>) \
79 MACRO(gettimeofday, RR_SaveRvalHadErrorNegative<RR_Compose< \
80 RR_WriteOptionalBufferFixedSize<0, sizeof(struct timeval)>, \
81 RR_WriteOptionalBufferFixedSize<1, sizeof(struct timezone)>>>, \
82 nullptr, nullptr, Preamble_PassThrough) \
83 MACRO(getuid, RR_ScalarRval) \
84 MACRO(geteuid, RR_ScalarRval) \
85 MACRO(getgid, RR_ScalarRval) \
86 MACRO(getegid, RR_ScalarRval) \
87 MACRO(issetugid, RR_ScalarRval) \
88 MACRO(__gettid, RR_ScalarRval) \
89 MACRO(getpid, nullptr, Preamble_getpid) \
90 MACRO(fcntl, RR_SaveRvalHadErrorNegative, Preamble_fcntl) \
91 MACRO(getattrlist, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<2, 3>>) \
92 MACRO(fstat$INODE64, \
93 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>, \
94 nullptr, nullptr, Preamble_SetError) \
95 MACRO(lstat$INODE64, \
96 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>, \
97 nullptr, nullptr, Preamble_SetError) \
99 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct stat)>>, \
100 nullptr, nullptr, Preamble_SetError) \
101 MACRO(statfs$INODE64, \
102 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct statfs)>>, \
103 nullptr, nullptr, Preamble_SetError) \
104 MACRO(fstatfs$INODE64, \
105 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct statfs)>>, \
106 nullptr, nullptr, Preamble_SetError) \
107 MACRO(readlink, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<1, 2>>) \
108 MACRO(__getdirentries64, RR_SaveRvalHadErrorNegative<RR_Compose< \
109 RR_WriteBuffer<1, 2>, \
110 RR_WriteBufferFixedSize<3, sizeof(size_t)>>>) \
111 MACRO(getdirentriesattr, RR_SaveRvalHadErrorNegative<RR_Compose< \
112 RR_WriteBufferFixedSize<1, sizeof(struct attrlist)>, \
113 RR_WriteBuffer<2, 3>, \
114 RR_WriteBufferFixedSize<4, sizeof(size_t)>, \
115 RR_WriteBufferFixedSize<5, sizeof(size_t)>, \
116 RR_WriteBufferFixedSize<6, sizeof(size_t)>>>) \
118 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct rusage)>>) \
120 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct rlimit)>>) \
121 MACRO(__setrlimit, RR_SaveRvalHadErrorNegative) \
123 RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(sigset_t)>>, \
124 nullptr, nullptr, Preamble_PassThrough) \
126 RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(stack_t)>>) \
128 RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(struct sigaction)>>) \
129 MACRO(__pthread_sigmask, \
130 RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(sigset_t)>>) \
131 MACRO(__fsgetpath, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<0, 1>>) \
132 MACRO(__disable_threadsignal, nullptr, Preamble___disable_threadsignal) \
133 MACRO(__sysctl, RR_SaveRvalHadErrorNegative<RR___sysctl>) \
134 MACRO(__mac_syscall, RR_SaveRvalHadErrorNegative) \
135 MACRO(getaudit_addr, \
136 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, sizeof(auditinfo_addr_t)>>) \
137 MACRO(umask, RR_ScalarRval) \
138 MACRO(__select, RR_SaveRvalHadErrorNegative<RR_Compose< \
139 RR_WriteBufferFixedSize<1, sizeof(fd_set)>, \
140 RR_WriteBufferFixedSize<2, sizeof(fd_set)>, \
141 RR_WriteBufferFixedSize<3, sizeof(fd_set)>, \
142 RR_WriteOptionalBufferFixedSize<4, sizeof(timeval)>>>) \
143 MACRO(__process_policy, RR_SaveRvalHadErrorNegative) \
144 MACRO(__kdebug_trace, RR_SaveRvalHadErrorNegative) \
145 MACRO(guarded_kqueue_np, \
146 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<0, sizeof(size_t)>>) \
147 MACRO(csops, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<2, 3>>) \
148 MACRO(__getlogin, RR_SaveRvalHadErrorNegative<RR_WriteBuffer<0, 1>>) \
149 MACRO(__workq_kernreturn, nullptr, Preamble___workq_kernreturn) \
150 MACRO(start_wqthread, nullptr, Preamble_start_wqthread) \
151 /* pthreads interface functions */ \
152 MACRO(pthread_cond_wait, nullptr, Preamble_pthread_cond_wait) \
153 MACRO(pthread_cond_timedwait, nullptr, Preamble_pthread_cond_timedwait) \
154 MACRO(pthread_cond_timedwait_relative_np, nullptr, Preamble_pthread_cond_timedwait_relative_np) \
155 MACRO(pthread_create, nullptr, Preamble_pthread_create, nullptr, Preamble_SetError) \
156 MACRO(pthread_join, nullptr, Preamble_pthread_join) \
157 MACRO(pthread_mutex_init, nullptr, Preamble_pthread_mutex_init) \
158 MACRO(pthread_mutex_destroy, nullptr, Preamble_pthread_mutex_destroy) \
159 MACRO(pthread_mutex_lock, nullptr, Preamble_pthread_mutex_lock) \
160 MACRO(pthread_mutex_trylock, nullptr, Preamble_pthread_mutex_trylock) \
161 MACRO(pthread_mutex_unlock, nullptr, Preamble_pthread_mutex_unlock) \
162 /* C Library functions */ \
163 MACRO(dlclose, nullptr, Preamble_Veto<0>) \
164 MACRO(dlopen, nullptr, Preamble_PassThrough) \
165 MACRO(dlsym, nullptr, Preamble_PassThrough) \
166 MACRO(fclose, RR_SaveRvalHadErrorNegative) \
167 MACRO(fopen, RR_SaveRvalHadErrorZero) \
168 MACRO(fread, RR_Compose<RR_ScalarRval, RR_fread>) \
169 MACRO(fseek, RR_SaveRvalHadErrorNegative) \
170 MACRO(ftell, RR_SaveRvalHadErrorNegative) \
171 MACRO(fwrite, RR_ScalarRval) \
172 MACRO(getenv, RR_CStringRval, nullptr, nullptr, Preamble_Veto<0>) \
173 MACRO(localtime_r, RR_SaveRvalHadErrorZero<RR_Compose< \
174 RR_WriteBufferFixedSize<1, sizeof(struct tm)>, \
175 RR_RvalIsArgument<1>>>) \
176 MACRO(gmtime_r, RR_SaveRvalHadErrorZero<RR_Compose< \
177 RR_WriteBufferFixedSize<1, sizeof(struct tm)>, \
178 RR_RvalIsArgument<1>>>) \
179 MACRO(localtime, nullptr, Preamble_localtime) \
180 MACRO(gmtime, nullptr, Preamble_gmtime) \
181 MACRO(mktime, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(struct tm)>>) \
182 MACRO(setlocale, RR_CStringRval) \
183 MACRO(strftime, RR_Compose<RR_ScalarRval, RR_WriteBufferViaRval<0, 1, 1>>) \
184 MACRO(arc4random, RR_ScalarRval) \
185 MACRO(mach_absolute_time, RR_ScalarRval, Preamble_mach_absolute_time, \
186 nullptr, Preamble_PassThrough) \
187 MACRO(mach_msg, RR_Compose<RR_ScalarRval, RR_WriteBuffer<0, 3>>) \
188 MACRO(mach_timebase_info, \
189 RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(mach_timebase_info_data_t)>>) \
190 MACRO(mach_vm_allocate, nullptr, Preamble_mach_vm_allocate) \
191 MACRO(mach_vm_deallocate, nullptr, Preamble_mach_vm_deallocate) \
192 MACRO(mach_vm_protect, nullptr, Preamble_mach_vm_protect) \
194 RR_SaveRvalHadErrorZero<RR_Compose<RR_CStringRval, \
195 RR_WriteOptionalBufferFixedSize<1, PATH_MAX>>>) \
196 MACRO(realpath$DARWIN_EXTSN, \
197 RR_SaveRvalHadErrorZero<RR_Compose<RR_CStringRval, \
198 RR_WriteOptionalBufferFixedSize<1, PATH_MAX>>>) \
199 /* By passing through events when initializing the sandbox, we ensure both */ \
200 /* that we actually initialize the process sandbox while replaying as well as */ \
201 /* while recording, and that any activity in these calls does not interfere */ \
202 /* with the replay. */ \
203 MACRO(sandbox_init, nullptr, Preamble_PassThrough) \
204 MACRO(sandbox_init_with_parameters, nullptr, Preamble_PassThrough) \
205 /* Make sure events are passed through here so that replaying processes can */ \
206 /* inspect their own threads. */ \
207 MACRO(task_threads, nullptr, Preamble_PassThrough) \
208 MACRO(vm_copy, nullptr, Preamble_vm_copy) \
209 MACRO(vm_purgable_control, nullptr, Preamble_vm_purgable_control) \
211 /* NSPR functions */ \
212 MACRO(PL_NewHashTable, nullptr, Preamble_PL_NewHashTable) \
213 MACRO(PL_HashTableDestroy, nullptr, Preamble_PL_HashTableDestroy) \
214 /* Objective C functions */ \
215 MACRO(class_getClassMethod, RR_ScalarRval) \
216 MACRO(class_getInstanceMethod, RR_ScalarRval) \
217 MACRO(method_exchangeImplementations) \
218 MACRO(objc_autoreleasePoolPop) \
219 MACRO(objc_autoreleasePoolPush, RR_ScalarRval) \
220 MACRO(objc_msgSend, RR_objc_msgSend, Preamble_objc_msgSend, \
221 Middleman_objc_msgSend, MiddlemanPreamble_objc_msgSend) \
222 /* Cocoa functions */ \
223 MACRO(AcquireFirstMatchingEventInQueue, RR_ScalarRval) \
224 MACRO(CFArrayAppendValue) \
225 MACRO(CFArrayCreate, RR_ScalarRval, nullptr, Middleman_CFArrayCreate) \
226 MACRO(CFArrayGetCount, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
227 MACRO(CFArrayGetValueAtIndex, RR_ScalarRval, nullptr, Middleman_CFArrayGetValueAtIndex) \
228 MACRO(CFArrayRemoveValueAtIndex) \
229 MACRO(CFAttributedStringCreate, RR_ScalarRval, nullptr, \
230 Middleman_Compose<Middleman_CFTypeArg<1>, Middleman_CFTypeArg<2>, Middleman_CreateCFTypeRval>) \
231 MACRO(CFBundleCopyExecutableURL, RR_ScalarRval) \
232 MACRO(CFBundleCopyInfoDictionaryForURL, RR_ScalarRval) \
233 MACRO(CFBundleCreate, RR_ScalarRval) \
234 MACRO(CFBundleGetBundleWithIdentifier, RR_ScalarRval) \
235 MACRO(CFBundleGetDataPointerForName, nullptr, Preamble_VetoIfNotPassedThrough<0>) \
236 MACRO(CFBundleGetFunctionPointerForName, nullptr, Preamble_VetoIfNotPassedThrough<0>) \
237 MACRO(CFBundleGetIdentifier, RR_ScalarRval) \
238 MACRO(CFBundleGetInfoDictionary, RR_ScalarRval) \
239 MACRO(CFBundleGetMainBundle, RR_ScalarRval) \
240 MACRO(CFBundleGetValueForInfoDictionaryKey, RR_ScalarRval) \
241 MACRO(CFDataGetBytePtr, RR_CFDataGetBytePtr, nullptr, Middleman_CFDataGetBytePtr) \
242 MACRO(CFDataGetLength, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
243 MACRO(CFDateFormatterCreate, RR_ScalarRval) \
244 MACRO(CFDateFormatterGetFormat, RR_ScalarRval) \
245 MACRO(CFDictionaryAddValue, nullptr, nullptr, \
246 Middleman_Compose<Middleman_UpdateCFTypeArg<0>, \
247 Middleman_CFTypeArg<1>, \
248 Middleman_CFTypeArg<2>>) \
249 MACRO(CFDictionaryCreate, RR_ScalarRval, nullptr, Middleman_CFDictionaryCreate) \
250 MACRO(CFDictionaryCreateMutable, RR_ScalarRval, nullptr, Middleman_CreateCFTypeRval) \
251 MACRO(CFDictionaryCreateMutableCopy, RR_ScalarRval, nullptr, \
252 Middleman_Compose<Middleman_CFTypeArg<2>, Middleman_CreateCFTypeRval>) \
253 MACRO(CFDictionaryGetValue, RR_ScalarRval, nullptr, \
254 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CFTypeRval>) \
255 MACRO(CFDictionaryGetValueIfPresent, \
256 RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<2, sizeof(const void*)>>, nullptr, \
257 Middleman_Compose<Middleman_CFTypeArg<0>, \
258 Middleman_CFTypeArg<1>, \
259 Middleman_CFTypeOutputArg<2>>) \
260 MACRO(CFDictionaryReplaceValue, nullptr, nullptr, \
261 Middleman_Compose<Middleman_UpdateCFTypeArg<0>, \
262 Middleman_CFTypeArg<1>, \
263 Middleman_CFTypeArg<2>>) \
264 MACRO(CFEqual, RR_ScalarRval, nullptr, \
265 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>>) \
266 MACRO(CFGetTypeID, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
267 MACRO(CFLocaleCopyCurrent, RR_ScalarRval) \
268 MACRO(CFLocaleCopyPreferredLanguages, RR_ScalarRval) \
269 MACRO(CFLocaleCreate, RR_ScalarRval) \
270 MACRO(CFLocaleGetIdentifier, RR_ScalarRval) \
271 MACRO(CFNotificationCenterAddObserver, nullptr, Preamble_CFNotificationCenterAddObserver) \
272 MACRO(CFNotificationCenterGetLocalCenter, RR_ScalarRval) \
273 MACRO(CFNotificationCenterRemoveObserver) \
274 MACRO(CFNumberCreate, RR_ScalarRval, nullptr, Middleman_CFNumberCreate) \
275 MACRO(CFNumberGetValue, RR_Compose<RR_ScalarRval, RR_CFNumberGetValue>, nullptr, \
276 Middleman_CFNumberGetValue) \
277 MACRO(CFNumberIsFloatType, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
278 MACRO(CFPreferencesAppValueIsForced, RR_ScalarRval) \
279 MACRO(CFPreferencesCopyAppValue, RR_ScalarRval) \
280 MACRO(CFPreferencesCopyValue, RR_ScalarRval) \
281 MACRO(CFPropertyListCreateFromXMLData, RR_ScalarRval) \
282 MACRO(CFPropertyListCreateWithStream, RR_ScalarRval) \
283 MACRO(CFReadStreamClose) \
284 MACRO(CFReadStreamCreateWithFile, RR_ScalarRval) \
285 MACRO(CFReadStreamOpen, RR_ScalarRval) \
286 /* Don't handle release/retain calls explicitly in the middleman, all resources */ \
287 /* will be cleaned up when its calls are reset. */ \
288 MACRO(CFRelease, RR_ScalarRval, nullptr, nullptr, Preamble_Veto<0>) \
289 MACRO(CFRetain, RR_ScalarRval, nullptr, nullptr, MiddlemanPreamble_CFRetain) \
290 MACRO(CFRunLoopAddSource) \
291 MACRO(CFRunLoopGetCurrent, RR_ScalarRval) \
292 MACRO(CFRunLoopRemoveSource) \
293 MACRO(CFRunLoopSourceCreate, RR_ScalarRval, Preamble_CFRunLoopSourceCreate) \
294 MACRO(CFRunLoopSourceSignal) \
295 MACRO(CFRunLoopWakeUp) \
296 MACRO(CFStringAppendCharacters) \
297 MACRO(CFStringCompare, RR_ScalarRval, nullptr, \
298 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>>) \
299 MACRO(CFStringCreateArrayBySeparatingStrings, RR_ScalarRval) \
300 MACRO(CFStringCreateMutable, RR_ScalarRval) \
301 MACRO(CFStringCreateWithBytes, RR_ScalarRval) \
302 MACRO(CFStringCreateWithBytesNoCopy, RR_ScalarRval) \
303 MACRO(CFStringCreateWithCharactersNoCopy, RR_ScalarRval, nullptr, \
304 Middleman_Compose<Middleman_Buffer<1, 2, UniChar>, Middleman_CreateCFTypeRval>) \
305 MACRO(CFStringCreateWithCString, RR_ScalarRval) \
306 MACRO(CFStringCreateWithFormat, RR_ScalarRval) \
307 /* Argument indexes are off by one here as the CFRange argument uses two slots. */ \
308 MACRO(CFStringGetBytes, RR_Compose< \
310 RR_WriteOptionalBuffer<6, 7>, \
311 RR_WriteOptionalBufferFixedSize<8, sizeof(CFIndex)>>) \
312 /* Argument indexes are off by one here as the CFRange argument uses two slots. */ \
313 /* We also need to specify the argument register with the range's length here. */ \
314 MACRO(CFStringGetCharacters, RR_WriteBuffer<3, 2, UniChar>, nullptr, \
315 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_WriteBuffer<3, 2, UniChar>>) \
316 MACRO(CFStringGetCString, RR_Compose<RR_ScalarRval, RR_WriteBuffer<1, 2>>) \
317 MACRO(CFStringGetCStringPtr, nullptr, Preamble_VetoIfNotPassedThrough<0>) \
318 MACRO(CFStringGetIntValue, RR_ScalarRval) \
319 MACRO(CFStringGetLength, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
320 MACRO(CFStringGetMaximumSizeForEncoding, RR_ScalarRval) \
321 MACRO(CFStringHasPrefix, RR_ScalarRval) \
322 MACRO(CFStringTokenizerAdvanceToNextToken, RR_ScalarRval) \
323 MACRO(CFStringTokenizerCreate, RR_ScalarRval) \
324 MACRO(CFStringTokenizerGetCurrentTokenRange, RR_ComplexScalarRval) \
325 MACRO(CFURLCreateFromFileSystemRepresentation, RR_ScalarRval) \
326 MACRO(CFURLCreateFromFSRef, RR_ScalarRval) \
327 MACRO(CFURLCreateWithFileSystemPath, RR_ScalarRval) \
328 MACRO(CFURLCreateWithString, RR_ScalarRval) \
329 MACRO(CFURLGetFileSystemRepresentation, RR_Compose<RR_ScalarRval, RR_WriteBuffer<2, 3>>) \
330 MACRO(CFURLGetFSRef, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<1, sizeof(FSRef)>>) \
331 MACRO(CFUUIDCreate, RR_ScalarRval) \
332 MACRO(CFUUIDCreateString, RR_ScalarRval) \
333 MACRO(CFUUIDGetUUIDBytes, RR_ComplexScalarRval) \
334 MACRO(CGAffineTransformConcat, RR_OversizeRval<sizeof(CGAffineTransform)>) \
335 MACRO(CGBitmapContextCreateImage, RR_ScalarRval) \
336 MACRO(CGBitmapContextCreateWithData, \
337 RR_Compose<RR_ScalarRval, RR_CGBitmapContextCreateWithData>, nullptr, \
338 Middleman_CGBitmapContextCreateWithData) \
339 MACRO(CGBitmapContextGetBytesPerRow, RR_ScalarRval) \
340 MACRO(CGBitmapContextGetHeight, RR_ScalarRval) \
341 MACRO(CGBitmapContextGetWidth, RR_ScalarRval) \
342 MACRO(CGColorRelease, RR_ScalarRval) \
343 MACRO(CGColorSpaceCopyICCProfile, RR_ScalarRval) \
344 MACRO(CGColorSpaceCreateDeviceRGB, RR_ScalarRval, nullptr, Middleman_CreateCFTypeRval) \
345 MACRO(CGColorSpaceCreatePattern, RR_ScalarRval) \
346 MACRO(CGColorSpaceRelease, RR_ScalarRval) \
347 MACRO(CGContextBeginTransparencyLayerWithRect) \
348 MACRO(CGContextClipToRects, RR_ScalarRval, nullptr, \
349 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_Buffer<1, 2, CGRect>>) \
350 MACRO(CGContextConcatCTM, nullptr, nullptr, \
351 Middleman_Compose<Middleman_CFTypeArg<0>, \
352 Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
353 MACRO(CGContextDrawImage, RR_FlushCGContext<0>) \
354 MACRO(CGContextEndTransparencyLayer) \
355 MACRO(CGContextFillRect, RR_FlushCGContext<0>, nullptr, \
356 Middleman_Compose<Middleman_CFTypeArg<0>, \
357 Middleman_StackArgumentData<sizeof(CGRect)>, \
358 Middleman_FlushCGContext<0>>) \
359 MACRO(CGContextGetClipBoundingBox, RR_OversizeRval<sizeof(CGRect)>) \
360 MACRO(CGContextGetCTM, RR_OversizeRval<sizeof(CGAffineTransform)>) \
361 MACRO(CGContextGetType, RR_ScalarRval) \
362 MACRO(CGContextGetUserSpaceToDeviceSpaceTransform, RR_OversizeRval<sizeof(CGAffineTransform)>) \
363 MACRO(CGContextRestoreGState, nullptr, Preamble_CGContextRestoreGState, \
364 Middleman_UpdateCFTypeArg<0>) \
365 MACRO(CGContextSaveGState, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
366 MACRO(CGContextSetAllowsFontSubpixelPositioning, nullptr, nullptr, \
367 Middleman_UpdateCFTypeArg<0>) \
368 MACRO(CGContextSetAllowsFontSubpixelQuantization, nullptr, nullptr, \
369 Middleman_UpdateCFTypeArg<0>) \
370 MACRO(CGContextSetAlpha, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
371 MACRO(CGContextSetBaseCTM, nullptr, nullptr, \
372 Middleman_Compose<Middleman_UpdateCFTypeArg<0>, \
373 Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
374 MACRO(CGContextSetCTM, nullptr, nullptr, \
375 Middleman_Compose<Middleman_UpdateCFTypeArg<0>, \
376 Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
377 MACRO(CGContextSetGrayFillColor, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
378 MACRO(CGContextSetRGBFillColor) \
379 MACRO(CGContextSetShouldAntialias, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
380 MACRO(CGContextSetShouldSmoothFonts, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
381 MACRO(CGContextSetShouldSubpixelPositionFonts, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
382 MACRO(CGContextSetShouldSubpixelQuantizeFonts, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
383 MACRO(CGContextSetTextDrawingMode, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
384 MACRO(CGContextSetTextMatrix, nullptr, nullptr, \
385 Middleman_Compose<Middleman_UpdateCFTypeArg<0>, \
386 Middleman_StackArgumentData<sizeof(CGAffineTransform)>>) \
387 MACRO(CGContextScaleCTM, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
388 MACRO(CGContextTranslateCTM, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \
389 MACRO(CGDataProviderCreateWithData, RR_Compose<RR_ScalarRval, RR_CGDataProviderCreateWithData>) \
390 MACRO(CGDataProviderRelease) \
391 MACRO(CGDisplayCopyColorSpace, RR_ScalarRval) \
392 MACRO(CGDisplayIOServicePort, RR_ScalarRval) \
393 MACRO(CGEventSourceCounterForEventType, RR_ScalarRval) \
394 MACRO(CGFontCopyTableForTag, RR_ScalarRval, nullptr, \
395 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
396 MACRO(CGFontCopyTableTags, RR_ScalarRval, nullptr, \
397 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
398 MACRO(CGFontCopyVariations, RR_ScalarRval, nullptr, \
399 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
400 MACRO(CGFontCreateCopyWithVariations, RR_ScalarRval) \
401 MACRO(CGFontCreateWithDataProvider, RR_ScalarRval) \
402 MACRO(CGFontCreateWithFontName, RR_ScalarRval, nullptr, \
403 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
404 MACRO(CGFontCreateWithPlatformFont, RR_ScalarRval) \
405 MACRO(CGFontGetAscent, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
406 MACRO(CGFontGetCapHeight, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
407 MACRO(CGFontGetDescent, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
408 MACRO(CGFontGetFontBBox, RR_OversizeRval<sizeof(CGRect)>, nullptr, \
409 Middleman_Compose<Middleman_CFTypeArg<1>, Middleman_OversizeRval<sizeof(CGRect)>>) \
410 MACRO(CGFontGetGlyphAdvances, RR_Compose<RR_ScalarRval, RR_WriteBuffer<3, 2, int>>, nullptr, \
411 Middleman_Compose<Middleman_CFTypeArg<0>, \
412 Middleman_Buffer<1, 2, CGGlyph>, \
413 Middleman_WriteBuffer<3, 2, int>>) \
414 MACRO(CGFontGetGlyphBBoxes, RR_Compose<RR_ScalarRval, RR_WriteBuffer<3, 2, CGRect>>, nullptr, \
415 Middleman_Compose<Middleman_CFTypeArg<0>, \
416 Middleman_Buffer<1, 2, CGGlyph>, \
417 Middleman_WriteBuffer<3, 2, CGRect>>) \
418 MACRO(CGFontGetGlyphPath, RR_ScalarRval) \
419 MACRO(CGFontGetLeading, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
420 MACRO(CGFontGetUnitsPerEm, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
421 MACRO(CGFontGetXHeight, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
422 MACRO(CGImageGetHeight, RR_ScalarRval) \
423 MACRO(CGImageGetWidth, RR_ScalarRval) \
424 MACRO(CGImageRelease, RR_ScalarRval) \
425 MACRO(CGMainDisplayID, RR_ScalarRval) \
426 MACRO(CGPathAddPath) \
427 MACRO(CGPathApply, nullptr, Preamble_CGPathApply) \
428 MACRO(CGPathContainsPoint, RR_ScalarRval) \
429 MACRO(CGPathCreateMutable, RR_ScalarRval) \
430 MACRO(CGPathGetBoundingBox, RR_OversizeRval<sizeof(CGRect)>) \
431 MACRO(CGPathGetCurrentPoint, RR_ComplexFloatRval) \
432 MACRO(CGPathIsEmpty, RR_ScalarRval) \
433 MACRO(CGSSetDebugOptions, RR_ScalarRval) \
434 MACRO(CGSShutdownServerConnections) \
435 MACRO(CTFontCopyFamilyName, RR_ScalarRval, nullptr, \
436 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
437 MACRO(CTFontCopyFeatures, RR_ScalarRval, nullptr, \
438 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
439 MACRO(CTFontCopyFontDescriptor, RR_ScalarRval, nullptr, \
440 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
441 MACRO(CTFontCopyGraphicsFont, RR_ScalarRval, nullptr, \
442 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
443 MACRO(CTFontCopyTable, RR_ScalarRval, nullptr, \
444 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
445 MACRO(CTFontCopyVariationAxes, RR_ScalarRval) \
446 MACRO(CTFontCreateForString, RR_ScalarRval, nullptr, \
447 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
448 MACRO(CTFontCreatePathForGlyph, RR_ScalarRval) \
449 MACRO(CTFontCreateWithFontDescriptor, RR_ScalarRval, nullptr, \
450 Middleman_Compose<Middleman_CFTypeArg<0>, \
451 Middleman_BufferFixedSize<1, sizeof(CGAffineTransform)>, \
452 Middleman_CreateCFTypeRval>) \
453 MACRO(CTFontCreateWithGraphicsFont, RR_ScalarRval, nullptr, \
454 Middleman_Compose<Middleman_CFTypeArg<0>, \
455 Middleman_BufferFixedSize<1, sizeof(CGAffineTransform)>, \
456 Middleman_CFTypeArg<2>, \
457 Middleman_CreateCFTypeRval>) \
458 MACRO(CTFontCreateWithName, RR_ScalarRval, nullptr, \
459 Middleman_Compose<Middleman_CFTypeArg<0>, \
460 Middleman_BufferFixedSize<1, sizeof(CGAffineTransform)>, \
461 Middleman_CreateCFTypeRval>) \
462 MACRO(CTFontDescriptorCopyAttribute, RR_ScalarRval, nullptr, \
463 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
464 MACRO(CTFontDescriptorCreateCopyWithAttributes, RR_ScalarRval, nullptr, \
465 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
466 MACRO(CTFontDescriptorCreateMatchingFontDescriptors, RR_ScalarRval, nullptr, \
467 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \
468 MACRO(CTFontDescriptorCreateWithAttributes, RR_ScalarRval, nullptr, \
469 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
470 MACRO(CTFontDrawGlyphs, RR_FlushCGContext<4>, nullptr, \
471 Middleman_Compose<Middleman_CFTypeArg<0>, \
472 Middleman_CFTypeArg<4>, \
473 Middleman_Buffer<1, 3, CGGlyph>, \
474 Middleman_Buffer<2, 3, CGPoint>, \
475 Middleman_FlushCGContext<4>>) \
476 MACRO(CTFontGetAdvancesForGlyphs, \
477 RR_Compose<RR_FloatRval, RR_WriteOptionalBuffer<3, 4, CGSize>>, nullptr, \
478 Middleman_Compose<Middleman_CFTypeArg<0>, \
479 Middleman_Buffer<2, 4, CGGlyph>, \
480 Middleman_WriteBuffer<3, 4, CGSize>>) \
481 MACRO(CTFontGetAscent, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
482 MACRO(CTFontGetBoundingBox, RR_OversizeRval<sizeof(CGRect)>, nullptr, \
483 Middleman_Compose<Middleman_CFTypeArg<1>, Middleman_OversizeRval<sizeof(CGRect)>>) \
484 MACRO(CTFontGetBoundingRectsForGlyphs, \
485 /* Argument indexes here are off by one due to the oversize rval. */ \
486 RR_Compose<RR_OversizeRval<sizeof(CGRect)>, \
487 RR_WriteOptionalBuffer<4, 5, CGRect>>, nullptr, \
488 Middleman_Compose<Middleman_CFTypeArg<1>, \
489 Middleman_Buffer<3, 5, CGGlyph>, \
490 Middleman_OversizeRval<sizeof(CGRect)>, \
491 Middleman_WriteBuffer<4, 5, CGRect>>) \
492 MACRO(CTFontGetCapHeight, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
493 MACRO(CTFontGetDescent, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
494 MACRO(CTFontGetGlyphCount, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
495 MACRO(CTFontGetGlyphsForCharacters, \
496 RR_Compose<RR_ScalarRval, RR_WriteBuffer<2, 3, CGGlyph>>, nullptr, \
497 Middleman_Compose<Middleman_CFTypeArg<0>, \
498 Middleman_Buffer<1, 3, UniChar>, \
499 Middleman_WriteBuffer<2, 3, CGGlyph>>) \
500 MACRO(CTFontGetLeading, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
501 MACRO(CTFontGetSize, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
502 MACRO(CTFontGetSymbolicTraits, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
503 MACRO(CTFontGetUnderlinePosition, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
504 MACRO(CTFontGetUnderlineThickness, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
505 MACRO(CTFontGetUnitsPerEm, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
506 MACRO(CTFontGetXHeight, RR_FloatRval, nullptr, Middleman_CFTypeArg<0>) \
507 MACRO(CTFontManagerCopyAvailableFontFamilyNames, RR_ScalarRval) \
508 MACRO(CTFontManagerRegisterFontsForURLs, RR_ScalarRval) \
509 MACRO(CTFontManagerSetAutoActivationSetting) \
510 MACRO(CTLineCreateWithAttributedString, RR_ScalarRval, nullptr, \
511 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CreateCFTypeRval>) \
512 MACRO(CTLineGetGlyphRuns, RR_ScalarRval, nullptr, \
513 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeRval>) \
514 MACRO(CTRunGetAttributes, RR_ScalarRval, nullptr, \
515 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeRval>) \
516 MACRO(CTRunGetGlyphCount, RR_ScalarRval, nullptr, Middleman_CFTypeArg<0>) \
517 MACRO(CTRunGetGlyphsPtr, RR_CTRunGetElements<CGGlyph, CTRunGetGlyphs>, nullptr, \
518 Middleman_CTRunGetElements<CGGlyph, CTRunGetGlyphs>) \
519 MACRO(CTRunGetPositionsPtr, RR_CTRunGetElements<CGPoint, CTRunGetPositions>, nullptr, \
520 Middleman_CTRunGetElements<CGPoint, CTRunGetPositions>) \
521 MACRO(CTRunGetStringIndicesPtr, RR_CTRunGetElements<CFIndex, CTRunGetStringIndices>, nullptr, \
522 Middleman_CTRunGetElements<CFIndex, CTRunGetStringIndices>) \
523 MACRO(CTRunGetStringRange, RR_ComplexScalarRval, nullptr, Middleman_CFTypeArg<0>) \
524 /* Argument indexes are off by one here as the CFRange argument uses two slots. */ \
525 MACRO(CTRunGetTypographicBounds, \
526 RR_Compose<RR_FloatRval, \
527 RR_WriteOptionalBufferFixedSize<3, sizeof(CGFloat)>, \
528 RR_WriteOptionalBufferFixedSize<4, sizeof(CGFloat)>, \
529 RR_WriteOptionalBufferFixedSize<5, sizeof(CGFloat)>>, nullptr, \
530 Middleman_Compose<Middleman_CFTypeArg<0>, \
531 Middleman_WriteBufferFixedSize<3, sizeof(CGFloat)>, \
532 Middleman_WriteBufferFixedSize<4, sizeof(CGFloat)>, \
533 Middleman_WriteBufferFixedSize<5, sizeof(CGFloat)>>) \
534 MACRO(CUIDraw, nullptr, nullptr, \
535 Middleman_Compose<Middleman_CFTypeArg<0>, \
536 Middleman_CFTypeArg<1>, \
537 Middleman_CFTypeArg<2>, \
538 Middleman_StackArgumentData<sizeof(CGRect)>>) \
539 MACRO(FSCompareFSRefs, RR_ScalarRval) \
540 MACRO(FSGetVolumeInfo, RR_Compose< \
542 RR_WriteBufferFixedSize<5, sizeof(HFSUniStr255)>, \
543 RR_WriteBufferFixedSize<6, sizeof(FSRef)>>) \
544 MACRO(FSFindFolder, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<3, sizeof(FSRef)>>) \
545 MACRO(Gestalt, RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<1, sizeof(SInt32)>>) \
546 MACRO(GetEventClass, RR_ScalarRval) \
547 MACRO(GetCurrentEventQueue, RR_ScalarRval) \
548 MACRO(GetCurrentProcess, \
549 RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<0, sizeof(ProcessSerialNumber)>>) \
550 MACRO(GetEventAttributes, RR_ScalarRval) \
551 MACRO(GetEventDispatcherTarget, RR_ScalarRval) \
552 MACRO(GetEventKind, RR_ScalarRval) \
553 MACRO(HIThemeDrawButton, RR_ScalarRval) \
554 MACRO(HIThemeDrawFrame, RR_ScalarRval) \
555 MACRO(HIThemeDrawGroupBox, RR_ScalarRval) \
556 MACRO(HIThemeDrawGrowBox, RR_ScalarRval) \
557 MACRO(HIThemeDrawMenuBackground, RR_ScalarRval) \
558 MACRO(HIThemeDrawMenuItem, RR_ScalarRval) \
559 MACRO(HIThemeDrawMenuSeparator, RR_ScalarRval) \
560 MACRO(HIThemeDrawSeparator, RR_ScalarRval) \
561 MACRO(HIThemeDrawTabPane, RR_ScalarRval) \
562 MACRO(HIThemeDrawTrack, RR_ScalarRval) \
563 MACRO(HIThemeGetGrowBoxBounds, \
564 RR_Compose<RR_ScalarRval, RR_WriteBufferFixedSize<2, sizeof(HIRect)>>) \
565 MACRO(HIThemeSetFill, RR_ScalarRval) \
566 MACRO(IORegistryEntrySearchCFProperty, RR_ScalarRval) \
567 MACRO(LSCopyAllHandlersForURLScheme, RR_ScalarRval) \
568 MACRO(LSCopyApplicationForMIMEType, \
569 RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<2, sizeof(CFURLRef)>>) \
570 MACRO(LSCopyItemAttribute, \
571 RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<3, sizeof(CFTypeRef)>>) \
572 MACRO(LSCopyKindStringForMIMEType, \
573 RR_Compose<RR_ScalarRval, RR_WriteOptionalBufferFixedSize<1, sizeof(CFStringRef)>>) \
574 MACRO(LSGetApplicationForInfo, RR_Compose< \
576 RR_WriteOptionalBufferFixedSize<4, sizeof(FSRef)>, \
577 RR_WriteOptionalBufferFixedSize<5, sizeof(CFURLRef)>>) \
578 MACRO(LSGetApplicationForURL, RR_Compose< \
580 RR_WriteOptionalBufferFixedSize<2, sizeof(FSRef)>, \
581 RR_WriteOptionalBufferFixedSize<3, sizeof(CFURLRef)>>) \
582 MACRO(NSClassFromString, RR_ScalarRval, nullptr, \
583 Middleman_Compose<Middleman_CFTypeArg<0>, Middleman_CFTypeRval>) \
585 MACRO(NSSearchPathForDirectoriesInDomains, RR_ScalarRval) \
586 MACRO(NSSetFocusRingStyle, RR_ScalarRval) \
587 MACRO(NSTemporaryDirectory, RR_ScalarRval) \
588 MACRO(OSSpinLockLock, nullptr, Preamble_OSSpinLockLock) \
589 MACRO(ReleaseEvent, RR_ScalarRval) \
590 MACRO(RemoveEventFromQueue, RR_ScalarRval) \
591 MACRO(RetainEvent, RR_ScalarRval) \
592 MACRO(SendEventToEventTarget, RR_ScalarRval) \
593 /* These are not public APIs, but other redirected functions may be aliases for */ \
594 /* these which are dynamically installed on the first call in a way that our */ \
595 /* redirection mechanism doesn't completely account for. */ \
596 MACRO(SLDisplayCopyColorSpace, RR_ScalarRval) \
597 MACRO(SLDisplayIOServicePort, RR_ScalarRval) \
598 MACRO(SLEventSourceCounterForEventType, RR_ScalarRval) \
599 MACRO(SLMainDisplayID, RR_ScalarRval) \
600 MACRO(SLSSetDenyWindowServerConnections, RR_ScalarRval) \
601 MACRO(SLSShutdownServerConnections)
603 #define MAKE_CALL_EVENT(aName, ...) CallEvent_ ##aName ,
606 FOR_EACH_REDIRECTION(MAKE_CALL_EVENT
) \
610 #undef MAKE_CALL_EVENT
612 ///////////////////////////////////////////////////////////////////////////////
614 ///////////////////////////////////////////////////////////////////////////////
617 CallbackEvent_CFRunLoopPerformCallBack
,
618 CallbackEvent_CGPathApplierFunction
621 typedef void (*CFRunLoopPerformCallBack
)(void*);
624 CFRunLoopPerformCallBackWrapper(void* aInfo
)
626 RecordReplayCallback(CFRunLoopPerformCallBack
, &aInfo
);
627 rrc
.mFunction(aInfo
);
629 // Make sure we service any callbacks that have been posted for the main
630 // thread whenever the main thread's message loop has any activity.
631 PauseMainThreadAndServiceCallbacks();
635 CGPathElementPointCount(CGPathElement
* aElement
)
637 switch (aElement
->type
) {
638 case kCGPathElementCloseSubpath
: return 0;
639 case kCGPathElementMoveToPoint
:
640 case kCGPathElementAddLineToPoint
: return 1;
641 case kCGPathElementAddQuadCurveToPoint
: return 2;
642 case kCGPathElementAddCurveToPoint
: return 3;
643 default: MOZ_CRASH();
648 CGPathApplierFunctionWrapper(void* aInfo
, CGPathElement
* aElement
)
650 RecordReplayCallback(CGPathApplierFunction
, &aInfo
);
652 CGPathElement replayElement
;
654 aElement
= &replayElement
;
657 aElement
->type
= (CGPathElementType
) RecordReplayValue(aElement
->type
);
659 size_t npoints
= CGPathElementPointCount(aElement
);
661 aElement
->points
= new CGPoint
[npoints
];
663 RecordReplayBytes(aElement
->points
, npoints
* sizeof(CGPoint
));
665 rrc
.mFunction(aInfo
, aElement
);
668 delete[] aElement
->points
;
673 ReplayInvokeCallback(size_t aCallbackId
)
675 MOZ_RELEASE_ASSERT(IsReplaying());
676 switch (aCallbackId
) {
677 case CallbackEvent_CFRunLoopPerformCallBack
:
678 CFRunLoopPerformCallBackWrapper(nullptr);
680 case CallbackEvent_CGPathApplierFunction
:
681 CGPathApplierFunctionWrapper(nullptr, nullptr);
688 ///////////////////////////////////////////////////////////////////////////////
689 // Middleman Call Helpers
690 ///////////////////////////////////////////////////////////////////////////////
693 TestObjCObjectClass(id aObj
, const char* aName
)
695 Class cls
= object_getClass(aObj
);
697 const char* className
= class_getName(cls
);
698 if (!strcmp(className
, aName
)) {
701 cls
= class_getSuperclass(cls
);
706 // Inputs that originate from static data in the replaying process itself
707 // rather than from previous middleman calls.
708 enum class ObjCInputKind
{
713 // Capture an Objective C or CoreFoundation input to a call, which may come
714 // either from another middleman call, or from static data in the replaying
717 Middleman_ObjCInput(MiddlemanCallContext
& aCx
, id
* aThingPtr
)
719 MOZ_RELEASE_ASSERT(aCx
.AccessPreface());
721 if (Middleman_SystemInput(aCx
, (const void**) aThingPtr
)) {
722 // This value came from a previous middleman call.
726 MOZ_RELEASE_ASSERT(aCx
.AccessInput());
728 if (aCx
.mPhase
== MiddlemanCallPhase::ReplayInput
) {
729 // Try to determine where this object came from.
731 // List of the Objective C classes which messages might be sent to directly.
732 static const char* gStaticClasses
[] = {
743 // Watch for messages sent to particular classes.
744 for (const char* className
: gStaticClasses
) {
745 Class cls
= objc_lookUpClass(className
);
746 if (cls
== (Class
) *aThingPtr
) {
747 aCx
.WriteInputScalar((size_t) ObjCInputKind::StaticClass
);
748 size_t len
= strlen(className
) + 1;
749 aCx
.WriteInputScalar(len
);
750 aCx
.WriteInputBytes(className
, len
);
755 // Watch for constant compile time strings baked into the generated code or
756 // stored in system libraries. We can crash here if the object came from
757 // e.g. a replayed pointer from the recording, as can happen if not enough
758 // redirections have middleman call hooks. We could do better here to make
759 // sure the pointer looks like it could be a constant string, but it seems
760 // better and simpler to crash more reliably here than mask problems due to
761 // missing middleman call hooks.
762 if (TestObjCObjectClass(*aThingPtr
, "NSString")) {
763 AutoPassThroughThreadEvents pt
;
764 CFIndex len
= CFStringGetLength((CFStringRef
)*aThingPtr
);
765 InfallibleVector
<UniChar
> buffer
;
766 buffer
.appendN(0, len
);
767 CFStringGetCharacters((CFStringRef
)*aThingPtr
, { 0, len
}, buffer
.begin());
768 aCx
.WriteInputScalar((size_t) ObjCInputKind::ConstantString
);
769 aCx
.WriteInputScalar(len
);
770 aCx
.WriteInputBytes(buffer
.begin(), len
* sizeof(UniChar
));
778 switch ((ObjCInputKind
) aCx
.ReadInputScalar()) {
779 case ObjCInputKind::StaticClass
: {
780 size_t len
= aCx
.ReadInputScalar();
781 UniquePtr
<char[]> className(new char[len
]);
782 aCx
.ReadInputBytes(className
.get(), len
);
783 *aThingPtr
= (id
) objc_lookUpClass(className
.get());
786 case ObjCInputKind::ConstantString
: {
787 size_t len
= aCx
.ReadInputScalar();
788 UniquePtr
<UniChar
[]> contents(new UniChar
[len
]);
789 aCx
.ReadInputBytes(contents
.get(), len
* sizeof(UniChar
));
790 *aThingPtr
= (id
) CFStringCreateWithCharacters(kCFAllocatorDefault
, contents
.get(), len
);
798 template <size_t Argument
>
800 Middleman_CFTypeArg(MiddlemanCallContext
& aCx
)
802 if (aCx
.AccessPreface()) {
803 auto& object
= aCx
.mArguments
->Arg
<Argument
, id
>();
804 Middleman_ObjCInput(aCx
, &object
);
809 Middleman_CFTypeOutput(MiddlemanCallContext
& aCx
, CFTypeRef
* aOutput
, bool aOwnsReference
)
811 Middleman_SystemOutput(aCx
, (const void**) aOutput
);
814 switch (aCx
.mPhase
) {
815 case MiddlemanCallPhase::MiddlemanOutput
:
816 if (!aOwnsReference
) {
820 case MiddlemanCallPhase::MiddlemanRelease
:
829 // For APIs using the 'Get' rule: no reference is held on the returned value.
831 Middleman_CFTypeRval(MiddlemanCallContext
& aCx
)
833 auto& rval
= aCx
.mArguments
->Rval
<CFTypeRef
>();
834 Middleman_CFTypeOutput(aCx
, &rval
, /* aOwnsReference = */ false);
837 // For APIs using the 'Create' rule: a reference is held on the returned
838 // value which must be released.
840 Middleman_CreateCFTypeRval(MiddlemanCallContext
& aCx
)
842 auto& rval
= aCx
.mArguments
->Rval
<CFTypeRef
>();
843 Middleman_CFTypeOutput(aCx
, &rval
, /* aOwnsReference = */ true);
846 template <size_t Argument
>
848 Middleman_CFTypeOutputArg(MiddlemanCallContext
& aCx
)
850 Middleman_WriteBufferFixedSize
<Argument
, sizeof(const void*)>(aCx
);
852 auto arg
= aCx
.mArguments
->Arg
<Argument
, const void**>();
853 Middleman_CFTypeOutput(aCx
, arg
, /* aOwnsReference = */ false);
856 // For APIs whose result will be released by the middleman's autorelease pool.
858 Middleman_AutoreleaseCFTypeRval(MiddlemanCallContext
& aCx
)
860 auto& rval
= aCx
.mArguments
->Rval
<const void*>();
861 Middleman_SystemOutput(aCx
, &rval
);
864 // For functions which have an input CFType value and also have side effects on
865 // that value, this associates the call with its own input value so that this
866 // will be treated as a dependent for any future calls using the value.
867 template <size_t Argument
>
869 Middleman_UpdateCFTypeArg(MiddlemanCallContext
& aCx
)
871 auto arg
= aCx
.mArguments
->Arg
<Argument
, const void*>();
873 Middleman_CFTypeArg
<Argument
>(aCx
);
874 Middleman_SystemOutput(aCx
, &arg
, /* aUpdating = */ true);
877 static PreambleResult
878 Preamble_SetError(CallArguments
* aArguments
)
880 aArguments
->Rval
<ssize_t
>() = -1;
882 return PreambleResult::Veto
;
885 ///////////////////////////////////////////////////////////////////////////////
886 // system call redirections
887 ///////////////////////////////////////////////////////////////////////////////
890 RR_recvmsg(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
892 auto& msg
= aArguments
->Arg
<1, struct msghdr
*>();
894 aEvents
.CheckInput(msg
->msg_iovlen
);
895 for (int i
= 0; i
< msg
->msg_iovlen
; i
++) {
896 aEvents
.CheckInput(msg
->msg_iov
[i
].iov_len
);
899 aEvents
.RecordOrReplayValue(&msg
->msg_flags
);
900 aEvents
.RecordOrReplayValue(&msg
->msg_controllen
);
901 aEvents
.RecordOrReplayBytes(msg
->msg_control
, msg
->msg_controllen
);
903 size_t nbytes
= aArguments
->Rval
<size_t>();
904 for (int i
= 0; nbytes
&& i
< msg
->msg_iovlen
; i
++) {
905 struct iovec
* iov
= &msg
->msg_iov
[i
];
906 size_t iovbytes
= nbytes
<= iov
->iov_len
? nbytes
: iov
->iov_len
;
907 aEvents
.RecordOrReplayBytes(iov
->iov_base
, iovbytes
);
910 MOZ_RELEASE_ASSERT(nbytes
== 0);
913 static PreambleResult
914 Preamble_mprotect(CallArguments
* aArguments
)
916 // Ignore any mprotect calls that occur after saving a checkpoint.
917 if (!HasSavedCheckpoint()) {
918 return PreambleResult::PassThrough
;
920 aArguments
->Rval
<ssize_t
>() = 0;
921 return PreambleResult::Veto
;
924 static PreambleResult
925 Preamble_mmap(CallArguments
* aArguments
)
927 auto& address
= aArguments
->Arg
<0, void*>();
928 auto& size
= aArguments
->Arg
<1, size_t>();
929 auto& prot
= aArguments
->Arg
<2, size_t>();
930 auto& flags
= aArguments
->Arg
<3, size_t>();
931 auto& fd
= aArguments
->Arg
<4, size_t>();
932 auto& offset
= aArguments
->Arg
<5, size_t>();
934 MOZ_RELEASE_ASSERT(address
== PageBase(address
));
936 // Make sure that fixed mappings do not interfere with snapshot state.
937 if (flags
& MAP_FIXED
) {
938 CheckFixedMemory(address
, RoundupSizeToPageBoundary(size
));
941 void* memory
= nullptr;
942 if ((flags
& MAP_ANON
) || (IsReplaying() && !AreThreadEventsPassedThrough())) {
943 // Get an anonymous mapping for the result.
944 if (flags
& MAP_FIXED
) {
945 // For fixed allocations, make sure this memory region is mapped and zero.
946 if (!HasSavedCheckpoint()) {
947 // Make sure this memory region is writable.
948 OriginalCall(mprotect
, int, address
, size
, PROT_READ
| PROT_WRITE
| PROT_EXEC
);
950 memset(address
, 0, size
);
953 memory
= AllocateMemoryTryAddress(address
, RoundupSizeToPageBoundary(size
),
954 MemoryKind::Tracked
);
957 // We have to call mmap itself, which can change memory protection flags
958 // for memory that is already allocated. If we haven't saved a checkpoint
959 // then this is no problem, but after saving a checkpoint we have to make
960 // sure that protection flags are what we expect them to be.
961 int newProt
= HasSavedCheckpoint() ? (PROT_READ
| PROT_EXEC
) : prot
;
962 memory
= OriginalCall(mmap
, void*, address
, size
, newProt
, flags
, fd
, offset
);
964 if (flags
& MAP_FIXED
) {
965 MOZ_RELEASE_ASSERT(memory
== address
);
966 RestoreWritableFixedMemory(memory
, RoundupSizeToPageBoundary(size
));
967 } else if (memory
&& memory
!= (void*)-1) {
968 RegisterAllocatedMemory(memory
, RoundupSizeToPageBoundary(size
), MemoryKind::Tracked
);
972 if (!(flags
& MAP_ANON
) && !AreThreadEventsPassedThrough()) {
973 // Include the data just mapped in the recording.
974 MOZ_RELEASE_ASSERT(memory
&& memory
!= (void*)-1);
975 RecordReplayBytes(memory
, size
);
978 aArguments
->Rval
<void*>() = memory
;
979 return PreambleResult::Veto
;
982 static PreambleResult
983 Preamble_munmap(CallArguments
* aArguments
)
985 auto& address
= aArguments
->Arg
<0, void*>();
986 auto& size
= aArguments
->Arg
<1, size_t>();
988 DeallocateMemory(address
, size
, MemoryKind::Tracked
);
989 aArguments
->Rval
<ssize_t
>() = 0;
990 return PreambleResult::Veto
;
994 RR_getsockopt(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
996 auto& optval
= aArguments
->Arg
<3, void*>();
997 auto& optlen
= aArguments
->Arg
<4, int*>();
999 // The initial length has already been clobbered while recording, but make
1000 // sure there is enough room for the copy while replaying.
1001 int initLen
= *optlen
;
1002 aEvents
.RecordOrReplayValue(optlen
);
1003 MOZ_RELEASE_ASSERT(*optlen
<= initLen
);
1005 aEvents
.RecordOrReplayBytes(optval
, *optlen
);
1008 static PreambleResult
1009 Preamble_getpid(CallArguments
* aArguments
)
1011 if (!AreThreadEventsPassedThrough()) {
1012 // Don't involve the recording with getpid calls, so that this can be used
1013 // after diverging from the recording.
1014 aArguments
->Rval
<size_t>() = GetRecordingPid();
1015 return PreambleResult::Veto
;
1017 return PreambleResult::Redirect
;
1020 static PreambleResult
1021 Preamble_fcntl(CallArguments
* aArguments
)
1023 // We don't record any outputs for fcntl other than its return value, but
1024 // some commands have an output parameter they write additional data to.
1025 // Handle this by only allowing a limited set of commands to be used when
1026 // events are not passed through and we are recording/replaying the outputs.
1027 if (AreThreadEventsPassedThrough()) {
1028 return PreambleResult::Redirect
;
1031 auto& cmd
= aArguments
->Arg
<1, size_t>();
1044 return PreambleResult::Redirect
;
1047 static PreambleResult
1048 Preamble___disable_threadsignal(CallArguments
* aArguments
)
1050 // __disable_threadsignal is called when a thread finishes. During replay a
1051 // terminated thread can cause problems such as changing access bits on
1052 // tracked memory behind the scenes.
1054 // Ideally, threads will never try to finish when we are replaying, since we
1055 // are supposed to have control over all threads in the system and only spawn
1056 // threads which will run forever. Unfortunately, GCD might have already
1057 // spawned threads before we were able to install our redirections, so use a
1058 // fallback here to keep these threads from terminating.
1059 if (IsReplaying()) {
1060 Thread::WaitForeverNoIdle();
1062 return PreambleResult::PassThrough
;
1066 RR___sysctl(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
1068 auto& old
= aArguments
->Arg
<2, void*>();
1069 auto& oldlenp
= aArguments
->Arg
<3, size_t*>();
1071 aEvents
.CheckInput((old
? 1 : 0) | (oldlenp
? 2 : 0));
1073 aEvents
.RecordOrReplayValue(oldlenp
);
1076 aEvents
.RecordOrReplayBytes(old
, *oldlenp
);
1080 static PreambleResult
1081 Preamble___workq_kernreturn(CallArguments
* aArguments
)
1083 // Busy-wait until initialization is complete.
1084 while (!gInitialized
) {
1088 // Make sure we know this thread exists.
1091 RecordReplayInvokeCall(CallEvent___workq_kernreturn
, aArguments
);
1092 return PreambleResult::Veto
;
1095 static PreambleResult
1096 Preamble_start_wqthread(CallArguments
* aArguments
)
1098 // When replaying we don't want system threads to run, but by the time we
1099 // initialize the record/replay system GCD has already started running.
1100 // Use this redirection to watch for new threads being spawned by GCD, and
1101 // suspend them immediately.
1102 if (IsReplaying()) {
1103 Thread::WaitForeverNoIdle();
1106 RecordReplayInvokeCall(CallEvent_start_wqthread
, aArguments
);
1107 return PreambleResult::Veto
;
1110 ///////////////////////////////////////////////////////////////////////////////
1111 // pthreads redirections
1112 ///////////////////////////////////////////////////////////////////////////////
1115 DirectLockMutex(pthread_mutex_t
* aMutex
)
1117 AutoPassThroughThreadEvents pt
;
1118 ssize_t rv
= OriginalCall(pthread_mutex_lock
, ssize_t
, aMutex
);
1119 MOZ_RELEASE_ASSERT(rv
== 0);
1123 DirectUnlockMutex(pthread_mutex_t
* aMutex
)
1125 AutoPassThroughThreadEvents pt
;
1126 ssize_t rv
= OriginalCall(pthread_mutex_unlock
, ssize_t
, aMutex
);
1127 MOZ_RELEASE_ASSERT(rv
== 0);
1130 // Handle a redirection which releases a mutex, waits in some way for a cvar,
1131 // and reacquires the mutex before returning.
1133 WaitForCvar(pthread_mutex_t
* aMutex
, bool aRecordReturnValue
,
1134 const std::function
<ssize_t()>& aCallback
)
1136 Lock
* lock
= Lock::Find(aMutex
);
1138 AutoEnsurePassThroughThreadEvents pt
;
1142 if (IsRecording()) {
1143 AutoPassThroughThreadEvents pt
;
1146 DirectUnlockMutex(aMutex
);
1150 if (IsReplaying()) {
1151 DirectLockMutex(aMutex
);
1153 if (aRecordReturnValue
) {
1154 return RecordReplayValue(rv
);
1156 MOZ_RELEASE_ASSERT(rv
== 0);
1160 static PreambleResult
1161 Preamble_pthread_cond_wait(CallArguments
* aArguments
)
1163 auto& cond
= aArguments
->Arg
<0, pthread_cond_t
*>();
1164 auto& mutex
= aArguments
->Arg
<1, pthread_mutex_t
*>();
1165 aArguments
->Rval
<ssize_t
>() =
1166 WaitForCvar(mutex
, false,
1167 [=]() { return OriginalCall(pthread_cond_wait
, ssize_t
, cond
, mutex
); });
1168 return PreambleResult::Veto
;
1171 static PreambleResult
1172 Preamble_pthread_cond_timedwait(CallArguments
* aArguments
)
1174 auto& cond
= aArguments
->Arg
<0, pthread_cond_t
*>();
1175 auto& mutex
= aArguments
->Arg
<1, pthread_mutex_t
*>();
1176 auto& timeout
= aArguments
->Arg
<2, timespec
*>();
1177 aArguments
->Rval
<ssize_t
>() =
1178 WaitForCvar(mutex
, true,
1179 [=]() { return OriginalCall(pthread_cond_timedwait
, ssize_t
,
1180 cond
, mutex
, timeout
); });
1181 return PreambleResult::Veto
;
1184 static PreambleResult
1185 Preamble_pthread_cond_timedwait_relative_np(CallArguments
* aArguments
)
1187 auto& cond
= aArguments
->Arg
<0, pthread_cond_t
*>();
1188 auto& mutex
= aArguments
->Arg
<1, pthread_mutex_t
*>();
1189 auto& timeout
= aArguments
->Arg
<2, timespec
*>();
1190 aArguments
->Rval
<ssize_t
>() =
1191 WaitForCvar(mutex
, true,
1192 [=]() { return OriginalCall(pthread_cond_timedwait_relative_np
, ssize_t
,
1193 cond
, mutex
, timeout
); });
1194 return PreambleResult::Veto
;
1197 static PreambleResult
1198 Preamble_pthread_create(CallArguments
* aArguments
)
1200 if (AreThreadEventsPassedThrough()) {
1201 return PreambleResult::Redirect
;
1204 auto& token
= aArguments
->Arg
<0, pthread_t
*>();
1205 auto& attr
= aArguments
->Arg
<1, const pthread_attr_t
*>();
1206 auto& start
= aArguments
->Arg
<2, void*>();
1207 auto& startArg
= aArguments
->Arg
<3, void*>();
1210 int rv
= pthread_attr_getdetachstate(attr
, &detachState
);
1211 MOZ_RELEASE_ASSERT(rv
== 0);
1213 *token
= Thread::StartThread((Thread::Callback
) start
, startArg
,
1214 detachState
== PTHREAD_CREATE_JOINABLE
);
1215 aArguments
->Rval
<ssize_t
>() = 0;
1216 return PreambleResult::Veto
;
1219 static PreambleResult
1220 Preamble_pthread_join(CallArguments
* aArguments
)
1222 if (AreThreadEventsPassedThrough()) {
1223 return PreambleResult::Redirect
;
1226 auto& token
= aArguments
->Arg
<0, pthread_t
>();
1227 auto& ptr
= aArguments
->Arg
<1, void**>();
1229 Thread
* thread
= Thread::GetByNativeId(token
);
1233 aArguments
->Rval
<ssize_t
>() = 0;
1234 return PreambleResult::Veto
;
1237 static PreambleResult
1238 Preamble_pthread_mutex_init(CallArguments
* aArguments
)
1240 auto& mutex
= aArguments
->Arg
<0, pthread_mutex_t
*>();
1241 auto& attr
= aArguments
->Arg
<1, pthread_mutexattr_t
*>();
1244 aArguments
->Rval
<ssize_t
>() = OriginalCall(pthread_mutex_init
, ssize_t
, mutex
, attr
);
1245 return PreambleResult::Veto
;
1248 static PreambleResult
1249 Preamble_pthread_mutex_destroy(CallArguments
* aArguments
)
1251 auto& mutex
= aArguments
->Arg
<0, pthread_mutex_t
*>();
1253 Lock::Destroy(mutex
);
1254 aArguments
->Rval
<ssize_t
>() = OriginalCall(pthread_mutex_destroy
, ssize_t
, mutex
);
1255 return PreambleResult::Veto
;
1258 static PreambleResult
1259 Preamble_pthread_mutex_lock(CallArguments
* aArguments
)
1261 auto& mutex
= aArguments
->Arg
<0, pthread_mutex_t
*>();
1263 Lock
* lock
= Lock::Find(mutex
);
1265 AutoEnsurePassThroughThreadEventsUseStackPointer pt
;
1266 aArguments
->Rval
<ssize_t
>() = OriginalCall(pthread_mutex_lock
, ssize_t
, mutex
);
1267 return PreambleResult::Veto
;
1270 if (IsRecording()) {
1271 AutoPassThroughThreadEvents pt
;
1272 rv
= OriginalCall(pthread_mutex_lock
, ssize_t
, mutex
);
1274 rv
= RecordReplayValue(rv
);
1275 MOZ_RELEASE_ASSERT(rv
== 0 || rv
== EDEADLK
);
1278 if (IsReplaying()) {
1279 DirectLockMutex(mutex
);
1282 aArguments
->Rval
<ssize_t
>() = rv
;
1283 return PreambleResult::Veto
;
1286 static PreambleResult
1287 Preamble_pthread_mutex_trylock(CallArguments
* aArguments
)
1289 auto& mutex
= aArguments
->Arg
<0, pthread_mutex_t
*>();
1291 Lock
* lock
= Lock::Find(mutex
);
1293 AutoEnsurePassThroughThreadEvents pt
;
1294 aArguments
->Rval
<ssize_t
>() = OriginalCall(pthread_mutex_trylock
, ssize_t
, mutex
);
1295 return PreambleResult::Veto
;
1298 if (IsRecording()) {
1299 AutoPassThroughThreadEvents pt
;
1300 rv
= OriginalCall(pthread_mutex_trylock
, ssize_t
, mutex
);
1302 rv
= RecordReplayValue(rv
);
1303 MOZ_RELEASE_ASSERT(rv
== 0 || rv
== EBUSY
);
1306 if (IsReplaying()) {
1307 DirectLockMutex(mutex
);
1310 aArguments
->Rval
<ssize_t
>() = rv
;
1311 return PreambleResult::Veto
;
1314 static PreambleResult
1315 Preamble_pthread_mutex_unlock(CallArguments
* aArguments
)
1317 auto& mutex
= aArguments
->Arg
<0, pthread_mutex_t
*>();
1319 Lock
* lock
= Lock::Find(mutex
);
1321 AutoEnsurePassThroughThreadEventsUseStackPointer pt
;
1322 aArguments
->Rval
<ssize_t
>() = OriginalCall(pthread_mutex_unlock
, ssize_t
, mutex
);
1323 return PreambleResult::Veto
;
1326 DirectUnlockMutex(mutex
);
1327 aArguments
->Rval
<ssize_t
>() = 0;
1328 return PreambleResult::Veto
;
1331 ///////////////////////////////////////////////////////////////////////////////
1332 // stdlib redirections
1333 ///////////////////////////////////////////////////////////////////////////////
1336 RR_fread(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
1338 auto& buf
= aArguments
->Arg
<0, void*>();
1339 auto& elemSize
= aArguments
->Arg
<1, size_t>();
1340 auto& capacity
= aArguments
->Arg
<2, size_t>();
1341 auto& rval
= aArguments
->Rval
<size_t>();
1343 aEvents
.CheckInput(elemSize
);
1344 aEvents
.CheckInput(capacity
);
1345 MOZ_RELEASE_ASSERT(rval
<= capacity
);
1346 aEvents
.RecordOrReplayBytes(buf
, rval
* elemSize
);
1349 static struct tm gGlobalTM
;
1351 // localtime behaves the same as localtime_r, except it is not reentrant.
1352 // For simplicity, define this in terms of localtime_r.
1353 static PreambleResult
1354 Preamble_localtime(CallArguments
* aArguments
)
1356 aArguments
->Rval
<struct tm
*>() = localtime_r(aArguments
->Arg
<0, const time_t*>(), &gGlobalTM
);
1357 return PreambleResult::Veto
;
1360 // The same concern here applies as for localtime.
1361 static PreambleResult
1362 Preamble_gmtime(CallArguments
* aArguments
)
1364 aArguments
->Rval
<struct tm
*>() = gmtime_r(aArguments
->Arg
<0, const time_t*>(), &gGlobalTM
);
1365 return PreambleResult::Veto
;
1368 static PreambleResult
1369 Preamble_mach_absolute_time(CallArguments
* aArguments
)
1371 // This function might be called through OSSpinLock while setting gTlsThreadKey.
1372 Thread
* thread
= Thread::GetByStackPointer(&thread
);
1373 if (!thread
|| thread
->PassThroughEvents()) {
1374 aArguments
->Rval
<uint64_t>() = OriginalCall(mach_absolute_time
, uint64_t);
1375 return PreambleResult::Veto
;
1377 return PreambleResult::Redirect
;
1380 static PreambleResult
1381 Preamble_mach_vm_allocate(CallArguments
* aArguments
)
1383 auto& address
= aArguments
->Arg
<1, void**>();
1384 auto& size
= aArguments
->Arg
<2, size_t>();
1385 *address
= AllocateMemory(size
, MemoryKind::Tracked
);
1386 aArguments
->Rval
<size_t>() = KERN_SUCCESS
;
1387 return PreambleResult::Veto
;
1390 static PreambleResult
1391 Preamble_mach_vm_deallocate(CallArguments
* aArguments
)
1393 auto& address
= aArguments
->Arg
<1, void*>();
1394 auto& size
= aArguments
->Arg
<2, size_t>();
1395 DeallocateMemory(address
, size
, MemoryKind::Tracked
);
1396 aArguments
->Rval
<size_t>() = KERN_SUCCESS
;
1397 return PreambleResult::Veto
;
1400 static PreambleResult
1401 Preamble_mach_vm_protect(CallArguments
* aArguments
)
1403 // Ignore any mach_vm_protect calls that occur after saving a checkpoint, as for mprotect.
1404 if (!HasSavedCheckpoint()) {
1405 return PreambleResult::PassThrough
;
1407 aArguments
->Rval
<size_t>() = KERN_SUCCESS
;
1408 return PreambleResult::Veto
;
1411 static PreambleResult
1412 Preamble_vm_purgable_control(CallArguments
* aArguments
)
1414 // Never allow purging of volatile memory, to simplify memory snapshots.
1415 auto& state
= aArguments
->Arg
<3, int*>();
1416 *state
= VM_PURGABLE_NONVOLATILE
;
1417 aArguments
->Rval
<size_t>() = KERN_SUCCESS
;
1418 return PreambleResult::Veto
;
1421 static PreambleResult
1422 Preamble_vm_copy(CallArguments
* aArguments
)
1424 // Asking the kernel to copy memory doesn't work right if the destination is
1425 // non-writable, so do the copy manually.
1426 auto& src
= aArguments
->Arg
<1, void*>();
1427 auto& size
= aArguments
->Arg
<2, size_t>();
1428 auto& dest
= aArguments
->Arg
<3, void*>();
1429 memcpy(dest
, src
, size
);
1430 aArguments
->Rval
<size_t>() = KERN_SUCCESS
;
1431 return PreambleResult::Veto
;
1434 ///////////////////////////////////////////////////////////////////////////////
1435 // NSPR redirections
1436 ///////////////////////////////////////////////////////////////////////////////
1438 // Even though NSPR is compiled as part of firefox, it is easier to just
1439 // redirect this stuff than get record/replay related changes into the source.
1441 static PreambleResult
1442 Preamble_PL_NewHashTable(CallArguments
* aArguments
)
1444 auto& keyHash
= aArguments
->Arg
<1, PLHashFunction
>();
1445 auto& keyCompare
= aArguments
->Arg
<2, PLHashComparator
>();
1446 auto& valueCompare
= aArguments
->Arg
<3, PLHashComparator
>();
1447 auto& allocOps
= aArguments
->Arg
<4, const PLHashAllocOps
*>();
1448 auto& allocPriv
= aArguments
->Arg
<5, void*>();
1450 GeneratePLHashTableCallbacks(&keyHash
, &keyCompare
, &valueCompare
, &allocOps
, &allocPriv
);
1451 return PreambleResult::PassThrough
;
1454 static PreambleResult
1455 Preamble_PL_HashTableDestroy(CallArguments
* aArguments
)
1457 auto& table
= aArguments
->Arg
<0, PLHashTable
*>();
1459 void* priv
= table
->allocPriv
;
1460 OriginalCall(PL_HashTableDestroy
, void, table
);
1461 DestroyPLHashTableCallbacks(priv
);
1462 return PreambleResult::Veto
;
1465 ///////////////////////////////////////////////////////////////////////////////
1466 // Objective C redirections
1467 ///////////////////////////////////////////////////////////////////////////////
1469 // From Foundation.h, which has lots of Objective C declarations and can't be
1471 struct NSFastEnumerationState
1473 unsigned long state
;
1475 unsigned long* mutationsPtr
;
1476 unsigned long extra
[5];
1479 // Emulation of NSFastEnumeration on arrays does not replay any exceptions
1480 // thrown by mutating the array while it is being iterated over.
1481 static unsigned long gNeverChange
;
1483 static PreambleResult
1484 Preamble_objc_msgSend(CallArguments
* aArguments
)
1486 if (!AreThreadEventsPassedThrough()) {
1487 auto message
= aArguments
->Arg
<1, const char*>();
1489 // Watch for some top level NSApplication messages that can cause Gecko
1490 // events to be processed.
1491 if (!strcmp(message
, "run") ||
1492 !strcmp(message
, "nextEventMatchingMask:untilDate:inMode:dequeue:"))
1494 PassThroughThreadEventsAllowCallbacks([&]() {
1495 RecordReplayInvokeCall(CallEvent_objc_msgSend
, aArguments
);
1497 RecordReplayBytes(&aArguments
->Rval
<size_t>(), sizeof(size_t));
1498 return PreambleResult::Veto
;
1501 return PreambleResult::Redirect
;
1505 RR_objc_msgSend(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
1507 auto& object
= aArguments
->Arg
<0, id
>();
1508 auto& message
= aArguments
->Arg
<1, const char*>();
1510 aEvents
.CheckInput(message
);
1512 aEvents
.RecordOrReplayValue(&aArguments
->Rval
<size_t>());
1513 aEvents
.RecordOrReplayBytes(&aArguments
->FloatRval(), sizeof(double));
1515 // Do some extra recording on messages that return additional state.
1517 if (!strcmp(message
, "countByEnumeratingWithState:objects:count:")) {
1518 auto& state
= aArguments
->Arg
<2, NSFastEnumerationState
*>();
1519 auto& rval
= aArguments
->Rval
<size_t>();
1520 if (IsReplaying()) {
1521 state
->itemsPtr
= NewLeakyArray
<id
>(rval
);
1522 state
->mutationsPtr
= &gNeverChange
;
1524 aEvents
.RecordOrReplayBytes(state
->itemsPtr
, rval
* sizeof(id
));
1527 if (!strcmp(message
, "getCharacters:")) {
1529 if (IsRecording()) {
1530 AutoPassThroughThreadEvents pt
;
1531 len
= CFStringGetLength((CFStringRef
) object
);
1533 aEvents
.RecordOrReplayValue(&len
);
1534 aEvents
.RecordOrReplayBytes(aArguments
->Arg
<2, void*>(), len
* sizeof(wchar_t));
1537 if (!strcmp(message
, "UTF8String") || !strcmp(message
, "cStringUsingEncoding:")) {
1538 auto& rval
= aArguments
->Rval
<char*>();
1539 size_t len
= IsRecording() ? strlen(rval
) : 0;
1540 aEvents
.RecordOrReplayValue(&len
);
1541 if (IsReplaying()) {
1542 rval
= NewLeakyArray
<char>(len
+ 1);
1544 aEvents
.RecordOrReplayBytes(rval
, len
+ 1);
1548 static PreambleResult
1549 MiddlemanPreamble_objc_msgSend(CallArguments
* aArguments
)
1551 auto message
= aArguments
->Arg
<1, const char*>();
1553 // Ignore uses of NSAutoreleasePool after diverging from the recording.
1554 // These are not performed in the middleman because the middleman has its
1555 // own autorelease pool, and because the middleman can process calls from
1556 // multiple threads which will cause these messages to behave differently.
1557 if (!strcmp(message
, "alloc") ||
1558 !strcmp(message
, "drain") ||
1559 !strcmp(message
, "init") ||
1560 !strcmp(message
, "release")) {
1561 // Fake a return value in case the caller null checks it.
1562 aArguments
->Rval
<size_t>() = 1;
1563 return PreambleResult::Veto
;
1566 // Other messages will be handled by Middleman_objc_msgSend.
1567 return PreambleResult::Redirect
;
1571 Middleman_PerformSelector(MiddlemanCallContext
& aCx
)
1573 Middleman_CString
<2>(aCx
);
1574 Middleman_CFTypeArg
<3>(aCx
);
1576 // The behavior of performSelector:withObject: varies depending on the
1577 // selector used, so use a whitelist here.
1578 if (aCx
.mPhase
== MiddlemanCallPhase::ReplayPreface
) {
1579 auto str
= aCx
.mArguments
->Arg
<2, const char*>();
1580 if (strcmp(str
, "appearanceNamed:")) {
1586 Middleman_AutoreleaseCFTypeRval(aCx
);
1590 Middleman_DictionaryWithObjects(MiddlemanCallContext
& aCx
)
1592 Middleman_Buffer
<2, 4, const void*>(aCx
);
1593 Middleman_Buffer
<3, 4, const void*>(aCx
);
1595 if (aCx
.AccessPreface()) {
1596 auto objects
= aCx
.mArguments
->Arg
<2, const void**>();
1597 auto keys
= aCx
.mArguments
->Arg
<3, const void**>();
1598 auto count
= aCx
.mArguments
->Arg
<4, CFIndex
>();
1600 for (CFIndex i
= 0; i
< count
; i
++) {
1601 Middleman_ObjCInput(aCx
, (id
*) &objects
[i
]);
1602 Middleman_ObjCInput(aCx
, (id
*) &keys
[i
]);
1606 Middleman_AutoreleaseCFTypeRval(aCx
);
1610 Middleman_NSStringGetCharacters(MiddlemanCallContext
& aCx
)
1612 auto string
= aCx
.mArguments
->Arg
<0, CFStringRef
>();
1613 auto& buffer
= aCx
.mArguments
->Arg
<2, void*>();
1615 if (aCx
.mPhase
== MiddlemanCallPhase::MiddlemanInput
) {
1616 size_t len
= CFStringGetLength(string
);
1617 buffer
= aCx
.AllocateBytes(len
* sizeof(UniChar
));
1620 if (aCx
.AccessOutput()) {
1622 (aCx
.mPhase
== MiddlemanCallPhase::MiddlemanOutput
) ? CFStringGetLength(string
) : 0;
1623 aCx
.ReadOrWriteOutputBytes(&len
, sizeof(len
));
1624 if (aCx
.mReplayOutputIsOld
) {
1625 buffer
= aCx
.AllocateBytes(len
* sizeof(UniChar
));
1627 aCx
.ReadOrWriteOutputBytes(buffer
, len
* sizeof(UniChar
));
1631 struct ObjCMessageInfo
1633 const char* mMessage
;
1634 MiddlemanCallFn mMiddlemanCall
;
1637 // All Objective C messages that can be called in the middleman, and hooks for
1638 // capturing any inputs and outputs other than the object and message.
1639 static ObjCMessageInfo gObjCMiddlemanCallMessages
[] = {
1640 { "performSelector:withObject:", Middleman_PerformSelector
},
1641 { "respondsToSelector:", Middleman_CString
<2> },
1645 { "objectAtIndex:", Middleman_AutoreleaseCFTypeRval
},
1648 { "currentControlTint" },
1651 { "dictionaryWithObjects:forKeys:count:", Middleman_DictionaryWithObjects
},
1654 { "boldSystemFontOfSize:", Middleman_AutoreleaseCFTypeRval
},
1655 { "controlContentFontOfSize:", Middleman_AutoreleaseCFTypeRval
},
1656 { "familyName", Middleman_AutoreleaseCFTypeRval
},
1657 { "fontDescriptor", Middleman_AutoreleaseCFTypeRval
},
1658 { "menuBarFontOfSize:", Middleman_AutoreleaseCFTypeRval
},
1660 { "smallSystemFontSize" },
1661 { "systemFontOfSize:", Middleman_AutoreleaseCFTypeRval
},
1662 { "toolTipsFontOfSize:", Middleman_AutoreleaseCFTypeRval
},
1663 { "userFontOfSize:", Middleman_AutoreleaseCFTypeRval
},
1666 { "availableMembersOfFontFamily:", Middleman_Compose
<Middleman_CFTypeArg
<2>, Middleman_AutoreleaseCFTypeRval
> },
1667 { "sharedFontManager", Middleman_AutoreleaseCFTypeRval
},
1670 { "numberWithBool:", Middleman_AutoreleaseCFTypeRval
},
1671 { "unsignedIntValue" },
1674 { "getCharacters:", Middleman_NSStringGetCharacters
},
1675 { "hasSuffix:", Middleman_CFTypeArg
<2> },
1676 { "isEqualToString:", Middleman_CFTypeArg
<2> },
1678 { "rangeOfString:options:", Middleman_CFTypeArg
<2> },
1679 { "stringWithCharacters:length:",
1680 Middleman_Compose
<Middleman_Buffer
<2, 3, UniChar
>, Middleman_AutoreleaseCFTypeRval
> },
1683 { "coreUIRenderer", Middleman_AutoreleaseCFTypeRval
},
1686 { "symbolicTraits" },
1690 Middleman_objc_msgSend(MiddlemanCallContext
& aCx
)
1692 auto& object
= aCx
.mArguments
->Arg
<0, id
>();
1693 auto message
= aCx
.mArguments
->Arg
<1, const char*>();
1695 for (const ObjCMessageInfo
& info
: gObjCMiddlemanCallMessages
) {
1696 if (!strcmp(info
.mMessage
, message
)) {
1697 if (aCx
.AccessPreface()) {
1698 Middleman_ObjCInput(aCx
, &object
);
1700 if (info
.mMiddlemanCall
&& !aCx
.mFailed
) {
1701 info
.mMiddlemanCall(aCx
);
1707 if (aCx
.mPhase
== MiddlemanCallPhase::ReplayPreface
) {
1712 ///////////////////////////////////////////////////////////////////////////////
1713 // Cocoa redirections
1714 ///////////////////////////////////////////////////////////////////////////////
1717 Middleman_CFArrayCreate(MiddlemanCallContext
& aCx
)
1719 Middleman_Buffer
<1, 2, const void*>(aCx
);
1721 if (aCx
.AccessPreface()) {
1722 auto values
= aCx
.mArguments
->Arg
<1, const void**>();
1723 auto numValues
= aCx
.mArguments
->Arg
<2, CFIndex
>();
1724 auto& callbacks
= aCx
.mArguments
->Arg
<3, const CFArrayCallBacks
*>();
1726 // For now we only support creating arrays with CFType elements.
1727 if (aCx
.mPhase
== MiddlemanCallPhase::MiddlemanInput
) {
1728 callbacks
= &kCFTypeArrayCallBacks
;
1730 MOZ_RELEASE_ASSERT(callbacks
== &kCFTypeArrayCallBacks
);
1733 for (CFIndex i
= 0; i
< numValues
; i
++) {
1734 Middleman_ObjCInput(aCx
, (id
*) &values
[i
]);
1738 Middleman_CreateCFTypeRval(aCx
);
1742 Middleman_CFArrayGetValueAtIndex(MiddlemanCallContext
& aCx
)
1744 Middleman_CFTypeArg
<0>(aCx
);
1746 auto array
= aCx
.mArguments
->Arg
<0, id
>();
1748 // We can't probe the array to see what callbacks it uses, so look at where
1749 // it came from to see whether its elements should be treated as CFTypes.
1750 MiddlemanCall
* call
= LookupMiddlemanCall(array
);
1751 bool isCFTypeRval
= false;
1753 switch (call
->mCallId
) {
1754 case CallEvent_CTLineGetGlyphRuns
:
1755 case CallEvent_CTFontDescriptorCreateMatchingFontDescriptors
:
1756 isCFTypeRval
= true;
1764 Middleman_CFTypeRval(aCx
);
1769 RR_CFDataGetBytePtr(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
1771 auto& rval
= aArguments
->Rval
<UInt8
*>();
1774 if (IsRecording()) {
1775 len
= OriginalCall(CFDataGetLength
, size_t, aArguments
->Arg
<0, CFDataRef
>());
1777 aEvents
.RecordOrReplayValue(&len
);
1778 if (IsReplaying()) {
1779 rval
= NewLeakyArray
<UInt8
>(len
);
1781 aEvents
.RecordOrReplayBytes(rval
, len
);
1785 Middleman_CFDataGetBytePtr(MiddlemanCallContext
& aCx
)
1787 Middleman_CFTypeArg
<0>(aCx
);
1789 auto data
= aCx
.mArguments
->Arg
<0, CFDataRef
>();
1790 auto& buffer
= aCx
.mArguments
->Rval
<void*>();
1792 if (aCx
.AccessOutput()) {
1793 size_t len
= (aCx
.mPhase
== MiddlemanCallPhase::MiddlemanOutput
) ? CFDataGetLength(data
) : 0;
1794 aCx
.ReadOrWriteOutputBytes(&len
, sizeof(len
));
1795 if (aCx
.mPhase
== MiddlemanCallPhase::ReplayOutput
) {
1796 buffer
= aCx
.AllocateBytes(len
);
1798 aCx
.ReadOrWriteOutputBytes(buffer
, len
);
1803 Middleman_CFDictionaryCreate(MiddlemanCallContext
& aCx
)
1805 Middleman_Buffer
<1, 3, const void*>(aCx
);
1806 Middleman_Buffer
<2, 3, const void*>(aCx
);
1808 if (aCx
.AccessPreface()) {
1809 auto keys
= aCx
.mArguments
->Arg
<1, const void**>();
1810 auto values
= aCx
.mArguments
->Arg
<2, const void**>();
1811 auto numValues
= aCx
.mArguments
->Arg
<3, CFIndex
>();
1812 auto& keyCallbacks
= aCx
.mArguments
->Arg
<4, const CFDictionaryKeyCallBacks
*>();
1813 auto& valueCallbacks
= aCx
.mArguments
->Arg
<5, const CFDictionaryValueCallBacks
*>();
1815 // For now we only support creating dictionaries with CFType keys and values.
1816 if (aCx
.mPhase
== MiddlemanCallPhase::MiddlemanInput
) {
1817 keyCallbacks
= &kCFTypeDictionaryKeyCallBacks
;
1818 valueCallbacks
= &kCFTypeDictionaryValueCallBacks
;
1820 MOZ_RELEASE_ASSERT(keyCallbacks
== &kCFTypeDictionaryKeyCallBacks
);
1821 MOZ_RELEASE_ASSERT(valueCallbacks
== &kCFTypeDictionaryValueCallBacks
);
1824 for (CFIndex i
= 0; i
< numValues
; i
++) {
1825 Middleman_ObjCInput(aCx
, (id
*) &keys
[i
]);
1826 Middleman_ObjCInput(aCx
, (id
*) &values
[i
]);
1830 Middleman_CreateCFTypeRval(aCx
);
1833 static void DummyCFNotificationCallback(CFNotificationCenterRef aCenter
, void* aObserver
,
1834 CFStringRef aName
, const void* aObject
,
1835 CFDictionaryRef aUserInfo
)
1841 static PreambleResult
1842 Preamble_CFNotificationCenterAddObserver(CallArguments
* aArguments
)
1844 auto& callback
= aArguments
->Arg
<2, CFNotificationCallback
>();
1845 if (!AreThreadEventsPassedThrough()) {
1846 callback
= DummyCFNotificationCallback
;
1848 return PreambleResult::Redirect
;
1852 CFNumberTypeBytes(CFNumberType aType
)
1855 case kCFNumberSInt8Type
: return sizeof(int8_t);
1856 case kCFNumberSInt16Type
: return sizeof(int16_t);
1857 case kCFNumberSInt32Type
: return sizeof(int32_t);
1858 case kCFNumberSInt64Type
: return sizeof(int64_t);
1859 case kCFNumberFloat32Type
: return sizeof(float);
1860 case kCFNumberFloat64Type
: return sizeof(double);
1861 case kCFNumberCharType
: return sizeof(char);
1862 case kCFNumberShortType
: return sizeof(short);
1863 case kCFNumberIntType
: return sizeof(int);
1864 case kCFNumberLongType
: return sizeof(long);
1865 case kCFNumberLongLongType
: return sizeof(long long);
1866 case kCFNumberFloatType
: return sizeof(float);
1867 case kCFNumberDoubleType
: return sizeof(double);
1868 case kCFNumberCFIndexType
: return sizeof(CFIndex
);
1869 case kCFNumberNSIntegerType
: return sizeof(long);
1870 case kCFNumberCGFloatType
: return sizeof(CGFloat
);
1871 default: MOZ_CRASH();
1876 Middleman_CFNumberCreate(MiddlemanCallContext
& aCx
)
1878 if (aCx
.AccessPreface()) {
1879 auto numberType
= aCx
.mArguments
->Arg
<1, CFNumberType
>();
1880 auto& valuePtr
= aCx
.mArguments
->Arg
<2, void*>();
1881 aCx
.ReadOrWritePrefaceBuffer(&valuePtr
, CFNumberTypeBytes(numberType
));
1884 Middleman_CreateCFTypeRval(aCx
);
1888 RR_CFNumberGetValue(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
1890 auto& type
= aArguments
->Arg
<1, CFNumberType
>();
1891 auto& value
= aArguments
->Arg
<2, void*>();
1893 aEvents
.CheckInput(type
);
1894 aEvents
.RecordOrReplayBytes(value
, CFNumberTypeBytes(type
));
1898 Middleman_CFNumberGetValue(MiddlemanCallContext
& aCx
)
1900 Middleman_CFTypeArg
<0>(aCx
);
1902 auto& buffer
= aCx
.mArguments
->Arg
<2, void*>();
1903 auto type
= aCx
.mArguments
->Arg
<1, CFNumberType
>();
1904 aCx
.ReadOrWriteOutputBuffer(&buffer
, CFNumberTypeBytes(type
));
1907 static PreambleResult
1908 MiddlemanPreamble_CFRetain(CallArguments
* aArguments
)
1910 aArguments
->Rval
<size_t>() = aArguments
->Arg
<0, size_t>();
1911 return PreambleResult::Veto
;
1914 static PreambleResult
1915 Preamble_CFRunLoopSourceCreate(CallArguments
* aArguments
)
1917 if (!AreThreadEventsPassedThrough()) {
1918 auto& cx
= aArguments
->Arg
<2, CFRunLoopSourceContext
*>();
1920 RegisterCallbackData(BitwiseCast
<void*>(cx
->perform
));
1921 RegisterCallbackData(cx
->info
);
1923 if (IsRecording()) {
1924 CallbackWrapperData
* wrapperData
= new CallbackWrapperData(cx
->perform
, cx
->info
);
1925 cx
->perform
= CFRunLoopPerformCallBackWrapper
;
1926 cx
->info
= wrapperData
;
1929 return PreambleResult::Redirect
;
1932 struct ContextDataInfo
1934 CGContextRef mContext
;
1938 ContextDataInfo(CGContextRef aContext
, void* aData
, size_t aDataSize
)
1939 : mContext(aContext
), mData(aData
), mDataSize(aDataSize
)
1943 static StaticInfallibleVector
<ContextDataInfo
> gContextData
;
1946 RR_CGBitmapContextCreateWithData(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
1948 auto& data
= aArguments
->Arg
<0, void*>();
1949 auto& height
= aArguments
->Arg
<2, size_t>();
1950 auto& bytesPerRow
= aArguments
->Arg
<4, size_t>();
1951 auto& rval
= aArguments
->Rval
<CGContextRef
>();
1953 MOZ_RELEASE_ASSERT(Thread::CurrentIsMainThread());
1955 // When replaying, Middleman_CGBitmapContextCreateWithData will take care of
1956 // updating gContextData with the right context pointer (after being mangled
1957 // in Middleman_SystemOutput).
1958 if (IsRecording()) {
1959 gContextData
.emplaceBack(rval
, data
, height
* bytesPerRow
);
1964 Middleman_CGBitmapContextCreateWithData(MiddlemanCallContext
& aCx
)
1966 Middleman_CFTypeArg
<5>(aCx
);
1967 Middleman_StackArgumentData
<3 * sizeof(size_t)>(aCx
);
1968 Middleman_CreateCFTypeRval(aCx
);
1970 auto& data
= aCx
.mArguments
->Arg
<0, void*>();
1971 auto height
= aCx
.mArguments
->Arg
<2, size_t>();
1972 auto bytesPerRow
= aCx
.mArguments
->Arg
<4, size_t>();
1973 auto rval
= aCx
.mArguments
->Rval
<CGContextRef
>();
1975 if (aCx
.mPhase
== MiddlemanCallPhase::MiddlemanInput
) {
1976 data
= aCx
.AllocateBytes(height
* bytesPerRow
);
1979 if ((aCx
.mPhase
== MiddlemanCallPhase::ReplayPreface
&& !HasDivergedFromRecording()) ||
1980 (aCx
.AccessOutput() && !aCx
.mReplayOutputIsOld
)) {
1981 gContextData
.emplaceBack(rval
, data
, height
* bytesPerRow
);
1985 template <size_t ContextArgument
>
1987 RR_FlushCGContext(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
1989 auto& context
= aArguments
->Arg
<ContextArgument
, CGContextRef
>();
1991 for (int i
= gContextData
.length() - 1; i
>= 0; i
--) {
1992 if (context
== gContextData
[i
].mContext
) {
1993 aEvents
.RecordOrReplayBytes(gContextData
[i
].mData
, gContextData
[i
].mDataSize
);
1997 MOZ_CRASH("RR_FlushCGContext");
2000 template <size_t ContextArgument
>
2002 Middleman_FlushCGContext(MiddlemanCallContext
& aCx
)
2004 auto context
= aCx
.mArguments
->Arg
<ContextArgument
, CGContextRef
>();
2006 // Update the contents of the target buffer in the middleman process to match
2007 // the current contents in the replaying process.
2008 if (aCx
.AccessInput()) {
2009 for (int i
= gContextData
.length() - 1; i
>= 0; i
--) {
2010 if (context
== gContextData
[i
].mContext
) {
2011 aCx
.ReadOrWriteInputBytes(gContextData
[i
].mData
, gContextData
[i
].mDataSize
);
2015 MOZ_CRASH("Middleman_FlushCGContext");
2018 // After performing the call, the buffer in the replaying process is updated
2019 // to match any data written by the middleman.
2020 if (aCx
.AccessOutput()) {
2021 for (int i
= gContextData
.length() - 1; i
>= 0; i
--) {
2022 if (context
== gContextData
[i
].mContext
) {
2023 aCx
.ReadOrWriteOutputBytes(gContextData
[i
].mData
, gContextData
[i
].mDataSize
);
2027 MOZ_CRASH("Middleman_FlushCGContext");
2031 static PreambleResult
2032 Preamble_CGContextRestoreGState(CallArguments
* aArguments
)
2034 return IsRecording() ? PreambleResult::PassThrough
: PreambleResult::Veto
;
2038 RR_CGDataProviderCreateWithData(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
2040 auto& info
= aArguments
->Arg
<0, void*>();
2041 auto& data
= aArguments
->Arg
<1, const void*>();
2042 auto& size
= aArguments
->Arg
<2, size_t>();
2043 auto& releaseData
= aArguments
->Arg
<3, CGDataProviderReleaseDataCallback
>();
2045 if (IsReplaying()) {
2046 // Immediately release the data, since there is no data provider to do it for us.
2047 releaseData(info
, data
, size
);
2051 static PreambleResult
2052 Preamble_CGPathApply(CallArguments
* aArguments
)
2054 if (AreThreadEventsPassedThrough()) {
2055 return PreambleResult::Redirect
;
2058 auto& path
= aArguments
->Arg
<0, CGPathRef
>();
2059 auto& data
= aArguments
->Arg
<1, void*>();
2060 auto& function
= aArguments
->Arg
<2, CGPathApplierFunction
>();
2062 RegisterCallbackData(BitwiseCast
<void*>(function
));
2063 RegisterCallbackData(data
);
2064 PassThroughThreadEventsAllowCallbacks([&]() {
2065 CallbackWrapperData
wrapperData(function
, data
);
2066 OriginalCall(CGPathApply
, void, path
, &wrapperData
, CGPathApplierFunctionWrapper
);
2068 RemoveCallbackData(data
);
2070 return PreambleResult::Veto
;
2073 // Note: We only redirect CTRunGetGlyphsPtr, not CTRunGetGlyphs. The latter may
2074 // be implemented with a loop that jumps back into the code we overwrite with a
2075 // jump, a pattern which ProcessRedirect.cpp does not handle. For the moment,
2076 // Gecko code only calls CTRunGetGlyphs if CTRunGetGlyphsPtr fails, so make
2077 // sure that CTRunGetGlyphsPtr always succeeds when it is being recorded.
2078 // The same concerns apply to CTRunGetPositionsPtr and CTRunGetStringIndicesPtr,
2079 // so they are all handled here.
2080 template <typename ElemType
, void (*GetElemsFn
)(CTRunRef
, CFRange
, ElemType
*)>
2082 RR_CTRunGetElements(Stream
& aEvents
, CallArguments
* aArguments
, ErrorType
* aError
)
2084 auto& run
= aArguments
->Arg
<0, CTRunRef
>();
2085 auto& rval
= aArguments
->Rval
<ElemType
*>();
2088 if (IsRecording()) {
2089 AutoPassThroughThreadEvents pt
;
2090 count
= CTRunGetGlyphCount(run
);
2092 rval
= NewLeakyArray
<ElemType
>(count
);
2093 GetElemsFn(run
, CFRangeMake(0, 0), rval
);
2096 aEvents
.RecordOrReplayValue(&count
);
2097 if (IsReplaying()) {
2098 rval
= NewLeakyArray
<ElemType
>(count
);
2100 aEvents
.RecordOrReplayBytes(rval
, count
* sizeof(ElemType
));
2103 template <typename ElemType
, void (*GetElemsFn
)(CTRunRef
, CFRange
, ElemType
*)>
2105 Middleman_CTRunGetElements(MiddlemanCallContext
& aCx
)
2107 Middleman_CFTypeArg
<0>(aCx
);
2109 if (aCx
.AccessOutput()) {
2110 auto run
= aCx
.mArguments
->Arg
<0, CTRunRef
>();
2111 auto& rval
= aCx
.mArguments
->Rval
<ElemType
*>();
2114 if (IsMiddleman()) {
2115 count
= CTRunGetGlyphCount(run
);
2117 rval
= (ElemType
*) aCx
.AllocateBytes(count
* sizeof(ElemType
));
2118 GetElemsFn(run
, CFRangeMake(0, 0), rval
);
2121 aCx
.ReadOrWriteOutputBytes(&count
, sizeof(count
));
2122 if (IsReplaying()) {
2123 rval
= (ElemType
*) aCx
.AllocateBytes(count
* sizeof(ElemType
));
2125 aCx
.ReadOrWriteOutputBytes(rval
, count
* sizeof(ElemType
));
2129 static PreambleResult
2130 Preamble_OSSpinLockLock(CallArguments
* aArguments
)
2132 auto& lock
= aArguments
->Arg
<0, OSSpinLock
*>();
2134 // These spin locks never need to be recorded, but they are used by malloc
2135 // and can end up calling other recorded functions like mach_absolute_time,
2136 // so make sure events are passed through here. Note that we don't have to
2137 // redirect OSSpinLockUnlock, as it doesn't have these issues.
2138 AutoEnsurePassThroughThreadEventsUseStackPointer pt
;
2139 OriginalCall(OSSpinLockLock
, void, lock
);
2141 return PreambleResult::Veto
;
2144 ///////////////////////////////////////////////////////////////////////////////
2145 // Redirection generation
2146 ///////////////////////////////////////////////////////////////////////////////
2148 #define MAKE_REDIRECTION_ENTRY(aName, ...) \
2149 { #aName, nullptr, nullptr, __VA_ARGS__ },
2151 Redirection gRedirections
[] = {
2152 FOR_EACH_REDIRECTION(MAKE_REDIRECTION_ENTRY
)
2156 #undef MAKE_REDIRECTION_ENTRY
2158 ///////////////////////////////////////////////////////////////////////////////
2159 // Direct system call API
2160 ///////////////////////////////////////////////////////////////////////////////
2163 SymbolNameRaw(void* aPtr
)
2166 return (dladdr(aPtr
, &info
) && info
.dli_sname
) ? info
.dli_sname
: "???";
2170 DirectAllocateMemory(void* aAddress
, size_t aSize
)
2172 void* res
= OriginalCall(mmap
, void*,
2173 aAddress
, aSize
, PROT_READ
| PROT_WRITE
| PROT_EXEC
,
2174 MAP_ANON
| MAP_PRIVATE
, -1, 0);
2175 MOZ_RELEASE_ASSERT(res
&& res
!= (void*)-1);
2180 DirectDeallocateMemory(void* aAddress
, size_t aSize
)
2182 ssize_t rv
= OriginalCall(munmap
, int, aAddress
, aSize
);
2183 MOZ_RELEASE_ASSERT(rv
>= 0);
2187 DirectWriteProtectMemory(void* aAddress
, size_t aSize
, bool aExecutable
,
2188 bool aIgnoreFailures
/* = false */)
2190 ssize_t rv
= OriginalCall(mprotect
, int, aAddress
, aSize
,
2191 PROT_READ
| (aExecutable
? PROT_EXEC
: 0));
2192 MOZ_RELEASE_ASSERT(aIgnoreFailures
|| rv
== 0);
2196 DirectUnprotectMemory(void* aAddress
, size_t aSize
, bool aExecutable
,
2197 bool aIgnoreFailures
/* = false */)
2199 ssize_t rv
= OriginalCall(mprotect
, int, aAddress
, aSize
,
2200 PROT_READ
| PROT_WRITE
| (aExecutable
? PROT_EXEC
: 0));
2201 MOZ_RELEASE_ASSERT(aIgnoreFailures
|| rv
== 0);
2205 DirectSeekFile(FileHandle aFd
, uint64_t aOffset
)
2207 static_assert(sizeof(uint64_t) == sizeof(off_t
), "off_t should have 64 bits");
2208 ssize_t rv
= HANDLE_EINTR(OriginalCall(lseek
, int, aFd
, aOffset
, SEEK_SET
));
2209 MOZ_RELEASE_ASSERT(rv
>= 0);
2213 DirectOpenFile(const char* aFilename
, bool aWriting
)
2215 int flags
= aWriting
? (O_WRONLY
| O_CREAT
| O_TRUNC
) : O_RDONLY
;
2216 int perms
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
2217 int fd
= HANDLE_EINTR(OriginalCall(open
, int, aFilename
, flags
, perms
));
2218 MOZ_RELEASE_ASSERT(fd
> 0);
2223 DirectCloseFile(FileHandle aFd
)
2225 ssize_t rv
= HANDLE_EINTR(OriginalCall(close
, int, aFd
));
2226 MOZ_RELEASE_ASSERT(rv
>= 0);
2230 DirectDeleteFile(const char* aFilename
)
2232 ssize_t rv
= unlink(aFilename
);
2233 MOZ_RELEASE_ASSERT(rv
>= 0 || errno
== ENOENT
);
2237 DirectWrite(FileHandle aFd
, const void* aData
, size_t aSize
)
2239 ssize_t rv
= HANDLE_EINTR(OriginalCall(write
, int, aFd
, aData
, aSize
));
2240 MOZ_RELEASE_ASSERT((size_t) rv
== aSize
);
2244 DirectPrint(const char* aString
)
2246 DirectWrite(STDERR_FILENO
, aString
, strlen(aString
));
2250 DirectRead(FileHandle aFd
, void* aData
, size_t aSize
)
2252 // Clear the memory in case it is write protected by the memory snapshot
2254 memset(aData
, 0, aSize
);
2255 ssize_t rv
= HANDLE_EINTR(OriginalCall(read
, int, aFd
, aData
, aSize
));
2256 MOZ_RELEASE_ASSERT(rv
>= 0);
2261 DirectCreatePipe(FileHandle
* aWriteFd
, FileHandle
* aReadFd
)
2264 ssize_t rv
= OriginalCall(pipe
, int, fds
);
2265 MOZ_RELEASE_ASSERT(rv
>= 0);
2270 static double gAbsoluteToNanosecondsRate
;
2273 InitializeCurrentTime()
2275 AbsoluteTime time
= { 1000000, 0 };
2276 Nanoseconds rate
= AbsoluteToNanoseconds(time
);
2277 MOZ_RELEASE_ASSERT(!rate
.hi
);
2278 gAbsoluteToNanosecondsRate
= rate
.lo
/ 1000000.0;
2284 return OriginalCall(mach_absolute_time
, int64_t) * gAbsoluteToNanosecondsRate
/ 1000.0;
2288 DirectSpawnThread(void (*aFunction
)(void*), void* aArgument
)
2290 MOZ_RELEASE_ASSERT(IsMiddleman() || AreThreadEventsPassedThrough());
2292 pthread_attr_t attr
;
2293 int rv
= pthread_attr_init(&attr
);
2294 MOZ_RELEASE_ASSERT(rv
== 0);
2296 rv
= pthread_attr_setstacksize(&attr
, 2 * 1024 * 1024);
2297 MOZ_RELEASE_ASSERT(rv
== 0);
2299 rv
= pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_JOINABLE
);
2300 MOZ_RELEASE_ASSERT(rv
== 0);
2303 rv
= OriginalCall(pthread_create
, int, &pthread
, &attr
, (void* (*)(void*)) aFunction
, aArgument
);
2304 MOZ_RELEASE_ASSERT(rv
== 0);
2306 rv
= pthread_attr_destroy(&attr
);
2307 MOZ_RELEASE_ASSERT(rv
== 0);