Bug 1431441 - Part 7 - Relax WebReplay fcntl rules to avoid sqlite crash r=froydnj
[gecko.git] / toolkit / recordreplay / ProcessRedirectDarwin.cpp
blob8d3be45f1aa6901a50d41c1b76070bfe2ae9b9f9
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"
12 #include "Lock.h"
13 #include "MemorySnapshot.h"
14 #include "ProcessRecordReplay.h"
15 #include "ProcessRewind.h"
16 #include "base/eintr_wrapper.h"
18 #include <dlfcn.h>
19 #include <fcntl.h>
20 #include <signal.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>
29 #include <sys/attr.h>
30 #include <sys/event.h>
31 #include <sys/mman.h>
32 #include <sys/mount.h>
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <sys/time.h>
36 #include <time.h>
38 #include <Carbon/Carbon.h>
39 #include <SystemConfiguration/SystemConfiguration.h>
40 #include <objc/objc-runtime.h>
42 namespace mozilla {
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) \
98 MACRO(stat$INODE64, \
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)>>>) \
117 MACRO(getrusage, \
118 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct rusage)>>) \
119 MACRO(__getrlimit, \
120 RR_SaveRvalHadErrorNegative<RR_WriteBufferFixedSize<1, sizeof(struct rlimit)>>) \
121 MACRO(__setrlimit, RR_SaveRvalHadErrorNegative) \
122 MACRO(sigprocmask, \
123 RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(sigset_t)>>, \
124 nullptr, nullptr, Preamble_PassThrough) \
125 MACRO(sigaltstack, \
126 RR_SaveRvalHadErrorNegative<RR_WriteOptionalBufferFixedSize<2, sizeof(stack_t)>>) \
127 MACRO(sigaction, \
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) \
193 MACRO(realpath, \
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) \
210 MACRO(tzset) \
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< \
309 RR_ScalarRval, \
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< \
541 RR_ScalarRval, \
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< \
575 RR_ScalarRval, \
576 RR_WriteOptionalBufferFixedSize<4, sizeof(FSRef)>, \
577 RR_WriteOptionalBufferFixedSize<5, sizeof(CFURLRef)>>) \
578 MACRO(LSGetApplicationForURL, RR_Compose< \
579 RR_ScalarRval, \
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>) \
584 MACRO(NSRectFill) \
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 ,
605 enum CallEvent { \
606 FOR_EACH_REDIRECTION(MAKE_CALL_EVENT) \
607 CallEvent_Count \
610 #undef MAKE_CALL_EVENT
612 ///////////////////////////////////////////////////////////////////////////////
613 // Callbacks
614 ///////////////////////////////////////////////////////////////////////////////
616 enum CallbackEvent {
617 CallbackEvent_CFRunLoopPerformCallBack,
618 CallbackEvent_CGPathApplierFunction
621 typedef void (*CFRunLoopPerformCallBack)(void*);
623 static 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();
634 static size_t
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();
647 static void
648 CGPathApplierFunctionWrapper(void* aInfo, CGPathElement* aElement)
650 RecordReplayCallback(CGPathApplierFunction, &aInfo);
652 CGPathElement replayElement;
653 if (IsReplaying()) {
654 aElement = &replayElement;
657 aElement->type = (CGPathElementType) RecordReplayValue(aElement->type);
659 size_t npoints = CGPathElementPointCount(aElement);
660 if (IsReplaying()) {
661 aElement->points = new CGPoint[npoints];
663 RecordReplayBytes(aElement->points, npoints * sizeof(CGPoint));
665 rrc.mFunction(aInfo, aElement);
667 if (IsReplaying()) {
668 delete[] aElement->points;
672 void
673 ReplayInvokeCallback(size_t aCallbackId)
675 MOZ_RELEASE_ASSERT(IsReplaying());
676 switch (aCallbackId) {
677 case CallbackEvent_CFRunLoopPerformCallBack:
678 CFRunLoopPerformCallBackWrapper(nullptr);
679 break;
680 case CallbackEvent_CGPathApplierFunction:
681 CGPathApplierFunctionWrapper(nullptr, nullptr);
682 break;
683 default:
684 MOZ_CRASH();
688 ///////////////////////////////////////////////////////////////////////////////
689 // Middleman Call Helpers
690 ///////////////////////////////////////////////////////////////////////////////
692 static bool
693 TestObjCObjectClass(id aObj, const char* aName)
695 Class cls = object_getClass(aObj);
696 while (cls) {
697 const char* className = class_getName(cls);
698 if (!strcmp(className, aName)) {
699 return true;
701 cls = class_getSuperclass(cls);
703 return false;
706 // Inputs that originate from static data in the replaying process itself
707 // rather than from previous middleman calls.
708 enum class ObjCInputKind {
709 StaticClass,
710 ConstantString,
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
715 // process.
716 static void
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.
723 return;
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[] = {
733 "NSAutoreleasePool",
734 "NSColor",
735 "NSDictionary",
736 "NSFont",
737 "NSFontManager",
738 "NSNumber",
739 "NSString",
740 "NSWindow",
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);
751 return;
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));
771 return;
774 aCx.MarkAsFailed();
775 return;
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());
784 break;
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);
791 break;
793 default:
794 MOZ_CRASH();
798 template <size_t Argument>
799 static void
800 Middleman_CFTypeArg(MiddlemanCallContext& aCx)
802 if (aCx.AccessPreface()) {
803 auto& object = aCx.mArguments->Arg<Argument, id>();
804 Middleman_ObjCInput(aCx, &object);
808 static void
809 Middleman_CFTypeOutput(MiddlemanCallContext& aCx, CFTypeRef* aOutput, bool aOwnsReference)
811 Middleman_SystemOutput(aCx, (const void**) aOutput);
813 if (*aOutput) {
814 switch (aCx.mPhase) {
815 case MiddlemanCallPhase::MiddlemanOutput:
816 if (!aOwnsReference) {
817 CFRetain(*aOutput);
819 break;
820 case MiddlemanCallPhase::MiddlemanRelease:
821 CFRelease(*aOutput);
822 break;
823 default:
824 break;
829 // For APIs using the 'Get' rule: no reference is held on the returned value.
830 static void
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.
839 static void
840 Middleman_CreateCFTypeRval(MiddlemanCallContext& aCx)
842 auto& rval = aCx.mArguments->Rval<CFTypeRef>();
843 Middleman_CFTypeOutput(aCx, &rval, /* aOwnsReference = */ true);
846 template <size_t Argument>
847 static void
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.
857 static void
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>
868 static void
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;
881 errno = EAGAIN;
882 return PreambleResult::Veto;
885 ///////////////////////////////////////////////////////////////////////////////
886 // system call redirections
887 ///////////////////////////////////////////////////////////////////////////////
889 static void
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);
908 nbytes -= 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);
951 memory = address;
952 } else {
953 memory = AllocateMemoryTryAddress(address, RoundupSizeToPageBoundary(size),
954 MemoryKind::Tracked);
956 } else {
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;
993 static void
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>();
1032 switch (cmd) {
1033 case F_GETFL:
1034 case F_SETFL:
1035 case F_GETFD:
1036 case F_SETFD:
1037 case F_NOCACHE:
1038 case F_SETLK:
1039 case F_SETLKW:
1040 break;
1041 default:
1042 MOZ_CRASH();
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;
1065 static void
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));
1072 if (oldlenp) {
1073 aEvents.RecordOrReplayValue(oldlenp);
1075 if (old) {
1076 aEvents.RecordOrReplayBytes(old, *oldlenp);
1080 static PreambleResult
1081 Preamble___workq_kernreturn(CallArguments* aArguments)
1083 // Busy-wait until initialization is complete.
1084 while (!gInitialized) {
1085 ThreadYield();
1088 // Make sure we know this thread exists.
1089 Thread::Current();
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 ///////////////////////////////////////////////////////////////////////////////
1114 static void
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);
1122 static void
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.
1132 static ssize_t
1133 WaitForCvar(pthread_mutex_t* aMutex, bool aRecordReturnValue,
1134 const std::function<ssize_t()>& aCallback)
1136 Lock* lock = Lock::Find(aMutex);
1137 if (!lock) {
1138 AutoEnsurePassThroughThreadEvents pt;
1139 return aCallback();
1141 ssize_t rv = 0;
1142 if (IsRecording()) {
1143 AutoPassThroughThreadEvents pt;
1144 rv = aCallback();
1145 } else {
1146 DirectUnlockMutex(aMutex);
1148 lock->Exit();
1149 lock->Enter();
1150 if (IsReplaying()) {
1151 DirectLockMutex(aMutex);
1153 if (aRecordReturnValue) {
1154 return RecordReplayValue(rv);
1156 MOZ_RELEASE_ASSERT(rv == 0);
1157 return 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*>();
1209 int detachState;
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);
1230 thread->Join();
1232 *ptr = nullptr;
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*>();
1243 Lock::New(mutex);
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);
1264 if (!lock) {
1265 AutoEnsurePassThroughThreadEventsUseStackPointer pt;
1266 aArguments->Rval<ssize_t>() = OriginalCall(pthread_mutex_lock, ssize_t, mutex);
1267 return PreambleResult::Veto;
1269 ssize_t rv = 0;
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);
1276 if (rv == 0) {
1277 lock->Enter();
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);
1292 if (!lock) {
1293 AutoEnsurePassThroughThreadEvents pt;
1294 aArguments->Rval<ssize_t>() = OriginalCall(pthread_mutex_trylock, ssize_t, mutex);
1295 return PreambleResult::Veto;
1297 ssize_t rv = 0;
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);
1304 if (rv == 0) {
1305 lock->Enter();
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);
1320 if (!lock) {
1321 AutoEnsurePassThroughThreadEventsUseStackPointer pt;
1322 aArguments->Rval<ssize_t>() = OriginalCall(pthread_mutex_unlock, ssize_t, mutex);
1323 return PreambleResult::Veto;
1325 lock->Exit();
1326 DirectUnlockMutex(mutex);
1327 aArguments->Rval<ssize_t>() = 0;
1328 return PreambleResult::Veto;
1331 ///////////////////////////////////////////////////////////////////////////////
1332 // stdlib redirections
1333 ///////////////////////////////////////////////////////////////////////////////
1335 static void
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
1470 // included here :(
1471 struct NSFastEnumerationState
1473 unsigned long state;
1474 id* itemsPtr;
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;
1504 static void
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:")) {
1528 size_t len = 0;
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;
1570 static void
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:")) {
1581 aCx.MarkAsFailed();
1582 return;
1586 Middleman_AutoreleaseCFTypeRval(aCx);
1589 static void
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);
1609 static void
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()) {
1621 size_t len =
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> },
1643 // NSArray
1644 { "count" },
1645 { "objectAtIndex:", Middleman_AutoreleaseCFTypeRval },
1647 // NSColor
1648 { "currentControlTint" },
1650 // NSDictionary
1651 { "dictionaryWithObjects:forKeys:count:", Middleman_DictionaryWithObjects },
1653 // NSFont
1654 { "boldSystemFontOfSize:", Middleman_AutoreleaseCFTypeRval },
1655 { "controlContentFontOfSize:", Middleman_AutoreleaseCFTypeRval },
1656 { "familyName", Middleman_AutoreleaseCFTypeRval },
1657 { "fontDescriptor", Middleman_AutoreleaseCFTypeRval },
1658 { "menuBarFontOfSize:", Middleman_AutoreleaseCFTypeRval },
1659 { "pointSize" },
1660 { "smallSystemFontSize" },
1661 { "systemFontOfSize:", Middleman_AutoreleaseCFTypeRval },
1662 { "toolTipsFontOfSize:", Middleman_AutoreleaseCFTypeRval },
1663 { "userFontOfSize:", Middleman_AutoreleaseCFTypeRval },
1665 // NSFontManager
1666 { "availableMembersOfFontFamily:", Middleman_Compose<Middleman_CFTypeArg<2>, Middleman_AutoreleaseCFTypeRval> },
1667 { "sharedFontManager", Middleman_AutoreleaseCFTypeRval },
1669 // NSNumber
1670 { "numberWithBool:", Middleman_AutoreleaseCFTypeRval },
1671 { "unsignedIntValue" },
1673 // NSString
1674 { "getCharacters:", Middleman_NSStringGetCharacters },
1675 { "hasSuffix:", Middleman_CFTypeArg<2> },
1676 { "isEqualToString:", Middleman_CFTypeArg<2> },
1677 { "length" },
1678 { "rangeOfString:options:", Middleman_CFTypeArg<2> },
1679 { "stringWithCharacters:length:",
1680 Middleman_Compose<Middleman_Buffer<2, 3, UniChar>, Middleman_AutoreleaseCFTypeRval> },
1682 // NSWindow
1683 { "coreUIRenderer", Middleman_AutoreleaseCFTypeRval },
1685 // UIFontDescriptor
1686 { "symbolicTraits" },
1689 static void
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);
1703 return;
1707 if (aCx.mPhase == MiddlemanCallPhase::ReplayPreface) {
1708 aCx.MarkAsFailed();
1712 ///////////////////////////////////////////////////////////////////////////////
1713 // Cocoa redirections
1714 ///////////////////////////////////////////////////////////////////////////////
1716 static void
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;
1729 } else {
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);
1741 static void
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;
1752 if (call) {
1753 switch (call->mCallId) {
1754 case CallEvent_CTLineGetGlyphRuns:
1755 case CallEvent_CTFontDescriptorCreateMatchingFontDescriptors:
1756 isCFTypeRval = true;
1757 break;
1758 default:
1759 break;
1763 if (isCFTypeRval) {
1764 Middleman_CFTypeRval(aCx);
1768 static void
1769 RR_CFDataGetBytePtr(Stream& aEvents, CallArguments* aArguments, ErrorType* aError)
1771 auto& rval = aArguments->Rval<UInt8*>();
1773 size_t len = 0;
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);
1784 static void
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);
1802 static void
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;
1819 } else {
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)
1837 // FIXME
1838 //MOZ_CRASH();
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;
1851 static size_t
1852 CFNumberTypeBytes(CFNumberType aType)
1854 switch (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();
1875 static void
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);
1887 static void
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));
1897 static void
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;
1935 void* mData;
1936 size_t mDataSize;
1938 ContextDataInfo(CGContextRef aContext, void* aData, size_t aDataSize)
1939 : mContext(aContext), mData(aData), mDataSize(aDataSize)
1943 static StaticInfallibleVector<ContextDataInfo> gContextData;
1945 static void
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);
1963 static void
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>
1986 static void
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);
1994 return;
1997 MOZ_CRASH("RR_FlushCGContext");
2000 template <size_t ContextArgument>
2001 static void
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);
2012 return;
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);
2024 return;
2027 MOZ_CRASH("Middleman_FlushCGContext");
2031 static PreambleResult
2032 Preamble_CGContextRestoreGState(CallArguments* aArguments)
2034 return IsRecording() ? PreambleResult::PassThrough : PreambleResult::Veto;
2037 static void
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*)>
2081 static void
2082 RR_CTRunGetElements(Stream& aEvents, CallArguments* aArguments, ErrorType* aError)
2084 auto& run = aArguments->Arg<0, CTRunRef>();
2085 auto& rval = aArguments->Rval<ElemType*>();
2087 size_t count;
2088 if (IsRecording()) {
2089 AutoPassThroughThreadEvents pt;
2090 count = CTRunGetGlyphCount(run);
2091 if (!rval) {
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*)>
2104 static void
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*>();
2113 size_t count = 0;
2114 if (IsMiddleman()) {
2115 count = CTRunGetGlyphCount(run);
2116 if (!rval) {
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 ///////////////////////////////////////////////////////////////////////////////
2162 const char*
2163 SymbolNameRaw(void* aPtr)
2165 Dl_info info;
2166 return (dladdr(aPtr, &info) && info.dli_sname) ? info.dli_sname : "???";
2169 void*
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);
2176 return res;
2179 void
2180 DirectDeallocateMemory(void* aAddress, size_t aSize)
2182 ssize_t rv = OriginalCall(munmap, int, aAddress, aSize);
2183 MOZ_RELEASE_ASSERT(rv >= 0);
2186 void
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);
2195 void
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);
2204 void
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);
2212 FileHandle
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);
2219 return fd;
2222 void
2223 DirectCloseFile(FileHandle aFd)
2225 ssize_t rv = HANDLE_EINTR(OriginalCall(close, int, aFd));
2226 MOZ_RELEASE_ASSERT(rv >= 0);
2229 void
2230 DirectDeleteFile(const char* aFilename)
2232 ssize_t rv = unlink(aFilename);
2233 MOZ_RELEASE_ASSERT(rv >= 0 || errno == ENOENT);
2236 void
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);
2243 void
2244 DirectPrint(const char* aString)
2246 DirectWrite(STDERR_FILENO, aString, strlen(aString));
2249 size_t
2250 DirectRead(FileHandle aFd, void* aData, size_t aSize)
2252 // Clear the memory in case it is write protected by the memory snapshot
2253 // mechanism.
2254 memset(aData, 0, aSize);
2255 ssize_t rv = HANDLE_EINTR(OriginalCall(read, int, aFd, aData, aSize));
2256 MOZ_RELEASE_ASSERT(rv >= 0);
2257 return (size_t) rv;
2260 void
2261 DirectCreatePipe(FileHandle* aWriteFd, FileHandle* aReadFd)
2263 int fds[2];
2264 ssize_t rv = OriginalCall(pipe, int, fds);
2265 MOZ_RELEASE_ASSERT(rv >= 0);
2266 *aWriteFd = fds[1];
2267 *aReadFd = fds[0];
2270 static double gAbsoluteToNanosecondsRate;
2272 void
2273 InitializeCurrentTime()
2275 AbsoluteTime time = { 1000000, 0 };
2276 Nanoseconds rate = AbsoluteToNanoseconds(time);
2277 MOZ_RELEASE_ASSERT(!rate.hi);
2278 gAbsoluteToNanosecondsRate = rate.lo / 1000000.0;
2281 double
2282 CurrentTime()
2284 return OriginalCall(mach_absolute_time, int64_t) * gAbsoluteToNanosecondsRate / 1000.0;
2287 void
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);
2302 pthread_t pthread;
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);
2310 } // recordreplay
2311 } // mozilla