|
|
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-load.m ! 26: * Copyright 1988, NeXT, Inc. ! 27: * Author: s. naroff ! 28: * ! 29: */ ! 30: #ifdef SHLIB ! 31: #import "shlib.h" ! 32: #endif SHLIB ! 33: ! 34: #import "objc-private.h" ! 35: #import "objc-load.h" ! 36: #import "objc-runtime.h" ! 37: #import "hashtable.h" ! 38: #import "Object.h" ! 39: #import "Protocol.h" ! 40: #include <NXString.h> ! 41: #include <mach-o/rld.h> ! 42: ! 43: #ifdef RUNTIME_DYLD ! 44: #include <mach-o/dyld.h> ! 45: #endif ! 46: ! 47: #ifdef KERNEL ! 48: extern char *getsectdatafromheader( ! 49: const struct mach_header *mhp, ! 50: const char *segname, ! 51: const char *sectname, ! 52: int *size); ! 53: #endif ! 54: ! 55: @interface Protocol(Private) ! 56: + _fixup: (void *)protos numElements: (int) nentries; ! 57: @end ! 58: ! 59: /* Private extern */ ! 60: extern struct mach_header *rld_get_current_header(void); ! 61: extern void (*callbackFunction)( Class, Category ); ! 62: ! 63: static inline void map_selrefs (SEL *sels, unsigned int cnt) ! 64: { ! 65: unsigned int i; ! 66: ! 67: /* Overwrite the string with a unique identifier. */ ! 68: for (i = 0; i < cnt; i++) ! 69: { ! 70: SEL sel = sel_registerName ((const char *) sels[i]); ! 71: ! 72: if (sels[i] != sel) ! 73: sels[i] = sel; ! 74: } ! 75: } ! 76: ! 77: ! 78: static inline void map_methods (struct objc_method_list *methods) ! 79: { ! 80: unsigned int i; ! 81: ! 82: for (i = 0; i < methods->method_count; i++) ! 83: { ! 84: Method method = &methods->method_list[i]; ! 85: SEL sel = sel_registerName ((const char *) method->method_name); ! 86: ! 87: if (method->method_name != sel) ! 88: method->method_name = sel; ! 89: } ! 90: } ! 91: ! 92: ! 93: static inline void map_method_descs (struct objc_method_description_list *methods) ! 94: { ! 95: unsigned int i; ! 96: ! 97: for (i = 0; i < methods->count; i++) ! 98: { ! 99: struct objc_method_description *method = &methods->list[i]; ! 100: SEL sel = sel_registerName ((const char *) method->name); ! 101: ! 102: if (method->name != sel) ! 103: method->name = sel; ! 104: } ! 105: } ! 106: ! 107: ! 108: static struct objc_method_list *get_base_method_list(Class cls) ! 109: { ! 110: struct objc_method_list *mlist, *prev = 0; ! 111: ! 112: for (mlist = cls->methods; mlist; mlist = mlist->method_next) ! 113: prev = mlist; ! 114: ! 115: return prev; ! 116: } ! 117: ! 118: static void send_load_message_to_class(Class cls, void *header_addr) ! 119: { ! 120: struct objc_method_list *mlist = get_base_method_list(cls->isa); ! 121: IMP load_method; ! 122: ! 123: if (mlist) { ! 124: load_method = ! 125: class_lookupMethodInMethodList(mlist, ! 126: @selector(finishLoading:)); ! 127: ! 128: /* go directly there, we do not want to accidentally send ! 129: the finishLoading: message to one of its categories... ! 130: */ ! 131: if (load_method) ! 132: (*load_method)((id)cls, @selector(finishLoading:), ! 133: header_addr); ! 134: } ! 135: } ! 136: ! 137: static void send_load_message_to_category(Category cat, void *header_addr) ! 138: { ! 139: struct objc_method_list *mlist = cat->class_methods; ! 140: IMP load_method; ! 141: Class cls; ! 142: ! 143: if (mlist) { ! 144: load_method = ! 145: class_lookupMethodInMethodList(mlist, ! 146: @selector(finishLoading:)); ! 147: ! 148: cls = objc_getClass (cat->class_name); ! 149: ! 150: /* go directly there, we do not want to accidentally send ! 151: the finishLoading: message to one of its categories... ! 152: */ ! 153: if (load_method) ! 154: (*load_method)(cls, @selector(finishLoading:), ! 155: header_addr); ! 156: } ! 157: } ! 158: ! 159: static void send_unload_message_to_class(Class cls) ! 160: { ! 161: struct objc_method_list *mlist = get_base_method_list(cls->isa); ! 162: IMP load_method; ! 163: ! 164: if (mlist) { ! 165: load_method = ! 166: class_lookupMethodInMethodList(mlist, ! 167: @selector(startUnloading)); ! 168: ! 169: /* go directly there, we do not want to accidentally send ! 170: the finishLoading: message to one of its categories... ! 171: */ ! 172: if (load_method) ! 173: (*load_method)((id)cls, ! 174: @selector(startUnloading)); ! 175: } ! 176: } ! 177: ! 178: static void send_unload_message_to_category(Category cat) ! 179: { ! 180: struct objc_method_list *mlist = cat->class_methods; ! 181: IMP load_method; ! 182: Class cls; ! 183: ! 184: if (mlist) { ! 185: load_method = ! 186: class_lookupMethodInMethodList(mlist, ! 187: @selector(startUnloading)); ! 188: ! 189: cls = objc_getClass (cat->class_name); ! 190: ! 191: /* go directly there, we do not want to accidentally send ! 192: the finishLoading: message to one of its categories... ! 193: */ ! 194: if (load_method) ! 195: (*load_method)((id)cls, ! 196: @selector(startUnloading)); ! 197: } ! 198: } ! 199: ! 200: static void _objc_fixup_string_objects_from_header(struct mach_header *header) ! 201: { ! 202: NXConstantString *section; ! 203: unsigned int size; ! 204: ! 205: section = (NXConstantString *) getsectdatafromheader (header, ! 206: SEG_OBJC, "__string_object", &size); ! 207: if (section != 0 && size != 0) ! 208: { ! 209: Class constantStringClass = objc_getClass ("NXConstantString"); ! 210: unsigned int i; ! 211: ! 212: for (i = 0; i < size / sizeof (NXConstantString); i++) ! 213: *((Class *) §ion[i]) = constantStringClass; ! 214: } ! 215: } ! 216: ! 217: ! 218: int objc_registerModule (struct mach_header *header_addr, ! 219: void (*class_callback) (Class, Category)) ! 220: { ! 221: Module mod, modhdr; ! 222: int size, saveSize, i; ! 223: SEL *sels; ! 224: // this isn't very object oriented!...bypass ivar protection. ! 225: struct proto_template { @defs(Protocol) } *protos; ! 226: Class *cls_refs; ! 227: int errflag = 0; ! 228: ! 229: #ifdef RUNTIME_DYLD ! 230: if (_dyld_present ()) ! 231: { ! 232: fprintf (stderr, "objc_registerModule not supported in dynamic programs\n"); ! 233: return 1; ! 234: } ! 235: #endif ! 236: ! 237: modhdr = (Module) getsectdatafromheader (header_addr, ! 238: SEG_OBJC, "__module_info", &saveSize); ! 239: ! 240: /* Check for duplicate classes. ! 241: This should never happen since rld should detect multiple ! 242: definitions of the .objc_class_name_XXX symbols. */ ! 243: for (mod = modhdr, size = saveSize; ! 244: mod && size; ! 245: size -= mod->size, (char *) mod += mod->size) ! 246: { ! 247: for (i = 0; i < mod->symtab->cls_def_cnt; i++) ! 248: { ! 249: Class cls = mod->symtab->defs[i]; ! 250: ! 251: if ((cls = objc_lookUpClass (mod->symtab->defs[i]))) ! 252: { ! 253: #if 0 ! 254: NXPrintf (errStream, "objc_loadModules(): " ! 255: "Duplicate definition for class `%s'\n", ! 256: [cls name]); ! 257: #endif ! 258: errflag = 1; ! 259: } ! 260: } ! 261: } ! 262: ! 263: if (errflag) ! 264: return 1; ! 265: ! 266: _objc_addHeader (header_addr, 0); ! 267: ! 268: /* Fixup string objects. */ ! 269: _objc_fixup_string_objects_from_header (header_addr); ! 270: ! 271: /* Map selectors. */ ! 272: sels = (SEL *) getsectdatafromheader (header_addr, ! 273: SEG_OBJC, "__message_refs", &size); ! 274: if (sels) ! 275: map_selrefs (sels, size / sizeof (SEL)); ! 276: ! 277: /* Fixup protocol objects. */ ! 278: protos = (struct proto_template *) getsectdatafromheader ( ! 279: header_addr, SEG_OBJC, "__protocol", &size); ! 280: if (protos) ! 281: { ! 282: unsigned int i; ! 283: ! 284: for (i = 0; i < size / sizeof (Protocol); i++) { ! 285: ! 286: /* can't use map_methods, the sizes differ. */ ! 287: if (protos[i].instance_methods) ! 288: map_method_descs (protos[i].instance_methods); ! 289: if (protos[i].class_methods) ! 290: map_method_descs (protos[i].class_methods); ! 291: } ! 292: [Protocol _fixup: protos numElements: size / sizeof (Protocol)]; ! 293: } ! 294: ! 295: /* Insert classes into class hashtable */ ! 296: for (mod = modhdr, size = saveSize; ! 297: mod && size; ! 298: size -= mod->size, (char *) mod += mod->size) ! 299: { ! 300: for (i = 0; i < mod->symtab->cls_def_cnt; i++) ! 301: { ! 302: objc_addClass (mod->symtab->defs[i]); ! 303: } ! 304: } ! 305: ! 306: /* Process class definitions. */ ! 307: for (mod = modhdr, size = saveSize; ! 308: mod && size; ! 309: size -= mod->size, (char *) mod += mod->size) ! 310: { ! 311: for (i = 0; i < mod->symtab->cls_def_cnt; i++) ! 312: { ! 313: Class cls = mod->symtab->defs[i]; ! 314: ! 315: if (cls->methods) ! 316: map_methods (cls->methods); ! 317: if (cls->isa->methods) ! 318: map_methods (cls->isa->methods); ! 319: ! 320: _class_install_relationships (cls, mod->version); ! 321: ! 322: /* Versions 3 and 4 will never ship; internal compatibility only. ! 323: Compensate for "next" field in struct objc_protocol_list. */ ! 324: if (cls->isa->version >= 3 && cls->isa->version <= 4 ! 325: && cls->protocols) ! 326: { ! 327: (char *) cls->protocols -= 4; ! 328: (char *) cls->isa->protocols -= 4; ! 329: } ! 330: ! 331: /* for internal compatibility...should remove! */ ! 332: if ((cls->isa->version == 3) && cls->protocols) ! 333: { ! 334: _objc_inform ("Unable to install protocols by name...\n"); ! 335: _objc_inform ("Class %s must be recompiled.\n", ! 336: cls->name); ! 337: cls->protocols = 0; ! 338: cls->isa->protocols = 0; ! 339: } ! 340: } ! 341: } ! 342: ! 343: /* We must process all classes before any categories, or else ! 344: we might map the selectors for a category method twice. */ ! 345: ! 346: /* Process category definitions. */ ! 347: for (mod = modhdr, size = saveSize; ! 348: mod && size; ! 349: size -= mod->size, (char *) mod += mod->size) ! 350: { ! 351: for (i = mod->symtab->cls_def_cnt; ! 352: i < mod->symtab->cls_def_cnt + mod->symtab->cat_def_cnt; ! 353: i++) ! 354: { ! 355: Category cat = mod->symtab->defs[i]; ! 356: ! 357: if (cat->instance_methods) ! 358: map_methods (cat->instance_methods); ! 359: if (cat->class_methods) ! 360: map_methods (cat->class_methods); ! 361: ! 362: _objc_add_category (mod->symtab->defs[i], mod->version); ! 363: } ! 364: } ! 365: ! 366: /* Handle v1.0 mapping of selector references */ ! 367: for (mod = modhdr, size = saveSize; ! 368: mod && size; ! 369: size -= mod->size, (char *) mod += mod->size) ! 370: { ! 371: if (mod->version == 1) ! 372: map_selrefs (mod->symtab->refs, mod->symtab->sel_ref_cnt); ! 373: } ! 374: ! 375: #ifdef OBJC_CLASS_REFS ! 376: /* Fixup class references. */ ! 377: cls_refs = (Class *) getsectdatafromheader ( ! 378: header_addr, SEG_OBJC, "__cls_refs", &size); ! 379: if (cls_refs) ! 380: { ! 381: unsigned int i; ! 382: ! 383: for (i = 0; i < size / sizeof (Class); i++) ! 384: cls_refs[i] = objc_getClass ((const char *) cls_refs[i]); ! 385: } ! 386: #endif /* OBJC_CLASS_REFS */ ! 387: ! 388: /* Do we guarantee any ordering of load messages? ! 389: We might send a load message to a subclass before its superclass. ! 390: ! 391: Also, a load method might send a message to a class which hasn't ! 392: received its load message yet by using objc_getClass (). ! 393: ! 394: To solve these problems properly, we probably need to add a ! 395: "loaded" bit to the class structure in addition to the ! 396: "initialized" bit. */ ! 397: ! 398: /* Send load messages and activate call backs to classes. */ ! 399: for (mod = modhdr, size = saveSize; ! 400: mod && size; ! 401: size -= mod->size, (char *) mod += mod->size) ! 402: { ! 403: for (i = 0; i < mod->symtab->cls_def_cnt; i++) ! 404: { ! 405: if (class_callback) ! 406: (*class_callback) (mod->symtab->defs[i], 0); ! 407: ! 408: send_load_message_to_class (mod->symtab->defs[i], ! 409: header_addr); ! 410: } ! 411: } ! 412: ! 413: /* Send load messages and activate call backs to categories. */ ! 414: for (mod = modhdr, size = saveSize; ! 415: mod && size; ! 416: size -= mod->size, (char *) mod += mod->size) ! 417: { ! 418: for (i = mod->symtab->cls_def_cnt; ! 419: i < mod->symtab->cls_def_cnt + mod->symtab->cat_def_cnt; ! 420: i++) ! 421: { ! 422: if (class_callback) ! 423: (*class_callback) (objc_getClass(((Category)mod->symtab->defs[i])->class_name), ! 424: (Category)mod->symtab->defs[i]); ! 425: ! 426: send_load_message_to_category((Category)mod->symtab->defs[i], ! 427: header_addr); ! 428: } ! 429: } ! 430: ! 431: return 0; ! 432: } ! 433: ! 434: ! 435: #ifndef KERNEL ! 436: static ! 437: #endif ! 438: void objc_unregisterModule (struct mach_header *header_addr, ! 439: void (*unload_callback) (Class, Category)) ! 440: { ! 441: Module mod, modhdr; ! 442: int size, i, saveSize, strsize; ! 443: const char *strs; ! 444: ! 445: #ifdef RUNTIME_DYLD ! 446: if (_dyld_present ()) ! 447: { ! 448: fprintf (stderr, "objc_unregisterModule not supported in dynamic programs\n"); ! 449: return; ! 450: } ! 451: #endif ! 452: ! 453: ! 454: modhdr = (Module) getsectdatafromheader (header_addr, ! 455: SEG_OBJC, "__module_info", &saveSize); ! 456: ! 457: /* Send unload messages and deactivate call backs to categories. */ ! 458: for (mod = modhdr, size = saveSize; ! 459: mod && size; ! 460: size -= mod->size, (char *) mod += mod->size) ! 461: { ! 462: for (i = mod->symtab->cls_def_cnt; ! 463: i < mod->symtab->cls_def_cnt + mod->symtab->cat_def_cnt; ! 464: i++) ! 465: { ! 466: Category cat = mod->symtab->defs[i]; ! 467: ! 468: if (unload_callback) ! 469: (*unload_callback) (objc_getClass (cat->class_name), cat); ! 470: ! 471: send_unload_message_to_category (cat); ! 472: } ! 473: } ! 474: ! 475: /* Send unload messages and deactivate call backs to classes. */ ! 476: for (mod = modhdr, size = saveSize; ! 477: mod && size; ! 478: size -= mod->size, (char *) mod += mod->size) ! 479: { ! 480: for (i = 0; i < mod->symtab->cls_def_cnt; i++) ! 481: { ! 482: Class cls = mod->symtab->defs[i]; ! 483: ! 484: if (unload_callback) ! 485: (*unload_callback) (cls, 0); ! 486: ! 487: send_unload_message_to_class (cls); ! 488: } ! 489: } ! 490: ! 491: /* Remove categories. */ ! 492: for (mod = modhdr, size = saveSize; ! 493: mod && size; ! 494: size -= mod->size, (char *) mod += mod->size) ! 495: { ! 496: for (i = mod->symtab->cls_def_cnt; ! 497: i < mod->symtab->cls_def_cnt + mod->symtab->cat_def_cnt; ! 498: i++) ! 499: { ! 500: Category cat = mod->symtab->defs[i]; ! 501: ! 502: _objc_remove_category (cat, mod->version); ! 503: } ! 504: } ! 505: ! 506: /* Remove classes. */ ! 507: for (mod = modhdr, size = saveSize; ! 508: mod && size; ! 509: size -= mod->size, (char *) mod += mod->size) ! 510: { ! 511: for (i = 0; i < mod->symtab->cls_def_cnt; i++) ! 512: { ! 513: Class cls = mod->symtab->defs[i]; ! 514: ! 515: _objc_removeClass (cls); ! 516: } ! 517: } ! 518: ! 519: /* Do we really want to do this? ! 520: What if I load Foo.o which contains a new selector "foo", ! 521: then I unload Foo.o and load Bar.o which also contains the ! 522: selector "foo". The value of the selector may change! ! 523: I think that selector mappings need to be permanent. */ ! 524: ! 525: /* Unload any selectors that might have been unique to this module. */ ! 526: strs = (const char *) getsectdatafromheader (header_addr, ! 527: SEG_OBJC, "__meth_var_names", &strsize); ! 528: ! 529: if (strs) ! 530: _sel_unloadSelectors (strs, strs + strsize); ! 531: ! 532: /* Unload old-style strings too. */ ! 533: strs = (const char *) getsectdatafromheader (header_addr, ! 534: SEG_OBJC, "__selector_strs", &strsize); ! 535: ! 536: if (strs) ! 537: _sel_unloadSelectors (strs, strs + strsize); ! 538: ! 539: _objc_removeHeader (header_addr); ! 540: } ! 541: ! 542: ! 543: #ifndef KERNEL ! 544: ! 545: /* Lock for dynamic loading and unloading. */ ! 546: ! 547: static OBJC_DECLARE_LOCK (loadLock); ! 548: ! 549: /* Loading isn't really thread safe. If a load message recursively calls ! 550: objc_loadModules() both sets will be loaded correctly, but if the original ! 551: caller calls objc_unloadModules() it will probably unload the wrong modules. ! 552: If a load message calls objc_unloadModules(), then it will unload ! 553: the modules currently being loaded, which will probably cause a crash. */ ! 554: ! 555: /* Error handling is still somewhat crude. If we encounter errors while ! 556: linking up classes or categories, we will not recover correctly. ! 557: Hopefully rld_load () will detect these problems for us. */ ! 558: ! 559: /* I removed atempts to lock the class hashtable, since this introduced ! 560: deadlock which was hard to remove. The only way you can get into trouble ! 561: is if one thread loads a module while another thread tries to access the ! 562: loaded classes (using objc_lookUpClass) before the load is complete. */ ! 563: ! 564: long objc_loadModules ( ! 565: char *modlist[], ! 566: NXStream *errStream, ! 567: void (*class_callback) (Class, Category), ! 568: struct mach_header **hdr_addr, ! 569: char *debug_file) ! 570: { ! 571: struct mach_header *header_addr; ! 572: int errflag = 0; ! 573: ! 574: #ifdef RUNTIME_DYLD ! 575: if (_dyld_present ()) ! 576: { ! 577: NSObjectFileImage objectFileImage; ! 578: NSModule module; ! 579: ! 580: char **modules; ! 581: ! 582: callbackFunction = class_callback; ! 583: for (modules = &modlist[0]; *modules != 0; modules++) ! 584: { ! 585: NSObjectFileImageReturnCode code ! 586: = NSCreateObjectFileImageFromFile (*modules, &objectFileImage); ! 587: ! 588: if (code != NSObjectFileImageSuccess) ! 589: { ! 590: if (errStream) ! 591: NXPrintf (errStream, ! 592: "objc_loadModules(%s) NSObjectFileImageReturnCode = %d\n", *modules, code); ! 593: ! 594: errflag = 1; ! 595: continue; ! 596: } ! 597: ! 598: module = NSLinkModule(objectFileImage, *modules, 0); ! 599: } ! 600: callbackFunction = 0; ! 601: } ! 602: else ! 603: #endif ! 604: ! 605: { ! 606: ! 607: OBJC_LOCK (&loadLock); ! 608: ! 609: if (rld_load (errStream, &header_addr, modlist, debug_file)) ! 610: { ! 611: errflag = objc_registerModule (header_addr, class_callback); ! 612: ! 613: /* Unload everything on errors. */ ! 614: if (errflag) ! 615: rld_unload (errStream); ! 616: else ! 617: { ! 618: /* Return optional output parameter */ ! 619: if (hdr_addr) ! 620: *hdr_addr = header_addr; ! 621: } ! 622: } ! 623: else ! 624: errflag = 1; ! 625: ! 626: OBJC_UNLOCK (&loadLock); ! 627: } ! 628: ! 629: return errflag; ! 630: } ! 631: ! 632: ! 633: /* Unloading isn't really thread safe. If an unload message calls ! 634: objc_loadModules() or objc_unloadModules(), then the current call ! 635: to objc_unloadModules() will probably unload the wrong stuff. */ ! 636: ! 637: long objc_unloadModules ( ! 638: NXStream *errStream, ! 639: void (*unload_callback) (Class, Category)) ! 640: { ! 641: struct mach_header *header_addr = rld_get_current_header (); ! 642: int errflag = 0; ! 643: ! 644: if (header_addr) ! 645: { ! 646: objc_unregisterModule (header_addr, unload_callback); ! 647: ! 648: OBJC_LOCK (&loadLock); ! 649: ! 650: if (rld_unload (errStream) == 0) ! 651: errflag = 1; ! 652: ! 653: OBJC_UNLOCK (&loadLock); ! 654: } ! 655: else ! 656: { ! 657: NXPrintf (errStream, "objc_unloadModules(): No modules to unload\n"); ! 658: errflag = 1; ! 659: } ! 660: ! 661: return errflag; ! 662: } ! 663: ! 664: #endif /* not KERNEL */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.