Loading...
libkern/c++/OSMetaClass.cpp xnu-2050.22.13 xnu-4903.231.4
--- xnu/xnu-2050.22.13/libkern/c++/OSMetaClass.cpp
+++ xnu/xnu-4903.231.4/libkern/c++/OSMetaClass.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2006 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -48,6 +48,9 @@
 
 #include <IOKit/IOLib.h>
 
+#include <IOKit/IOKitDebug.h>
+
+
 __BEGIN_DECLS
 
 #include <sys/systm.h>
@@ -64,13 +67,6 @@
 /*********************************************************************
 * Macros
 *********************************************************************/
-#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
@@ -111,10 +107,13 @@
 } * sStalled;
 IOLock * sStalledClassesLock = NULL;
 
-
 struct ExpansionData {
-    OSOrderedSet * instances;
-    OSKext *       kext;
+    OSOrderedSet    * instances;
+    OSKext          * kext;
+    uint32_t          retain;
+#if IOTRACKING
+    IOTrackingQueue * tracking;
+#endif
 };
 
 
@@ -149,6 +148,66 @@
     { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 6); }
 #endif
 
+
+/*********************************************************************
+*********************************************************************/
+
+#if defined(__arm__) || defined(__arm64__)
+
+
+
+/*
+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
+OSMetaClassBase::_ptmf2ptf(const OSMetaClassBase *self, void (OSMetaClassBase::*func)(void))
+{
+	typedef long int ptrdiff_t;
+    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 (map.pTMF.delta & 1) {
+        // virtual
+        union {
+            const OSMetaClassBase *fObj;
+            _ptf_t **vtablep;
+        } u;
+        u.fObj = self;
+
+        // Virtual member function so dereference table
+        pfn = *(_ptf_t *)(((uintptr_t)*u.vtablep) + (uintptr_t)pfn);
+        return pfn;
+
+    } else {
+        // Not virtual, i.e. plain member func
+        return pfn;
+    }
+}
+
+#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
@@ -393,6 +452,21 @@
 
     reserved = IONew(ExpansionData, 1);
     bzero(reserved, sizeof(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
@@ -416,7 +490,7 @@
             int newSize = oldSize
                 + kKModCapacityIncrement * sizeof(OSMetaClass *);
 
-            sStalled->classes = (OSMetaClass **)kalloc(newSize);
+            sStalled->classes = (OSMetaClass **)kalloc_tag(newSize, VM_KERN_MEMORY_OSKEXT);
             if (!sStalled->classes) {
                 sStalled->classes = oldStalled;
                 sStalled->result = kOSMetaClassNoTempData;
@@ -426,7 +500,7 @@
             sStalled->capacity += kKModCapacityIncrement;
             memmove(sStalled->classes, oldStalled, oldSize);
             kfree(oldStalled, oldSize);
-            ACCUMSIZE(newSize - oldSize);
+            OSMETA_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize));
         }
 
         sStalled->classes[sStalled->count++] = this;
@@ -452,7 +526,7 @@
         if (myKext) {
             sAllClassesDict->removeObject(className);
         } else {
-            sAllClassesDict->removeObject((char *)className);
+            sAllClassesDict->removeObject((const char *)className);
         }
     }
     IOLockUnlock(sAllClassesLock);
@@ -489,12 +563,15 @@
             }
         }
     }
+#if IOTRACKING
+    IOTrackingQueueFree(reserved->tracking);
+#endif
+    IODelete(reserved, ExpansionData, 1);
 }
 
 /*********************************************************************
 * Empty overrides.
 *********************************************************************/
-void * OSMetaClass::operator new(__unused size_t size) { return 0; }
 void OSMetaClass::retain() const { }
 void OSMetaClass::release() const { }
 void OSMetaClass::release(__unused int when) const { }
@@ -534,15 +611,15 @@
     IOLockLock(sStalledClassesLock);
 
     assert (sStalled == NULL);
-    sStalled = (StalledData *)kalloc(sizeof(* sStalled));
+    sStalled = (StalledData *)kalloc_tag(sizeof(* sStalled), VM_KERN_MEMORY_OSKEXT);
     if (sStalled) {
         sStalled->classes = (OSMetaClass **)
-            kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
+            kalloc_tag(kKModCapacityIncrement * sizeof(OSMetaClass *), VM_KERN_MEMORY_OSKEXT);
         if (!sStalled->classes) {
             kfree(sStalled, sizeof(*sStalled));
             return 0;
         }
-        ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
+        OSMETA_ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
             sizeof(*sStalled));
 
         sStalled->result   = kOSReturnSuccess;
@@ -587,6 +664,7 @@
         case kNoDictionaries:
             sBootstrapState = kMakingDictionaries;
             // No break; fall through
+           [[clang::fallthrough]];
             
         case kMakingDictionaries:
             sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
@@ -596,7 +674,8 @@
             }
             sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
 
-        // No break; fall through
+           // No break; fall through
+           [[clang::fallthrough]];
 
         case kCompletedBootstrap:
         {
@@ -638,7 +717,11 @@
                    /* Log this error here so we can include the class name.
                     * xxx - we should look up the other kext that defines the class
                     */
+#if CONFIG_EMBEDDED
+                    panic(
+#else
                     OSKextLog(myKext, kOSMetaClassLogSpec,
+#endif /* CONFIG_EMBEDDED */
                         "OSMetaClass: Kext %s class %s is a duplicate;"
                         "kext %s already has a class by that name.",
                          sStalled->kextIdentifier, (const char *)me->className,
@@ -707,11 +790,11 @@
         OSMetaClassLogErrorForKext(result, myKext);
     }
 
-    OSSafeRelease(myKextName);
-    OSSafeRelease(myKext);
+    OSSafeReleaseNULL(myKextName);
+    OSSafeReleaseNULL(myKext);
 
     if (sStalled) {
-        ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
+        OSMETA_ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
             sizeof(*sStalled)));
         kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *));
         kfree(sStalled, sizeof(*sStalled));
@@ -770,7 +853,7 @@
     result = theKext->hasOSMetaClassInstances();
 
 finish:
-    OSSafeRelease(theKext);
+    OSSafeReleaseNULL(theKext);
     return result;
 }
 
@@ -813,8 +896,10 @@
 	    if (superClassLink) {
 		superClassLink->removeInstance(reserved->instances, true);
 	    }
+	    IOLockLock(sAllClassesLock);
 	    reserved->instances->release();
 	    reserved->instances = 0;
+	    IOLockUnlock(sAllClassesLock);
 	}
     }
 
@@ -926,6 +1011,43 @@
 
 /*********************************************************************
 *********************************************************************/
+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)
 {
@@ -946,15 +1068,46 @@
 
 /*********************************************************************
 *********************************************************************/
+const OSMetaClass *
+OSMetaClass::copyMetaClassWithName(const OSSymbol * name)
+{
+    const OSMetaClass * meta;
+
+    if (!name) return (0);
+
+    meta = 0;
+    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)
 {
-    OSObject * result = 0;
-
-    const OSMetaClass * const meta = getMetaClassWithName(name);
-
-    if (meta) {
+    const OSMetaClass * meta;
+    OSObject          * result;
+
+    result = 0;
+    meta = copyMetaClassWithName(name);
+    if (meta)
+    {
         result = meta->alloc();
+        meta->releaseMetaClass();
     }
 
     return result;
@@ -1185,9 +1338,67 @@
     } while (0);
 
 finish:
-    OSSafeRelease(classDict);
+    OSSafeReleaseNULL(classDict);
 
     IOLockUnlock(sAllClassesLock);
 
     return;
 }
+
+
+/*********************************************************************
+*********************************************************************/
+
+#if IOTRACKING
+
+void *OSMetaClass::trackedNew(size_t size)
+{
+    IOTracking * mem;
+
+    mem = (typeof(mem)) kalloc_tag_bt(size + sizeof(IOTracking), 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--;
+
+    kfree(mem, size + sizeof(IOTracking));
+    OSIVAR_ACCUMSIZE(-size);
+}
+
+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 */