Loading...
--- xnu/xnu-12377.101.15/libkern/c++/OSMetaClass.cpp
+++ xnu/xnu-124.1/libkern/c++/OSMetaClass.cpp
@@ -1,1611 +1,794 @@
/*
- * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * unlawful or unlicensed copies of an Apple operating system, or to
- * circumvent, violate, or enable the circumvention or violation of, any
- * terms of an Apple operating system software license agreement.
- *
- * Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
*/
/* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */
#include <string.h>
+#include <sys/systm.h>
#include <libkern/OSReturn.h>
#include <libkern/c++/OSMetaClass.h>
+
#include <libkern/c++/OSObject.h>
-#include <libkern/c++/OSKext.h>
-
#include <libkern/c++/OSCollectionIterator.h>
#include <libkern/c++/OSDictionary.h>
-#include <libkern/c++/OSArray.h>
-#include <libkern/c++/OSSet.h>
+#include <libkern/c++/OSArray.h>
+#include <libkern/c++/OSSet.h>
#include <libkern/c++/OSSymbol.h>
#include <libkern/c++/OSNumber.h>
#include <libkern/c++/OSSerialize.h>
-
#include <libkern/c++/OSLib.h>
#include <libkern/OSAtomic.h>
-#include <IOKit/IOLib.h>
-
-#include <IOKit/IOKitDebug.h>
-
-
__BEGIN_DECLS
-#include <sys/systm.h>
#include <mach/mach_types.h>
-#include <kern/locks.h>
+#include <mach/etap_events.h>
+#include <kern/lock.h>
#include <kern/clock.h>
#include <kern/thread_call.h>
-#include <kern/host.h>
+#include <mach/kmod.h>
#include <mach/mach_interface.h>
-#include <stddef.h>
-
-#if PRAGMA_MARK
-#pragma mark Macros
-#endif /* PRAGMA_MARK */
-/*********************************************************************
-* Macros
-*********************************************************************/
+
+extern void OSRuntimeUnloadCPP(kmod_info_t *ki, void *);
+
+#if OSALLOCDEBUG
+extern int debug_container_malloc_size;
+#define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
+#else
+#define ACCUMSIZE(s)
+#endif /* OSALLOCDEBUG */
+
__END_DECLS
-#if PRAGMA_MARK
-#pragma mark Internal constants & data structs
-#endif /* PRAGMA_MARK */
-/*********************************************************************
-* Internal constants & data structs
-*********************************************************************/
-OSKextLogSpec kOSMetaClassLogSpec =
- kOSKextLogErrorLevel |
- kOSKextLogLoadFlag |
- kOSKextLogKextBookkeepingFlag;
-
static enum {
- kCompletedBootstrap = 0,
- kNoDictionaries = 1,
- kMakingDictionaries = 2
+ kCompletedBootstrap = 0,
+ kNoDictionaries = 1,
+ kMakingDictionaries = 2
} sBootstrapState = kNoDictionaries;
-static const int kClassCapacityIncrement = 40;
-static const int kKModCapacityIncrement = 10;
-static OSDictionary * sAllClassesDict;
-static unsigned int sDeepestClass;
-IOLock * sAllClassesLock = NULL;
-IOLock * sInstancesLock = NULL;
-
-/*
- * While loading a kext and running all its constructors to register
- * all OSMetaClass classes, the classes are queued up here. Only one
- * kext can be in flight at a time, guarded by sStalledClassesLock
- */
+static const int kClassCapacityIncrement = 40;
+static const int kKModCapacityIncrement = 10;
+static OSDictionary *sAllClassesDict, *sKModClassesDict;
+
+static mutex_t *loadLock;
static struct StalledData {
- const char * kextIdentifier;
- OSReturn result;
- unsigned int capacity;
- unsigned int count;
- OSMetaClass ** classes;
-} * sStalled;
-IOLock * sStalledClassesLock = NULL;
-
-struct ExpansionData {
- OSOrderedSet * instances;
- OSKext * kext;
- uint32_t retain;
-#if IOTRACKING
- IOTrackingQueue * tracking;
-#endif
-};
-
-
-#if PRAGMA_MARK
-#pragma mark OSMetaClassBase
-#endif /* PRAGMA_MARK */
-/*********************************************************************
-* OSMetaClassBase.
-*********************************************************************/
-
-#if APPLE_KEXT_VTABLE_PADDING
-/*********************************************************************
-* Reserved vtable functions.
-*********************************************************************/
-#if defined(__arm64__) || defined(__arm__)
-void
-OSMetaClassBase::_RESERVEDOSMetaClassBase0()
-{
- panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0);
-}
-void
-OSMetaClassBase::_RESERVEDOSMetaClassBase1()
-{
- panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1);
-}
-void
-OSMetaClassBase::_RESERVEDOSMetaClassBase2()
-{
- panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 2);
-}
-void
-OSMetaClassBase::_RESERVEDOSMetaClassBase3()
-{
- panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3);
-}
-#endif /* defined(__arm64__) || defined(__arm__) */
-
-// As these slots are used move them up inside the #if above
-void
-OSMetaClassBase::_RESERVEDOSMetaClassBase4()
-{
- panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4);
-}
-void
-OSMetaClassBase::_RESERVEDOSMetaClassBase5()
-{
- panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5);
-}
-void
-OSMetaClassBase::_RESERVEDOSMetaClassBase6()
-{
- panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 6);
-}
-#endif
-
-/*********************************************************************
-*********************************************************************/
-
-#if defined(__arm__) || defined(__arm64__)
-
-#if defined(HAS_APPLE_PAC)
-#include <ptrauth.h>
-#endif /* defined(HAS_APPLE_PAC) */
-
-/*
- * IHI0059A "C++ Application Binary Interface Standard for the ARM 64 - bit Architecture":
- *
- * 3.2.1 Representation of pointer to member function The generic C++ ABI [GC++ABI]
- * specifies that a pointer to member function is a pair of words <ptr, adj>. The
- * least significant bit of ptr discriminates between (0) the address of a non-
- * virtual member function and (1) the offset in the class's virtual table of the
- * address of a virtual function. This encoding cannot work for the AArch64
- * instruction set where the architecture reserves all bits of code addresses. This
- * ABI specifies that adj contains twice the this adjustment, plus 1 if the member
- * function is virtual. The least significant bit of adj then makes exactly the
- * same discrimination as the least significant bit of ptr does for Itanium. A
- * pointer to member function is NULL when ptr = 0 and the least significant bit of
- * adj is zero.
- */
-
-OSMetaClassBase::_ptf_t
-#if defined(HAS_APPLE_PAC) && \
- __has_feature(ptrauth_member_function_pointer_type_discrimination)
-OSMetaClassBase::_ptmf2ptf(const OSMetaClassBase *self __attribute__((unused)),
- void (OSMetaClassBase::*func)(void))
-#else
-OSMetaClassBase::_ptmf2ptf(const OSMetaClassBase *self,
- void (OSMetaClassBase::*func)(void))
-#endif
-{
- struct ptmf_t {
- _ptf_t fPFN;
- ptrdiff_t delta;
- };
- union {
- void (OSMetaClassBase::*fIn)(void);
- struct ptmf_t pTMF;
- } map;
- _ptf_t pfn;
-
- map.fIn = func;
- pfn = map.pTMF.fPFN;
-
-#if defined(HAS_APPLE_PAC) && \
- __has_feature(ptrauth_member_function_pointer_type_discrimination)
- // Authenticate 'pfn' using the member function pointer type discriminator
- // and resign it as a C function pointer. 'pfn' can point to either a
- // non-virtual function or a virtual member function thunk.
- // It can also be NULL.
- if (pfn) {
- pfn = ptrauth_auth_and_resign(pfn, ptrauth_key_function_pointer,
- ptrauth_type_discriminator(__typeof__(func)),
- ptrauth_key_function_pointer,
- ptrauth_function_pointer_type_discriminator(_ptf_t));
- }
- return pfn;
-#else
- if (map.pTMF.delta & 1) {
- // virtual
- union {
- const OSMetaClassBase *fObj;
- _ptf_t **vtablep;
- } u;
- u.fObj = self;
-
- // Virtual member function so dereference table
-#if defined(HAS_APPLE_PAC)
- // The entity hash is stored in the top 32-bits of the vtable offset of a
- // member function pointer.
- uint32_t entity_hash = ((uintptr_t)pfn) >> 32;
- pfn = (_ptf_t)(((uintptr_t) pfn) & 0xFFFFFFFF);
-
-#if __has_builtin(__builtin_get_vtable_pointer)
- const _ptf_t *vtablep =
- (const _ptf_t *)__builtin_get_vtable_pointer(u.fObj);
-#else
- // Authenticate the vtable pointer.
- const _ptf_t *vtablep = ptrauth_auth_data(*u.vtablep,
- ptrauth_key_cxx_vtable_pointer, 0);
-#endif
- // Calculate the address of the vtable entry.
- _ptf_t *vtentryp = (_ptf_t *)(((uintptr_t)vtablep) + (uintptr_t)pfn);
- // Load the pointer from the vtable entry.
- pfn = *vtentryp;
-
- // Finally, resign the vtable entry as a function pointer.
- uintptr_t auth_data = ptrauth_blend_discriminator(vtentryp, entity_hash);
- pfn = ptrauth_auth_and_resign(pfn, ptrauth_key_function_pointer,
- auth_data, ptrauth_key_function_pointer,
- ptrauth_function_pointer_type_discriminator(_ptf_t));
-#else /* defined(HAS_APPLE_PAC) */
- pfn = *(_ptf_t *)(((uintptr_t)*u.vtablep) + (uintptr_t)pfn);
-#endif /* !defined(HAS_APPLE_PAC) */
- return pfn;
- } else {
- // Not virtual, i.e. plain member func
- return pfn;
- }
-#endif
-}
-
-#endif /* defined(__arm__) || defined(__arm64__) */
-/*********************************************************************
-* These used to be inline in the header but gcc didn't believe us
-* Now we MUST pull the inline out at least until the compiler is
-* repaired.
-*
-* Helper inlines for runtime type preprocessor macros
-*********************************************************************/
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClassBase::safeMetaCast(
- const OSMetaClassBase * me,
- const OSMetaClass * toType)
-{
- return (me)? me->metaCast(toType) : NULL;
-}
-
-/// A helper function to crash with a kernel panic.
-__attribute__((cold, not_tail_called, noreturn))
-static inline void
-panic_crash_fail_cast(const OSMetaClassBase *me,
- const OSMetaClass *toType)
-{
- panic("Unexpected cast fail: from %p to %p", me, toType);
- __builtin_unreachable();
-}
-
-OSMetaClassBase *
-OSMetaClassBase::requiredMetaCast(
- const OSMetaClassBase * me,
- const OSMetaClass * toType)
-{
- if (!me) {
- return NULL;
- }
- OSMetaClassBase *tmp = safeMetaCast(me, toType);
- if (!tmp) {
- panic_crash_fail_cast(me, toType);
- }
- return tmp;
-}
-
-/*********************************************************************
-*********************************************************************/
-bool
-OSMetaClassBase::checkTypeInst(
- const OSMetaClassBase * inst,
- const OSMetaClassBase * typeinst)
-{
- const OSMetaClass * toType = OSTypeIDInst(typeinst);
- return typeinst && inst && (NULL != inst->metaCast(toType));
-}
-
-/*********************************************************************
-*********************************************************************/
-void
-OSMetaClassBase::
-initialize()
-{
- sAllClassesLock = IOLockAlloc();
- sStalledClassesLock = IOLockAlloc();
- sInstancesLock = IOLockAlloc();
-}
-
-#if APPLE_KEXT_VTABLE_PADDING
-/*********************************************************************
-* If you need this slot you had better setup an IOCTL style interface.
-* 'Cause the whole kernel world depends on OSMetaClassBase and YOU
-* CANT change the VTABLE size ever.
-*********************************************************************/
-void
-OSMetaClassBase::_RESERVEDOSMetaClassBase7()
-{
- panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7);
-}
-#endif
-
-/*********************************************************************
-*********************************************************************/
+ const char *kmodName;
+ OSReturn result;
+ unsigned int capacity;
+ unsigned int count;
+ OSMetaClass **classes;
+} *sStalled;
+
+static unsigned int sConsiderUnloadDelay = 60; /* secs */
+
+static const char OSMetaClassBasePanicMsg[] =
+ "OSMetaClassBase::_RESERVEDOSMetaClassBase%d called\n";
+
+void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
+ { panic(OSMetaClassBasePanicMsg, 0); }
+void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
+ { panic(OSMetaClassBasePanicMsg, 1); }
+void OSMetaClassBase::_RESERVEDOSMetaClassBase2()
+ { panic(OSMetaClassBasePanicMsg, 2); }
+void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
+ { panic(OSMetaClassBasePanicMsg, 3); }
+void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
+ { panic(OSMetaClassBasePanicMsg, 4); }
+void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
+ { panic(OSMetaClassBasePanicMsg, 5); }
+void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
+ { panic(OSMetaClassBasePanicMsg, 6); }
+void OSMetaClassBase::_RESERVEDOSMetaClassBase7()
+ { panic(OSMetaClassBasePanicMsg, 7); }
+
OSMetaClassBase::OSMetaClassBase()
{
}
-/*********************************************************************
-*********************************************************************/
OSMetaClassBase::~OSMetaClassBase()
{
- void ** thisVTable;
-
- thisVTable = (void **) this;
- *thisVTable = (void *) -1UL;
-}
-
-/*********************************************************************
-*********************************************************************/
-bool
-OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const
-{
- return this == anObj;
-}
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const
-{
- return toMeta->checkMetaCast(this);
-}
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const
-{
- return OSMetaClass::checkMetaCastWithName(toMetaSymb, this);
-}
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClassBase::metaCast(const OSString * toMetaStr) const
-{
- const OSSymbol * tempSymb = OSSymbol::withString(toMetaStr);
- OSMetaClassBase * ret = NULL;
- if (tempSymb) {
- ret = metaCast(tempSymb);
- tempSymb->release();
- }
- return ret;
-}
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClassBase::metaCast(const char * toMetaCStr) const
-{
- const OSSymbol * tempSymb = OSSymbol::withCString(toMetaCStr);
- OSMetaClassBase * ret = NULL;
- if (tempSymb) {
- ret = metaCast(tempSymb);
- tempSymb->release();
- }
- return ret;
-}
-
-#if PRAGMA_MARK
-#pragma mark OSMetaClassMeta
-#endif /* PRAGMA_MARK */
-/*********************************************************************
-* OSMetaClassMeta - the bootstrap metaclass of OSMetaClass
-*********************************************************************/
-class OSMetaClassMeta : public OSMetaClass
+ void **thisVTable;
+
+ thisVTable = (void **) this;
+ *thisVTable = (void *) -1UL;
+}
+
+bool OSMetaClassBase::isEqualTo(const OSMetaClassBase *anObj) const
+{
+ return this == anObj;
+}
+
+OSMetaClassBase *OSMetaClassBase::metaCast(const OSMetaClass *toMeta) const
+{
+ return toMeta->checkMetaCast(this);
+}
+
+OSMetaClassBase *OSMetaClassBase::metaCast(const OSSymbol *toMetaSymb) const
+{
+ return OSMetaClass::checkMetaCastWithName(toMetaSymb, this);
+}
+
+OSMetaClassBase *OSMetaClassBase::metaCast(const OSString *toMetaStr) const
+{
+ const OSSymbol *tempSymb = OSSymbol::withString(toMetaStr);
+ OSMetaClassBase *ret = 0;
+ if (tempSymb) {
+ ret = metaCast(tempSymb);
+ tempSymb->release();
+ }
+ return ret;
+}
+
+OSMetaClassBase *OSMetaClassBase::metaCast(const char *toMetaCStr) const
+{
+ const OSSymbol *tempSymb = OSSymbol::withCStringNoCopy(toMetaCStr);
+ OSMetaClassBase *ret = 0;
+ if (tempSymb) {
+ ret = metaCast(tempSymb);
+ tempSymb->release();
+ }
+ return ret;
+}
+
+class OSMetaClassMeta : public OSMetaClass
{
public:
- OSMetaClassMeta();
- OSObject * alloc() const override;
+ OSMetaClassMeta();
+ OSObject *alloc() const;
};
OSMetaClassMeta::OSMetaClassMeta()
- : OSMetaClass("OSMetaClass", NULL, sizeof(OSMetaClass))
-{
-}
-OSObject *
-OSMetaClassMeta::alloc() const
-{
- return NULL;
-}
+ : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass))
+ { }
+OSObject *OSMetaClassMeta::alloc() const { return 0; }
static OSMetaClassMeta sOSMetaClassMeta;
const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta;
-const OSMetaClass *
-OSMetaClass::getMetaClass() const
-{
- return &sOSMetaClassMeta;
-}
-
-#if PRAGMA_MARK
-#pragma mark OSMetaClass
-#endif /* PRAGMA_MARK */
-/*********************************************************************
-* OSMetaClass
-*********************************************************************/
-
-#if APPLE_KEXT_VTABLE_PADDING
-/*********************************************************************
-* Reserved functions.
-*********************************************************************/
-void
-OSMetaClass::_RESERVEDOSMetaClass0()
-{
- panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0);
-}
-void
-OSMetaClass::_RESERVEDOSMetaClass1()
-{
- panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1);
-}
-void
-OSMetaClass::_RESERVEDOSMetaClass2()
-{
- panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2);
-}
-void
-OSMetaClass::_RESERVEDOSMetaClass3()
-{
- panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3);
-}
-void
-OSMetaClass::_RESERVEDOSMetaClass4()
-{
- panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4);
-}
-void
-OSMetaClass::_RESERVEDOSMetaClass5()
-{
- panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5);
-}
-void
-OSMetaClass::_RESERVEDOSMetaClass6()
-{
- panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6);
-}
-void
-OSMetaClass::_RESERVEDOSMetaClass7()
-{
- panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7);
-}
-#endif
-
-/*********************************************************************
-*********************************************************************/
-static void
-OSMetaClassLogErrorForKext(
- OSReturn error,
- OSKext * aKext)
-{
- const char * message = NULL;
-
- switch (error) {
- case kOSReturnSuccess:
+const OSMetaClass * OSMetaClass::getMetaClass() const
+ { return &sOSMetaClassMeta; }
+
+static const char OSMetaClassPanicMsg[] =
+ "OSMetaClass::_RESERVEDOSMetaClass%d called\n";
+
+void OSMetaClass::_RESERVEDOSMetaClass0()
+ { panic(OSMetaClassPanicMsg, 0); }
+void OSMetaClass::_RESERVEDOSMetaClass1()
+ { panic(OSMetaClassPanicMsg, 1); }
+void OSMetaClass::_RESERVEDOSMetaClass2()
+ { panic(OSMetaClassPanicMsg, 2); }
+void OSMetaClass::_RESERVEDOSMetaClass3()
+ { panic(OSMetaClassPanicMsg, 3); }
+void OSMetaClass::_RESERVEDOSMetaClass4()
+ { panic(OSMetaClassPanicMsg, 4); }
+void OSMetaClass::_RESERVEDOSMetaClass5()
+ { panic(OSMetaClassPanicMsg, 5); }
+void OSMetaClass::_RESERVEDOSMetaClass6()
+ { panic(OSMetaClassPanicMsg, 6); }
+void OSMetaClass::_RESERVEDOSMetaClass7()
+ { panic(OSMetaClassPanicMsg, 7); }
+
+void OSMetaClass::logError(OSReturn result)
+{
+ const char *msg;
+
+ switch (result) {
+ case kOSMetaClassNoInit:
+ msg="OSMetaClass::preModLoad wasn't called, runtime internal error";
+ break;
+ case kOSMetaClassNoDicts:
+ msg="Allocation failure for Metaclass internal dictionaries"; break;
+ case kOSMetaClassNoKModSet:
+ msg="Allocation failure for internal kmodule set"; break;
+ case kOSMetaClassNoInsKModSet:
+ msg="Can't insert the KMod set into the module dictionary"; break;
+ case kOSMetaClassDuplicateClass:
+ msg="Duplicate class"; break;
+ case kOSMetaClassNoSuper:
+ msg="Can't associate a class with its super class"; break;
+ case kOSMetaClassInstNoSuper:
+ msg="Instance construction, unknown super class."; break;
+ default:
+ case kOSMetaClassInternal:
+ msg="runtime internal error"; break;
+ case kOSReturnSuccess:
+ return;
+ }
+ printf("%s\n", msg);
+}
+
+OSMetaClass::OSMetaClass(const char *inClassName,
+ const OSMetaClass *inSuperClass,
+ unsigned int inClassSize)
+{
+ instanceCount = 0;
+ classSize = inClassSize;
+ superClassLink = inSuperClass;
+
+ className = (const OSSymbol *) inClassName;
+
+ if (!sStalled) {
+ printf("OSMetaClass::preModLoad wasn't called for %s, "
+ "runtime internal error\n", inClassName);
+ } else if (!sStalled->result) {
+ // Grow stalled array if neccessary
+ if (sStalled->count >= sStalled->capacity) {
+ OSMetaClass **oldStalled = sStalled->classes;
+ int oldSize = sStalled->capacity * sizeof(OSMetaClass *);
+ int newSize = oldSize
+ + kKModCapacityIncrement * sizeof(OSMetaClass *);
+
+ sStalled->classes = (OSMetaClass **) kalloc(newSize);
+ if (!sStalled->classes) {
+ sStalled->classes = oldStalled;
+ sStalled->result = kOSMetaClassNoTempData;
return;
- case kOSMetaClassNoInit: // xxx - never returned; logged at fail site
- message = "OSMetaClass: preModLoad() wasn't called (runtime internal error).";
+ }
+
+ sStalled->capacity += kKModCapacityIncrement;
+ memmove(sStalled->classes, oldStalled, oldSize);
+ kfree((vm_offset_t)oldStalled, oldSize);
+ ACCUMSIZE(newSize - oldSize);
+ }
+
+ sStalled->classes[sStalled->count++] = this;
+ }
+}
+
+OSMetaClass::~OSMetaClass()
+{
+ do {
+ OSCollectionIterator *iter;
+
+ if (sAllClassesDict)
+ sAllClassesDict->removeObject(className);
+
+ iter = OSCollectionIterator::withCollection(sKModClassesDict);
+ if (!iter)
+ break;
+
+ OSSymbol *iterKey;
+ while ( (iterKey = (OSSymbol *) iter->getNextObject()) ) {
+ OSSet *kmodClassSet;
+ kmodClassSet = (OSSet *) sKModClassesDict->getObject(iterKey);
+ if (kmodClassSet && kmodClassSet->containsObject(this)) {
+ kmodClassSet->removeObject(this);
break;
- case kOSMetaClassNoDicts:
- message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries.";
+ }
+ }
+ iter->release();
+ } while (false);
+
+ if (sStalled) {
+ unsigned int i;
+
+ // First pass find class in stalled list
+ for (i = 0; i < sStalled->count; i++)
+ if (this == sStalled->classes[i])
break;
- case kOSMetaClassNoKModSet:
- message = "OSMetaClass: Allocation failure for internal kext recording set/set missing.";
+
+ if (i < sStalled->count) {
+ sStalled->count--;
+ if (i < sStalled->count)
+ memmove(&sStalled->classes[i], &sStalled->classes[i+1],
+ (sStalled->count - i) * sizeof(OSMetaClass *));
+ }
+ return;
+ }
+}
+
+// Don't do anything as these classes must be statically allocated
+void *OSMetaClass::operator new(size_t size) { return 0; }
+void OSMetaClass::operator delete(void *mem, size_t size) { }
+void OSMetaClass::retain() const { }
+void OSMetaClass::release() const { }
+void OSMetaClass::release(int when) const { };
+int OSMetaClass::getRetainCount() const { return 0; }
+
+const char *OSMetaClass::getClassName() const
+{
+ return className->getCStringNoCopy();
+}
+
+unsigned int OSMetaClass::getClassSize() const
+{
+ return classSize;
+}
+
+void *OSMetaClass::preModLoad(const char *kmodName)
+{
+ if (!loadLock) {
+ loadLock = mutex_alloc(ETAP_IO_AHA);
+ _mutex_lock(loadLock);
+ }
+ else
+ _mutex_lock(loadLock);
+
+ sStalled = (StalledData *) kalloc(sizeof(*sStalled));
+ if (sStalled) {
+ sStalled->classes = (OSMetaClass **)
+ kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
+ if (!sStalled->classes) {
+ kfree((vm_offset_t) sStalled, sizeof(*sStalled));
+ return 0;
+ }
+ ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + sizeof(*sStalled));
+
+ sStalled->result = kOSReturnSuccess;
+ sStalled->capacity = kKModCapacityIncrement;
+ sStalled->count = 0;
+ sStalled->kmodName = kmodName;
+ bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *));
+ }
+
+ return sStalled;
+}
+
+bool OSMetaClass::checkModLoad(void *loadHandle)
+{
+ return sStalled && loadHandle == sStalled
+ && sStalled->result == kOSReturnSuccess;
+}
+
+OSReturn OSMetaClass::postModLoad(void *loadHandle)
+{
+ OSReturn result = kOSReturnSuccess;
+ OSSet *kmodSet = 0;
+
+ if (!sStalled || loadHandle != sStalled) {
+ logError(kOSMetaClassInternal);
+ return kOSMetaClassInternal;
+ }
+
+ if (sStalled->result)
+ result = sStalled->result;
+ else switch (sBootstrapState) {
+ case kNoDictionaries:
+ sBootstrapState = kMakingDictionaries;
+ // No break; fall through
+
+ case kMakingDictionaries:
+ sKModClassesDict = OSDictionary::withCapacity(kKModCapacityIncrement);
+ sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
+ if (!sAllClassesDict || !sKModClassesDict) {
+ result = kOSMetaClassNoDicts;
+ break;
+ }
+ // No break; fall through
+
+ case kCompletedBootstrap:
+ {
+ unsigned int i;
+
+ if (!sStalled->count)
+ break; // Nothing to do so just get out
+
+ // First pass checking classes aren't already loaded
+ for (i = 0; i < sStalled->count; i++) {
+ OSMetaClass *me = sStalled->classes[i];
+
+ if (0 != sAllClassesDict->getObject((const char *) me->className)) {
+ printf("Class \"%s\" is duplicate\n", (const char *) me->className);
+ result = kOSMetaClassDuplicateClass;
+ break;
+ }
+ }
+ if (i != sStalled->count)
+ break;
+
+ kmodSet = OSSet::withCapacity(sStalled->count);
+ if (!kmodSet) {
+ result = kOSMetaClassNoKModSet;
+ break;
+ }
+
+ if (!sKModClassesDict->setObject(sStalled->kmodName, kmodSet)) {
+ result = kOSMetaClassNoInsKModSet;
+ break;
+ }
+
+ // Second pass symbolling strings and inserting classes in dictionary
+ for (unsigned int i = 0; i < sStalled->count; i++) {
+ OSMetaClass *me = sStalled->classes[i];
+ me->className =
+ OSSymbol::withCStringNoCopy((const char *) me->className);
+
+ sAllClassesDict->setObject(me->className, me);
+ kmodSet->setObject(me);
+ }
+ sBootstrapState = kCompletedBootstrap;
+ break;
+ }
+
+ default:
+ result = kOSMetaClassInternal;
+ break;
+ }
+
+ if (kmodSet)
+ kmodSet->release();
+
+ if (sStalled) {
+ ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *)
+ + sizeof(*sStalled)));
+ kfree((vm_offset_t) sStalled->classes,
+ sStalled->capacity * sizeof(OSMetaClass *));
+ kfree((vm_offset_t) sStalled, sizeof(*sStalled));
+ sStalled = 0;
+ }
+
+ logError(result);
+ mutex_unlock(loadLock);
+ return result;
+}
+
+
+void OSMetaClass::instanceConstructed() const
+{
+ // if ((0 == OSIncrementAtomic((SInt32 *)&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
+ if ((0 == OSIncrementAtomic((SInt32 *) &instanceCount)) && superClassLink)
+ superClassLink->instanceConstructed();
+}
+
+void OSMetaClass::instanceDestructed() const
+{
+ if ((1 == OSDecrementAtomic((SInt32 *) &instanceCount)) && superClassLink)
+ superClassLink->instanceDestructed();
+
+ if( ((int) instanceCount) < 0)
+ printf("%s: bad retain(%d)", getClassName(), instanceCount);
+}
+
+bool OSMetaClass::modHasInstance(const char *kmodName)
+{
+ bool result = false;
+
+ if (!loadLock) {
+ loadLock = mutex_alloc(ETAP_IO_AHA);
+ _mutex_lock(loadLock);
+ }
+ else
+ _mutex_lock(loadLock);
+
+ do {
+ OSSet *kmodClasses;
+ OSCollectionIterator *iter;
+ OSMetaClass *checkClass;
+
+ kmodClasses = OSDynamicCast(OSSet,
+ sKModClassesDict->getObject(kmodName));
+ if (!kmodClasses)
+ break;
+
+ iter = OSCollectionIterator::withCollection(kmodClasses);
+ if (!iter)
+ break;
+
+ while ( (checkClass = (OSMetaClass *) iter->getNextObject()) )
+ if (checkClass->getInstanceCount()) {
+ result = true;
break;
- case kOSMetaClassNoInsKModSet:
- message = "OSMetaClass: Failed to record class in kext.";
+ }
+
+ iter->release();
+ } while (false);
+
+ mutex_unlock(loadLock);
+
+ return result;
+}
+
+void OSMetaClass::reportModInstances(const char *kmodName)
+{
+ OSSet *kmodClasses;
+ OSCollectionIterator *iter;
+ OSMetaClass *checkClass;
+
+ kmodClasses = OSDynamicCast(OSSet,
+ sKModClassesDict->getObject(kmodName));
+ if (!kmodClasses)
+ return;
+
+ iter = OSCollectionIterator::withCollection(kmodClasses);
+ if (!iter)
+ return;
+
+ while ( (checkClass = (OSMetaClass *) iter->getNextObject()) )
+ if (checkClass->getInstanceCount()) {
+ printf("%s: %s has %d instance(s)\n",
+ kmodName,
+ checkClass->getClassName(),
+ checkClass->getInstanceCount());
+ }
+
+ iter->release();
+}
+
+static void _OSMetaClassConsiderUnloads(thread_call_param_t p0,
+ thread_call_param_t p1)
+{
+ OSSet *kmodClasses;
+ OSSymbol *kmodName;
+ OSCollectionIterator *kmods;
+ OSCollectionIterator *classes;
+ OSMetaClass *checkClass;
+ kmod_info_t *ki;
+ kern_return_t ret;
+ bool didUnload;
+
+ _mutex_lock(loadLock);
+
+ do {
+
+ kmods = OSCollectionIterator::withCollection(sKModClassesDict);
+ if (!kmods)
+ break;
+
+ didUnload = false;
+ while ( (kmodName = (OSSymbol *) kmods->getNextObject()) ) {
+
+ ki = kmod_lookupbyname((char *)kmodName->getCStringNoCopy());
+ if (!ki)
+ continue;
+
+ if (ki->reference_count)
+ continue;
+
+ kmodClasses = OSDynamicCast(OSSet,
+ sKModClassesDict->getObject(kmodName));
+ classes = OSCollectionIterator::withCollection(kmodClasses);
+ if (!classes)
+ continue;
+
+ while ((checkClass = (OSMetaClass *) classes->getNextObject())
+ && (0 == checkClass->getInstanceCount()))
+ {}
+ classes->release();
+
+ if (0 == checkClass) {
+ OSRuntimeUnloadCPP(ki, 0); // call destructors
+ ret = kmod_destroy(host_priv_self(), ki->id);
+ didUnload = true;
+ }
+
+ } while (false);
+
+ kmods->release();
+
+ } while (didUnload);
+
+ mutex_unlock(loadLock);
+}
+
+void OSMetaClass::considerUnloads()
+{
+ static thread_call_t unloadCallout;
+ AbsoluteTime when;
+
+ _mutex_lock(loadLock);
+
+ if (!unloadCallout)
+ unloadCallout = thread_call_allocate(&_OSMetaClassConsiderUnloads, 0);
+
+ thread_call_cancel(unloadCallout);
+ clock_interval_to_deadline(sConsiderUnloadDelay, 1000 * 1000 * 1000, &when);
+ thread_call_enter_delayed(unloadCallout, when);
+
+ mutex_unlock(loadLock);
+}
+
+const OSMetaClass *OSMetaClass::getMetaClassWithName(const OSSymbol *name)
+{
+ OSMetaClass *retMeta = 0;
+
+ if (!name)
+ return 0;
+
+ if (sAllClassesDict)
+ retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
+
+ if (!retMeta && sStalled)
+ {
+ // Oh dear we have to scan the stalled list and walk the
+ // the stalled list manually.
+ const char *cName = name->getCStringNoCopy();
+ unsigned int i;
+
+ // find class in stalled list
+ for (i = 0; i < sStalled->count; i++) {
+ retMeta = sStalled->classes[i];
+ if (0 == strcmp(cName, (const char *) retMeta->className))
break;
- case kOSMetaClassDuplicateClass:
- message = "OSMetaClass: Duplicate class encountered.";
- break;
- case kOSMetaClassNoSuper: // xxx - never returned
- message = "OSMetaClass: Can't associate a class with its superclass.";
- break;
- case kOSMetaClassInstNoSuper: // xxx - never returned
- message = "OSMetaClass: Instance construction error; unknown superclass.";
- break;
- case kOSMetaClassNoKext:
- message = "OSMetaClass: Kext not found for metaclass.";
- break;
- case kOSMetaClassInternal:
- default:
- message = "OSMetaClass: Runtime internal error.";
- break;
- }
-
- if (message) {
- OSKextLog(aKext, kOSMetaClassLogSpec, "%s", message);
- }
+ }
+
+ if (i < sStalled->count)
+ retMeta = 0;
+ }
+
+ return retMeta;
+}
+
+OSObject *OSMetaClass::allocClassWithName(const OSSymbol *name)
+{
+ OSObject * result;
+ _mutex_lock(loadLock);
+
+ const OSMetaClass * const meta = getMetaClassWithName(name);
+
+ if (meta)
+ result = meta->alloc();
+ else
+ result = 0;
+
+ mutex_unlock(loadLock);
+
+ return result;
+}
+
+OSObject *OSMetaClass::allocClassWithName(const OSString *name)
+{
+ const OSSymbol *tmpKey = OSSymbol::withString(name);
+ OSObject *result = allocClassWithName(tmpKey);
+ tmpKey->release();
+ return result;
+}
+
+OSObject *OSMetaClass::allocClassWithName(const char *name)
+{
+ const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
+ OSObject *result = allocClassWithName(tmpKey);
+ tmpKey->release();
+ return result;
+}
+
+
+OSMetaClassBase *OSMetaClass::
+checkMetaCastWithName(const OSSymbol *name, const OSMetaClassBase *in)
+{
+ OSMetaClassBase * result;
+ _mutex_lock(loadLock);
+ const OSMetaClass * const meta = getMetaClassWithName(name);
+
+ if (meta)
+ result = meta->checkMetaCast(in);
+ else
+ result = 0;
+
+ mutex_unlock(loadLock);
+ return result;
+}
+
+OSMetaClassBase *OSMetaClass::
+checkMetaCastWithName(const OSString *name, const OSMetaClassBase *in)
+{
+ const OSSymbol *tmpKey = OSSymbol::withString(name);
+ OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in);
+ tmpKey->release();
+ return result;
+}
+
+OSMetaClassBase *OSMetaClass::
+checkMetaCastWithName(const char *name, const OSMetaClassBase *in)
+{
+ const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
+ OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in);
+ tmpKey->release();
+ return result;
+}
+
+/*
+OSMetaClass::checkMetaCast
+ checkMetaCast(const OSMetaClassBase *check)
+
+Check to see if the 'check' object has this object in it's metaclass chain. Returns check if it is indeed a kind of the current meta class, 0 otherwise.
+
+Generally this method is not invoked directly but is used to implement the OSMetaClassBase::metaCast member function.
+
+See also OSMetaClassBase::metaCast
+
+ */
+OSMetaClassBase *OSMetaClass::checkMetaCast(const OSMetaClassBase *check) const
+{
+ const OSMetaClass * const toMeta = this;
+ const OSMetaClass *fromMeta;
+
+ for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) {
+ if (toMeta == fromMeta)
+ return (OSMetaClassBase *) check; // Discard const
+
+ if (!fromMeta->superClassLink)
+ break;
+ }
+
+ return 0;
+}
+
+void OSMetaClass::reservedCalled(int ind) const
+{
+ const char *cname = className->getCStringNoCopy();
+ panic("%s::_RESERVED%s%d called\n", cname, cname, ind);
+}
+
+const OSMetaClass *OSMetaClass::getSuperClass() const
+{
+ return superClassLink;
+}
+
+unsigned int OSMetaClass::getInstanceCount() const
+{
+ return instanceCount;
+}
+
+void OSMetaClass::printInstanceCounts()
+{
+ OSCollectionIterator *classes;
+ OSSymbol *className;
+ OSMetaClass *meta;
+
+ classes = OSCollectionIterator::withCollection(sAllClassesDict);
+ if (!classes)
return;
-}
-
-void
-OSMetaClass::logError(OSReturn error)
-{
- OSMetaClassLogErrorForKext(error, NULL);
-}
-
-/*********************************************************************
-* The core constructor for a MetaClass (defined with this name always
-* but within the scope of its represented class).
-*
-* MetaClass constructors are invoked in OSRuntimeInitializeCPP(),
-* in between calls to OSMetaClass::preModLoad(), which sets up for
-* registration, and OSMetaClass::postModLoad(), which actually
-* records all the class/kext relationships of the new MetaClasses.
-*********************************************************************/
-
-OSMetaClass::OSMetaClass(
- const char * inClassName,
- const OSMetaClass * inSuperClass,
- unsigned int inClassSize)
-{
- instanceCount = 0;
- classSize = inClassSize;
- superClassLink = inSuperClass;
-
- reserved = IOMallocType(ExpansionData);
-#if IOTRACKING
- uint32_t numSiteQs = 0;
- if ((this == &OSSymbol ::gMetaClass)
- || (this == &OSString ::gMetaClass)
- || (this == &OSNumber ::gMetaClass)
- || (this == &OSString ::gMetaClass)
- || (this == &OSData ::gMetaClass)
- || (this == &OSDictionary::gMetaClass)
- || (this == &OSArray ::gMetaClass)
- || (this == &OSSet ::gMetaClass)) {
- numSiteQs = 27;
- }
-
- reserved->tracking = IOTrackingQueueAlloc(inClassName, (uintptr_t) this,
- inClassSize, 0, kIOTrackingQueueTypeAlloc,
- numSiteQs);
-#endif
-
- /* Hack alert: We are just casting inClassName and storing it in
- * an OSString * instance variable. This may be because you can't
- * create C++ objects in static constructors, but I really don't know!
- */
- className = (const OSSymbol *)inClassName;
-
- // sStalledClassesLock taken in preModLoad
- if (!sStalled) {
- /* There's no way we can look up the kext here, unfortunately.
- */
- OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
- "OSMetaClass: preModLoad() wasn't called for class %s "
- "(runtime internal error).",
- inClassName);
- } else if (!sStalled->result) {
- // Grow stalled array if neccessary
- if (sStalled->count >= sStalled->capacity) {
- OSMetaClass **oldStalled = sStalled->classes;
- int oldCount = sStalled->capacity;
- int newCount = oldCount + kKModCapacityIncrement;
-
- sStalled->classes = kalloc_type_tag(OSMetaClass *, newCount,
- Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
- if (!sStalled->classes) {
- sStalled->classes = oldStalled;
- sStalled->result = kOSMetaClassNoTempData;
- return;
- }
-
- sStalled->capacity = newCount;
- memmove(sStalled->classes, oldStalled,
- sizeof(OSMetaClass *) * oldCount);
- kfree_type(OSMetaClass *, oldCount, oldStalled);
- OSMETA_ACCUMSIZE(sizeof(OSMetaClass *) * (newCount - oldCount));
- }
-
- sStalled->classes[sStalled->count++] = this;
- }
-}
-
-OSMetaClass::OSMetaClass(
- const char * inClassName,
- const OSMetaClass * inSuperClass,
- unsigned int inClassSize,
- zone_t * inZone,
- const char * zone_name,
- zone_create_flags_t zflags) : OSMetaClass(inClassName, inSuperClass,
- inClassSize)
-{
- if (!(kIOTracking & gIOKitDebug)) {
- *inZone = zone_create(zone_name, inClassSize,
- (zone_create_flags_t) (ZC_ZFREE_CLEARMEM | zflags));
- }
-}
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClass::~OSMetaClass()
-{
- OSKext * myKext = reserved->kext; // do not release
-
- /* Hack alert: 'className' is a C string during early C++ init, and
- * is converted to a real OSSymbol only when we record the OSKext in
- * OSMetaClass::postModLoad(). So only do this bit if we have an OSKext.
- * We can't safely cast or check 'className'.
- *
- * Also, release className *after* calling into the kext,
- * as removeClass() may access className.
- */
- IOLockLock(sAllClassesLock);
- if (sAllClassesDict) {
- if (myKext) {
- sAllClassesDict->removeObject(className);
- } else {
- sAllClassesDict->removeObject((const char *)className);
- }
- }
- IOLockUnlock(sAllClassesLock);
-
- if (myKext) {
- if (myKext->removeClass(this) != kOSReturnSuccess) {
- // xxx - what can we do?
- }
- className->release();
- }
-
- // sStalledClassesLock taken in preModLoad
- if (sStalled) {
- unsigned int i;
-
- /* First pass find class in stalled list. If we find it that means
- * we started C++ init with constructors but now we're tearing down
- * because of some failure.
- */
- for (i = 0; i < sStalled->count; i++) {
- if (this == sStalled->classes[i]) {
- break;
- }
- }
-
- /* Remove this metaclass from the stalled list so postModLoad() doesn't
- * try to register it.
- */
- if (i < sStalled->count) {
- sStalled->count--;
- if (i < sStalled->count) {
- memmove(&sStalled->classes[i], &sStalled->classes[i + 1],
- (sStalled->count - i) * sizeof(OSMetaClass *));
- }
- }
- }
-#if IOTRACKING
- IOTrackingQueueFree(reserved->tracking);
-#endif
- IOFreeType(reserved, ExpansionData);
-}
-
-/*********************************************************************
-* Empty overrides.
-*********************************************************************/
-void
-OSMetaClass::retain() const
-{
-}
-void
-OSMetaClass::release() const
-{
-}
-void
-OSMetaClass::release(__unused int when) const
-{
-}
-void
-OSMetaClass::taggedRetain(__unused const void * tag) const
-{
-}
-void
-OSMetaClass::taggedRelease(__unused const void * tag) const
-{
-}
-void
-OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const
-{
-}
-int
-OSMetaClass::getRetainCount() const
-{
- return 0;
-}
-
-/*********************************************************************
-*********************************************************************/
-const char *
-OSMetaClass::getClassName() const
-{
- if (!className) {
- return NULL;
- }
- return className->getCStringNoCopy();
-}
-/*********************************************************************
-*********************************************************************/
-const OSSymbol *
-OSMetaClass::getClassNameSymbol() const
-{
- return className;
-}
-/*********************************************************************
-*********************************************************************/
-unsigned int
-OSMetaClass::getClassSize() const
-{
- return classSize;
-}
-
-/*********************************************************************
-*********************************************************************/
-void *
-OSMetaClass::preModLoad(const char * kextIdentifier)
-{
- IOLockLock(sStalledClassesLock);
-
- assert(sStalled == NULL);
- sStalled = kalloc_type(StalledData, Z_WAITOK_ZERO_NOFAIL);
-
- sStalled->classes = kalloc_type_tag(OSMetaClass *,
- kKModCapacityIncrement, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
- if (!sStalled->classes) {
- kfree_type(StalledData, sStalled);
- return NULL;
- }
- OSMETA_ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
- sizeof(*sStalled));
-
- sStalled->result = kOSReturnSuccess;
- sStalled->capacity = kKModCapacityIncrement;
- sStalled->count = 0;
- sStalled->kextIdentifier = kextIdentifier;
-
- // keep sStalledClassesLock locked until postModLoad
-
- return sStalled;
-}
-
-/*********************************************************************
-*********************************************************************/
-bool
-OSMetaClass::checkModLoad(void * loadHandle)
-{
- return sStalled && loadHandle == sStalled &&
- sStalled->result == kOSReturnSuccess;
-}
-
-/*********************************************************************
-*********************************************************************/
-OSReturn
-OSMetaClass::postModLoad(void * loadHandle)
-{
- OSReturn result = kOSReturnSuccess;
- OSSymbol * myKextName = NULL;// must release
- OSKext * myKext = NULL;// must release
-
- if (!sStalled || loadHandle != sStalled) {
- result = kOSMetaClassInternal;
- goto finish;
- }
-
- if (sStalled->result) {
- result = sStalled->result;
- } else {
- switch (sBootstrapState) {
- case kNoDictionaries:
- sBootstrapState = kMakingDictionaries;
- // No break; fall through
- [[clang::fallthrough]];
-
- case kMakingDictionaries:
- sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
- if (!sAllClassesDict) {
- result = kOSMetaClassNoDicts;
- break;
- }
- sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
-
- // No break; fall through
- [[clang::fallthrough]];
-
- case kCompletedBootstrap:
- {
- unsigned int i;
- myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy(
- sStalled->kextIdentifier));
-
- if (!sStalled->count) {
- break; // Nothing to do so just get out
- }
-
- myKext = OSKext::lookupKextWithIdentifier(myKextName);
- if (!myKext) {
- result = kOSMetaClassNoKext;
-
- /* Log this error here so we can include the kext name.
- */
- OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
- "OSMetaClass: Can't record classes for kext %s - kext not found.",
- sStalled->kextIdentifier);
- break;
- }
-
- /* First pass checking classes aren't already loaded. If any already
- * exist, we don't register any, and so we don't technically have
- * to do any C++ teardown.
- *
- * Hack alert: me->className has been a C string until now.
- * We only release the OSSymbol if we store the kext.
- */
- IOLockLock(sAllClassesLock);
- for (i = 0; i < sStalled->count; i++) {
- const OSMetaClass * me = sStalled->classes[i];
- OSMetaClass * orig = OSDynamicCast(OSMetaClass,
- sAllClassesDict->getObject((const char *)me->className));
-
- if (orig) {
- /* Log this error here so we can include the class name.
- * xxx - we should look up the other kext that defines the class
- */
-#if defined(XNU_TARGET_OS_OSX)
- OSKextLog(myKext, kOSMetaClassLogSpec,
-#else
- panic(
-#endif /* defined(XNU_TARGET_OS_OSX) */
- "OSMetaClass: Kext %s class %s is a duplicate;"
- "kext %s already has a class by that name.",
- sStalled->kextIdentifier, (const char *)me->className,
- ((OSKext *)orig->reserved->kext)->getIdentifierCString());
- result = kOSMetaClassDuplicateClass;
- break;
- }
- unsigned int depth = 1;
- while ((me = me->superClassLink)) {
- depth++;
- }
- if (depth > sDeepestClass) {
- sDeepestClass = depth;
- }
- }
- IOLockUnlock(sAllClassesLock);
-
- /* Bail if we didn't go through the entire list of new classes
- * (if we hit a duplicate).
- */
- if (i != sStalled->count) {
- break;
- }
-
- // Second pass symbolling strings and inserting classes in dictionary
- IOLockLock(sAllClassesLock);
- for (i = 0; i < sStalled->count; i++) {
- OSMetaClass * me = sStalled->classes[i];
-
- /* Hack alert: me->className has been a C string until now.
- * We only release the OSSymbol in ~OSMetaClass()
- * if we set the reference to the kext.
- */
- me->className =
- OSSymbol::withCStringNoCopy((const char *)me->className);
-
- // xxx - I suppose if these fail we're going to panic soon....
- sAllClassesDict->setObject(me->className, me);
-
- /* Do not retain the kext object here.
- */
- me->reserved->kext = myKext;
- if (myKext) {
- result = myKext->addClass(me, sStalled->count);
- if (result != kOSReturnSuccess) {
- /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */
- break;
- }
- }
- }
- IOLockUnlock(sAllClassesLock);
- sBootstrapState = kCompletedBootstrap;
- break;
- }
-
- default:
- result = kOSMetaClassInternal;
- break;
- }
- }
-
-finish:
- /* Don't call logError() for success or the conditions logged above
- * or by called function.
- */
- if (result != kOSReturnSuccess &&
- result != kOSMetaClassNoInsKModSet &&
- result != kOSMetaClassDuplicateClass &&
- result != kOSMetaClassNoKext) {
- OSMetaClassLogErrorForKext(result, myKext);
- }
-
- OSSafeReleaseNULL(myKextName);
- OSSafeReleaseNULL(myKext);
-
- if (sStalled) {
- OSMETA_ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
- sizeof(*sStalled)));
- kfree_type(OSMetaClass *, sStalled->capacity, sStalled->classes);
- kfree_type(StalledData, sStalled);
- sStalled = NULL;
- }
-
- IOLockUnlock(sStalledClassesLock);
-
- return result;
-}
-
-
-/*********************************************************************
-*********************************************************************/
-void
-OSMetaClass::instanceConstructed() const
-{
- // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
- if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) {
- superClassLink->instanceConstructed();
- }
-}
-
-/*********************************************************************
-*********************************************************************/
-void
-OSMetaClass::instanceDestructed() const
-{
- if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) {
- superClassLink->instanceDestructed();
- }
-
- if (((int)instanceCount) < 0) {
- OSKext * myKext = reserved->kext;
-
- OSKextLog(myKext, kOSMetaClassLogSpec,
- // xxx - this phrasing is rather cryptic
- "OSMetaClass: Class %s - bad retain (%d)",
- getClassName(), instanceCount);
- }
-}
-
-/*********************************************************************
-*********************************************************************/
-bool
-OSMetaClass::modHasInstance(const char * kextIdentifier)
-{
- bool result = false;
- OSKext * theKext = NULL; // must release
-
- theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
- if (!theKext) {
- goto finish;
- }
-
- result = theKext->hasOSMetaClassInstances();
-
-finish:
- OSSafeReleaseNULL(theKext);
- return result;
-}
-
-/*********************************************************************
-*********************************************************************/
-void
-OSMetaClass::reportModInstances(const char * kextIdentifier)
-{
- OSKext::reportOSMetaClassInstances(kextIdentifier,
- kOSKextLogExplicitLevel);
- return;
-}
-/*********************************************************************
-*********************************************************************/
-
-void
-OSMetaClass::addInstance(const OSObject * instance, bool super) const
-{
- if (!super) {
- IOLockLock(sInstancesLock);
- }
-
- if (!reserved->instances) {
- reserved->instances = OSOrderedSet::withCapacity(16);
- if (superClassLink) {
- superClassLink->addInstance(reserved->instances, true);
- }
- }
- reserved->instances->setLastObject(instance);
-
- if (!super) {
- IOLockUnlock(sInstancesLock);
- }
-}
-
-void
-OSMetaClass::removeInstance(const OSObject * instance, bool super) const
-{
- if (!super) {
- IOLockLock(sInstancesLock);
- }
-
- if (reserved->instances) {
- reserved->instances->removeObject(instance);
- if (0 == reserved->instances->getCount()) {
- if (superClassLink) {
- superClassLink->removeInstance(reserved->instances, true);
- }
- IOLockLock(sAllClassesLock);
- reserved->instances->release();
- reserved->instances = NULL;
- IOLockUnlock(sAllClassesLock);
- }
- }
-
- if (!super) {
- IOLockUnlock(sInstancesLock);
- }
-}
-
-void
-OSMetaClass::applyToInstances(OSOrderedSet * set,
- OSMetaClassInstanceApplierFunction applier,
- void * context)
-{
- enum { kLocalDepth = 24 };
- unsigned int _nextIndex[kLocalDepth];
- OSOrderedSet * _sets[kLocalDepth];
- unsigned int * nextIndex = &_nextIndex[0];
- OSOrderedSet ** sets = &_sets[0];
- OSObject * obj;
- OSOrderedSet * childSet;
- unsigned int maxDepth;
- unsigned int idx;
- unsigned int level;
- bool done;
-
- maxDepth = sDeepestClass;
- if (maxDepth > kLocalDepth) {
- nextIndex = IONewData(typeof(nextIndex[0]), maxDepth);
- sets = IONew(typeof(sets[0]), maxDepth);
- }
- done = false;
- level = 0;
- idx = 0;
- do{
- while (!done && (obj = set->getObject(idx++))) {
- if ((childSet = OSDynamicCast(OSOrderedSet, obj))) {
- if (level >= maxDepth) {
- panic(">maxDepth");
- }
- sets[level] = set;
- nextIndex[level] = idx;
- level++;
- set = childSet;
- idx = 0;
- break;
- }
- done = (*applier)(obj, context);
- }
- if (!obj) {
- if (!done && level) {
- level--;
- set = sets[level];
- idx = nextIndex[level];
- } else {
- done = true;
- }
- }
- }while (!done);
- if (maxDepth > kLocalDepth) {
- IODeleteData(nextIndex, typeof(nextIndex[0]), maxDepth);
- IODelete(sets, typeof(sets[0]), maxDepth);
- }
-}
-
-void
-OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier,
- void * context) const
-{
- IOLockLock(sInstancesLock);
- if (reserved->instances) {
- applyToInstances(reserved->instances, applier, context);
- }
- IOLockUnlock(sInstancesLock);
-}
-
-void
-OSMetaClass::applyToInstancesOfClassName(
- const OSSymbol * name,
- OSMetaClassInstanceApplierFunction applier,
- void * context)
-{
- OSMetaClass * meta;
- OSOrderedSet * set = NULL;
-
- IOLockLock(sAllClassesLock);
- if (sAllClassesDict
- && (meta = (OSMetaClass *) sAllClassesDict->getObject(name))
- && (set = meta->reserved->instances)) {
- set->retain();
- }
- IOLockUnlock(sAllClassesLock);
-
- if (!set) {
- return;
- }
-
- IOLockLock(sInstancesLock);
- applyToInstances(set, applier, context);
- IOLockUnlock(sInstancesLock);
- set->release();
-}
-
-/*********************************************************************
-*********************************************************************/
-void
-OSMetaClass::considerUnloads()
-{
- OSKext::considerUnloads();
-}
-
-/*********************************************************************
-*********************************************************************/
-bool
-OSMetaClass::removeClasses(OSCollection * metaClasses)
-{
- OSCollectionIterator * classIterator;
- OSMetaClass * checkClass;
- bool result;
-
- classIterator = OSCollectionIterator::withCollection(metaClasses);
- if (!classIterator) {
- return false;
- }
-
- IOLockLock(sAllClassesLock);
-
- result = false;
- do{
- while ((checkClass = (OSMetaClass *)classIterator->getNextObject())
- && !checkClass->getInstanceCount()
- && !checkClass->reserved->retain) {
- }
- if (checkClass) {
- break;
- }
- classIterator->reset();
- while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
- sAllClassesDict->removeObject(checkClass->className);
- }
- result = true;
- }while (false);
-
- IOLockUnlock(sAllClassesLock);
- OSSafeReleaseNULL(classIterator);
-
- return result;
-}
-
-
-/*********************************************************************
-*********************************************************************/
-const OSMetaClass *
-OSMetaClass::getMetaClassWithName(const OSSymbol * name)
-{
- OSMetaClass * retMeta = NULL;
-
- if (!name) {
- return NULL;
- }
-
- IOLockLock(sAllClassesLock);
- if (sAllClassesDict) {
- retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
- }
- IOLockUnlock(sAllClassesLock);
-
- return retMeta;
-}
-
-/*********************************************************************
-*********************************************************************/
-const OSMetaClass *
-OSMetaClass::copyMetaClassWithName(const OSSymbol * name)
-{
- const OSMetaClass * meta;
-
- if (!name) {
- return NULL;
- }
-
- meta = NULL;
- IOLockLock(sAllClassesLock);
- if (sAllClassesDict) {
- meta = (OSMetaClass *) sAllClassesDict->getObject(name);
- if (meta) {
- OSIncrementAtomic(&meta->reserved->retain);
- }
- }
- IOLockUnlock(sAllClassesLock);
-
- return meta;
-}
-
-/*********************************************************************
-*********************************************************************/
-void
-OSMetaClass::releaseMetaClass() const
-{
- OSDecrementAtomic(&reserved->retain);
-}
-
-/*********************************************************************
-*********************************************************************/
-OSObject *
-OSMetaClass::allocClassWithName(const OSSymbol * name)
-{
- const OSMetaClass * meta;
- OSObject * result;
-
- result = NULL;
- meta = copyMetaClassWithName(name);
- if (meta) {
- result = meta->alloc();
- meta->releaseMetaClass();
- }
-
- return result;
-}
-
-/*********************************************************************
-*********************************************************************/
-OSObject *
-OSMetaClass::allocClassWithName(const OSString * name)
-{
- const OSSymbol * tmpKey = OSSymbol::withString(name);
- OSObject * result = allocClassWithName(tmpKey);
- tmpKey->release();
- return result;
-}
-
-/*********************************************************************
-*********************************************************************/
-OSObject *
-OSMetaClass::allocClassWithName(const char * name)
-{
- const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name);
- OSObject * result = allocClassWithName(tmpKey);
- tmpKey->release();
- return result;
-}
-
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClass::checkMetaCastWithName(
- const OSSymbol * name,
- const OSMetaClassBase * in)
-{
- OSMetaClassBase * result = NULL;
-
- const OSMetaClass * const meta = getMetaClassWithName(name);
-
- if (meta) {
- result = meta->checkMetaCast(in);
- }
-
- return result;
-}
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClass::
-checkMetaCastWithName(
- const OSString * name,
- const OSMetaClassBase * in)
-{
- const OSSymbol * tmpKey = OSSymbol::withString(name);
- OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
-
- tmpKey->release();
- return result;
-}
-
-/*********************************************************************
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClass::checkMetaCastWithName(
- const char * name,
- const OSMetaClassBase * in)
-{
- const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name);
- OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
-
- tmpKey->release();
- return result;
-}
-
-/*********************************************************************
-* OSMetaClass::checkMetaCast()
-* Check to see if the 'check' object has this object in its metaclass chain.
-* Returns check if it is indeed a kind of the current meta class, 0 otherwise.
-*
-* Generally this method is not invoked directly but is used to implement
-* the OSMetaClassBase::metaCast member function.
-*
-* See also OSMetaClassBase::metaCast
-*********************************************************************/
-OSMetaClassBase *
-OSMetaClass::checkMetaCast(
- const OSMetaClassBase * check) const
-{
- const OSMetaClass * const toMeta = this;
- const OSMetaClass * fromMeta;
-
- for (fromMeta = check->getMetaClass();; fromMeta = fromMeta->superClassLink) {
- if (toMeta == fromMeta) {
- return const_cast<OSMetaClassBase *>(check); // Discard const
- }
- if (!fromMeta->superClassLink) {
- break;
- }
- }
-
- return NULL;
-}
-
-/*********************************************************************
-*********************************************************************/
-__dead2
-void
-OSMetaClass::reservedCalled(int ind) const
-{
- const char * cname = className->getCStringNoCopy();
- panic("%s::_RESERVED%s%d called.", cname, cname, ind);
-}
-
-/*********************************************************************
-*********************************************************************/
-const
-OSMetaClass *
-OSMetaClass::getSuperClass() const
-{
- return superClassLink;
-}
-
-/*********************************************************************
-*********************************************************************/
-const OSSymbol *
-OSMetaClass::getKmodName() const
-{
- OSKext * myKext = reserved ? reserved->kext : NULL;
- if (myKext) {
- return myKext->getIdentifier();
- }
- return OSSymbol::withCStringNoCopy("unknown");
-}
-
-/*********************************************************************
-*********************************************************************/
-OSKext *
-OSMetaClass::getKext() const
-{
- return reserved ? reserved->kext : NULL;
-}
-
-/*********************************************************************
-*********************************************************************/
-unsigned int
-OSMetaClass::getInstanceCount() const
-{
- return instanceCount;
-}
-
-/*********************************************************************
-*********************************************************************/
-/* static */
-void
-OSMetaClass::printInstanceCounts()
-{
- OSCollectionIterator * classes;
- OSSymbol * className;
- OSMetaClass * meta;
-
- IOLockLock(sAllClassesLock);
- classes = OSCollectionIterator::withCollection(sAllClassesDict);
- assert(classes);
-
- while ((className = (OSSymbol *)classes->getNextObject())) {
- meta = (OSMetaClass *)sAllClassesDict->getObject(className);
- assert(meta);
-
- printf("%24s count: %03d x 0x%03x = 0x%06x\n",
- className->getCStringNoCopy(),
- meta->getInstanceCount(),
- meta->getClassSize(),
- meta->getInstanceCount() * meta->getClassSize());
- }
- printf("\n");
- classes->release();
- IOLockUnlock(sAllClassesLock);
- return;
-}
-
-/*********************************************************************
-*********************************************************************/
-OSDictionary *
-OSMetaClass::getClassDictionary()
-{
- panic("OSMetaClass::getClassDictionary() is obsoleted.");
- return NULL;
-}
-
-/*********************************************************************
-*********************************************************************/
-bool
-OSMetaClass::serialize(__unused OSSerialize * s) const
-{
- panic("OSMetaClass::serialize(): Obsoleted");
- return false;
-}
-
-/*********************************************************************
-*********************************************************************/
-/* static */
-void
-OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary)
-{
- OSDictionary * classDict = NULL;
-
- IOLockLock(sAllClassesLock);
-
- classDict = OSDictionary::withCapacity(sAllClassesDict->getCount());
- if (!classDict) {
- goto finish;
- }
-
- do {
- OSCollectionIterator * classes;
- const OSSymbol * className;
-
- classes = OSCollectionIterator::withCollection(sAllClassesDict);
- if (!classes) {
- break;
- }
-
- while ((className = (const OSSymbol *)classes->getNextObject())) {
- const OSMetaClass * meta;
- OSNumber * count;
-
- meta = (OSMetaClass *)sAllClassesDict->getObject(className);
- count = OSNumber::withNumber(meta->getInstanceCount(), 32);
- if (count) {
- classDict->setObject(className, count);
- count->release();
- }
- }
- classes->release();
-
- serializeDictionary->setObject("Classes", classDict);
- } while (0);
-
-finish:
- OSSafeReleaseNULL(classDict);
-
- IOLockUnlock(sAllClassesLock);
-
- return;
-}
-
-
-/*********************************************************************
-*********************************************************************/
-
-#if IOTRACKING
-
-__typed_allocators_ignore_push
-
-void *
-OSMetaClass::trackedNew(size_t size)
-{
- IOTracking * mem;
-
- mem = (typeof(mem))kheap_alloc(KHEAP_DEFAULT, size + sizeof(IOTracking),
- Z_VM_TAG_BT(Z_WAITOK, VM_KERN_MEMORY_LIBKERN));
- assert(mem);
- if (!mem) {
- return mem;
- }
-
- memset(mem, 0, size + sizeof(IOTracking));
- mem++;
-
- OSIVAR_ACCUMSIZE(size);
-
- return mem;
-}
-
-void
-OSMetaClass::trackedDelete(void * instance, size_t size)
-{
- IOTracking * mem = (typeof(mem))instance; mem--;
-
- kheap_free(KHEAP_DEFAULT, mem, size + sizeof(IOTracking));
- OSIVAR_ACCUMSIZE(-size);
-}
-
-__typed_allocators_ignore_pop
-
-void
-OSMetaClass::trackedInstance(OSObject * instance) const
-{
- IOTracking * mem = (typeof(mem))instance; mem--;
-
- return IOTrackingAdd(reserved->tracking, mem, classSize, false, VM_KERN_MEMORY_NONE);
-}
-
-void
-OSMetaClass::trackedFree(OSObject * instance) const
-{
- IOTracking * mem = (typeof(mem))instance; mem--;
-
- return IOTrackingRemove(reserved->tracking, mem, classSize);
-}
-
-void
-OSMetaClass::trackedAccumSize(OSObject * instance, size_t size) const
-{
- IOTracking * mem = (typeof(mem))instance; mem--;
-
- return IOTrackingAccumSize(reserved->tracking, mem, size);
-}
-
-IOTrackingQueue *
-OSMetaClass::getTracking() const
-{
- return reserved->tracking;
-}
-
-#endif /* IOTRACKING */
+
+ while( (className = (OSSymbol *)classes->getNextObject())) {
+ meta = (OSMetaClass *) sAllClassesDict->getObject(className);
+ assert(meta);
+
+ printf("%24s count: %03d x 0x%03x = 0x%06x\n",
+ className->getCStringNoCopy(),
+ meta->getInstanceCount(),
+ meta->getClassSize(),
+ meta->getInstanceCount() * meta->getClassSize() );
+ }
+ printf("\n");
+ classes->release();
+}
+
+OSDictionary * OSMetaClass::getClassDictionary()
+{
+ return sAllClassesDict;
+}
+
+bool OSMetaClass::serialize(OSSerialize *s) const
+{
+ OSDictionary * dict;
+ OSNumber * off;
+ bool ok = false;
+
+ if (s->previouslySerialized(this)) return true;
+
+ dict = 0;// IODictionary::withCapacity(2);
+ off = OSNumber::withNumber(getInstanceCount(), 32);
+
+ if (dict) {
+ dict->setObject("InstanceCount", off );
+ ok = dict->serialize(s);
+ } else if( off)
+ ok = off->serialize(s);
+
+ if (dict)
+ dict->release();
+ if (off)
+ off->release();
+
+ return ok;
+}
+