#include <string.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++/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 <kern/clock.h>
#include <kern/thread_call.h>
#include <kern/host.h>
#include <mach/mach_interface.h>
#include <stddef.h>
#if PRAGMA_MARK
#pragma mark Macros
#endif
__END_DECLS
#if PRAGMA_MARK
#pragma mark Internal constants & data structs
#endif
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;
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
#if APPLE_KEXT_VTABLE_PADDING
#if SLOT_USED
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
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
OSMetaClassBase::_ptf_t
#if defined(HAS_APPLE_PAC) && __has_feature(ptrauth_type_discriminator)
OSMetaClassBase::_ptmf2ptf(const OSMetaClassBase *self __attribute__((unused)),
void (OSMetaClassBase::*func)(void), uintptr_t typeDisc)
#else
OSMetaClassBase::_ptmf2ptf(const OSMetaClassBase *self,
void (OSMetaClassBase::*func)(void),
uintptr_t typeDisc
__attribute__((unused)))
#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_type_discriminator)
pfn = ptrauth_auth_function(pfn, ptrauth_key_function_pointer, typeDisc);
return pfn;
#else
if (map.pTMF.delta & 1) {
union {
const OSMetaClassBase *fObj;
_ptf_t **vtablep;
} u;
u.fObj = self;
#if defined(HAS_APPLE_PAC)
uint32_t entity_hash = ((uintptr_t)pfn) >> 32;
pfn = (_ptf_t)(((uintptr_t) pfn) & 0xFFFFFFFF);
_ptf_t *vtablep = ptrauth_auth_data(*u.vtablep,
ptrauth_key_cxx_vtable_pointer, 0);
_ptf_t *vtentryp = (_ptf_t *)(((uintptr_t)vtablep) + (uintptr_t)pfn);
pfn = *vtentryp;
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, 0);
#else
pfn = *(_ptf_t *)(((uintptr_t)*u.vtablep) + (uintptr_t)pfn);
#endif
return pfn;
} else {
return pfn;
}
#endif
}
#endif
OSMetaClassBase *
OSMetaClassBase::safeMetaCast(
const OSMetaClassBase * me,
const OSMetaClass * toType)
{
return (me)? me->metaCast(toType) : NULL;
}
__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
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 = 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
class OSMetaClassMeta : public OSMetaClass
{
public:
OSMetaClassMeta();
OSObject * alloc() const;
};
OSMetaClassMeta::OSMetaClassMeta()
: 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;
}
#if PRAGMA_MARK
#pragma mark OSMetaClass
#endif
#if APPLE_KEXT_VTABLE_PADDING
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: 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: message = "OSMetaClass: Can't associate a class with its superclass.";
break;
case kOSMetaClassInstNoSuper: 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;
}
void
OSMetaClass::logError(OSReturn error)
{
OSMetaClassLogErrorForKext(error, NULL);
}
OSMetaClass::OSMetaClass(
const char * inClassName,
const OSMetaClass * inSuperClass,
unsigned int inClassSize)
{
instanceCount = 0;
classSize = inClassSize;
superClassLink = inSuperClass;
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
className = (const OSSymbol *)inClassName;
if (!sStalled) {
OSKextLog( NULL, kOSMetaClassLogSpec,
"OSMetaClass: preModLoad() wasn't called for class %s "
"(runtime internal error).",
inClassName);
} else if (!sStalled->result) {
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_tag(newSize, VM_KERN_MEMORY_OSKEXT);
if (!sStalled->classes) {
sStalled->classes = oldStalled;
sStalled->result = kOSMetaClassNoTempData;
return;
}
sStalled->capacity += kKModCapacityIncrement;
memmove(sStalled->classes, oldStalled, oldSize);
kfree(oldStalled, oldSize);
OSMETA_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize));
}
sStalled->classes[sStalled->count++] = this;
}
}
OSMetaClass::~OSMetaClass()
{
OSKext * myKext = reserved ? reserved->kext : NULL;
IOLockLock(sAllClassesLock);
if (sAllClassesDict) {
if (myKext) {
sAllClassesDict->removeObject(className);
} else {
sAllClassesDict->removeObject((const char *)className);
}
}
IOLockUnlock(sAllClassesLock);
if (myKext) {
if (myKext->removeClass(this) != kOSReturnSuccess) {
}
className->release();
}
if (sStalled) {
unsigned int i;
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 *));
}
}
}
#if IOTRACKING
IOTrackingQueueFree(reserved->tracking);
#endif
IODelete(reserved, ExpansionData, 1);
}
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 = (StalledData *)kalloc_tag(sizeof(*sStalled), VM_KERN_MEMORY_OSKEXT);
if (sStalled) {
sStalled->classes = (OSMetaClass **)
kalloc_tag(kKModCapacityIncrement * sizeof(OSMetaClass *), VM_KERN_MEMORY_OSKEXT);
if (!sStalled->classes) {
kfree(sStalled, sizeof(*sStalled));
return NULL;
}
OSMETA_ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
sizeof(*sStalled));
sStalled->result = kOSReturnSuccess;
sStalled->capacity = kKModCapacityIncrement;
sStalled->count = 0;
sStalled->kextIdentifier = kextIdentifier;
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;
OSSymbol * myKextName = NULL; OSKext * myKext = NULL;
if (!sStalled || loadHandle != sStalled) {
result = kOSMetaClassInternal;
goto finish;
}
if (sStalled->result) {
result = sStalled->result;
} else {
switch (sBootstrapState) {
case kNoDictionaries:
sBootstrapState = kMakingDictionaries;
[[clang::fallthrough]];
case kMakingDictionaries:
sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
if (!sAllClassesDict) {
result = kOSMetaClassNoDicts;
break;
}
sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
[[clang::fallthrough]];
case kCompletedBootstrap:
{
unsigned int i;
myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy(
sStalled->kextIdentifier));
if (!sStalled->count) {
break; }
myKext = OSKext::lookupKextWithIdentifier(myKextName);
if (!myKext) {
result = kOSMetaClassNoKext;
OSKextLog( NULL, kOSMetaClassLogSpec,
"OSMetaClass: Can't record classes for kext %s - kext not found.",
sStalled->kextIdentifier);
break;
}
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) {
#if CONFIG_EMBEDDED
panic(
#else
OSKextLog(myKext, kOSMetaClassLogSpec,
#endif
"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);
if (i != sStalled->count) {
break;
}
IOLockLock(sAllClassesLock);
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);
me->reserved->kext = myKext;
if (myKext) {
result = myKext->addClass(me, sStalled->count);
if (result != kOSReturnSuccess) {
break;
}
}
}
IOLockUnlock(sAllClassesLock);
sBootstrapState = kCompletedBootstrap;
break;
}
default:
result = kOSMetaClassInternal;
break;
}
}
finish:
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(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *));
kfree(sStalled, sizeof(*sStalled));
sStalled = NULL;
}
IOLockUnlock(sStalledClassesLock);
return result;
}
void
OSMetaClass::instanceConstructed() const
{
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,
"OSMetaClass: Class %s - bad retain (%d)",
getClassName(), instanceCount);
}
}
bool
OSMetaClass::modHasInstance(const char * kextIdentifier)
{
bool result = false;
OSKext * theKext = NULL;
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 = IONew(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) {
IODelete(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;
}
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); }
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;
}
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.\n");
return NULL;
}
bool
OSMetaClass::serialize(__unused OSSerialize * s) const
{
panic("OSMetaClass::serialize(): Obsoleted\n");
return false;
}
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
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