2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
21 * @APPLE_LICENSE_HEADER_END@
23 /***********************************************************************
25 * Copyright 1988-1996, NeXT Software, Inc.
28 **********************************************************************/
32 /***********************************************************************
34 **********************************************************************/
36 #include "objc-private.h"
37 #include "objc-loadmethod.h"
40 OBJC_EXPORT Class getOriginalClassForPosingClass(Class);
43 /***********************************************************************
45 **********************************************************************/
47 // Settings from environment variables
49 int PrintImages = -1; // env OBJC_PRINT_IMAGES
50 int PrintLoading = -1; // env OBJC_PRINT_LOAD_METHODS
51 int PrintInitializing = -1; // env OBJC_PRINT_INITIALIZE_METHODS
52 int PrintResolving = -1; // env OBJC_PRINT_RESOLVED_METHODS
53 int PrintConnecting = -1; // env OBJC_PRINT_CLASS_SETUP
54 int PrintProtocols = -1; // env OBJC_PRINT_PROTOCOL_SETUP
55 int PrintIvars = -1; // env OBJC_PRINT_IVAR_SETUP
56 int PrintVtables = -1; // env OBJC_PRINT_VTABLE_SETUP
57 int PrintVtableImages = -1;//env OBJC_PRINT_VTABLE_IMAGES
58 int PrintFuture = -1; // env OBJC_PRINT_FUTURE_CLASSES
59 int PrintGC = -1; // env OBJC_PRINT_GC
60 int PrintPreopt = -1; // env OBJC_PRINT_PREOPTIMIZATION
61 int PrintCxxCtors = -1; // env OBJC_PRINT_CXX_CTORS
62 int PrintExceptions = -1; // env OBJC_PRINT_EXCEPTIONS
63 int PrintExceptionThrow = -1; // env OBJC_PRINT_EXCEPTION_THROW
64 int PrintAltHandlers = -1; // env OBJC_PRINT_ALT_HANDLERS
65 int PrintDeprecation = -1;// env OBJC_PRINT_DEPRECATION_WARNINGS
66 int PrintReplacedMethods = -1; // env OBJC_PRINT_REPLACED_METHODS
67 int PrintCaches = -1; // env OBJC_PRINT_CACHE_SETUP
68 int PrintPoolHiwat = -1; // env OBJC_PRINT_POOL_HIGHWATER
69 int PrintCustomRR = -1; // env OBJC_PRINT_CUSTOM_RR
70 int PrintCustomAWZ = -1; // env OBJC_PRINT_CUSTOM_AWZ
72 int UseInternalZone = -1; // env OBJC_USE_INTERNAL_ZONE
74 int DebugUnload = -1; // env OBJC_DEBUG_UNLOAD
75 int DebugFragileSuperclasses = -1; // env OBJC_DEBUG_FRAGILE_SUPERCLASSES
76 int DebugNilSync = -1; // env OBJC_DEBUG_NIL_SYNC
77 int DebugNonFragileIvars = -1; // env OBJC_DEBUG_NONFRAGILE_IVARS
78 int DebugAltHandlers = -1;// env OBJC_DEBUG_ALT_HANDLERS
80 int DisableGC = -1; // env OBJC_DISABLE_GC
81 int DisableVtables = -1; // env OBJC_DISABLE_VTABLES
82 int DisablePreopt = -1; // env OBJC_DISABLE_PREOPTIMIZATION
83 int DebugFinalizers = -1; // env OBJC_DEBUG_FINALIZERS
87 // objc's key for pthread_getspecific
88 static tls_key_t _objc_pthread_key;
92 SEL SEL_initialize = NULL;
93 SEL SEL_resolveInstanceMethod = NULL;
94 SEL SEL_resolveClassMethod = NULL;
95 SEL SEL_cxx_construct = NULL;
96 SEL SEL_cxx_destruct = NULL;
97 SEL SEL_retain = NULL;
98 SEL SEL_release = NULL;
99 SEL SEL_autorelease = NULL;
100 SEL SEL_retainCount = NULL;
101 SEL SEL_alloc = NULL;
102 SEL SEL_allocWithZone = NULL;
105 SEL SEL_finalize = NULL;
106 SEL SEL_forwardInvocation = NULL;
108 header_info *FirstHeader = 0; // NULL means empty list
109 header_info *LastHeader = 0; // NULL means invalid; recompute it
114 /***********************************************************************
115 * objc_getClass. Return the id of the named class. If the class does
116 * not exist, call _objc_classLoader and then objc_classHandler, either of
117 * which may create a new class.
118 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
119 **********************************************************************/
120 id objc_getClass(const char *aClassName)
122 if (!aClassName) return Nil;
124 // NO unconnected, YES class handler
125 return look_up_class(aClassName, NO, YES);
129 /***********************************************************************
130 * objc_getRequiredClass.
131 * Same as objc_getClass, but kills the process if the class is not found.
132 * This is used by ZeroLink, where failing to find a class would be a
133 * compile-time link error without ZeroLink.
134 **********************************************************************/
135 id objc_getRequiredClass(const char *aClassName)
137 id cls = objc_getClass(aClassName);
138 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
143 /***********************************************************************
144 * objc_lookUpClass. Return the id of the named class.
145 * If the class does not exist, call _objc_classLoader, which may create
148 * Formerly objc_getClassWithoutWarning ()
149 **********************************************************************/
150 id objc_lookUpClass(const char *aClassName)
152 if (!aClassName) return Nil;
154 // NO unconnected, NO class handler
155 return look_up_class(aClassName, NO, NO);
158 /***********************************************************************
159 * objc_getFutureClass. Return the id of the named class.
160 * If the class does not exist, return an uninitialized class
161 * structure that will be used for the class when and if it
164 **********************************************************************/
165 Class objc_getFutureClass(const char *name)
169 // YES unconnected, NO class handler
170 // (unconnected is OK because it will someday be the real class)
171 cls = (Class)look_up_class(name, YES, NO);
174 _objc_inform("FUTURE: found %p already in use for %s", cls, name);
179 // No class or future class with that name yet. Make one.
180 // fixme not thread-safe with respect to
181 // simultaneous library load or getFutureClass.
182 return _objc_allocateFutureClass(name);
186 /***********************************************************************
187 * objc_getMetaClass. Return the id of the meta class the named class.
188 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
189 **********************************************************************/
190 id objc_getMetaClass(const char *aClassName)
194 if (!aClassName) return Nil;
196 cls = (Class)objc_getClass (aClassName);
199 _objc_inform ("class `%s' not linked into application", aClassName);
207 /***********************************************************************
208 * appendHeader. Add a newly-constructed header_info to the list.
209 **********************************************************************/
210 void appendHeader(header_info *hi)
212 // Add the header to the header list.
213 // The header is appended to the list, to preserve the bottom-up order.
218 FirstHeader = LastHeader = hi;
221 // list is not empty, but LastHeader is invalid - recompute it
222 LastHeader = FirstHeader;
223 while (LastHeader->next) LastHeader = LastHeader->next;
225 // LastHeader is now valid
226 LastHeader->next = hi;
232 /***********************************************************************
234 * Remove the given header from the header list.
235 * FirstHeader is updated.
236 * LastHeader is set to NULL. Any code that uses LastHeader must
237 * detect this NULL and recompute LastHeader by traversing the list.
238 **********************************************************************/
239 void removeHeader(header_info *hi)
243 for (hiP = &FirstHeader; *hiP != NULL; hiP = &(**hiP).next) {
245 header_info *deadHead = *hiP;
247 // Remove from the linked list (updating FirstHeader if necessary).
250 // Update LastHeader if necessary.
251 if (LastHeader == deadHead) {
252 LastHeader = NULL; // will be recomputed next time it's used
262 /***********************************************************************
264 * Read environment variables that affect the runtime.
265 * Also print environment variable help, if requested.
266 **********************************************************************/
267 void environ_init(void)
270 int PrintHelp = (getenv("OBJC_HELP") != NULL);
271 int PrintOptions = (getenv("OBJC_PRINT_OPTIONS") != NULL);
272 int secure = issetugid();
275 // All environment variables are ignored when setuid or setgid.
276 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
280 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
281 _objc_inform("OBJC_HELP: describe available environment variables");
283 _objc_inform("OBJC_HELP is set");
285 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
288 _objc_inform("OBJC_PRINT_OPTIONS is set");
292 #define OPTION(var, env, help) \
294 char *value = getenv(#env); \
295 var = value != NULL && !strcmp("YES", value); \
297 if (var) _objc_inform(#env " ignored when running setuid or setgid"); \
300 if (PrintHelp) _objc_inform(#env ": " help); \
301 if (PrintOptions && var) _objc_inform(#env " is set"); \
305 OPTION(PrintImages, OBJC_PRINT_IMAGES,
306 "log image and library names as they are loaded");
307 OPTION(PrintLoading, OBJC_PRINT_LOAD_METHODS,
308 "log calls to class and category +load methods");
309 OPTION(PrintInitializing, OBJC_PRINT_INITIALIZE_METHODS,
310 "log calls to class +initialize methods");
311 OPTION(PrintResolving, OBJC_PRINT_RESOLVED_METHODS,
312 "log methods created by +resolveClassMethod: and +resolveInstanceMethod:");
313 OPTION(PrintConnecting, OBJC_PRINT_CLASS_SETUP,
314 "log progress of class and category setup");
315 OPTION(PrintProtocols, OBJC_PRINT_PROTOCOL_SETUP,
316 "log progress of protocol setup");
317 OPTION(PrintIvars, OBJC_PRINT_IVAR_SETUP,
318 "log processing of non-fragile ivars");
319 OPTION(PrintVtables, OBJC_PRINT_VTABLE_SETUP,
320 "log processing of class vtables");
321 OPTION(PrintVtableImages, OBJC_PRINT_VTABLE_IMAGES,
322 "print vtable images showing overridden methods");
323 OPTION(PrintCaches, OBJC_PRINT_CACHE_SETUP,
324 "log processing of method caches");
325 OPTION(PrintFuture, OBJC_PRINT_FUTURE_CLASSES,
326 "log use of future classes for toll-free bridging");
327 OPTION(PrintGC, OBJC_PRINT_GC,
328 "log some GC operations");
329 OPTION(PrintPreopt, OBJC_PRINT_PREOPTIMIZATION,
330 "log preoptimization courtesy of dyld shared cache");
331 OPTION(PrintCxxCtors, OBJC_PRINT_CXX_CTORS,
332 "log calls to C++ ctors and dtors for instance variables");
333 OPTION(PrintExceptions, OBJC_PRINT_EXCEPTIONS,
334 "log exception handling");
335 OPTION(PrintExceptionThrow, OBJC_PRINT_EXCEPTION_THROW,
336 "log backtrace of every objc_exception_throw()");
337 OPTION(PrintAltHandlers, OBJC_PRINT_ALT_HANDLERS,
338 "log processing of exception alt handlers");
339 OPTION(PrintReplacedMethods, OBJC_PRINT_REPLACED_METHODS,
340 "log methods replaced by category implementations");
341 OPTION(PrintDeprecation, OBJC_PRINT_DEPRECATION_WARNINGS,
342 "warn about calls to deprecated runtime functions");
343 OPTION(PrintPoolHiwat, OBJC_PRINT_POOL_HIGHWATER,
344 "log high-water marks for autorelease pools");
345 OPTION(PrintCustomRR, OBJC_PRINT_CUSTOM_RR,
346 "log classes with un-optimized custom retain/release methods");
347 OPTION(PrintCustomAWZ, OBJC_PRINT_CUSTOM_AWZ,
348 "log classes with un-optimized custom allocWithZone methods");
350 OPTION(DebugUnload, OBJC_DEBUG_UNLOAD,
351 "warn about poorly-behaving bundles when unloaded");
352 OPTION(DebugFragileSuperclasses, OBJC_DEBUG_FRAGILE_SUPERCLASSES,
353 "warn about subclasses that may have been broken by subsequent changes to superclasses");
354 OPTION(DebugFinalizers, OBJC_DEBUG_FINALIZERS,
355 "warn about classes that implement -dealloc but not -finalize");
356 OPTION(DebugNilSync, OBJC_DEBUG_NIL_SYNC,
357 "warn about @synchronized(nil), which does no synchronization");
358 OPTION(DebugNonFragileIvars, OBJC_DEBUG_NONFRAGILE_IVARS,
359 "capriciously rearrange non-fragile ivars");
360 OPTION(DebugAltHandlers, OBJC_DEBUG_ALT_HANDLERS,
361 "record more info about bad alt handler use");
363 OPTION(UseInternalZone, OBJC_USE_INTERNAL_ZONE,
364 "allocate runtime data in a dedicated malloc zone");
366 OPTION(DisableGC, OBJC_DISABLE_GC,
367 "force GC OFF, even if the executable wants it on");
368 OPTION(DisableVtables, OBJC_DISABLE_VTABLES,
369 "disable vtable dispatch");
370 OPTION(DisablePreopt, OBJC_DISABLE_PREOPTIMIZATION,
371 "disable preoptimization courtesy of dyld shared cache");
378 /***********************************************************************
380 * OBJC_PRINT_REPLACED_METHODS implementation
381 **********************************************************************/
383 logReplacedMethod(const char *className, SEL s,
384 BOOL isMeta, const char *catName,
385 IMP oldImp, IMP newImp)
387 const char *oldImage = "??";
388 const char *newImage = "??";
390 // Silently ignore +load replacement because category +load is special
391 if (s == SEL_load) return;
394 // don't know dladdr()/dli_fname equivalent
398 if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
399 if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
402 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
403 isMeta ? '+' : '-', className, sel_getName(s),
404 catName ? "by category " : "", catName ? catName : "",
405 oldImp, oldImage, newImp, newImage);
410 /***********************************************************************
411 * objc_setMultithreaded.
412 **********************************************************************/
413 void objc_setMultithreaded (BOOL flag)
415 OBJC_WARN_DEPRECATED;
417 // Nothing here. Thread synchronization in the runtime is always active.
421 /***********************************************************************
422 * _objc_fetch_pthread_data
423 * Fetch objc's pthread data for this thread.
424 * If the data doesn't exist yet and create is NO, return NULL.
425 * If the data doesn't exist yet and create is YES, allocate and return it.
426 **********************************************************************/
427 _objc_pthread_data *_objc_fetch_pthread_data(BOOL create)
429 _objc_pthread_data *data;
431 data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
432 if (!data && create) {
433 data = (_objc_pthread_data *)
434 _calloc_internal(1, sizeof(_objc_pthread_data));
435 tls_set(_objc_pthread_key, data);
442 /***********************************************************************
443 * _objc_pthread_destroyspecific
444 * Destructor for objc's per-thread data.
445 * arg shouldn't be NULL, but we check anyway.
446 **********************************************************************/
447 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
448 void _objc_pthread_destroyspecific(void *arg)
450 _objc_pthread_data *data = (_objc_pthread_data *)arg;
452 _destroyInitializingClassList(data->initializingClasses);
453 _destroySyncCache(data->syncCache);
454 _destroyAltHandlerList(data->handlerList);
456 // add further cleanup here...
458 _free_internal(data);
465 #if SUPPORT_DIRECT_THREAD_KEYS
466 _objc_pthread_key = TLS_DIRECT_KEY;
467 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
469 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
474 /***********************************************************************
476 * Former library initializer. This function is now merely a placeholder
477 * for external callers. All runtime initialization has now been moved
478 * to map_images() and _objc_init.
479 **********************************************************************/
486 #if !(TARGET_OS_WIN32 || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)
487 /***********************************************************************
488 * _objc_setNilReceiver
489 **********************************************************************/
490 id _objc_setNilReceiver(id newNilReceiver)
494 oldNilReceiver = _objc_nilReceiver;
495 _objc_nilReceiver = newNilReceiver;
497 return oldNilReceiver;
500 /***********************************************************************
501 * _objc_getNilReceiver
502 **********************************************************************/
503 id _objc_getNilReceiver(void)
505 return _objc_nilReceiver;
510 /***********************************************************************
511 * objc_setForwardHandler
512 **********************************************************************/
513 void objc_setForwardHandler(void *fwd, void *fwd_stret)
515 _objc_forward_handler = fwd;
516 _objc_forward_stret_handler = fwd_stret;
520 #if defined(__i386__) || defined(__x86_64__)
522 /**********************************************************************
524 * Returns the number of BYTES needed
525 * for a branch from entry to target.
526 **********************************************************************/
527 size_t objc_branch_size(void *entry, void *target)
529 return objc_cond_branch_size(entry, target, COND_ALWAYS);
533 objc_cond_branch_size(void *entry, void *target, unsigned cond)
535 // For simplicity, always use 32-bit relative jumps.
536 if (cond == COND_ALWAYS) return 5;
540 /**********************************************************************
542 * Writes at entry an i386 branch instruction sequence that branches to target.
543 * The sequence written will be objc_branch_size(entry, target) BYTES.
544 * Returns the number of BYTES written.
545 **********************************************************************/
546 size_t objc_write_branch(void *entry, void *target)
548 return objc_write_cond_branch(entry, target, COND_ALWAYS);
552 objc_write_cond_branch(void *entry, void *target, unsigned cond)
554 uint8_t *address = (uint8_t *)entry; // instructions written to here
555 intptr_t destination = (intptr_t)target; // branch dest as absolute address
556 intptr_t displacement = (intptr_t)destination - ((intptr_t)address + objc_cond_branch_size(entry, target, cond)); // branch dest as relative offset
558 // For simplicity, always use 32-bit relative jumps
559 if (cond != COND_ALWAYS) {
560 *address++ = 0x0f; // Jcc prefix
563 *address++ = displacement & 0xff;
564 *address++ = (displacement >> 8) & 0xff;
565 *address++ = (displacement >> 16) & 0xff;
566 *address++ = (displacement >> 24) & 0xff;
568 return address - (uint8_t *)entry;
579 OBJC_EXTERN Class _objc_getOrigClass(const char *name);
581 const char *class_getImageName(Class cls)
585 DWORD charactersCopied;
590 if (!cls) return NULL;
593 cls = _objc_getOrigClass(_class_getName(cls));
596 charactersCopied = 0;
597 szFileName = malloc(MAX_PATH * sizeof(TCHAR));
599 origCls = objc_getOrigClass(class_getName(cls));
601 res = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCTSTR)origCls, &classModule);
602 if (res && classModule) {
603 charactersCopied = GetModuleFileName(classModule, szFileName, MAX_PATH * sizeof(TCHAR));
605 if (classModule) FreeLibrary(classModule);
606 if (charactersCopied) {
607 return (const char *)szFileName;
612 return dyld_image_path_containing_address(cls);
617 const char **objc_copyImageNames(unsigned int *outCount)
621 int max = HeaderCount;
623 const TCHAR **names = (const TCHAR **)calloc(max+1, sizeof(TCHAR *));
625 const char **names = (const char **)calloc(max+1, sizeof(char *));
628 for (hi = FirstHeader; hi != NULL && count < max; hi = hi->next) {
630 if (hi->moduleName) {
631 names[count++] = hi->moduleName;
635 names[count++] = hi->fname;
642 // Return NULL instead of empty list if there are no images
647 if (outCount) *outCount = count;
652 /**********************************************************************
654 **********************************************************************/
656 objc_copyClassNamesForImage(const char *image, unsigned int *outCount)
661 if (outCount) *outCount = 0;
666 for (hi = FirstHeader; hi != NULL; hi = hi->next) {
668 if (0 == wcscmp((TCHAR *)image, hi->moduleName)) break;
670 if (0 == strcmp(image, hi->fname)) break;
675 if (outCount) *outCount = 0;
679 return _objc_copyClassNamesForImage(hi, outCount);
683 /**********************************************************************
684 * Fast Enumeration Support
685 **********************************************************************/
687 static void (*enumerationMutationHandler)(id);
689 /**********************************************************************
690 * objc_enumerationMutation
691 * called by compiler when a mutation is detected during foreach iteration
692 **********************************************************************/
693 void objc_enumerationMutation(id object) {
694 if (enumerationMutationHandler == nil) {
695 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", object);
697 (*enumerationMutationHandler)(object);
701 /**********************************************************************
702 * objc_setEnumerationMutationHandler
703 * an entry point to customize mutation error handing
704 **********************************************************************/
705 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
706 enumerationMutationHandler = handler;
710 /**********************************************************************
711 * Associative Reference Support
712 **********************************************************************/
715 id objc_getAssociatedObject_gc(id object, const void *key) {
716 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
720 id objc_getAssociatedObject_non_gc(id object, const void *key) {
721 return _object_get_associative_reference(object, (void *)key);
724 id objc_getAssociatedObject(id object, const void *key) {
727 return (id)auto_zone_get_associative_ref(gc_zone, object, (void *)key);
731 return _object_get_associative_reference(object, (void *)key);
736 void objc_setAssociatedObject_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
737 if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
738 value = ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
740 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
744 void objc_setAssociatedObject_non_gc(id object, const void *key, id value, objc_AssociationPolicy policy) {
745 _object_set_associative_reference(object, (void *)key, value, policy);
748 void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
751 if ((policy & OBJC_ASSOCIATION_COPY_NONATOMIC) == OBJC_ASSOCIATION_COPY_NONATOMIC) {
752 value = ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
754 auto_zone_set_associative_ref(gc_zone, object, (void *)key, value);
758 // Note, creates a retained reference in non-GC.
759 _object_set_associative_reference(object, (void *)key, value, policy);
763 void objc_removeAssociatedObjects(id object) {
766 auto_zone_erase_associative_refs(gc_zone, object);
770 if (_class_instancesHaveAssociatedObjects(_object_getClass(object))) _object_remove_assocations(object);
774 BOOL class_instancesHaveAssociatedObjects(Class cls) {
775 return _class_instancesHaveAssociatedObjects(cls);
779 /**********************************************************************
782 * Debugger mode is used when gdb wants to call runtime functions
783 * and other methods while other threads are stopped. The runtime
784 * provides best-effort functionality while avoiding deadlocks
785 * with the stopped threads. gdb is responsible for ensuring that all
786 * threads but one stay stopped.
788 * When debugger mode starts, the runtime acquires as many locks as
789 * it can. Any locks that can't be acquired are off-limits until
790 * debugger mode ends. The locking functions in objc-os.h check each
791 * operation and halt if a disallowed lock is used; gdb catches that
792 * trap and cleans up.
794 * Each ABI is responsible for tracking its locks. Any lock not
795 * handled there is a potential gdb deadlock.
796 **********************************************************************/
798 #if SUPPORT_DEBUGGER_MODE
800 int DebuggerMode = DEBUGGER_OFF;
801 objc_thread_t DebuggerModeThread = 0;
802 static int DebuggerModeCount;
804 /**********************************************************************
805 * gdb_objc_startDebuggerMode
806 * Start debugger mode by taking locks. Return 0 if not enough locks
808 **********************************************************************/
809 int gdb_objc_startDebuggerMode(uint32_t flags)
811 BOOL wantFull = flags & OBJC_DEBUGMODE_FULL;
812 if (! DebuggerMode) {
813 // Start debugger mode
814 int mode = startDebuggerMode(); // Do this FIRST
815 if (mode == DEBUGGER_OFF) {
819 else if (mode == DEBUGGER_PARTIAL && wantFull) {
827 DebuggerModeCount = 1;
828 DebuggerModeThread = thread_self();
832 else if (DebuggerMode == DEBUGGER_PARTIAL && wantFull) {
833 // Debugger mode already active, but not as requested - sorry
837 // Debugger mode already active as requested
838 if (thread_self() == DebuggerModeThread) {
842 _objc_inform("DEBUGGER MODE: debugger is buggy: can't run "
843 "debugger mode from two threads!");
850 /**********************************************************************
851 * gdb_objc_endDebuggerMode
852 * Relinquish locks and end debugger mode.
853 **********************************************************************/
854 void gdb_objc_endDebuggerMode(void)
856 if (DebuggerMode && thread_self() == DebuggerModeThread) {
857 if (--DebuggerModeCount == 0) {
859 DebuggerModeThread = 0;
860 endDebuggerMode(); // Do this LAST
863 _objc_inform("DEBUGGER MODE: debugger is buggy: debugger mode "
864 "not active for this thread!");
869 /**********************************************************************
870 * gdb_objc_debuggerModeFailure
871 * Breakpoint hook for gdb when debugger mode can't finish something
872 **********************************************************************/
873 void gdb_objc_debuggerModeFailure(void)
875 _objc_fatal("DEBUGGER MODE: failed");
878 // SUPPORT_DEBUGGER_MODE