]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-runtime.m
objc4-267.tar.gz
[apple/objc4.git] / runtime / objc-runtime.m
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /***********************************************************************
26 * objc-runtime.m
27 * Copyright 1988-1996, NeXT Software, Inc.
28 * Author: s. naroff
29 *
30 **********************************************************************/
31
32 /***********************************************************************
33 * Class loading and connecting (GrP 2004-2-11)
34 *
35 * When images are loaded (during program startup or otherwise), the
36 * runtime needs to load classes and categories from the images, connect
37 * classes to superclasses and categories to parent classes, and call
38 * +load methods.
39 *
40 * The Objective-C runtime can cope with classes arriving in any order.
41 * That is, a class may be discovered by the runtime before some
42 * superclass is known. To handle out-of-order class loads, the
43 * runtime uses a "pending class" system.
44 *
45 * (Historical note)
46 * Panther and earlier: many classes arrived out-of-order because of
47 * the poorly-ordered callback from dyld. However, the runtime's
48 * pending mechanism only handled "missing superclass" and not
49 * "present superclass but missing higher class". See Radar #3225652.
50 * Tiger: The runtime's pending mechanism was augmented to handle
51 * arbitrary missing classes. In addition, dyld was rewritten and
52 * now sends the callbacks in strictly bottom-up link order.
53 * The pending mechanism may now be needed only for rare and
54 * hard to construct programs.
55 * (End historical note)
56 *
57 * A class when first seen in an image is considered "unconnected".
58 * It is stored in `unconnected_class_hash`. If all of the class's
59 * superclasses exist and are already "connected", then the new class
60 * can be connected to its superclasses and moved to `class_hash` for
61 * normal use. Otherwise, the class waits in `unconnected_class_hash`
62 * until the superclasses finish connecting.
63 *
64 * A "connected" class is
65 * (1) in `class_hash`,
66 * (2) connected to its superclasses,
67 * (3) has no unconnected superclasses,
68 * (4) is otherwise initialized and ready for use, and
69 * (5) is eligible for +load if +load has not already been called.
70 *
71 * An "unconnected" class is
72 * (1) in `unconnected_class_hash`,
73 * (2) not connected to its superclasses,
74 * (3) has an immediate superclass which is either missing or unconnected,
75 * (4) is not ready for use, and
76 * (5) is not yet eligible for +load.
77 *
78 * Image mapping is NOT CURRENTLY THREAD-SAFE with respect to just about
79 * * * anything. Image mapping IS RE-ENTRANT in several places: superclass
80 * lookup may cause ZeroLink to load another image, and +load calls may
81 * cause dyld to load another image.
82 *
83 * Image mapping sequence:
84 *
85 * Read all classes in all new images.
86 * Add them all to unconnected_class_hash.
87 * Note any +load implementations before categories are attached.
88 * Fix up any pended classrefs referring to them.
89 * Attach any pending categories.
90 * Read all categories in all new images.
91 * Attach categories whose parent class exists (connected or not),
92 * and pend the rest.
93 * Mark them all eligible for +load (if implemented), even if the
94 * parent class is missing.
95 * Try to connect all classes in all new images.
96 * If the superclass is missing, pend the class
97 * If the superclass is unconnected, try to recursively connect it
98 * If the superclass is connected:
99 * connect the class
100 * mark the class eligible for +load, if implemented
101 * connect any pended subclasses of the class
102 * Resolve selector refs and class refs in all new images.
103 * Class refs whose classes still do not exist are pended.
104 * Fix up protocol objects in all new images.
105 * Call +load for classes and categories.
106 * May include classes or categories that are not in these images,
107 * but are newly eligible because of these image.
108 * Class +loads will be called superclass-first because of the
109 * superclass-first nature of the connecting process.
110 * Category +load needs to be deferred until the parent class is
111 * connected and has had its +load called.
112 *
113 * Performance: all classes are read before any categories are read.
114 * Fewer categories need be pended for lack of a parent class.
115 *
116 * Performance: all categories are attempted to be attached before
117 * any classes are connected. Fewer class caches need be flushed.
118 * (Unconnected classes and their respective subclasses are guaranteed
119 * to be un-messageable, so their caches will be empty.)
120 *
121 * Performance: all classes are read before any classes are connected.
122 * Fewer classes need be pended for lack of a superclass.
123 *
124 * Correctness: all selector and class refs are fixed before any
125 * protocol fixups or +load methods. libobjc itself contains selector
126 * and class refs which are used in protocol fixup and +load.
127 *
128 * Correctness: +load methods are scheduled in bottom-up link order.
129 * This constraint is in addition to superclass order. Some +load
130 * implementations expect to use another class in a linked-to library,
131 * even if the two classes don't share a direct superclass relationship.
132 *
133 * Correctness: all classes are scanned for +load before any categories
134 * are attached. Otherwise, if a category implements +load and its class
135 * has no class methods, the class's +load scan would find the category's
136 * +load method, which would then be called twice.
137 *
138 **********************************************************************/
139
140
141 /***********************************************************************
142 * Imports.
143 **********************************************************************/
144
145 #include <mach-o/ldsyms.h>
146 #include <mach-o/dyld.h>
147 #include <mach-o/dyld_gdb.h>
148 #include <mach/mach.h>
149 #include <mach/mach_error.h>
150
151 // project headers first, otherwise we get the installed ones
152 #import "objc-class.h"
153 #import <objc/objc-runtime.h>
154 #import <objc/hashtable2.h>
155 #import "maptable.h"
156 #import "objc-private.h"
157 #import <objc/Object.h>
158 #import <objc/Protocol.h>
159 #import "objc-rtp.h"
160 #import "objc-auto.h"
161
162 #include <sys/time.h>
163 #include <sys/resource.h>
164 #include <sys/types.h>
165 #include <sys/stat.h>
166 #include <fcntl.h>
167
168 /* NXHashTable SPI */
169 OBJC_EXPORT unsigned _NXHashCapacity(NXHashTable *table);
170 OBJC_EXPORT void _NXHashRehashToCapacity(NXHashTable *table, unsigned newCapacity);
171
172
173 OBJC_EXPORT Class _objc_getNonexistentClass(void);
174
175
176 OBJC_EXPORT Class getOriginalClassForPosingClass(Class);
177
178
179 /***********************************************************************
180 * Constants and macros internal to this module.
181 **********************************************************************/
182
183 /* Turn on support for literal string objects. */
184 #define LITERAL_STRING_OBJECTS
185
186 /***********************************************************************
187 * Types internal to this module.
188 **********************************************************************/
189
190 typedef struct _objc_unresolved_category
191 {
192 struct _objc_unresolved_category * next;
193 struct objc_category * cat; // may be NULL
194 long version;
195 } _objc_unresolved_category;
196
197 typedef struct _PendingSubclass
198 {
199 struct objc_class *subclass; // subclass to finish connecting; may be NULL
200 struct _PendingSubclass *next;
201 } PendingSubclass;
202
203 typedef struct _PendingClassRef
204 {
205 struct objc_class **ref; // class reference to fix up; may be NULL
206 struct _PendingClassRef *next;
207 } PendingClassRef;
208
209 struct loadable_class {
210 struct objc_class *cls; // may be NULL
211 IMP method;
212 };
213
214 struct loadable_category {
215 struct objc_category *cat; // may be NULL
216 IMP method;
217 };
218
219
220 /***********************************************************************
221 * Exports.
222 **********************************************************************/
223
224 // Function called after class has been fixed up (MACH only)
225 void (*callbackFunction)(Class, const char *) = 0;
226
227 // Lock for class hashtable
228 OBJC_DECLARE_LOCK (classLock);
229
230 // Settings from environment variables
231 __private_extern__ int PrintImages = -1; // env OBJC_PRINT_IMAGES
232 __private_extern__ int PrintLoading = -1; // env OBJC_PRINT_LOAD_METHODS
233 __private_extern__ int PrintConnecting = -1; // env OBJC_PRINT_CONNECTION
234 __private_extern__ int PrintRTP = -1; // env OBJC_PRINT_RTP
235 __private_extern__ int PrintGC = -1; // env OBJC_PRINT_GC
236 __private_extern__ int PrintSharing = -1; // env OBJC_PRINT_SHARING
237 __private_extern__ int PrintCxxCtors = -1; // env OBJC_PRINT_CXX_CTORS
238
239 __private_extern__ int UseInternalZone = -1; // env OBJC_USE_INTERNAL_ZONE
240 __private_extern__ int AllowInterposing = -1;// env OBJC_ALLOW_INTERPOSING
241
242 __private_extern__ int DebugUnload = -1; // env OBJC_DEBUG_UNLOAD
243 __private_extern__ int DebugFragileSuperclasses = -1; // env OBJC_DEBUG_FRAGILE_SUPERCLASSES
244
245 __private_extern__ int ForceGC = -1; // env OBJC_FORCE_GC
246 __private_extern__ int ForceNoGC = -1; // env OBJC_FORCE_NO_GC
247 __private_extern__ int CheckFinalizers = -1; // env OBJC_CHECK_FINALIZERS
248
249 // objc's key for pthread_getspecific
250 __private_extern__ pthread_key_t _objc_pthread_key = 0;
251
252 // List of classes that need +load called (pending superclass +load)
253 // This list always has superclasses first because of the way it is constructed
254 static struct loadable_class *loadable_classes NOBSS = NULL;
255 static int loadable_classes_used NOBSS = 0;
256 static int loadable_classes_allocated NOBSS = 0;
257
258 // List of categories that need +load called (pending parent class +load)
259 static struct loadable_category *loadable_categories NOBSS = NULL;
260 static int loadable_categories_used NOBSS = 0;
261 static int loadable_categories_allocated NOBSS = 0;
262
263 // Selectors for which @selector() doesn't work
264 __private_extern__ SEL cxx_construct_sel = NULL;
265 __private_extern__ SEL cxx_destruct_sel = NULL;
266 __private_extern__ const char *cxx_construct_name = ".cxx_construct";
267 __private_extern__ const char *cxx_destruct_name = ".cxx_destruct";
268
269
270 /***********************************************************************
271 * Function prototypes internal to this module.
272 **********************************************************************/
273
274 static unsigned classHash (void * info, struct objc_class * data);
275 static int classIsEqual (void * info, struct objc_class * name, struct objc_class * cls);
276 static int _objc_defaultClassHandler (const char * clsName);
277 static void _objcTweakMethodListPointerForClass (struct objc_class * cls);
278 static void _objc_add_category_flush_caches(struct objc_class * cls, struct objc_category * category, int version);
279 static void _objc_add_category(struct objc_class * cls, struct objc_category * category, int version);
280 static void _objc_register_category (struct objc_category * cat, long version);
281 static void _objc_read_categories_from_image (header_info * hi);
282 static const header_info * _headerForClass (struct objc_class * cls);
283 static NXMapTable * pendingClassRefsMapTable (void);
284 static NXMapTable * pendingSubclassesMapTable (void);
285 static void _objc_read_classes_from_image (header_info * hi);
286 static void _objc_map_class_refs_for_image (header_info * hi);
287 static void _objc_fixup_protocol_objects_for_image (header_info * hi);
288 static void _objc_fixup_selector_refs (const header_info * hi);
289 static void _objc_unmap_image(const headerType *mh);
290 static BOOL connect_class(struct objc_class *cls);
291 static void add_category_to_loadable_list(struct objc_category *cat);
292 static vm_range_t get_shared_range(vm_address_t start, vm_address_t end);
293 static void offer_shared_range(vm_address_t start, vm_address_t end);
294 static void install_shared_range(vm_range_t remote, vm_address_t local);
295 static void clear_shared_range_file_cache(void);
296
297
298 /***********************************************************************
299 * Static data internal to this module.
300 **********************************************************************/
301
302 // we keep a linked list of header_info's describing each image as told to us by dyld
303 static header_info *FirstHeader NOBSS = 0; // NULL means empty list
304 static header_info *LastHeader NOBSS = 0; // NULL means invalid; recompute it
305
306 // Hash table of classes
307 static NXHashTable * class_hash NOBSS = 0;
308 static NXHashTablePrototype classHashPrototype =
309 {
310 (unsigned (*) (const void *, const void *)) classHash,
311 (int (*)(const void *, const void *, const void *)) classIsEqual,
312 NXNoEffectFree, 0
313 };
314
315 // Hash table of unconnected classes
316 static NXHashTable *unconnected_class_hash NOBSS = NULL;
317
318 // Exported copy of class_hash variable (hook for debugging tools)
319 NXHashTable *_objc_debug_class_hash = NULL;
320
321 // Function pointer objc_getClass calls through when class is not found
322 static int (*objc_classHandler) (const char *) = _objc_defaultClassHandler;
323
324 // Function pointer called by objc_getClass and objc_lookupClass when
325 // class is not found. _objc_classLoader is called before objc_classHandler.
326 static BOOL (*_objc_classLoader)(const char *) = NULL;
327
328 // Category and class registries
329 // Keys are COPIES of strings, to prevent stale pointers with unloaded bundles
330 // Use NXMapKeyCopyingInsert and NXMapKeyFreeingRemove
331 static NXMapTable * category_hash = NULL;
332
333 // Keys are COPIES of strings, to prevent stale pointers with unloaded bundles
334 // Use NXMapKeyCopyingInsert and NXMapKeyFreeingRemove
335 static NXMapTable * pendingClassRefsMap = NULL;
336 static NXMapTable * pendingSubclassesMap = NULL;
337
338 /***********************************************************************
339 * objc_dump_class_hash. Log names of all known classes.
340 **********************************************************************/
341 void objc_dump_class_hash (void)
342 {
343 NXHashTable * table;
344 unsigned count;
345 struct objc_class * data;
346 NXHashState state;
347
348 table = class_hash;
349 count = 0;
350 state = NXInitHashState (table);
351 while (NXNextHashState (table, &state, (void **) &data))
352 printf ("class %d: %s\n", ++count, data->name);
353 }
354
355 /***********************************************************************
356 * classHash.
357 **********************************************************************/
358 static unsigned classHash (void * info,
359 struct objc_class * data)
360 {
361 // Nil classes hash to zero
362 if (!data)
363 return 0;
364
365 // Call through to real hash function
366 return _objc_strhash ((unsigned char *) ((struct objc_class *) data)->name);
367 }
368
369 /***********************************************************************
370 * classIsEqual. Returns whether the class names match. If we ever
371 * check more than the name, routines like objc_lookUpClass have to
372 * change as well.
373 **********************************************************************/
374 static int classIsEqual (void * info,
375 struct objc_class * name,
376 struct objc_class * cls)
377 {
378 // Standard string comparison
379 // Our local inlined version is significantly shorter on PPC and avoids the
380 // mflr/mtlr and dyld_stub overhead when calling strcmp.
381 return _objc_strcmp(name->name, cls->name) == 0;
382 }
383
384
385 /***********************************************************************
386 * NXMapKeyCopyingInsert
387 * Like NXMapInsert, but strdups the key if necessary.
388 * Used to prevent stale pointers when bundles are unloaded.
389 **********************************************************************/
390 static void *NXMapKeyCopyingInsert(NXMapTable *table, const void *key, const void *value)
391 {
392 void *realKey;
393 void *realValue = NULL;
394
395 if ((realKey = NXMapMember(table, key, &realValue)) != NX_MAPNOTAKEY) {
396 // key DOES exist in table - use table's key for insertion
397 } else {
398 // key DOES NOT exist in table - copy the new key before insertion
399 realKey = _strdup_internal(key);
400 }
401 return NXMapInsert(table, realKey, value);
402 }
403
404
405 /***********************************************************************
406 * NXMapKeyFreeingRemove
407 * Like NXMapRemove, but frees the existing key if necessary.
408 * Used to prevent stale pointers when bundles are unloaded.
409 **********************************************************************/
410 static void *NXMapKeyFreeingRemove(NXMapTable *table, const void *key)
411 {
412 void *realKey;
413 void *realValue = NULL;
414
415 if ((realKey = NXMapMember(table, key, &realValue)) != NX_MAPNOTAKEY) {
416 // key DOES exist in table - remove pair and free key
417 realValue = NXMapRemove(table, realKey);
418 _free_internal(realKey); // the key from the table, not necessarily the one given
419 return realValue;
420 } else {
421 // key DOES NOT exist in table - nothing to do
422 return NULL;
423 }
424 }
425
426
427 /***********************************************************************
428 * _objc_init_class_hash. Return the class lookup table, create it if
429 * necessary.
430 **********************************************************************/
431 void _objc_init_class_hash (void)
432 {
433 // Do nothing if class hash table already exists
434 if (class_hash)
435 return;
436
437 // class_hash starts small, with only enough capacity for libobjc itself.
438 // If a second library is found by map_images(), class_hash is immediately
439 // resized to capacity 1024 to cut down on rehashes.
440 // Old numbers: A smallish Foundation+AppKit program will have
441 // about 520 classes. Larger apps (like IB or WOB) have more like
442 // 800 classes. Some customers have massive quantities of classes.
443 // Foundation-only programs aren't likely to notice the ~6K loss.
444 class_hash = NXCreateHashTableFromZone (classHashPrototype,
445 16,
446 nil,
447 _objc_internal_zone ());
448 _objc_debug_class_hash = class_hash;
449 }
450
451 /***********************************************************************
452 * objc_getClassList. Return the known classes.
453 **********************************************************************/
454 int objc_getClassList(Class *buffer, int bufferLen) {
455 NXHashState state;
456 struct objc_class * class;
457 int cnt, num;
458
459 OBJC_LOCK(&classLock);
460 num = NXCountHashTable(class_hash);
461 if (NULL == buffer) {
462 OBJC_UNLOCK(&classLock);
463 return num;
464 }
465 cnt = 0;
466 state = NXInitHashState(class_hash);
467 while (cnt < bufferLen &&
468 NXNextHashState(class_hash, &state, (void **)&class))
469 {
470 buffer[cnt++] = class;
471 }
472 OBJC_UNLOCK(&classLock);
473 return num;
474 }
475
476 /***********************************************************************
477 * objc_getClasses. Return class lookup table.
478 *
479 * NOTE: This function is very dangerous, since you cannot safely use
480 * the hashtable without locking it, and the lock is private!
481 **********************************************************************/
482 void * objc_getClasses (void)
483 {
484 // Return the class lookup hash table
485 return class_hash;
486 }
487
488 /***********************************************************************
489 * _objc_defaultClassHandler. Default objc_classHandler. Does nothing.
490 **********************************************************************/
491 static int _objc_defaultClassHandler (const char * clsName)
492 {
493 // Return zero so objc_getClass doesn't bother re-searching
494 return 0;
495 }
496
497 /***********************************************************************
498 * objc_setClassHandler. Set objc_classHandler to the specified value.
499 *
500 * NOTE: This should probably deal with userSuppliedHandler being NULL,
501 * because the objc_classHandler caller does not check... it would bus
502 * error. It would make sense to handle NULL by restoring the default
503 * handler. Is anyone hacking with this, though?
504 **********************************************************************/
505 void objc_setClassHandler (int (*userSuppliedHandler) (const char *))
506 {
507 objc_classHandler = userSuppliedHandler;
508 }
509
510
511 /***********************************************************************
512 * look_up_class
513 * Map a class name to a class using various methods.
514 * This is the common implementation of objc_lookUpClass and objc_getClass,
515 * and is also used internally to get additional search options.
516 * Sequence:
517 * 1. class_hash
518 * 2. unconnected_class_hash (optional)
519 * 3. classLoader callback
520 * 4. classHandler callback (optional)
521 **********************************************************************/
522 static id look_up_class(const char *aClassName, BOOL includeUnconnected, BOOL includeClassHandler)
523 {
524 BOOL includeClassLoader = YES; // class loader cannot be skipped
525 id result = nil;
526 struct objc_class query;
527
528 query.name = aClassName;
529
530 retry:
531
532 if (!result && class_hash) {
533 // Check ordinary classes
534 OBJC_LOCK (&classLock);
535 result = (id)NXHashGet(class_hash, &query);
536 OBJC_UNLOCK (&classLock);
537 }
538
539 if (!result && includeUnconnected && unconnected_class_hash) {
540 // Check not-yet-connected classes
541 OBJC_LOCK(&classLock);
542 result = (id)NXHashGet(unconnected_class_hash, &query);
543 OBJC_UNLOCK(&classLock);
544 }
545
546 if (!result && includeClassLoader && _objc_classLoader) {
547 // Try class loader callback
548 if ((*_objc_classLoader)(aClassName)) {
549 // Re-try lookup without class loader
550 includeClassLoader = NO;
551 goto retry;
552 }
553 }
554
555 if (!result && includeClassHandler && objc_classHandler) {
556 // Try class handler callback
557 if ((*objc_classHandler)(aClassName)) {
558 // Re-try lookup without class handler or class loader
559 includeClassLoader = NO;
560 includeClassHandler = NO;
561 goto retry;
562 }
563 }
564
565 return result;
566 }
567
568
569 /***********************************************************************
570 * objc_getClass. Return the id of the named class. If the class does
571 * not exist, call _objc_classLoader and then objc_classHandler, either of
572 * which may create a new class.
573 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
574 **********************************************************************/
575 id objc_getClass (const char * aClassName)
576 {
577 // NO unconnected, YES class handler
578 return look_up_class(aClassName, NO, YES);
579 }
580
581
582 /***********************************************************************
583 * objc_getRequiredClass.
584 * Same as objc_getClass, but kills the process if the class is not found.
585 * This is used by ZeroLink, where failing to find a class would be a
586 * compile-time link error without ZeroLink.
587 **********************************************************************/
588 id objc_getRequiredClass(const char *aClassName)
589 {
590 id cls = objc_getClass(aClassName);
591 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
592 return cls;
593 }
594
595
596 /***********************************************************************
597 * objc_lookUpClass. Return the id of the named class.
598 * If the class does not exist, call _objc_classLoader, which may create
599 * a new class.
600 *
601 * Formerly objc_getClassWithoutWarning ()
602 **********************************************************************/
603 id objc_lookUpClass (const char * aClassName)
604 {
605 // NO unconnected, NO class handler
606 return look_up_class(aClassName, NO, NO);
607 }
608
609 /***********************************************************************
610 * objc_getMetaClass. Return the id of the meta class the named class.
611 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
612 **********************************************************************/
613 id objc_getMetaClass (const char * aClassName)
614 {
615 struct objc_class * cls;
616
617 cls = objc_getClass (aClassName);
618 if (!cls)
619 {
620 _objc_inform ("class `%s' not linked into application", aClassName);
621 return Nil;
622 }
623
624 return cls->isa;
625 }
626
627 /***********************************************************************
628 * objc_addClass. Add the specified class to the table of known classes,
629 * after doing a little verification and fixup.
630 **********************************************************************/
631 void objc_addClass (struct objc_class *cls)
632 {
633 // Synchronize access to hash table
634 OBJC_LOCK (&classLock);
635
636 // Make sure both the class and the metaclass have caches!
637 // Clear all bits of the info fields except CLS_CLASS and CLS_META.
638 // Normally these bits are already clear but if someone tries to cons
639 // up their own class on the fly they might need to be cleared.
640 if (cls->cache == NULL) {
641 cls->cache = (Cache) &emptyCache;
642 cls->info = CLS_CLASS;
643 }
644
645 if (cls->isa->cache == NULL) {
646 cls->isa->cache = (Cache) &emptyCache;
647 cls->isa->info = CLS_META;
648 }
649
650 // methodLists should be:
651 // 1. NULL (Tiger and later only)
652 // 2. A -1 terminated method list array
653 // In either case, CLS_NO_METHOD_ARRAY remains clear.
654 // If the user manipulates the method list directly,
655 // they must use the magic private format.
656
657 // Add the class to the table
658 (void) NXHashInsert (class_hash, cls);
659
660 // Desynchronize
661 OBJC_UNLOCK (&classLock);
662 }
663
664 /***********************************************************************
665 * _objcTweakMethodListPointerForClass.
666 * Change the class's method list pointer to a method list array.
667 * Does nothing if the method list pointer is already a method list array.
668 * If the class is currently in use, methodListLock must be held by the caller.
669 **********************************************************************/
670 static void _objcTweakMethodListPointerForClass (struct objc_class * cls)
671 {
672 struct objc_method_list * originalList;
673 const int initialEntries = 4;
674 int mallocSize;
675 struct objc_method_list ** ptr;
676
677 // Do nothing if methodLists is already an array.
678 if (cls->methodLists && !(cls->info & CLS_NO_METHOD_ARRAY)) return;
679
680 // Remember existing list
681 originalList = (struct objc_method_list *) cls->methodLists;
682
683 // Allocate and zero a method list array
684 mallocSize = sizeof(struct objc_method_list *) * initialEntries;
685 ptr = (struct objc_method_list **) _calloc_internal(1, mallocSize);
686
687 // Insert the existing list into the array
688 ptr[initialEntries - 1] = END_OF_METHODS_LIST;
689 ptr[0] = originalList;
690
691 // Replace existing list with array
692 cls->methodLists = ptr;
693 _class_clearInfo(cls, CLS_NO_METHOD_ARRAY);
694 }
695
696
697 /***********************************************************************
698 * _objc_insertMethods.
699 * Adds methods to a class.
700 * Does not flush any method caches.
701 * Does not take any locks.
702 * If the class is already in use, use class_addMethods() instead.
703 **********************************************************************/
704 void _objc_insertMethods(struct objc_class *cls,
705 struct objc_method_list *mlist)
706 {
707 struct objc_method_list ***list;
708 struct objc_method_list **ptr;
709 int endIndex;
710 int oldSize;
711 int newSize;
712
713 if (!cls->methodLists) {
714 // cls has no methods - simply use this method list
715 cls->methodLists = (struct objc_method_list **)mlist;
716 _class_setInfo(cls, CLS_NO_METHOD_ARRAY);
717 return;
718 }
719
720 // Create method list array if necessary
721 _objcTweakMethodListPointerForClass(cls);
722
723 list = &cls->methodLists;
724
725 // Locate unused entry for insertion point
726 ptr = *list;
727 while ((*ptr != 0) && (*ptr != END_OF_METHODS_LIST))
728 ptr += 1;
729
730 // If array is full, add to it
731 if (*ptr == END_OF_METHODS_LIST)
732 {
733 // Calculate old and new dimensions
734 endIndex = ptr - *list;
735 oldSize = (endIndex + 1) * sizeof(void *);
736 newSize = oldSize + sizeof(struct objc_method_list *); // only increase by 1
737
738 // Grow the method list array by one.
739 // This block may be from user code; don't use _realloc_internal
740 *list = (struct objc_method_list **)realloc(*list, newSize);
741
742 // Zero out addition part of new array
743 bzero (&((*list)[endIndex]), newSize - oldSize);
744
745 // Place new end marker
746 (*list)[(newSize/sizeof(void *)) - 1] = END_OF_METHODS_LIST;
747
748 // Insertion point corresponds to old array end
749 ptr = &((*list)[endIndex]);
750 }
751
752 // Right shift existing entries by one
753 bcopy (*list, (*list) + 1, ((void *) ptr) - ((void *) *list));
754
755 // Insert at method list at beginning of array
756 **list = mlist;
757 }
758
759 /***********************************************************************
760 * _objc_removeMethods.
761 * Remove methods from a class.
762 * Does not take any locks.
763 * Does not flush any method caches.
764 * If the class is currently in use, use class_removeMethods() instead.
765 **********************************************************************/
766 void _objc_removeMethods(struct objc_class *cls,
767 struct objc_method_list *mlist)
768 {
769 struct objc_method_list ***list;
770 struct objc_method_list **ptr;
771
772 if (cls->methodLists == NULL) {
773 // cls has no methods
774 return;
775 }
776 if (cls->methodLists == (struct objc_method_list **)mlist) {
777 // mlist is the class's only method list - erase it
778 cls->methodLists = NULL;
779 return;
780 }
781 if (cls->info & CLS_NO_METHOD_ARRAY) {
782 // cls has only one method list, and this isn't it - do nothing
783 return;
784 }
785
786 // cls has a method list array - search it
787
788 list = &cls->methodLists;
789
790 // Locate list in the array
791 ptr = *list;
792 while (*ptr != mlist) {
793 // fix for radar # 2538790
794 if ( *ptr == END_OF_METHODS_LIST ) return;
795 ptr += 1;
796 }
797
798 // Remove this entry
799 *ptr = 0;
800
801 // Left shift the following entries
802 while (*(++ptr) != END_OF_METHODS_LIST)
803 *(ptr-1) = *ptr;
804 *(ptr-1) = 0;
805 }
806
807 /***********************************************************************
808 * _objc_add_category. Install the specified category's methods and
809 * protocols into the class it augments.
810 * The class is assumed not to be in use yet: no locks are taken and
811 * no method caches are flushed.
812 **********************************************************************/
813 static inline void _objc_add_category(struct objc_class *cls, struct objc_category *category, int version)
814 {
815 if (PrintConnecting) {
816 _objc_inform("CONNECT: attaching category '%s (%s)'", cls->name, category->category_name);
817 }
818
819 // Augment instance methods
820 if (category->instance_methods)
821 _objc_insertMethods (cls, category->instance_methods);
822
823 // Augment class methods
824 if (category->class_methods)
825 _objc_insertMethods (cls->isa, category->class_methods);
826
827 // Augment protocols
828 if ((version >= 5) && category->protocols)
829 {
830 if (cls->isa->version >= 5)
831 {
832 category->protocols->next = cls->protocols;
833 cls->protocols = category->protocols;
834 cls->isa->protocols = category->protocols;
835 }
836 else
837 {
838 _objc_inform ("unable to add protocols from category %s...\n", category->category_name);
839 _objc_inform ("class `%s' must be recompiled\n", category->class_name);
840 }
841 }
842 }
843
844 /***********************************************************************
845 * _objc_add_category_flush_caches. Install the specified category's
846 * methods into the class it augments, and flush the class' method cache.
847 **********************************************************************/
848 static void _objc_add_category_flush_caches(struct objc_class *cls, struct objc_category *category, int version)
849 {
850 // Install the category's methods into its intended class
851 OBJC_LOCK(&methodListLock);
852 _objc_add_category (cls, category, version);
853 OBJC_UNLOCK(&methodListLock);
854
855 // Flush caches so category's methods can get called
856 _objc_flush_caches (cls);
857 }
858
859
860 /***********************************************************************
861 * reverse_cat
862 * Reverse the given linked list of pending categories.
863 * The pending category list is built backwards, and needs to be
864 * reversed before actually attaching the categories to a class.
865 * Returns the head of the new linked list.
866 **********************************************************************/
867 static _objc_unresolved_category *reverse_cat(_objc_unresolved_category *cat)
868 {
869 if (!cat) return NULL;
870
871 _objc_unresolved_category *prev = NULL;
872 _objc_unresolved_category *cur = cat;
873 _objc_unresolved_category *ahead = cat->next;
874
875 while (cur) {
876 ahead = cur->next;
877 cur->next = prev;
878 prev = cur;
879 cur = ahead;
880 }
881
882 return prev;
883 }
884
885
886 /***********************************************************************
887 * resolve_categories_for_class.
888 * Install all existing categories intended for the specified class.
889 * cls must be a true class and not a metaclass.
890 **********************************************************************/
891 static void resolve_categories_for_class(struct objc_class *cls)
892 {
893 _objc_unresolved_category * pending;
894 _objc_unresolved_category * next;
895
896 // Nothing to do if there are no categories at all
897 if (!category_hash) return;
898
899 // Locate and remove first element in category list
900 // associated with this class
901 pending = NXMapKeyFreeingRemove (category_hash, cls->name);
902
903 // Traverse the list of categories, if any, registered for this class
904
905 // The pending list is built backwards. Reverse it and walk forwards.
906 pending = reverse_cat(pending);
907
908 while (pending) {
909 if (pending->cat) {
910 // Install the category
911 // use the non-flush-cache version since we are only
912 // called from the class intialization code
913 _objc_add_category(cls, pending->cat, pending->version);
914 }
915
916 // Delink and reclaim this registration
917 next = pending->next;
918 _free_internal(pending);
919 pending = next;
920 }
921 }
922
923
924 /***********************************************************************
925 * _objc_resolve_categories_for_class.
926 * Public version of resolve_categories_for_class. This was
927 * exported pre-10.4 for Omni et al. to workaround a problem
928 * with too-lazy category attachment.
929 * cls should be a class, but this function can also cope with metaclasses.
930 **********************************************************************/
931 void _objc_resolve_categories_for_class(struct objc_class *cls)
932 {
933
934 // If cls is a metaclass, get the class.
935 // resolve_categories_for_class() requires a real class to work correctly.
936 if (ISMETA(cls)) {
937 if (strncmp(cls->name, "_%", 2) == 0) {
938 // Posee's meta's name is smashed and isn't in the class_hash,
939 // so objc_getClass doesn't work.
940 char *baseName = strchr(cls->name, '%'); // get posee's real name
941 cls = objc_getClass(baseName);
942 } else {
943 cls = objc_getClass(cls->name);
944 }
945 }
946
947 resolve_categories_for_class(cls);
948 }
949
950
951 /***********************************************************************
952 * _objc_register_category.
953 * Process a category read from an image.
954 * If the category's class exists, attach the category immediately.
955 * If the category's class does not exist yet, pend the category for
956 * later attachment. Pending categories are attached in the order
957 * they were discovered.
958 **********************************************************************/
959 static void _objc_register_category(struct objc_category *cat, long version)
960 {
961 _objc_unresolved_category * new_cat;
962 _objc_unresolved_category * old;
963 struct objc_class *theClass;
964
965 // If the category's class exists, attach the category.
966 if ((theClass = objc_lookUpClass(cat->class_name))) {
967 _objc_add_category_flush_caches(theClass, cat, version);
968 return;
969 }
970
971 // If the category's class exists but is unconnected,
972 // then attach the category to the class but don't bother
973 // flushing any method caches (because they must be empty).
974 // YES unconnected, NO class_handler
975 if ((theClass = look_up_class(cat->class_name, YES, NO))) {
976 _objc_add_category(theClass, cat, version);
977 return;
978 }
979
980
981 // Category's class does not exist yet.
982 // Save the category for later attachment.
983
984 if (PrintConnecting) {
985 _objc_inform("CONNECT: pending category '%s (%s)'", cat->class_name, cat->category_name);
986 }
987
988 // Create category lookup table if needed
989 if (!category_hash)
990 category_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype,
991 128,
992 _objc_internal_zone ());
993
994 // Locate an existing list of categories, if any, for the class.
995 old = NXMapGet (category_hash, cat->class_name);
996
997 // Register the category to be fixed up later.
998 // The category list is built backwards, and is reversed again
999 // by resolve_categories_for_class().
1000 new_cat = _malloc_internal(sizeof(_objc_unresolved_category));
1001 new_cat->next = old;
1002 new_cat->cat = cat;
1003 new_cat->version = version;
1004 (void) NXMapKeyCopyingInsert (category_hash, cat->class_name, new_cat);
1005 }
1006
1007
1008 /***********************************************************************
1009 * _objc_read_categories_from_image.
1010 * Read all categories from the given image.
1011 * Install them on their parent classes, or register them for later
1012 * installation.
1013 * Register them for later +load, if implemented.
1014 **********************************************************************/
1015 static void _objc_read_categories_from_image (header_info * hi)
1016 {
1017 Module mods;
1018 unsigned int midx;
1019
1020 if (_objcHeaderIsReplacement(hi)) {
1021 // Ignore any categories in this image
1022 return;
1023 }
1024
1025 // Major loop - process all modules in the header
1026 mods = hi->mod_ptr;
1027
1028 // NOTE: The module and category lists are traversed backwards
1029 // to preserve the pre-10.4 processing order. Changing the order
1030 // would have a small chance of introducing binary compatibility bugs.
1031 midx = hi->mod_count;
1032 while (midx-- > 0) {
1033 unsigned int index;
1034 unsigned int total;
1035
1036 // Nothing to do for a module without a symbol table
1037 if (mods[midx].symtab == NULL)
1038 continue;
1039
1040 // Total entries in symbol table (class entries followed
1041 // by category entries)
1042 total = mods[midx].symtab->cls_def_cnt +
1043 mods[midx].symtab->cat_def_cnt;
1044
1045 // Minor loop - register all categories from given module
1046 index = total;
1047 while (index-- > mods[midx].symtab->cls_def_cnt) {
1048 struct objc_category *cat = mods[midx].symtab->defs[index];
1049 _objc_register_category(cat, mods[midx].version);
1050 add_category_to_loadable_list(cat);
1051 }
1052 }
1053 }
1054
1055
1056 /***********************************************************************
1057 * _headerForAddress.
1058 * addr can be a class or a category
1059 **********************************************************************/
1060 static const header_info *_headerForAddress(void *addr)
1061 {
1062 unsigned long size;
1063 unsigned long seg;
1064 header_info * hInfo;
1065
1066 // Check all headers in the vector
1067 for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next)
1068 {
1069 // Locate header data, if any
1070 if (!hInfo->objcSegmentHeader) continue;
1071 seg = hInfo->objcSegmentHeader->vmaddr + hInfo->image_slide;
1072 size = hInfo->objcSegmentHeader->filesize;
1073
1074 // Is the class in this header?
1075 if ((seg <= (unsigned long) addr) &&
1076 ((unsigned long) addr < (seg + size)))
1077 return hInfo;
1078 }
1079
1080 // Not found
1081 return 0;
1082 }
1083
1084
1085 /***********************************************************************
1086 * _headerForClass
1087 * Return the image header containing this class, or NULL.
1088 * Returns NULL on runtime-constructed classes, and the NSCF classes.
1089 **********************************************************************/
1090 static const header_info *_headerForClass(struct objc_class *cls)
1091 {
1092 return _headerForAddress(cls);
1093 }
1094
1095
1096 /***********************************************************************
1097 * _nameForHeader.
1098 **********************************************************************/
1099 const char * _nameForHeader (const headerType * header)
1100 {
1101 return _getObjcHeaderName ((headerType *) header);
1102 }
1103
1104
1105 /***********************************************************************
1106 * class_is_connected.
1107 * Returns TRUE if class cls is connected.
1108 * A connected class has either a connected superclass or a NULL superclass,
1109 * and is present in class_hash.
1110 **********************************************************************/
1111 static BOOL class_is_connected(struct objc_class *cls)
1112 {
1113 BOOL result;
1114 OBJC_LOCK(&classLock);
1115 result = NXHashMember(class_hash, cls);
1116 OBJC_UNLOCK(&classLock);
1117 return result;
1118 }
1119
1120
1121 /***********************************************************************
1122 * pendingClassRefsMapTable. Return a pointer to the lookup table for
1123 * pending class refs.
1124 **********************************************************************/
1125 static inline NXMapTable *pendingClassRefsMapTable(void)
1126 {
1127 // Allocate table if needed
1128 if (!pendingClassRefsMap) {
1129 pendingClassRefsMap =
1130 NXCreateMapTableFromZone(NXStrValueMapPrototype,
1131 10, _objc_internal_zone ());
1132 }
1133
1134 // Return table pointer
1135 return pendingClassRefsMap;
1136 }
1137
1138
1139 /***********************************************************************
1140 * pendingSubclassesMapTable. Return a pointer to the lookup table for
1141 * pending subclasses.
1142 **********************************************************************/
1143 static inline NXMapTable *pendingSubclassesMapTable(void)
1144 {
1145 // Allocate table if needed
1146 if (!pendingSubclassesMap) {
1147 pendingSubclassesMap =
1148 NXCreateMapTableFromZone(NXStrValueMapPrototype,
1149 10, _objc_internal_zone ());
1150 }
1151
1152 // Return table pointer
1153 return pendingSubclassesMap;
1154 }
1155
1156
1157 /***********************************************************************
1158 * pendClassInstallation
1159 * Finish connecting class cls when its superclass becomes connected.
1160 * Check for multiple pends of the same class because connect_class does not.
1161 **********************************************************************/
1162 static void pendClassInstallation(struct objc_class *cls,
1163 const char *superName)
1164 {
1165 NXMapTable *table;
1166 PendingSubclass *pending;
1167 PendingSubclass *oldList;
1168 PendingSubclass *l;
1169
1170 // Create and/or locate pending class lookup table
1171 table = pendingSubclassesMapTable ();
1172
1173 // Make sure this class isn't already in the pending list.
1174 oldList = NXMapGet (table, superName);
1175 for (l = oldList; l != NULL; l = l->next) {
1176 if (l->subclass == cls) return; // already here, nothing to do
1177 }
1178
1179 // Create entry referring to this class
1180 pending = _malloc_internal(sizeof(PendingSubclass));
1181 pending->subclass = cls;
1182
1183 // Link new entry into head of list of entries for this class
1184 pending->next = oldList;
1185
1186 // (Re)place entry list in the table
1187 (void) NXMapKeyCopyingInsert (table, superName, pending);
1188 }
1189
1190
1191 /***********************************************************************
1192 * pendClassReference
1193 * Fix up a class ref when the class with the given name becomes connected.
1194 **********************************************************************/
1195 static void pendClassReference(struct objc_class **ref,
1196 const char *className)
1197 {
1198 NXMapTable *table;
1199 PendingClassRef *pending;
1200
1201 // Create and/or locate pending class lookup table
1202 table = pendingClassRefsMapTable ();
1203
1204 // Create entry containing the class reference
1205 pending = _malloc_internal(sizeof(PendingClassRef));
1206 pending->ref = ref;
1207
1208 // Link new entry into head of list of entries for this class
1209 pending->next = NXMapGet (table, className);
1210
1211 // (Re)place entry list in the table
1212 (void) NXMapKeyCopyingInsert (table, className, pending);
1213
1214 if (PrintConnecting) {
1215 _objc_inform("CONNECT: pended reference to class '%s' at %p",
1216 className, (void *)ref);
1217 }
1218 }
1219
1220
1221 /***********************************************************************
1222 * resolve_references_to_class
1223 * Fix up any pending class refs to this class.
1224 **********************************************************************/
1225 static void resolve_references_to_class(struct objc_class *cls)
1226 {
1227 PendingClassRef *pending;
1228
1229 if (!pendingClassRefsMap) return; // no unresolved refs for any class
1230
1231 pending = NXMapGet(pendingClassRefsMap, cls->name);
1232 if (!pending) return; // no unresolved refs for this class
1233
1234 NXMapKeyFreeingRemove(pendingClassRefsMap, cls->name);
1235
1236 if (PrintConnecting) {
1237 _objc_inform("CONNECT: resolving references to class '%s'", cls->name);
1238 }
1239
1240 while (pending) {
1241 PendingClassRef *next = pending->next;
1242 if (pending->ref) *pending->ref = cls;
1243 _free_internal(pending);
1244 pending = next;
1245 }
1246
1247 if (NXCountMapTable(pendingClassRefsMap) == 0) {
1248 NXFreeMapTable(pendingClassRefsMap);
1249 pendingClassRefsMap = NULL;
1250 }
1251 }
1252
1253
1254 /***********************************************************************
1255 * resolve_subclasses_of_class
1256 * Fix up any pending subclasses of this class.
1257 **********************************************************************/
1258 static void resolve_subclasses_of_class(struct objc_class *cls)
1259 {
1260 PendingSubclass *pending;
1261
1262 if (!pendingSubclassesMap) return; // no unresolved subclasses
1263
1264 pending = NXMapGet(pendingSubclassesMap, cls->name);
1265 if (!pending) return; // no unresolved subclasses for this class
1266
1267 NXMapKeyFreeingRemove(pendingSubclassesMap, cls->name);
1268
1269 // Destroy the pending table if it's now empty, to save memory.
1270 if (NXCountMapTable(pendingSubclassesMap) == 0) {
1271 NXFreeMapTable(pendingSubclassesMap);
1272 pendingSubclassesMap = NULL;
1273 }
1274
1275 if (PrintConnecting) {
1276 _objc_inform("CONNECT: resolving subclasses of class '%s'", cls->name);
1277 }
1278
1279 while (pending) {
1280 PendingSubclass *next = pending->next;
1281 if (pending->subclass) connect_class(pending->subclass);
1282 _free_internal(pending);
1283 pending = next;
1284 }
1285 }
1286
1287
1288 /***********************************************************************
1289 * get_base_method_list
1290 * Returns the method list containing the class's own methods,
1291 * ignoring any method lists added by categories or class_addMethods.
1292 * Called only by add_class_to_loadable_list.
1293 * Does not hold methodListLock because add_class_to_loadable_list
1294 * does not manipulate in-use classes.
1295 **********************************************************************/
1296 static struct objc_method_list *get_base_method_list(struct objc_class *cls)
1297 {
1298 struct objc_method_list **ptr;
1299
1300 if (!cls->methodLists) return NULL;
1301 if (cls->info & CLS_NO_METHOD_ARRAY) return (struct objc_method_list *)cls->methodLists;
1302 ptr = cls->methodLists;
1303 if (!*ptr || *ptr == END_OF_METHODS_LIST) return NULL;
1304 while ( *ptr != 0 && *ptr != END_OF_METHODS_LIST ) { ptr++; }
1305 --ptr;
1306 return *ptr;
1307 }
1308
1309
1310 /***********************************************************************
1311 * add_class_to_loadable_list
1312 * Class cls has just become connected. Schedule it for +load if
1313 * it implements a +load method.
1314 **********************************************************************/
1315 static void add_class_to_loadable_list(struct objc_class *cls)
1316 {
1317 IMP method = NULL;
1318 struct objc_method_list *mlist;
1319
1320 if (cls->isa->info & CLS_HAS_LOAD_METHOD) {
1321 mlist = get_base_method_list(cls->isa);
1322 if (mlist) {
1323 method = lookupNamedMethodInMethodList (mlist, "load");
1324 }
1325 }
1326 // Don't bother if cls has no +load method
1327 if (!method) return;
1328
1329 if (PrintLoading) {
1330 _objc_inform("LOAD: class '%s' scheduled for +load", cls->name);
1331 }
1332
1333 if (loadable_classes_used == loadable_classes_allocated) {
1334 loadable_classes_allocated = loadable_classes_allocated*2 + 16;
1335 loadable_classes =
1336 _realloc_internal(loadable_classes,
1337 loadable_classes_allocated *
1338 sizeof(struct loadable_class));
1339 }
1340
1341 loadable_classes[loadable_classes_used].cls = cls;
1342 loadable_classes[loadable_classes_used].method = method;
1343 loadable_classes_used++;
1344 }
1345
1346
1347 /***********************************************************************
1348 * add_category_to_loadable_list
1349 * Category cat's parent class exists and the category has been attached
1350 * to its class. Schedule this category for +load after its parent class
1351 * becomes connected and has its own +load method called.
1352 **********************************************************************/
1353 static void add_category_to_loadable_list(struct objc_category *cat)
1354 {
1355 IMP method = NULL;
1356 struct objc_method_list *mlist;
1357
1358 mlist = cat->class_methods;
1359 if (mlist) {
1360 method = lookupNamedMethodInMethodList (mlist, "load");
1361 }
1362 // Don't bother if cat has no +load method
1363 if (!method) return;
1364
1365 if (PrintLoading) {
1366 _objc_inform("LOAD: category '%s(%s)' scheduled for +load",
1367 cat->class_name, cat->category_name);
1368 }
1369
1370 if (loadable_categories_used == loadable_categories_allocated) {
1371 loadable_categories_allocated = loadable_categories_allocated*2 + 16;
1372 loadable_categories =
1373 _realloc_internal(loadable_categories,
1374 loadable_categories_allocated *
1375 sizeof(struct loadable_category));
1376 }
1377
1378 loadable_categories[loadable_categories_used].cat = cat;
1379 loadable_categories[loadable_categories_used].method = method;
1380 loadable_categories_used++;
1381 }
1382
1383
1384 /***********************************************************************
1385 * remove_class_from_loadable_list
1386 * Class cls may have been loadable before, but it is now no longer
1387 * loadable (because its image is being unmapped).
1388 **********************************************************************/
1389 static void remove_class_from_loadable_list(struct objc_class *cls)
1390 {
1391 if (loadable_classes) {
1392 int i;
1393 for (i = 0; i < loadable_classes_used; i++) {
1394 if (loadable_classes[i].cls == cls) {
1395 loadable_classes[i].cls = NULL;
1396 if (PrintLoading) {
1397 _objc_inform("LOAD: class '%s' unscheduled for +load", cls->name);
1398 }
1399 return;
1400 }
1401 }
1402 }
1403 }
1404
1405
1406 /***********************************************************************
1407 * remove_category_from_loadable_list
1408 * Category cat may have been loadable before, but it is now no longer
1409 * loadable (because its image is being unmapped).
1410 **********************************************************************/
1411 static void remove_category_from_loadable_list(struct objc_category *cat)
1412 {
1413 if (loadable_categories) {
1414 int i;
1415 for (i = 0; i < loadable_categories_used; i++) {
1416 if (loadable_categories[i].cat == cat) {
1417 loadable_categories[i].cat = NULL;
1418 if (PrintLoading) {
1419 _objc_inform("LOAD: category '%s(%s)' unscheduled for +load",
1420 cat->class_name, cat->category_name);
1421 }
1422 return;
1423 }
1424 }
1425 }
1426 }
1427
1428
1429 /***********************************************************************
1430 * call_class_loads
1431 * Call all pending class +load methods.
1432 * If new classes become loadable, +load is NOT called for them.
1433 *
1434 * Called only by call_load_methods().
1435 **********************************************************************/
1436 static void call_class_loads(void)
1437 {
1438 int i;
1439
1440 // Detach current loadable list.
1441 struct loadable_class *classes = loadable_classes;
1442 int used = loadable_classes_used;
1443 loadable_classes = NULL;
1444 loadable_classes_allocated = 0;
1445 loadable_classes_used = 0;
1446
1447 // Call all +loads for the detached list.
1448 for (i = 0; i < used; i++) {
1449 struct objc_class *cls = classes[i].cls;
1450 IMP load_method = classes[i].method;
1451 if (!cls) continue;
1452
1453 if (PrintLoading) {
1454 _objc_inform("LOAD: +[%s load]\n", cls->name);
1455 }
1456 (*load_method) ((id) cls, @selector(load));
1457 }
1458
1459 // Destroy the detached list.
1460 if (classes) _free_internal(classes);
1461 }
1462
1463
1464 /***********************************************************************
1465 * call_category_loads
1466 * Call some pending category +load methods.
1467 * The parent class of the +load-implementing categories has all of
1468 * its categories attached, in case some are lazily waiting for +initalize.
1469 * Don't call +load unless the parent class is connected.
1470 * If new categories become loadable, +load is NOT called, and they
1471 * are added to the end of the loadable list, and we return TRUE.
1472 * Return FALSE if no new categories became loadable.
1473 *
1474 * Called only by call_load_methods().
1475 **********************************************************************/
1476 static BOOL call_category_loads(void)
1477 {
1478 int i, shift;
1479 BOOL new_categories_added = NO;
1480
1481 // Detach current loadable list.
1482 struct loadable_category *cats = loadable_categories;
1483 int used = loadable_categories_used;
1484 int allocated = loadable_categories_allocated;
1485 loadable_categories = NULL;
1486 loadable_categories_allocated = 0;
1487 loadable_categories_used = 0;
1488
1489 // Call all +loads for the detached list.
1490 for (i = 0; i < used; i++) {
1491 struct objc_category *cat = cats[i].cat;
1492 IMP load_method = cats[i].method;
1493 struct objc_class *cls;
1494 if (!cat) continue;
1495
1496 cls = objc_getClass(cat->class_name);
1497 if (cls && class_is_connected(cls)) {
1498 if (PrintLoading) {
1499 _objc_inform("LOAD: +[%s(%s) load]\n",
1500 cls->name, cat->category_name);
1501 }
1502 (*load_method) ((id) cls, @selector(load));
1503 cats[i].cat = NULL;
1504 }
1505 }
1506
1507 // Compact detached list (order-preserving)
1508 shift = 0;
1509 for (i = 0; i < used; i++) {
1510 if (cats[i].cat) {
1511 cats[i-shift] = cats[i];
1512 } else {
1513 shift++;
1514 }
1515 }
1516 used -= shift;
1517
1518 // Copy any new +load candidates from the new list to the detached list.
1519 new_categories_added = (loadable_categories_used > 0);
1520 for (i = 0; i < loadable_categories_used; i++) {
1521 if (used == allocated) {
1522 allocated = allocated*2 + 16;
1523 cats = _realloc_internal(cats, allocated *
1524 sizeof(struct loadable_category));
1525 }
1526 cats[used++] = loadable_categories[i];
1527 }
1528
1529 // Destroy the new list.
1530 if (loadable_categories) _free_internal(loadable_categories);
1531
1532 // Reattach the (now augmented) detached list.
1533 // But if there's nothing left to load, destroy the list.
1534 if (used) {
1535 loadable_categories = cats;
1536 loadable_categories_used = used;
1537 loadable_categories_allocated = allocated;
1538 } else {
1539 if (cats) _free_internal(cats);
1540 loadable_categories = NULL;
1541 loadable_categories_used = 0;
1542 loadable_categories_allocated = 0;
1543 }
1544
1545 if (PrintLoading) {
1546 if (loadable_categories_used != 0) {
1547 _objc_inform("LOAD: %d categories still waiting for +load\n",
1548 loadable_categories_used);
1549 }
1550 }
1551
1552 return new_categories_added;
1553 }
1554
1555
1556 /***********************************************************************
1557 * call_load_methods
1558 * Call all pending class and category +load methods.
1559 * Class +load methods are called superclass-first.
1560 * Category +load methods are not called until after the parent class's +load.
1561 *
1562 * This method must be RE-ENTRANT, because a +load could trigger
1563 * more image mapping. In addition, the superclass-first ordering
1564 * must be preserved in the face of re-entrant calls. Therefore,
1565 * only the OUTERMOST call of this function will do anything, and
1566 * that call will handle all loadable classes, even those generated
1567 * while it was running.
1568 *
1569 * The sequence below preserves +load ordering in the face of
1570 * image loading during a +load, and make sure that no
1571 * +load method is forgotten because it was added during
1572 * a +load call.
1573 * Sequence:
1574 * 1. Repeatedly call class +loads until there aren't any more
1575 * 2. Call category +loads ONCE.
1576 * 3. Run more +loads if:
1577 * (a) there are more classes to load, OR
1578 * (b) there are some potential category +loads that have
1579 * still never been attempted.
1580 * Category +loads are only run once to ensure "parent class first"
1581 * ordering, even if a category +load triggers a new loadable class
1582 * and a new loadable category attached to that class.
1583 *
1584 * fixme this is not thread-safe, but neither is the rest of image mapping.
1585 **********************************************************************/
1586 static void call_load_methods(void)
1587 {
1588 static pthread_t load_method_thread NOBSS = NULL;
1589 BOOL more_categories;
1590
1591 if (load_method_thread) {
1592 // +loads are already being called. Do nothing, but complain
1593 // if it looks like multithreaded use of this thread-unsafe code.
1594
1595 if (! pthread_equal(load_method_thread, pthread_self())) {
1596 _objc_inform("WARNING: multi-threaded library loading detected "
1597 "(implementation is not thread-safe)");
1598 }
1599 return;
1600 }
1601
1602 // Nobody else is calling +loads, so we should do it ourselves.
1603 load_method_thread = pthread_self();
1604
1605 do {
1606 // 1. Repeatedly call class +loads until there aren't any more
1607 while (loadable_classes_used > 0) {
1608 call_class_loads();
1609 }
1610
1611 // 2. Call category +loads ONCE
1612 more_categories = call_category_loads();
1613
1614 // 3. Run more +loads if there are classes OR more untried categories
1615 } while (loadable_classes_used > 0 || more_categories);
1616
1617 load_method_thread = NULL;
1618 }
1619
1620
1621 /***********************************************************************
1622 * really_connect_class
1623 * Connect cls to superclass supercls unconditionally.
1624 * Also adjust the class hash tables and handle +load and pended subclasses.
1625 *
1626 * This should be called from connect_class() ONLY.
1627 **********************************************************************/
1628 static void really_connect_class(struct objc_class *cls,
1629 struct objc_class *supercls)
1630 {
1631 struct objc_class *oldCls;
1632 struct objc_class *meta = cls->isa;
1633
1634 // Wire the classes together.
1635 if (supercls) {
1636 cls->super_class = supercls;
1637 meta->super_class = supercls->isa;
1638 meta->isa = supercls->isa->isa;
1639 } else {
1640 cls->super_class = NULL; // superclass of root class is NULL
1641 meta->super_class = cls; // superclass of root metaclass is root class
1642 meta->isa = meta; // metaclass of root metaclass is root metaclass
1643 }
1644
1645 OBJC_LOCK(&classLock);
1646
1647 // Update hash tables.
1648 NXHashRemove(unconnected_class_hash, cls);
1649 oldCls = NXHashInsert(class_hash, cls);
1650
1651 // Delete unconnected_class_hash if it is now empty.
1652 if (NXCountHashTable(unconnected_class_hash) == 0) {
1653 NXFreeHashTable(unconnected_class_hash);
1654 unconnected_class_hash = NULL;
1655 }
1656
1657 OBJC_UNLOCK(&classLock);
1658
1659 // Warn if the new class has the same name as a previously-installed class.
1660 // The new class is kept and the old class is discarded.
1661 if (oldCls) {
1662 const header_info *oldHeader = _headerForClass(oldCls);
1663 const header_info *newHeader = _headerForClass(cls);
1664 const char *oldName = _nameForHeader(oldHeader->mhdr);
1665 const char *newName = _nameForHeader(newHeader->mhdr);
1666
1667 _objc_inform ("Both %s and %s have implementations of class %s.",
1668 oldName, newName, oldCls->name);
1669 _objc_inform ("Using implementation from %s.", newName);
1670 }
1671
1672 // Prepare for +load and connect newly-connectable subclasses
1673 add_class_to_loadable_list(cls);
1674 resolve_subclasses_of_class(cls);
1675
1676 // GC debugging: make sure all classes with -dealloc also have -finalize
1677 if (CheckFinalizers) {
1678 extern IMP findIMPInClass(Class cls, SEL sel);
1679 if (findIMPInClass(cls, sel_getUid("dealloc")) &&
1680 ! findIMPInClass(cls, sel_getUid("finalize")))
1681 {
1682 _objc_inform("GC: class '%s' implements -dealloc but not -finalize", cls->name);
1683 }
1684 }
1685
1686 // Debugging: if this class has ivars, make sure this class's ivars don't
1687 // overlap with its super's. This catches some broken fragile base classes.
1688 // Do not use super->instance_size vs. self->ivar[0] to check this.
1689 // Ivars may be packed across instance_size boundaries.
1690 if (DebugFragileSuperclasses && cls->ivars && cls->ivars->ivar_count) {
1691 struct objc_class *ivar_cls = supercls;
1692
1693 // Find closest superclass that has some ivars, if one exists.
1694 while (ivar_cls &&
1695 (!ivar_cls->ivars || ivar_cls->ivars->ivar_count == 0))
1696 {
1697 ivar_cls = ivar_cls->super_class;
1698 }
1699
1700 if (ivar_cls) {
1701 // Compare superclass's last ivar to this class's first ivar
1702 struct objc_ivar *super_ivar =
1703 &ivar_cls->ivars->ivar_list[ivar_cls->ivars->ivar_count - 1];
1704 struct objc_ivar *self_ivar =
1705 &cls->ivars->ivar_list[0];
1706
1707 // fixme could be smarter about super's ivar size
1708 if (self_ivar->ivar_offset <= super_ivar->ivar_offset) {
1709 _objc_inform("WARNING: ivars of superclass '%s' and "
1710 "subclass '%s' overlap; superclass may have "
1711 "changed since subclass was compiled",
1712 ivar_cls->name, cls->name);
1713 }
1714 }
1715 }
1716 }
1717
1718
1719 /***********************************************************************
1720 * connect_class
1721 * Connect class cls to its superclasses, if possible.
1722 * If cls becomes connected, move it from unconnected_class_hash
1723 * to connected_class_hash.
1724 * Returns TRUE if cls is connected.
1725 * Returns FALSE if cls could not be connected for some reason
1726 * (missing superclass or still-unconnected superclass)
1727 **********************************************************************/
1728 static BOOL connect_class(struct objc_class *cls)
1729 {
1730 if (class_is_connected(cls)) {
1731 // This class is already connected to its superclass.
1732 // Do nothing.
1733 return TRUE;
1734 }
1735 else if (cls->super_class == NULL) {
1736 // This class is a root class.
1737 // Connect it to itself.
1738
1739 if (PrintConnecting) {
1740 _objc_inform("CONNECT: class '%s' now connected (root class)",
1741 cls->name);
1742 }
1743
1744 really_connect_class(cls, NULL);
1745 return TRUE;
1746 }
1747 else {
1748 // This class is not a root class and is not yet connected.
1749 // Connect it if its superclass and root class are already connected.
1750 // Otherwise, add this class to the to-be-connected list,
1751 // pending the completion of its superclass and root class.
1752
1753 // At this point, cls->super_class and cls->isa->isa are still STRINGS
1754 char *supercls_name = (char *)cls->super_class;
1755 struct objc_class *supercls;
1756
1757 // YES unconnected, YES class handler
1758 if (NULL == (supercls = look_up_class(supercls_name, YES, YES))) {
1759 // Superclass does not exist yet.
1760 // pendClassInstallation will handle duplicate pends of this class
1761 pendClassInstallation(cls, supercls_name);
1762
1763 if (PrintConnecting) {
1764 _objc_inform("CONNECT: class '%s' NOT connected (missing super)", cls->name);
1765 }
1766 return FALSE;
1767 }
1768
1769 if (! connect_class(supercls)) {
1770 // Superclass exists but is not yet connected.
1771 // pendClassInstallation will handle duplicate pends of this class
1772 pendClassInstallation(cls, supercls_name);
1773
1774 if (PrintConnecting) {
1775 _objc_inform("CONNECT: class '%s' NOT connected (unconnected super)", cls->name);
1776 }
1777 return FALSE;
1778 }
1779
1780 // Superclass exists and is connected.
1781 // Connect this class to the superclass.
1782
1783 if (PrintConnecting) {
1784 _objc_inform("CONNECT: class '%s' now connected", cls->name);
1785 }
1786
1787 really_connect_class(cls, supercls);
1788 return TRUE;
1789 }
1790 }
1791
1792
1793 /***********************************************************************
1794 * _objc_read_classes_from_image.
1795 * Read classes from the given image, perform assorted minor fixups,
1796 * scan for +load implementation.
1797 * Does not connect classes to superclasses.
1798 * Does attach pended categories to the classes.
1799 * Adds all classes to unconnected_class_hash. class_hash is unchanged.
1800 **********************************************************************/
1801 static void _objc_read_classes_from_image(header_info *hi)
1802 {
1803 unsigned int index;
1804 unsigned int midx;
1805 Module mods;
1806 int isBundle = (hi->mhdr->filetype == MH_BUNDLE);
1807
1808 if (_objcHeaderIsReplacement(hi)) {
1809 // Ignore any classes in this image
1810 return;
1811 }
1812
1813 // class_hash starts small, enough only for libobjc itself.
1814 // If other Objective-C libraries are found, immediately resize
1815 // class_hash, assuming that Foundation and AppKit are about
1816 // to add lots of classes.
1817 OBJC_LOCK(&classLock);
1818 if (hi->mhdr != &_mh_dylib_header && _NXHashCapacity(class_hash) < 1024) {
1819 _NXHashRehashToCapacity(class_hash, 1024);
1820 }
1821 OBJC_UNLOCK(&classLock);
1822
1823 // Major loop - process all modules in the image
1824 mods = hi->mod_ptr;
1825 for (midx = 0; midx < hi->mod_count; midx += 1)
1826 {
1827 // Skip module containing no classes
1828 if (mods[midx].symtab == NULL)
1829 continue;
1830
1831 // Minor loop - process all the classes in given module
1832 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1833 {
1834 struct objc_class * newCls;
1835 struct objc_method_list *mlist;
1836
1837 // Locate the class description pointer
1838 newCls = mods[midx].symtab->defs[index];
1839
1840 // Classes loaded from Mach-O bundles can be unloaded later.
1841 // Nothing uses this class yet, so _class_setInfo is not needed.
1842 if (isBundle) newCls->info |= CLS_FROM_BUNDLE;
1843 if (isBundle) newCls->isa->info |= CLS_FROM_BUNDLE;
1844
1845 // Use common static empty cache instead of NULL
1846 if (newCls->cache == NULL)
1847 newCls->cache = (Cache) &emptyCache;
1848 if (newCls->isa->cache == NULL)
1849 newCls->isa->cache = (Cache) &emptyCache;
1850
1851 // Set metaclass version
1852 newCls->isa->version = mods[midx].version;
1853
1854 // methodLists is NULL or a single list, not an array
1855 newCls->info |= CLS_NO_METHOD_ARRAY;
1856 newCls->isa->info |= CLS_NO_METHOD_ARRAY;
1857
1858 // Check for +load implementation before categories are attached
1859 if ((mlist = get_base_method_list(newCls->isa))) {
1860 if (lookupNamedMethodInMethodList (mlist, "load")) {
1861 newCls->isa->info |= CLS_HAS_LOAD_METHOD;
1862 }
1863 }
1864
1865 // Install into unconnected_class_hash
1866 OBJC_LOCK(&classLock);
1867 if (!unconnected_class_hash) {
1868 unconnected_class_hash =
1869 NXCreateHashTableFromZone(classHashPrototype, 128, NULL,
1870 _objc_internal_zone());
1871 }
1872 NXHashInsert(unconnected_class_hash, newCls);
1873 OBJC_UNLOCK(&classLock);
1874
1875 // Fix up pended class refs to this class, if any
1876 resolve_references_to_class(newCls);
1877
1878 // Attach pended categories for this class, if any
1879 resolve_categories_for_class(newCls);
1880 }
1881 }
1882 }
1883
1884
1885 /***********************************************************************
1886 * _objc_connect_classes_from_image.
1887 * Connect the classes in the given image to their superclasses,
1888 * or register them for later connection if any superclasses are missing.
1889 **********************************************************************/
1890 static void _objc_connect_classes_from_image(header_info *hi)
1891 {
1892 unsigned int index;
1893 unsigned int midx;
1894 Module mods;
1895 BOOL replacement = _objcHeaderIsReplacement(hi);
1896
1897 // Major loop - process all modules in the image
1898 mods = hi->mod_ptr;
1899 for (midx = 0; midx < hi->mod_count; midx += 1)
1900 {
1901 // Skip module containing no classes
1902 if (mods[midx].symtab == NULL)
1903 continue;
1904
1905 // Minor loop - process all the classes in given module
1906 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
1907 {
1908 struct objc_class *cls = mods[midx].symtab->defs[index];
1909 if (! replacement) {
1910 BOOL connected = connect_class(cls);
1911 if (connected && callbackFunction) {
1912 (*callbackFunction)(cls, 0);
1913 }
1914 } else {
1915 // Replacement image - fix up super_class only (#3704817)
1916 const char *super_name = (const char *) cls->super_class;
1917 if (super_name) cls->super_class = objc_getClass(super_name);
1918 }
1919 }
1920 }
1921 }
1922
1923
1924 /***********************************************************************
1925 * _objc_map_class_refs_for_image. Convert the class ref entries from
1926 * a class name string pointer to a class pointer. If the class does
1927 * not yet exist, the reference is added to a list of pending references
1928 * to be fixed up at a later date.
1929 **********************************************************************/
1930 static void _objc_map_class_refs_for_image (header_info * hi)
1931 {
1932 struct objc_class * * cls_refs;
1933 unsigned int size;
1934 unsigned int index;
1935
1936 // Locate class refs in image
1937 cls_refs = _getObjcClassRefs ((headerType *) hi->mhdr, &size);
1938 if (!cls_refs)
1939 return;
1940 cls_refs = (struct objc_class * *) ((unsigned long) cls_refs + hi->image_slide);
1941
1942 // Process each class ref
1943 for (index = 0; index < size; index += 1)
1944 {
1945 const char * ref;
1946 struct objc_class * cls;
1947
1948 // Get ref to convert from name string to class pointer
1949 ref = (const char *) cls_refs[index];
1950
1951 // Get pointer to class of this name
1952 // YES unconnected, YES class loader
1953 cls = look_up_class(ref, YES, YES);
1954 if (cls) {
1955 // Referenced class exists. Fix up the reference.
1956 cls_refs[index] = cls;
1957 } else {
1958 // Referenced class does not exist yet. Insert a placeholder
1959 // class and fix up the reference later.
1960 pendClassReference (&cls_refs[index], ref);
1961 cls_refs[index] = _objc_getNonexistentClass ();
1962 }
1963 }
1964 }
1965
1966
1967 /***********************************************************************
1968 * _objc_remove_pending_class_refs_in_image
1969 * Delete any pending class ref fixups for class refs in the given image,
1970 * because the image is about to be unloaded.
1971 **********************************************************************/
1972 static void _objc_remove_pending_class_refs_in_image(header_info *hi)
1973 {
1974 struct objc_class **cls_refs, **cls_refs_end;
1975 unsigned int size;
1976
1977 if (!pendingClassRefsMap) return;
1978
1979 // Locate class refs in this image
1980 cls_refs = _getObjcClassRefs ((headerType *) hi->mhdr, &size);
1981 if (!cls_refs)
1982 return;
1983 cls_refs = (struct objc_class **) ((uintptr_t)cls_refs + hi->image_slide);
1984 cls_refs_end = (struct objc_class **)(size + (uintptr_t)cls_refs);
1985
1986 // Search the pending class ref table for class refs in this range.
1987 // The class refs may have already been stomped with nonexistentClass,
1988 // so there's no way to recover the original class name.
1989
1990 const char *key;
1991 PendingClassRef *pending;
1992 NXMapState state = NXInitMapState(pendingClassRefsMap);
1993 while(NXNextMapState(pendingClassRefsMap, &state,
1994 (const void **)&key, (const void **)&pending))
1995 {
1996 for ( ; pending != NULL; pending = pending->next) {
1997 if (pending->ref >= cls_refs && pending->ref < cls_refs_end) {
1998 pending->ref = NULL;
1999 }
2000 }
2001 }
2002 }
2003
2004
2005 /***********************************************************************
2006 * map_selrefs. Register each selector in the specified array. If a
2007 * given selector is already registered, update this array to point to
2008 * the registered selector string.
2009 * If copy is TRUE, all selector data is always copied. This is used
2010 * for registering selectors from unloadable bundles, so the selector
2011 * can still be used after the bundle's data segment is unmapped.
2012 * Returns YES if dst was written to, NO if it was unchanged.
2013 **********************************************************************/
2014 static inline BOOL map_selrefs(SEL *src, SEL *dst, size_t size, BOOL copy)
2015 {
2016 BOOL result = NO;
2017 unsigned int cnt = size / sizeof(SEL);
2018 unsigned int index;
2019
2020 sel_lock();
2021
2022 // Process each selector
2023 for (index = 0; index < cnt; index += 1)
2024 {
2025 SEL sel;
2026
2027 // Lookup pointer to uniqued string
2028 sel = sel_registerNameNoLock((const char *) src[index], copy);
2029
2030 // Replace this selector with uniqued one (avoid
2031 // modifying the VM page if this would be a NOP)
2032 if (dst[index] != sel) {
2033 dst[index] = sel;
2034 result = YES;
2035 }
2036 }
2037
2038 sel_unlock();
2039
2040 return result;
2041 }
2042
2043
2044 /***********************************************************************
2045 * map_method_descs. For each method in the specified method list,
2046 * replace the name pointer with a uniqued selector.
2047 * If copy is TRUE, all selector data is always copied. This is used
2048 * for registering selectors from unloadable bundles, so the selector
2049 * can still be used after the bundle's data segment is unmapped.
2050 **********************************************************************/
2051 static void map_method_descs (struct objc_method_description_list * methods, BOOL copy)
2052 {
2053 unsigned int index;
2054
2055 sel_lock();
2056
2057 // Process each method
2058 for (index = 0; index < methods->count; index += 1)
2059 {
2060 struct objc_method_description * method;
2061 SEL sel;
2062
2063 // Get method entry to fix up
2064 method = &methods->list[index];
2065
2066 // Lookup pointer to uniqued string
2067 sel = sel_registerNameNoLock((const char *) method->name, copy);
2068
2069 // Replace this selector with uniqued one (avoid
2070 // modifying the VM page if this would be a NOP)
2071 if (method->name != sel)
2072 method->name = sel;
2073 }
2074
2075 sel_unlock();
2076 }
2077
2078 /***********************************************************************
2079 * _fixup.
2080 **********************************************************************/
2081 @interface Protocol(RuntimePrivate)
2082 + _fixup: (OBJC_PROTOCOL_PTR)protos numElements: (int) nentries;
2083 @end
2084
2085 /***********************************************************************
2086 * _objc_fixup_protocol_objects_for_image. For each protocol in the
2087 * specified image, selectorize the method names and call +_fixup.
2088 **********************************************************************/
2089 static void _objc_fixup_protocol_objects_for_image (header_info * hi)
2090 {
2091 unsigned int size;
2092 OBJC_PROTOCOL_PTR protos;
2093 unsigned int index;
2094 int isBundle = hi->mhdr->filetype == MH_BUNDLE;
2095
2096 // Locate protocols in the image
2097 protos = (OBJC_PROTOCOL_PTR) _getObjcProtocols ((headerType *) hi->mhdr, &size);
2098 if (!protos)
2099 return;
2100
2101 // Apply the slide bias
2102 protos = (OBJC_PROTOCOL_PTR) ((unsigned long) protos + hi->image_slide);
2103
2104 // Process each protocol
2105 for (index = 0; index < size; index += 1)
2106 {
2107 // Selectorize the instance methods
2108 if (protos[index] OBJC_PROTOCOL_DEREF instance_methods)
2109 map_method_descs (protos[index] OBJC_PROTOCOL_DEREF instance_methods, isBundle);
2110
2111 // Selectorize the class methods
2112 if (protos[index] OBJC_PROTOCOL_DEREF class_methods)
2113 map_method_descs (protos[index] OBJC_PROTOCOL_DEREF class_methods, isBundle);
2114 }
2115
2116 // Invoke Protocol class method to fix up the protocol
2117 [Protocol _fixup:(OBJC_PROTOCOL_PTR)protos numElements:size];
2118 }
2119
2120 /***********************************************************************
2121 * _objc_headerStart. Return what headers we know about.
2122 **********************************************************************/
2123 header_info * _objc_headerStart ()
2124 {
2125
2126 // Take advatage of our previous work
2127 return FirstHeader;
2128 }
2129
2130 void _objc_bindModuleContainingList() {
2131 /* We define this for backwards binary compat with things which should not
2132 * have been using it (cough OmniWeb), but now it does nothing for them.
2133 */
2134 }
2135
2136
2137 /***********************************************************************
2138 * _objc_addHeader.
2139 **********************************************************************/
2140
2141 // tested with 2; typical case is 4, but OmniWeb & Mail push it towards 20
2142 #define HINFO_SIZE 16
2143
2144 static int HeaderInfoCounter NOBSS = 0;
2145 static header_info HeaderInfoTable[HINFO_SIZE] NOBSS = { {0} };
2146
2147 static header_info * _objc_addHeader(const struct mach_header *header)
2148 {
2149 int mod_count = 0;
2150 uintptr_t mod_unslid;
2151 uint32_t info_size = 0;
2152 uintptr_t image_info_unslid;
2153 const struct segment_command *objc_segment;
2154 ptrdiff_t slide;
2155 header_info *result;
2156
2157 // Locate the __OBJC segment
2158 objc_segment = getsegbynamefromheader(header, SEG_OBJC);
2159 if (!objc_segment) return NULL;
2160
2161 // Locate some sections in the __OBJC segment
2162 mod_unslid = (uintptr_t)_getObjcModules(header, &mod_count);
2163 if (!mod_unslid) return NULL;
2164 image_info_unslid = (uintptr_t)_getObjcImageInfo(header, &info_size);
2165
2166 // Calculate vm slide.
2167 slide = _getImageSlide(header);
2168
2169
2170 // Find or allocate a header_info entry.
2171 if (HeaderInfoCounter < HINFO_SIZE) {
2172 result = &HeaderInfoTable[HeaderInfoCounter++];
2173 } else {
2174 result = _malloc_internal(sizeof(header_info));
2175 }
2176
2177 // Set up the new header_info entry.
2178 result->mhdr = header;
2179 result->mod_ptr = (Module)(mod_unslid + slide);
2180 result->mod_count = mod_count;
2181 result->image_slide = slide;
2182 result->objcSegmentHeader = objc_segment;
2183 if (image_info_unslid) {
2184 result->info = (objc_image_info *)(image_info_unslid + slide);
2185 } else {
2186 result->info = NULL;
2187 }
2188
2189 // Make sure every copy of objc_image_info in this image is the same.
2190 // This means same version and same bitwise contents.
2191 if (result->info) {
2192 objc_image_info *start = result->info;
2193 objc_image_info *end =
2194 (objc_image_info *)(info_size + (uint8_t *)start);
2195 objc_image_info *info = start;
2196 while (info < end) {
2197 // version is byte size, except for version 0
2198 size_t struct_size = info->version;
2199 if (struct_size == 0) struct_size = 2 * sizeof(uint32_t);
2200 if (info->version != start->version ||
2201 0 != memcmp(info, start, struct_size))
2202 {
2203 _objc_fatal("'%s' has inconsistently-compiled Objective-C "
2204 "code. Please recompile all code in it.",
2205 _nameForHeader(header));
2206 }
2207 info = (objc_image_info *)(struct_size + (uint8_t *)info);
2208 }
2209 }
2210
2211 // Add the header to the header list.
2212 // The header is appended to the list, to preserve the bottom-up order.
2213 result->next = NULL;
2214 if (!FirstHeader) {
2215 // list is empty
2216 FirstHeader = LastHeader = result;
2217 } else {
2218 if (!LastHeader) {
2219 // list is not empty, but LastHeader is invalid - recompute it
2220 LastHeader = FirstHeader;
2221 while (LastHeader->next) LastHeader = LastHeader->next;
2222 }
2223 // LastHeader is now valid
2224 LastHeader->next = result;
2225 LastHeader = result;
2226 }
2227
2228 return result;
2229 }
2230
2231
2232 /***********************************************************************
2233 * _objc_RemoveHeader
2234 * Remove the given header from the header list.
2235 * FirstHeader is updated.
2236 * LastHeader is set to NULL. Any code that uses LastHeader must
2237 * detect this NULL and recompute LastHeader by traversing the list.
2238 **********************************************************************/
2239 static void _objc_removeHeader(header_info *hi)
2240 {
2241 header_info **hiP;
2242
2243 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
2244 if (*hiP == hi) {
2245 header_info *deadHead = *hiP;
2246
2247 // Remove from the linked list (updating FirstHeader if necessary).
2248 *hiP = (**hiP).next;
2249
2250 // Update LastHeader if necessary.
2251 if (LastHeader == deadHead) {
2252 LastHeader = NULL; // will be recomputed next time it's used
2253 }
2254
2255 // Free the memory, unless it was in the static HeaderInfoTable.
2256 if (deadHead < HeaderInfoTable ||
2257 deadHead >= HeaderInfoTable + HINFO_SIZE)
2258 {
2259 _free_internal(deadHead);
2260 }
2261
2262 break;
2263 }
2264 }
2265 }
2266
2267
2268 /***********************************************************************
2269 * check_gc
2270 * Check whether the executable supports or requires GC, and make sure
2271 * all already-loaded libraries support the executable's GC mode.
2272 * Returns TRUE if the executable wants GC on.
2273 **********************************************************************/
2274 static BOOL check_wants_gc(void)
2275 {
2276 // GC is off in Tiger.
2277 return NO;
2278 /*
2279 const header_info *hi;
2280 BOOL appWantsGC;
2281
2282 // Environment variables can override the following.
2283 if (ForceGC) {
2284 _objc_inform("GC: forcing GC ON because OBJC_FORCE_GC is set");
2285 appWantsGC = YES;
2286 }
2287 else if (ForceNoGC) {
2288 _objc_inform("GC: forcing GC OFF because OBJC_FORCE_NO_GC is set");
2289 appWantsGC = NO;
2290 }
2291 else {
2292 // Find the executable and check its GC bits.
2293 // If the executable cannot be found, default to NO.
2294 // (The executable will not be found if the executable contains
2295 // no Objective-C code.)
2296 appWantsGC = NO;
2297 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
2298 if (hi->mhdr->filetype == MH_EXECUTE) {
2299 appWantsGC = _objcHeaderSupportsGC(hi) ? YES : NO;
2300 if (PrintGC) {
2301 _objc_inform("GC: executable '%s' %s GC",
2302 _nameForHeader(hi->mhdr),
2303 appWantsGC ? "supports" : "does not support");
2304 }
2305 }
2306 }
2307 }
2308 return appWantsGC;
2309 */
2310 }
2311
2312 /***********************************************************************
2313 * verify_gc_readiness
2314 * if we want gc, verify that every header describes files compiled
2315 * and presumably ready for gc.
2316 ************************************************************************/
2317
2318 static void verify_gc_readiness(BOOL wantsGC, header_info *hi)
2319 {
2320 BOOL busted = NO;
2321
2322 // Find the libraries and check their GC bits against the app's request
2323 for (; hi != NULL; hi = hi->next) {
2324 if (hi->mhdr->filetype == MH_EXECUTE) {
2325 continue;
2326 }
2327 else if (hi->mhdr == &_mh_dylib_header) {
2328 // libobjc itself works with anything even though it is not
2329 // compiled with -fobjc-gc (fixme should it be?)
2330 }
2331 else if (wantsGC && ! _objcHeaderSupportsGC(hi)) {
2332 // App wants GC but library does not support it - bad
2333 _objc_inform("'%s' was not compiled with -fobjc-gc, but "
2334 "the application requires GC",
2335 _nameForHeader(hi->mhdr));
2336 busted = YES;
2337 }
2338
2339 if (PrintGC) {
2340 _objc_inform("GC: library '%s' %s GC", _nameForHeader(hi->mhdr),
2341 _objcHeaderSupportsGC(hi) ? "supports" : "does not support");
2342 }
2343 }
2344
2345 if (busted) {
2346 // GC state is not consistent.
2347 // Kill the process unless one of the forcing flags is set.
2348 if (!ForceGC && !ForceNoGC) {
2349 _objc_fatal("*** GC capability of application and some libraries did not match");
2350 }
2351 }
2352 }
2353
2354
2355 /***********************************************************************
2356 * _objc_fixup_selector_refs. Register all of the selectors in each
2357 * image, and fix them all up.
2358 *
2359 * If the image is a dylib (not a bundle or an executable), and contains
2360 * at least one full aligned page of selector refs, this function uses
2361 * the shared range functions to try to recycle already-written memory
2362 * from other processes.
2363 **********************************************************************/
2364 static void _objc_fixup_selector_refs (const header_info * hi)
2365 {
2366 unsigned int count;
2367 Module mods;
2368 vm_address_t local_sels;
2369 vm_size_t local_size;
2370
2371 mods = hi->mod_ptr;
2372
2373 // Fix up message refs
2374 local_sels = (vm_address_t) _getObjcMessageRefs ((headerType *) hi->mhdr, &count);
2375 local_size = count * sizeof(SEL);
2376
2377 if (local_sels) {
2378 vm_address_t aligned_start, aligned_end;
2379
2380 local_sels = local_sels + hi->image_slide;
2381 aligned_start = round_page(local_sels);
2382 aligned_end = trunc_page(local_sels + local_size);
2383
2384 if (aligned_start >= aligned_end ||
2385 hi->mhdr->filetype == MH_BUNDLE ||
2386 hi->mhdr->filetype == MH_EXECUTE)
2387 {
2388 // Less than a page of sels, OR bundle or executable - fix in place
2389
2390 map_selrefs((SEL *)local_sels, (SEL *)local_sels, local_size,
2391 hi->mhdr->filetype == MH_BUNDLE);
2392
2393 if (PrintSharing) {
2394 _objc_inform("SHARING: NONE [%p..%p) (%d pages) for %s",
2395 local_sels, local_sels+local_size,
2396 (aligned_end > aligned_start ?
2397 (aligned_end-aligned_start) / vm_page_size : 0),
2398 _nameForHeader(hi->mhdr));
2399 }
2400 }
2401 else {
2402 // At least one page of sels - try to use sharing
2403 vm_range_t remote_range;
2404
2405 if (PrintSharing) {
2406 _objc_inform("SHARING: looking for range [%p..%p) ...",
2407 aligned_start, aligned_end);
2408 }
2409
2410 remote_range = get_shared_range(aligned_start, aligned_end);
2411
2412 if (remote_range.address != 0) {
2413 // Sharing succeeded - fix using remote_range
2414 BOOL stomped;
2415
2416 // local_sels..aligned_start (unshared)
2417 map_selrefs((SEL *)local_sels, (SEL *)local_sels,
2418 aligned_start - local_sels, NO);
2419 // aligned_start..aligned_end (shared)
2420 stomped =
2421 map_selrefs((SEL *)aligned_start, (SEL *)remote_range.address,
2422 aligned_end - aligned_start, NO);
2423 // aligned_end..local_sels+local_size (unshared)
2424 map_selrefs((SEL *)aligned_end, (SEL *)aligned_end,
2425 local_sels+local_size - aligned_end, NO);
2426
2427 install_shared_range(remote_range, aligned_start);
2428
2429 if (PrintSharing) {
2430 _objc_inform("SHARING: %s [%p..%p) (%d pages) for %s",
2431 stomped ? "TRIED" : "USING",
2432 local_sels, local_sels+local_size,
2433 (aligned_end-aligned_start) / vm_page_size,
2434 _nameForHeader(hi->mhdr));
2435 }
2436 }
2437 else {
2438 // Sharing failed, including first process -
2439 // fix in place and then offer to share
2440
2441 map_selrefs((SEL *)local_sels, (SEL *)local_sels, local_size, NO);
2442
2443 offer_shared_range(aligned_start, aligned_end);
2444
2445 if (PrintSharing) {
2446 _objc_inform("SHARING: OFFER [%p..%p) (%d pages) for %s",
2447 local_sels, local_sels+local_size,
2448 (aligned_end-aligned_start) / vm_page_size,
2449 _nameForHeader(hi->mhdr));
2450 }
2451 }
2452 }
2453 }
2454 }
2455
2456
2457 /***********************************************************************
2458 * objc_setConfiguration
2459 * Read environment variables that affect the runtime.
2460 * Also print environment variable help, if requested.
2461 **********************************************************************/
2462 static void objc_setConfiguration() {
2463 int PrintHelp = (getenv("OBJC_HELP") != NULL);
2464 int PrintOptions = (getenv("OBJC_PRINT_OPTIONS") != NULL);
2465
2466 if (PrintHelp) {
2467 _objc_inform("OBJC_HELP: describe Objective-C runtime environment variables");
2468 if (PrintOptions) {
2469 _objc_inform("OBJC_HELP is set");
2470 }
2471 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
2472 }
2473 if (PrintOptions) {
2474 _objc_inform("OBJC_PRINT_OPTIONS is set");
2475 }
2476
2477 #define OPTION(var, env, help) \
2478 if ( var == -1 ) { \
2479 var = getenv(#env) != NULL; \
2480 if (PrintHelp) _objc_inform(#env ": " help); \
2481 if (PrintOptions && var) _objc_inform(#env " is set"); \
2482 }
2483
2484 OPTION(PrintImages, OBJC_PRINT_IMAGES,
2485 "log image and library names as the runtime loads them");
2486 OPTION(PrintConnecting, OBJC_PRINT_CONNECTION,
2487 "log progress of class and category connections");
2488 OPTION(PrintLoading, OBJC_PRINT_LOAD_METHODS,
2489 "log class and category +load methods as they are called");
2490 OPTION(PrintRTP, OBJC_PRINT_RTP,
2491 "log initialization of the Objective-C runtime pages");
2492 OPTION(PrintGC, OBJC_PRINT_GC,
2493 "log some GC operations");
2494 OPTION(PrintSharing, OBJC_PRINT_SHARING,
2495 "log cross-process memory sharing");
2496 OPTION(PrintCxxCtors, OBJC_PRINT_CXX_CTORS,
2497 "log calls to C++ ctors and dtors for instance variables");
2498
2499 OPTION(DebugUnload, OBJC_DEBUG_UNLOAD,
2500 "warn about poorly-behaving bundles when unloaded");
2501 OPTION(DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES,
2502 "warn about subclasses that may have been broken by subsequent changes to superclasses");
2503
2504 OPTION(UseInternalZone, OBJC_USE_INTERNAL_ZONE,
2505 "allocate runtime data in a dedicated malloc zone");
2506 OPTION(AllowInterposing, OBJC_ALLOW_INTERPOSING,
2507 "allow function interposing of objc_msgSend()");
2508
2509 OPTION(ForceGC, OBJC_FORCE_GC,
2510 "force GC ON, even if the executable wants it off");
2511 OPTION(ForceNoGC, OBJC_FORCE_NO_GC,
2512 "force GC OFF, even if the executable wants it on");
2513 OPTION(CheckFinalizers, OBJC_CHECK_FINALIZERS,
2514 "warn about classes that implement -dealloc but not -finalize");
2515 #undef OPTION
2516 }
2517
2518
2519 /***********************************************************************
2520 * objc_setMultithreaded.
2521 **********************************************************************/
2522 void objc_setMultithreaded (BOOL flag)
2523 {
2524 // Nothing here. Thread synchronization in the runtime is always active.
2525 }
2526
2527
2528
2529 /***********************************************************************
2530 * _objc_pthread_destroyspecific
2531 * Destructor for objc's per-thread data.
2532 * arg shouldn't be NULL, but we check anyway.
2533 **********************************************************************/
2534 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
2535 void _objc_pthread_destroyspecific(void *arg)
2536 {
2537 _objc_pthread_data *data = (_objc_pthread_data *)arg;
2538 if (data != NULL) {
2539 _destroyInitializingClassList(data->initializingClasses);
2540
2541 // add further cleanup here...
2542
2543 _free_internal(data);
2544 }
2545 }
2546
2547
2548 /***********************************************************************
2549 * _objcInit
2550 * Former library initializer. This function is now merely a placeholder
2551 * for external callers. All runtime initialization has now been moved
2552 * to map_images().
2553 **********************************************************************/
2554 void _objcInit(void)
2555 {
2556 // do nothing
2557 }
2558
2559
2560 /***********************************************************************
2561 * map_images
2562 * Process the given images which are being mapped in by dyld.
2563 * All class registration and fixups are performed (or deferred pending
2564 * discovery of missing superclasses etc), and +load methods are called.
2565 *
2566 * info[] is in bottom-up order i.e. libobjc will be earlier in the
2567 * array than any library that links to libobjc.
2568 **********************************************************************/
2569 static void map_images(const struct dyld_image_info infoList[],
2570 uint32_t infoCount)
2571 {
2572 static BOOL firstTime = YES;
2573 static BOOL wantsGC NOBSS = NO;
2574 uint32_t i;
2575 header_info *firstNewHeader = NULL;
2576 header_info *hInfo;
2577
2578 // Perform first-time initialization if necessary.
2579 // This function is called before ordinary library initializers.
2580 if (firstTime) {
2581 pthread_key_create(&_objc_pthread_key, _objc_pthread_destroyspecific);
2582 objc_setConfiguration(); // read environment variables
2583 _objc_init_class_hash (); // create class_hash
2584 // grab selectors for which @selector() doesn't work
2585 cxx_construct_sel = sel_registerName(cxx_construct_name);
2586 cxx_destruct_sel = sel_registerName(cxx_destruct_name);
2587 }
2588
2589 if (PrintImages) {
2590 _objc_inform("IMAGES: processing %u newly-mapped images...\n", infoCount);
2591 }
2592
2593
2594 // Find all images with an __OBJC segment.
2595 // firstNewHeader is set the the first one, and the header_info
2596 // linked list following firstNewHeader is the rest.
2597 for (i = 0; i < infoCount; i++) {
2598 const struct mach_header *mhdr = infoList[i].imageLoadAddress;
2599
2600 hInfo = _objc_addHeader(mhdr);
2601 if (!hInfo) {
2602 // no objc data in this entry
2603 if (PrintImages) {
2604 _objc_inform("IMAGES: image '%s' contains no __OBJC segment\n",
2605 infoList[i].imageFilePath);
2606 }
2607 continue;
2608 }
2609
2610 if (!firstNewHeader) firstNewHeader = hInfo;
2611
2612 if (PrintImages) {
2613 _objc_inform("IMAGES: loading image for %s%s%s%s\n",
2614 _nameForHeader(mhdr),
2615 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
2616 _objcHeaderIsReplacement(hInfo) ? " (replacement)":"",
2617 _objcHeaderSupportsGC(hInfo) ? " (supports GC)":"");
2618 }
2619 }
2620
2621 // Perform one-time runtime initialization that must be deferred until
2622 // the executable itself is found. This needs to be done before
2623 // further initialization.
2624 // (The executable may not be present in this infoList if the
2625 // executable does not contain Objective-C code but Objective-C
2626 // is dynamically loaded later. In that case, check_wants_gc()
2627 // will do the right thing.)
2628 if (firstTime) {
2629 wantsGC = check_wants_gc();
2630 verify_gc_readiness(wantsGC, FirstHeader);
2631 // TIGER DEVELOPMENT ONLY
2632 // REQUIRE A SPECIAL NON-SHIPPING FILE TO ENABLE GC
2633 if (wantsGC) {
2634 // make sure that the special file is there before proceeding with GC
2635 struct stat ignored;
2636 wantsGC = stat("/autozone", &ignored) != -1;
2637 if (!wantsGC && PrintGC)
2638 _objc_inform("GC: disabled, lacking /autozone file");
2639 }
2640
2641 gc_init(wantsGC); // needs executable for GC decision
2642 rtp_init(); // needs GC decision first
2643 } else {
2644 verify_gc_readiness(wantsGC, firstNewHeader);
2645 }
2646
2647
2648 // Initialize everything. Parts of this order are important for
2649 // correctness or performance.
2650
2651 // Read classes from all images.
2652 for (hInfo = firstNewHeader; hInfo != NULL; hInfo = hInfo->next) {
2653 _objc_read_classes_from_image(hInfo);
2654 }
2655
2656 // Read categories from all images.
2657 for (hInfo = firstNewHeader; hInfo != NULL; hInfo = hInfo->next) {
2658 _objc_read_categories_from_image(hInfo);
2659 }
2660
2661 // Connect classes from all images.
2662 for (hInfo = firstNewHeader; hInfo != NULL; hInfo = hInfo->next) {
2663 _objc_connect_classes_from_image(hInfo);
2664 }
2665
2666 // Fix up class refs, selector refs, and protocol objects from all images.
2667 for (hInfo = firstNewHeader; hInfo != NULL; hInfo = hInfo->next) {
2668 _objc_map_class_refs_for_image(hInfo);
2669 _objc_fixup_selector_refs(hInfo);
2670 _objc_fixup_protocol_objects_for_image(hInfo);
2671 }
2672
2673 // Close any shared range file left open during selector uniquing
2674 clear_shared_range_file_cache();
2675
2676 firstTime = NO;
2677
2678 // Call pending +load methods.
2679 // Note that this may in turn cause map_images() to be called again.
2680 call_load_methods();
2681 }
2682
2683
2684 /***********************************************************************
2685 * unmap_images
2686 * Process the given images which are about to be unmapped by dyld.
2687 * Currently we assume only MH_BUNDLE images are unmappable, and
2688 * print warnings about anything else.
2689 **********************************************************************/
2690 static void unmap_images(const struct dyld_image_info infoList[],
2691 uint32_t infoCount)
2692 {
2693 uint32_t i;
2694
2695 if (PrintImages) {
2696 _objc_inform("IMAGES: processing %u newly-unmapped images...\n", infoCount);
2697 }
2698
2699 for (i = 0; i < infoCount; i++) {
2700 const struct mach_header *mhdr = infoList[i].imageLoadAddress;
2701
2702 if (mhdr->filetype == MH_BUNDLE) {
2703 _objc_unmap_image(mhdr);
2704 } else {
2705 // currently only MH_BUNDLEs can be unmapped safely
2706 if (PrintImages) {
2707 _objc_inform("IMAGES: unmapped image '%s' was not a Mach-O bundle; ignoring\n", infoList[i].imageFilePath);
2708 }
2709 }
2710 }
2711 }
2712
2713
2714 /***********************************************************************
2715 * _objc_notify_images
2716 * Callback from dyld informing objc of images to be added or removed.
2717 * This function is never called directly. Instead, a section
2718 * __OBJC,__image_notify contains a function pointer to this, and dyld
2719 * discovers it from there.
2720 **********************************************************************/
2721 __private_extern__
2722 void _objc_notify_images(enum dyld_image_mode mode, uint32_t infoCount,
2723 const struct dyld_image_info infoList[])
2724 {
2725 if (mode == dyld_image_adding) {
2726 map_images(infoList, infoCount);
2727 } else if (mode == dyld_image_removing) {
2728 unmap_images(infoList, infoCount);
2729 }
2730 }
2731
2732
2733 /***********************************************************************
2734 * _objc_remove_classes_in_image
2735 * Remove all classes in the given image from the runtime, because
2736 * the image is about to be unloaded.
2737 * Things to clean up:
2738 * class_hash
2739 * unconnected_class_hash
2740 * pending subclasses list (only if class is still unconnected)
2741 * loadable class list
2742 * class's method caches
2743 * class refs in all other images
2744 **********************************************************************/
2745 static void _objc_remove_classes_in_image(header_info *hi)
2746 {
2747 unsigned int index;
2748 unsigned int midx;
2749 Module mods;
2750
2751 OBJC_LOCK(&classLock);
2752
2753 // Major loop - process all modules in the image
2754 mods = hi->mod_ptr;
2755 for (midx = 0; midx < hi->mod_count; midx += 1)
2756 {
2757 // Skip module containing no classes
2758 if (mods[midx].symtab == NULL)
2759 continue;
2760
2761 // Minor loop - process all the classes in given module
2762 for (index = 0; index < mods[midx].symtab->cls_def_cnt; index += 1)
2763 {
2764 struct objc_class * cls;
2765
2766 // Locate the class description pointer
2767 cls = mods[midx].symtab->defs[index];
2768
2769 // Remove from loadable class list, if present
2770 remove_class_from_loadable_list(cls);
2771
2772 // Remove from unconnected_class_hash and pending subclasses
2773 if (unconnected_class_hash && NXHashMember(unconnected_class_hash, cls)) {
2774 NXHashRemove(unconnected_class_hash, cls);
2775 if (pendingSubclassesMap) {
2776 // Find this class in its superclass's pending list
2777 char *supercls_name = (char *)cls->super_class;
2778 PendingSubclass *pending =
2779 NXMapGet(pendingSubclassesMap, supercls_name);
2780 for ( ; pending != NULL; pending = pending->next) {
2781 if (pending->subclass == cls) {
2782 pending->subclass = Nil;
2783 break;
2784 }
2785 }
2786 }
2787 }
2788
2789 // Remove from class_hash
2790 NXHashRemove(class_hash, cls);
2791
2792 // Free method list array (from objcTweakMethodListPointerForClass)
2793 // These blocks might be from user code; don't use free_internal
2794 if (cls->methodLists && !(cls->info & CLS_NO_METHOD_ARRAY)) {
2795 free(cls->methodLists);
2796 }
2797 if (cls->isa->methodLists && !(cls->isa->info & CLS_NO_METHOD_ARRAY)) {
2798 free(cls->isa->methodLists);
2799 }
2800
2801 // Free method caches, if any
2802 if (cls->cache && cls->cache != &emptyCache) {
2803 _free_internal(cls->cache);
2804 }
2805 if (cls->isa->cache && cls->isa->cache != &emptyCache) {
2806 _free_internal(cls->isa->cache);
2807 }
2808 }
2809 }
2810
2811
2812 // Search all other images for class refs that point back to this range.
2813 // Un-fix and re-pend any such class refs.
2814
2815 // Get the location of the dying image's __OBJC segment
2816 uintptr_t seg = hi->objcSegmentHeader->vmaddr + hi->image_slide;
2817 size_t seg_size = hi->objcSegmentHeader->filesize;
2818
2819 header_info *other_hi;
2820 for (other_hi = FirstHeader; other_hi != NULL; other_hi = other_hi->next) {
2821 struct objc_class **other_refs;
2822 unsigned int size;
2823 if (other_hi == hi) continue; // skip the image being unloaded
2824
2825 // Locate class refs in the other image
2826 other_refs = _getObjcClassRefs((headerType *)other_hi->mhdr, &size);
2827 if (!other_refs) continue;
2828 other_refs = (struct objc_class **)((uintptr_t)other_refs + other_hi->image_slide);
2829
2830 // Process each class ref
2831 for (index = 0; index < size; index++) {
2832 if ((uintptr_t)(other_refs[index]) >= seg &&
2833 (uintptr_t)(other_refs[index]) < seg+seg_size)
2834 {
2835 pendClassReference(&other_refs[index],other_refs[index]->name);
2836 other_refs[index] = _objc_getNonexistentClass ();
2837 }
2838 }
2839 }
2840
2841 OBJC_UNLOCK(&classLock);
2842 }
2843
2844
2845 /***********************************************************************
2846 * _objc_remove_categories_in_image
2847 * Remove all categories in the given image from the runtime, because
2848 * the image is about to be unloaded.
2849 * Things to clean up:
2850 * unresolved category list
2851 * loadable category list
2852 **********************************************************************/
2853 static void _objc_remove_categories_in_image(header_info *hi)
2854 {
2855 Module mods;
2856 unsigned int midx;
2857
2858 // Major loop - process all modules in the header
2859 mods = hi->mod_ptr;
2860
2861 for (midx = 0; midx < hi->mod_count; midx++) {
2862 unsigned int index;
2863 unsigned int total;
2864 Symtab symtab = mods[midx].symtab;
2865
2866 // Nothing to do for a module without a symbol table
2867 if (symtab == NULL) continue;
2868
2869 // Total entries in symbol table (class entries followed
2870 // by category entries)
2871 total = symtab->cls_def_cnt + symtab->cat_def_cnt;
2872
2873 // Minor loop - check all categories from given module
2874 for (index = symtab->cls_def_cnt; index < total; index++) {
2875 struct objc_category *cat = symtab->defs[index];
2876
2877 // Clean up loadable category list
2878 remove_category_from_loadable_list(cat);
2879
2880 // Clean up category_hash
2881 if (category_hash) {
2882 _objc_unresolved_category *cat_entry =
2883 NXMapGet(category_hash, cat->class_name);
2884 for ( ; cat_entry != NULL; cat_entry = cat_entry->next) {
2885 if (cat_entry->cat == cat) {
2886 cat_entry->cat = NULL;
2887 break;
2888 }
2889 }
2890 }
2891 }
2892 }
2893 }
2894
2895
2896 /***********************************************************************
2897 * unload_paranoia
2898 * Various paranoid debugging checks that look for poorly-behaving
2899 * unloadable bundles.
2900 * Called by _objc_unmap_image when OBJC_UNLOAD_DEBUG is set.
2901 **********************************************************************/
2902 static void unload_paranoia(header_info *hi)
2903 {
2904 // Get the location of the dying image's __OBJC segment
2905 uintptr_t seg = hi->objcSegmentHeader->vmaddr + hi->image_slide;
2906 size_t seg_size = hi->objcSegmentHeader->filesize;
2907
2908 _objc_inform("UNLOAD DEBUG: unloading image '%s' [%p..%p]",
2909 _nameForHeader(hi->mhdr), seg, seg+seg_size);
2910
2911 OBJC_LOCK(&classLock);
2912
2913 // Make sure the image contains no categories on surviving classes.
2914 {
2915 Module mods;
2916 unsigned int midx;
2917
2918 // Major loop - process all modules in the header
2919 mods = hi->mod_ptr;
2920
2921 for (midx = 0; midx < hi->mod_count; midx++) {
2922 unsigned int index;
2923 unsigned int total;
2924 Symtab symtab = mods[midx].symtab;
2925
2926 // Nothing to do for a module without a symbol table
2927 if (symtab == NULL) continue;
2928
2929 // Total entries in symbol table (class entries followed
2930 // by category entries)
2931 total = symtab->cls_def_cnt + symtab->cat_def_cnt;
2932
2933 // Minor loop - check all categories from given module
2934 for (index = symtab->cls_def_cnt; index < total; index++) {
2935 struct objc_category *cat = symtab->defs[index];
2936 struct objc_class query;
2937
2938 query.name = cat->class_name;
2939 if (NXHashMember(class_hash, &query)) {
2940 _objc_inform("UNLOAD DEBUG: dying image contains category '%s(%s)' on surviving class '%s'!", cat->class_name, cat->category_name, cat->class_name);
2941 }
2942 }
2943 }
2944 }
2945
2946 // Make sure no surviving class is in the dying image.
2947 // Make sure no surviving class has a superclass in the dying image.
2948 // fixme check method implementations too
2949 {
2950 struct objc_class *cls;
2951 NXHashState state;
2952
2953 state = NXInitHashState(class_hash);
2954 while (NXNextHashState(class_hash, &state, (void **)&cls)) {
2955 if ((vm_address_t)cls >= seg &&
2956 (vm_address_t)cls < seg+seg_size)
2957 {
2958 _objc_inform("UNLOAD DEBUG: dying image contains surviving class '%s'!", cls->name);
2959 }
2960
2961 if ((vm_address_t)cls->super_class >= seg &&
2962 (vm_address_t)cls->super_class < seg+seg_size)
2963 {
2964 _objc_inform("UNLOAD DEBUG: dying image contains superclass '%s' of surviving class '%s'!", cls->super_class->name, cls->name);
2965 }
2966 }
2967 }
2968
2969 OBJC_UNLOCK(&classLock);
2970 }
2971
2972
2973 /***********************************************************************
2974 * _objc_unmap_image.
2975 * Destroy any Objective-C data for the given image, which is about to
2976 * be unloaded by dyld.
2977 * Note: not thread-safe, but image loading isn't either.
2978 **********************************************************************/
2979 static void _objc_unmap_image(const headerType *mh)
2980 {
2981 header_info *hi;
2982
2983 // Find the runtime's header_info struct for the image
2984 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
2985 if (hi->mhdr == mh) break;
2986 }
2987 if (hi == NULL) return; // no objc data for this image
2988
2989 if (PrintImages) {
2990 _objc_inform("IMAGES: unloading image for %s%s%s%s\n",
2991 _nameForHeader(mh),
2992 mh->filetype == MH_BUNDLE ? " (bundle)" : "",
2993 _objcHeaderIsReplacement(hi) ? " (replacement)" : "",
2994 _objcHeaderSupportsGC(hi) ? " (supports GC)" : "");
2995 }
2996
2997 // Cleanup:
2998 // Remove image's classes from the class list and free auxiliary data.
2999 // Remove image's unresolved or loadable categories and free auxiliary data
3000 // Remove image's unresolved class refs.
3001 _objc_remove_classes_in_image(hi);
3002 _objc_remove_categories_in_image(hi);
3003 _objc_remove_pending_class_refs_in_image(hi);
3004
3005 // Perform various debugging checks if requested.
3006 if (DebugUnload) unload_paranoia(hi);
3007
3008 // Remove header_info from header list
3009 _objc_removeHeader(hi);
3010 }
3011
3012
3013 /***********************************************************************
3014 * _objc_setNilReceiver
3015 **********************************************************************/
3016 id _objc_setNilReceiver(id newNilReceiver)
3017 {
3018 id oldNilReceiver;
3019
3020 oldNilReceiver = _objc_nilReceiver;
3021 _objc_nilReceiver = newNilReceiver;
3022
3023 return oldNilReceiver;
3024 }
3025
3026 /***********************************************************************
3027 * _objc_getNilReceiver
3028 **********************************************************************/
3029 id _objc_getNilReceiver(void)
3030 {
3031 return _objc_nilReceiver;
3032 }
3033
3034
3035 /***********************************************************************
3036 * _objc_setClassLoader
3037 * Similar to objc_setClassHandler, but objc_classLoader is used for
3038 * both objc_getClass() and objc_lookupClass(), and objc_classLoader
3039 * pre-empts objc_classHandler.
3040 **********************************************************************/
3041 void _objc_setClassLoader(BOOL (*newClassLoader)(const char *))
3042 {
3043 _objc_classLoader = newClassLoader;
3044 }
3045
3046
3047 #if defined(__ppc__)
3048
3049 /**********************************************************************
3050 * objc_write_branch
3051 * Writes at entry a PPC branch instruction sequence that branches to target.
3052 * The sequence written will be 1 or 4 instructions long.
3053 * Returns the number of instructions written.
3054 **********************************************************************/
3055 __private_extern__ size_t objc_write_branch(void *entry, void *target)
3056 {
3057 unsigned *address = (unsigned *)entry; // location to store the 32 bit PPC instructions
3058 intptr_t destination = (intptr_t)target; // destination as an absolute address
3059 intptr_t displacement = (intptr_t)destination - (intptr_t)address; // destination as a branch relative offset
3060
3061 // Test to see if either the displacement or destination is within the +/- 2^25 range needed
3062 // for a simple PPC branch instruction. Shifting the high bit of the displacement (or destination)
3063 // left 6 bits and then 6 bits arithmetically to the right does a sign extend of the 26th bit. If
3064 // that result is equivalent to the original value, then the displacement (or destination) will fit
3065 // into a simple branch. Otherwise a four instruction branch sequence is required.
3066 if (((displacement << 6) >> 6) == displacement) {
3067 // use a relative branch with the displacement
3068 address[0] = 0x48000000 | (displacement & 0x03fffffc); // b *+displacement
3069 // issued 1 instruction
3070 return 1;
3071 } else if (((destination << 6) >> 6) == destination) {
3072 // use an absolute branch with the destination
3073 address[0] = 0x48000000 | (destination & 0x03fffffc) | 2; // ba destination (2 is the absolute flag)
3074 // issued 1 instruction
3075 return 1;
3076 } else {
3077 // The four instruction branch sequence requires that the destination be loaded
3078 // into a register, moved to the CTR register then branch using the contents
3079 // of the CTR register.
3080 unsigned lo = destination & 0xffff;
3081 unsigned hi = (destination >> 16) & 0xffff;
3082
3083 address[0] = 0x3d800000 | hi; // lis r12,hi ; load the hi half of destination
3084 address[1] = 0x618c0000 | lo; // ori r12,r12,lo ; merge in the lo half of destination
3085 address[2] = 0x7d8903a6; // mtctr ; move destination to the CTR register
3086 address[3] = 0x4e800420; // bctr ; branch to destination
3087 // issued 4 instructions
3088 return 4;
3089 }
3090 }
3091
3092 // defined(__ppc__)
3093 #endif
3094
3095
3096 /**********************************************************************
3097 * secure_open
3098 * Securely open a file from a world-writable directory (like /tmp)
3099 * If the file does not exist, it will be atomically created with mode 0600
3100 * If the file exists, it must be, and remain after opening:
3101 * 1. a regular file (in particular, not a symlink)
3102 * 2. owned by euid
3103 * 3. permissions 0600
3104 * 4. link count == 1
3105 * Returns a file descriptor or -1. Errno may or may not be set on error.
3106 **********************************************************************/
3107 __private_extern__ int secure_open(const char *filename, int flags, uid_t euid)
3108 {
3109 struct stat fs, ls;
3110 int fd = -1;
3111 BOOL truncate = NO;
3112 BOOL create = NO;
3113
3114 if (flags & O_TRUNC) {
3115 // Don't truncate the file until after it is open and verified.
3116 truncate = YES;
3117 flags &= ~O_TRUNC;
3118 }
3119 if (flags & O_CREAT) {
3120 // Don't create except when we're ready for it
3121 create = YES;
3122 flags &= ~O_CREAT;
3123 flags &= ~O_EXCL;
3124 }
3125
3126 if (lstat(filename, &ls) < 0) {
3127 if (errno == ENOENT && create) {
3128 // No such file - create it
3129 fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
3130 if (fd >= 0) {
3131 // File was created successfully.
3132 // New file does not need to be truncated.
3133 return fd;
3134 } else {
3135 // File creation failed.
3136 return -1;
3137 }
3138 } else {
3139 // lstat failed, or user doesn't want to create the file
3140 return -1;
3141 }
3142 } else {
3143 // lstat succeeded - verify attributes and open
3144 if (S_ISREG(ls.st_mode) && // regular file?
3145 ls.st_nlink == 1 && // link count == 1?
3146 ls.st_uid == euid && // owned by euid?
3147 (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
3148 {
3149 // Attributes look ok - open it and check attributes again
3150 fd = open(filename, flags, 0000);
3151 if (fd >= 0) {
3152 // File is open - double-check attributes
3153 if (0 == fstat(fd, &fs) &&
3154 fs.st_nlink == ls.st_nlink && // link count == 1?
3155 fs.st_uid == ls.st_uid && // owned by euid?
3156 fs.st_mode == ls.st_mode && // regular file, 0600?
3157 fs.st_ino == ls.st_ino && // same inode as before?
3158 fs.st_dev == ls.st_dev) // same device as before?
3159 {
3160 // File is open and OK
3161 if (truncate) ftruncate(fd, 0);
3162 return fd;
3163 } else {
3164 // Opened file looks funny - close it
3165 close(fd);
3166 return -1;
3167 }
3168 } else {
3169 // File didn't open
3170 return -1;
3171 }
3172 } else {
3173 // Unopened file looks funny - don't open it
3174 return -1;
3175 }
3176 }
3177 }
3178
3179
3180 /**********************************************************************
3181 * Shared range support:
3182 *
3183 * Some libraries contain many pages worth of selector references.
3184 * In most processes, these libraries get loaded at the same addresses,
3185 * so the selectors are uniqued to the same values. To save memory,
3186 * the runtime tries to share these memory pages across processes.
3187 *
3188 * A file /tmp/objc_sharing_<arch>_<euid> records memory ranges and process
3189 * IDs. When a set of selector refs is to be uniqued, this file is checked
3190 * for a matching memory range being shared by another process. If
3191 * such a range is found:
3192 * 1. map the sharing process's memory somewhere into this address space
3193 * 2. read from the real selector refs and write into the mapped memory.
3194 * 3. vm_copy from the mapped memory to the real selector refs location
3195 * 4. deallocate the mapped memory
3196 *
3197 * The mapped memory is merely used as a guess. Correct execution is
3198 * guaranteed no matter what values the mapped memory actually contains.
3199 * If the mapped memory really matches the values needed in this process,
3200 * the mapped memory will be unchanged. If the mapped memory doesn't match,
3201 * or contains random values, it will be fixed up to the correct values.
3202 * The memory is shared whenever the guess happens to be correct.
3203 *
3204 * The file of shared ranges is imprecise. Processes may die leaving
3205 * their entries in the file. A PID may be recycled to some process that
3206 * does not use Objective-C. The sharing mechanism is robust in the face
3207 * of these failures. Bad shared memory is simply fixed up. No shared
3208 * memory means the selectors are fixed in place. If an entry in the
3209 * file is found to be unusable, the process that finds it will instead
3210 * offer to share its own memory, replacing the bad entry in the file.
3211 *
3212 * Individual entries in the file are written atomically, but the file is
3213 * otherwise unsynchronized. At worst, a sharing opportunity may be missed
3214 * because two new entries are written simultaneously in the same place.
3215 **********************************************************************/
3216
3217
3218 struct remote_range_t {
3219 vm_range_t range;
3220 pid_t pid;
3221 };
3222
3223
3224 // Cache for the last shared range file used, and its EUID.
3225 static pthread_mutex_t sharedRangeLock = PTHREAD_MUTEX_INITIALIZER;
3226 static uid_t sharedRangeEUID = 0;
3227 static FILE * sharedRangeFile = NULL;
3228 static BOOL sharedRangeFileInUse = NO;
3229
3230
3231 /**********************************************************************
3232 * open_shared_range_file
3233 * Open the shared range file "/tmp/objc_sharing_<arch>_<euid>" in
3234 * the given mode.
3235 * The returned file should be closed with close_shared_range_file().
3236 **********************************************************************/
3237 static FILE *open_shared_range_file(BOOL create)
3238 {
3239 const char arch[] =
3240 #if defined(__ppc__) || defined(ppc)
3241 "ppc";
3242 #elif defined(__ppc64__) || defined(ppc64)
3243 "ppc64";
3244 #elif defined(__i386__) || defined(i386)
3245 "i386";
3246 #else
3247 # error "unknown architecture"
3248 #endif
3249 char filename[18 + sizeof(arch) + 1 + 3*sizeof(uid_t) + 1];
3250 uid_t euid;
3251 FILE *file = NULL;
3252 int fd;
3253
3254 // Never share when superuser
3255 euid = geteuid();
3256 if (euid == 0) {
3257 if (PrintSharing) {
3258 _objc_inform("SHARING: superuser never shares");
3259 }
3260 return NULL;
3261 }
3262
3263 // Return cached file if it matches and it's not still being used
3264 pthread_mutex_lock(&sharedRangeLock);
3265 if (!sharedRangeFileInUse && euid == sharedRangeEUID) {
3266 file = sharedRangeFile;
3267 sharedRangeFileInUse = YES;
3268 pthread_mutex_unlock(&sharedRangeLock);
3269 rewind(file);
3270 return file;
3271 }
3272 pthread_mutex_unlock(&sharedRangeLock);
3273
3274 // Open /tmp/objc_sharing_<euid>
3275 snprintf(filename,sizeof(filename), "/tmp/objc_sharing_%s_%u", arch, euid);
3276 fd = secure_open(filename, O_RDWR | (create ? O_CREAT : 0), euid);
3277 if (fd >= 0) {
3278 file = fdopen(fd, "r+");
3279 }
3280
3281 if (file) {
3282 // Cache this file if there's no already-open file cached
3283 pthread_mutex_lock(&sharedRangeLock);
3284 if (!sharedRangeFileInUse) {
3285 sharedRangeFile = file;
3286 sharedRangeEUID = euid;
3287 sharedRangeFileInUse = YES;
3288 }
3289 pthread_mutex_unlock(&sharedRangeLock);
3290 }
3291 else {
3292 // open() or fdopen() failed
3293 if (PrintSharing) {
3294 _objc_inform("SHARING: bad or missing sharing file '%s': %s",
3295 filename, errno ? strerror(errno) :
3296 "potential security violation");
3297 }
3298 }
3299
3300 return file;
3301 }
3302
3303
3304 /**********************************************************************
3305 * close_shared_range_file
3306 * Close a file opened with open_shared_range_file.
3307 * The file may actually be kept open and cached for a future
3308 * open_shared_range_file call. If so, clear_shared_range_file_cache()
3309 * can be used to really close the file.
3310 **********************************************************************/
3311 static void close_shared_range_file(FILE *file)
3312 {
3313 // Flush any writes in case the file is kept open.
3314 fflush(file);
3315
3316 pthread_mutex_lock(&sharedRangeLock);
3317 if (file == sharedRangeFile && sharedRangeFileInUse) {
3318 // This file is the cached shared file.
3319 // Leave the file open and cached, but no longer in use.
3320 sharedRangeFileInUse = NO;
3321 } else {
3322 // This is not the cached file.
3323 fclose(file);
3324 }
3325 pthread_mutex_unlock(&sharedRangeLock);
3326 }
3327
3328
3329 /**********************************************************************
3330 * clear_shared_range_file_cache
3331 * Really close any file left open by close_shared_range_file.
3332 * This is called by map_images() after loading multiple images, each
3333 * of which may have used the shared range file.
3334 **********************************************************************/
3335 static void clear_shared_range_file_cache(void)
3336 {
3337 pthread_mutex_lock(&sharedRangeLock);
3338 if (sharedRangeFile && !sharedRangeFileInUse) {
3339 fclose(sharedRangeFile);
3340 sharedRangeFile = NULL;
3341 sharedRangeEUID = 0;
3342 sharedRangeFileInUse = 0;
3343 }
3344 pthread_mutex_unlock(&sharedRangeLock);
3345 }
3346
3347
3348 /**********************************************************************
3349 * get_shared_range
3350 * Try to find a shared range matching addresses [aligned_start..aligned_end).
3351 * If a range is found, it is mapped into this process and returned.
3352 * If no range is found, or the found range could not be mapped for
3353 * some reason, the range {0, 0} is returned.
3354 * aligned_start and aligned_end must be page-aligned.
3355 **********************************************************************/
3356 static vm_range_t get_shared_range(vm_address_t aligned_start,
3357 vm_address_t aligned_end)
3358 {
3359 struct remote_range_t remote;
3360 vm_range_t result;
3361 FILE *file;
3362
3363 result.address = 0;
3364 result.size = 0;
3365
3366 // Open shared range file, but don't create it
3367 file = open_shared_range_file(NO);
3368 if (!file) return result;
3369
3370 // Search for the desired memory range
3371 while (1 == fread(&remote, sizeof(remote), 1, file)) {
3372 if (remote.pid != 0 &&
3373 remote.range.address == aligned_start &&
3374 remote.range.size == aligned_end - aligned_start)
3375 {
3376 // Found a match in the file - try to grab the memory
3377 mach_port_name_t remote_task;
3378 vm_prot_t cur_prot, max_prot;
3379 vm_address_t local_addr;
3380 kern_return_t kr;
3381
3382 // Find the task offering the memory
3383 kr = task_for_pid(mach_task_self(), remote.pid, &remote_task);
3384 if (kr != KERN_SUCCESS) {
3385 // task is dead
3386 if (PrintSharing) {
3387 _objc_inform("SHARING: no task for pid %d: %s",
3388 remote.pid, mach_error_string(kr));
3389 }
3390 break;
3391 }
3392
3393 // Map the memory into our process
3394 local_addr = 0;
3395 kr = vm_remap(mach_task_self(), &local_addr, remote.range.size,
3396 0 /*alignment*/, 1 /*anywhere*/,
3397 remote_task, remote.range.address,
3398 1 /*copy*/, &cur_prot, &max_prot, VM_INHERIT_NONE);
3399 mach_port_deallocate(mach_task_self(), remote_task);
3400
3401 if (kr != KERN_SUCCESS) {
3402 // couldn't map memory
3403 if (PrintSharing) {
3404 _objc_inform("SHARING: vm_remap from pid %d failed: %s",
3405 remote.pid, mach_error_string(kr));
3406 }
3407 break;
3408 }
3409
3410 if (!(cur_prot & VM_PROT_READ) || !(cur_prot & VM_PROT_WRITE)) {
3411 // Received memory is not mapped read/write - don't use it
3412 // fixme try to change permissions? check max_prot?
3413 if (PrintSharing) {
3414 _objc_inform("SHARING: memory from pid %d not read/write",
3415 remote.pid);
3416 }
3417 vm_deallocate(mach_task_self(), local_addr, remote.range.size);
3418 break;
3419 }
3420
3421 // Success
3422 result.address = local_addr;
3423 result.size = remote.range.size;
3424 }
3425 }
3426
3427 close_shared_range_file(file);
3428 return result;
3429 }
3430
3431
3432 /**********************************************************************
3433 * offer_shared_range
3434 * Offer memory range [aligned_start..aligned_end) in this process
3435 * to other Objective-C-using processes.
3436 * If some other entry in the shared range list matches this range,
3437 * is is overwritten with this process's PID. (Thus any stale PIDs are
3438 * replaced.)
3439 * If the shared range file could not be updated for any reason, this
3440 * function fails silently.
3441 * aligned_start and aligned_end must be page-aligned.
3442 **********************************************************************/
3443 static void offer_shared_range(vm_address_t aligned_start,
3444 vm_address_t aligned_end)
3445 {
3446 struct remote_range_t remote;
3447 struct remote_range_t local;
3448 BOOL found = NO;
3449 FILE *file;
3450 int err = 0;
3451
3452 local.range.address = aligned_start;
3453 local.range.size = aligned_end - aligned_start;
3454 local.pid = getpid();
3455
3456 // Open shared range file, creating if necessary
3457 file = open_shared_range_file(YES);
3458 if (!file) return;
3459
3460 // Find an existing entry for this range, if any
3461 while (1 == fread(&remote, sizeof(remote), 1, file)) {
3462 if (remote.pid != 0 &&
3463 remote.range.address == aligned_start &&
3464 remote.range.size == aligned_end - aligned_start)
3465 {
3466 // Found a match - overwrite it
3467 err = fseek(file, -sizeof(remote), SEEK_CUR);
3468 found = YES;
3469 break;
3470 }
3471 }
3472
3473 if (!found) {
3474 // No existing entry - write at the end of the file
3475 err = fseek(file, 0, SEEK_END);
3476 }
3477
3478 if (err == 0) {
3479 fwrite(&local, sizeof(local), 1, file);
3480 }
3481
3482 close_shared_range_file(file);
3483 }
3484
3485
3486 /**********************************************************************
3487 * install_shared_range
3488 * Install a shared range received from get_shared_range() into
3489 * its final resting place.
3490 * If possible, the memory is copied using virtual memory magic rather
3491 * than actual data writes. dst always gets updated values, even if
3492 * virtual memory magic is not possible.
3493 * The shared range is always deallocated.
3494 * src and dst must be page-aligned.
3495 **********************************************************************/
3496 static void install_shared_range(vm_range_t src, vm_address_t dst)
3497 {
3498 kern_return_t kr;
3499
3500 // Copy from src to dst
3501 kr = vm_copy(mach_task_self(), src.address, src.size, dst);
3502 if (kr != KERN_SUCCESS) {
3503 // VM copy failed. Use non-VM copy.
3504 if (PrintSharing) {
3505 _objc_inform("SHARING: vm_copy failed: %s", mach_error_string(kr));
3506 }
3507 memmove((void *)dst, (void *)src.address, src.size);
3508 }
3509
3510 // Unmap the shared range at src
3511 vm_deallocate(mach_task_self(), src.address, src.size);
3512 }