1 | /* |
2 | * Block_private.h |
3 | * |
4 | * SPI for Blocks |
5 | * |
6 | * Copyright (c) 2008-2010 Apple Inc. All rights reserved. |
7 | * |
8 | * @APPLE_LLVM_LICENSE_HEADER@ |
9 | * |
10 | */ |
11 | |
12 | #ifndef _BLOCK_PRIVATE_H_ |
13 | #define _BLOCK_PRIVATE_H_ |
14 | |
15 | #include <Availability.h> |
16 | #include <AvailabilityMacros.h> |
17 | #ifndef KERNEL |
18 | #include <TargetConditionals.h> |
19 | #endif |
20 | |
21 | #include <stdbool.h> |
22 | #include <stdint.h> |
23 | #ifdef KERNEL |
24 | #include <sys/systm.h> |
25 | #else |
26 | #include <stdio.h> |
27 | #endif |
28 | |
29 | |
30 | #ifdef KERNEL |
31 | #include <libkern/Block.h> |
32 | struct Block_byref; |
33 | #else |
34 | #include <Block.h> |
35 | #endif |
36 | |
37 | #if __has_include(<ptrauth.h>) |
38 | #include <ptrauth.h> |
39 | #endif |
40 | |
41 | #if __has_feature(ptrauth_calls) && __cplusplus < 201103L |
42 | |
43 | // C ptrauth or old C++ ptrauth |
44 | |
45 | #define _Block_set_function_pointer(field, value) \ |
46 | ((value) \ |
47 | ? ((field) = \ |
48 | (__typeof__(field)) \ |
49 | ptrauth_auth_and_resign((void*)(value), \ |
50 | ptrauth_key_function_pointer, 0, \ |
51 | ptrauth_key_block_function, &(field))) \ |
52 | : ((field) = 0)) |
53 | |
54 | #define _Block_get_function_pointer(field) \ |
55 | ((field) \ |
56 | ? (__typeof__(field)) \ |
57 | ptrauth_auth_function((void*)(field), \ |
58 | ptrauth_key_block_function, &(field)) \ |
59 | : (__typeof__(field))0) |
60 | |
61 | #else |
62 | |
63 | // C++11 ptrauth or no ptrauth |
64 | |
65 | #define _Block_set_function_pointer(field, value) \ |
66 | (field) = (value) |
67 | |
68 | #define _Block_get_function_pointer(field) \ |
69 | (field) |
70 | |
71 | #endif |
72 | |
73 | |
74 | #if __has_feature(ptrauth_calls) && __cplusplus >= 201103L |
75 | |
76 | // StorageSignedFunctionPointer<Key, Fn> stores a function pointer of type |
77 | // Fn but signed with the given ptrauth key and with the address of its |
78 | // storage as extra data. |
79 | // Function pointers inside block objects are signed this way. |
80 | template <typename Fn, ptrauth_key Key> |
81 | class StorageSignedFunctionPointer { |
82 | uintptr_t bits; |
83 | |
84 | public: |
85 | |
86 | // Authenticate function pointer fn as a C function pointer. |
87 | // Re-sign it with our key and the storage address as extra data. |
88 | // DOES NOT actually write to our storage. |
89 | uintptr_t prepareWrite(Fn fn) const |
90 | { |
91 | if (fn == nullptr) { |
92 | return 0; |
93 | } else { |
94 | return (uintptr_t) |
95 | ptrauth_auth_and_resign(fn, ptrauth_key_function_pointer, 0, |
96 | Key, &bits); |
97 | } |
98 | } |
99 | |
100 | // Authenticate otherBits at otherStorage. |
101 | // Re-sign it with our storage address. |
102 | // DOES NOT actually write to our storage. |
103 | uintptr_t prepareWrite(const StorageSignedFunctionPointer& other) const |
104 | { |
105 | if (other.bits == 0) { |
106 | return 0; |
107 | } else { |
108 | return (uintptr_t) |
109 | ptrauth_auth_and_resign((void*)other.bits, Key, &other.bits, |
110 | Key, &bits); |
111 | } |
112 | } |
113 | |
114 | // Authenticate ptr as if it were stored at our storage address. |
115 | // Re-sign it as a C function pointer. |
116 | // DOES NOT actually read from our storage. |
117 | Fn completeReadFn(uintptr_t ptr) const |
118 | { |
119 | if (ptr == 0) { |
120 | return nullptr; |
121 | } else { |
122 | return ptrauth_auth_function((Fn)ptr, Key, &bits); |
123 | } |
124 | } |
125 | |
126 | // Authenticate ptr as if it were at our storage address. |
127 | // Return it as a dereferenceable pointer. |
128 | // DOES NOT actually read from our storage. |
129 | void* completeReadRaw(uintptr_t ptr) const |
130 | { |
131 | if (ptr == 0) { |
132 | return nullptr; |
133 | } else { |
134 | return ptrauth_auth_data((void*)ptr, Key, &bits); |
135 | } |
136 | } |
137 | |
138 | StorageSignedFunctionPointer() { } |
139 | |
140 | StorageSignedFunctionPointer(Fn value) |
141 | : bits(prepareWrite(value)) { } |
142 | |
143 | StorageSignedFunctionPointer(const StorageSignedFunctionPointer& value) |
144 | : bits(prepareWrite(value)) { } |
145 | |
146 | StorageSignedFunctionPointer& |
147 | operator = (Fn rhs) { |
148 | bits = prepareWrite(rhs); |
149 | return *this; |
150 | } |
151 | |
152 | StorageSignedFunctionPointer& |
153 | operator = (const StorageSignedFunctionPointer& rhs) { |
154 | bits = prepareWrite(rhs); |
155 | return *this; |
156 | } |
157 | |
158 | operator Fn () const { |
159 | return completeReadFn(bits); |
160 | } |
161 | |
162 | explicit operator void* () const { |
163 | return completeReadRaw(bits); |
164 | } |
165 | |
166 | explicit operator bool () const { |
167 | return completeReadRaw(bits) != nullptr; |
168 | } |
169 | }; |
170 | |
171 | using BlockCopyFunction = StorageSignedFunctionPointer |
172 | <void(*)(void *, const void *), |
173 | ptrauth_key_block_function>; |
174 | |
175 | using BlockDisposeFunction = StorageSignedFunctionPointer |
176 | <void(*)(const void *), |
177 | ptrauth_key_block_function>; |
178 | |
179 | using BlockInvokeFunction = StorageSignedFunctionPointer |
180 | <void(*)(void *, ...), |
181 | ptrauth_key_block_function>; |
182 | |
183 | using BlockByrefKeepFunction = StorageSignedFunctionPointer |
184 | <void(*)(struct Block_byref *, struct Block_byref *), |
185 | ptrauth_key_block_function>; |
186 | |
187 | using BlockByrefDestroyFunction = StorageSignedFunctionPointer |
188 | <void(*)(struct Block_byref *), |
189 | ptrauth_key_block_function>; |
190 | |
191 | // c++11 and ptrauth_calls |
192 | #elif !__has_feature(ptrauth_calls) |
193 | // not ptrauth_calls |
194 | |
195 | typedef void(*BlockCopyFunction)(void *, const void *); |
196 | typedef void(*BlockDisposeFunction)(const void *); |
197 | typedef void(*BlockInvokeFunction)(void *, ...); |
198 | typedef void(*BlockByrefKeepFunction)(struct Block_byref*, struct Block_byref*); |
199 | typedef void(*BlockByrefDestroyFunction)(struct Block_byref *); |
200 | |
201 | #else |
202 | // ptrauth_calls but not c++11 |
203 | |
204 | typedef uintptr_t BlockCopyFunction; |
205 | typedef uintptr_t BlockDisposeFunction; |
206 | typedef uintptr_t BlockInvokeFunction; |
207 | typedef uintptr_t BlockByrefKeepFunction; |
208 | typedef uintptr_t BlockByrefDestroyFunction; |
209 | |
210 | #endif |
211 | |
212 | |
213 | // Values for Block_layout->flags to describe block objects |
214 | enum { |
215 | BLOCK_DEALLOCATING = (0x0001), // runtime |
216 | BLOCK_REFCOUNT_MASK = (0xfffe), // runtime |
217 | BLOCK_NEEDS_FREE = (1 << 24), // runtime |
218 | BLOCK_HAS_COPY_DISPOSE = (1 << 25), // compiler |
219 | BLOCK_HAS_CTOR = (1 << 26), // compiler: helpers have C++ code |
220 | BLOCK_IS_GC = (1 << 27), // runtime |
221 | BLOCK_IS_GLOBAL = (1 << 28), // compiler |
222 | BLOCK_USE_STRET = (1 << 29), // compiler: undefined if !BLOCK_HAS_SIGNATURE |
223 | BLOCK_HAS_SIGNATURE = (1 << 30), // compiler |
224 | BLOCK_HAS_EXTENDED_LAYOUT=(1 << 31) // compiler |
225 | }; |
226 | |
227 | #define BLOCK_DESCRIPTOR_1 1 |
228 | struct Block_descriptor_1 { |
229 | uintptr_t reserved; |
230 | uintptr_t size; |
231 | }; |
232 | |
233 | #define BLOCK_DESCRIPTOR_2 1 |
234 | struct Block_descriptor_2 { |
235 | // requires BLOCK_HAS_COPY_DISPOSE |
236 | BlockCopyFunction copy; |
237 | BlockDisposeFunction dispose; |
238 | }; |
239 | |
240 | #define BLOCK_DESCRIPTOR_3 1 |
241 | struct Block_descriptor_3 { |
242 | // requires BLOCK_HAS_SIGNATURE |
243 | const char *signature; |
244 | const char *layout; // contents depend on BLOCK_HAS_EXTENDED_LAYOUT |
245 | }; |
246 | |
247 | struct Block_layout { |
248 | void *isa; |
249 | volatile int32_t flags; // contains ref count |
250 | int32_t reserved; |
251 | BlockInvokeFunction invoke; |
252 | struct Block_descriptor_1 *descriptor; |
253 | // imported variables |
254 | }; |
255 | |
256 | |
257 | // Values for Block_byref->flags to describe __block variables |
258 | enum { |
259 | // Byref refcount must use the same bits as Block_layout's refcount. |
260 | // BLOCK_DEALLOCATING = (0x0001), // runtime |
261 | // BLOCK_REFCOUNT_MASK = (0xfffe), // runtime |
262 | |
263 | BLOCK_BYREF_LAYOUT_MASK = (0xf << 28), // compiler |
264 | BLOCK_BYREF_LAYOUT_EXTENDED = ( 1 << 28), // compiler |
265 | BLOCK_BYREF_LAYOUT_NON_OBJECT = ( 2 << 28), // compiler |
266 | BLOCK_BYREF_LAYOUT_STRONG = ( 3 << 28), // compiler |
267 | BLOCK_BYREF_LAYOUT_WEAK = ( 4 << 28), // compiler |
268 | BLOCK_BYREF_LAYOUT_UNRETAINED = ( 5 << 28), // compiler |
269 | |
270 | BLOCK_BYREF_IS_GC = ( 1 << 27), // runtime |
271 | |
272 | BLOCK_BYREF_HAS_COPY_DISPOSE = ( 1 << 25), // compiler |
273 | BLOCK_BYREF_NEEDS_FREE = ( 1 << 24), // runtime |
274 | }; |
275 | |
276 | struct Block_byref { |
277 | void *isa; |
278 | struct Block_byref *forwarding; |
279 | volatile int32_t flags; // contains ref count |
280 | uint32_t size; |
281 | }; |
282 | |
283 | struct Block_byref_2 { |
284 | // requires BLOCK_BYREF_HAS_COPY_DISPOSE |
285 | BlockByrefKeepFunction byref_keep; |
286 | BlockByrefDestroyFunction byref_destroy; |
287 | }; |
288 | |
289 | struct Block_byref_3 { |
290 | // requires BLOCK_BYREF_LAYOUT_EXTENDED |
291 | const char *layout; |
292 | }; |
293 | |
294 | |
295 | // Extended layout encoding. |
296 | |
297 | // Values for Block_descriptor_3->layout with BLOCK_HAS_EXTENDED_LAYOUT |
298 | // and for Block_byref_3->layout with BLOCK_BYREF_LAYOUT_EXTENDED |
299 | |
300 | // If the layout field is less than 0x1000, then it is a compact encoding |
301 | // of the form 0xXYZ: X strong pointers, then Y byref pointers, |
302 | // then Z weak pointers. |
303 | |
304 | // If the layout field is 0x1000 or greater, it points to a |
305 | // string of layout bytes. Each byte is of the form 0xPN. |
306 | // Operator P is from the list below. Value N is a parameter for the operator. |
307 | // Byte 0x00 terminates the layout; remaining block data is non-pointer bytes. |
308 | |
309 | enum { |
310 | BLOCK_LAYOUT_ESCAPE = 0, // N=0 halt, rest is non-pointer. N!=0 reserved. |
311 | BLOCK_LAYOUT_NON_OBJECT_BYTES = 1, // N bytes non-objects |
312 | BLOCK_LAYOUT_NON_OBJECT_WORDS = 2, // N words non-objects |
313 | BLOCK_LAYOUT_STRONG = 3, // N words strong pointers |
314 | BLOCK_LAYOUT_BYREF = 4, // N words byref pointers |
315 | BLOCK_LAYOUT_WEAK = 5, // N words weak pointers |
316 | BLOCK_LAYOUT_UNRETAINED = 6, // N words unretained pointers |
317 | BLOCK_LAYOUT_UNKNOWN_WORDS_7 = 7, // N words, reserved |
318 | BLOCK_LAYOUT_UNKNOWN_WORDS_8 = 8, // N words, reserved |
319 | BLOCK_LAYOUT_UNKNOWN_WORDS_9 = 9, // N words, reserved |
320 | BLOCK_LAYOUT_UNKNOWN_WORDS_A = 0xA, // N words, reserved |
321 | BLOCK_LAYOUT_UNUSED_B = 0xB, // unspecified, reserved |
322 | BLOCK_LAYOUT_UNUSED_C = 0xC, // unspecified, reserved |
323 | BLOCK_LAYOUT_UNUSED_D = 0xD, // unspecified, reserved |
324 | BLOCK_LAYOUT_UNUSED_E = 0xE, // unspecified, reserved |
325 | BLOCK_LAYOUT_UNUSED_F = 0xF, // unspecified, reserved |
326 | }; |
327 | |
328 | |
329 | // Runtime support functions used by compiler when generating copy/dispose helpers |
330 | |
331 | // Values for _Block_object_assign() and _Block_object_dispose() parameters |
332 | enum { |
333 | // see function implementation for a more complete description of these fields and combinations |
334 | BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ... |
335 | BLOCK_FIELD_IS_BLOCK = 7, // a block variable |
336 | BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable |
337 | BLOCK_FIELD_IS_WEAK = 16, // declared __weak, only used in byref copy helpers |
338 | BLOCK_BYREF_CALLER = 128, // called from __block (byref) copy/dispose support routines. |
339 | }; |
340 | |
341 | enum { |
342 | BLOCK_ALL_COPY_DISPOSE_FLAGS = |
343 | BLOCK_FIELD_IS_OBJECT | BLOCK_FIELD_IS_BLOCK | BLOCK_FIELD_IS_BYREF | |
344 | BLOCK_FIELD_IS_WEAK | BLOCK_BYREF_CALLER |
345 | }; |
346 | |
347 | |
348 | // Function pointer accessors |
349 | |
350 | static inline __typeof__(void (*)(void *, ...)) |
351 | _Block_get_invoke_fn(struct Block_layout *block) |
352 | { |
353 | return (void (*)(void *, ...))_Block_get_function_pointer(block->invoke); |
354 | } |
355 | |
356 | static inline void |
357 | _Block_set_invoke_fn(struct Block_layout *block, void (*fn)(void *, ...)) |
358 | { |
359 | _Block_set_function_pointer(block->invoke, fn); |
360 | } |
361 | |
362 | |
363 | static inline __typeof__(void (*)(void *, const void *)) |
364 | _Block_get_copy_fn(struct Block_descriptor_2 *desc) |
365 | { |
366 | return (void (*)(void *, const void *))_Block_get_function_pointer(desc->copy); |
367 | } |
368 | |
369 | static inline void |
370 | _Block_set_copy_fn(struct Block_descriptor_2 *desc, |
371 | void (*fn)(void *, const void *)) |
372 | { |
373 | _Block_set_function_pointer(desc->copy, fn); |
374 | } |
375 | |
376 | |
377 | static inline __typeof__(void (*)(const void *)) |
378 | _Block_get_dispose_fn(struct Block_descriptor_2 *desc) |
379 | { |
380 | return (void (*)(const void *))_Block_get_function_pointer(desc->dispose); |
381 | } |
382 | |
383 | static inline void |
384 | _Block_set_dispose_fn(struct Block_descriptor_2 *desc, |
385 | void (*fn)(const void *)) |
386 | { |
387 | _Block_set_function_pointer(desc->dispose, fn); |
388 | } |
389 | |
390 | |
391 | // Other support functions |
392 | |
393 | |
394 | // runtime entry to get total size of a closure |
395 | BLOCK_EXPORT size_t Block_size(void *aBlock); |
396 | |
397 | // indicates whether block was compiled with compiler that sets the ABI related metadata bits |
398 | BLOCK_EXPORT bool _Block_has_signature(void *aBlock) |
399 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); |
400 | |
401 | // returns TRUE if return value of block is on the stack, FALSE otherwise |
402 | BLOCK_EXPORT bool _Block_use_stret(void *aBlock) |
403 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); |
404 | |
405 | // Returns a string describing the block's parameter and return types. |
406 | // The encoding scheme is the same as Objective-C @encode. |
407 | // Returns NULL for blocks compiled with some compilers. |
408 | BLOCK_EXPORT const char * _Block_signature(void *aBlock) |
409 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); |
410 | |
411 | // Returns a string describing the block's GC layout. |
412 | // This uses the GC skip/scan encoding. |
413 | // May return NULL. |
414 | BLOCK_EXPORT const char * _Block_layout(void *aBlock) |
415 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); |
416 | |
417 | // Returns a string describing the block's layout. |
418 | // This uses the "extended layout" form described above. |
419 | // May return NULL. |
420 | BLOCK_EXPORT const char * _Block_extended_layout(void *aBlock) |
421 | __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_7_0); |
422 | |
423 | // Callable only from the ARR weak subsystem while in exclusion zone |
424 | BLOCK_EXPORT bool _Block_tryRetain(const void *aBlock) |
425 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); |
426 | |
427 | // Callable only from the ARR weak subsystem while in exclusion zone |
428 | BLOCK_EXPORT bool _Block_isDeallocating(const void *aBlock) |
429 | __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3); |
430 | |
431 | |
432 | // the raw data space for runtime classes for blocks |
433 | // class+meta used for stack, malloc, and collectable based blocks |
434 | BLOCK_EXPORT void * _NSConcreteMallocBlock[32] |
435 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2); |
436 | BLOCK_EXPORT void * _NSConcreteAutoBlock[32] |
437 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2); |
438 | BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32] |
439 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2); |
440 | BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32] |
441 | __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2); |
442 | // declared in Block.h |
443 | // BLOCK_EXPORT void * _NSConcreteGlobalBlock[32]; |
444 | // BLOCK_EXPORT void * _NSConcreteStackBlock[32]; |
445 | |
446 | |
447 | struct Block_callbacks_RR { |
448 | size_t size; // size == sizeof(struct Block_callbacks_RR) |
449 | void (*retain)(const void *); |
450 | void (*release)(const void *); |
451 | void (*destructInstance)(const void *); |
452 | }; |
453 | typedef struct Block_callbacks_RR Block_callbacks_RR; |
454 | |
455 | BLOCK_EXPORT void _Block_use_RR2(const Block_callbacks_RR *callbacks); |
456 | |
457 | |
458 | #endif |
459 | |