xref: /xnu-11215/iokit/Kernel/IOKitDebug.cpp (revision bb611c8f)
1c1dac77fSApple OSS Distributions /*
288cc0b97SApple OSS Distributions  * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
3c1dac77fSApple OSS Distributions  *
4e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5c1dac77fSApple OSS Distributions  *
6e13b1fa5SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7e13b1fa5SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8e13b1fa5SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9e13b1fa5SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10e13b1fa5SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11e13b1fa5SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12e13b1fa5SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13e13b1fa5SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14c1dac77fSApple OSS Distributions  *
15e13b1fa5SApple OSS Distributions  * Please obtain a copy of the License at
16e13b1fa5SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17e13b1fa5SApple OSS Distributions  *
18e13b1fa5SApple OSS Distributions  * The Original Code and all software distributed under the License are
19e13b1fa5SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20c1dac77fSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21c1dac77fSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22e13b1fa5SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23e13b1fa5SApple OSS Distributions  * Please see the License for the specific language governing rights and
24e13b1fa5SApple OSS Distributions  * limitations under the License.
25c1dac77fSApple OSS Distributions  *
26e13b1fa5SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27c1dac77fSApple OSS Distributions  */
28c1dac77fSApple OSS Distributions 
290f3703acSApple OSS Distributions 
3014e3d835SApple OSS Distributions #include <sys/sysctl.h>
310f3703acSApple OSS Distributions extern "C" {
320f3703acSApple OSS Distributions #include <vm/vm_kern.h>
3388cc0b97SApple OSS Distributions #include <kern/task.h>
3488cc0b97SApple OSS Distributions #include <kern/debug.h>
350f3703acSApple OSS Distributions }
3614e3d835SApple OSS Distributions 
37855239e5SApple OSS Distributions #include <libkern/c++/OSContainers.h>
380f3703acSApple OSS Distributions #include <libkern/OSDebug.h>
39855239e5SApple OSS Distributions #include <libkern/c++/OSCPPDebug.h>
4088cc0b97SApple OSS Distributions #include <kern/backtrace.h>
41855239e5SApple OSS Distributions 
42c1dac77fSApple OSS Distributions #include <IOKit/IOKitDebug.h>
43c1dac77fSApple OSS Distributions #include <IOKit/IOLib.h>
44c1dac77fSApple OSS Distributions #include <IOKit/assert.h>
45c1dac77fSApple OSS Distributions #include <IOKit/IODeviceTreeSupport.h>
46c1dac77fSApple OSS Distributions #include <IOKit/IOService.h>
47c1dac77fSApple OSS Distributions 
4888cc0b97SApple OSS Distributions #include "IOKitKernelInternal.h"
4988cc0b97SApple OSS Distributions 
50c1dac77fSApple OSS Distributions #ifdef IOKITDEBUG
5114e3d835SApple OSS Distributions #define DEBUG_INIT_VALUE IOKITDEBUG
5214e3d835SApple OSS Distributions #else
5314e3d835SApple OSS Distributions #define DEBUG_INIT_VALUE 0
54c1dac77fSApple OSS Distributions #endif
5514e3d835SApple OSS Distributions 
5614e3d835SApple OSS Distributions SInt64          gIOKitDebug = DEBUG_INIT_VALUE;
57855239e5SApple OSS Distributions SInt64          gIOKitTrace = 0;
58855239e5SApple OSS Distributions 
59a3bb9fccSApple OSS Distributions #if DEVELOPMENT || DEBUG
60a3bb9fccSApple OSS Distributions #define IODEBUG_CTLFLAGS        CTLFLAG_RW
61a3bb9fccSApple OSS Distributions #else
62a3bb9fccSApple OSS Distributions #define IODEBUG_CTLFLAGS        CTLFLAG_RD
63a3bb9fccSApple OSS Distributions #endif
64a3bb9fccSApple OSS Distributions 
65855239e5SApple OSS Distributions SYSCTL_QUAD(_debug, OID_AUTO, iotrace, CTLFLAG_RW | CTLFLAG_LOCKED, &gIOKitTrace, "trace io");
6614e3d835SApple OSS Distributions 
6776e12aa3SApple OSS Distributions static int
6876e12aa3SApple OSS Distributions sysctl_debug_iokit
6976e12aa3SApple OSS Distributions (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
7076e12aa3SApple OSS Distributions {
7176e12aa3SApple OSS Distributions 	SInt64 newValue;
7276e12aa3SApple OSS Distributions 	int changed, error = sysctl_io_number(req, gIOKitDebug, sizeof(gIOKitDebug), &newValue, &changed);
7376e12aa3SApple OSS Distributions 	if (changed) {
7476e12aa3SApple OSS Distributions 		gIOKitDebug = ((gIOKitDebug & ~kIOKitDebugUserOptions) | (newValue & kIOKitDebugUserOptions));
7576e12aa3SApple OSS Distributions 	}
76a5e72196SApple OSS Distributions 	return error;
7776e12aa3SApple OSS Distributions }
7876e12aa3SApple OSS Distributions 
7976e12aa3SApple OSS Distributions SYSCTL_PROC(_debug, OID_AUTO, iokit,
8076e12aa3SApple OSS Distributions     CTLTYPE_QUAD | IODEBUG_CTLFLAGS | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
8176e12aa3SApple OSS Distributions     &gIOKitDebug, 0, sysctl_debug_iokit, "Q", "boot_arg io");
82c1dac77fSApple OSS Distributions 
83*bb611c8fSApple OSS Distributions size_t          debug_malloc_size;
84*bb611c8fSApple OSS Distributions size_t          debug_iomalloc_size;
85e13b1fa5SApple OSS Distributions 
8614e3d835SApple OSS Distributions vm_size_t       debug_iomallocpageable_size;
87*bb611c8fSApple OSS Distributions size_t          debug_container_malloc_size;
88c1dac77fSApple OSS Distributions // int          debug_ivars_size; // in OSObject.cpp
89c1dac77fSApple OSS Distributions 
9014e3d835SApple OSS Distributions extern "C" {
913ca3bd55SApple OSS Distributions #if 0
923ca3bd55SApple OSS Distributions #define DEBG(fmt, args...)   { kprintf(fmt, ## args); }
933ca3bd55SApple OSS Distributions #else
943ca3bd55SApple OSS Distributions #define DEBG(fmt, args...)   { IOLog(fmt, ## args); }
953ca3bd55SApple OSS Distributions #endif
9614e3d835SApple OSS Distributions 
97a5e72196SApple OSS Distributions void
98a5e72196SApple OSS Distributions IOPrintPlane( const IORegistryPlane * plane )
99c1dac77fSApple OSS Distributions {
100c1dac77fSApple OSS Distributions 	IORegistryEntry *           next;
101c1dac77fSApple OSS Distributions 	IORegistryIterator *        iter;
102c1dac77fSApple OSS Distributions 	OSOrderedSet *              all;
103c1dac77fSApple OSS Distributions 	char                        format[] = "%xxxs";
104c1dac77fSApple OSS Distributions 	IOService *                 service;
105c1dac77fSApple OSS Distributions 
106c1dac77fSApple OSS Distributions 	iter = IORegistryIterator::iterateOver( plane );
107c1dac77fSApple OSS Distributions 	assert( iter );
108c1dac77fSApple OSS Distributions 	all = iter->iterateAll();
109c1dac77fSApple OSS Distributions 	if (all) {
1103ca3bd55SApple OSS Distributions 		DEBG("Count %d\n", all->getCount());
111c1dac77fSApple OSS Distributions 		all->release();
112a5e72196SApple OSS Distributions 	} else {
1133ca3bd55SApple OSS Distributions 		DEBG("Empty\n");
114a5e72196SApple OSS Distributions 	}
115c1dac77fSApple OSS Distributions 
116c1dac77fSApple OSS Distributions 	iter->reset();
117c1dac77fSApple OSS Distributions 	while ((next = iter->getNextObjectRecursive())) {
118e13b1fa5SApple OSS Distributions 		snprintf(format + 1, sizeof(format) - 1, "%ds", 2 * next->getDepth( plane ));
1193ca3bd55SApple OSS Distributions 		DEBG( format, "");
1203ca3bd55SApple OSS Distributions 		DEBG( "\033[33m%s", next->getName( plane ));
121a5e72196SApple OSS Distributions 		if ((next->getLocation( plane ))) {
1223ca3bd55SApple OSS Distributions 			DEBG("@%s", next->getLocation( plane ));
123a5e72196SApple OSS Distributions 		}
1243ca3bd55SApple OSS Distributions 		DEBG("\033[0m <class %s", next->getMetaClass()->getClassName());
125a5e72196SApple OSS Distributions 		if ((service = OSDynamicCast(IOService, next))) {
1263ca3bd55SApple OSS Distributions 			DEBG(", busy %ld", (long) service->getBusyState());
127a5e72196SApple OSS Distributions 		}
1283ca3bd55SApple OSS Distributions 		DEBG( ">\n");
1293ca3bd55SApple OSS Distributions //      IOSleep(250);
130c1dac77fSApple OSS Distributions 	}
131c1dac77fSApple OSS Distributions 	iter->release();
132c1dac77fSApple OSS Distributions }
133c1dac77fSApple OSS Distributions 
134a5e72196SApple OSS Distributions void
135a5e72196SApple OSS Distributions db_piokjunk(void)
136368ad365SApple OSS Distributions {
137368ad365SApple OSS Distributions }
138d0c1fef6SApple OSS Distributions 
139a5e72196SApple OSS Distributions void
140a5e72196SApple OSS Distributions db_dumpiojunk( const IORegistryPlane * plane __unused )
141d0c1fef6SApple OSS Distributions {
142368ad365SApple OSS Distributions }
143368ad365SApple OSS Distributions 
144a5e72196SApple OSS Distributions void
145a5e72196SApple OSS Distributions IOPrintMemory( void )
146c1dac77fSApple OSS Distributions {
147c1dac77fSApple OSS Distributions //    OSMetaClass::printInstanceCounts();
148c1dac77fSApple OSS Distributions 
149c1dac77fSApple OSS Distributions 	IOLog("\n"
150*bb611c8fSApple OSS Distributions 	    "ivar kalloc()       0x%08lx\n"
151*bb611c8fSApple OSS Distributions 	    "malloc()            0x%08lx\n"
152*bb611c8fSApple OSS Distributions 	    "containers kalloc() 0x%08lx\n"
153*bb611c8fSApple OSS Distributions 	    "IOMalloc()          0x%08lx\n"
154c1dac77fSApple OSS Distributions 	    "----------------------------------------\n",
155c1dac77fSApple OSS Distributions 	    debug_ivars_size,
156c1dac77fSApple OSS Distributions 	    debug_malloc_size,
157c1dac77fSApple OSS Distributions 	    debug_container_malloc_size,
158c1dac77fSApple OSS Distributions 	    debug_iomalloc_size
159c1dac77fSApple OSS Distributions 	    );
160c1dac77fSApple OSS Distributions }
161c1dac77fSApple OSS Distributions } /* extern "C" */
162c1dac77fSApple OSS Distributions 
1630f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
164c1dac77fSApple OSS Distributions 
165c1dac77fSApple OSS Distributions #define super OSObject
166c1dac77fSApple OSS Distributions OSDefineMetaClassAndStructors(IOKitDiagnostics, OSObject)
167c1dac77fSApple OSS Distributions 
1680f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
169c1dac77fSApple OSS Distributions 
170c1dac77fSApple OSS Distributions OSObject * IOKitDiagnostics::diagnostics( void )
171c1dac77fSApple OSS Distributions {
172c1dac77fSApple OSS Distributions 	IOKitDiagnostics * diags;
173c1dac77fSApple OSS Distributions 
174c1dac77fSApple OSS Distributions 	diags = new IOKitDiagnostics;
175c1dac77fSApple OSS Distributions 	if (diags && !diags->init()) {
176c1dac77fSApple OSS Distributions 		diags->release();
177a5e72196SApple OSS Distributions 		diags = NULL;
178c1dac77fSApple OSS Distributions 	}
179c1dac77fSApple OSS Distributions 
180a5e72196SApple OSS Distributions 	return diags;
181c1dac77fSApple OSS Distributions }
182c1dac77fSApple OSS Distributions 
183a5e72196SApple OSS Distributions void
184a5e72196SApple OSS Distributions IOKitDiagnostics::updateOffset( OSDictionary * dict,
1850f3703acSApple OSS Distributions     UInt64 value, const char * name )
186c1dac77fSApple OSS Distributions {
187c1dac77fSApple OSS Distributions 	OSNumber * off;
188c1dac77fSApple OSS Distributions 
1890f3703acSApple OSS Distributions 	off = OSNumber::withNumber( value, 64 );
190a5e72196SApple OSS Distributions 	if (!off) {
191c1dac77fSApple OSS Distributions 		return;
192a5e72196SApple OSS Distributions 	}
193c1dac77fSApple OSS Distributions 
194c1dac77fSApple OSS Distributions 	dict->setObject( name, off );
195c1dac77fSApple OSS Distributions 	off->release();
196c1dac77fSApple OSS Distributions }
197c1dac77fSApple OSS Distributions 
198a5e72196SApple OSS Distributions bool
199a5e72196SApple OSS Distributions IOKitDiagnostics::serialize(OSSerialize *s) const
200c1dac77fSApple OSS Distributions {
201c1dac77fSApple OSS Distributions 	OSDictionary *      dict;
202c1dac77fSApple OSS Distributions 	bool                ok;
203c1dac77fSApple OSS Distributions 
204c1dac77fSApple OSS Distributions 	dict = OSDictionary::withCapacity( 5 );
205a5e72196SApple OSS Distributions 	if (!dict) {
206a5e72196SApple OSS Distributions 		return false;
207a5e72196SApple OSS Distributions 	}
208c1dac77fSApple OSS Distributions 
209c1dac77fSApple OSS Distributions 	updateOffset( dict, debug_ivars_size, "Instance allocation" );
210c1dac77fSApple OSS Distributions 	updateOffset( dict, debug_container_malloc_size, "Container allocation" );
211c1dac77fSApple OSS Distributions 	updateOffset( dict, debug_iomalloc_size, "IOMalloc allocation" );
21214e3d835SApple OSS Distributions 	updateOffset( dict, debug_iomallocpageable_size, "Pageable allocation" );
213c1dac77fSApple OSS Distributions 
214368ad365SApple OSS Distributions 	OSMetaClass::serializeClassDictionary(dict);
215c1dac77fSApple OSS Distributions 
216c1dac77fSApple OSS Distributions 	ok = dict->serialize( s );
217c1dac77fSApple OSS Distributions 
218c1dac77fSApple OSS Distributions 	dict->release();
219c1dac77fSApple OSS Distributions 
220a5e72196SApple OSS Distributions 	return ok;
221c1dac77fSApple OSS Distributions }
222c1dac77fSApple OSS Distributions 
2230f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2240f3703acSApple OSS Distributions 
2250f3703acSApple OSS Distributions #if IOTRACKING
2260f3703acSApple OSS Distributions 
2270f3703acSApple OSS Distributions #include <libkern/c++/OSCPPDebug.h>
2280f3703acSApple OSS Distributions #include <libkern/c++/OSKext.h>
2290f3703acSApple OSS Distributions #include <kern/zalloc.h>
2300f3703acSApple OSS Distributions 
2310f3703acSApple OSS Distributions __private_extern__ "C" void qsort(
2320f3703acSApple OSS Distributions 	void * array,
2330f3703acSApple OSS Distributions 	size_t nmembers,
2340f3703acSApple OSS Distributions 	size_t member_size,
2350f3703acSApple OSS Distributions 	int (*)(const void *, const void *));
2360f3703acSApple OSS Distributions 
2370f3703acSApple OSS Distributions extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
2380f3703acSApple OSS Distributions extern "C" ppnum_t pmap_valid_page(ppnum_t pn);
2390f3703acSApple OSS Distributions 
2400f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2410f3703acSApple OSS Distributions 
242a5e72196SApple OSS Distributions struct IOTRecursiveLock {
2430f3703acSApple OSS Distributions 	lck_mtx_t * mutex;
2440f3703acSApple OSS Distributions 	thread_t    thread;
2450f3703acSApple OSS Distributions 	UInt32      count;
2460f3703acSApple OSS Distributions };
2470f3703acSApple OSS Distributions 
248a5e72196SApple OSS Distributions struct IOTrackingQueue {
2490f3703acSApple OSS Distributions 	queue_chain_t     link;
2500f3703acSApple OSS Distributions 	IOTRecursiveLock  lock;
2510f3703acSApple OSS Distributions 	const char *      name;
25288cc0b97SApple OSS Distributions 	uintptr_t         btEntry;
2530f3703acSApple OSS Distributions 	size_t            allocSize;
2540f3703acSApple OSS Distributions 	size_t            minCaptureSize;
2550f3703acSApple OSS Distributions 	uint32_t          siteCount;
25688cc0b97SApple OSS Distributions 	uint32_t          type;
25788cc0b97SApple OSS Distributions 	uint32_t          numSiteQs;
2580f3703acSApple OSS Distributions 	uint8_t           captureOn;
25988cc0b97SApple OSS Distributions 	queue_head_t      sites[];
2600f3703acSApple OSS Distributions };
2610f3703acSApple OSS Distributions 
262*bb611c8fSApple OSS Distributions 
263*bb611c8fSApple OSS Distributions struct IOTrackingCallSiteUser {
264*bb611c8fSApple OSS Distributions 	pid_t         pid;
265*bb611c8fSApple OSS Distributions 	uint8_t       user32;
266*bb611c8fSApple OSS Distributions 	uint8_t       userCount;
267*bb611c8fSApple OSS Distributions 	uintptr_t     bt[kIOTrackingCallSiteBTs];
268*bb611c8fSApple OSS Distributions };
269*bb611c8fSApple OSS Distributions 
270a5e72196SApple OSS Distributions struct IOTrackingCallSite {
2710f3703acSApple OSS Distributions 	queue_chain_t          link;
272*bb611c8fSApple OSS Distributions 	queue_head_t           instances;
2730f3703acSApple OSS Distributions 	IOTrackingQueue *      queue;
274*bb611c8fSApple OSS Distributions 	IOTracking *           addresses;
275*bb611c8fSApple OSS Distributions 	size_t        size[2];
2760f3703acSApple OSS Distributions 	uint32_t               crc;
277*bb611c8fSApple OSS Distributions 	uint32_t      count;
27888cc0b97SApple OSS Distributions 
27976e12aa3SApple OSS Distributions 	vm_tag_t      tag;
280*bb611c8fSApple OSS Distributions 	uint8_t       user32;
281*bb611c8fSApple OSS Distributions 	uint8_t       userCount;
282*bb611c8fSApple OSS Distributions 	pid_t         btPID;
28388cc0b97SApple OSS Distributions 
284*bb611c8fSApple OSS Distributions 	uintptr_t     bt[kIOTrackingCallSiteBTs];
285*bb611c8fSApple OSS Distributions 	IOTrackingCallSiteUser     user[0];
2860f3703acSApple OSS Distributions };
2870f3703acSApple OSS Distributions 
288*bb611c8fSApple OSS Distributions 
289a5e72196SApple OSS Distributions struct IOTrackingLeaksRef {
2900f3703acSApple OSS Distributions 	uintptr_t * instances;
29188cc0b97SApple OSS Distributions 	uint32_t    zoneSize;
2920f3703acSApple OSS Distributions 	uint32_t    count;
2930f3703acSApple OSS Distributions 	uint32_t    found;
29476e12aa3SApple OSS Distributions 	uint32_t    foundzlen;
2950f3703acSApple OSS Distributions 	size_t      bytes;
2960f3703acSApple OSS Distributions };
2970f3703acSApple OSS Distributions 
2980f3703acSApple OSS Distributions lck_mtx_t *  gIOTrackingLock;
2990f3703acSApple OSS Distributions queue_head_t gIOTrackingQ;
3000f3703acSApple OSS Distributions 
301a5e72196SApple OSS Distributions enum{
3020f3703acSApple OSS Distributions 	kTrackingAddressFlagAllocated    = 0x00000001
3030f3703acSApple OSS Distributions };
3040f3703acSApple OSS Distributions 
3050f3703acSApple OSS Distributions #if defined(__LP64__)
3060f3703acSApple OSS Distributions #define IOTrackingAddressFlags(ptr)     (ptr->flags)
3070f3703acSApple OSS Distributions #else
3080f3703acSApple OSS Distributions #define IOTrackingAddressFlags(ptr)     (ptr->tracking.flags)
3090f3703acSApple OSS Distributions #endif
3100f3703acSApple OSS Distributions 
3110f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3120f3703acSApple OSS Distributions 
3130f3703acSApple OSS Distributions static void
3140f3703acSApple OSS Distributions IOTRecursiveLockLock(IOTRecursiveLock * lock)
3150f3703acSApple OSS Distributions {
316a5e72196SApple OSS Distributions 	if (lock->thread == current_thread()) {
317a5e72196SApple OSS Distributions 		lock->count++;
318a5e72196SApple OSS Distributions 	} else {
3190f3703acSApple OSS Distributions 		lck_mtx_lock(lock->mutex);
320a5e72196SApple OSS Distributions 		assert(lock->thread == NULL);
3210f3703acSApple OSS Distributions 		assert(lock->count == 0);
3220f3703acSApple OSS Distributions 		lock->thread = current_thread();
3230f3703acSApple OSS Distributions 		lock->count = 1;
3240f3703acSApple OSS Distributions 	}
3250f3703acSApple OSS Distributions }
3260f3703acSApple OSS Distributions 
3270f3703acSApple OSS Distributions static void
3280f3703acSApple OSS Distributions IOTRecursiveLockUnlock(IOTRecursiveLock * lock)
3290f3703acSApple OSS Distributions {
3300f3703acSApple OSS Distributions 	assert(lock->thread == current_thread());
331a5e72196SApple OSS Distributions 	if (0 == (--lock->count)) {
332a5e72196SApple OSS Distributions 		lock->thread = NULL;
3330f3703acSApple OSS Distributions 		lck_mtx_unlock(lock->mutex);
3340f3703acSApple OSS Distributions 	}
3350f3703acSApple OSS Distributions }
3360f3703acSApple OSS Distributions 
3370f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3380f3703acSApple OSS Distributions 
3390f3703acSApple OSS Distributions void
3400f3703acSApple OSS Distributions IOTrackingInit(void)
3410f3703acSApple OSS Distributions {
3420f3703acSApple OSS Distributions 	queue_init(&gIOTrackingQ);
3430f3703acSApple OSS Distributions 	gIOTrackingLock = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
3440f3703acSApple OSS Distributions }
3450f3703acSApple OSS Distributions 
3460f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3470f3703acSApple OSS Distributions 
3480f3703acSApple OSS Distributions IOTrackingQueue *
34988cc0b97SApple OSS Distributions IOTrackingQueueAlloc(const char * name, uintptr_t btEntry,
35088cc0b97SApple OSS Distributions     size_t allocSize, size_t minCaptureSize,
35188cc0b97SApple OSS Distributions     uint32_t type, uint32_t numSiteQs)
3520f3703acSApple OSS Distributions {
3530f3703acSApple OSS Distributions 	IOTrackingQueue * queue;
35488cc0b97SApple OSS Distributions 	uint32_t          idx;
35588cc0b97SApple OSS Distributions 
356a5e72196SApple OSS Distributions 	if (!numSiteQs) {
357a5e72196SApple OSS Distributions 		numSiteQs = 1;
358a5e72196SApple OSS Distributions 	}
35988cc0b97SApple OSS Distributions 	queue = (typeof(queue))kalloc(sizeof(IOTrackingQueue) + numSiteQs * sizeof(queue->sites[0]));
3600f3703acSApple OSS Distributions 	bzero(queue, sizeof(IOTrackingQueue));
3610f3703acSApple OSS Distributions 
3620f3703acSApple OSS Distributions 	queue->name           = name;
36388cc0b97SApple OSS Distributions 	queue->btEntry        = btEntry;
3640f3703acSApple OSS Distributions 	queue->allocSize      = allocSize;
3650f3703acSApple OSS Distributions 	queue->minCaptureSize = minCaptureSize;
3660f3703acSApple OSS Distributions 	queue->lock.mutex     = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
36788cc0b97SApple OSS Distributions 	queue->numSiteQs      = numSiteQs;
36888cc0b97SApple OSS Distributions 	queue->type           = type;
36988cc0b97SApple OSS Distributions 	enum { kFlags = (kIOTracking | kIOTrackingBoot) };
37088cc0b97SApple OSS Distributions 	queue->captureOn = (kFlags == (kFlags & gIOKitDebug))
37188cc0b97SApple OSS Distributions 	    || (kIOTrackingQueueTypeDefaultOn & type);
3720f3703acSApple OSS Distributions 
373a5e72196SApple OSS Distributions 	for (idx = 0; idx < numSiteQs; idx++) {
374a5e72196SApple OSS Distributions 		queue_init(&queue->sites[idx]);
375a5e72196SApple OSS Distributions 	}
3760f3703acSApple OSS Distributions 
3770f3703acSApple OSS Distributions 	lck_mtx_lock(gIOTrackingLock);
3780f3703acSApple OSS Distributions 	queue_enter(&gIOTrackingQ, queue, IOTrackingQueue *, link);
3790f3703acSApple OSS Distributions 	lck_mtx_unlock(gIOTrackingLock);
3800f3703acSApple OSS Distributions 
381a5e72196SApple OSS Distributions 	return queue;
3820f3703acSApple OSS Distributions };
3830f3703acSApple OSS Distributions 
384*bb611c8fSApple OSS Distributions void
385*bb611c8fSApple OSS Distributions IOTrackingQueueCollectUser(IOTrackingQueue * queue)
386*bb611c8fSApple OSS Distributions {
387*bb611c8fSApple OSS Distributions 	assert(0 == queue->siteCount);
388*bb611c8fSApple OSS Distributions 	queue->type |= kIOTrackingQueueTypeUser;
389*bb611c8fSApple OSS Distributions }
390*bb611c8fSApple OSS Distributions 
3910f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3920f3703acSApple OSS Distributions 
3930f3703acSApple OSS Distributions void
3940f3703acSApple OSS Distributions IOTrackingQueueFree(IOTrackingQueue * queue)
3950f3703acSApple OSS Distributions {
3960f3703acSApple OSS Distributions 	lck_mtx_lock(gIOTrackingLock);
3970f3703acSApple OSS Distributions 	IOTrackingReset(queue);
3980f3703acSApple OSS Distributions 	remque(&queue->link);
3990f3703acSApple OSS Distributions 	lck_mtx_unlock(gIOTrackingLock);
4000f3703acSApple OSS Distributions 
4010f3703acSApple OSS Distributions 	lck_mtx_free(queue->lock.mutex, IOLockGroup);
4020f3703acSApple OSS Distributions 
40388cc0b97SApple OSS Distributions 	kfree(queue, sizeof(IOTrackingQueue) + queue->numSiteQs * sizeof(queue->sites[0]));
4040f3703acSApple OSS Distributions };
4050f3703acSApple OSS Distributions 
4060f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4070f3703acSApple OSS Distributions 
4080f3703acSApple OSS Distributions /* fasthash
409a5e72196SApple OSS Distributions  *  The MIT License
410a5e72196SApple OSS Distributions  *
411a5e72196SApple OSS Distributions  *  Copyright (C) 2012 Zilong Tan ([email protected])
412a5e72196SApple OSS Distributions  *
413a5e72196SApple OSS Distributions  *  Permission is hereby granted, free of charge, to any person
414a5e72196SApple OSS Distributions  *  obtaining a copy of this software and associated documentation
415a5e72196SApple OSS Distributions  *  files (the "Software"), to deal in the Software without
416a5e72196SApple OSS Distributions  *  restriction, including without limitation the rights to use, copy,
417a5e72196SApple OSS Distributions  *  modify, merge, publish, distribute, sublicense, and/or sell copies
418a5e72196SApple OSS Distributions  *  of the Software, and to permit persons to whom the Software is
419a5e72196SApple OSS Distributions  *  furnished to do so, subject to the following conditions:
420a5e72196SApple OSS Distributions  *
421a5e72196SApple OSS Distributions  *  The above copyright notice and this permission notice shall be
422a5e72196SApple OSS Distributions  *  included in all copies or substantial portions of the Software.
423a5e72196SApple OSS Distributions  *
424a5e72196SApple OSS Distributions  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
425a5e72196SApple OSS Distributions  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
426a5e72196SApple OSS Distributions  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
427a5e72196SApple OSS Distributions  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
428a5e72196SApple OSS Distributions  *  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
429a5e72196SApple OSS Distributions  *  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
430a5e72196SApple OSS Distributions  *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
431a5e72196SApple OSS Distributions  *  SOFTWARE.
4320f3703acSApple OSS Distributions  */
4330f3703acSApple OSS Distributions 
4340f3703acSApple OSS Distributions 
4350f3703acSApple OSS Distributions // Compression function for Merkle-Damgard construction.
4360f3703acSApple OSS Distributions // This function is generated using the framework provided.
4370f3703acSApple OSS Distributions #define mix(h) ({                               \
4380f3703acSApple OSS Distributions 	          (h) ^= (h) >> 23;             \
4390f3703acSApple OSS Distributions 	          (h) *= 0x2127599bf4325c37ULL; \
4400f3703acSApple OSS Distributions 	          (h) ^= (h) >> 47; })
4410f3703acSApple OSS Distributions 
4420f3703acSApple OSS Distributions static uint64_t
4430f3703acSApple OSS Distributions fasthash64(const void *buf, size_t len, uint64_t seed)
4440f3703acSApple OSS Distributions {
4450f3703acSApple OSS Distributions 	const uint64_t    m = 0x880355f21e6d1965ULL;
4460f3703acSApple OSS Distributions 	const uint64_t *pos = (const uint64_t *)buf;
4470f3703acSApple OSS Distributions 	const uint64_t *end = pos + (len / 8);
4480f3703acSApple OSS Distributions 	const unsigned char *pos2;
4490f3703acSApple OSS Distributions 	uint64_t h = seed ^ (len * m);
4500f3703acSApple OSS Distributions 	uint64_t v;
4510f3703acSApple OSS Distributions 
4520f3703acSApple OSS Distributions 	while (pos != end) {
4530f3703acSApple OSS Distributions 		v  = *pos++;
4540f3703acSApple OSS Distributions 		h ^= mix(v);
4550f3703acSApple OSS Distributions 		h *= m;
4560f3703acSApple OSS Distributions 	}
4570f3703acSApple OSS Distributions 
4580f3703acSApple OSS Distributions 	pos2 = (const unsigned char*)pos;
4590f3703acSApple OSS Distributions 	v = 0;
4600f3703acSApple OSS Distributions 
4610f3703acSApple OSS Distributions 	switch (len & 7) {
4620f3703acSApple OSS Distributions 	case 7: v ^= (uint64_t)pos2[6] << 48;
46388cc0b97SApple OSS Distributions 		[[clang::fallthrough]];
4640f3703acSApple OSS Distributions 	case 6: v ^= (uint64_t)pos2[5] << 40;
46588cc0b97SApple OSS Distributions 		[[clang::fallthrough]];
4660f3703acSApple OSS Distributions 	case 5: v ^= (uint64_t)pos2[4] << 32;
46788cc0b97SApple OSS Distributions 		[[clang::fallthrough]];
4680f3703acSApple OSS Distributions 	case 4: v ^= (uint64_t)pos2[3] << 24;
46988cc0b97SApple OSS Distributions 		[[clang::fallthrough]];
4700f3703acSApple OSS Distributions 	case 3: v ^= (uint64_t)pos2[2] << 16;
47188cc0b97SApple OSS Distributions 		[[clang::fallthrough]];
4720f3703acSApple OSS Distributions 	case 2: v ^= (uint64_t)pos2[1] << 8;
47388cc0b97SApple OSS Distributions 		[[clang::fallthrough]];
4740f3703acSApple OSS Distributions 	case 1: v ^= (uint64_t)pos2[0];
4750f3703acSApple OSS Distributions 		h ^= mix(v);
4760f3703acSApple OSS Distributions 		h *= m;
4770f3703acSApple OSS Distributions 	}
4780f3703acSApple OSS Distributions 
4790f3703acSApple OSS Distributions 	return mix(h);
4800f3703acSApple OSS Distributions }
4810f3703acSApple OSS Distributions 
4820f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4830f3703acSApple OSS Distributions 
4840f3703acSApple OSS Distributions static uint32_t
4850f3703acSApple OSS Distributions fasthash32(const void *buf, size_t len, uint32_t seed)
4860f3703acSApple OSS Distributions {
4870f3703acSApple OSS Distributions 	// the following trick converts the 64-bit hashcode to Fermat
4880f3703acSApple OSS Distributions 	// residue, which shall retain information from both the higher
4890f3703acSApple OSS Distributions 	// and lower parts of hashcode.
4900f3703acSApple OSS Distributions 	uint64_t h = fasthash64(buf, len, seed);
491*bb611c8fSApple OSS Distributions 	return (uint32_t) (h - (h >> 32));
4920f3703acSApple OSS Distributions }
4930f3703acSApple OSS Distributions 
4940f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4950f3703acSApple OSS Distributions 
4960f3703acSApple OSS Distributions void
49788cc0b97SApple OSS Distributions IOTrackingAddUser(IOTrackingQueue * queue, IOTrackingUser * mem, vm_size_t size)
49888cc0b97SApple OSS Distributions {
49988cc0b97SApple OSS Distributions 	uint32_t num;
500*bb611c8fSApple OSS Distributions 	int pid;
50188cc0b97SApple OSS Distributions 
502a5e72196SApple OSS Distributions 	if (!queue->captureOn) {
503a5e72196SApple OSS Distributions 		return;
504a5e72196SApple OSS Distributions 	}
505a5e72196SApple OSS Distributions 	if (size < queue->minCaptureSize) {
506a5e72196SApple OSS Distributions 		return;
507a5e72196SApple OSS Distributions 	}
50888cc0b97SApple OSS Distributions 
50988cc0b97SApple OSS Distributions 	assert(!mem->link.next);
51088cc0b97SApple OSS Distributions 
511a5e72196SApple OSS Distributions 	num = backtrace(&mem->bt[0], kIOTrackingCallSiteBTs, NULL);
51288cc0b97SApple OSS Distributions 	num = 0;
513*bb611c8fSApple OSS Distributions 	if ((kernel_task != current_task()) && (pid = proc_selfpid())) {
514a5e72196SApple OSS Distributions 		bool user_64 = false;
515*bb611c8fSApple OSS Distributions 		mem->btPID  = pid;
516*bb611c8fSApple OSS Distributions 		num = backtrace_user(&mem->btUser[0], kIOTrackingCallSiteBTs - 1, NULL,
517a5e72196SApple OSS Distributions 		    &user_64, NULL);
51888cc0b97SApple OSS Distributions 		mem->user32 = !user_64;
51988cc0b97SApple OSS Distributions 	}
52088cc0b97SApple OSS Distributions 	assert(num <= kIOTrackingCallSiteBTs);
521*bb611c8fSApple OSS Distributions 	static_assert(kIOTrackingCallSiteBTs <= UINT8_MAX);
522*bb611c8fSApple OSS Distributions 	mem->userCount = ((uint8_t) num);
52388cc0b97SApple OSS Distributions 
52488cc0b97SApple OSS Distributions 	IOTRecursiveLockLock(&queue->lock);
52588cc0b97SApple OSS Distributions 	queue_enter/*last*/ (&queue->sites[0], mem, IOTrackingUser *, link);
52688cc0b97SApple OSS Distributions 	queue->siteCount++;
52788cc0b97SApple OSS Distributions 	IOTRecursiveLockUnlock(&queue->lock);
52888cc0b97SApple OSS Distributions }
52988cc0b97SApple OSS Distributions 
53088cc0b97SApple OSS Distributions void
53188cc0b97SApple OSS Distributions IOTrackingRemoveUser(IOTrackingQueue * queue, IOTrackingUser * mem)
53288cc0b97SApple OSS Distributions {
533a5e72196SApple OSS Distributions 	if (!mem->link.next) {
534a5e72196SApple OSS Distributions 		return;
535a5e72196SApple OSS Distributions 	}
53688cc0b97SApple OSS Distributions 
53788cc0b97SApple OSS Distributions 	IOTRecursiveLockLock(&queue->lock);
538a5e72196SApple OSS Distributions 	if (mem->link.next) {
53988cc0b97SApple OSS Distributions 		remque(&mem->link);
54088cc0b97SApple OSS Distributions 		assert(queue->siteCount);
54188cc0b97SApple OSS Distributions 		queue->siteCount--;
54288cc0b97SApple OSS Distributions 	}
54388cc0b97SApple OSS Distributions 	IOTRecursiveLockUnlock(&queue->lock);
54488cc0b97SApple OSS Distributions }
54588cc0b97SApple OSS Distributions 
54688cc0b97SApple OSS Distributions uint64_t gIOTrackingAddTime;
54788cc0b97SApple OSS Distributions 
54888cc0b97SApple OSS Distributions void
54976e12aa3SApple OSS Distributions IOTrackingAdd(IOTrackingQueue * queue, IOTracking * mem, size_t size, bool address, vm_tag_t tag)
5500f3703acSApple OSS Distributions {
5510f3703acSApple OSS Distributions 	IOTrackingCallSite * site;
5520f3703acSApple OSS Distributions 	uint32_t             crc, num;
5530f3703acSApple OSS Distributions 	uintptr_t            bt[kIOTrackingCallSiteBTs + 1];
554*bb611c8fSApple OSS Distributions 	uintptr_t            btUser[kIOTrackingCallSiteBTs];
55588cc0b97SApple OSS Distributions 	queue_head_t       * que;
556*bb611c8fSApple OSS Distributions 	bool                 user;
557*bb611c8fSApple OSS Distributions 	int                  pid;
558*bb611c8fSApple OSS Distributions 	int                  userCount;
559*bb611c8fSApple OSS Distributions 	bool                 user64;
5600f3703acSApple OSS Distributions 
561a5e72196SApple OSS Distributions 	if (mem->site) {
562a5e72196SApple OSS Distributions 		return;
563a5e72196SApple OSS Distributions 	}
564a5e72196SApple OSS Distributions 	if (!queue->captureOn) {
565a5e72196SApple OSS Distributions 		return;
566a5e72196SApple OSS Distributions 	}
567a5e72196SApple OSS Distributions 	if (size < queue->minCaptureSize) {
568a5e72196SApple OSS Distributions 		return;
569a5e72196SApple OSS Distributions 	}
5700f3703acSApple OSS Distributions 
571*bb611c8fSApple OSS Distributions 	user = (0 != (kIOTrackingQueueTypeUser & queue->type));
572*bb611c8fSApple OSS Distributions 
5730f3703acSApple OSS Distributions 	assert(!mem->link.next);
5740f3703acSApple OSS Distributions 
575a5e72196SApple OSS Distributions 	num  = backtrace(&bt[0], kIOTrackingCallSiteBTs + 1, NULL);
576a5e72196SApple OSS Distributions 	if (!num) {
577a5e72196SApple OSS Distributions 		return;
578a5e72196SApple OSS Distributions 	}
5790f3703acSApple OSS Distributions 	num--;
5800f3703acSApple OSS Distributions 	crc = fasthash32(&bt[1], num * sizeof(bt[0]), 0x04C11DB7);
5810f3703acSApple OSS Distributions 
582*bb611c8fSApple OSS Distributions 	userCount = 0;
583*bb611c8fSApple OSS Distributions 	user64 = false;
584*bb611c8fSApple OSS Distributions 	pid = 0;
585*bb611c8fSApple OSS Distributions 	if (user) {
586*bb611c8fSApple OSS Distributions 		if ((kernel_task != current_task()) && (pid = proc_selfpid())) {
587*bb611c8fSApple OSS Distributions 			userCount = backtrace_user(&btUser[0], kIOTrackingCallSiteBTs, NULL, &user64, NULL);
588*bb611c8fSApple OSS Distributions 			assert(userCount <= kIOTrackingCallSiteBTs);
589*bb611c8fSApple OSS Distributions 			crc = fasthash32(&btUser[0], userCount * sizeof(bt[0]), crc);
590*bb611c8fSApple OSS Distributions 		}
591*bb611c8fSApple OSS Distributions 	}
592*bb611c8fSApple OSS Distributions 
5930f3703acSApple OSS Distributions 	IOTRecursiveLockLock(&queue->lock);
59488cc0b97SApple OSS Distributions 	que = &queue->sites[crc % queue->numSiteQs];
59588cc0b97SApple OSS Distributions 	queue_iterate(que, site, IOTrackingCallSite *, link)
5960f3703acSApple OSS Distributions 	{
597a5e72196SApple OSS Distributions 		if (tag != site->tag) {
598a5e72196SApple OSS Distributions 			continue;
599a5e72196SApple OSS Distributions 		}
600*bb611c8fSApple OSS Distributions 		if (user && (pid != site->user[0].pid)) {
601*bb611c8fSApple OSS Distributions 			continue;
602*bb611c8fSApple OSS Distributions 		}
603a5e72196SApple OSS Distributions 		if (crc == site->crc) {
604a5e72196SApple OSS Distributions 			break;
605a5e72196SApple OSS Distributions 		}
6060f3703acSApple OSS Distributions 	}
6070f3703acSApple OSS Distributions 
608a5e72196SApple OSS Distributions 	if (queue_end(que, (queue_entry_t) site)) {
609*bb611c8fSApple OSS Distributions 		size_t siteSize = sizeof(IOTrackingCallSite);
610*bb611c8fSApple OSS Distributions 		if (user) {
611*bb611c8fSApple OSS Distributions 			siteSize += sizeof(IOTrackingCallSiteUser);
612*bb611c8fSApple OSS Distributions 		}
613*bb611c8fSApple OSS Distributions 		site = (typeof(site))kalloc(siteSize);
6140f3703acSApple OSS Distributions 
6150f3703acSApple OSS Distributions 		queue_init(&site->instances);
6160f3703acSApple OSS Distributions 		site->addresses  = (IOTracking *) &site->instances;
6170f3703acSApple OSS Distributions 		site->queue      = queue;
6180f3703acSApple OSS Distributions 		site->crc        = crc;
61988cc0b97SApple OSS Distributions 		site->count      = 0;
62076e12aa3SApple OSS Distributions 		site->tag        = tag;
62188cc0b97SApple OSS Distributions 		memset(&site->size[0], 0, sizeof(site->size));
62288cc0b97SApple OSS Distributions 		bcopy(&bt[1], &site->bt[0], num * sizeof(site->bt[0]));
6230f3703acSApple OSS Distributions 		assert(num <= kIOTrackingCallSiteBTs);
62488cc0b97SApple OSS Distributions 		bzero(&site->bt[num], (kIOTrackingCallSiteBTs - num) * sizeof(site->bt[0]));
625*bb611c8fSApple OSS Distributions 		if (user) {
626*bb611c8fSApple OSS Distributions 			bcopy(&btUser[0], &site->user[0].bt[0], userCount * sizeof(site->user[0].bt[0]));
627*bb611c8fSApple OSS Distributions 			assert(userCount <= kIOTrackingCallSiteBTs);
628*bb611c8fSApple OSS Distributions 			bzero(&site->user[0].bt[userCount], (kIOTrackingCallSiteBTs - userCount) * sizeof(site->user[0].bt[0]));
629*bb611c8fSApple OSS Distributions 			site->user[0].pid  = pid;
630*bb611c8fSApple OSS Distributions 			site->user[0].user32 = !user64;
631*bb611c8fSApple OSS Distributions 			static_assert(kIOTrackingCallSiteBTs <= UINT8_MAX);
632*bb611c8fSApple OSS Distributions 			site->user[0].userCount = ((uint8_t) userCount);
633*bb611c8fSApple OSS Distributions 		}
63488cc0b97SApple OSS Distributions 		queue_enter_first(que, site, IOTrackingCallSite *, link);
6350f3703acSApple OSS Distributions 		queue->siteCount++;
6360f3703acSApple OSS Distributions 	}
6370f3703acSApple OSS Distributions 
638a5e72196SApple OSS Distributions 	if (address) {
63988cc0b97SApple OSS Distributions 		queue_enter/*last*/ (&site->instances, mem, IOTracking *, link);
640a5e72196SApple OSS Distributions 		if (queue_end(&site->instances, (queue_entry_t)site->addresses)) {
641a5e72196SApple OSS Distributions 			site->addresses = mem;
6420f3703acSApple OSS Distributions 		}
643a5e72196SApple OSS Distributions 	} else {
644a5e72196SApple OSS Distributions 		queue_enter_first(&site->instances, mem, IOTracking *, link);
645a5e72196SApple OSS Distributions 	}
6460f3703acSApple OSS Distributions 
6470f3703acSApple OSS Distributions 	mem->site      = site;
64888cc0b97SApple OSS Distributions 	site->size[0] += size;
64988cc0b97SApple OSS Distributions 	site->count++;
6500f3703acSApple OSS Distributions 
6510f3703acSApple OSS Distributions 	IOTRecursiveLockUnlock(&queue->lock);
6520f3703acSApple OSS Distributions }
6530f3703acSApple OSS Distributions 
6540f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6550f3703acSApple OSS Distributions 
6560f3703acSApple OSS Distributions void
6570f3703acSApple OSS Distributions IOTrackingRemove(IOTrackingQueue * queue, IOTracking * mem, size_t size)
6580f3703acSApple OSS Distributions {
659a5e72196SApple OSS Distributions 	if (!mem->link.next) {
660a5e72196SApple OSS Distributions 		return;
661a5e72196SApple OSS Distributions 	}
6620f3703acSApple OSS Distributions 
6630f3703acSApple OSS Distributions 	IOTRecursiveLockLock(&queue->lock);
664a5e72196SApple OSS Distributions 	if (mem->link.next) {
6650f3703acSApple OSS Distributions 		assert(mem->site);
6660f3703acSApple OSS Distributions 
667a5e72196SApple OSS Distributions 		if (mem == mem->site->addresses) {
668a5e72196SApple OSS Distributions 			mem->site->addresses = (IOTracking *) queue_next(&mem->link);
669a5e72196SApple OSS Distributions 		}
6700f3703acSApple OSS Distributions 		remque(&mem->link);
6710f3703acSApple OSS Distributions 
67288cc0b97SApple OSS Distributions 		assert(mem->site->count);
67388cc0b97SApple OSS Distributions 		mem->site->count--;
67488cc0b97SApple OSS Distributions 		assert(mem->site->size[0] >= size);
67588cc0b97SApple OSS Distributions 		mem->site->size[0] -= size;
676a5e72196SApple OSS Distributions 		if (!mem->site->count) {
6770f3703acSApple OSS Distributions 			assert(queue_empty(&mem->site->instances));
67888cc0b97SApple OSS Distributions 			assert(!mem->site->size[0]);
67988cc0b97SApple OSS Distributions 			assert(!mem->site->size[1]);
6800f3703acSApple OSS Distributions 
6810f3703acSApple OSS Distributions 			remque(&mem->site->link);
6820f3703acSApple OSS Distributions 			assert(queue->siteCount);
6830f3703acSApple OSS Distributions 			queue->siteCount--;
684*bb611c8fSApple OSS Distributions 			size_t siteSize = sizeof(IOTrackingCallSite);
685*bb611c8fSApple OSS Distributions 			if (kIOTrackingQueueTypeUser & queue->type) {
686*bb611c8fSApple OSS Distributions 				siteSize += sizeof(IOTrackingCallSiteUser);
687*bb611c8fSApple OSS Distributions 			}
688*bb611c8fSApple OSS Distributions 			kfree(mem->site, siteSize);
6890f3703acSApple OSS Distributions 		}
69076e12aa3SApple OSS Distributions 		mem->site = NULL;
69188cc0b97SApple OSS Distributions 	}
6920f3703acSApple OSS Distributions 	IOTRecursiveLockUnlock(&queue->lock);
6930f3703acSApple OSS Distributions }
6940f3703acSApple OSS Distributions 
6950f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
6960f3703acSApple OSS Distributions 
6970f3703acSApple OSS Distributions void
6980f3703acSApple OSS Distributions IOTrackingAlloc(IOTrackingQueue * queue, uintptr_t address, size_t size)
6990f3703acSApple OSS Distributions {
7000f3703acSApple OSS Distributions 	IOTrackingAddress * tracking;
7010f3703acSApple OSS Distributions 
702a5e72196SApple OSS Distributions 	if (!queue->captureOn) {
703a5e72196SApple OSS Distributions 		return;
704a5e72196SApple OSS Distributions 	}
705a5e72196SApple OSS Distributions 	if (size < queue->minCaptureSize) {
706a5e72196SApple OSS Distributions 		return;
707a5e72196SApple OSS Distributions 	}
7080f3703acSApple OSS Distributions 
7090f3703acSApple OSS Distributions 	address = ~address;
7100f3703acSApple OSS Distributions 	tracking = (typeof(tracking))kalloc(sizeof(IOTrackingAddress));
7110f3703acSApple OSS Distributions 	bzero(tracking, sizeof(IOTrackingAddress));
7120f3703acSApple OSS Distributions 	IOTrackingAddressFlags(tracking) |= kTrackingAddressFlagAllocated;
7130f3703acSApple OSS Distributions 	tracking->address = address;
7140f3703acSApple OSS Distributions 	tracking->size    = size;
7150f3703acSApple OSS Distributions 
71676e12aa3SApple OSS Distributions 	IOTrackingAdd(queue, &tracking->tracking, size, true, VM_KERN_MEMORY_NONE);
7170f3703acSApple OSS Distributions }
7180f3703acSApple OSS Distributions 
7190f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7200f3703acSApple OSS Distributions 
7210f3703acSApple OSS Distributions void
7220f3703acSApple OSS Distributions IOTrackingFree(IOTrackingQueue * queue, uintptr_t address, size_t size)
7230f3703acSApple OSS Distributions {
7240f3703acSApple OSS Distributions 	IOTrackingCallSite * site;
7250f3703acSApple OSS Distributions 	IOTrackingAddress  * tracking;
72688cc0b97SApple OSS Distributions 	uint32_t             idx;
7270f3703acSApple OSS Distributions 	bool                 done;
7280f3703acSApple OSS Distributions 
7290f3703acSApple OSS Distributions 	address = ~address;
7300f3703acSApple OSS Distributions 	IOTRecursiveLockLock(&queue->lock);
7310f3703acSApple OSS Distributions 	done = false;
732a5e72196SApple OSS Distributions 	for (idx = 0; idx < queue->numSiteQs; idx++) {
73388cc0b97SApple OSS Distributions 		queue_iterate(&queue->sites[idx], site, IOTrackingCallSite *, link)
7340f3703acSApple OSS Distributions 		{
735a5e72196SApple OSS Distributions 			tracking = (IOTrackingAddress *) site->addresses;
736a5e72196SApple OSS Distributions 			while (!queue_end(&site->instances, &tracking->tracking.link)) {
737a5e72196SApple OSS Distributions 				if ((done = (address == tracking->address))) {
7380f3703acSApple OSS Distributions 					IOTrackingRemove(queue, &tracking->tracking, size);
7390f3703acSApple OSS Distributions 					kfree(tracking, sizeof(IOTrackingAddress));
740a5e72196SApple OSS Distributions 					break;
741a5e72196SApple OSS Distributions 				} else {
742a5e72196SApple OSS Distributions 					tracking = (IOTrackingAddress *) queue_next(&tracking->tracking.link);
7430f3703acSApple OSS Distributions 				}
7440f3703acSApple OSS Distributions 			}
745a5e72196SApple OSS Distributions 			if (done) {
746a5e72196SApple OSS Distributions 				break;
7470f3703acSApple OSS Distributions 			}
748a5e72196SApple OSS Distributions 		}
749a5e72196SApple OSS Distributions 		if (done) {
750a5e72196SApple OSS Distributions 			break;
751a5e72196SApple OSS Distributions 		}
75288cc0b97SApple OSS Distributions 	}
7530f3703acSApple OSS Distributions 	IOTRecursiveLockUnlock(&queue->lock);
7540f3703acSApple OSS Distributions }
7550f3703acSApple OSS Distributions 
7560f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7570f3703acSApple OSS Distributions 
7580f3703acSApple OSS Distributions void
7590f3703acSApple OSS Distributions IOTrackingAccumSize(IOTrackingQueue * queue, IOTracking * mem, size_t size)
7600f3703acSApple OSS Distributions {
7610f3703acSApple OSS Distributions 	IOTRecursiveLockLock(&queue->lock);
762a5e72196SApple OSS Distributions 	if (mem->link.next) {
7630f3703acSApple OSS Distributions 		assert(mem->site);
76488cc0b97SApple OSS Distributions 		assert((size > 0) || (mem->site->size[1] >= -size));
76588cc0b97SApple OSS Distributions 		mem->site->size[1] += size;
766a5e72196SApple OSS Distributions 	}
767a5e72196SApple OSS Distributions 	;
7680f3703acSApple OSS Distributions 	IOTRecursiveLockUnlock(&queue->lock);
7690f3703acSApple OSS Distributions }
7700f3703acSApple OSS Distributions 
7710f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7720f3703acSApple OSS Distributions 
7730f3703acSApple OSS Distributions void
7740f3703acSApple OSS Distributions IOTrackingReset(IOTrackingQueue * queue)
7750f3703acSApple OSS Distributions {
7760f3703acSApple OSS Distributions 	IOTrackingCallSite * site;
77788cc0b97SApple OSS Distributions 	IOTrackingUser     * user;
7780f3703acSApple OSS Distributions 	IOTracking         * tracking;
7790f3703acSApple OSS Distributions 	IOTrackingAddress  * trackingAddress;
78088cc0b97SApple OSS Distributions 	uint32_t             idx;
7810f3703acSApple OSS Distributions 	bool                 addresses;
7820f3703acSApple OSS Distributions 
7830f3703acSApple OSS Distributions 	IOTRecursiveLockLock(&queue->lock);
784a5e72196SApple OSS Distributions 	for (idx = 0; idx < queue->numSiteQs; idx++) {
785a5e72196SApple OSS Distributions 		while (!queue_empty(&queue->sites[idx])) {
786a5e72196SApple OSS Distributions 			if (kIOTrackingQueueTypeMap & queue->type) {
78788cc0b97SApple OSS Distributions 				queue_remove_first(&queue->sites[idx], user, IOTrackingUser *, link);
78888cc0b97SApple OSS Distributions 				user->link.next = user->link.prev = NULL;
789a5e72196SApple OSS Distributions 			} else {
79088cc0b97SApple OSS Distributions 				queue_remove_first(&queue->sites[idx], site, IOTrackingCallSite *, link);
7910f3703acSApple OSS Distributions 				addresses = false;
792a5e72196SApple OSS Distributions 				while (!queue_empty(&site->instances)) {
7930f3703acSApple OSS Distributions 					queue_remove_first(&site->instances, tracking, IOTracking *, link);
794a5e72196SApple OSS Distributions 					if (tracking == site->addresses) {
795a5e72196SApple OSS Distributions 						addresses = true;
796a5e72196SApple OSS Distributions 					}
797a5e72196SApple OSS Distributions 					if (addresses) {
7980f3703acSApple OSS Distributions 						trackingAddress = (typeof(trackingAddress))tracking;
799a5e72196SApple OSS Distributions 						if (kTrackingAddressFlagAllocated & IOTrackingAddressFlags(trackingAddress)) {
8000f3703acSApple OSS Distributions 							kfree(tracking, sizeof(IOTrackingAddress));
8010f3703acSApple OSS Distributions 						}
8020f3703acSApple OSS Distributions 					}
8030f3703acSApple OSS Distributions 				}
804*bb611c8fSApple OSS Distributions 				size_t siteSize = sizeof(IOTrackingCallSite);
805*bb611c8fSApple OSS Distributions 				if (kIOTrackingQueueTypeUser & queue->type) {
806*bb611c8fSApple OSS Distributions 					siteSize += sizeof(IOTrackingCallSiteUser);
807*bb611c8fSApple OSS Distributions 				}
808*bb611c8fSApple OSS Distributions 				kfree(site, siteSize);
8090f3703acSApple OSS Distributions 			}
81088cc0b97SApple OSS Distributions 		}
81188cc0b97SApple OSS Distributions 	}
8120f3703acSApple OSS Distributions 	queue->siteCount = 0;
8130f3703acSApple OSS Distributions 	IOTRecursiveLockUnlock(&queue->lock);
8140f3703acSApple OSS Distributions }
8150f3703acSApple OSS Distributions 
8160f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8170f3703acSApple OSS Distributions 
8180f3703acSApple OSS Distributions static int
8190f3703acSApple OSS Distributions IOTrackingCallSiteInfoCompare(const void * left, const void * right)
8200f3703acSApple OSS Distributions {
8210f3703acSApple OSS Distributions 	IOTrackingCallSiteInfo * l = (typeof(l))left;
8220f3703acSApple OSS Distributions 	IOTrackingCallSiteInfo * r = (typeof(r))right;
8230f3703acSApple OSS Distributions 	size_t                   lsize, rsize;
8240f3703acSApple OSS Distributions 
8250f3703acSApple OSS Distributions 	rsize = r->size[0] + r->size[1];
8260f3703acSApple OSS Distributions 	lsize = l->size[0] + l->size[1];
8270f3703acSApple OSS Distributions 
828a5e72196SApple OSS Distributions 	return (rsize > lsize) ? 1 : ((rsize == lsize) ? 0 : -1);
8290f3703acSApple OSS Distributions }
8300f3703acSApple OSS Distributions 
8310f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8320f3703acSApple OSS Distributions 
8330f3703acSApple OSS Distributions static int
8340f3703acSApple OSS Distributions IOTrackingAddressCompare(const void * left, const void * right)
8350f3703acSApple OSS Distributions {
8360f3703acSApple OSS Distributions 	IOTracking * instance;
8370f3703acSApple OSS Distributions 	uintptr_t    inst, laddr, raddr;
8380f3703acSApple OSS Distributions 
8390f3703acSApple OSS Distributions 	inst = ((typeof(inst) *)left)[0];
84088cc0b97SApple OSS Distributions 	instance = (typeof(instance))INSTANCE_GET(inst);
841a5e72196SApple OSS Distributions 	if (kInstanceFlagAddress & inst) {
842a5e72196SApple OSS Distributions 		laddr = ~((IOTrackingAddress *)instance)->address;
843a5e72196SApple OSS Distributions 	} else {
844a5e72196SApple OSS Distributions 		laddr = (uintptr_t) (instance + 1);
845a5e72196SApple OSS Distributions 	}
8460f3703acSApple OSS Distributions 
8470f3703acSApple OSS Distributions 	inst = ((typeof(inst) *)right)[0];
8480f3703acSApple OSS Distributions 	instance = (typeof(instance))(inst & ~kInstanceFlags);
849a5e72196SApple OSS Distributions 	if (kInstanceFlagAddress & inst) {
850a5e72196SApple OSS Distributions 		raddr = ~((IOTrackingAddress *)instance)->address;
851a5e72196SApple OSS Distributions 	} else {
852a5e72196SApple OSS Distributions 		raddr = (uintptr_t) (instance + 1);
853a5e72196SApple OSS Distributions 	}
8540f3703acSApple OSS Distributions 
855a5e72196SApple OSS Distributions 	return (laddr > raddr) ? 1 : ((laddr == raddr) ? 0 : -1);
8560f3703acSApple OSS Distributions }
8570f3703acSApple OSS Distributions 
85888cc0b97SApple OSS Distributions 
85988cc0b97SApple OSS Distributions static int
86088cc0b97SApple OSS Distributions IOTrackingZoneElementCompare(const void * left, const void * right)
86188cc0b97SApple OSS Distributions {
86288cc0b97SApple OSS Distributions 	uintptr_t    inst, laddr, raddr;
86388cc0b97SApple OSS Distributions 
86488cc0b97SApple OSS Distributions 	inst = ((typeof(inst) *)left)[0];
86588cc0b97SApple OSS Distributions 	laddr = INSTANCE_PUT(inst);
86688cc0b97SApple OSS Distributions 	inst = ((typeof(inst) *)right)[0];
86788cc0b97SApple OSS Distributions 	raddr = INSTANCE_PUT(inst);
86888cc0b97SApple OSS Distributions 
869a5e72196SApple OSS Distributions 	return (laddr > raddr) ? 1 : ((laddr == raddr) ? 0 : -1);
87088cc0b97SApple OSS Distributions }
87188cc0b97SApple OSS Distributions 
87288cc0b97SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
87388cc0b97SApple OSS Distributions 
87488cc0b97SApple OSS Distributions static void
875*bb611c8fSApple OSS Distributions CopyOutBacktraces(IOTrackingCallSite * site, IOTrackingCallSiteInfo * siteInfo)
87688cc0b97SApple OSS Distributions {
87788cc0b97SApple OSS Distributions 	uint32_t j;
87888cc0b97SApple OSS Distributions 	mach_vm_address_t bt, btEntry;
87988cc0b97SApple OSS Distributions 
88088cc0b97SApple OSS Distributions 	btEntry = site->queue->btEntry;
881a5e72196SApple OSS Distributions 	for (j = 0; j < kIOTrackingCallSiteBTs; j++) {
88288cc0b97SApple OSS Distributions 		bt = site->bt[j];
88388cc0b97SApple OSS Distributions 		if (btEntry
884a5e72196SApple OSS Distributions 		    && (!bt || (j == (kIOTrackingCallSiteBTs - 1)))) {
88588cc0b97SApple OSS Distributions 			bt = btEntry;
88688cc0b97SApple OSS Distributions 			btEntry = 0;
88788cc0b97SApple OSS Distributions 		}
88888cc0b97SApple OSS Distributions 		siteInfo->bt[0][j] = VM_KERNEL_UNSLIDE(bt);
88988cc0b97SApple OSS Distributions 	}
890*bb611c8fSApple OSS Distributions 
891*bb611c8fSApple OSS Distributions 	siteInfo->btPID = 0;
892*bb611c8fSApple OSS Distributions 	if (kIOTrackingQueueTypeUser & site->queue->type) {
893*bb611c8fSApple OSS Distributions 		siteInfo->btPID = site->user[0].pid;
894*bb611c8fSApple OSS Distributions 		uint32_t * bt32 = (typeof(bt32))((void *) &site->user[0].bt[0]);
895*bb611c8fSApple OSS Distributions 		uint64_t * bt64 = (typeof(bt64))((void *) &site->user[0].bt[0]);
896*bb611c8fSApple OSS Distributions 		for (uint32_t j = 0; j < kIOTrackingCallSiteBTs; j++) {
897*bb611c8fSApple OSS Distributions 			if (j >= site->user[0].userCount) {
898*bb611c8fSApple OSS Distributions 				siteInfo->bt[1][j] = 0;
899*bb611c8fSApple OSS Distributions 			} else if (site->user[0].user32) {
900*bb611c8fSApple OSS Distributions 				siteInfo->bt[1][j] = bt32[j];
901*bb611c8fSApple OSS Distributions 			} else {
902*bb611c8fSApple OSS Distributions 				siteInfo->bt[1][j] = bt64[j];
903*bb611c8fSApple OSS Distributions 			}
904*bb611c8fSApple OSS Distributions 		}
905*bb611c8fSApple OSS Distributions 	}
90688cc0b97SApple OSS Distributions }
90788cc0b97SApple OSS Distributions 
9080f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9090f3703acSApple OSS Distributions 
9100f3703acSApple OSS Distributions static void
9110f3703acSApple OSS Distributions IOTrackingLeakScan(void * refcon)
9120f3703acSApple OSS Distributions {
9130f3703acSApple OSS Distributions 	IOTrackingLeaksRef * ref = (typeof(ref))refcon;
9140f3703acSApple OSS Distributions 	uintptr_t          * instances;
9150f3703acSApple OSS Distributions 	IOTracking         * instance;
9160f3703acSApple OSS Distributions 	uint64_t             vaddr, vincr;
9170f3703acSApple OSS Distributions 	ppnum_t              ppn;
91888cc0b97SApple OSS Distributions 	uintptr_t            ptr, addr, vphysaddr, inst;
91976e12aa3SApple OSS Distributions 	size_t               size, origsize;
9200f3703acSApple OSS Distributions 	uint32_t             baseIdx, lim, ptrIdx, count;
9210f3703acSApple OSS Distributions 	boolean_t            is;
92288cc0b97SApple OSS Distributions 	AbsoluteTime         deadline;
9230f3703acSApple OSS Distributions 
9240f3703acSApple OSS Distributions 	instances       = ref->instances;
9250f3703acSApple OSS Distributions 	count           = ref->count;
92676e12aa3SApple OSS Distributions 	size = origsize = ref->zoneSize;
9270f3703acSApple OSS Distributions 
92888cc0b97SApple OSS Distributions 	for (deadline = 0, vaddr = VM_MIN_KERNEL_AND_KEXT_ADDRESS;
92988cc0b97SApple OSS Distributions 	    ;
930a5e72196SApple OSS Distributions 	    vaddr += vincr) {
931a5e72196SApple OSS Distributions 		if ((mach_absolute_time() > deadline) || (vaddr >= VM_MAX_KERNEL_ADDRESS)) {
932a5e72196SApple OSS Distributions 			if (deadline) {
93388cc0b97SApple OSS Distributions 				ml_set_interrupts_enabled(is);
93488cc0b97SApple OSS Distributions 				IODelay(10);
93588cc0b97SApple OSS Distributions 			}
936a5e72196SApple OSS Distributions 			if (vaddr >= VM_MAX_KERNEL_ADDRESS) {
937a5e72196SApple OSS Distributions 				break;
938a5e72196SApple OSS Distributions 			}
9390f3703acSApple OSS Distributions 			is = ml_set_interrupts_enabled(false);
94088cc0b97SApple OSS Distributions 			clock_interval_to_deadline(10, kMillisecondScale, &deadline);
94188cc0b97SApple OSS Distributions 		}
9420f3703acSApple OSS Distributions 
94388cc0b97SApple OSS Distributions 		ppn = kernel_pmap_present_mapping(vaddr, &vincr, &vphysaddr);
9440f3703acSApple OSS Distributions 		// check noencrypt to avoid VM structs (map entries) with pointers
945a5e72196SApple OSS Distributions 		if (ppn && (!pmap_valid_page(ppn) || (!ref->zoneSize && pmap_is_noencrypt(ppn)))) {
946a5e72196SApple OSS Distributions 			ppn = 0;
947a5e72196SApple OSS Distributions 		}
948a5e72196SApple OSS Distributions 		if (!ppn) {
949a5e72196SApple OSS Distributions 			continue;
950a5e72196SApple OSS Distributions 		}
9510f3703acSApple OSS Distributions 
952a5e72196SApple OSS Distributions 		for (ptrIdx = 0; ptrIdx < (page_size / sizeof(uintptr_t)); ptrIdx++) {
95388cc0b97SApple OSS Distributions 			ptr = ((uintptr_t *)vphysaddr)[ptrIdx];
954*bb611c8fSApple OSS Distributions #if defined(HAS_APPLE_PAC)
955*bb611c8fSApple OSS Distributions 			// strip possible ptrauth signature from candidate data pointer
956*bb611c8fSApple OSS Distributions 			ptr = (uintptr_t)ptrauth_strip((void*)ptr, ptrauth_key_process_independent_data);
957*bb611c8fSApple OSS Distributions #endif /* defined(HAS_APPLE_PAC) */
9580f3703acSApple OSS Distributions 
959a5e72196SApple OSS Distributions 			for (lim = count, baseIdx = 0; lim; lim >>= 1) {
9600f3703acSApple OSS Distributions 				inst = instances[baseIdx + (lim >> 1)];
96188cc0b97SApple OSS Distributions 				instance = (typeof(instance))INSTANCE_GET(inst);
96288cc0b97SApple OSS Distributions 
963a5e72196SApple OSS Distributions 				if (ref->zoneSize) {
96488cc0b97SApple OSS Distributions 					addr = INSTANCE_PUT(inst) & ~kInstanceFlags;
965a5e72196SApple OSS Distributions 				} else if (kInstanceFlagAddress & inst) {
9660f3703acSApple OSS Distributions 					addr            = ~((IOTrackingAddress *)instance)->address;
96776e12aa3SApple OSS Distributions 					origsize = size = ((IOTrackingAddress *)instance)->size;
968a5e72196SApple OSS Distributions 					if (!size) {
969a5e72196SApple OSS Distributions 						size = 1;
9700f3703acSApple OSS Distributions 					}
971a5e72196SApple OSS Distributions 				} else {
9720f3703acSApple OSS Distributions 					addr            = (uintptr_t) (instance + 1);
97376e12aa3SApple OSS Distributions 					origsize = size = instance->site->queue->allocSize;
9740f3703acSApple OSS Distributions 				}
97588cc0b97SApple OSS Distributions 				if ((ptr >= addr) && (ptr < (addr + size))
97688cc0b97SApple OSS Distributions 
97788cc0b97SApple OSS Distributions 				    && (((vaddr + ptrIdx * sizeof(uintptr_t)) < addr)
978a5e72196SApple OSS Distributions 				    || ((vaddr + ptrIdx * sizeof(uintptr_t)) >= (addr + size)))) {
979a5e72196SApple OSS Distributions 					if (!(kInstanceFlagReferenced & inst)) {
9800f3703acSApple OSS Distributions 						inst |= kInstanceFlagReferenced;
9810f3703acSApple OSS Distributions 						instances[baseIdx + (lim >> 1)] = inst;
9820f3703acSApple OSS Distributions 						ref->found++;
983a5e72196SApple OSS Distributions 						if (!origsize) {
984a5e72196SApple OSS Distributions 							ref->foundzlen++;
985a5e72196SApple OSS Distributions 						}
9860f3703acSApple OSS Distributions 					}
9870f3703acSApple OSS Distributions 					break;
9880f3703acSApple OSS Distributions 				}
989a5e72196SApple OSS Distributions 				if (ptr > addr) {
9900f3703acSApple OSS Distributions 					// move right
9910f3703acSApple OSS Distributions 					baseIdx += (lim >> 1) + 1;
9920f3703acSApple OSS Distributions 					lim--;
9930f3703acSApple OSS Distributions 				}
9940f3703acSApple OSS Distributions 				// else move left
9950f3703acSApple OSS Distributions 			}
9960f3703acSApple OSS Distributions 		}
9970f3703acSApple OSS Distributions 		ref->bytes += page_size;
9980f3703acSApple OSS Distributions 	}
9990f3703acSApple OSS Distributions }
10000f3703acSApple OSS Distributions 
10010f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
10020f3703acSApple OSS Distributions 
100388cc0b97SApple OSS Distributions extern "C" void
100488cc0b97SApple OSS Distributions zone_leaks_scan(uintptr_t * instances, uint32_t count, uint32_t zoneSize, uint32_t * found)
100588cc0b97SApple OSS Distributions {
100688cc0b97SApple OSS Distributions 	IOTrackingLeaksRef       ref;
100788cc0b97SApple OSS Distributions 	IOTrackingCallSiteInfo   siteInfo;
100888cc0b97SApple OSS Distributions 	uint32_t                 idx;
100988cc0b97SApple OSS Distributions 
101088cc0b97SApple OSS Distributions 	qsort(instances, count, sizeof(*instances), &IOTrackingZoneElementCompare);
101188cc0b97SApple OSS Distributions 
101288cc0b97SApple OSS Distributions 	bzero(&siteInfo, sizeof(siteInfo));
101388cc0b97SApple OSS Distributions 	bzero(&ref, sizeof(ref));
101488cc0b97SApple OSS Distributions 	ref.instances = instances;
101588cc0b97SApple OSS Distributions 	ref.count = count;
101688cc0b97SApple OSS Distributions 	ref.zoneSize = zoneSize;
101788cc0b97SApple OSS Distributions 
1018a5e72196SApple OSS Distributions 	for (idx = 0; idx < 2; idx++) {
101988cc0b97SApple OSS Distributions 		ref.bytes = 0;
102088cc0b97SApple OSS Distributions 		IOTrackingLeakScan(&ref);
102188cc0b97SApple OSS Distributions 		IOLog("leaks(%d) scanned %ld MB, instance count %d, found %d\n", idx, ref.bytes / 1024 / 1024, count, ref.found);
1022a5e72196SApple OSS Distributions 		if (count <= ref.found) {
1023a5e72196SApple OSS Distributions 			break;
1024a5e72196SApple OSS Distributions 		}
102588cc0b97SApple OSS Distributions 	}
102688cc0b97SApple OSS Distributions 
102788cc0b97SApple OSS Distributions 	*found = ref.found;
102888cc0b97SApple OSS Distributions }
102988cc0b97SApple OSS Distributions 
103088cc0b97SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
103188cc0b97SApple OSS Distributions 
103288cc0b97SApple OSS Distributions static void
103388cc0b97SApple OSS Distributions ZoneSiteProc(void * refCon, uint32_t siteCount, uint32_t zoneSize,
103488cc0b97SApple OSS Distributions     uintptr_t * backtrace, uint32_t btCount)
103588cc0b97SApple OSS Distributions {
103688cc0b97SApple OSS Distributions 	IOTrackingCallSiteInfo siteInfo;
103788cc0b97SApple OSS Distributions 	OSData               * leakData;
103888cc0b97SApple OSS Distributions 	uint32_t               idx;
103988cc0b97SApple OSS Distributions 
104088cc0b97SApple OSS Distributions 	leakData = (typeof(leakData))refCon;
104188cc0b97SApple OSS Distributions 
104288cc0b97SApple OSS Distributions 	bzero(&siteInfo, sizeof(siteInfo));
104388cc0b97SApple OSS Distributions 	siteInfo.count   = siteCount;
104488cc0b97SApple OSS Distributions 	siteInfo.size[0] = zoneSize * siteCount;
104588cc0b97SApple OSS Distributions 
1046a5e72196SApple OSS Distributions 	for (idx = 0; (idx < btCount) && (idx < kIOTrackingCallSiteBTs); idx++) {
104788cc0b97SApple OSS Distributions 		siteInfo.bt[0][idx] = VM_KERNEL_UNSLIDE(backtrace[idx]);
104888cc0b97SApple OSS Distributions 	}
104988cc0b97SApple OSS Distributions 
105088cc0b97SApple OSS Distributions 	leakData->appendBytes(&siteInfo, sizeof(siteInfo));
105188cc0b97SApple OSS Distributions }
105288cc0b97SApple OSS Distributions 
105388cc0b97SApple OSS Distributions 
105488cc0b97SApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
105588cc0b97SApple OSS Distributions 
10560f3703acSApple OSS Distributions static OSData *
1057a5e72196SApple OSS Distributions IOTrackingLeaks(LIBKERN_CONSUMED OSData * data)
10580f3703acSApple OSS Distributions {
10590f3703acSApple OSS Distributions 	IOTrackingLeaksRef       ref;
106088cc0b97SApple OSS Distributions 	IOTrackingCallSiteInfo   siteInfo;
10610f3703acSApple OSS Distributions 	IOTrackingCallSite     * site;
10620f3703acSApple OSS Distributions 	OSData                 * leakData;
10630f3703acSApple OSS Distributions 	uintptr_t              * instances;
10640f3703acSApple OSS Distributions 	IOTracking             * instance;
10650f3703acSApple OSS Distributions 	uintptr_t                inst;
10660f3703acSApple OSS Distributions 	uint32_t                 count, idx, numSites, dups, siteCount;
10670f3703acSApple OSS Distributions 
10680f3703acSApple OSS Distributions 	instances = (typeof(instances))data->getBytesNoCopy();
10690f3703acSApple OSS Distributions 	count = (data->getLength() / sizeof(*instances));
10700f3703acSApple OSS Distributions 	qsort(instances, count, sizeof(*instances), &IOTrackingAddressCompare);
10710f3703acSApple OSS Distributions 
107288cc0b97SApple OSS Distributions 	bzero(&siteInfo, sizeof(siteInfo));
10730f3703acSApple OSS Distributions 	bzero(&ref, sizeof(ref));
10740f3703acSApple OSS Distributions 	ref.instances = instances;
10750f3703acSApple OSS Distributions 	ref.count = count;
1076a5e72196SApple OSS Distributions 	for (idx = 0; idx < 2; idx++) {
107788cc0b97SApple OSS Distributions 		ref.bytes = 0;
10780f3703acSApple OSS Distributions 		IOTrackingLeakScan(&ref);
107976e12aa3SApple OSS Distributions 		IOLog("leaks(%d) scanned %ld MB, instance count %d, found %d (zlen %d)\n", idx, ref.bytes / 1024 / 1024, count, ref.found, ref.foundzlen);
1080a5e72196SApple OSS Distributions 		if (count <= ref.found) {
1081a5e72196SApple OSS Distributions 			break;
1082a5e72196SApple OSS Distributions 		}
108388cc0b97SApple OSS Distributions 	}
10840f3703acSApple OSS Distributions 
10850f3703acSApple OSS Distributions 	leakData = OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo));
10860f3703acSApple OSS Distributions 
1087a5e72196SApple OSS Distributions 	for (numSites = 0, idx = 0; idx < count; idx++) {
10880f3703acSApple OSS Distributions 		inst = instances[idx];
1089a5e72196SApple OSS Distributions 		if (kInstanceFlagReferenced & inst) {
1090a5e72196SApple OSS Distributions 			continue;
1091a5e72196SApple OSS Distributions 		}
109288cc0b97SApple OSS Distributions 		instance = (typeof(instance))INSTANCE_GET(inst);
10930f3703acSApple OSS Distributions 		site = instance->site;
10940f3703acSApple OSS Distributions 		instances[numSites] = (uintptr_t) site;
10950f3703acSApple OSS Distributions 		numSites++;
10960f3703acSApple OSS Distributions 	}
10970f3703acSApple OSS Distributions 
1098a5e72196SApple OSS Distributions 	for (idx = 0; idx < numSites; idx++) {
10990f3703acSApple OSS Distributions 		inst = instances[idx];
1100a5e72196SApple OSS Distributions 		if (!inst) {
1101a5e72196SApple OSS Distributions 			continue;
1102a5e72196SApple OSS Distributions 		}
11030f3703acSApple OSS Distributions 		site = (typeof(site))inst;
1104a5e72196SApple OSS Distributions 		for (siteCount = 1, dups = (idx + 1); dups < numSites; dups++) {
1105a5e72196SApple OSS Distributions 			if (instances[dups] == (uintptr_t) site) {
11060f3703acSApple OSS Distributions 				siteCount++;
11070f3703acSApple OSS Distributions 				instances[dups] = 0;
11080f3703acSApple OSS Distributions 			}
11090f3703acSApple OSS Distributions 		}
111088cc0b97SApple OSS Distributions 		siteInfo.count   = siteCount;
111188cc0b97SApple OSS Distributions 		siteInfo.size[0] = (site->size[0] * site->count) / siteCount;
111288cc0b97SApple OSS Distributions 		siteInfo.size[1] = (site->size[1] * site->count) / siteCount;;
1113*bb611c8fSApple OSS Distributions 		CopyOutBacktraces(site, &siteInfo);
111488cc0b97SApple OSS Distributions 		leakData->appendBytes(&siteInfo, sizeof(siteInfo));
11150f3703acSApple OSS Distributions 	}
11160f3703acSApple OSS Distributions 	data->release();
11170f3703acSApple OSS Distributions 
1118a5e72196SApple OSS Distributions 	return leakData;
11190f3703acSApple OSS Distributions }
11200f3703acSApple OSS Distributions 
11210f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11220f3703acSApple OSS Distributions 
11230f3703acSApple OSS Distributions static bool
11240f3703acSApple OSS Distributions SkipName(uint32_t options, const char * name, size_t namesLen, const char * names)
11250f3703acSApple OSS Distributions {
11260f3703acSApple OSS Distributions 	const char * scan;
11270f3703acSApple OSS Distributions 	const char * next;
11280f3703acSApple OSS Distributions 	bool         exclude, found;
11290f3703acSApple OSS Distributions 	size_t       qLen, sLen;
11300f3703acSApple OSS Distributions 
1131a5e72196SApple OSS Distributions 	if (!namesLen || !names) {
1132a5e72196SApple OSS Distributions 		return false;
1133a5e72196SApple OSS Distributions 	}
11340f3703acSApple OSS Distributions 	// <len><name>...<len><name><0>
11350f3703acSApple OSS Distributions 	exclude = (0 != (kIOTrackingExcludeNames & options));
11360f3703acSApple OSS Distributions 	qLen    = strlen(name);
11370f3703acSApple OSS Distributions 	scan    = names;
11380f3703acSApple OSS Distributions 	found   = false;
1139a5e72196SApple OSS Distributions 	do{
11400f3703acSApple OSS Distributions 		sLen = scan[0];
11410f3703acSApple OSS Distributions 		scan++;
11420f3703acSApple OSS Distributions 		next = scan + sLen;
1143a5e72196SApple OSS Distributions 		if (next >= (names + namesLen)) {
1144a5e72196SApple OSS Distributions 			break;
1145a5e72196SApple OSS Distributions 		}
11460f3703acSApple OSS Distributions 		found = ((sLen == qLen) && !strncmp(scan, name, sLen));
11470f3703acSApple OSS Distributions 		scan = next;
1148a5e72196SApple OSS Distributions 	}while (!found && (scan < (names + namesLen)));
11490f3703acSApple OSS Distributions 
1150a5e72196SApple OSS Distributions 	return !(exclude ^ found);
11510f3703acSApple OSS Distributions }
11520f3703acSApple OSS Distributions 
11530f3703acSApple OSS Distributions #endif /* IOTRACKING */
11540f3703acSApple OSS Distributions 
11550f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11560f3703acSApple OSS Distributions 
115776e12aa3SApple OSS Distributions static kern_return_t
115888cc0b97SApple OSS Distributions IOTrackingDebug(uint32_t selector, uint32_t options, uint64_t value,
115976e12aa3SApple OSS Distributions     uint32_t intag, uint32_t inzsize,
11600f3703acSApple OSS Distributions     const char * names, size_t namesLen,
11610f3703acSApple OSS Distributions     size_t size, OSObject ** result)
11620f3703acSApple OSS Distributions {
11630f3703acSApple OSS Distributions 	kern_return_t            ret;
11640f3703acSApple OSS Distributions 	OSData                 * data;
11650f3703acSApple OSS Distributions 
1166a5e72196SApple OSS Distributions 	if (result) {
1167a5e72196SApple OSS Distributions 		*result = NULL;
1168a5e72196SApple OSS Distributions 	}
1169a5e72196SApple OSS Distributions 	data = NULL;
11700f3703acSApple OSS Distributions 	ret = kIOReturnNotReady;
11710f3703acSApple OSS Distributions 
11720f3703acSApple OSS Distributions #if IOTRACKING
11730f3703acSApple OSS Distributions 
117488cc0b97SApple OSS Distributions 	kern_return_t            kr;
11750f3703acSApple OSS Distributions 	IOTrackingQueue        * queue;
11760f3703acSApple OSS Distributions 	IOTracking             * instance;
11770f3703acSApple OSS Distributions 	IOTrackingCallSite     * site;
117888cc0b97SApple OSS Distributions 	IOTrackingCallSiteInfo   siteInfo;
117988cc0b97SApple OSS Distributions 	IOTrackingUser         * user;
118088cc0b97SApple OSS Distributions 	task_t                   mapTask;
118188cc0b97SApple OSS Distributions 	mach_vm_address_t        mapAddress;
118288cc0b97SApple OSS Distributions 	mach_vm_size_t           mapSize;
118388cc0b97SApple OSS Distributions 	uint32_t                 num, idx, qIdx;
11840f3703acSApple OSS Distributions 	uintptr_t                instFlags;
118588cc0b97SApple OSS Distributions 	proc_t                   proc;
118688cc0b97SApple OSS Distributions 	bool                     addresses;
11870f3703acSApple OSS Distributions 
11880f3703acSApple OSS Distributions 	ret = kIOReturnNotFound;
118988cc0b97SApple OSS Distributions 	proc = NULL;
1190a5e72196SApple OSS Distributions 	if (kIOTrackingGetMappings == selector) {
1191a5e72196SApple OSS Distributions 		if (value != -1ULL) {
1192*bb611c8fSApple OSS Distributions 			proc = proc_find((pid_t) value);
1193a5e72196SApple OSS Distributions 			if (!proc) {
1194a5e72196SApple OSS Distributions 				return kIOReturnNotFound;
1195a5e72196SApple OSS Distributions 			}
119688cc0b97SApple OSS Distributions 		}
119788cc0b97SApple OSS Distributions 	}
11980f3703acSApple OSS Distributions 
119988cc0b97SApple OSS Distributions 	bzero(&siteInfo, sizeof(siteInfo));
12000f3703acSApple OSS Distributions 	lck_mtx_lock(gIOTrackingLock);
12010f3703acSApple OSS Distributions 	queue_iterate(&gIOTrackingQ, queue, IOTrackingQueue *, link)
12020f3703acSApple OSS Distributions 	{
1203a5e72196SApple OSS Distributions 		if (SkipName(options, queue->name, namesLen, names)) {
1204a5e72196SApple OSS Distributions 			continue;
1205a5e72196SApple OSS Distributions 		}
12060f3703acSApple OSS Distributions 
1207a5e72196SApple OSS Distributions 		if (!(kIOTracking & gIOKitDebug) && (kIOTrackingQueueTypeAlloc & queue->type)) {
1208a5e72196SApple OSS Distributions 			continue;
1209a5e72196SApple OSS Distributions 		}
121088cc0b97SApple OSS Distributions 
1211a5e72196SApple OSS Distributions 		switch (selector) {
12120f3703acSApple OSS Distributions 		case kIOTrackingResetTracking:
12130f3703acSApple OSS Distributions 		{
12140f3703acSApple OSS Distributions 			IOTrackingReset(queue);
12150f3703acSApple OSS Distributions 			ret = kIOReturnSuccess;
12160f3703acSApple OSS Distributions 			break;
12170f3703acSApple OSS Distributions 		}
12180f3703acSApple OSS Distributions 
12190f3703acSApple OSS Distributions 		case kIOTrackingStartCapture:
12200f3703acSApple OSS Distributions 		case kIOTrackingStopCapture:
12210f3703acSApple OSS Distributions 		{
12220f3703acSApple OSS Distributions 			queue->captureOn = (kIOTrackingStartCapture == selector);
12230f3703acSApple OSS Distributions 			ret = kIOReturnSuccess;
12240f3703acSApple OSS Distributions 			break;
12250f3703acSApple OSS Distributions 		}
12260f3703acSApple OSS Distributions 
12270f3703acSApple OSS Distributions 		case kIOTrackingSetMinCaptureSize:
12280f3703acSApple OSS Distributions 		{
12290f3703acSApple OSS Distributions 			queue->minCaptureSize = size;
12300f3703acSApple OSS Distributions 			ret = kIOReturnSuccess;
12310f3703acSApple OSS Distributions 			break;
12320f3703acSApple OSS Distributions 		}
12330f3703acSApple OSS Distributions 
12340f3703acSApple OSS Distributions 		case kIOTrackingLeaks:
12350f3703acSApple OSS Distributions 		{
1236a5e72196SApple OSS Distributions 			if (!(kIOTrackingQueueTypeAlloc & queue->type)) {
1237a5e72196SApple OSS Distributions 				break;
1238a5e72196SApple OSS Distributions 			}
12390f3703acSApple OSS Distributions 
1240a5e72196SApple OSS Distributions 			if (!data) {
1241a5e72196SApple OSS Distributions 				data = OSData::withCapacity(1024 * sizeof(uintptr_t));
1242a5e72196SApple OSS Distributions 			}
12430f3703acSApple OSS Distributions 
12440f3703acSApple OSS Distributions 			IOTRecursiveLockLock(&queue->lock);
1245a5e72196SApple OSS Distributions 			for (idx = 0; idx < queue->numSiteQs; idx++) {
124688cc0b97SApple OSS Distributions 				queue_iterate(&queue->sites[idx], site, IOTrackingCallSite *, link)
12470f3703acSApple OSS Distributions 				{
12480f3703acSApple OSS Distributions 					addresses = false;
12490f3703acSApple OSS Distributions 					queue_iterate(&site->instances, instance, IOTracking *, link)
12500f3703acSApple OSS Distributions 					{
1251a5e72196SApple OSS Distributions 						if (instance == site->addresses) {
1252a5e72196SApple OSS Distributions 							addresses = true;
1253a5e72196SApple OSS Distributions 						}
12540f3703acSApple OSS Distributions 						instFlags = (typeof(instFlags))instance;
1255a5e72196SApple OSS Distributions 						if (addresses) {
1256a5e72196SApple OSS Distributions 							instFlags |= kInstanceFlagAddress;
1257a5e72196SApple OSS Distributions 						}
12580f3703acSApple OSS Distributions 						data->appendBytes(&instFlags, sizeof(instFlags));
12590f3703acSApple OSS Distributions 					}
12600f3703acSApple OSS Distributions 				}
126188cc0b97SApple OSS Distributions 			}
12620f3703acSApple OSS Distributions 			// queue is locked
12630f3703acSApple OSS Distributions 			ret = kIOReturnSuccess;
12640f3703acSApple OSS Distributions 			break;
12650f3703acSApple OSS Distributions 		}
12660f3703acSApple OSS Distributions 
126776e12aa3SApple OSS Distributions 
12680f3703acSApple OSS Distributions 		case kIOTrackingGetTracking:
12690f3703acSApple OSS Distributions 		{
1270a5e72196SApple OSS Distributions 			if (kIOTrackingQueueTypeMap & queue->type) {
1271a5e72196SApple OSS Distributions 				break;
1272a5e72196SApple OSS Distributions 			}
127388cc0b97SApple OSS Distributions 
1274a5e72196SApple OSS Distributions 			if (!data) {
1275a5e72196SApple OSS Distributions 				data = OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo));
1276a5e72196SApple OSS Distributions 			}
12770f3703acSApple OSS Distributions 
12780f3703acSApple OSS Distributions 			IOTRecursiveLockLock(&queue->lock);
12790f3703acSApple OSS Distributions 			num = queue->siteCount;
12800f3703acSApple OSS Distributions 			idx = 0;
1281a5e72196SApple OSS Distributions 			for (qIdx = 0; qIdx < queue->numSiteQs; qIdx++) {
128288cc0b97SApple OSS Distributions 				queue_iterate(&queue->sites[qIdx], site, IOTrackingCallSite *, link)
12830f3703acSApple OSS Distributions 				{
12840f3703acSApple OSS Distributions 					assert(idx < num);
12850f3703acSApple OSS Distributions 					idx++;
12860f3703acSApple OSS Distributions 
128776e12aa3SApple OSS Distributions 					size_t tsize[2];
128876e12aa3SApple OSS Distributions 					uint32_t count = site->count;
128976e12aa3SApple OSS Distributions 					tsize[0] = site->size[0];
129076e12aa3SApple OSS Distributions 					tsize[1] = site->size[1];
12910f3703acSApple OSS Distributions 
1292a5e72196SApple OSS Distributions 					if (intag || inzsize) {
129376e12aa3SApple OSS Distributions 						uintptr_t addr;
129476e12aa3SApple OSS Distributions 						vm_size_t size, zoneSize;
129576e12aa3SApple OSS Distributions 						vm_tag_t  tag;
129676e12aa3SApple OSS Distributions 
1297a5e72196SApple OSS Distributions 						if (kIOTrackingQueueTypeAlloc & queue->type) {
129876e12aa3SApple OSS Distributions 							addresses = false;
129976e12aa3SApple OSS Distributions 							count = 0;
130076e12aa3SApple OSS Distributions 							tsize[0] = tsize[1] = 0;
130176e12aa3SApple OSS Distributions 							queue_iterate(&site->instances, instance, IOTracking *, link)
130276e12aa3SApple OSS Distributions 							{
1303a5e72196SApple OSS Distributions 								if (instance == site->addresses) {
1304a5e72196SApple OSS Distributions 									addresses = true;
1305a5e72196SApple OSS Distributions 								}
130676e12aa3SApple OSS Distributions 
1307a5e72196SApple OSS Distributions 								if (addresses) {
1308a5e72196SApple OSS Distributions 									addr = ~((IOTrackingAddress *)instance)->address;
1309a5e72196SApple OSS Distributions 								} else {
1310a5e72196SApple OSS Distributions 									addr = (uintptr_t) (instance + 1);
1311a5e72196SApple OSS Distributions 								}
131276e12aa3SApple OSS Distributions 
131376e12aa3SApple OSS Distributions 								kr = vm_kern_allocation_info(addr, &size, &tag, &zoneSize);
1314a5e72196SApple OSS Distributions 								if (KERN_SUCCESS != kr) {
1315a5e72196SApple OSS Distributions 									continue;
1316a5e72196SApple OSS Distributions 								}
131776e12aa3SApple OSS Distributions 
1318a5e72196SApple OSS Distributions 								if ((VM_KERN_MEMORY_NONE != intag) && (intag != tag)) {
1319a5e72196SApple OSS Distributions 									continue;
1320a5e72196SApple OSS Distributions 								}
1321a5e72196SApple OSS Distributions 								if (inzsize && (inzsize != zoneSize)) {
1322a5e72196SApple OSS Distributions 									continue;
1323a5e72196SApple OSS Distributions 								}
132476e12aa3SApple OSS Distributions 
132576e12aa3SApple OSS Distributions 								count++;
132676e12aa3SApple OSS Distributions 								tsize[0] += size;
132776e12aa3SApple OSS Distributions 							}
1328a5e72196SApple OSS Distributions 						} else {
1329a5e72196SApple OSS Distributions 							if (!intag || inzsize || (intag != site->tag)) {
1330a5e72196SApple OSS Distributions 								continue;
133176e12aa3SApple OSS Distributions 							}
133276e12aa3SApple OSS Distributions 						}
133376e12aa3SApple OSS Distributions 					}
133476e12aa3SApple OSS Distributions 
1335a5e72196SApple OSS Distributions 					if (!count) {
1336a5e72196SApple OSS Distributions 						continue;
1337a5e72196SApple OSS Distributions 					}
1338a5e72196SApple OSS Distributions 					if (size && ((tsize[0] + tsize[1]) < size)) {
1339a5e72196SApple OSS Distributions 						continue;
1340a5e72196SApple OSS Distributions 					}
134176e12aa3SApple OSS Distributions 					siteInfo.count   = count;
134276e12aa3SApple OSS Distributions 					siteInfo.size[0] = tsize[0];
134376e12aa3SApple OSS Distributions 					siteInfo.size[1] = tsize[1];
1344*bb611c8fSApple OSS Distributions 					CopyOutBacktraces(site, &siteInfo);
134588cc0b97SApple OSS Distributions 					data->appendBytes(&siteInfo, sizeof(siteInfo));
13460f3703acSApple OSS Distributions 				}
13470f3703acSApple OSS Distributions 			}
13480f3703acSApple OSS Distributions 			assert(idx == num);
13490f3703acSApple OSS Distributions 			IOTRecursiveLockUnlock(&queue->lock);
13500f3703acSApple OSS Distributions 			ret = kIOReturnSuccess;
13510f3703acSApple OSS Distributions 			break;
13520f3703acSApple OSS Distributions 		}
135388cc0b97SApple OSS Distributions 
135488cc0b97SApple OSS Distributions 		case kIOTrackingGetMappings:
135588cc0b97SApple OSS Distributions 		{
1356a5e72196SApple OSS Distributions 			if (!(kIOTrackingQueueTypeMap & queue->type)) {
1357a5e72196SApple OSS Distributions 				break;
1358a5e72196SApple OSS Distributions 			}
1359a5e72196SApple OSS Distributions 			if (!data) {
1360*bb611c8fSApple OSS Distributions 				data = OSData::withCapacity((unsigned int) page_size);
1361a5e72196SApple OSS Distributions 			}
136288cc0b97SApple OSS Distributions 
136388cc0b97SApple OSS Distributions 			IOTRecursiveLockLock(&queue->lock);
136488cc0b97SApple OSS Distributions 			num = queue->siteCount;
136588cc0b97SApple OSS Distributions 			idx = 0;
1366a5e72196SApple OSS Distributions 			for (qIdx = 0; qIdx < queue->numSiteQs; qIdx++) {
136788cc0b97SApple OSS Distributions 				queue_iterate(&queue->sites[qIdx], user, IOTrackingUser *, link)
136888cc0b97SApple OSS Distributions 				{
136988cc0b97SApple OSS Distributions 					assert(idx < num);
137088cc0b97SApple OSS Distributions 					idx++;
137188cc0b97SApple OSS Distributions 
137288cc0b97SApple OSS Distributions 					kr = IOMemoryMapTracking(user, &mapTask, &mapAddress, &mapSize);
1373a5e72196SApple OSS Distributions 					if (kIOReturnSuccess != kr) {
1374a5e72196SApple OSS Distributions 						continue;
1375a5e72196SApple OSS Distributions 					}
1376a5e72196SApple OSS Distributions 					if (proc && (mapTask != proc_task(proc))) {
1377a5e72196SApple OSS Distributions 						continue;
1378a5e72196SApple OSS Distributions 					}
1379a5e72196SApple OSS Distributions 					if (size && (mapSize < size)) {
1380a5e72196SApple OSS Distributions 						continue;
1381a5e72196SApple OSS Distributions 					}
138288cc0b97SApple OSS Distributions 
138388cc0b97SApple OSS Distributions 					siteInfo.count      = 1;
138488cc0b97SApple OSS Distributions 					siteInfo.size[0]    = mapSize;
138588cc0b97SApple OSS Distributions 					siteInfo.address    = mapAddress;
138688cc0b97SApple OSS Distributions 					siteInfo.addressPID = task_pid(mapTask);
138788cc0b97SApple OSS Distributions 					siteInfo.btPID      = user->btPID;
138888cc0b97SApple OSS Distributions 
1389a5e72196SApple OSS Distributions 					for (uint32_t j = 0; j < kIOTrackingCallSiteBTs; j++) {
139088cc0b97SApple OSS Distributions 						siteInfo.bt[0][j] = VM_KERNEL_UNSLIDE(user->bt[j]);
139188cc0b97SApple OSS Distributions 					}
139288cc0b97SApple OSS Distributions 					uint32_t * bt32 = (typeof(bt32)) & user->btUser[0];
139388cc0b97SApple OSS Distributions 					uint64_t * bt64 = (typeof(bt64))((void *) &user->btUser[0]);
1394a5e72196SApple OSS Distributions 					for (uint32_t j = 0; j < kIOTrackingCallSiteBTs; j++) {
1395a5e72196SApple OSS Distributions 						if (j >= user->userCount) {
1396a5e72196SApple OSS Distributions 							siteInfo.bt[1][j] = 0;
1397a5e72196SApple OSS Distributions 						} else if (user->user32) {
1398a5e72196SApple OSS Distributions 							siteInfo.bt[1][j] = bt32[j];
1399a5e72196SApple OSS Distributions 						} else {
1400a5e72196SApple OSS Distributions 							siteInfo.bt[1][j] = bt64[j];
1401a5e72196SApple OSS Distributions 						}
140288cc0b97SApple OSS Distributions 					}
140388cc0b97SApple OSS Distributions 					data->appendBytes(&siteInfo, sizeof(siteInfo));
140488cc0b97SApple OSS Distributions 				}
140588cc0b97SApple OSS Distributions 			}
140688cc0b97SApple OSS Distributions 			assert(idx == num);
140788cc0b97SApple OSS Distributions 			IOTRecursiveLockUnlock(&queue->lock);
140888cc0b97SApple OSS Distributions 			ret = kIOReturnSuccess;
140988cc0b97SApple OSS Distributions 			break;
141088cc0b97SApple OSS Distributions 		}
141188cc0b97SApple OSS Distributions 
14120f3703acSApple OSS Distributions 		default:
14130f3703acSApple OSS Distributions 			ret = kIOReturnUnsupported;
14140f3703acSApple OSS Distributions 			break;
14150f3703acSApple OSS Distributions 		}
14160f3703acSApple OSS Distributions 	}
14170f3703acSApple OSS Distributions 
1418a5e72196SApple OSS Distributions 	if ((kIOTrackingLeaks == selector) && data) {
14190f3703acSApple OSS Distributions 		data = IOTrackingLeaks(data);
14200f3703acSApple OSS Distributions 		queue_iterate(&gIOTrackingQ, queue, IOTrackingQueue *, link)
14210f3703acSApple OSS Distributions 		{
1422a5e72196SApple OSS Distributions 			if (SkipName(options, queue->name, namesLen, names)) {
1423a5e72196SApple OSS Distributions 				continue;
1424a5e72196SApple OSS Distributions 			}
1425a5e72196SApple OSS Distributions 			if (!(kIOTrackingQueueTypeAlloc & queue->type)) {
1426a5e72196SApple OSS Distributions 				continue;
1427a5e72196SApple OSS Distributions 			}
14280f3703acSApple OSS Distributions 			IOTRecursiveLockUnlock(&queue->lock);
14290f3703acSApple OSS Distributions 		}
14300f3703acSApple OSS Distributions 	}
14310f3703acSApple OSS Distributions 
14320f3703acSApple OSS Distributions 	lck_mtx_unlock(gIOTrackingLock);
14330f3703acSApple OSS Distributions 
1434a5e72196SApple OSS Distributions 	if ((kIOTrackingLeaks == selector) && namesLen && names) {
143588cc0b97SApple OSS Distributions 		const char * scan;
143688cc0b97SApple OSS Distributions 		const char * next;
1437*bb611c8fSApple OSS Distributions 		uint8_t      sLen;
14380f3703acSApple OSS Distributions 
1439a5e72196SApple OSS Distributions 		if (!data) {
1440a5e72196SApple OSS Distributions 			data = OSData::withCapacity(4096 * sizeof(uintptr_t));
1441a5e72196SApple OSS Distributions 		}
144288cc0b97SApple OSS Distributions 
144388cc0b97SApple OSS Distributions 		// <len><name>...<len><name><0>
144488cc0b97SApple OSS Distributions 		scan    = names;
1445a5e72196SApple OSS Distributions 		do{
1446*bb611c8fSApple OSS Distributions 			sLen = ((uint8_t) scan[0]);
144788cc0b97SApple OSS Distributions 			scan++;
144888cc0b97SApple OSS Distributions 			next = scan + sLen;
1449a5e72196SApple OSS Distributions 			if (next >= (names + namesLen)) {
1450a5e72196SApple OSS Distributions 				break;
145188cc0b97SApple OSS Distributions 			}
1452a5e72196SApple OSS Distributions 			kr = zone_leaks(scan, sLen, &ZoneSiteProc, data);
1453a5e72196SApple OSS Distributions 			if (KERN_SUCCESS == kr) {
1454a5e72196SApple OSS Distributions 				ret = kIOReturnSuccess;
1455a5e72196SApple OSS Distributions 			} else if (KERN_INVALID_NAME != kr) {
1456a5e72196SApple OSS Distributions 				ret = kIOReturnVMError;
1457a5e72196SApple OSS Distributions 			}
1458a5e72196SApple OSS Distributions 			scan = next;
1459a5e72196SApple OSS Distributions 		}while (scan < (names + namesLen));
146088cc0b97SApple OSS Distributions 	}
146188cc0b97SApple OSS Distributions 
1462a5e72196SApple OSS Distributions 	if (data) {
1463a5e72196SApple OSS Distributions 		switch (selector) {
146488cc0b97SApple OSS Distributions 		case kIOTrackingLeaks:
146588cc0b97SApple OSS Distributions 		case kIOTrackingGetTracking:
146688cc0b97SApple OSS Distributions 		case kIOTrackingGetMappings:
146788cc0b97SApple OSS Distributions 		{
146888cc0b97SApple OSS Distributions 			IOTrackingCallSiteInfo * siteInfos;
146988cc0b97SApple OSS Distributions 			siteInfos = (typeof(siteInfos))data->getBytesNoCopy();
147088cc0b97SApple OSS Distributions 			num = (data->getLength() / sizeof(*siteInfos));
147188cc0b97SApple OSS Distributions 			qsort(siteInfos, num, sizeof(*siteInfos), &IOTrackingCallSiteInfoCompare);
147288cc0b97SApple OSS Distributions 			break;
14730f3703acSApple OSS Distributions 		}
147488cc0b97SApple OSS Distributions 		default: assert(false); break;
14750f3703acSApple OSS Distributions 		}
1476a5e72196SApple OSS Distributions 	}
14770f3703acSApple OSS Distributions 
14780f3703acSApple OSS Distributions 	*result = data;
1479a5e72196SApple OSS Distributions 	if (proc) {
1480a5e72196SApple OSS Distributions 		proc_rele(proc);
1481a5e72196SApple OSS Distributions 	}
14820f3703acSApple OSS Distributions 
14830f3703acSApple OSS Distributions #endif /* IOTRACKING */
14840f3703acSApple OSS Distributions 
1485a5e72196SApple OSS Distributions 	return ret;
14860f3703acSApple OSS Distributions }
14870f3703acSApple OSS Distributions 
14880f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
14890f3703acSApple OSS Distributions 
14900f3703acSApple OSS Distributions #include <IOKit/IOKitDiagnosticsUserClient.h>
14910f3703acSApple OSS Distributions 
14920f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
14930f3703acSApple OSS Distributions 
14940f3703acSApple OSS Distributions #undef super
14950f3703acSApple OSS Distributions #define super IOUserClient
14960f3703acSApple OSS Distributions 
14970f3703acSApple OSS Distributions OSDefineMetaClassAndStructors(IOKitDiagnosticsClient, IOUserClient)
14980f3703acSApple OSS Distributions 
14990f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15000f3703acSApple OSS Distributions 
15010f3703acSApple OSS Distributions IOUserClient * IOKitDiagnosticsClient::withTask(task_t owningTask)
15020f3703acSApple OSS Distributions {
15030f3703acSApple OSS Distributions 	IOKitDiagnosticsClient * inst;
15040f3703acSApple OSS Distributions 
15050f3703acSApple OSS Distributions 	inst = new IOKitDiagnosticsClient;
1506a5e72196SApple OSS Distributions 	if (inst && !inst->init()) {
15070f3703acSApple OSS Distributions 		inst->release();
1508a5e72196SApple OSS Distributions 		inst = NULL;
15090f3703acSApple OSS Distributions 	}
15100f3703acSApple OSS Distributions 
1511a5e72196SApple OSS Distributions 	return inst;
15120f3703acSApple OSS Distributions }
15130f3703acSApple OSS Distributions 
1514a5e72196SApple OSS Distributions IOReturn
1515a5e72196SApple OSS Distributions IOKitDiagnosticsClient::clientClose(void)
15160f3703acSApple OSS Distributions {
15170f3703acSApple OSS Distributions 	terminate();
1518a5e72196SApple OSS Distributions 	return kIOReturnSuccess;
15190f3703acSApple OSS Distributions }
15200f3703acSApple OSS Distributions 
1521a5e72196SApple OSS Distributions IOReturn
1522a5e72196SApple OSS Distributions IOKitDiagnosticsClient::setProperties(OSObject * properties)
15230f3703acSApple OSS Distributions {
15240f3703acSApple OSS Distributions 	IOReturn kr = kIOReturnUnsupported;
1525a5e72196SApple OSS Distributions 	return kr;
15260f3703acSApple OSS Distributions }
15270f3703acSApple OSS Distributions 
1528a5e72196SApple OSS Distributions IOReturn
1529a5e72196SApple OSS Distributions IOKitDiagnosticsClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
15300f3703acSApple OSS Distributions     IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
15310f3703acSApple OSS Distributions {
15320f3703acSApple OSS Distributions 	IOReturn                           ret = kIOReturnBadArgument;
15330f3703acSApple OSS Distributions 	const IOKitDiagnosticsParameters * params;
15340f3703acSApple OSS Distributions 	const char * names;
15350f3703acSApple OSS Distributions 	size_t       namesLen;
15360f3703acSApple OSS Distributions 	OSObject   * result;
15370f3703acSApple OSS Distributions 
1538a5e72196SApple OSS Distributions 	if (args->structureInputSize < sizeof(IOKitDiagnosticsParameters)) {
1539a5e72196SApple OSS Distributions 		return kIOReturnBadArgument;
1540a5e72196SApple OSS Distributions 	}
15410f3703acSApple OSS Distributions 	params = (typeof(params))args->structureInput;
1542a5e72196SApple OSS Distributions 	if (!params) {
1543a5e72196SApple OSS Distributions 		return kIOReturnBadArgument;
1544a5e72196SApple OSS Distributions 	}
15450f3703acSApple OSS Distributions 
1546a5e72196SApple OSS Distributions 	names = NULL;
15470f3703acSApple OSS Distributions 	namesLen = args->structureInputSize - sizeof(IOKitDiagnosticsParameters);
1548a5e72196SApple OSS Distributions 	if (namesLen) {
1549a5e72196SApple OSS Distributions 		names = (typeof(names))(params + 1);
1550a5e72196SApple OSS Distributions 	}
15510f3703acSApple OSS Distributions 
155276e12aa3SApple OSS Distributions 	ret = IOTrackingDebug(selector, params->options, params->value, params->tag, params->zsize, names, namesLen, params->size, &result);
15530f3703acSApple OSS Distributions 
1554a5e72196SApple OSS Distributions 	if ((kIOReturnSuccess == ret) && args->structureVariableOutputData) {
1555a5e72196SApple OSS Distributions 		*args->structureVariableOutputData = result;
1556a5e72196SApple OSS Distributions 	} else if (result) {
1557a5e72196SApple OSS Distributions 		result->release();
1558a5e72196SApple OSS Distributions 	}
15590f3703acSApple OSS Distributions 
1560a5e72196SApple OSS Distributions 	return ret;
15610f3703acSApple OSS Distributions }
15620f3703acSApple OSS Distributions 
15630f3703acSApple OSS Distributions /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1564