]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-runtime.m
objc4-371.2.tar.gz
[apple/objc4.git] / runtime / objc-runtime.m
CommitLineData
13d88034 1/*
b3962a83 2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
390d5862 3 *
b3962a83 4 * @APPLE_LICENSE_HEADER_START@
390d5862
A
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13d88034 13 * The Original Code and all software distributed under the License are
390d5862 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
13d88034
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
390d5862
A
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
13d88034
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/***********************************************************************
41c8faa5
A
24* objc-runtime.m
25* Copyright 1988-1996, NeXT Software, Inc.
26* Author: s. naroff
27*
28**********************************************************************/
13d88034 29
2bfd4448
A
30
31
13d88034 32/***********************************************************************
41c8faa5
A
33* Imports.
34**********************************************************************/
13d88034 35
13d88034
A
36#include <mach-o/ldsyms.h>
37#include <mach-o/dyld.h>
2bfd4448 38#include <mach-o/dyld_gdb.h>
b3962a83 39#include <mach-o/dyld_priv.h>
2bfd4448
A
40#include <mach/mach.h>
41#include <mach/mach_error.h>
13d88034
A
42#include <sys/time.h>
43#include <sys/resource.h>
2bfd4448
A
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <fcntl.h>
b3962a83
A
47#include <crt_externs.h>
48#include <libgen.h>
2bfd4448 49
b3962a83
A
50#include <crt_externs.h>
51#include <libgen.h>
41c8faa5 52
b3962a83
A
53#import "objc-private.h"
54#import "hashtable2.h"
55#import "maptable.h"
56#import "Object.h"
57#import "objc-rtp.h"
58#import "objc-auto.h"
59#import "objc-loadmethod.h"
2bfd4448 60
b3962a83 61OBJC_EXPORT Class getOriginalClassForPosingClass(Class);
2bfd4448
A
62
63
64/***********************************************************************
b3962a83 65* Exports.
2bfd4448 66**********************************************************************/
2bfd4448 67
b3962a83
A
68// Settings from environment variables
69__private_extern__ int PrintImages = -1; // env OBJC_PRINT_IMAGES
70__private_extern__ int PrintLoading = -1; // env OBJC_PRINT_LOAD_METHODS
71__private_extern__ int PrintInitializing = -1; // env OBJC_PRINT_INITIALIZE_METHODS
72__private_extern__ int PrintResolving = -1; // env OBJC_PRINT_RESOLVED_METHODS
73__private_extern__ int PrintConnecting = -1; // env OBJC_PRINT_CLASS_SETUP
74__private_extern__ int PrintProtocols = -1; // env OBJC_PRINT_PROTOCOL_SETUP
75__private_extern__ int PrintIvars = -1; // env OBJC_PRINT_IVAR_SETUP
76__private_extern__ int PrintFuture = -1; // env OBJC_PRINT_FUTURE_CLASSES
77__private_extern__ int PrintRTP = -1; // env OBJC_PRINT_RTP
78__private_extern__ int PrintGC = -1; // env OBJC_PRINT_GC
79__private_extern__ int PrintSharing = -1; // env OBJC_PRINT_SHARING
80__private_extern__ int PrintCxxCtors = -1; // env OBJC_PRINT_CXX_CTORS
81__private_extern__ int PrintExceptions = -1; // env OBJC_PRINT_EXCEPTIONS
82__private_extern__ int PrintAltHandlers = -1; // env OBJC_PRINT_ALT_HANDLERS
83__private_extern__ int PrintDeprecation = -1;// env OBJC_PRINT_DEPRECATION_WARNINGS
84__private_extern__ int PrintReplacedMethods = -1; // env OBJC_PRINT_REPLACED_METHODS
85__private_extern__ int PrintCacheCollection = -1; // env OBJC_PRINT_CACHE_COLLECTION
2bfd4448 86
b3962a83
A
87__private_extern__ int UseInternalZone = -1; // env OBJC_USE_INTERNAL_ZONE
88__private_extern__ int AllowInterposing = -1;// env OBJC_ALLOW_INTERPOSING
2bfd4448 89
b3962a83
A
90__private_extern__ int DebugUnload = -1; // env OBJC_DEBUG_UNLOAD
91__private_extern__ int DebugFragileSuperclasses = -1; // env OBJC_DEBUG_FRAGILE_SUPERCLASSES
92__private_extern__ int DebugNilSync = -1; // env OBJC_DEBUG_NIL_SYNC
2bfd4448 93
b3962a83
A
94__private_extern__ int DisableGC = -1; // env OBJC_DISABLE_GC
95__private_extern__ int DebugFinalizers = -1; // env OBJC_DEBUG_FINALIZERS
2bfd4448 96
2bfd4448 97
b3962a83
A
98// objc's key for pthread_getspecific
99static pthread_key_t _objc_pthread_key = 0;
2bfd4448 100
b3962a83
A
101// Selectors for which @selector() doesn't work
102__private_extern__ SEL cxx_construct_sel = NULL;
103__private_extern__ SEL cxx_destruct_sel = NULL;
104__private_extern__ const char *cxx_construct_name = ".cxx_construct";
105__private_extern__ const char *cxx_destruct_name = ".cxx_destruct";
2bfd4448
A
106
107
108/***********************************************************************
b3962a83 109* Function prototypes internal to this module.
2bfd4448 110**********************************************************************/
2bfd4448 111
b3962a83 112static void _objc_unmap_image(header_info *hi);
2bfd4448 113
2bfd4448 114
b3962a83
A
115/***********************************************************************
116* Static data internal to this module.
117**********************************************************************/
2bfd4448 118
b3962a83
A
119// we keep a linked list of header_info's describing each image as told to us by dyld
120static header_info *FirstHeader NOBSS = 0; // NULL means empty list
121static header_info *LastHeader NOBSS = 0; // NULL means invalid; recompute it
122static int HeaderCount NOBSS = 0;
13d88034 123
2bfd4448 124
13d88034 125/***********************************************************************
b3962a83
A
126* objc_getClass. Return the id of the named class. If the class does
127* not exist, call _objc_classLoader and then objc_classHandler, either of
128* which may create a new class.
129* Warning: doesn't work if aClassName is the name of a posed-for class's isa!
41c8faa5 130**********************************************************************/
b3962a83 131id objc_getClass(const char *aClassName)
13d88034 132{
b3962a83 133 if (!aClassName) return Nil;
41c8faa5 134
b3962a83
A
135 // NO unconnected, YES class handler
136 return look_up_class(aClassName, NO, YES);
13d88034
A
137}
138
2bfd4448 139
13d88034 140/***********************************************************************
b3962a83
A
141* objc_getRequiredClass.
142* Same as objc_getClass, but kills the process if the class is not found.
143* This is used by ZeroLink, where failing to find a class would be a
144* compile-time link error without ZeroLink.
41c8faa5 145**********************************************************************/
b3962a83 146id objc_getRequiredClass(const char *aClassName)
13d88034 147{
b3962a83
A
148 id cls = objc_getClass(aClassName);
149 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
150 return cls;
13d88034
A
151}
152
2bfd4448 153
13d88034 154/***********************************************************************
b3962a83
A
155* objc_lookUpClass. Return the id of the named class.
156* If the class does not exist, call _objc_classLoader, which may create
157* a new class.
158*
159* Formerly objc_getClassWithoutWarning ()
41c8faa5 160**********************************************************************/
b3962a83 161id objc_lookUpClass(const char *aClassName)
13d88034 162{
b3962a83 163 if (!aClassName) return Nil;
13d88034 164
b3962a83
A
165 // NO unconnected, NO class handler
166 return look_up_class(aClassName, NO, NO);
167}
2bfd4448
A
168
169/***********************************************************************
b3962a83
A
170* objc_getFutureClass. Return the id of the named class.
171* If the class does not exist, return an uninitialized class
172* structure that will be used for the class when and if it
173* does get loaded.
174* Not thread safe.
2bfd4448 175**********************************************************************/
b3962a83 176Class objc_getFutureClass(const char *name)
2bfd4448 177{
b3962a83 178 Class cls;
2bfd4448 179
b3962a83
A
180 // YES unconnected, NO class handler
181 // (unconnected is OK because it will someday be the real class)
182 cls = look_up_class(name, YES, NO);
183 if (cls) {
184 if (PrintFuture) {
185 _objc_inform("FUTURE: found %p already in use for %s", cls, name);
2bfd4448 186 }
b3962a83
A
187 return cls;
188 }
189
190 // No class or future class with that name yet. Make one.
191 // fixme not thread-safe with respect to
192 // simultaneous library load or getFutureClass.
193 return _objc_allocateFutureClass(name);
2bfd4448
A
194}
195
196
13d88034 197/***********************************************************************
b3962a83
A
198* objc_getMetaClass. Return the id of the meta class the named class.
199* Warning: doesn't work if aClassName is the name of a posed-for class's isa!
41c8faa5 200**********************************************************************/
b3962a83 201id objc_getMetaClass(const char *aClassName)
41c8faa5 202{
b3962a83 203 Class cls;
41c8faa5 204
b3962a83 205 if (!aClassName) return Nil;
390d5862 206
b3962a83
A
207 cls = objc_getClass (aClassName);
208 if (!cls)
41c8faa5 209 {
b3962a83
A
210 _objc_inform ("class `%s' not linked into application", aClassName);
211 return Nil;
41c8faa5 212 }
2bfd4448 213
b3962a83 214 return ((id)cls)->isa;
13d88034
A
215}
216
217
b3962a83
A
218#if !__LP64__
219// Not updated for 64-bit ABI
220
13d88034 221/***********************************************************************
b3962a83
A
222* _headerForAddress.
223* addr can be a class or a category
41c8faa5 224**********************************************************************/
b3962a83 225static const header_info *_headerForAddress(void *addr)
13d88034 226{
b3962a83
A
227 unsigned long size;
228 unsigned long seg;
229 header_info * hInfo;
390d5862 230
b3962a83
A
231 // Check all headers in the vector
232 for (hInfo = FirstHeader; hInfo != NULL; hInfo = hInfo->next)
41c8faa5 233 {
b3962a83
A
234 // Locate header data, if any
235 if (!hInfo->objcSegmentHeader) continue;
236 seg = hInfo->objcSegmentHeader->vmaddr + hInfo->image_slide;
237 size = hInfo->objcSegmentHeader->filesize;
41c8faa5 238
b3962a83
A
239 // Is the class in this header?
240 if ((seg <= (unsigned long) addr) &&
241 ((unsigned long) addr < (seg + size)))
242 return hInfo;
41c8faa5 243 }
390d5862 244
b3962a83
A
245 // Not found
246 return 0;
13d88034
A
247}
248
b3962a83 249
13d88034 250/***********************************************************************
b3962a83
A
251* _headerForClass
252* Return the image header containing this class, or NULL.
253* Returns NULL on runtime-constructed classes, and the NSCF classes.
41c8faa5 254**********************************************************************/
b3962a83
A
255__private_extern__ const header_info *_headerForClass(Class cls)
256{
257 return _headerForAddress(cls);
258}
259
260// !__LP64__
261#endif
262
13d88034
A
263
264/***********************************************************************
b3962a83 265* _nameForHeader.
41c8faa5 266**********************************************************************/
b3962a83 267__private_extern__ const char *_nameForHeader(const headerType *header)
13d88034 268{
b3962a83
A
269 return _getObjcHeaderName ((headerType *) header);
270}
41c8faa5 271
41c8faa5 272
b3962a83
A
273/***********************************************************************
274* _gcForHInfo.
275**********************************************************************/
276__private_extern__ const char *_gcForHInfo(const header_info *hinfo)
277{
278 if (_objcHeaderRequiresGC(hinfo)) return "requires GC";
279 else if (_objcHeaderSupportsGC(hinfo)) return "supports GC";
280 else return "does not support GC";
281}
282__private_extern__ const char *_gcForHInfo2(const header_info *hinfo)
283{
284 if (_objcHeaderRequiresGC(hinfo)) return " (requires GC)";
285 else if (_objcHeaderSupportsGC(hinfo)) return " (supports GC)";
286 else return "";
287}
41c8faa5 288
41c8faa5 289
b3962a83
A
290/***********************************************************************
291* bad_magic.
292* Return YES if the header has invalid Mach-o magic.
293**********************************************************************/
294static BOOL bad_magic(const headerType *mhdr)
295{
296 return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
297 mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
13d88034
A
298}
299
b3962a83 300
13d88034 301/***********************************************************************
41c8faa5
A
302* _objc_headerStart. Return what headers we know about.
303**********************************************************************/
b3962a83 304__private_extern__ header_info *_objc_headerStart(void)
13d88034 305{
41c8faa5
A
306 // Take advatage of our previous work
307 return FirstHeader;
13d88034
A
308}
309
41c8faa5 310
2bfd4448
A
311/***********************************************************************
312* _objc_addHeader.
b3962a83 313* Returns NULL if the header has no ObjC metadata.
2bfd4448 314**********************************************************************/
41c8faa5 315
2bfd4448
A
316// tested with 2; typical case is 4, but OmniWeb & Mail push it towards 20
317#define HINFO_SIZE 16
390d5862 318
2bfd4448
A
319static int HeaderInfoCounter NOBSS = 0;
320static header_info HeaderInfoTable[HINFO_SIZE] NOBSS = { {0} };
13d88034 321
b3962a83 322static header_info * _objc_addHeader(const headerType *header)
390d5862 323{
b3962a83
A
324 size_t info_size = 0;
325 const segmentType *objc_segment;
326 const segmentType *objc2_segment;
327 const objc_image_info *image_info;
328 const segmentType *data_segment;
2bfd4448 329 header_info *result;
b3962a83
A
330 ptrdiff_t image_slide;
331
332 // Weed out duplicates
333 for (result = FirstHeader; result; result = result->next) {
334 if (header == result->mhdr) return NULL;
335 }
41c8faa5 336
2bfd4448 337 // Locate the __OBJC segment
b3962a83
A
338 image_slide = _getImageSlide(header);
339 image_info = _getObjcImageInfo(header, image_slide, &info_size);
2bfd4448 340 objc_segment = getsegbynamefromheader(header, SEG_OBJC);
b3962a83
A
341 objc2_segment = getsegbynamefromheader(header, SEG_OBJC2);
342 data_segment = getsegbynamefromheader(header, SEG_DATA);
343 if (!objc_segment && !image_info && !objc2_segment) return NULL;
41c8faa5 344
2bfd4448
A
345 // Find or allocate a header_info entry.
346 if (HeaderInfoCounter < HINFO_SIZE) {
347 result = &HeaderInfoTable[HeaderInfoCounter++];
348 } else {
349 result = _malloc_internal(sizeof(header_info));
1f20c7a7 350 }
1f20c7a7 351
2bfd4448
A
352 // Set up the new header_info entry.
353 result->mhdr = header;
b3962a83 354 result->image_slide = image_slide;
2bfd4448 355 result->objcSegmentHeader = objc_segment;
b3962a83
A
356 result->dataSegmentHeader = data_segment;
357#if !__OBJC2__
358 result->mod_count = 0;
359 result->mod_ptr = _getObjcModules(header, result->image_slide, &result->mod_count);
360#endif
361 result->info = image_info;
362 dladdr(result->mhdr, &result->dl_info);
363 result->allClassesRealized = NO;
364
365 // dylibs are not allowed to unload
366 if (result->mhdr->filetype == MH_DYLIB) {
367 dlopen(result->dl_info.dli_fname, RTLD_NOLOAD);
2bfd4448 368 }
1f20c7a7 369
2bfd4448
A
370 // Make sure every copy of objc_image_info in this image is the same.
371 // This means same version and same bitwise contents.
372 if (result->info) {
b3962a83
A
373 const objc_image_info *start = result->info;
374 const objc_image_info *end =
2bfd4448 375 (objc_image_info *)(info_size + (uint8_t *)start);
b3962a83 376 const objc_image_info *info = start;
2bfd4448
A
377 while (info < end) {
378 // version is byte size, except for version 0
379 size_t struct_size = info->version;
380 if (struct_size == 0) struct_size = 2 * sizeof(uint32_t);
381 if (info->version != start->version ||
382 0 != memcmp(info, start, struct_size))
383 {
b3962a83 384 _objc_inform("'%s' has inconsistently-compiled Objective-C "
2bfd4448
A
385 "code. Please recompile all code in it.",
386 _nameForHeader(header));
387 }
388 info = (objc_image_info *)(struct_size + (uint8_t *)info);
389 }
390d5862 390 }
2bfd4448
A
391
392 // Add the header to the header list.
393 // The header is appended to the list, to preserve the bottom-up order.
b3962a83 394 HeaderCount++;
2bfd4448
A
395 result->next = NULL;
396 if (!FirstHeader) {
397 // list is empty
398 FirstHeader = LastHeader = result;
399 } else {
400 if (!LastHeader) {
401 // list is not empty, but LastHeader is invalid - recompute it
402 LastHeader = FirstHeader;
403 while (LastHeader->next) LastHeader = LastHeader->next;
390d5862 404 }
2bfd4448
A
405 // LastHeader is now valid
406 LastHeader->next = result;
407 LastHeader = result;
390d5862
A
408 }
409
2bfd4448 410 return result;
390d5862
A
411}
412
2bfd4448 413
390d5862 414/***********************************************************************
2bfd4448
A
415* _objc_RemoveHeader
416* Remove the given header from the header list.
417* FirstHeader is updated.
418* LastHeader is set to NULL. Any code that uses LastHeader must
419* detect this NULL and recompute LastHeader by traversing the list.
390d5862 420**********************************************************************/
2bfd4448 421static void _objc_removeHeader(header_info *hi)
390d5862 422{
2bfd4448
A
423 header_info **hiP;
424
425 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
426 if (*hiP == hi) {
427 header_info *deadHead = *hiP;
428
429 // Remove from the linked list (updating FirstHeader if necessary).
430 *hiP = (**hiP).next;
431
432 // Update LastHeader if necessary.
433 if (LastHeader == deadHead) {
434 LastHeader = NULL; // will be recomputed next time it's used
435 }
436
437 // Free the memory, unless it was in the static HeaderInfoTable.
438 if (deadHead < HeaderInfoTable ||
439 deadHead >= HeaderInfoTable + HINFO_SIZE)
440 {
441 _free_internal(deadHead);
442 }
443
b3962a83
A
444 HeaderCount--;
445
2bfd4448 446 break;
390d5862
A
447 }
448 }
390d5862
A
449}
450
451
13d88034 452/***********************************************************************
2bfd4448
A
453* check_gc
454* Check whether the executable supports or requires GC, and make sure
455* all already-loaded libraries support the executable's GC mode.
456* Returns TRUE if the executable wants GC on.
41c8faa5 457**********************************************************************/
2bfd4448 458static BOOL check_wants_gc(void)
13d88034 459{
2bfd4448
A
460 const header_info *hi;
461 BOOL appWantsGC;
462
463 // Environment variables can override the following.
b3962a83
A
464 if (DisableGC) {
465 _objc_inform("GC: forcing GC OFF because OBJC_DISABLE_GC is set");
2bfd4448 466 appWantsGC = NO;
41c8faa5
A
467 }
468 else {
2bfd4448
A
469 // Find the executable and check its GC bits.
470 // If the executable cannot be found, default to NO.
471 // (The executable will not be found if the executable contains
472 // no Objective-C code.)
473 appWantsGC = NO;
474 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
475 if (hi->mhdr->filetype == MH_EXECUTE) {
476 appWantsGC = _objcHeaderSupportsGC(hi) ? YES : NO;
477 if (PrintGC) {
b3962a83
A
478 _objc_inform("GC: executable '%s' %s",
479 _nameForHeader(hi->mhdr), _gcForHInfo(hi));
2bfd4448
A
480 }
481 }
482 }
390d5862 483 }
2bfd4448 484 return appWantsGC;
13d88034
A
485}
486
2bfd4448
A
487/***********************************************************************
488* verify_gc_readiness
489* if we want gc, verify that every header describes files compiled
490* and presumably ready for gc.
491************************************************************************/
492
b3962a83
A
493static void verify_gc_readiness(BOOL wantsGC, header_info **hList,
494 uint32_t hCount)
13d88034 495{
2bfd4448 496 BOOL busted = NO;
b3962a83 497 uint32_t i;
2bfd4448
A
498
499 // Find the libraries and check their GC bits against the app's request
b3962a83
A
500 for (i = 0; i < hCount; i++) {
501 header_info *hi = hList[i];
2bfd4448
A
502 if (hi->mhdr->filetype == MH_EXECUTE) {
503 continue;
504 }
505 else if (hi->mhdr == &_mh_dylib_header) {
506 // libobjc itself works with anything even though it is not
507 // compiled with -fobjc-gc (fixme should it be?)
508 }
509 else if (wantsGC && ! _objcHeaderSupportsGC(hi)) {
510 // App wants GC but library does not support it - bad
b3962a83
A
511 _objc_inform_now_and_on_crash
512 ("'%s' was not compiled with -fobjc-gc or -fobjc-gc-only, "
513 "but the application requires GC",
514 _nameForHeader(hi->mhdr));
2bfd4448
A
515 busted = YES;
516 }
b3962a83
A
517 else if (!wantsGC && _objcHeaderRequiresGC(hi)) {
518 // App doesn't want GC but library requires it - bad
519 _objc_inform_now_and_on_crash
520 ("'%s' was compiled with -fobjc-gc-only, "
521 "but the application does not support GC",
522 _nameForHeader(hi->mhdr));
523 busted = YES;
524 }
2bfd4448
A
525
526 if (PrintGC) {
b3962a83
A
527 _objc_inform("GC: library '%s' %s",
528 _nameForHeader(hi->mhdr), _gcForHInfo(hi));
2bfd4448
A
529 }
530 }
41c8faa5 531
2bfd4448
A
532 if (busted) {
533 // GC state is not consistent.
534 // Kill the process unless one of the forcing flags is set.
b3962a83 535 if (!DisableGC) {
2bfd4448 536 _objc_fatal("*** GC capability of application and some libraries did not match");
41c8faa5
A
537 }
538 }
13d88034
A
539}
540
2bfd4448 541
13d88034 542/***********************************************************************
2bfd4448
A
543* objc_setConfiguration
544* Read environment variables that affect the runtime.
545* Also print environment variable help, if requested.
41c8faa5
A
546**********************************************************************/
547static void objc_setConfiguration() {
2bfd4448
A
548 int PrintHelp = (getenv("OBJC_HELP") != NULL);
549 int PrintOptions = (getenv("OBJC_PRINT_OPTIONS") != NULL);
b3962a83
A
550 int secure = issetugid();
551
552 if (secure) {
553 // All environment variables are ignored when setuid or setgid.
554 if (PrintHelp) _objc_inform("OBJC_HELP ignored when running setuid or setgid");
555 if (PrintOptions) _objc_inform("OBJC_PRINT_OPTIONS ignored when running setuid or setgid");
556 }
557 else {
558 if (PrintHelp) {
559 _objc_inform("OBJC_HELP: describe Objective-C runtime environment variables");
560 if (PrintOptions) {
561 _objc_inform("OBJC_HELP is set");
562 }
563 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
564 }
2bfd4448 565 if (PrintOptions) {
b3962a83 566 _objc_inform("OBJC_PRINT_OPTIONS is set");
2bfd4448 567 }
41c8faa5 568 }
2bfd4448
A
569
570#define OPTION(var, env, help) \
571 if ( var == -1 ) { \
b3962a83
A
572 char *value = getenv(#env); \
573 var = value != NULL && !strcmp("YES", value); \
574 if (secure) { \
575 if (var) _objc_inform(#env " ignored when running setuid or setgid"); \
576 var = 0; \
577 } else { \
578 if (PrintHelp) _objc_inform(#env ": " help); \
579 if (PrintOptions && var) _objc_inform(#env " is set"); \
580 } \
390d5862 581 }
2bfd4448
A
582
583 OPTION(PrintImages, OBJC_PRINT_IMAGES,
b3962a83 584 "log image and library names as they are loaded");
2bfd4448 585 OPTION(PrintLoading, OBJC_PRINT_LOAD_METHODS,
b3962a83
A
586 "log calls to class and category +load methods");
587 OPTION(PrintInitializing, OBJC_PRINT_INITIALIZE_METHODS,
588 "log calls to class +initialize methods");
589 OPTION(PrintResolving, OBJC_PRINT_RESOLVED_METHODS,
590 "log methods created by +resolveClassMethod: and +resolveInstanceMethod:");
591 OPTION(PrintConnecting, OBJC_PRINT_CLASS_SETUP,
592 "log progress of class and category setup");
593 OPTION(PrintProtocols, OBJC_PRINT_PROTOCOL_SETUP,
594 "log progresso of protocol setup");
595 OPTION(PrintIvars, OBJC_PRINT_IVAR_SETUP,
596 "log processing of non-fragile ivars");
597 OPTION(PrintFuture, OBJC_PRINT_FUTURE_CLASSES,
598 "log use of future classes for toll-free bridging");
2bfd4448
A
599 OPTION(PrintRTP, OBJC_PRINT_RTP,
600 "log initialization of the Objective-C runtime pages");
601 OPTION(PrintGC, OBJC_PRINT_GC,
602 "log some GC operations");
603 OPTION(PrintSharing, OBJC_PRINT_SHARING,
604 "log cross-process memory sharing");
605 OPTION(PrintCxxCtors, OBJC_PRINT_CXX_CTORS,
606 "log calls to C++ ctors and dtors for instance variables");
b3962a83
A
607 OPTION(PrintExceptions, OBJC_PRINT_EXCEPTIONS,
608 "log exception handling");
609 OPTION(PrintAltHandlers, OBJC_PRINT_ALT_HANDLERS,
610 "log processing of exception alt handlers");
611 OPTION(PrintReplacedMethods, OBJC_PRINT_REPLACED_METHODS,
612 "log methods replaced by category implementations");
613 OPTION(PrintDeprecation, OBJC_PRINT_DEPRECATION_WARNINGS,
614 "warn about calls to deprecated runtime functions");
615 OPTION(PrintCacheCollection, OBJC_PRINT_CACHE_COLLECTION,
616 "log cleanup of stale method caches");
2bfd4448
A
617
618 OPTION(DebugUnload, OBJC_DEBUG_UNLOAD,
619 "warn about poorly-behaving bundles when unloaded");
620 OPTION(DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES,
621 "warn about subclasses that may have been broken by subsequent changes to superclasses");
b3962a83
A
622 OPTION(DebugFinalizers, OBJC_DEBUG_FINALIZERS,
623 "warn about classes that implement -dealloc but not -finalize");
624 OPTION(DebugNilSync, OBJC_DEBUG_NIL_SYNC,
625 "warn about @synchronized(nil), which does no synchronization");
2bfd4448
A
626
627 OPTION(UseInternalZone, OBJC_USE_INTERNAL_ZONE,
628 "allocate runtime data in a dedicated malloc zone");
629 OPTION(AllowInterposing, OBJC_ALLOW_INTERPOSING,
630 "allow function interposing of objc_msgSend()");
631
b3962a83 632 OPTION(DisableGC, OBJC_DISABLE_GC,
2bfd4448 633 "force GC OFF, even if the executable wants it on");
b3962a83 634
2bfd4448 635#undef OPTION
41c8faa5 636}
2bfd4448
A
637
638
41c8faa5
A
639/***********************************************************************
640* objc_setMultithreaded.
641**********************************************************************/
13d88034
A
642void objc_setMultithreaded (BOOL flag)
643{
b3962a83
A
644 OBJC_WARN_DEPRECATED;
645
1f20c7a7 646 // Nothing here. Thread synchronization in the runtime is always active.
13d88034 647}
1f20c7a7
A
648
649
b3962a83
A
650/***********************************************************************
651* _objc_fetch_pthread_data
652* Fetch objc's pthread data for this thread.
653* If the data doesn't exist yet and create is NO, return NULL.
654* If the data doesn't exist yet and create is YES, allocate and return it.
655**********************************************************************/
656__private_extern__ _objc_pthread_data *_objc_fetch_pthread_data(BOOL create)
657{
658 _objc_pthread_data *data;
659
660 data = pthread_getspecific(_objc_pthread_key);
661 if (!data && create) {
662 data = _calloc_internal(1, sizeof(_objc_pthread_data));
663 pthread_setspecific(_objc_pthread_key, data);
664 }
665
666 return data;
667}
668
1f20c7a7
A
669
670/***********************************************************************
671* _objc_pthread_destroyspecific
672* Destructor for objc's per-thread data.
673* arg shouldn't be NULL, but we check anyway.
674**********************************************************************/
675extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
b3962a83 676__private_extern__ void _objc_pthread_destroyspecific(void *arg)
1f20c7a7
A
677{
678 _objc_pthread_data *data = (_objc_pthread_data *)arg;
679 if (data != NULL) {
680 _destroyInitializingClassList(data->initializingClasses);
b3962a83
A
681 _destroyLockList(data->lockList);
682 _destroySyncCache(data->syncCache);
683 _destroyAltHandlerList(data->handlerList);
1f20c7a7
A
684
685 // add further cleanup here...
686
b3962a83
A
687 _free_internal(data);
688 }
689}
690
691
692/***********************************************************************
693* _objcInit
694* Former library initializer. This function is now merely a placeholder
695* for external callers. All runtime initialization has now been moved
696* to map_images() and _objc_init.
697**********************************************************************/
698void _objcInit(void)
699{
700 // do nothing
701}
702
703
704/***********************************************************************
705* gc_enforcer
706* Make sure that images about to be loaded by dyld are GC-acceptable.
707* Images linked to the executable are always permitted; they are
708* enforced inside map_images() itself.
709**********************************************************************/
710static BOOL InitialDyldRegistration = NO;
711static const char *gc_enforcer(enum dyld_image_states state,
712 uint32_t infoCount,
713 const struct dyld_image_info info[])
714{
715 uint32_t i;
716
717 // Linked images get a free pass
718 if (InitialDyldRegistration) return NULL;
719
720 if (PrintImages) {
721 _objc_inform("IMAGES: checking %d images for compatibility...",
722 infoCount);
723 }
724
725 for (i = 0; i < infoCount; i++) {
726 const headerType *mhdr = (const headerType *)info[i].imageLoadAddress;
727 if (bad_magic(mhdr)) continue;
728
729 objc_image_info *image_info;
730 size_t size;
731
732 if (mhdr == &_mh_dylib_header) {
733 // libobjc itself - OK
734 continue;
735 }
736
737#if !__LP64__
738 // 32-bit: __OBJC seg but no image_info means no GC support
739 if (!getsegbynamefromheader(mhdr, SEG_OBJC)) {
740 // not objc - assume OK
741 continue;
742 }
743 image_info = _getObjcImageInfo(mhdr, _getImageSlide(mhdr), &size);
744 if (!image_info) {
745 // No image_info - assume GC unsupported
746 if (!UseGC) {
747 // GC is OFF - ok
748 continue;
749 } else {
750 // GC is ON - bad
751 if (PrintImages || PrintGC) {
752 _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC (no image_info)", infoCount, info[i].imageFilePath);
753 }
754 return "GC capability mismatch";
755 }
756 }
757#else
758 // 64-bit: no image_info means no objc at all
759 image_info = _getObjcImageInfo(mhdr, _getImageSlide(mhdr), &size);
760 if (!image_info) {
761 // not objc - assume OK
762 continue;
763 }
764#endif
765
766 if (UseGC && !_objcInfoSupportsGC(image_info)) {
767 // GC is ON, but image does not support GC
768 if (PrintImages || PrintGC) {
769 _objc_inform("IMAGES: rejecting %d images because %s doesn't support GC", infoCount, info[i].imageFilePath);
770 }
771 return "GC capability mismatch";
772 }
773 if (!UseGC && _objcInfoRequiresGC(image_info)) {
774 // GC is OFF, but image requires GC
775 if (PrintImages || PrintGC) {
776 _objc_inform("IMAGES: rejecting %d images because %s requires GC", infoCount, info[i].imageFilePath);
777 }
778 return "GC capability mismatch";
779 }
1f20c7a7 780 }
1f20c7a7 781
b3962a83 782 return NULL;
2bfd4448
A
783}
784
13d88034 785
2bfd4448
A
786/***********************************************************************
787* map_images
788* Process the given images which are being mapped in by dyld.
789* All class registration and fixups are performed (or deferred pending
790* discovery of missing superclasses etc), and +load methods are called.
791*
792* info[] is in bottom-up order i.e. libobjc will be earlier in the
793* array than any library that links to libobjc.
794**********************************************************************/
b3962a83
A
795static const char *map_images(enum dyld_image_states state, uint32_t infoCount,
796 const struct dyld_image_info infoList[])
2bfd4448
A
797{
798 static BOOL firstTime = YES;
799 static BOOL wantsGC NOBSS = NO;
800 uint32_t i;
41c8faa5 801 header_info *hInfo;
b3962a83
A
802 header_info *hList[infoCount];
803 uint32_t hCount;
13d88034 804
2bfd4448
A
805 // Perform first-time initialization if necessary.
806 // This function is called before ordinary library initializers.
807 if (firstTime) {
b3962a83
A
808 extern SEL FwdSel; // in objc-msg-*.s
809 // workaround for rdar://5198739
810 pthread_key_t unused;
811 pthread_key_create(&unused, NULL);
2bfd4448
A
812 pthread_key_create(&_objc_pthread_key, _objc_pthread_destroyspecific);
813 objc_setConfiguration(); // read environment variables
2bfd4448
A
814 // grab selectors for which @selector() doesn't work
815 cxx_construct_sel = sel_registerName(cxx_construct_name);
816 cxx_destruct_sel = sel_registerName(cxx_destruct_name);
b3962a83
A
817 FwdSel = sel_registerName("forward::"); // in objc-msg-*.s
818 exception_init();
819
820 InitialDyldRegistration = YES;
821 dyld_register_image_state_change_handler(dyld_image_state_mapped, 0 /* batch */, &gc_enforcer);
822 InitialDyldRegistration = NO;
2bfd4448 823 }
13d88034 824
2bfd4448
A
825 if (PrintImages) {
826 _objc_inform("IMAGES: processing %u newly-mapped images...\n", infoCount);
827 }
41c8faa5 828
41c8faa5 829
b3962a83
A
830 // Find all images with Objective-C metadata.
831 hCount = 0;
832 i = infoCount;
833 while (i--) {
834 const headerType *mhdr = (headerType *)infoList[i].imageLoadAddress;
835 if (bad_magic(mhdr)) continue;
41c8faa5 836
2bfd4448
A
837 hInfo = _objc_addHeader(mhdr);
838 if (!hInfo) {
839 // no objc data in this entry
2bfd4448
A
840 continue;
841 }
41c8faa5 842
b3962a83 843 hList[hCount++] = hInfo;
2bfd4448
A
844
845 if (PrintImages) {
846 _objc_inform("IMAGES: loading image for %s%s%s%s\n",
847 _nameForHeader(mhdr),
848 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
849 _objcHeaderIsReplacement(hInfo) ? " (replacement)":"",
b3962a83 850 _gcForHInfo2(hInfo));
2bfd4448
A
851 }
852 }
41c8faa5 853
2bfd4448
A
854 // Perform one-time runtime initialization that must be deferred until
855 // the executable itself is found. This needs to be done before
856 // further initialization.
857 // (The executable may not be present in this infoList if the
858 // executable does not contain Objective-C code but Objective-C
859 // is dynamically loaded later. In that case, check_wants_gc()
860 // will do the right thing.)
861 if (firstTime) {
862 wantsGC = check_wants_gc();
b3962a83
A
863
864 verify_gc_readiness(wantsGC, hList, hCount);
865
2bfd4448
A
866 gc_init(wantsGC); // needs executable for GC decision
867 rtp_init(); // needs GC decision first
868 } else {
b3962a83 869 verify_gc_readiness(wantsGC, hList, hCount);
2bfd4448 870 }
41c8faa5 871
b3962a83 872 _read_images(hList, hCount);
41c8faa5 873
2bfd4448 874 firstTime = NO;
41c8faa5 875
b3962a83 876 return NULL;
2bfd4448 877}
41c8faa5 878
13d88034 879
b3962a83
A
880static const char *load_images(enum dyld_image_states state,uint32_t infoCount,
881 const struct dyld_image_info infoList[])
2bfd4448 882{
b3962a83 883 BOOL found = NO;
2bfd4448 884 uint32_t i;
13d88034 885
b3962a83
A
886 i = infoCount;
887 while (i--) {
888 header_info *hi;
889 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
890 const headerType *mhdr = (headerType*)infoList[i].imageLoadAddress;
891 if (hi->mhdr == mhdr) {
892 prepare_load_methods(hi);
893 found = YES;
2bfd4448
A
894 }
895 }
41c8faa5 896 }
13d88034 897
b3962a83 898 if (found) call_load_methods();
41c8faa5 899
b3962a83 900 return NULL;
2bfd4448 901}
41c8faa5 902
2bfd4448 903/***********************************************************************
b3962a83
A
904* unmap_image
905* Process the given image which is about to be unmapped by dyld.
906* mh is mach_header instead of headerType because that's what
907* dyld_priv.h says even for 64-bit.
2bfd4448 908**********************************************************************/
b3962a83 909static void unmap_image(const struct mach_header *mh, intptr_t vmaddr_slide)
2bfd4448 910{
b3962a83
A
911 if (PrintImages) {
912 _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
41c8faa5
A
913 }
914
b3962a83 915 header_info *hi;
2bfd4448 916
b3962a83
A
917 // Find the runtime's header_info struct for the image
918 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
919 if (hi->mhdr == (const headerType *)mh) {
920 _objc_unmap_image(hi);
921 return;
13d88034 922 }
2bfd4448 923 }
b3962a83
A
924
925 // no objc data for this image
2bfd4448 926}
13d88034 927
13d88034 928
2bfd4448 929/***********************************************************************
b3962a83
A
930* _objc_init
931* Static initializer. Registers our image notifier with dyld.
932* fixme move map_images' firstTime code here - but GC code might need
933* another earlier image notifier
2bfd4448 934**********************************************************************/
b3962a83
A
935static __attribute__((constructor))
936void _objc_init(void)
2bfd4448 937{
b3962a83
A
938 // Register for unmap first, in case some +load unmaps something
939 _dyld_register_func_for_remove_image(&unmap_image);
940 dyld_register_image_state_change_handler(dyld_image_state_bound,
941 1/*batch*/, &map_images);
942 dyld_register_image_state_change_handler(dyld_image_state_dependents_initialized, 0/*not batch*/, &load_images);
13d88034 943}
13d88034 944
2bfd4448 945
13d88034 946/***********************************************************************
41c8faa5 947* _objc_unmap_image.
2bfd4448
A
948* Destroy any Objective-C data for the given image, which is about to
949* be unloaded by dyld.
950* Note: not thread-safe, but image loading isn't either.
41c8faa5 951**********************************************************************/
b3962a83 952static void _objc_unmap_image(header_info *hi)
2bfd4448 953{
2bfd4448
A
954 if (PrintImages) {
955 _objc_inform("IMAGES: unloading image for %s%s%s%s\n",
b3962a83
A
956 _nameForHeader(hi->mhdr),
957 hi->mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
2bfd4448 958 _objcHeaderIsReplacement(hi) ? " (replacement)" : "",
b3962a83 959 _gcForHInfo2(hi));
2bfd4448
A
960 }
961
b3962a83 962 _unload_image(hi);
2bfd4448
A
963
964 // Remove header_info from header list
965 _objc_removeHeader(hi);
13d88034 966}
13d88034 967
2bfd4448 968
13d88034 969/***********************************************************************
390d5862 970* _objc_setNilReceiver
41c8faa5 971**********************************************************************/
390d5862 972id _objc_setNilReceiver(id newNilReceiver)
13d88034 973{
390d5862
A
974 id oldNilReceiver;
975
976 oldNilReceiver = _objc_nilReceiver;
977 _objc_nilReceiver = newNilReceiver;
978
979 return oldNilReceiver;
13d88034
A
980}
981
982/***********************************************************************
390d5862 983* _objc_getNilReceiver
41c8faa5 984**********************************************************************/
390d5862 985id _objc_getNilReceiver(void)
13d88034 986{
390d5862 987 return _objc_nilReceiver;
13d88034
A
988}
989
13d88034 990
390d5862 991/***********************************************************************
b3962a83
A
992* objc_setForwardHandler
993**********************************************************************/
994void objc_setForwardHandler(void *fwd, void *fwd_stret)
995{
996 _objc_forward_handler = fwd;
997 _objc_forward_stret_handler = fwd_stret;
998}
999
1000
1001#if defined(__ppc__) || defined(__ppc64__)
1002
1003// Test to see if either the displacement or destination is within
1004// the +/- 2^25 range needed for a PPC branch immediate instruction.
1005// Shifting the high bit of the displacement (or destination)
1006// left 6 bits and then 6 bits arithmetically to the right does a
1007// sign extend of the 26th bit. If that result is equivalent to the
1008// original value, then the displacement (or destination) will fit
1009// into a simple branch. Otherwise a larger branch sequence is required.
1010// ppc64: max displacement is still +/- 2^25, but intptr_t is bigger
1011
1012// tiny: bc*
1013// small: b, ba (unconditional only)
1014// 32: bctr with lis+ori only
1015static BOOL ppc_tiny_displacement(intptr_t displacement)
1016{
1017 size_t shift = sizeof(intptr_t) - 16; // ilp32=16, lp64=48
1018 return (((displacement << shift) >> shift) == displacement);
1019}
1020
1021static BOOL ppc_small_displacement(intptr_t displacement)
1022{
1023 size_t shift = sizeof(intptr_t) - 26; // ilp32=6, lp64=38
1024 return (((displacement << shift) >> shift) == displacement);
1025}
1026
1027#if defined(__ppc64__)
1028// Same as ppc_small_displacement, but decides whether 32 bits is big enough.
1029static BOOL ppc_32bit_displacement(intptr_t displacement)
1030{
1031 size_t shift = sizeof(intptr_t) - 32;
1032 return (((displacement << shift) >> shift) == displacement);
1033}
1034#endif
1035
1036/**********************************************************************
1037* objc_branch_size
1038* Returns the number of instructions needed
1039* for a branch from entry to target.
390d5862 1040**********************************************************************/
b3962a83 1041__private_extern__ size_t objc_branch_size(void *entry, void *target)
390d5862 1042{
b3962a83 1043 return objc_cond_branch_size(entry, target, COND_ALWAYS);
390d5862 1044}
2bfd4448 1045
b3962a83
A
1046__private_extern__ size_t
1047objc_cond_branch_size(void *entry, void *target, unsigned cond)
1048{
1049 intptr_t destination = (intptr_t)target;
1050 intptr_t displacement = (intptr_t)destination - (intptr_t)entry;
2bfd4448 1051
b3962a83
A
1052 if (cond == COND_ALWAYS && ppc_small_displacement(displacement)) {
1053 // fits in unconditional relative branch immediate
1054 return 1;
1055 }
1056 if (cond == COND_ALWAYS && ppc_small_displacement(destination)) {
1057 // fits in unconditional absolute branch immediate
1058 return 1;
1059 }
1060 if (ppc_tiny_displacement(displacement)) {
1061 // fits in conditional relative branch immediate
1062 return 1;
1063 }
1064 if (ppc_tiny_displacement(destination)) {
1065 // fits in conditional absolute branch immediate
1066 return 1;
1067 }
1068#if defined(__ppc64__)
1069 if (!ppc_32bit_displacement(destination)) {
1070 // fits in 64-bit absolute branch through CTR
1071 return 7;
1072 }
1073#endif
1074
1075 // fits in 32-bit absolute branch through CTR
1076 return 4;
1077}
2bfd4448
A
1078
1079/**********************************************************************
1080* objc_write_branch
1081* Writes at entry a PPC branch instruction sequence that branches to target.
b3962a83 1082* The sequence written will be objc_branch_size(entry, target) instructions.
2bfd4448
A
1083* Returns the number of instructions written.
1084**********************************************************************/
1085__private_extern__ size_t objc_write_branch(void *entry, void *target)
b3962a83
A
1086{
1087 return objc_write_cond_branch(entry, target, COND_ALWAYS);
1088}
1089
1090__private_extern__ size_t
1091objc_write_cond_branch(void *entry, void *target, unsigned cond)
2bfd4448
A
1092{
1093 unsigned *address = (unsigned *)entry; // location to store the 32 bit PPC instructions
1094 intptr_t destination = (intptr_t)target; // destination as an absolute address
1095 intptr_t displacement = (intptr_t)destination - (intptr_t)address; // destination as a branch relative offset
1096
b3962a83
A
1097 if (cond == COND_ALWAYS && ppc_small_displacement(displacement)) {
1098 // use unconditional relative branch with the displacement
1099 address[0] = 0x48000000 | (unsigned)(displacement & 0x03fffffc); // b *+displacement
2bfd4448
A
1100 // issued 1 instruction
1101 return 1;
b3962a83
A
1102 }
1103 if (cond == COND_ALWAYS && ppc_small_displacement(destination)) {
1104 // use unconditional absolute branch with the destination
1105 address[0] = 0x48000000 | (unsigned)(destination & 0x03fffffc) | 2; // ba destination (2 is the absolute flag)
2bfd4448
A
1106 // issued 1 instruction
1107 return 1;
b3962a83
A
1108 }
1109
1110 if (ppc_tiny_displacement(displacement)) {
1111 // use conditional relative branch with the displacement
1112 address[0] = 0x40000000 | cond | (unsigned)(displacement & 0x0000fffc); // b *+displacement
1113 // issued 1 instruction
1114 return 1;
1115 }
1116 if (ppc_tiny_displacement(destination)) {
1117 // use conditional absolute branch with the destination
1118 address[0] = 0x40000000 | cond | (unsigned)(destination & 0x0000fffc) | 2; // ba destination (2 is the absolute flag)
1119 // issued 1 instruction
1120 return 1;
1121 }
1122
1123
1124 // destination is large and far away.
1125 // Use an absolute branch via CTR.
1126
1127#if defined(__ppc64__)
1128 if (!ppc_32bit_displacement(destination)) {
1129 uint16_t lo = destination & 0xffff;
1130 uint16_t hi = (destination >> 16) & 0xffff;
1131 uint16_t hi2 = (destination >> 32) & 0xffff;
1132 uint16_t hi3 = (destination >> 48) & 0xffff;
1133
1134 address[0] = 0x3d800000 | hi3; // lis r12, hi3
1135 address[1] = 0x618c0000 | hi2; // ori r12, r12, hi2
1136 address[2] = 0x798c07c6; // sldi r12, r12, 32
1137 address[3] = 0x658c0000 | hi; // oris r12, r12, hi
1138 address[4] = 0x618c0000 | lo; // ori r12, r12, lo
1139 address[5] = 0x7d8903a6; // mtctr r12
1140 address[6] = 0x4c000420 | cond; // bctr
1141 // issued 7 instructions
1142 return 7;
1143 }
1144#endif
1145
1146 {
1147 uint16_t lo = destination & 0xffff;
1148 uint16_t hi = (destination >> 16) & 0xffff;
1149
1150 address[0] = 0x3d800000 | hi; // lis r12,hi
1151 address[1] = 0x618c0000 | lo; // ori r12,r12,lo
1152 address[2] = 0x7d8903a6; // mtctr r12
1153 address[3] = 0x4c000420 | cond; // bctr
2bfd4448
A
1154 // issued 4 instructions
1155 return 4;
1156 }
1157}
1158
b3962a83
A
1159// defined(__ppc__) || defined(__ppc64__)
1160#endif
1161
1162#if defined(__i386__) || defined(__x86_64__)
1163
1164/**********************************************************************
1165* objc_branch_size
1166* Returns the number of BYTES needed
1167* for a branch from entry to target.
1168**********************************************************************/
1169__private_extern__ size_t objc_branch_size(void *entry, void *target)
1170{
1171 return objc_cond_branch_size(entry, target, COND_ALWAYS);
1172}
1173
1174__private_extern__ size_t
1175objc_cond_branch_size(void *entry, void *target, unsigned cond)
1176{
1177 // For simplicity, always use 32-bit relative jumps.
1178 if (cond == COND_ALWAYS) return 5;
1179 else return 6;
1180}
1181
1182/**********************************************************************
1183* objc_write_branch
1184* Writes at entry an i386 branch instruction sequence that branches to target.
1185* The sequence written will be objc_branch_size(entry, target) BYTES.
1186* Returns the number of BYTES written.
1187**********************************************************************/
1188__private_extern__ size_t objc_write_branch(void *entry, void *target)
1189{
1190 return objc_write_cond_branch(entry, target, COND_ALWAYS);
1191}
1192
1193__private_extern__ size_t
1194objc_write_cond_branch(void *entry, void *target, unsigned cond)
1195{
1196 uint8_t *address = (uint8_t *)entry; // instructions written to here
1197 intptr_t destination = (intptr_t)target; // branch dest as absolute address
1198 intptr_t displacement = (intptr_t)destination - ((intptr_t)address + objc_cond_branch_size(entry, target, cond)); // branch dest as relative offset
1199
1200 // For simplicity, always use 32-bit relative jumps
1201 if (cond != COND_ALWAYS) {
1202 *address++ = 0x0f; // Jcc prefix
1203 }
1204 *address++ = cond;
1205 *address++ = displacement & 0xff;
1206 *address++ = (displacement >> 8) & 0xff;
1207 *address++ = (displacement >> 16) & 0xff;
1208 *address++ = (displacement >> 24) & 0xff;
1209
1210 return address - (uint8_t *)entry;
1211}
1212
1213// defined __i386__
2bfd4448
A
1214#endif
1215
1216
1217/**********************************************************************
1218* secure_open
1219* Securely open a file from a world-writable directory (like /tmp)
1220* If the file does not exist, it will be atomically created with mode 0600
1221* If the file exists, it must be, and remain after opening:
1222* 1. a regular file (in particular, not a symlink)
1223* 2. owned by euid
1224* 3. permissions 0600
1225* 4. link count == 1
1226* Returns a file descriptor or -1. Errno may or may not be set on error.
1227**********************************************************************/
1228__private_extern__ int secure_open(const char *filename, int flags, uid_t euid)
1229{
1230 struct stat fs, ls;
1231 int fd = -1;
1232 BOOL truncate = NO;
1233 BOOL create = NO;
1234
1235 if (flags & O_TRUNC) {
1236 // Don't truncate the file until after it is open and verified.
1237 truncate = YES;
1238 flags &= ~O_TRUNC;
1239 }
1240 if (flags & O_CREAT) {
1241 // Don't create except when we're ready for it
1242 create = YES;
1243 flags &= ~O_CREAT;
1244 flags &= ~O_EXCL;
1245 }
1246
1247 if (lstat(filename, &ls) < 0) {
1248 if (errno == ENOENT && create) {
1249 // No such file - create it
1250 fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
1251 if (fd >= 0) {
1252 // File was created successfully.
1253 // New file does not need to be truncated.
1254 return fd;
1255 } else {
1256 // File creation failed.
1257 return -1;
1258 }
1259 } else {
1260 // lstat failed, or user doesn't want to create the file
1261 return -1;
1262 }
1263 } else {
1264 // lstat succeeded - verify attributes and open
1265 if (S_ISREG(ls.st_mode) && // regular file?
1266 ls.st_nlink == 1 && // link count == 1?
1267 ls.st_uid == euid && // owned by euid?
1268 (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
1269 {
1270 // Attributes look ok - open it and check attributes again
1271 fd = open(filename, flags, 0000);
1272 if (fd >= 0) {
1273 // File is open - double-check attributes
1274 if (0 == fstat(fd, &fs) &&
1275 fs.st_nlink == ls.st_nlink && // link count == 1?
1276 fs.st_uid == ls.st_uid && // owned by euid?
1277 fs.st_mode == ls.st_mode && // regular file, 0600?
1278 fs.st_ino == ls.st_ino && // same inode as before?
1279 fs.st_dev == ls.st_dev) // same device as before?
1280 {
1281 // File is open and OK
1282 if (truncate) ftruncate(fd, 0);
1283 return fd;
1284 } else {
1285 // Opened file looks funny - close it
1286 close(fd);
1287 return -1;
1288 }
1289 } else {
1290 // File didn't open
1291 return -1;
1292 }
1293 } else {
1294 // Unopened file looks funny - don't open it
1295 return -1;
1296 }
1297 }
1298}
1299
1300
b3962a83
A
1301#if !__OBJC2__
1302// GrP fixme
1303extern Class _objc_getOrigClass(const char *name);
1304#endif
1305const char *class_getImageName(Class cls)
1306{
1307 int ok;
1308 Dl_info info;
1309
1310 if (!cls) return NULL;
1311
1312#if !__OBJC2__
1313 cls = _objc_getOrigClass(_class_getName(cls));
1314#endif
1315
1316 ok = dladdr(cls, &info);
1317 if (ok) return info.dli_fname;
1318 else return NULL;
1319}
1320
1321
1322const char **objc_copyImageNames(unsigned int *outCount)
1323{
1324 header_info *hi;
1325 int count = 0;
1326 int max = HeaderCount;
1327 const char **names = calloc(max+1, sizeof(char *));
1328
1329 for (hi = _objc_headerStart();
1330 hi != NULL && count < max;
1331 hi = hi->next)
1332 {
1333 if (hi->dl_info.dli_fname) {
1334 names[count++] = hi->dl_info.dli_fname;
1335 }
1336 }
1337 names[count] = NULL;
1338
1339 if (count == 0) {
1340 // Return NULL instead of empty list if there are no images
1341 free(names);
1342 names = NULL;
1343 }
1344
1345 if (outCount) *outCount = count;
1346 return names;
1347}
1348
1349
1350/**********************************************************************
1351*
1352**********************************************************************/
1353const char **
1354objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
1355{
1356 header_info *hi;
1357
1358 if (!image) {
1359 if (outCount) *outCount = 0;
1360 return NULL;
1361 }
1362
1363 // Find the image.
1364 for (hi = _objc_headerStart(); hi != NULL; hi = hi->next) {
1365 if (0 == strcmp(image, hi->dl_info.dli_fname)) break;
1366 }
1367
1368 if (!hi) {
1369 if (outCount) *outCount = 0;
1370 return NULL;
1371 }
1372
1373 return _objc_copyClassNamesForImage(hi, outCount);
1374}
1375
1376
1377/**********************************************************************
1378* Fast Enumeration Support
1379**********************************************************************/
1380
1381static void (*enumerationMutationHandler)(id);
1382
1383/**********************************************************************
1384* objc_enumerationMutation
1385* called by compiler when a mutation is detected during foreach iteration
1386**********************************************************************/
1387void objc_enumerationMutation(id object) {
1388 if (enumerationMutationHandler == nil) {
1389 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", object);
1390 }
1391 (*enumerationMutationHandler)(object);
1392}
1393
1394
1395/**********************************************************************
1396* objc_setEnumerationMutationHandler
1397* an entry point to customize mutation error handing
1398**********************************************************************/
1399void objc_setEnumerationMutationHandler(void (*handler)(id)) {
1400 enumerationMutationHandler = handler;
1401}