|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.0 (the 'License'). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License." ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* ! 25: * objc-runtime.m ! 26: * Copyright 1988, NeXT, Inc. ! 27: * Author: s. naroff ! 28: * ! 29: */ ! 30: ! 31: #ifdef SHLIB ! 32: #import "shlib.h" ! 33: #endif SHLIB ! 34: ! 35: #import "objc-private.h" ! 36: #include <mach-o/ldsyms.h> ! 37: #import "objc-runtime.h" ! 38: #import "hashtable.h" ! 39: #import "maptable.h" ! 40: #import "Object.h" ! 41: #import "Protocol.h" ! 42: ! 43: void *getsectdatafromheader(const struct mach_header *, char *, char *, int *); ! 44: static const struct segment_command * ! 45: getobjcsegmentfromheader(const struct mach_header *mhp); ! 46: ! 47: void (*callbackFunction)( Class, Category ) = 0; ! 48: ! 49: void *getsectdatafromheaderinfo(const struct header_info * info, ! 50: char * segname, ! 51: char * sectname, ! 52: int * size) ! 53: { ! 54: char *addr = getsectdatafromheader (info->mhdr, segname, sectname, size); ! 55: if (addr) ! 56: addr += info->image_slide; ! 57: return addr; ! 58: } ! 59: ! 60: /* Turn on support for literal string objects. */ ! 61: #define LITERAL_STRING_OBJECTS ! 62: ! 63: /* system vectors...created at runtime by reading the `__OBJC' segments ! 64: * that are a part of the application. ! 65: */ ! 66: ! 67: /* These two variables are now obsolete. ! 68: They have been replaced by header_vector and header_count. */ ! 69: ! 70: static unsigned int module_count; ! 71: static Module *module_vector; ! 72: ! 73: /* We do not lock these variables, since they are only set during startup. */ ! 74: ! 75: static struct header_info *header_vector = 0; ! 76: static unsigned int header_count = 0; ! 77: ! 78: /* ! 79: * Hash table of classes... ! 80: */ ! 81: static NXHashTable *class_hash = 0; ! 82: ! 83: /* Mask which specifies whether we are multi-threaded or not. ! 84: A value of -1 means single-threaded, 0 means multi-threaded. */ ! 85: int _objc_multithread_mask = -1; ! 86: ! 87: /* Lock for class hashtable. (Private extern) */ ! 88: ! 89: OBJC_DECLARE_LOCK (classLock); ! 90: ! 91: static unsigned classHash (void *info, Class data) ! 92: { ! 93: return (data) ? _objc_strhash ((unsigned char *)((Class) data)->name) : 0; ! 94: } ! 95: ! 96: static int classIsEqual (void *info, Class name, Class cls) ! 97: { ! 98: return ((name->name[0] == cls->name[0]) && ! 99: (strcmp(name->name, cls->name) == 0)); ! 100: } ! 101: ! 102: static NXHashTablePrototype classHashPrototype = ! 103: { ! 104: (unsigned (*)(const void *, const void *))classHash, ! 105: (int (*)(const void *, const void *, const void *))classIsEqual, ! 106: NXNoEffectFree, 0 ! 107: }; ! 108: ! 109: /* This function is very dangerous, since you cannot safely use the hashtable ! 110: without locking it, and the lock is private! */ ! 111: ! 112: NXHashTable *objc_getClasses (void) ! 113: { ! 114: return class_hash; ! 115: } ! 116: ! 117: static int _objc_defaultClassHandler(const char *clsName) ! 118: { ! 119: _objc_inform("class `%s' not linked into application", clsName); ! 120: return 0; ! 121: } ! 122: ! 123: static int (*objc_classHandler)(const char *) = _objc_defaultClassHandler; ! 124: ! 125: void objc_setClassHandler(int (*userSuppliedHandler)(const char *)) ! 126: { ! 127: objc_classHandler = userSuppliedHandler; ! 128: } ! 129: ! 130: id objc_getClass(const char *aClassName) ! 131: { ! 132: struct objc_class cls; ! 133: id ret; ! 134: ! 135: OBJC_LOCK (&classLock); ! 136: cls.name = aClassName; ! 137: ! 138: if (!(ret = (id)NXHashGet(class_hash, &cls))) ! 139: { ! 140: int result; ! 141: ! 142: OBJC_UNLOCK (&classLock); ! 143: result = (*objc_classHandler)(aClassName); ! 144: OBJC_LOCK (&classLock); ! 145: ! 146: if (result) ! 147: ret = (id)NXHashGet(class_hash, &cls); ! 148: } ! 149: ! 150: OBJC_UNLOCK (&classLock); ! 151: return ret; ! 152: } ! 153: ! 154: /* Formerly objc_getClassWithoutWarning(). */ ! 155: ! 156: id objc_lookUpClass (const char *aClassName) ! 157: { ! 158: struct objc_class cls; ! 159: id ret; ! 160: ! 161: OBJC_LOCK (&classLock); ! 162: cls.name = aClassName; ! 163: ! 164: ret = (id)NXHashGet(class_hash, &cls); ! 165: ! 166: OBJC_UNLOCK (&classLock); ! 167: return ret; ! 168: } ! 169: ! 170: id objc_getMetaClass(const char *aClassName) ! 171: { ! 172: Class class = objc_getClass (aClassName); ! 173: ! 174: if (class) ! 175: return class->isa; ! 176: else ! 177: return Nil; ! 178: } ! 179: ! 180: void objc_addClass (Class class) ! 181: { ! 182: OBJC_LOCK (&classLock); ! 183: ! 184: // make sure both the class and the metaclass have caches! ! 185: // Clear all bits of the info fields except CLS_CLASS and CLS_META. ! 186: // Normally these bits are already clear but if someone tries to cons ! 187: // up their own class on the fly they may need to be cleared. ! 188: ! 189: if (class->cache == NULL) { ! 190: class->cache = (Cache) &emptyCache; ! 191: class->info = CLS_CLASS; ! 192: } ! 193: if (class->isa->cache == NULL) { ! 194: class->isa->cache = (Cache) &emptyCache; ! 195: class->isa->info = CLS_META; ! 196: } ! 197: ! 198: NXHashInsert (class_hash, class); ! 199: OBJC_UNLOCK (&classLock); ! 200: ! 201: } ! 202: ! 203: /* Private extern used by objc_unloadModules(). */ ! 204: void _objc_removeClass (Class class) ! 205: { ! 206: OBJC_LOCK (&classLock); ! 207: NXHashRemove (class_hash, class); ! 208: OBJC_UNLOCK (&classLock); ! 209: ! 210: } ! 211: ! 212: /* This only returns the statically linked modules. ! 213: I do not believe this is used now. ! 214: It has been replaced by _objc_headerVector(). */ ! 215: ! 216: Module *objc_getModules (void) ! 217: { ! 218: if (!module_vector) { ! 219: Module mods; ! 220: unsigned int hidx, midx; ! 221: Module *mvp; ! 222: ! 223: for (hidx = 0; hidx < header_count; hidx++) ! 224: module_count += header_vector[hidx].mod_count; ! 225: ! 226: if (!(module_vector = NXZoneMalloc(_objc_create_zone(), sizeof(Module) * (module_count+1)))) ! 227: _objc_fatal("unable to allocate module vector"); ! 228: ! 229: for (hidx = 0, mvp = module_vector; ! 230: hidx < header_count; hidx++) { ! 231: for (mods = header_vector[hidx].mod_ptr, midx = 0; ! 232: midx < header_vector[hidx].mod_count; ! 233: midx++, mvp++) { ! 234: ! 235: *mvp = mods+midx; ! 236: } ! 237: } ! 238: *mvp = 0; ! 239: } ! 240: return module_vector; ! 241: } ! 242: ! 243: /* What could this be used for? It is not currently used. */ ! 244: ! 245: Module *objc_addModule(Module myModule) ! 246: { ! 247: module_count++; ! 248: if (module_vector) { ! 249: module_vector = (Module *)NXZoneRealloc(_objc_create_zone(), ! 250: module_vector, ! 251: sizeof(Module) * (module_count + 1)); ! 252: } else { ! 253: module_vector = (Module *)NXZoneMalloc(_objc_create_zone(), ! 254: sizeof(Module) * (module_count + 1)); ! 255: } ! 256: if (!module_vector) ! 257: _objc_fatal("unable to reallocate module vector"); ! 258: ! 259: module_vector[module_count-1] = myModule; ! 260: module_vector[module_count] = 0; ! 261: return module_vector; ! 262: } ! 263: ! 264: /* Private extern used by objc_unloadModules(). */ ! 265: ! 266: void _objc_remove_category(struct objc_category *category, int version) ! 267: { ! 268: Class cls; ! 269: ! 270: if ((cls = objc_getClass(category->class_name))) { ! 271: if (category->instance_methods) ! 272: class_removeMethods(cls, category->instance_methods); ! 273: ! 274: if (category->class_methods) ! 275: class_removeMethods(cls->isa, category->class_methods); ! 276: if (version >= 5 && category->protocols) ! 277: _class_removeProtocols (cls, category->protocols); ! 278: } else { ! 279: _objc_inform("unable to remove category %s...\n", ! 280: category->category_name); ! 281: _objc_inform("class `%s' not linked into application\n", ! 282: category->class_name); ! 283: } ! 284: } ! 285: ! 286: static inline void ! 287: __objc_add_category(struct objc_category *category, int version) ! 288: { ! 289: Class cls; ! 290: ! 291: if ((cls = (Class)objc_getClass(category->class_name))) { ! 292: if (category->instance_methods) { ! 293: category->instance_methods->method_next = cls->methods; ! 294: cls->methods = category->instance_methods; ! 295: } ! 296: if (category->class_methods) { ! 297: category->class_methods->method_next = cls->isa->methods; ! 298: cls->isa->methods = category->class_methods; ! 299: } ! 300: if (version >= 5 && category->protocols) ! 301: { ! 302: if (cls->isa->version >= 5) ! 303: { ! 304: category->protocols->next = cls->protocols; ! 305: cls->protocols = category->protocols; ! 306: cls->isa->protocols = category->protocols; ! 307: } ! 308: else ! 309: { ! 310: _objc_inform ("unable to add protocols from category %s...\n", ! 311: category->category_name); ! 312: _objc_inform ("class `%s' must be recompiled\n", ! 313: category->class_name); ! 314: } ! 315: } ! 316: } else { ! 317: _objc_inform("unable to add category %s...\n", ! 318: category->category_name); ! 319: _objc_inform("class `%s' not linked into application\n", ! 320: category->class_name); ! 321: } ! 322: } ! 323: ! 324: /* Private extern used by objc_loadModules(). */ ! 325: ! 326: void _objc_add_category(struct objc_category *category, int version) ! 327: { ! 328: __objc_add_category (category, version); ! 329: ! 330: _objc_flush_caches (objc_getClass (category->class_name)); ! 331: } ! 332: ! 333: struct _objc_unresolved_category { ! 334: struct _objc_unresolved_category* next; ! 335: struct objc_category* cat; ! 336: long version; ! 337: }; ! 338: ! 339: static NXMapTable* category_hash = 0; ! 340: ! 341: static void _objc_resolve_categories_for_class (Class cls) ! 342: { ! 343: struct _objc_unresolved_category *cat, *next; ! 344: ! 345: if (!category_hash) ! 346: return; ! 347: ! 348: cat = NXMapRemove (category_hash, cls->name); ! 349: ! 350: while (cat) ! 351: { ! 352: _objc_add_category (cat->cat, cat->version); ! 353: ! 354: next = cat->next; ! 355: free (cat); ! 356: cat = next; ! 357: } ! 358: } ! 359: ! 360: ! 361: static void _objc_register_category (struct objc_category *cat, long version) ! 362: { ! 363: struct _objc_unresolved_category *new_cat, *old; ! 364: ! 365: if (objc_lookUpClass (cat->class_name)) ! 366: { ! 367: _objc_add_category (cat, version); ! 368: return; ! 369: } ! 370: ! 371: if (!category_hash) ! 372: category_hash = NXCreateMapTableFromZone (NXStrValueMapPrototype, ! 373: 128, ! 374: _objc_create_zone ()); ! 375: ! 376: old = NXMapGet (category_hash, cat->class_name); ! 377: new_cat = NXZoneMalloc (_objc_create_zone(), sizeof (struct _objc_unresolved_category)); ! 378: new_cat->next = old; ! 379: new_cat->cat = cat; ! 380: new_cat->version = version; ! 381: NXMapInsert (category_hash, cat->class_name , new_cat); ! 382: } ! 383: ! 384: ! 385: static void _objc_add_categories_from_image (struct header_info *hi) ! 386: { ! 387: Module mods; ! 388: unsigned int midx; ! 389: ! 390: for (mods = hi->mod_ptr, midx = 0; ! 391: midx < hi->mod_count; ! 392: midx++) { ! 393: unsigned int i, total; ! 394: ! 395: if (mods[midx].symtab == NULL) ! 396: continue; ! 397: ! 398: total = mods[midx].symtab->cls_def_cnt + ! 399: mods[midx].symtab->cat_def_cnt; ! 400: ! 401: /* add categories */ ! 402: for (i = mods[midx].symtab->cls_def_cnt; ! 403: i < total; i++) ! 404: _objc_register_category(mods[midx].symtab->defs[i], ! 405: mods[midx].version); ! 406: } ! 407: } ! 408: ! 409: static const struct header_info *_headerForClass(Class class) ! 410: { ! 411: const struct mach_header *foundHeader; ! 412: const struct segment_command *objcSeg; ! 413: unsigned int hidx; ! 414: ! 415: for (foundHeader = NULL, hidx = 0; ! 416: !foundHeader && (hidx < header_count); ! 417: hidx++) ! 418: { ! 419: unsigned long slide = header_vector[hidx].image_slide; ! 420: objcSeg = getobjcsegmentfromheader(header_vector[hidx].mhdr); ! 421: if ((objcSeg->vmaddr + slide <= (unsigned long)class) ! 422: && ((unsigned long)class < (objcSeg->vmaddr + slide + objcSeg->vmsize))) ! 423: { ! 424: return &(header_vector[hidx]); ! 425: } ! 426: } ! 427: ! 428: return 0; ! 429: } ! 430: ! 431: static const struct mach_header *_getExecHeader () ! 432: { ! 433: unsigned int hidx; ! 434: for (hidx = 0; hidx < header_count; hidx++) ! 435: if (header_vector[hidx].mhdr->filetype != MH_FVMLIB) ! 436: { ! 437: return header_vector[hidx].mhdr; ! 438: } ! 439: return NULL; ! 440: } ! 441: ! 442: /* private extern. */ ! 443: ! 444: const char *_nameForHeader(const struct mach_header *header) ! 445: { ! 446: const struct mach_header *execHeader; ! 447: const struct fvmlib_command *libCmd, *endOfCmds; ! 448: char **argv; ! 449: #if defined(__DYNAMIC__) ! 450: extern char ***_NSGetArgv(); ! 451: argv = *_NSGetArgv(); ! 452: #else ! 453: extern char **NXArgv; ! 454: argv = NXArgv; ! 455: #endif ! 456: if (header && header->filetype == MH_FVMLIB) { ! 457: execHeader = _getExecHeader(); ! 458: for (libCmd = (const struct fvmlib_command *)(execHeader + 1), ! 459: endOfCmds = ((void *)libCmd) + execHeader->sizeofcmds; ! 460: libCmd < endOfCmds; ! 461: ((void *)libCmd) += libCmd->cmdsize) { ! 462: if ((libCmd->cmd == LC_LOADFVMLIB) ! 463: && (libCmd->fvmlib.header_addr ! 464: == (unsigned long)header)) { ! 465: return (char *)libCmd ! 466: + libCmd->fvmlib.name.offset; ! 467: } ! 468: } ! 469: return NULL; ! 470: } else ! 471: return argv[0]; ! 472: } ! 473: ! 474: static void _resolveClassConflict(NXHashTable *clsHash, ! 475: Class oldClass, ! 476: Class newClass) ! 477: { ! 478: const struct header_info *oldHeader = _headerForClass(oldClass); ! 479: const struct header_info *newHeader = _headerForClass(newClass); ! 480: const char *oldName = _nameForHeader(oldHeader->mhdr); ! 481: const char *newName = _nameForHeader(newHeader->mhdr); ! 482: ! 483: _objc_inform("Both %s and %s have implementations of class %s.", ! 484: oldName, newName, oldClass->name); ! 485: if (newHeader->mhdr->filetype == MH_FVMLIB) { ! 486: NXHashInsert(clsHash, oldClass); ! 487: _objc_inform("Using implementation from %s.", oldName); ! 488: } else ! 489: _objc_inform("Using implementation from %s.", newName); ! 490: } ! 491: ! 492: static NXHashTable *_objc_init_class_hash () ! 493: { ! 494: return NXCreateHashTableFromZone(classHashPrototype, 8, nil, _objc_create_zone()); ! 495: } ! 496: ! 497: ! 498: static NXHashTable *_objc_get_classes_from_image (NXHashTable *clsHash, ! 499: struct header_info* hi) ! 500: { ! 501: unsigned int i; ! 502: Module mods; ! 503: unsigned int midx; ! 504: Class oldCls, newCls; ! 505: ! 506: for (mods = hi->mod_ptr, midx = 0; ! 507: midx < hi->mod_count; ! 508: midx++) ! 509: { ! 510: if (mods[midx].symtab == NULL) ! 511: continue; ! 512: ! 513: for (i = 0; i < mods[midx].symtab->cls_def_cnt; i++) { ! 514: oldCls = NXHashInsert(clsHash, ! 515: mods[midx].symtab->defs[i]); ! 516: if (oldCls) ! 517: { ! 518: _resolveClassConflict(clsHash, ! 519: oldCls, ! 520: mods[midx].symtab->defs[i]); ! 521: newCls = objc_lookUpClass (oldCls->name); ! 522: } ! 523: else ! 524: { ! 525: newCls = mods[midx].symtab->defs[i]; ! 526: } ! 527: ! 528: if (newCls != oldCls) ! 529: { ! 530: newCls->isa->version = mods[midx].version; ! 531: } ! 532: ! 533: _objc_resolve_categories_for_class (newCls); ! 534: } ! 535: } ! 536: ! 537: return clsHash; ! 538: } ! 539: ! 540: ! 541: #ifdef LITERAL_STRING_OBJECTS ! 542: ! 543: /* Initialize the isa pointers of all NXConstantString objects. */ ! 544: ! 545: #include <NXString.h> ! 546: ! 547: static void _objc_fixup_string_objects_for_image (struct header_info* hi) ! 548: { ! 549: NXConstantString *section; ! 550: unsigned int size; ! 551: ! 552: section = getsectdatafromheaderinfo (hi, ! 553: SEG_OBJC, "__string_object", &size); ! 554: if (section != 0 && size != 0) ! 555: { ! 556: Class constantStringClass = objc_getClass ("NXConstantString"); ! 557: unsigned int i; ! 558: ! 559: for (i = 0; i < size / sizeof (NXConstantString); i++) ! 560: *((Class *) §ion[i]) = constantStringClass; ! 561: } ! 562: } ! 563: #endif /* LITERAL_STRING_OBJECTS */ ! 564: ! 565: #ifdef OBJC_CLASS_REFS ! 566: static void _objc_map_class_refs_for_image (struct header_info* hi) ! 567: { ! 568: Class *cls_refs; ! 569: unsigned int size; ! 570: ! 571: cls_refs = (Class *) getsectdatafromheaderinfo (hi, ! 572: SEG_OBJC, ! 573: "__cls_refs", ! 574: &size); ! 575: ! 576: if (cls_refs) ! 577: { ! 578: unsigned int i; ! 579: ! 580: for (i = 0; i < size / sizeof (Class); i++) { ! 581: const char *ref = (const char *) cls_refs[i]; ! 582: Class cls = objc_lookUpClass( ref ); ! 583: cls_refs[i] = cls; ! 584: } ! 585: } ! 586: } ! 587: #endif /* OBJC_CLASS_REFS */ ! 588: ! 589: ! 590: static inline void map_selrefs (SEL *sels, unsigned int cnt) ! 591: { ! 592: unsigned int i; ! 593: ! 594: /* Overwrite the string with a unique identifier. */ ! 595: for (i = 0; i < cnt; i++) ! 596: { ! 597: SEL sel = _sel_registerName ((const char *) sels[i]); ! 598: ! 599: if (sels[i] != sel) ! 600: sels[i] = sel; ! 601: } ! 602: } ! 603: ! 604: ! 605: static inline void map_methods (struct objc_method_list *methods) ! 606: { ! 607: unsigned int i; ! 608: ! 609: for (i = 0; i < methods->method_count; i++) ! 610: { ! 611: Method method = &methods->method_list[i]; ! 612: SEL sel = _sel_registerName ((const char *) method->method_name); ! 613: ! 614: if (method->method_name != sel) ! 615: method->method_name = sel; ! 616: } ! 617: } ! 618: ! 619: ! 620: static inline void map_method_descs (struct objc_method_description_list *methods) ! 621: { ! 622: unsigned int i; ! 623: ! 624: for (i = 0; i < methods->count; i++) ! 625: { ! 626: struct objc_method_description *method = &methods->list[i]; ! 627: SEL sel = _sel_registerName ((const char *) method->name); ! 628: ! 629: if (method->name != sel) ! 630: method->name = sel; ! 631: } ! 632: } ! 633: ! 634: #import "Protocol.h" ! 635: ! 636: struct objc_protocol ! 637: { ! 638: @defs(Protocol) ! 639: }; ! 640: ! 641: @interface Protocol(RuntimePrivate) ! 642: + _fixup: (Protocol *)protos numElements: (int) nentries; ! 643: @end ! 644: ! 645: static void ! 646: _objc_fixup_protocol_objects_for_image (struct header_info* hi) ! 647: { ! 648: unsigned int size; ! 649: /* Fixup protocol objects. */ ! 650: struct objc_protocol * protos = (struct objc_protocol *) ! 651: getsectdatafromheaderinfo (hi, SEG_OBJC, "__protocol", &size); ! 652: ! 653: if (protos) ! 654: { ! 655: unsigned int i; ! 656: ! 657: for (i = 0; i < size / sizeof (Protocol); i++) { ! 658: ! 659: /* can't use map_methods, the sizes differ. */ ! 660: if (protos[i].instance_methods) ! 661: map_method_descs (protos[i].instance_methods); ! 662: if (protos[i].class_methods) ! 663: map_method_descs (protos[i].class_methods); ! 664: } ! 665: [Protocol _fixup: (Protocol *)protos numElements: size / sizeof (Protocol)]; ! 666: } ! 667: } ! 668: ! 669: ! 670: ! 671: static const struct segment_command * ! 672: getobjcsegmentfromheader(const struct mach_header *mhp) ! 673: { ! 674: struct segment_command *sgp; ! 675: unsigned long i; ! 676: ! 677: sgp = (struct segment_command *) ! 678: ((char *)mhp + sizeof(struct mach_header)); ! 679: for(i = 0; i < mhp->ncmds; i++){ ! 680: if(sgp->cmd == LC_SEGMENT) ! 681: if(strncmp(sgp->segname, "__OBJC", sizeof(sgp->segname)) == 0) ! 682: return sgp; ! 683: sgp = (struct segment_command *)((char *)sgp + sgp->cmdsize); ! 684: } ! 685: return((struct segment_command *)0); ! 686: } ! 687: ! 688: ! 689: /* Comparison function for sorting headers. Place all headers which have ! 690: freeze-dried hashtables before any which don't. Otherwise sort by ! 691: decreasing size. */ ! 692: ! 693: static int compareHeaders (const void *x1, const void *x2) ! 694: { ! 695: const struct header_info *header1 = x1, *header2 = x2; ! 696: ! 697: if (header1->frozenTable && !header2->frozenTable) ! 698: return -1; ! 699: else if (header2->frozenTable && !header1->frozenTable) ! 700: return 1; ! 701: ! 702: return (header2->objcSize - header1->objcSize); ! 703: } ! 704: ! 705: ! 706: /* Build the header vector, sorting it as _objc_map_selectors() expects. */ ! 707: ! 708: struct header_info *_objc_headerVector (const struct mach_header * const *machhdrs) ! 709: { ! 710: unsigned int hidx; ! 711: struct header_info *hdrVec; ! 712: ! 713: if (header_vector) ! 714: return header_vector; ! 715: ! 716: for (hidx = 0; machhdrs[hidx]; hidx++) ! 717: header_count++; ! 718: ! 719: hdrVec = NXZoneMalloc (_objc_create_zone(), ! 720: header_count * sizeof (struct header_info)); ! 721: if (!hdrVec) ! 722: _objc_fatal ("unable to allocate module vector"); ! 723: ! 724: for (hidx = 0; hidx < header_count; hidx++) ! 725: { ! 726: int size; ! 727: const struct segment_command *objcSeg; ! 728: ! 729: hdrVec[hidx].mhdr = machhdrs[hidx]; ! 730: hdrVec[hidx].image_slide = 0; ! 731: hdrVec[hidx].mod_ptr = (Module) getsectdatafromheader (machhdrs[hidx], ! 732: SEG_OBJC, SECT_OBJC_MODULES, &size); ! 733: hdrVec[hidx].mod_count = size / sizeof (struct objc_module); ! 734: hdrVec[hidx].frozenTable = getsectdatafromheader (machhdrs[hidx], ! 735: SEG_OBJC, "__runtime_setup", &size); ! 736: objcSeg = getobjcsegmentfromheader (machhdrs[hidx]); ! 737: if (objcSeg) ! 738: hdrVec[hidx].objcSize = objcSeg->filesize; ! 739: else ! 740: hdrVec[hidx].objcSize = 0; ! 741: } ! 742: ! 743: /* Sort the headers for _objc_map_selectors(). */ ! 744: qsort (hdrVec, header_count, sizeof (struct header_info), &compareHeaders); ! 745: ! 746: return hdrVec; ! 747: } ! 748: ! 749: ! 750: unsigned int _objc_headerCount (void) ! 751: { ! 752: return header_count; ! 753: } ! 754: ! 755: ! 756: void _objc_addHeader (const struct mach_header *header, long vmaddr_slide) ! 757: { ! 758: header_count++; ! 759: if (header_vector == 0) ! 760: header_vector = NXZoneMalloc (_objc_create_zone(), ! 761: header_count * sizeof (struct header_info)); ! 762: else ! 763: { ! 764: void *old = (void*)header_vector; ! 765: header_vector = NXZoneMalloc (_objc_create_zone(), ! 766: header_count * sizeof (struct header_info)); ! 767: ! 768: memcpy ((void*)header_vector, old, (header_count-1) * sizeof (struct header_info)); ! 769: NXZoneFree (_objc_create_zone(), old); ! 770: // header_vector = NXZoneRealloc (_objc_create_zone(), header_vector, ! 771: // header_count * sizeof (struct header_info)); ! 772: } ! 773: ! 774: header_vector[header_count - 1].mhdr = header; ! 775: header_vector[header_count - 1].mod_ptr = NULL; ! 776: header_vector[header_count - 1].mod_count = 0; ! 777: header_vector[header_count - 1].frozenTable = NULL; ! 778: header_vector[header_count - 1].image_slide = 0; ! 779: header_vector[header_count - 1].objcSize = 0; ! 780: } ! 781: ! 782: ! 783: void _objc_removeHeader (const struct mach_header *header) ! 784: { ! 785: unsigned int i, j; ! 786: ! 787: for (i = 0; i < header_count; i++) ! 788: if (header_vector[i].mhdr == header) ! 789: for (j = i; j < header_count - 1; j++) ! 790: header_vector[j] = header_vector[j + 1]; ! 791: ! 792: header_count--; ! 793: header_vector = NXZoneRealloc (_objc_create_zone(), header_vector, ! 794: header_count * sizeof (struct header_info)); ! 795: } ! 796: ! 797: ! 798: /* Register all of the selectors in each image, and fix them all up. ! 799: We must register all images which have freeze-dried hashtables before any ! 800: which don't, since the freeze-dried hashtables are searched before the ! 801: dynamic hashtable. We also want to register the freeze-dried hashtables ! 802: in decreasing order of size to minimize selector lookup time. We don't ! 803: need to fixup the selectors in the first image we register, since those ! 804: strings will always be used. If the first image has a freeze-dried ! 805: hashtable, then we don't need to run over its selectors at all, since ! 806: we can register them all at once. */ ! 807: ! 808: static void _objc_map_install_selectors (struct header_info* hi) ! 809: { ! 810: Module mods = hi->mod_ptr; ! 811: unsigned int midx; ! 812: unsigned int size; ! 813: ! 814: /* Register selectors from freeze-dried hashtables. */ ! 815: if (hi->frozenTable) ! 816: { ! 817: const char *strings = (const char *) ! 818: getsectdatafromheaderinfo (hi, ! 819: SEG_OBJC, "__meth_var_names", &size); ! 820: ! 821: if (!strings) ! 822: { ! 823: /* Try old-style strings. */ ! 824: strings = (const char *) ! 825: getsectdatafromheaderinfo (hi, ! 826: SEG_OBJC, ! 827: "__selector_strs", &size); ! 828: } ! 829: ! 830: _sel_init (hi->mhdr, ! 831: strings, ! 832: size, ! 833: hi->frozenTable); ! 834: } ! 835: } ! 836: ! 837: static void _objc_map_selectors_from_image (struct header_info* hi) ! 838: { ! 839: Module mods = hi->mod_ptr; ! 840: unsigned int midx; ! 841: unsigned int size; ! 842: SEL *messages_refs; ! 843: struct proto_template { @defs (Protocol) } *protos; ! 844: ! 845: /* Map message refs. */ ! 846: messages_refs = (SEL *) getsectdatafromheaderinfo (hi, ! 847: SEG_OBJC, ! 848: "__message_refs", ! 849: &size); ! 850: if (messages_refs) ! 851: map_selrefs (messages_refs, size / sizeof (SEL)); ! 852: ! 853: for (midx = 0; midx < hi->mod_count; midx++) ! 854: { ! 855: unsigned int i; ! 856: struct objc_method_list* mlist; ! 857: ! 858: if (mods[midx].symtab == NULL) ! 859: continue; ! 860: ! 861: /* Map class defs. */ ! 862: for (i = 0; i < mods[midx].symtab->cls_def_cnt; i++) ! 863: { ! 864: Class cls = mods[midx].symtab->defs[i]; ! 865: ! 866: if (cls->methods) ! 867: { ! 868: mlist = cls->methods; ! 869: while (mlist->method_next) mlist = mlist->method_next; ! 870: map_methods (mlist); ! 871: } ! 872: ! 873: if (cls->isa->methods) ! 874: { ! 875: mlist = cls->isa->methods; ! 876: while (mlist->method_next) mlist = mlist->method_next; ! 877: map_methods (mlist); ! 878: } ! 879: } ! 880: ! 881: /* Map category defs. */ ! 882: for (i = mods[midx].symtab->cls_def_cnt; ! 883: i < (mods[midx].symtab->cls_def_cnt + ! 884: mods[midx].symtab->cat_def_cnt); ! 885: i++) ! 886: { ! 887: Category cat = mods[midx].symtab->defs[i]; ! 888: ! 889: if (cat->instance_methods) ! 890: map_methods (cat->instance_methods); ! 891: if (cat->class_methods) ! 892: map_methods (cat->class_methods); ! 893: } ! 894: } ! 895: ! 896: /* Fixup protocols. */ ! 897: protos = (struct proto_template *) getsectdatafromheaderinfo ( hi, ! 898: SEG_OBJC, ! 899: "__protocol", ! 900: &size); ! 901: if (protos) ! 902: { ! 903: unsigned int i; ! 904: ! 905: for (i = 0; i < size / sizeof (Protocol); i++) ! 906: { ! 907: if (protos[i].instance_methods) ! 908: map_method_descs (protos[i].instance_methods); ! 909: if (protos[i].class_methods) ! 910: map_method_descs (protos[i].class_methods); ! 911: } ! 912: } ! 913: } ! 914: ! 915: #if 0 ! 916: /* ! 917: * Purpose: The idea here is to call objc_msgSend() with the ! 918: * arguments in args. The args must already be in the ! 919: * appropriate format for the stack (perhaps copied ! 920: * form some other stack frame). ! 921: * ! 922: * The final call to objc_msgSend () is thus equivalent to ! 923: * objc_msgSend (self, op, arg[0], arg[1], ..., arg[size - 1]). ! 924: * ! 925: * Assumptions: Do not compile this with -fomit-frame-pointer! ! 926: */ ! 927: id objc_msgSendv (id self, SEL sel, unsigned size, marg_list args) ! 928: { ! 929: unsigned int i; ! 930: ! 931: size -= (sizeof(id) + sizeof(SEL)); ! 932: args += (sizeof(id) + sizeof(SEL)); ! 933: ! 934: #ifdef m68k ! 935: /* Push the args onto the stack. */ ! 936: for (i = (size + 1) / sizeof (short); i > 0; i--) ! 937: asm ("movew %0,sp@-" : : "a" (((short *) args)[i-1])); ! 938: #else ! 939: panic ("objc_msgSendv"); ! 940: #endif ! 941: return objc_msgSend (self, sel); ! 942: } ! 943: #endif ! 944: ! 945: static void _objc_call_loads_for_image (struct header_info* header) ! 946: { ! 947: extern IMP class_lookupMethodInMethodList(struct objc_method_list *mlist, ! 948: SEL sel); ! 949: Class class, *pClass; ! 950: Category *pCategory; ! 951: IMP load_method; ! 952: struct objc_method_list *methods; ! 953: unsigned int nModules, nClasses, nCategories; ! 954: struct objc_module *module; ! 955: struct objc_symtab *symtab; ! 956: ! 957: for (nModules = header->mod_count, module = header->mod_ptr; ! 958: nModules; ! 959: nModules--, module++) { ! 960: ! 961: symtab = module->symtab; ! 962: if (symtab == NULL) ! 963: continue; ! 964: for (nClasses = symtab->cls_def_cnt, pClass = (Class *)symtab->defs; ! 965: nClasses; ! 966: nClasses--, pClass++) ! 967: { ! 968: class = *pClass; ! 969: ! 970: if (methods = class->isa->methods) ! 971: { ! 972: while (methods->method_next) ! 973: methods = methods->method_next; ! 974: ! 975: load_method = class_lookupMethodInMethodList(methods, ! 976: @selector(load)); ! 977: if (load_method) ! 978: (*load_method)((id)class, @selector(load)); ! 979: } ! 980: } ! 981: ! 982: for (nCategories = symtab->cat_def_cnt, ! 983: pCategory = (Category *)&symtab->defs[symtab->cls_def_cnt]; ! 984: nCategories; ! 985: nCategories--, pCategory++) ! 986: { ! 987: class = objc_getClass ((*pCategory)->class_name); ! 988: ! 989: if (methods = (*pCategory)->class_methods) ! 990: { ! 991: load_method = class_lookupMethodInMethodList(methods, ! 992: @selector(load)); ! 993: if (load_method) ! 994: (*load_method)((id)class, @selector(load)); ! 995: } ! 996: } ! 997: } ! 998: } ! 999: ! 1000: ! 1001: void objc_setMultithreaded (BOOL flag) ! 1002: { ! 1003: if (flag == YES) ! 1004: _objc_multithread_mask = 0; ! 1005: else ! 1006: _objc_multithread_mask = -1; ! 1007: } ! 1008: ! 1009: ! 1010: static void ! 1011: _objc_map_image_callback (struct header_info *h); ! 1012: ! 1013: void _objcInit (void) ! 1014: { ! 1015: int hidx; ! 1016: class_hash = _objc_init_class_hash(); ! 1017: ! 1018: { ! 1019: extern struct mach_header **getmachheaders (void); ! 1020: struct mach_header **machheaders; ! 1021: ! 1022: if ((machheaders = getmachheaders())) { ! 1023: int i = -1; ! 1024: header_vector = _objc_headerVector( machheaders ); ! 1025: while ( ++i < header_count ) ! 1026: _objc_map_install_selectors (&header_vector[i]); ! 1027: ! 1028: i = -1; ! 1029: while ( ++i < header_count ) ! 1030: _objc_map_image_callback (&header_vector[i]); ! 1031: ! 1032: free (machheaders); ! 1033: } ! 1034: ! 1035: for (hidx = 0; hidx < header_count; hidx++) ! 1036: { ! 1037: int nModules, i; ! 1038: struct objc_module* module; ! 1039: ! 1040: for (nModules = header_vector[hidx].mod_count, module = header_vector[hidx]. mod_ptr; ! 1041: nModules; ! 1042: nModules--, module++) ! 1043: { ! 1044: for (i = 0; i < module->symtab->cls_def_cnt; i++) ! 1045: { ! 1046: Class cls = (Class)module->symtab->defs[i]; ! 1047: _class_install_relationships (cls, module->version); ! 1048: } ! 1049: } ! 1050: ! 1051: #ifdef LITERAL_STRING_OBJECTS ! 1052: _objc_fixup_string_objects_for_image (&header_vector[hidx]); ! 1053: #endif /* LITERAL_STRING_OBJECTS */ ! 1054: #ifdef OBJC_CLASS_REFS ! 1055: _objc_map_class_refs_for_image (&header_vector[hidx]); ! 1056: #endif /* OBJC_CLASS_REFS */ ! 1057: } ! 1058: ! 1059: for (hidx = 0; hidx < header_count; hidx++) ! 1060: _objc_fixup_protocol_objects_for_image (&header_vector[hidx]); ! 1061: ! 1062: for (hidx = 0; hidx < header_count; hidx++) ! 1063: _objc_call_loads_for_image (&header_vector[hidx]); ! 1064: } ! 1065: } ! 1066: ! 1067: static void ! 1068: _objc_map_image_callback (struct header_info *h ) ! 1069: { ! 1070: class_hash = _objc_get_classes_from_image (class_hash, h); ! 1071: ! 1072: _objc_map_selectors_from_image (h); ! 1073: _objc_add_categories_from_image (h); ! 1074: } ! 1075: ! 1076:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.