Loading...
libkern/c++/OSMetaClass.cpp xnu-792 xnu-10002.61.3
--- xnu/xnu-792/libkern/c++/OSMetaClass.cpp
+++ xnu/xnu-10002.61.3/libkern/c++/OSMetaClass.cpp
@@ -1,23 +1,29 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
  *
- * @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
+ * @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
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * 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@
+ * 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@
  */
 /* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */
 
@@ -26,838 +32,1580 @@
 #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/lock.h>
+#include <kern/locks.h>
 #include <kern/clock.h>
 #include <kern/thread_call.h>
 #include <kern/host.h>
-#include <mach/kmod.h>
 #include <mach/mach_interface.h>
-
-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)
+#include <stddef.h>
+
+#if PRAGMA_MARK
+#pragma mark Macros
+#endif /* PRAGMA_MARK */
+/*********************************************************************
+* Macros
+*********************************************************************/
+__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
+} 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 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
-#define ACCUMSIZE(s)
-#endif /* OSALLOCDEBUG */
-
-__END_DECLS
-
-static enum {
-    kCompletedBootstrap = 0,
-    kNoDictionaries = 1,
-    kMakingDictionaries = 2
-} sBootstrapState = kNoDictionaries;
-
-static const int kClassCapacityIncrement = 40;
-static const int kKModCapacityIncrement = 10;
-static OSDictionary *sAllClassesDict, *sKModClassesDict, *sSortedByClassesDict;
-
-static mutex_t *loadLock;
-static struct StalledData {
-    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";
-
-#if SLOT_USED
-void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
-    { panic(OSMetaClassBasePanicMsg, 0); }
-void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
-    { panic(OSMetaClassBasePanicMsg, 1); }
-void OSMetaClassBase::_RESERVEDOSMetaClassBase2()
-    { panic(OSMetaClassBasePanicMsg, 2); }
-#endif /* SLOT_USED */
-
-// As these slots are used move them up inside the #if above
-void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
-    { panic(OSMetaClassBasePanicMsg, 3); }
-void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
-    { panic(OSMetaClassBasePanicMsg, 4); }
-void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
-    { panic(OSMetaClassBasePanicMsg, 5); }
-void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
-    { panic(OSMetaClassBasePanicMsg, 6); }
-    
-/*
- * 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) : 0; }
-
-bool OSMetaClassBase::
-checkTypeInst(const OSMetaClassBase *inst, const OSMetaClassBase *typeinst)
-{
-    const OSMetaClass *toType = OSTypeIDInst(typeinst);
-    return typeinst && inst && (0 != inst->metaCast(toType));
-}
-
-
-// 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(OSMetaClassBasePanicMsg, 7); }
-
+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
+
+/*********************************************************************
+*********************************************************************/
 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 = 0;
-    if (tempSymb) {
-        ret = metaCast(tempSymb);
-        tempSymb->release();
-    }
-    return ret;
-}
-
-OSMetaClassBase *OSMetaClassBase::metaCast(const char *toMetaCStr) const
-{
-    const OSSymbol *tempSymb = OSSymbol::withCString(toMetaCStr);
-    OSMetaClassBase *ret = 0;
-    if (tempSymb) {
-        ret = metaCast(tempSymb);
-        tempSymb->release();
-    }
-    return ret;
-}
-
-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 = 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
 {
 public:
-    OSMetaClassMeta();
-    OSObject *alloc() const;
+	OSMetaClassMeta();
+	OSObject * alloc() const;
 };
 OSMetaClassMeta::OSMetaClassMeta()
-    : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass))
-    { }
-OSObject *OSMetaClassMeta::alloc() const { return 0; }
+	: OSMetaClass("OSMetaClass", NULL, sizeof(OSMetaClass))
+{
+}
+OSObject *
+OSMetaClassMeta::alloc() const
+{
+	return NULL;
+}
 
 static OSMetaClassMeta sOSMetaClassMeta;
 
 const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta;
-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:
+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:
+		return;
+	case kOSMetaClassNoInit: // xxx - never returned; logged at fail site
+		message = "OSMetaClass: preModLoad() wasn't called (runtime internal error).";
+		break;
+	case kOSMetaClassNoDicts:
+		message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries.";
+		break;
+	case kOSMetaClassNoKModSet:
+		message = "OSMetaClass: Allocation failure for internal kext recording set/set missing.";
+		break;
+	case kOSMetaClassNoInsKModSet:
+		message = "OSMetaClass: Failed to record class in kext.";
+		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);
+	}
 	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;
-	    }
-
-	    sStalled->capacity += kKModCapacityIncrement;
-	    memmove(sStalled->classes, oldStalled, oldSize);
-	    kfree((vm_offset_t)oldStalled, oldSize);
-	    ACCUMSIZE(newSize - oldSize);
-	}
-
-	sStalled->classes[sStalled->count++] = this;
-    }
-}
-
+}
+
+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()
 {
-    do {
-	OSCollectionIterator *iter;
-
+	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) {
-	    sAllClassesDict->removeObject(className);
-	    className->release();
-	}
-
-	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;
-	    }
-	}
-	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;
-
-	if (i < sStalled->count) {
-	    sStalled->count--;
-	    if (i < sStalled->count)
-		memmove(&sStalled->classes[i], &sStalled->classes[i+1],
-			    (sStalled->count - i) * sizeof(OSMetaClass *));
-	}
-    }
-}
-
-void *OSMetaClass::operator new(size_t size) { return 0; }
-void OSMetaClass::retain() const { }
-void OSMetaClass::release() const { }
-void OSMetaClass::release(int when) const { }
-void OSMetaClass::taggedRetain(const void *tag) const { }
-void OSMetaClass::taggedRelease(const void *tag) const { }
-void OSMetaClass::taggedRelease(const void *tag, const 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(0);
-	mutex_lock(loadLock);
-    }
-    else
-	mutex_lock(loadLock);
-
-    sStalled = (StalledData *) kalloc(sizeof(*sStalled));
-    if (sStalled) {
-	sStalled->classes  = (OSMetaClass **)
-			kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
+		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((vm_offset_t) sStalled, sizeof(*sStalled));
-	    return 0;
-	}
-	ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + sizeof(*sStalled));
-
-        sStalled->result   = kOSReturnSuccess;
+		kfree_type(StalledData, sStalled);
+		return NULL;
+	}
+	OSMETA_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;
-    OSSymbol *myname = 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);
-	sSortedByClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
-	if (!sAllClassesDict || !sKModClassesDict || !sSortedByClassesDict) {
-	    result = kOSMetaClassNoDicts;
-	    break;
-	}
-	// No break; fall through
-
-    case kCompletedBootstrap:
-    {
-        unsigned int i;
-        myname = OSSymbol::withCStringNoCopy(sStalled->kmodName);
-
-	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(myname, kmodSet)) {
-	    result = kOSMetaClassNoInsKModSet;
-	    break;
-	}
-
-	// Second pass symbolling strings and inserting classes in dictionary
-	for (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);
-	    sSortedByClassesDict->setObject((const OSSymbol *)me, myname);
-	}
-	sBootstrapState = kCompletedBootstrap;
-	break;
-    }
-
-    default:
-	result = kOSMetaClassInternal;
-	break;
-    }
-
-    if (kmodSet)
-	kmodSet->release();
-
-	if (myname)
-	myname->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(0);
-	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;
-	    }
-
-	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();
-}
-
-extern "C" kern_return_t kmod_unload_cache(void);
-
-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 = 0;
-    kern_return_t ret;
-    bool didUnload;
-
-    mutex_lock(loadLock);
-
-    do {
-
-	kmods = OSCollectionIterator::withCollection(sKModClassesDict);
-	if (!kmods)
-	    break;
-
-        didUnload = false;
-        while ( (kmodName = (OSSymbol *) kmods->getNextObject()) ) {
-
-            if (ki) {
-                kfree((vm_offset_t) ki, sizeof(kmod_info_t));
-                ki = 0;
-            }
-
-            ki = kmod_lookupbyname_locked((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;
-            }
-
-        }
-
-        kmods->release();
-
-    } while (didUnload);
-
-    mutex_unlock(loadLock);
-
-    kmod_unload_cache();
-}
-
-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;
-	}
-
-	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;
-}
-
-const OSSymbol *OSMetaClass::getKmodName() const
-{	
-    return sSortedByClassesDict->getObject((const OSSymbol *)this);
-}
-
-unsigned int OSMetaClass::getInstanceCount() const
-{
-    return instanceCount;
-}
-
-void OSMetaClass::printInstanceCounts()
-{
-    OSCollectionIterator *classes;
-    OSSymbol		 *className;
-    OSMetaClass		 *meta;
-
-    classes = OSCollectionIterator::withCollection(sAllClassesDict);
-    if (!classes)
-	return;
-
-    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()
-{
-    panic("OSMetaClass::getClassDictionary(): Obsoleted\n");
-    return 0;
-}
-
-bool OSMetaClass::serialize(OSSerialize *s) const
-{
-    panic("OSMetaClass::serialize(): Obsoleted\n");
-    return false;
-}
-
-void OSMetaClass::serializeClassDictionary(OSDictionary *serializeDictionary)
-{
-    OSDictionary *classDict;
-
-    classDict = OSDictionary::withCapacity(sAllClassesDict->getCount());
-    if (!classDict)
+	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;
-
-    mutex_lock(loadLock);
-    do {
-        OSCollectionIterator *classes;
-        const OSSymbol *className;
-
+}
+/*********************************************************************
+*********************************************************************/
+
+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);
-        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();
-            }
-        }
+        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();
-
-        serializeDictionary->setObject("Classes", classDict);
-    } while (0);
-
-    mutex_unlock(loadLock);
-
-    classDict->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 */