Loading...
iokit/Kernel/IOStatistics.cpp xnu-12377.101.15 /dev/null
--- xnu/xnu-12377.101.15/iokit/Kernel/IOStatistics.cpp
+++ /dev/null
@@ -1,1312 +0,0 @@
-/*
- * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * unlawful or unlicensed copies of an Apple operating system, or to
- * circumvent, violate, or enable the circumvention or violation of, any
- * terms of an Apple operating system software license agreement.
- *
- * Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
- */
-
-#include <sys/sysctl.h>
-#include <kern/backtrace.h>
-#include <kern/host.h>
-#include <kern/zalloc.h>
-
-#include <IOKit/system.h>
-#include <libkern/c++/OSKext.h>
-#include <libkern/OSAtomic.h>
-
-#include <IOKit/IOStatisticsPrivate.h>
-#include <IOKit/IOUserClient.h>
-#include <IOKit/IOEventSource.h>
-#include <IOKit/IOKitDebug.h>
-
-#if IOKITSTATS
-bool IOStatistics::enabled = false;
-
-uint32_t IOStatistics::sequenceID = 0;
-
-uint32_t IOStatistics::lastClassIndex = 0;
-uint32_t IOStatistics::lastKextIndex = 0;
-
-uint32_t IOStatistics::loadedKexts = 0;
-uint32_t IOStatistics::registeredClasses = 0;
-uint32_t IOStatistics::registeredCounters = 0;
-uint32_t IOStatistics::registeredWorkloops = 0;
-
-uint32_t IOStatistics::attachedEventSources = 0;
-
-IOWorkLoopDependency *IOStatistics::nextWorkLoopDependency = NULL;
-
-/* Logging */
-
-#define LOG_LEVEL 0
-
-#define LOG(level, format, ...) \
-do { \
-	if (level <= LOG_LEVEL) \
-	        printf(format, ##__VA_ARGS__); \
-} while (0)
-
-/* Locks */
-
-IORWLock *IOStatistics::lock = NULL;
-
-/* Kext tree */
-
-KextNode *IOStatistics::kextHint = NULL;
-
-IOStatistics::KextTreeHead IOStatistics::kextHead = RB_INITIALIZER(&IOStatistics::kextHead);
-
-int
-IOStatistics::kextNodeCompare(KextNode *e1, KextNode *e2)
-{
-	if (e1->kext < e2->kext) {
-		return -1;
-	} else if (e1->kext > e2->kext) {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-RB_GENERATE(IOStatistics::KextTree, KextNode, link, kextNodeCompare);
-
-/* Kext tree ordered by address */
-
-IOStatistics::KextAddressTreeHead IOStatistics::kextAddressHead = RB_INITIALIZER(&IOStatistics::kextAddressHead);
-
-int
-IOStatistics::kextAddressNodeCompare(KextNode *e1, KextNode *e2)
-{
-	if (e1->address < e2->address) {
-		return -1;
-	} else if (e1->address > e2->address) {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-RB_GENERATE(IOStatistics::KextAddressTree, KextNode, addressLink, kextAddressNodeCompare);
-
-/* Class tree */
-
-IOStatistics::ClassTreeHead IOStatistics::classHead = RB_INITIALIZER(&IOStatistics::classHead);
-
-int
-IOStatistics::classNodeCompare(ClassNode *e1, ClassNode *e2)
-{
-	if (e1->metaClass < e2->metaClass) {
-		return -1;
-	} else if (e1->metaClass > e2->metaClass) {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-RB_GENERATE(IOStatistics::ClassTree, ClassNode, tLink, classNodeCompare);
-
-/* Workloop dependencies */
-
-int
-IOWorkLoopCounter::loadTagCompare(IOWorkLoopDependency *e1, IOWorkLoopDependency *e2)
-{
-	if (e1->loadTag < e2->loadTag) {
-		return -1;
-	} else if (e1->loadTag > e2->loadTag) {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-RB_GENERATE(IOWorkLoopCounter::DependencyTree, IOWorkLoopDependency, link, IOWorkLoopCounter::loadTagCompare);
-
-/* sysctl stuff */
-
-static int
-oid_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1, int arg2, struct sysctl_req *req)
-{
-	int error = EINVAL;
-	uint32_t request = arg2;
-
-	if (!IOStatistics::isEnabled()) {
-		return ENOENT;
-	}
-
-	switch (request) {
-	case kIOStatisticsGeneral:
-		error = IOStatistics::getStatistics(req);
-		break;
-	case kIOStatisticsWorkLoop:
-		error = IOStatistics::getWorkLoopStatistics(req);
-		break;
-	case kIOStatisticsUserClient:
-		error = IOStatistics::getUserClientStatistics(req);
-		break;
-	default:
-		break;
-	}
-
-	return error;
-}
-
-SYSCTL_NODE(_debug, OID_AUTO, iokit_statistics, CTLFLAG_RW | CTLFLAG_LOCKED, NULL, "IOStatistics");
-
-static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, general,
-    CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
-    NULL, kIOStatisticsGeneral, oid_sysctl, "S", "");
-
-static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, workloop,
-    CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
-    NULL, kIOStatisticsWorkLoop, oid_sysctl, "S", "");
-
-static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, userclient,
-    CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
-    NULL, kIOStatisticsUserClient, oid_sysctl, "S", "");
-
-
-void
-IOStatistics::initialize()
-{
-	if (enabled) {
-		return;
-	}
-
-	/* Only enabled if the boot argument is set. */
-	if (!(kIOStatistics & gIOKitDebug)) {
-		return;
-	}
-
-	lock = IORWLockAlloc();
-	if (!lock) {
-		return;
-	}
-
-	nextWorkLoopDependency = kalloc_type(IOWorkLoopDependency, Z_WAITOK);
-	if (!nextWorkLoopDependency) {
-		return;
-	}
-
-	enabled = true;
-}
-
-void
-IOStatistics::onKextLoad(OSKext *kext, kmod_info_t *kmod_info)
-{
-	KextNode *ke;
-
-	assert(kext && kmod_info);
-
-	if (!enabled) {
-		return;
-	}
-
-	LOG(1, "IOStatistics::onKextLoad: %s, tag %d, address 0x%llx, address end 0x%llx\n",
-	    kext->getIdentifierCString(), kmod_info->id, (uint64_t)kmod_info->address, (uint64_t)(kmod_info->address + kmod_info->size));
-
-	ke = kalloc_type(KextNode, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
-	if (!ke) {
-		return;
-	}
-
-	ke->kext = kext;
-	ke->loadTag = kmod_info->id;
-	ke->address = kmod_info->address;
-	ke->address_end = kmod_info->address + kmod_info->size;
-
-	SLIST_INIT(&ke->classList);
-	TAILQ_INIT(&ke->userClientCallList);
-
-	IORWLockWrite(lock);
-
-	RB_INSERT(KextTree, &kextHead, ke);
-	RB_INSERT(KextAddressTree, &kextAddressHead, ke);
-
-	sequenceID++;
-	loadedKexts++;
-	lastKextIndex++;
-
-	IORWLockUnlock(lock);
-}
-
-void
-IOStatistics::onKextUnload(OSKext *kext)
-{
-	KextNode sought, *found;
-
-	assert(kext);
-
-	if (!enabled) {
-		return;
-	}
-
-	LOG(1, "IOStatistics::onKextUnload: %s\n", kext->getIdentifierCString());
-
-	IORWLockWrite(lock);
-
-	sought.kext = kext;
-	found = RB_FIND(KextTree, &kextHead, &sought);
-	if (found) {
-		IOWorkLoopCounter *wlc;
-		IOUserClientProcessEntry *uce;
-
-		/* Disconnect workloop counters; cleanup takes place in unregisterWorkLoop() */
-		while ((wlc = SLIST_FIRST(&found->workLoopList))) {
-			SLIST_REMOVE_HEAD(&found->workLoopList, link);
-			wlc->parentKext = NULL;
-		}
-
-		/* Free up the user client list */
-		while ((uce = TAILQ_FIRST(&found->userClientCallList))) {
-			TAILQ_REMOVE(&found->userClientCallList, uce, link);
-			kfree_type(IOUserClientProcessEntry, uce);
-		}
-
-		/* Remove from kext trees */
-		RB_REMOVE(KextTree, &kextHead, found);
-		RB_REMOVE(KextAddressTree, &kextAddressHead, found);
-
-		/*
-		 * Clear a matching kextHint to avoid use after free in
-		 * onClassAdded() for a class add after a KEXT unload.
-		 */
-		if (found == kextHint) {
-			kextHint = NULL;
-		}
-
-		/* Finally, free the class node */
-		kfree_type(KextNode, found);
-
-		sequenceID++;
-		loadedKexts--;
-	} else {
-		panic("IOStatistics::onKextUnload: cannot find kext: %s", kext->getIdentifierCString());
-	}
-
-	IORWLockUnlock(lock);
-}
-
-void
-IOStatistics::onClassAdded(OSKext *parentKext, OSMetaClass *metaClass)
-{
-	ClassNode *ce;
-	KextNode soughtKext, *foundKext = NULL;
-
-	assert(parentKext && metaClass);
-
-	if (!enabled) {
-		return;
-	}
-
-	LOG(1, "IOStatistics::onClassAdded: %s\n", metaClass->getClassName());
-
-	ce = kalloc_type(ClassNode, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
-	if (!ce) {
-		return;
-	}
-
-	IORWLockWrite(lock);
-
-	/* Hinted? */
-	if (kextHint && kextHint->kext == parentKext) {
-		foundKext = kextHint;
-	} else {
-		soughtKext.kext = parentKext;
-		foundKext = RB_FIND(KextTree, &kextHead, &soughtKext);
-	}
-
-	if (foundKext) {
-		ClassNode soughtClass, *foundClass = NULL;
-		const OSMetaClass *superClass;
-
-		ce->metaClass = metaClass;
-		ce->classID = lastClassIndex++;
-		ce->parentKext = foundKext;
-
-		/* Has superclass? */
-		superClass = ce->metaClass->getSuperClass();
-		if (superClass) {
-			soughtClass.metaClass = superClass;
-			foundClass = RB_FIND(ClassTree, &classHead, &soughtClass);
-		}
-		ce->superClassID = foundClass ? foundClass->classID : (uint32_t)(-1);
-
-		SLIST_INIT(&ce->counterList);
-		SLIST_INIT(&ce->userClientList);
-
-		RB_INSERT(ClassTree, &classHead, ce);
-		SLIST_INSERT_HEAD(&foundKext->classList, ce, lLink);
-
-		foundKext->classes++;
-
-		kextHint = foundKext;
-
-		sequenceID++;
-		registeredClasses++;
-	} else {
-		panic("IOStatistics::onClassAdded: cannot find parent kext: %s", parentKext->getIdentifierCString());
-	}
-
-	IORWLockUnlock(lock);
-}
-
-void
-IOStatistics::onClassRemoved(OSKext *parentKext, OSMetaClass *metaClass)
-{
-	ClassNode sought, *found;
-
-	assert(parentKext && metaClass);
-
-	if (!enabled) {
-		return;
-	}
-
-	LOG(1, "IOStatistics::onClassRemoved: %s\n", metaClass->getClassName());
-
-	IORWLockWrite(lock);
-
-	sought.metaClass = metaClass;
-	found = RB_FIND(ClassTree, &classHead, &sought);
-	if (found) {
-		IOEventSourceCounter *esc;
-		IOUserClientCounter *ucc;
-
-		/* Free up the list of counters */
-		while ((esc = SLIST_FIRST(&found->counterList))) {
-			SLIST_REMOVE_HEAD(&found->counterList, link);
-			kfree_type(IOEventSourceCounter, esc);
-		}
-
-		/* Free up the user client list */
-		while ((ucc = SLIST_FIRST(&found->userClientList))) {
-			SLIST_REMOVE_HEAD(&found->userClientList, link);
-			kfree_type(IOUserClientCounter, ucc);
-		}
-
-		/* Remove from class tree */
-		RB_REMOVE(ClassTree, &classHead, found);
-
-		/* Remove from parent */
-		SLIST_REMOVE(&found->parentKext->classList, found, ClassNode, lLink);
-
-		/* Finally, free the class node */
-		kfree_type(ClassNode, found);
-
-		sequenceID++;
-		registeredClasses--;
-	} else {
-		panic("IOStatistics::onClassRemoved: cannot find class: %s", metaClass->getClassName());
-	}
-
-	IORWLockUnlock(lock);
-}
-
-IOEventSourceCounter *
-IOStatistics::registerEventSource(OSObject *inOwner)
-{
-	IOEventSourceCounter *counter = NULL;
-	ClassNode sought, *found = NULL;
-	boolean_t createDummyCounter = FALSE;
-
-	assert(inOwner);
-
-	if (!enabled) {
-		return NULL;
-	}
-
-	counter = kalloc_type(IOEventSourceCounter, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
-	if (!counter) {
-		return NULL;
-	}
-
-	IORWLockWrite(lock);
-
-	/* Workaround for <rdar://problem/7158117> - create a dummy counter when inOwner is bad.
-	 * We use retainCount here as our best indication that the pointer is awry.
-	 */
-	if (inOwner->retainCount > 0xFFFFFF) {
-		kprintf("IOStatistics::registerEventSource - bad metaclass %p\n", inOwner);
-		createDummyCounter = TRUE;
-	} else {
-		sought.metaClass = inOwner->getMetaClass();
-		found = RB_FIND(ClassTree, &classHead, &sought);
-	}
-
-	if (found) {
-		counter->parentClass = found;
-		SLIST_INSERT_HEAD(&found->counterList, counter, link);
-		registeredCounters++;
-	}
-
-	if (!(createDummyCounter || found)) {
-		panic("IOStatistics::registerEventSource: cannot find parent class: %s", inOwner->getMetaClass()->getClassName());
-	}
-
-	IORWLockUnlock(lock);
-
-	return counter;
-}
-
-void
-IOStatistics::unregisterEventSource(IOEventSourceCounter *counter)
-{
-	if (!counter) {
-		return;
-	}
-
-	IORWLockWrite(lock);
-
-	if (counter->parentClass) {
-		SLIST_REMOVE(&counter->parentClass->counterList, counter, IOEventSourceCounter, link);
-		registeredCounters--;
-	}
-	kfree_type(IOEventSourceCounter, counter);
-
-	IORWLockUnlock(lock);
-}
-
-IOWorkLoopCounter*
-IOStatistics::registerWorkLoop(IOWorkLoop *workLoop)
-{
-	IOWorkLoopCounter *counter = NULL;
-	KextNode *found;
-
-	assert(workLoop);
-
-	if (!enabled) {
-		return NULL;
-	}
-
-	counter = kalloc_type(IOWorkLoopCounter, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
-	if (!counter) {
-		return NULL;
-	}
-
-	found = getKextNodeFromBacktrace(TRUE);
-	if (!found) {
-		panic("IOStatistics::registerWorkLoop: cannot find parent kext");
-	}
-
-	counter->parentKext = found;
-	counter->workLoop = workLoop;
-	RB_INIT(&counter->dependencyHead);
-	SLIST_INSERT_HEAD(&found->workLoopList, counter, link);
-	registeredWorkloops++;
-
-	releaseKextNode(found);
-
-	return counter;
-}
-
-void
-IOStatistics::unregisterWorkLoop(IOWorkLoopCounter *counter)
-{
-	if (!counter) {
-		return;
-	}
-
-	IORWLockWrite(lock);
-	if (counter->parentKext) {
-		SLIST_REMOVE(&counter->parentKext->workLoopList, counter, IOWorkLoopCounter, link);
-	}
-	kfree_type(IOWorkLoopCounter, counter);
-	registeredWorkloops--;
-
-	IORWLockUnlock(lock);
-}
-
-IOUserClientCounter *
-IOStatistics::registerUserClient(IOUserClient *userClient)
-{
-	ClassNode sought, *found;
-	IOUserClientCounter *counter = NULL;
-
-	assert(userClient);
-
-	if (!enabled) {
-		return NULL;
-	}
-
-	counter = kalloc_type(IOUserClientCounter, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
-	if (!counter) {
-		return NULL;
-	}
-
-	IORWLockWrite(lock);
-
-	sought.metaClass = userClient->getMetaClass();
-
-	found = RB_FIND(ClassTree, &classHead, &sought);
-	if (found) {
-		counter->parentClass = found;
-		SLIST_INSERT_HEAD(&found->userClientList, counter, link);
-	} else {
-		panic("IOStatistics::registerUserClient: cannot find parent class: %s", sought.metaClass->getClassName());
-	}
-
-	IORWLockUnlock(lock);
-
-	return counter;
-}
-
-void
-IOStatistics::unregisterUserClient(IOUserClientCounter *counter)
-{
-	if (!counter) {
-		return;
-	}
-
-	IORWLockWrite(lock);
-
-	SLIST_REMOVE(&counter->parentClass->userClientList, counter, IOUserClientCounter, link);
-	kfree_type(IOUserClientCounter, counter);
-
-	IORWLockUnlock(lock);
-}
-
-void
-IOStatistics::attachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc)
-{
-	if (!wlc) {
-		return;
-	}
-
-	IORWLockWrite(lock);
-
-	if (!nextWorkLoopDependency) {
-		return;
-	}
-
-	attachedEventSources++;
-	wlc->attachedEventSources++;
-
-	/* Track the kext dependency */
-	nextWorkLoopDependency->loadTag = esc->parentClass->parentKext->loadTag;
-	if (NULL == RB_INSERT(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, nextWorkLoopDependency)) {
-		nextWorkLoopDependency = kalloc_type(IOWorkLoopDependency, Z_WAITOK);
-	}
-
-	IORWLockUnlock(lock);
-}
-
-void
-IOStatistics::detachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc)
-{
-	IOWorkLoopDependency sought, *found;
-
-	if (!wlc) {
-		return;
-	}
-
-	IORWLockWrite(lock);
-
-	attachedEventSources--;
-	wlc->attachedEventSources--;
-
-	sought.loadTag = esc->parentClass->parentKext->loadTag;
-
-	found = RB_FIND(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, &sought);
-	if (found) {
-		RB_REMOVE(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, found);
-		kfree_type(IOWorkLoopDependency, found);
-	}
-
-	IORWLockUnlock(lock);
-}
-
-int
-IOStatistics::getStatistics(sysctl_req *req)
-{
-	int error;
-	uint32_t calculatedSize, size;
-	char *buffer, *ptr;
-	IOStatisticsHeader *header;
-
-	assert(IOStatistics::enabled && req);
-
-	IORWLockRead(IOStatistics::lock);
-
-	/* Work out how much we need to allocate. IOStatisticsKext is of variable size. */
-	calculatedSize = sizeof(IOStatisticsHeader) +
-	    sizeof(IOStatisticsGlobal) +
-	    (sizeof(IOStatisticsKext) * loadedKexts) + (sizeof(uint32_t) * registeredClasses) +
-	    (sizeof(IOStatisticsMemory) * loadedKexts) +
-	    (sizeof(IOStatisticsClass) * registeredClasses) +
-	    (sizeof(IOStatisticsCounter) * registeredClasses) +
-	    (sizeof(IOStatisticsKextIdentifier) * loadedKexts) +
-	    (sizeof(IOStatisticsClassName) * registeredClasses);
-
-	/* Size request? */
-	if (req->oldptr == USER_ADDR_NULL) {
-		error = SYSCTL_OUT(req, NULL, calculatedSize);
-		goto exit;
-	}
-
-	/* Read only */
-	if (req->newptr != USER_ADDR_NULL) {
-		error = EPERM;
-		goto exit;
-	}
-
-	buffer = (char*)kalloc_data(calculatedSize, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
-	if (!buffer) {
-		error = ENOMEM;
-		goto exit;
-	}
-
-	ptr = buffer;
-
-	header = (IOStatisticsHeader*)((void*)ptr);
-
-	header->sig = IOSTATISTICS_SIG;
-	header->ver = IOSTATISTICS_VER;
-
-	header->seq = sequenceID;
-
-	ptr += sizeof(IOStatisticsHeader);
-
-	/* Global data - seq, timers, interrupts, etc) */
-	header->globalStatsOffset = sizeof(IOStatisticsHeader);
-	size = copyGlobalStatistics((IOStatisticsGlobal*)((void*)ptr));
-	ptr += size;
-
-	/* Kext statistics */
-	header->kextStatsOffset = header->globalStatsOffset + size;
-	size = copyKextStatistics((IOStatisticsKext*)((void*)ptr));
-	ptr += size;
-
-	/* Memory allocation info */
-	header->memoryStatsOffset = header->kextStatsOffset + size;
-	size = copyMemoryStatistics((IOStatisticsMemory*)((void*)ptr));
-	ptr += size;
-
-	/* Class statistics */
-	header->classStatsOffset = header->memoryStatsOffset + size;
-	size = copyClassStatistics((IOStatisticsClass*)((void*)ptr));
-	ptr += size;
-
-	/* Dynamic class counter data */
-	header->counterStatsOffset = header->classStatsOffset + size;
-	size = copyCounterStatistics((IOStatisticsCounter*)((void*)ptr));
-	ptr += size;
-
-	/* Kext identifiers */
-	header->kextIdentifiersOffset = header->counterStatsOffset + size;
-	size = copyKextIdentifiers((IOStatisticsKextIdentifier*)((void*)ptr));
-	ptr += size;
-
-	/* Class names */
-	header->classNamesOffset = header->kextIdentifiersOffset + size;
-	size = copyClassNames((IOStatisticsClassName*)ptr);
-	ptr += size;
-
-	LOG(2, "IOStatistics::getStatistics - calculatedSize 0x%x, kexts 0x%x, classes 0x%x.\n",
-	    calculatedSize, loadedKexts, registeredClasses);
-
-	assert((uint32_t)(ptr - buffer) == calculatedSize );
-
-	error = SYSCTL_OUT(req, buffer, calculatedSize);
-
-	kfree_data(buffer, calculatedSize);
-
-exit:
-	IORWLockUnlock(IOStatistics::lock);
-	return error;
-}
-
-int
-IOStatistics::getWorkLoopStatistics(sysctl_req *req)
-{
-	int error;
-	uint32_t calculatedSize, size;
-	char *buffer;
-	IOStatisticsWorkLoopHeader *header;
-
-	assert(IOStatistics::enabled && req);
-
-	IORWLockRead(IOStatistics::lock);
-
-	/* Approximate how much we need to allocate (worse case estimate) */
-	calculatedSize = sizeof(IOStatisticsWorkLoop) * registeredWorkloops +
-	    sizeof(uint32_t) * attachedEventSources;
-
-	/* Size request? */
-	if (req->oldptr == USER_ADDR_NULL) {
-		error = SYSCTL_OUT(req, NULL, calculatedSize);
-		goto exit;
-	}
-
-	/* Read only */
-	if (req->newptr != USER_ADDR_NULL) {
-		error = EPERM;
-		goto exit;
-	}
-
-	buffer = (char*)kalloc_data(calculatedSize, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
-	if (!buffer) {
-		error = ENOMEM;
-		goto exit;
-	}
-	header = (IOStatisticsWorkLoopHeader*)((void*)buffer);
-
-	header->sig = IOSTATISTICS_SIG_WORKLOOP;
-	header->ver = IOSTATISTICS_VER;
-
-	header->seq = sequenceID;
-
-	header->workloopCount = registeredWorkloops;
-
-	size = copyWorkLoopStatistics(&header->workLoopStats);
-
-	LOG(2, "IOStatistics::getWorkLoopStatistics: calculatedSize %d, size %d\n", calculatedSize, size);
-
-	assert( size <= calculatedSize );
-
-	error = SYSCTL_OUT(req, buffer, size);
-
-	kfree_data(buffer, calculatedSize);
-
-exit:
-	IORWLockUnlock(IOStatistics::lock);
-	return error;
-}
-
-int
-IOStatistics::getUserClientStatistics(sysctl_req *req)
-{
-	int error;
-	uint32_t calculatedSize, size;
-	char *buffer;
-	uint32_t requestedLoadTag = 0;
-	IOStatisticsUserClientHeader *header;
-
-	assert(IOStatistics::enabled && req);
-
-	IORWLockRead(IOStatistics::lock);
-
-	/* Work out how much we need to allocate */
-	calculatedSize = sizeof(IOStatisticsUserClientHeader) +
-	    sizeof(IOStatisticsUserClientCall) * IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS * loadedKexts;
-
-	/* Size request? */
-	if (req->oldptr == USER_ADDR_NULL) {
-		error = SYSCTL_OUT(req, NULL, calculatedSize);
-		goto exit;
-	}
-
-	/* Kext request (potentially) valid? */
-	if (!req->newptr || req->newlen < sizeof(requestedLoadTag)) {
-		error = EINVAL;
-		goto exit;
-	}
-
-	error = SYSCTL_IN(req, &requestedLoadTag, sizeof(requestedLoadTag));
-	if (error) {
-		goto exit;
-	}
-
-	LOG(2, "IOStatistics::getUserClientStatistics - requesting kext w/load tag: %d\n", requestedLoadTag);
-
-	buffer = (char*)kalloc_data(calculatedSize, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
-	if (!buffer) {
-		error = ENOMEM;
-		goto exit;
-	}
-	header = (IOStatisticsUserClientHeader*)((void*)buffer);
-
-	header->sig = IOSTATISTICS_SIG_USERCLIENT;
-	header->ver = IOSTATISTICS_VER;
-
-	header->seq = sequenceID;
-
-	header->processes = 0;
-
-	size = copyUserClientStatistics(header, requestedLoadTag);
-
-	assert((sizeof(IOStatisticsUserClientHeader) + size) <= calculatedSize);
-
-	if (size) {
-		error = SYSCTL_OUT(req, buffer, sizeof(IOStatisticsUserClientHeader) + size);
-	} else {
-		error = EINVAL;
-	}
-
-	kfree_data(buffer, calculatedSize);
-
-exit:
-	IORWLockUnlock(IOStatistics::lock);
-	return error;
-}
-
-uint32_t
-IOStatistics::copyGlobalStatistics(IOStatisticsGlobal *stats)
-{
-	stats->kextCount = loadedKexts;
-	stats->classCount = registeredClasses;
-	stats->workloops = registeredWorkloops;
-
-	return sizeof(IOStatisticsGlobal);
-}
-
-uint32_t
-IOStatistics::copyKextStatistics(IOStatisticsKext *stats)
-{
-	KextNode *ke;
-	ClassNode *ce;
-	uint32_t index = 0;
-
-	RB_FOREACH(ke, KextTree, &kextHead) {
-		stats->loadTag = ke->loadTag;
-		ke->kext->getSizeInfo(&stats->loadSize, &stats->wiredSize);
-
-		stats->classes = ke->classes;
-
-		/* Append indices of owned classes */
-		SLIST_FOREACH(ce, &ke->classList, lLink) {
-			stats->classIndexes[index++] = ce->classID;
-		}
-
-		stats = (IOStatisticsKext *)((void*)((char*)stats + sizeof(IOStatisticsKext) + (ke->classes * sizeof(uint32_t))));
-	}
-
-	return sizeof(IOStatisticsKext) * loadedKexts + sizeof(uint32_t) * registeredClasses;
-}
-
-uint32_t
-IOStatistics::copyMemoryStatistics(IOStatisticsMemory *stats)
-{
-	KextNode *ke;
-
-	RB_FOREACH(ke, KextTree, &kextHead) {
-		stats->allocatedSize = ke->memoryCounters[kIOStatisticsMalloc];
-		stats->freedSize = ke->memoryCounters[kIOStatisticsFree];
-		stats->allocatedAlignedSize = ke->memoryCounters[kIOStatisticsMallocAligned];
-		stats->freedAlignedSize = ke->memoryCounters[kIOStatisticsFreeAligned];
-		stats->allocatedContiguousSize = ke->memoryCounters[kIOStatisticsMallocContiguous];
-		stats->freedContiguousSize = ke->memoryCounters[kIOStatisticsFreeContiguous];
-		stats->allocatedPageableSize = ke->memoryCounters[kIOStatisticsMallocPageable];
-		stats->freedPageableSize = ke->memoryCounters[kIOStatisticsFreePageable];
-		stats++;
-	}
-
-	return sizeof(IOStatisticsMemory) * loadedKexts;
-}
-
-uint32_t
-IOStatistics::copyClassStatistics(IOStatisticsClass *stats)
-{
-	KextNode *ke;
-	ClassNode *ce;
-
-	RB_FOREACH(ke, KextTree, &kextHead) {
-		SLIST_FOREACH(ce, &ke->classList, lLink) {
-			stats->classID = ce->classID;
-			stats->superClassID = ce->superClassID;
-			stats->classSize = ce->metaClass->getClassSize();
-
-			stats++;
-		}
-	}
-
-	return sizeof(IOStatisticsClass) * registeredClasses;
-}
-
-uint32_t
-IOStatistics::copyCounterStatistics(IOStatisticsCounter *stats)
-{
-	KextNode *ke;
-	ClassNode *ce;
-
-	RB_FOREACH(ke, KextTree, &kextHead) {
-		SLIST_FOREACH(ce, &ke->classList, lLink) {
-			IOUserClientCounter *userClientCounter;
-			IOEventSourceCounter *counter;
-
-			stats->classID = ce->classID;
-			stats->classInstanceCount = ce->metaClass->getInstanceCount();
-
-			IOStatisticsUserClients *uc = &stats->userClientStatistics;
-
-			/* User client counters */
-			SLIST_FOREACH(userClientCounter, &ce->userClientList, link) {
-				uc->clientCalls += userClientCounter->clientCalls;
-				uc->created++;
-			}
-
-			IOStatisticsInterruptEventSources *iec = &stats->interruptEventSourceStatistics;
-			IOStatisticsInterruptEventSources *fiec = &stats->filterInterruptEventSourceStatistics;
-			IOStatisticsTimerEventSources *tec = &stats->timerEventSourceStatistics;
-			IOStatisticsCommandGates *cgc = &stats->commandGateStatistics;
-			IOStatisticsCommandQueues *cqc = &stats->commandQueueStatistics;
-			IOStatisticsDerivedEventSources *dec = &stats->derivedEventSourceStatistics;
-
-			/* Event source counters */
-			SLIST_FOREACH(counter, &ce->counterList, link) {
-				switch (counter->type) {
-				case kIOStatisticsInterruptEventSourceCounter:
-					iec->created++;
-					iec->produced += counter->u.interrupt.produced;
-					iec->checksForWork += counter->u.interrupt.checksForWork;
-					break;
-				case kIOStatisticsFilterInterruptEventSourceCounter:
-					fiec->created++;
-					fiec->produced += counter->u.filter.produced;
-					fiec->checksForWork += counter->u.filter.checksForWork;
-					break;
-				case kIOStatisticsTimerEventSourceCounter:
-					tec->created++;
-					tec->timeouts += counter->u.timer.timeouts;
-					tec->checksForWork += counter->u.timer.checksForWork;
-					tec->timeOnGate += counter->timeOnGate;
-					tec->closeGateCalls += counter->closeGateCalls;
-					tec->openGateCalls += counter->openGateCalls;
-					break;
-				case kIOStatisticsCommandGateCounter:
-					cgc->created++;
-					cgc->timeOnGate += counter->timeOnGate;
-					cgc->actionCalls += counter->u.commandGate.actionCalls;
-					break;
-				case kIOStatisticsCommandQueueCounter:
-					cqc->created++;
-					cqc->actionCalls += counter->u.commandQueue.actionCalls;
-					break;
-				case kIOStatisticsDerivedEventSourceCounter:
-					dec->created++;
-					dec->timeOnGate += counter->timeOnGate;
-					dec->closeGateCalls += counter->closeGateCalls;
-					dec->openGateCalls += counter->openGateCalls;
-					break;
-				default:
-					break;
-				}
-			}
-
-			stats++;
-		}
-	}
-
-	return sizeof(IOStatisticsCounter) * registeredClasses;
-}
-
-uint32_t
-IOStatistics::copyKextIdentifiers(IOStatisticsKextIdentifier *kextIDs)
-{
-	KextNode *ke;
-
-	RB_FOREACH(ke, KextTree, &kextHead) {
-		strncpy(kextIDs->identifier, ke->kext->getIdentifierCString(), kIOStatisticsDriverNameLength);
-		kextIDs++;
-	}
-
-	return sizeof(IOStatisticsKextIdentifier) * loadedKexts;
-}
-
-uint32_t
-IOStatistics::copyClassNames(IOStatisticsClassName *classNames)
-{
-	KextNode *ke;
-	ClassNode *ce;
-
-	RB_FOREACH(ke, KextTree, &kextHead) {
-		SLIST_FOREACH(ce, &ke->classList, lLink) {
-			strncpy(classNames->name, ce->metaClass->getClassName(), kIOStatisticsClassNameLength);
-			classNames++;
-		}
-	}
-
-	return sizeof(IOStatisticsClassName) * registeredClasses;
-}
-
-uint32_t
-IOStatistics::copyWorkLoopStatistics(IOStatisticsWorkLoop *stats)
-{
-	KextNode *ke;
-	IOWorkLoopCounter *wlc;
-	IOWorkLoopDependency *dependentNode;
-	uint32_t size, accumulatedSize = 0;
-
-	RB_FOREACH(ke, KextTree, &kextHead) {
-		SLIST_FOREACH(wlc, &ke->workLoopList, link) {
-			stats->kextLoadTag = ke->loadTag;
-			stats->attachedEventSources = wlc->attachedEventSources;
-			stats->timeOnGate = wlc->timeOnGate;
-			stats->dependentKexts = 0;
-			RB_FOREACH(dependentNode, IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead) {
-				stats->dependentKextLoadTags[stats->dependentKexts] = dependentNode->loadTag;
-				stats->dependentKexts++;
-			}
-
-			size = sizeof(IOStatisticsWorkLoop) + (sizeof(uint32_t) * stats->dependentKexts);
-
-			accumulatedSize += size;
-			stats = (IOStatisticsWorkLoop*)((void*)((char*)stats + size));
-		}
-	}
-
-	return accumulatedSize;
-}
-
-uint32_t
-IOStatistics::copyUserClientStatistics(IOStatisticsUserClientHeader *stats, uint32_t loadTag)
-{
-	KextNode *sought, *found = NULL;
-	uint32_t procs = 0;
-	IOUserClientProcessEntry *processEntry;
-
-	RB_FOREACH(sought, KextTree, &kextHead) {
-		if (sought->loadTag == loadTag) {
-			found = sought;
-			break;
-		}
-	}
-
-	if (!found) {
-		return 0;
-	}
-
-	TAILQ_FOREACH(processEntry, &found->userClientCallList, link) {
-		strncpy(stats->userClientCalls[procs].processName, processEntry->processName, kIOStatisticsProcessNameLength);
-		stats->userClientCalls[procs].pid = processEntry->pid;
-		stats->userClientCalls[procs].calls = processEntry->calls;
-		stats->processes++;
-		procs++;
-	}
-
-	return sizeof(IOStatisticsUserClientCall) * stats->processes;
-}
-
-void
-IOStatistics::storeUserClientCallInfo(IOUserClient *userClient, IOUserClientCounter *counter)
-{
-	OSString *ossUserClientCreator = NULL;
-	int32_t pid = -1;
-	KextNode *parentKext;
-	IOUserClientProcessEntry *entry, *nextEntry, *prevEntry = NULL;
-	uint32_t count = 0;
-	const char *ptr = NULL;
-	OSObject *obj;
-
-	/* TODO: see if this can be more efficient */
-	obj = userClient->copyProperty("IOUserClientCreator",
-	    gIOServicePlane,
-	    kIORegistryIterateRecursively | kIORegistryIterateParents);
-
-	if (!obj) {
-		goto err_nounlock;
-	}
-
-	ossUserClientCreator = OSDynamicCast(OSString, obj);
-
-	if (ossUserClientCreator) {
-		uint32_t len, lenIter = 0;
-
-		ptr = ossUserClientCreator->getCStringNoCopy();
-		len = ossUserClientCreator->getLength();
-
-		while ((*ptr != ' ') && (lenIter < len)) {
-			ptr++;
-			lenIter++;
-		}
-
-		if (lenIter < len) {
-			ptr++; // Skip the space
-			lenIter++;
-			pid = 0;
-			while ((*ptr != ',') && (lenIter < len)) {
-				pid = pid * 10 + (*ptr - '0');
-				ptr++;
-				lenIter++;
-			}
-
-			if (lenIter == len) {
-				pid = -1;
-			} else {
-				ptr += 2;
-			}
-		}
-	}
-
-	if (-1 == pid) {
-		goto err_nounlock;
-	}
-
-	IORWLockWrite(lock);
-
-	parentKext = counter->parentClass->parentKext;
-
-	TAILQ_FOREACH(entry, &parentKext->userClientCallList, link) {
-		if (entry->pid == pid) {
-			/* Found, so increment count and move to the head */
-			entry->calls++;
-			if (count) {
-				TAILQ_REMOVE(&parentKext->userClientCallList, entry, link);
-				break;
-			} else {
-				/* At the head already, so increment and return */
-				goto err_unlock;
-			}
-		}
-
-		count++;
-	}
-
-	if (!entry) {
-		if (count == IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS) {
-			/* Max elements hit, so reuse the last */
-			entry = TAILQ_LAST(&parentKext->userClientCallList, ProcessEntryList);
-			TAILQ_REMOVE(&parentKext->userClientCallList, entry, link);
-		} else {
-			/* Otherwise, allocate a new entry */
-			entry = kalloc_type(IOUserClientProcessEntry, Z_WAITOK);
-			if (!entry) {
-				goto err_unlock;
-			}
-		}
-
-		strncpy(entry->processName, ptr, kIOStatisticsProcessNameLength);
-		entry->pid = pid;
-		entry->calls = 1;
-	}
-
-	TAILQ_FOREACH(nextEntry, &parentKext->userClientCallList, link) {
-		if (nextEntry->calls <= entry->calls) {
-			break;
-		}
-
-		prevEntry = nextEntry;
-	}
-
-	if (!prevEntry) {
-		TAILQ_INSERT_HEAD(&parentKext->userClientCallList, entry, link);
-	} else {
-		TAILQ_INSERT_AFTER(&parentKext->userClientCallList, prevEntry, entry, link);
-	}
-
-err_unlock:
-	IORWLockUnlock(lock);
-
-err_nounlock:
-	if (obj) {
-		obj->release();
-	}
-}
-
-void
-IOStatistics::countUserClientCall(IOUserClient *client)
-{
-	IOUserClient::ExpansionData *data;
-	IOUserClientCounter *counter;
-
-	/* Guard against an uninitialized client object - <rdar://problem/8577946> */
-	if (!(data = client->reserved)) {
-		return;
-	}
-
-	if ((counter = data->counter)) {
-		storeUserClientCallInfo(client, counter);
-		OSIncrementAtomic(&counter->clientCalls);
-	}
-}
-
-KextNode *
-IOStatistics::getKextNodeFromBacktrace(boolean_t write)
-{
-	const uint32_t btMin = 3;
-
-	void *bt[16];
-	unsigned btCount = sizeof(bt) / sizeof(bt[0]);
-	vm_offset_t *scanAddr = NULL;
-	uint32_t i;
-	KextNode *found = NULL, *ke = NULL;
-
-	/*
-	 * Gathering the backtrace is a significant source of
-	 * overhead. OSBacktrace does many safety checks that
-	 * are not needed in this situation.
-	 */
-	btCount = backtrace((uintptr_t*)bt, btCount, NULL, NULL);
-
-	if (write) {
-		IORWLockWrite(lock);
-	} else {
-		IORWLockRead(lock);
-	}
-
-	/* Ignore first levels */
-	scanAddr = (vm_offset_t *)&bt[btMin - 1];
-
-	for (i = btMin - 1; i < btCount; i++, scanAddr++) {
-		ke = RB_ROOT(&kextAddressHead);
-		while (ke) {
-			if (*scanAddr < ke->address) {
-				ke = RB_LEFT(ke, addressLink);
-			} else {
-				if ((*scanAddr < ke->address_end) && (*scanAddr >= ke->address)) {
-					if (!ke->kext->isKernelComponent()) {
-						return ke;
-					} else {
-						found = ke;
-					}
-				}
-				ke = RB_RIGHT(ke, addressLink);
-			}
-		}
-	}
-
-	if (!found) {
-		IORWLockUnlock(lock);
-	}
-
-	return found;
-}
-
-void
-IOStatistics::releaseKextNode(KextNode *node)
-{
-#pragma unused(node)
-	IORWLockUnlock(lock);
-}
-
-/* IOLib allocations */
-void
-IOStatistics::countAlloc(uint32_t index, vm_size_t size)
-{
-	KextNode *ke;
-
-	if (!enabled) {
-		return;
-	}
-	if (size > INT_MAX) {
-		return;
-	}
-
-	ke = getKextNodeFromBacktrace(FALSE);
-	if (ke) {
-		OSAddAtomic((SInt32) size, &ke->memoryCounters[index]);
-		releaseKextNode(ke);
-	}
-}
-
-#endif /* IOKITSTATS */