#include <sys/sysctl.h>
extern "C" {
#include <vm/vm_kern.h>
}
#include <libkern/c++/OSContainers.h>
#include <libkern/OSDebug.h>
#include <libkern/c++/OSCPPDebug.h>
#include <IOKit/IOKitDebug.h>
#include <IOKit/IOLib.h>
#include <IOKit/assert.h>
#include <IOKit/IODeviceTreeSupport.h>
#include <IOKit/IOService.h>
#ifdef IOKITDEBUG
#define DEBUG_INIT_VALUE IOKITDEBUG
#else
#define DEBUG_INIT_VALUE 0
#endif
SInt64 gIOKitDebug = DEBUG_INIT_VALUE;
SInt64 gIOKitTrace = 0;
#if DEVELOPMENT || DEBUG
#define IODEBUG_CTLFLAGS CTLFLAG_RW
#else
#define IODEBUG_CTLFLAGS CTLFLAG_RD
#endif
SYSCTL_QUAD(_debug, OID_AUTO, iokit, IODEBUG_CTLFLAGS | CTLFLAG_LOCKED, &gIOKitDebug, "boot_arg io");
SYSCTL_QUAD(_debug, OID_AUTO, iotrace, CTLFLAG_RW | CTLFLAG_LOCKED, &gIOKitTrace, "trace io");
int debug_malloc_size;
int debug_iomalloc_size;
vm_size_t debug_iomallocpageable_size;
int debug_container_malloc_size;
extern "C" {
#if 0
#define DEBG(fmt, args...) { kprintf(fmt, ## args); }
#else
#define DEBG(fmt, args...) { IOLog(fmt, ## args); }
#endif
void IOPrintPlane( const IORegistryPlane * plane )
{
IORegistryEntry * next;
IORegistryIterator * iter;
OSOrderedSet * all;
char format[] = "%xxxs";
IOService * service;
iter = IORegistryIterator::iterateOver( plane );
assert( iter );
all = iter->iterateAll();
if( all) {
DEBG("Count %d\n", all->getCount() );
all->release();
} else
DEBG("Empty\n");
iter->reset();
while( (next = iter->getNextObjectRecursive())) {
snprintf(format + 1, sizeof(format) - 1, "%ds", 2 * next->getDepth( plane ));
DEBG( format, "");
DEBG( "\033[33m%s", next->getName( plane ));
if( (next->getLocation( plane )))
DEBG("@%s", next->getLocation( plane ));
DEBG("\033[0m <class %s", next->getMetaClass()->getClassName());
if( (service = OSDynamicCast(IOService, next)))
DEBG(", busy %ld", (long) service->getBusyState());
DEBG( ">\n");
}
iter->release();
}
void db_piokjunk(void)
{
}
void db_dumpiojunk( const IORegistryPlane * plane __unused )
{
}
void IOPrintMemory( void )
{
IOLog("\n"
"ivar kalloc() 0x%08x\n"
"malloc() 0x%08x\n"
"containers kalloc() 0x%08x\n"
"IOMalloc() 0x%08x\n"
"----------------------------------------\n",
debug_ivars_size,
debug_malloc_size,
debug_container_malloc_size,
debug_iomalloc_size
);
}
}
#define super OSObject
OSDefineMetaClassAndStructors(IOKitDiagnostics, OSObject)
OSObject * IOKitDiagnostics::diagnostics( void )
{
IOKitDiagnostics * diags;
diags = new IOKitDiagnostics;
if( diags && !diags->init()) {
diags->release();
diags = 0;
}
return( diags );
}
void IOKitDiagnostics::updateOffset( OSDictionary * dict,
UInt64 value, const char * name )
{
OSNumber * off;
off = OSNumber::withNumber( value, 64 );
if( !off)
return;
dict->setObject( name, off );
off->release();
}
bool IOKitDiagnostics::serialize(OSSerialize *s) const
{
OSDictionary * dict;
bool ok;
dict = OSDictionary::withCapacity( 5 );
if( !dict)
return( false );
updateOffset( dict, debug_ivars_size, "Instance allocation" );
updateOffset( dict, debug_container_malloc_size, "Container allocation" );
updateOffset( dict, debug_iomalloc_size, "IOMalloc allocation" );
updateOffset( dict, debug_iomallocpageable_size, "Pageable allocation" );
OSMetaClass::serializeClassDictionary(dict);
ok = dict->serialize( s );
dict->release();
return( ok );
}
#if IOTRACKING
#include <libkern/c++/OSCPPDebug.h>
#include <libkern/c++/OSKext.h>
#include <kern/zalloc.h>
__private_extern__ "C" void qsort(
void * array,
size_t nmembers,
size_t member_size,
int (*)(const void *, const void *));
extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
extern "C" ppnum_t pmap_valid_page(ppnum_t pn);
struct IOTRecursiveLock
{
lck_mtx_t * mutex;
thread_t thread;
UInt32 count;
};
struct IOTrackingQueue
{
queue_chain_t link;
IOTRecursiveLock lock;
queue_head_t sites;
const char * name;
size_t allocSize;
size_t minCaptureSize;
uint32_t siteCount;
uint8_t captureOn;
uint8_t isAlloc;
};
struct IOTrackingCallSite
{
queue_chain_t link;
IOTrackingQueue * queue;
uint32_t crc;
IOTrackingCallSiteInfo info;
queue_chain_t instances;
IOTracking * addresses;
};
struct IOTrackingLeaksRef
{
uintptr_t * instances;
uint32_t count;
uint32_t found;
size_t bytes;
};
enum
{
kInstanceFlagAddress = 0x01UL,
kInstanceFlagReferenced = 0x02UL,
kInstanceFlags = 0x03UL
};
lck_mtx_t * gIOTrackingLock;
queue_head_t gIOTrackingQ;
enum
{
kTrackingAddressFlagAllocated = 0x00000001
};
#if defined(__LP64__)
#define IOTrackingAddressFlags(ptr) (ptr->flags)
#else
#define IOTrackingAddressFlags(ptr) (ptr->tracking.flags)
#endif
static void
IOTRecursiveLockLock(IOTRecursiveLock * lock)
{
if (lock->thread == current_thread()) lock->count++;
else
{
lck_mtx_lock(lock->mutex);
assert(lock->thread == 0);
assert(lock->count == 0);
lock->thread = current_thread();
lock->count = 1;
}
}
static void
IOTRecursiveLockUnlock(IOTRecursiveLock * lock)
{
assert(lock->thread == current_thread());
if (0 == (--lock->count))
{
lock->thread = 0;
lck_mtx_unlock(lock->mutex);
}
}
void
IOTrackingInit(void)
{
queue_init(&gIOTrackingQ);
gIOTrackingLock = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
}
IOTrackingQueue *
IOTrackingQueueAlloc(const char * name, size_t allocSize, size_t minCaptureSize, bool isAlloc)
{
IOTrackingQueue * queue;
queue = (typeof(queue)) kalloc(sizeof(IOTrackingQueue));
bzero(queue, sizeof(IOTrackingQueue));
queue->name = name;
queue->allocSize = allocSize;
queue->minCaptureSize = minCaptureSize;
queue->lock.mutex = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
queue_init(&queue->sites);
queue->captureOn = (0 != (kIOTrackingBoot & gIOKitDebug));
queue->isAlloc = isAlloc;
lck_mtx_lock(gIOTrackingLock);
queue_enter(&gIOTrackingQ, queue, IOTrackingQueue *, link);
lck_mtx_unlock(gIOTrackingLock);
return (queue);
};
void
IOTrackingQueueFree(IOTrackingQueue * queue)
{
lck_mtx_lock(gIOTrackingLock);
IOTrackingReset(queue);
remque(&queue->link);
lck_mtx_unlock(gIOTrackingLock);
lck_mtx_free(queue->lock.mutex, IOLockGroup);
kfree(queue, sizeof(IOTrackingQueue));
};
#define mix(h) ({ \
(h) ^= (h) >> 23; \
(h) *= 0x2127599bf4325c37ULL; \
(h) ^= (h) >> 47; })
static uint64_t
fasthash64(const void *buf, size_t len, uint64_t seed)
{
const uint64_t m = 0x880355f21e6d1965ULL;
const uint64_t *pos = (const uint64_t *)buf;
const uint64_t *end = pos + (len / 8);
const unsigned char *pos2;
uint64_t h = seed ^ (len * m);
uint64_t v;
while (pos != end) {
v = *pos++;
h ^= mix(v);
h *= m;
}
pos2 = (const unsigned char*)pos;
v = 0;
switch (len & 7) {
case 7: v ^= (uint64_t)pos2[6] << 48;
case 6: v ^= (uint64_t)pos2[5] << 40;
case 5: v ^= (uint64_t)pos2[4] << 32;
case 4: v ^= (uint64_t)pos2[3] << 24;
case 3: v ^= (uint64_t)pos2[2] << 16;
case 2: v ^= (uint64_t)pos2[1] << 8;
case 1: v ^= (uint64_t)pos2[0];
h ^= mix(v);
h *= m;
}
return mix(h);
}
static uint32_t
fasthash32(const void *buf, size_t len, uint32_t seed)
{
uint64_t h = fasthash64(buf, len, seed);
return h - (h >> 32);
}
void
IOTrackingAdd(IOTrackingQueue * queue, IOTracking * mem, size_t size, bool address)
{
IOTrackingCallSite * site;
uint32_t crc, num;
uintptr_t bt[kIOTrackingCallSiteBTs + 1];
if (mem->site) return;
if (!queue->captureOn) return;
if (size < queue->minCaptureSize) return;
assert(!mem->link.next);
num = fastbacktrace(&bt[0], kIOTrackingCallSiteBTs + 1);
num--;
crc = fasthash32(&bt[1], num * sizeof(bt[0]), 0x04C11DB7);
IOTRecursiveLockLock(&queue->lock);
queue_iterate(&queue->sites, site, IOTrackingCallSite *, link)
{
if (crc == site->crc) break;
}
if (queue_end(&queue->sites, (queue_entry_t) site))
{
site = (typeof(site)) kalloc(sizeof(IOTrackingCallSite));
queue_init(&site->instances);
site->addresses = (IOTracking *) &site->instances;
site->queue = queue;
site->crc = crc;
site->info.count = 0;
memset(&site->info.size[0], 0, sizeof(site->info.size));
bcopy(&bt[1], &site->info.bt[0], num * sizeof(site->info.bt[0]));
assert(num <= kIOTrackingCallSiteBTs);
bzero(&site->info.bt[num], (kIOTrackingCallSiteBTs - num) * sizeof(site->info.bt[0]));
queue_enter_first(&queue->sites, site, IOTrackingCallSite *, link);
queue->siteCount++;
}
if (address)
{
queue_enter(&site->instances, mem, IOTrackingCallSite *, link);
if (queue_end(&site->instances, (queue_entry_t)site->addresses)) site->addresses = mem;
}
else queue_enter_first(&site->instances, mem, IOTrackingCallSite *, link);
mem->site = site;
site->info.size[0] += size;
site->info.count++;
IOTRecursiveLockUnlock(&queue->lock);
}
void
IOTrackingRemove(IOTrackingQueue * queue, IOTracking * mem, size_t size)
{
if (!mem->link.next) return;
IOTRecursiveLockLock(&queue->lock);
assert(mem->site);
if (mem == mem->site->addresses) mem->site->addresses = (IOTracking *) queue_next(&mem->link);
remque(&mem->link);
assert(mem->site->info.count);
mem->site->info.count--;
assert(mem->site->info.size[0] >= size);
mem->site->info.size[0] -= size;
if (!mem->site->info.count)
{
assert(queue_empty(&mem->site->instances));
assert(!mem->site->info.size[0]);
assert(!mem->site->info.size[1]);
remque(&mem->site->link);
assert(queue->siteCount);
queue->siteCount--;
kfree(mem->site, sizeof(IOTrackingCallSite));
}
IOTRecursiveLockUnlock(&queue->lock);
}
void
IOTrackingAlloc(IOTrackingQueue * queue, uintptr_t address, size_t size)
{
IOTrackingAddress * tracking;
if (!queue->captureOn) return;
if (size < queue->minCaptureSize) return;
address = ~address;
tracking = (typeof(tracking)) kalloc(sizeof(IOTrackingAddress));
bzero(tracking, sizeof(IOTrackingAddress));
IOTrackingAddressFlags(tracking) |= kTrackingAddressFlagAllocated;
tracking->address = address;
tracking->size = size;
IOTrackingAdd(queue, &tracking->tracking, size, true);
}
void
IOTrackingFree(IOTrackingQueue * queue, uintptr_t address, size_t size)
{
IOTrackingCallSite * site;
IOTrackingAddress * tracking;
bool done;
address = ~address;
IOTRecursiveLockLock(&queue->lock);
done = false;
queue_iterate(&queue->sites, site, IOTrackingCallSite *, link)
{
for (tracking = (IOTrackingAddress *) site->addresses;
!done && !queue_end(&site->instances, (queue_entry_t) tracking);
tracking = (IOTrackingAddress *) queue_next(&tracking->tracking.link))
{
if ((done = (address == tracking->address)))
{
IOTrackingRemove(queue, &tracking->tracking, size);
kfree(tracking, sizeof(IOTrackingAddress));
}
}
if (done) break;
}
IOTRecursiveLockUnlock(&queue->lock);
}
void
IOTrackingAccumSize(IOTrackingQueue * queue, IOTracking * mem, size_t size)
{
IOTRecursiveLockLock(&queue->lock);
if (mem->link.next)
{
assert(mem->site);
assert((size > 0) || (mem->site->info.size[1] >= -size));
mem->site->info.size[1] += size;
};
IOTRecursiveLockUnlock(&queue->lock);
}
void
IOTrackingReset(IOTrackingQueue * queue)
{
IOTrackingCallSite * site;
IOTracking * tracking;
IOTrackingAddress * trackingAddress;
bool addresses;
IOTRecursiveLockLock(&queue->lock);
while (!queue_empty(&queue->sites))
{
queue_remove_first(&queue->sites, site, IOTrackingCallSite *, link);
addresses = false;
while (!queue_empty(&site->instances))
{
queue_remove_first(&site->instances, tracking, IOTracking *, link);
tracking->link.next = 0;
if (tracking == site->addresses) addresses = true;
if (addresses)
{
trackingAddress = (typeof(trackingAddress)) tracking;
if (kTrackingAddressFlagAllocated & IOTrackingAddressFlags(trackingAddress))
{
kfree(tracking, sizeof(IOTrackingAddress));
}
}
}
kfree(site, sizeof(IOTrackingCallSite));
}
queue->siteCount = 0;
IOTRecursiveLockUnlock(&queue->lock);
}
static int
IOTrackingCallSiteInfoCompare(const void * left, const void * right)
{
IOTrackingCallSiteInfo * l = (typeof(l)) left;
IOTrackingCallSiteInfo * r = (typeof(r)) right;
size_t lsize, rsize;
rsize = r->size[0] + r->size[1];
lsize = l->size[0] + l->size[1];
return ((rsize > lsize) ? 1 : ((rsize == lsize) ? 0 : -1));
}
static int
IOTrackingAddressCompare(const void * left, const void * right)
{
IOTracking * instance;
uintptr_t inst, laddr, raddr;
inst = ((typeof(inst) *) left)[0];
instance = (typeof(instance)) (inst & ~kInstanceFlags);
if (kInstanceFlagAddress & inst) laddr = ~((IOTrackingAddress *)instance)->address;
else laddr = (uintptr_t) (instance + 1);
inst = ((typeof(inst) *) right)[0];
instance = (typeof(instance)) (inst & ~kInstanceFlags);
if (kInstanceFlagAddress & inst) raddr = ~((IOTrackingAddress *)instance)->address;
else raddr = (uintptr_t) (instance + 1);
return ((laddr > raddr) ? 1 : ((laddr == raddr) ? 0 : -1));
}
static void
IOTrackingLeakScan(void * refcon)
{
IOTrackingLeaksRef * ref = (typeof(ref)) refcon;
uintptr_t * instances;
IOTracking * instance;
uint64_t vaddr, vincr;
ppnum_t ppn;
uintptr_t ptr, addr, inst;
size_t size;
uint32_t baseIdx, lim, ptrIdx, count;
boolean_t is;
instances = ref->instances;
count = ref->count;
for (vaddr = VM_MIN_KERNEL_AND_KEXT_ADDRESS;
vaddr < VM_MAX_KERNEL_ADDRESS;
ml_set_interrupts_enabled(is), vaddr += vincr)
{
#if !defined(__LP64__)
thread_block(NULL);
#endif
is = ml_set_interrupts_enabled(false);
ppn = kernel_pmap_present_mapping(vaddr, &vincr);
if (ppn && (!pmap_valid_page(ppn) || pmap_is_noencrypt(ppn))) ppn = 0;
if (!ppn) continue;
for (ptrIdx = 0; ptrIdx < (page_size / sizeof(uintptr_t)); ptrIdx++)
{
ptr = ((uintptr_t *)vaddr)[ptrIdx];
for (lim = count, baseIdx = 0; lim; lim >>= 1)
{
inst = instances[baseIdx + (lim >> 1)];
instance = (typeof(instance)) (inst & ~kInstanceFlags);
if (kInstanceFlagAddress & inst)
{
addr = ~((IOTrackingAddress *)instance)->address;
size = ((IOTrackingAddress *)instance)->size;
}
else
{
addr = (uintptr_t) (instance + 1);
size = instance->site->queue->allocSize;
}
if ((ptr >= addr) && (ptr < (addr + size)))
{
if (!(kInstanceFlagReferenced & inst))
{
inst |= kInstanceFlagReferenced;
instances[baseIdx + (lim >> 1)] = inst;
ref->found++;
}
break;
}
if (ptr > addr)
{
baseIdx += (lim >> 1) + 1;
lim--;
}
}
}
ref->bytes += page_size;
}
}
static OSData *
IOTrackingLeaks(OSData * data)
{
IOTrackingLeaksRef ref;
IOTrackingCallSiteInfo unslideInfo;
IOTrackingCallSite * site;
OSData * leakData;
uintptr_t * instances;
IOTracking * instance;
uintptr_t inst;
uint32_t count, idx, numSites, dups, siteCount;
instances = (typeof(instances)) data->getBytesNoCopy();
count = (data->getLength() / sizeof(*instances));
qsort(instances, count, sizeof(*instances), &IOTrackingAddressCompare);
bzero(&ref, sizeof(ref));
ref.instances = instances;
ref.count = count;
IOTrackingLeakScan(&ref);
IOLog("leaks scanned %ld MB, instance count %d, found %d\n", ref.bytes / 1024 / 1024, count, ref.found);
leakData = OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo));
for (numSites = 0, idx = 0; idx < count; idx++)
{
inst = instances[idx];
if (kInstanceFlagReferenced & inst) continue;
instance = (typeof(instance)) (inst & ~kInstanceFlags);
site = instance->site;
instances[numSites] = (uintptr_t) site;
numSites++;
}
for (idx = 0; idx < numSites; idx++)
{
inst = instances[idx];
if (!inst) continue;
site = (typeof(site)) inst;
for (siteCount = 1, dups = (idx + 1); dups < numSites; dups++)
{
if (instances[dups] == (uintptr_t) site)
{
siteCount++;
instances[dups] = 0;
}
}
unslideInfo.count = siteCount;
unslideInfo.size[0] = (site->info.size[0] * site->info.count) / siteCount;
unslideInfo.size[1] = (site->info.size[1] * site->info.count) / siteCount;;
for (uint32_t j = 0; j < kIOTrackingCallSiteBTs; j++)
{
unslideInfo.bt[j] = VM_KERNEL_UNSLIDE(site->info.bt[j]);
}
leakData->appendBytes(&unslideInfo, sizeof(unslideInfo));
}
data->release();
return (leakData);
}
static bool
SkipName(uint32_t options, const char * name, size_t namesLen, const char * names)
{
const char * scan;
const char * next;
bool exclude, found;
size_t qLen, sLen;
if (!namesLen || !names) return (false);
exclude = (0 != (kIOTrackingExcludeNames & options));
qLen = strlen(name);
scan = names;
found = false;
do
{
sLen = scan[0];
scan++;
next = scan + sLen;
if (next >= (names + namesLen)) break;
found = ((sLen == qLen) && !strncmp(scan, name, sLen));
scan = next;
}
while (!found && (scan < (names + namesLen)));
return (!(exclude ^ found));
}
#endif
kern_return_t
IOTrackingDebug(uint32_t selector, uint32_t options,
const char * names, size_t namesLen,
size_t size, OSObject ** result)
{
kern_return_t ret;
OSData * data;
if (result) *result = 0;
data = 0;
ret = kIOReturnNotReady;
#if IOTRACKING
IOTrackingQueue * queue;
IOTracking * instance;
IOTrackingCallSite * site;
IOTrackingCallSiteInfo * siteInfos;
IOTrackingCallSiteInfo * siteInfo;
bool addresses;
uint32_t num, idx;
uintptr_t instFlags;
if (!(kIOTracking & gIOKitDebug)) return (kIOReturnNotReady);
ret = kIOReturnNotFound;
lck_mtx_lock(gIOTrackingLock);
queue_iterate(&gIOTrackingQ, queue, IOTrackingQueue *, link)
{
if (SkipName(options, queue->name, namesLen, names)) continue;
switch (selector)
{
case kIOTrackingResetTracking:
{
IOTrackingReset(queue);
ret = kIOReturnSuccess;
break;
}
case kIOTrackingStartCapture:
case kIOTrackingStopCapture:
{
queue->captureOn = (kIOTrackingStartCapture == selector);
ret = kIOReturnSuccess;
break;
}
case kIOTrackingSetMinCaptureSize:
{
queue->minCaptureSize = size;
ret = kIOReturnSuccess;
break;
}
case kIOTrackingLeaks:
{
if (!queue->isAlloc) break;
if (!data) data = OSData::withCapacity(1024 * sizeof(uintptr_t));
IOTRecursiveLockLock(&queue->lock);
queue_iterate(&queue->sites, site, IOTrackingCallSite *, link)
{
addresses = false;
queue_iterate(&site->instances, instance, IOTracking *, link)
{
if (instance == site->addresses) addresses = true;
instFlags = (typeof(instFlags)) instance;
if (addresses) instFlags |= kInstanceFlagAddress;
data->appendBytes(&instFlags, sizeof(instFlags));
}
}
ret = kIOReturnSuccess;
break;
}
case kIOTrackingGetTracking:
case kIOTrackingPrintTracking:
{
if (!data) data = OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo));
IOTRecursiveLockLock(&queue->lock);
num = queue->siteCount;
idx = 0;
queue_iterate(&queue->sites, site, IOTrackingCallSite *, link)
{
assert(idx < num);
idx++;
if (size && ((site->info.size[0] + site->info.size[1]) < size)) continue;
IOTrackingCallSiteInfo unslideInfo;
unslideInfo.count = site->info.count;
memcpy(&unslideInfo.size[0], &site->info.size[0], sizeof(unslideInfo.size));
for (uint32_t j = 0; j < kIOTrackingCallSiteBTs; j++)
{
unslideInfo.bt[j] = VM_KERNEL_UNSLIDE(site->info.bt[j]);
}
data->appendBytes(&unslideInfo, sizeof(unslideInfo));
}
assert(idx == num);
IOTRecursiveLockUnlock(&queue->lock);
ret = kIOReturnSuccess;
break;
}
default:
ret = kIOReturnUnsupported;
break;
}
}
if ((kIOTrackingLeaks == selector) && data)
{
data = IOTrackingLeaks(data);
queue_iterate(&gIOTrackingQ, queue, IOTrackingQueue *, link)
{
if (SkipName(options, queue->name, namesLen, names)) continue;
if (!queue->isAlloc) continue;
IOTRecursiveLockUnlock(&queue->lock);
}
}
lck_mtx_unlock(gIOTrackingLock);
if (data)
{
siteInfos = (typeof(siteInfos)) data->getBytesNoCopy();
num = (data->getLength() / sizeof(IOTrackingCallSiteInfo));
qsort(siteInfos, num, sizeof(*siteInfos), &IOTrackingCallSiteInfoCompare);
if (kIOTrackingPrintTracking == selector)
{
for (idx = 0; idx < num; idx++)
{
siteInfo = &siteInfos[idx];
printf("\n0x%lx bytes (0x%lx + 0x%lx), %d call%s, [%d]\n",
siteInfo->size[0] + siteInfo->size[1],
siteInfo->size[0], siteInfo->size[1],
siteInfo->count, (siteInfo->count != 1) ? "s" : "", idx);
uintptr_t * bt = &siteInfo->bt[0];
printf(" Backtrace 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
bt[0], bt[1], bt[2], bt[3], bt[4], bt[5], bt[6], bt[7],
bt[8], bt[9], bt[10], bt[11], bt[12], bt[13], bt[14], bt[15]);
kmod_dump_log((vm_offset_t *) &bt[0], kIOTrackingCallSiteBTs, FALSE);
}
data->release();
data = 0;
}
}
*result = data;
#endif
return (ret);
}
#include <IOKit/IOKitDiagnosticsUserClient.h>
#undef super
#define super IOUserClient
OSDefineMetaClassAndStructors(IOKitDiagnosticsClient, IOUserClient)
IOUserClient * IOKitDiagnosticsClient::withTask(task_t owningTask)
{
IOKitDiagnosticsClient * inst;
inst = new IOKitDiagnosticsClient;
if (inst && !inst->init())
{
inst->release();
inst = 0;
}
return (inst);
}
IOReturn IOKitDiagnosticsClient::clientClose(void)
{
terminate();
return (kIOReturnSuccess);
}
IOReturn IOKitDiagnosticsClient::setProperties(OSObject * properties)
{
IOReturn kr = kIOReturnUnsupported;
return (kr);
}
IOReturn IOKitDiagnosticsClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
{
IOReturn ret = kIOReturnBadArgument;
const IOKitDiagnosticsParameters * params;
const char * names;
size_t namesLen;
OSObject * result;
if (args->structureInputSize < sizeof(IOKitDiagnosticsParameters)) return (kIOReturnBadArgument);
params = (typeof(params)) args->structureInput;
if (!params) return (kIOReturnBadArgument);
names = 0;
namesLen = args->structureInputSize - sizeof(IOKitDiagnosticsParameters);
if (namesLen) names = (typeof(names))(params + 1);
ret = IOTrackingDebug(selector, params->options, names, namesLen, params->size, &result);
if ((kIOReturnSuccess == ret) && args->structureVariableOutputData) *args->structureVariableOutputData = result;
else if (result) result->release();
return (ret);
}