]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOKitDebug.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOKitDebug.cpp
CommitLineData
1c79356b 1/*
39037602 2 * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
1c79356b 28
3e170ce0 29
91447636 30#include <sys/sysctl.h>
3e170ce0
A
31extern "C" {
32#include <vm/vm_kern.h>
39037602
A
33#include <kern/task.h>
34#include <kern/debug.h>
3e170ce0 35}
91447636 36
6d2010ae 37#include <libkern/c++/OSContainers.h>
3e170ce0 38#include <libkern/OSDebug.h>
6d2010ae 39#include <libkern/c++/OSCPPDebug.h>
39037602 40#include <kern/backtrace.h>
6d2010ae 41
1c79356b
A
42#include <IOKit/IOKitDebug.h>
43#include <IOKit/IOLib.h>
44#include <IOKit/assert.h>
45#include <IOKit/IODeviceTreeSupport.h>
46#include <IOKit/IOService.h>
47
39037602
A
48#include "IOKitKernelInternal.h"
49
1c79356b 50#ifdef IOKITDEBUG
91447636
A
51#define DEBUG_INIT_VALUE IOKITDEBUG
52#else
53#define DEBUG_INIT_VALUE 0
1c79356b 54#endif
91447636 55
3e170ce0
A
56SInt64 gIOKitDebug = DEBUG_INIT_VALUE;
57SInt64 gIOKitTrace = 0;
060df5ea 58
fe8ab488 59#if DEVELOPMENT || DEBUG
3e170ce0 60#define IODEBUG_CTLFLAGS CTLFLAG_RW
fe8ab488 61#else
3e170ce0 62#define IODEBUG_CTLFLAGS CTLFLAG_RD
fe8ab488
A
63#endif
64
060df5ea 65SYSCTL_QUAD(_debug, OID_AUTO, iotrace, CTLFLAG_RW | CTLFLAG_LOCKED, &gIOKitTrace, "trace io");
91447636 66
5ba3f43e
A
67static int
68sysctl_debug_iokit
69(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
70{
0a7de745
A
71 SInt64 newValue;
72 int changed, error = sysctl_io_number(req, gIOKitDebug, sizeof(gIOKitDebug), &newValue, &changed);
73 if (changed) {
74 gIOKitDebug = ((gIOKitDebug & ~kIOKitDebugUserOptions) | (newValue & kIOKitDebugUserOptions));
75 }
76 return error;
5ba3f43e
A
77}
78
79SYSCTL_PROC(_debug, OID_AUTO, iokit,
c3c9b80d 80 CTLTYPE_QUAD | IODEBUG_CTLFLAGS | CTLFLAG_KERN | CTLFLAG_LOCKED,
0a7de745 81 &gIOKitDebug, 0, sysctl_debug_iokit, "Q", "boot_arg io");
1c79356b 82
f427ee49
A
83size_t debug_malloc_size;
84size_t debug_iomalloc_size;
2d21ac55 85
3e170ce0 86vm_size_t debug_iomallocpageable_size;
f427ee49 87size_t debug_container_malloc_size;
3e170ce0 88// int debug_ivars_size; // in OSObject.cpp
1c79356b 89
91447636 90extern "C" {
b0d623f7
A
91#if 0
92#define DEBG(fmt, args...) { kprintf(fmt, ## args); }
93#else
94#define DEBG(fmt, args...) { IOLog(fmt, ## args); }
95#endif
91447636 96
0a7de745
A
97void
98IOPrintPlane( const IORegistryPlane * plane )
1c79356b 99{
0a7de745
A
100 IORegistryEntry * next;
101 IORegistryIterator * iter;
102 OSOrderedSet * all;
103 char format[] = "%xxxs";
104 IOService * service;
105
106 iter = IORegistryIterator::iterateOver( plane );
107 assert( iter );
108 all = iter->iterateAll();
109 if (all) {
110 DEBG("Count %d\n", all->getCount());
111 all->release();
112 } else {
113 DEBG("Empty\n");
114 }
115
116 iter->reset();
117 while ((next = iter->getNextObjectRecursive())) {
118 snprintf(format + 1, sizeof(format) - 1, "%ds", 2 * next->getDepth( plane ));
119 DEBG( format, "");
120 DEBG( "\033[33m%s", next->getName( plane ));
121 if ((next->getLocation( plane ))) {
122 DEBG("@%s", next->getLocation( plane ));
123 }
124 DEBG("\033[0m <class %s", next->getMetaClass()->getClassName());
125 if ((service = OSDynamicCast(IOService, next))) {
126 DEBG(", busy %ld", (long) service->getBusyState());
127 }
128 DEBG( ">\n");
3e170ce0 129// IOSleep(250);
0a7de745
A
130 }
131 iter->release();
1c79356b
A
132}
133
0a7de745
A
134void
135db_piokjunk(void)
316670eb 136{
55e303ae
A
137}
138
0a7de745
A
139void
140db_dumpiojunk( const IORegistryPlane * plane __unused )
55e303ae 141{
55e303ae
A
142}
143
0a7de745
A
144void
145IOPrintMemory( void )
1c79356b 146{
1c79356b
A
147// OSMetaClass::printInstanceCounts();
148
0a7de745 149 IOLog("\n"
f427ee49
A
150 "ivar kalloc() 0x%08lx\n"
151 "malloc() 0x%08lx\n"
152 "containers kalloc() 0x%08lx\n"
153 "IOMalloc() 0x%08lx\n"
0a7de745
A
154 "----------------------------------------\n",
155 debug_ivars_size,
156 debug_malloc_size,
157 debug_container_malloc_size,
158 debug_iomalloc_size
159 );
1c79356b 160}
1c79356b
A
161} /* extern "C" */
162
3e170ce0 163/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b
A
164
165#define super OSObject
166OSDefineMetaClassAndStructors(IOKitDiagnostics, OSObject)
167
3e170ce0 168/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b
A
169
170OSObject * IOKitDiagnostics::diagnostics( void )
171{
0a7de745 172 IOKitDiagnostics * diags;
1c79356b 173
0a7de745
A
174 diags = new IOKitDiagnostics;
175 if (diags && !diags->init()) {
176 diags->release();
cb323159 177 diags = NULL;
0a7de745 178 }
1c79356b 179
0a7de745 180 return diags;
1c79356b
A
181}
182
0a7de745
A
183void
184IOKitDiagnostics::updateOffset( OSDictionary * dict,
185 UInt64 value, const char * name )
1c79356b 186{
0a7de745 187 OSNumber * off;
1c79356b 188
0a7de745
A
189 off = OSNumber::withNumber( value, 64 );
190 if (!off) {
191 return;
192 }
1c79356b 193
0a7de745
A
194 dict->setObject( name, off );
195 off->release();
1c79356b
A
196}
197
0a7de745
A
198bool
199IOKitDiagnostics::serialize(OSSerialize *s) const
1c79356b 200{
0a7de745
A
201 OSDictionary * dict;
202 bool ok;
1c79356b 203
0a7de745
A
204 dict = OSDictionary::withCapacity( 5 );
205 if (!dict) {
206 return false;
207 }
1c79356b 208
0a7de745
A
209 updateOffset( dict, debug_ivars_size, "Instance allocation" );
210 updateOffset( dict, debug_container_malloc_size, "Container allocation" );
211 updateOffset( dict, debug_iomalloc_size, "IOMalloc allocation" );
212 updateOffset( dict, debug_iomallocpageable_size, "Pageable allocation" );
1c79356b 213
0a7de745 214 OSMetaClass::serializeClassDictionary(dict);
1c79356b 215
0a7de745 216 ok = dict->serialize( s );
1c79356b 217
0a7de745 218 dict->release();
1c79356b 219
0a7de745 220 return ok;
1c79356b
A
221}
222
3e170ce0
A
223/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
224
225#if IOTRACKING
226
227#include <libkern/c++/OSCPPDebug.h>
228#include <libkern/c++/OSKext.h>
229#include <kern/zalloc.h>
230
231__private_extern__ "C" void qsort(
0a7de745
A
232 void * array,
233 size_t nmembers,
234 size_t member_size,
235 int (*)(const void *, const void *));
3e170ce0
A
236
237extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
238extern "C" ppnum_t pmap_valid_page(ppnum_t pn);
239
240/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
241
0a7de745
A
242struct IOTRecursiveLock {
243 lck_mtx_t * mutex;
244 thread_t thread;
245 UInt32 count;
3e170ce0
A
246};
247
0a7de745
A
248struct IOTrackingQueue {
249 queue_chain_t link;
250 IOTRecursiveLock lock;
251 const char * name;
252 uintptr_t btEntry;
253 size_t allocSize;
254 size_t minCaptureSize;
255 uint32_t siteCount;
256 uint32_t type;
257 uint32_t numSiteQs;
258 uint8_t captureOn;
259 queue_head_t sites[];
3e170ce0
A
260};
261
f427ee49
A
262
263struct IOTrackingCallSiteUser {
264 pid_t pid;
265 uint8_t user32;
266 uint8_t userCount;
267 uintptr_t bt[kIOTrackingCallSiteBTs];
268};
269
0a7de745
A
270struct IOTrackingCallSite {
271 queue_chain_t link;
f427ee49 272 queue_head_t instances;
0a7de745 273 IOTrackingQueue * queue;
f427ee49
A
274 IOTracking * addresses;
275 size_t size[2];
0a7de745 276 uint32_t crc;
f427ee49 277 uint32_t count;
39037602 278
0a7de745 279 vm_tag_t tag;
f427ee49
A
280 uint8_t user32;
281 uint8_t userCount;
282 pid_t btPID;
39037602 283
f427ee49
A
284 uintptr_t bt[kIOTrackingCallSiteBTs];
285 IOTrackingCallSiteUser user[0];
3e170ce0
A
286};
287
f427ee49 288
0a7de745
A
289struct IOTrackingLeaksRef {
290 uintptr_t * instances;
291 uint32_t zoneSize;
292 uint32_t count;
293 uint32_t found;
294 uint32_t foundzlen;
295 size_t bytes;
3e170ce0
A
296};
297
3e170ce0
A
298lck_mtx_t * gIOTrackingLock;
299queue_head_t gIOTrackingQ;
300
0a7de745
A
301enum{
302 kTrackingAddressFlagAllocated = 0x00000001
3e170ce0
A
303};
304
305#if defined(__LP64__)
0a7de745 306#define IOTrackingAddressFlags(ptr) (ptr->flags)
3e170ce0 307#else
0a7de745 308#define IOTrackingAddressFlags(ptr) (ptr->tracking.flags)
3e170ce0
A
309#endif
310
311/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
312
0a7de745 313static void
3e170ce0
A
314IOTRecursiveLockLock(IOTRecursiveLock * lock)
315{
0a7de745
A
316 if (lock->thread == current_thread()) {
317 lock->count++;
318 } else {
319 lck_mtx_lock(lock->mutex);
cb323159 320 assert(lock->thread == NULL);
0a7de745
A
321 assert(lock->count == 0);
322 lock->thread = current_thread();
323 lock->count = 1;
324 }
3e170ce0
A
325}
326
0a7de745 327static void
3e170ce0
A
328IOTRecursiveLockUnlock(IOTRecursiveLock * lock)
329{
0a7de745
A
330 assert(lock->thread == current_thread());
331 if (0 == (--lock->count)) {
cb323159 332 lock->thread = NULL;
0a7de745
A
333 lck_mtx_unlock(lock->mutex);
334 }
3e170ce0
A
335}
336
337/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
338
339void
340IOTrackingInit(void)
341{
0a7de745
A
342 queue_init(&gIOTrackingQ);
343 gIOTrackingLock = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
3e170ce0
A
344}
345
346/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
347
348IOTrackingQueue *
39037602 349IOTrackingQueueAlloc(const char * name, uintptr_t btEntry,
0a7de745
A
350 size_t allocSize, size_t minCaptureSize,
351 uint32_t type, uint32_t numSiteQs)
3e170ce0 352{
0a7de745
A
353 IOTrackingQueue * queue;
354 uint32_t idx;
355
356 if (!numSiteQs) {
357 numSiteQs = 1;
358 }
359 queue = (typeof(queue))kalloc(sizeof(IOTrackingQueue) + numSiteQs * sizeof(queue->sites[0]));
360 bzero(queue, sizeof(IOTrackingQueue));
361
362 queue->name = name;
363 queue->btEntry = btEntry;
364 queue->allocSize = allocSize;
365 queue->minCaptureSize = minCaptureSize;
366 queue->lock.mutex = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
367 queue->numSiteQs = numSiteQs;
368 queue->type = type;
369 enum { kFlags = (kIOTracking | kIOTrackingBoot) };
370 queue->captureOn = (kFlags == (kFlags & gIOKitDebug))
371 || (kIOTrackingQueueTypeDefaultOn & type);
372
373 for (idx = 0; idx < numSiteQs; idx++) {
374 queue_init(&queue->sites[idx]);
375 }
376
377 lck_mtx_lock(gIOTrackingLock);
378 queue_enter(&gIOTrackingQ, queue, IOTrackingQueue *, link);
379 lck_mtx_unlock(gIOTrackingLock);
380
381 return queue;
3e170ce0
A
382};
383
f427ee49
A
384void
385IOTrackingQueueCollectUser(IOTrackingQueue * queue)
386{
387 assert(0 == queue->siteCount);
388 queue->type |= kIOTrackingQueueTypeUser;
389}
390
3e170ce0
A
391/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
392
393void
394IOTrackingQueueFree(IOTrackingQueue * queue)
395{
0a7de745
A
396 lck_mtx_lock(gIOTrackingLock);
397 IOTrackingReset(queue);
398 remque(&queue->link);
399 lck_mtx_unlock(gIOTrackingLock);
3e170ce0 400
0a7de745 401 lck_mtx_free(queue->lock.mutex, IOLockGroup);
3e170ce0 402
0a7de745 403 kfree(queue, sizeof(IOTrackingQueue) + queue->numSiteQs * sizeof(queue->sites[0]));
3e170ce0
A
404};
405
406/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
407
408/* fasthash
0a7de745
A
409 * The MIT License
410 *
411 * Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
412 *
413 * Permission is hereby granted, free of charge, to any person
414 * obtaining a copy of this software and associated documentation
415 * files (the "Software"), to deal in the Software without
416 * restriction, including without limitation the rights to use, copy,
417 * modify, merge, publish, distribute, sublicense, and/or sell copies
418 * of the Software, and to permit persons to whom the Software is
419 * furnished to do so, subject to the following conditions:
420 *
421 * The above copyright notice and this permission notice shall be
422 * included in all copies or substantial portions of the Software.
423 *
424 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
425 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
426 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
427 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
428 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
429 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
430 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
431 * SOFTWARE.
432 */
3e170ce0
A
433
434
435// Compression function for Merkle-Damgard construction.
436// This function is generated using the framework provided.
437#define mix(h) ({ \
0a7de745
A
438 (h) ^= (h) >> 23; \
439 (h) *= 0x2127599bf4325c37ULL; \
440 (h) ^= (h) >> 47; })
3e170ce0
A
441
442static uint64_t
443fasthash64(const void *buf, size_t len, uint64_t seed)
444{
0a7de745
A
445 const uint64_t m = 0x880355f21e6d1965ULL;
446 const uint64_t *pos = (const uint64_t *)buf;
447 const uint64_t *end = pos + (len / 8);
448 const unsigned char *pos2;
449 uint64_t h = seed ^ (len * m);
450 uint64_t v;
451
452 while (pos != end) {
453 v = *pos++;
454 h ^= mix(v);
455 h *= m;
456 }
457
458 pos2 = (const unsigned char*)pos;
459 v = 0;
460
461 switch (len & 7) {
462 case 7: v ^= (uint64_t)pos2[6] << 48;
463 [[clang::fallthrough]];
464 case 6: v ^= (uint64_t)pos2[5] << 40;
465 [[clang::fallthrough]];
466 case 5: v ^= (uint64_t)pos2[4] << 32;
467 [[clang::fallthrough]];
468 case 4: v ^= (uint64_t)pos2[3] << 24;
469 [[clang::fallthrough]];
470 case 3: v ^= (uint64_t)pos2[2] << 16;
471 [[clang::fallthrough]];
472 case 2: v ^= (uint64_t)pos2[1] << 8;
473 [[clang::fallthrough]];
474 case 1: v ^= (uint64_t)pos2[0];
475 h ^= mix(v);
476 h *= m;
477 }
478
479 return mix(h);
480}
3e170ce0
A
481
482/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
483
484static uint32_t
485fasthash32(const void *buf, size_t len, uint32_t seed)
486{
0a7de745
A
487 // the following trick converts the 64-bit hashcode to Fermat
488 // residue, which shall retain information from both the higher
489 // and lower parts of hashcode.
490 uint64_t h = fasthash64(buf, len, seed);
f427ee49 491 return (uint32_t) (h - (h >> 32));
3e170ce0
A
492}
493
494/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
495
39037602
A
496void
497IOTrackingAddUser(IOTrackingQueue * queue, IOTrackingUser * mem, vm_size_t size)
498{
0a7de745 499 uint32_t num;
f427ee49 500 int pid;
0a7de745
A
501
502 if (!queue->captureOn) {
503 return;
504 }
505 if (size < queue->minCaptureSize) {
506 return;
507 }
508
509 assert(!mem->link.next);
510
cb323159 511 num = backtrace(&mem->bt[0], kIOTrackingCallSiteBTs, NULL);
0a7de745 512 num = 0;
f427ee49 513 if ((kernel_task != current_task()) && (pid = proc_selfpid())) {
cb323159 514 bool user_64 = false;
f427ee49 515 mem->btPID = pid;
ea3f0419 516 num = backtrace_user(&mem->btUser[0], kIOTrackingCallSiteBTs - 1, NULL,
cb323159 517 &user_64, NULL);
0a7de745 518 mem->user32 = !user_64;
0a7de745
A
519 }
520 assert(num <= kIOTrackingCallSiteBTs);
f427ee49
A
521 static_assert(kIOTrackingCallSiteBTs <= UINT8_MAX);
522 mem->userCount = ((uint8_t) num);
0a7de745
A
523
524 IOTRecursiveLockLock(&queue->lock);
525 queue_enter/*last*/ (&queue->sites[0], mem, IOTrackingUser *, link);
526 queue->siteCount++;
527 IOTRecursiveLockUnlock(&queue->lock);
39037602
A
528}
529
530void
531IOTrackingRemoveUser(IOTrackingQueue * queue, IOTrackingUser * mem)
532{
0a7de745
A
533 if (!mem->link.next) {
534 return;
535 }
536
537 IOTRecursiveLockLock(&queue->lock);
538 if (mem->link.next) {
539 remque(&mem->link);
540 assert(queue->siteCount);
541 queue->siteCount--;
542 }
543 IOTRecursiveLockUnlock(&queue->lock);
39037602
A
544}
545
546uint64_t gIOTrackingAddTime;
547
3e170ce0 548void
5ba3f43e 549IOTrackingAdd(IOTrackingQueue * queue, IOTracking * mem, size_t size, bool address, vm_tag_t tag)
3e170ce0 550{
0a7de745
A
551 IOTrackingCallSite * site;
552 uint32_t crc, num;
553 uintptr_t bt[kIOTrackingCallSiteBTs + 1];
f427ee49 554 uintptr_t btUser[kIOTrackingCallSiteBTs];
0a7de745 555 queue_head_t * que;
f427ee49
A
556 bool user;
557 int pid;
558 int userCount;
559 bool user64;
0a7de745
A
560
561 if (mem->site) {
562 return;
563 }
564 if (!queue->captureOn) {
565 return;
566 }
567 if (size < queue->minCaptureSize) {
568 return;
569 }
570
f427ee49
A
571 user = (0 != (kIOTrackingQueueTypeUser & queue->type));
572
0a7de745
A
573 assert(!mem->link.next);
574
cb323159 575 num = backtrace(&bt[0], kIOTrackingCallSiteBTs + 1, NULL);
0a7de745
A
576 if (!num) {
577 return;
578 }
579 num--;
580 crc = fasthash32(&bt[1], num * sizeof(bt[0]), 0x04C11DB7);
581
f427ee49
A
582 userCount = 0;
583 user64 = false;
584 pid = 0;
585 if (user) {
586 if ((kernel_task != current_task()) && (pid = proc_selfpid())) {
587 userCount = backtrace_user(&btUser[0], kIOTrackingCallSiteBTs, NULL, &user64, NULL);
588 assert(userCount <= kIOTrackingCallSiteBTs);
589 crc = fasthash32(&btUser[0], userCount * sizeof(bt[0]), crc);
590 }
591 }
592
0a7de745
A
593 IOTRecursiveLockLock(&queue->lock);
594 que = &queue->sites[crc % queue->numSiteQs];
595 queue_iterate(que, site, IOTrackingCallSite *, link)
596 {
597 if (tag != site->tag) {
598 continue;
599 }
f427ee49
A
600 if (user && (pid != site->user[0].pid)) {
601 continue;
602 }
0a7de745
A
603 if (crc == site->crc) {
604 break;
605 }
606 }
607
608 if (queue_end(que, (queue_entry_t) site)) {
f427ee49
A
609 size_t siteSize = sizeof(IOTrackingCallSite);
610 if (user) {
611 siteSize += sizeof(IOTrackingCallSiteUser);
612 }
613 site = (typeof(site))kalloc(siteSize);
0a7de745
A
614
615 queue_init(&site->instances);
616 site->addresses = (IOTracking *) &site->instances;
617 site->queue = queue;
618 site->crc = crc;
619 site->count = 0;
620 site->tag = tag;
621 memset(&site->size[0], 0, sizeof(site->size));
622 bcopy(&bt[1], &site->bt[0], num * sizeof(site->bt[0]));
623 assert(num <= kIOTrackingCallSiteBTs);
624 bzero(&site->bt[num], (kIOTrackingCallSiteBTs - num) * sizeof(site->bt[0]));
f427ee49
A
625 if (user) {
626 bcopy(&btUser[0], &site->user[0].bt[0], userCount * sizeof(site->user[0].bt[0]));
627 assert(userCount <= kIOTrackingCallSiteBTs);
628 bzero(&site->user[0].bt[userCount], (kIOTrackingCallSiteBTs - userCount) * sizeof(site->user[0].bt[0]));
629 site->user[0].pid = pid;
630 site->user[0].user32 = !user64;
631 static_assert(kIOTrackingCallSiteBTs <= UINT8_MAX);
632 site->user[0].userCount = ((uint8_t) userCount);
633 }
0a7de745
A
634 queue_enter_first(que, site, IOTrackingCallSite *, link);
635 queue->siteCount++;
636 }
637
638 if (address) {
639 queue_enter/*last*/ (&site->instances, mem, IOTracking *, link);
640 if (queue_end(&site->instances, (queue_entry_t)site->addresses)) {
641 site->addresses = mem;
642 }
643 } else {
644 queue_enter_first(&site->instances, mem, IOTracking *, link);
645 }
646
647 mem->site = site;
648 site->size[0] += size;
649 site->count++;
650
651 IOTRecursiveLockUnlock(&queue->lock);
3e170ce0
A
652}
653
654/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
655
656void
657IOTrackingRemove(IOTrackingQueue * queue, IOTracking * mem, size_t size)
658{
0a7de745
A
659 if (!mem->link.next) {
660 return;
661 }
662
663 IOTRecursiveLockLock(&queue->lock);
664 if (mem->link.next) {
665 assert(mem->site);
666
667 if (mem == mem->site->addresses) {
668 mem->site->addresses = (IOTracking *) queue_next(&mem->link);
669 }
670 remque(&mem->link);
671
672 assert(mem->site->count);
673 mem->site->count--;
674 assert(mem->site->size[0] >= size);
675 mem->site->size[0] -= size;
676 if (!mem->site->count) {
677 assert(queue_empty(&mem->site->instances));
678 assert(!mem->site->size[0]);
679 assert(!mem->site->size[1]);
680
681 remque(&mem->site->link);
682 assert(queue->siteCount);
683 queue->siteCount--;
f427ee49
A
684 size_t siteSize = sizeof(IOTrackingCallSite);
685 if (kIOTrackingQueueTypeUser & queue->type) {
686 siteSize += sizeof(IOTrackingCallSiteUser);
687 }
688 kfree(mem->site, siteSize);
0a7de745
A
689 }
690 mem->site = NULL;
691 }
692 IOTRecursiveLockUnlock(&queue->lock);
3e170ce0
A
693}
694
695/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
696
697void
698IOTrackingAlloc(IOTrackingQueue * queue, uintptr_t address, size_t size)
699{
0a7de745
A
700 IOTrackingAddress * tracking;
701
702 if (!queue->captureOn) {
703 return;
704 }
705 if (size < queue->minCaptureSize) {
706 return;
707 }
708
709 address = ~address;
710 tracking = (typeof(tracking))kalloc(sizeof(IOTrackingAddress));
711 bzero(tracking, sizeof(IOTrackingAddress));
712 IOTrackingAddressFlags(tracking) |= kTrackingAddressFlagAllocated;
713 tracking->address = address;
714 tracking->size = size;
715
716 IOTrackingAdd(queue, &tracking->tracking, size, true, VM_KERN_MEMORY_NONE);
3e170ce0
A
717}
718
719/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
720
721void
722IOTrackingFree(IOTrackingQueue * queue, uintptr_t address, size_t size)
723{
0a7de745
A
724 IOTrackingCallSite * site;
725 IOTrackingAddress * tracking;
726 uint32_t idx;
727 bool done;
728
729 address = ~address;
730 IOTRecursiveLockLock(&queue->lock);
731 done = false;
732 for (idx = 0; idx < queue->numSiteQs; idx++) {
733 queue_iterate(&queue->sites[idx], site, IOTrackingCallSite *, link)
734 {
735 tracking = (IOTrackingAddress *) site->addresses;
736 while (!queue_end(&site->instances, &tracking->tracking.link)) {
737 if ((done = (address == tracking->address))) {
738 IOTrackingRemove(queue, &tracking->tracking, size);
739 kfree(tracking, sizeof(IOTrackingAddress));
740 break;
741 } else {
742 tracking = (IOTrackingAddress *) queue_next(&tracking->tracking.link);
743 }
744 }
745 if (done) {
746 break;
747 }
748 }
749 if (done) {
750 break;
751 }
752 }
753 IOTRecursiveLockUnlock(&queue->lock);
3e170ce0
A
754}
755
756/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
757
758void
759IOTrackingAccumSize(IOTrackingQueue * queue, IOTracking * mem, size_t size)
760{
0a7de745
A
761 IOTRecursiveLockLock(&queue->lock);
762 if (mem->link.next) {
763 assert(mem->site);
764 assert((size > 0) || (mem->site->size[1] >= -size));
765 mem->site->size[1] += size;
766 }
767 ;
768 IOTRecursiveLockUnlock(&queue->lock);
3e170ce0
A
769}
770
771/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
772
773void
774IOTrackingReset(IOTrackingQueue * queue)
775{
0a7de745
A
776 IOTrackingCallSite * site;
777 IOTrackingUser * user;
778 IOTracking * tracking;
779 IOTrackingAddress * trackingAddress;
780 uint32_t idx;
781 bool addresses;
782
783 IOTRecursiveLockLock(&queue->lock);
784 for (idx = 0; idx < queue->numSiteQs; idx++) {
785 while (!queue_empty(&queue->sites[idx])) {
786 if (kIOTrackingQueueTypeMap & queue->type) {
787 queue_remove_first(&queue->sites[idx], user, IOTrackingUser *, link);
788 user->link.next = user->link.prev = NULL;
789 } else {
790 queue_remove_first(&queue->sites[idx], site, IOTrackingCallSite *, link);
791 addresses = false;
792 while (!queue_empty(&site->instances)) {
793 queue_remove_first(&site->instances, tracking, IOTracking *, link);
794 if (tracking == site->addresses) {
795 addresses = true;
796 }
797 if (addresses) {
798 trackingAddress = (typeof(trackingAddress))tracking;
799 if (kTrackingAddressFlagAllocated & IOTrackingAddressFlags(trackingAddress)) {
800 kfree(tracking, sizeof(IOTrackingAddress));
801 }
802 }
803 }
f427ee49
A
804 size_t siteSize = sizeof(IOTrackingCallSite);
805 if (kIOTrackingQueueTypeUser & queue->type) {
806 siteSize += sizeof(IOTrackingCallSiteUser);
807 }
808 kfree(site, siteSize);
0a7de745
A
809 }
810 }
811 }
812 queue->siteCount = 0;
813 IOTRecursiveLockUnlock(&queue->lock);
3e170ce0
A
814}
815
816/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
817
818static int
819IOTrackingCallSiteInfoCompare(const void * left, const void * right)
820{
0a7de745
A
821 IOTrackingCallSiteInfo * l = (typeof(l))left;
822 IOTrackingCallSiteInfo * r = (typeof(r))right;
823 size_t lsize, rsize;
3e170ce0 824
0a7de745
A
825 rsize = r->size[0] + r->size[1];
826 lsize = l->size[0] + l->size[1];
3e170ce0 827
0a7de745 828 return (rsize > lsize) ? 1 : ((rsize == lsize) ? 0 : -1);
3e170ce0
A
829}
830
831/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
832
833static int
834IOTrackingAddressCompare(const void * left, const void * right)
835{
0a7de745
A
836 IOTracking * instance;
837 uintptr_t inst, laddr, raddr;
838
839 inst = ((typeof(inst) *)left)[0];
840 instance = (typeof(instance))INSTANCE_GET(inst);
841 if (kInstanceFlagAddress & inst) {
842 laddr = ~((IOTrackingAddress *)instance)->address;
843 } else {
844 laddr = (uintptr_t) (instance + 1);
845 }
3e170ce0 846
0a7de745
A
847 inst = ((typeof(inst) *)right)[0];
848 instance = (typeof(instance))(inst & ~kInstanceFlags);
849 if (kInstanceFlagAddress & inst) {
850 raddr = ~((IOTrackingAddress *)instance)->address;
851 } else {
852 raddr = (uintptr_t) (instance + 1);
853 }
3e170ce0 854
0a7de745 855 return (laddr > raddr) ? 1 : ((laddr == raddr) ? 0 : -1);
3e170ce0
A
856}
857
39037602
A
858
859static int
860IOTrackingZoneElementCompare(const void * left, const void * right)
861{
0a7de745 862 uintptr_t inst, laddr, raddr;
39037602 863
0a7de745
A
864 inst = ((typeof(inst) *)left)[0];
865 laddr = INSTANCE_PUT(inst);
866 inst = ((typeof(inst) *)right)[0];
867 raddr = INSTANCE_PUT(inst);
39037602 868
0a7de745 869 return (laddr > raddr) ? 1 : ((laddr == raddr) ? 0 : -1);
39037602
A
870}
871
872/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
873
874static void
f427ee49 875CopyOutBacktraces(IOTrackingCallSite * site, IOTrackingCallSiteInfo * siteInfo)
39037602 876{
0a7de745
A
877 uint32_t j;
878 mach_vm_address_t bt, btEntry;
879
880 btEntry = site->queue->btEntry;
881 for (j = 0; j < kIOTrackingCallSiteBTs; j++) {
882 bt = site->bt[j];
883 if (btEntry
884 && (!bt || (j == (kIOTrackingCallSiteBTs - 1)))) {
885 bt = btEntry;
886 btEntry = 0;
887 }
888 siteInfo->bt[0][j] = VM_KERNEL_UNSLIDE(bt);
889 }
f427ee49
A
890
891 siteInfo->btPID = 0;
892 if (kIOTrackingQueueTypeUser & site->queue->type) {
893 siteInfo->btPID = site->user[0].pid;
894 uint32_t * bt32 = (typeof(bt32))((void *) &site->user[0].bt[0]);
895 uint64_t * bt64 = (typeof(bt64))((void *) &site->user[0].bt[0]);
896 for (uint32_t j = 0; j < kIOTrackingCallSiteBTs; j++) {
897 if (j >= site->user[0].userCount) {
898 siteInfo->bt[1][j] = 0;
899 } else if (site->user[0].user32) {
900 siteInfo->bt[1][j] = bt32[j];
901 } else {
902 siteInfo->bt[1][j] = bt64[j];
903 }
904 }
905 }
39037602
A
906}
907
3e170ce0
A
908/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
909
910static void
911IOTrackingLeakScan(void * refcon)
912{
0a7de745
A
913 IOTrackingLeaksRef * ref = (typeof(ref))refcon;
914 uintptr_t * instances;
915 IOTracking * instance;
916 uint64_t vaddr, vincr;
917 ppnum_t ppn;
918 uintptr_t ptr, addr, vphysaddr, inst;
919 size_t size, origsize;
920 uint32_t baseIdx, lim, ptrIdx, count;
921 boolean_t is;
922 AbsoluteTime deadline;
923
924 instances = ref->instances;
925 count = ref->count;
926 size = origsize = ref->zoneSize;
927
928 for (deadline = 0, vaddr = VM_MIN_KERNEL_AND_KEXT_ADDRESS;
929 ;
930 vaddr += vincr) {
931 if ((mach_absolute_time() > deadline) || (vaddr >= VM_MAX_KERNEL_ADDRESS)) {
932 if (deadline) {
933 ml_set_interrupts_enabled(is);
934 IODelay(10);
935 }
936 if (vaddr >= VM_MAX_KERNEL_ADDRESS) {
937 break;
938 }
939 is = ml_set_interrupts_enabled(false);
940 clock_interval_to_deadline(10, kMillisecondScale, &deadline);
941 }
942
943 ppn = kernel_pmap_present_mapping(vaddr, &vincr, &vphysaddr);
944 // check noencrypt to avoid VM structs (map entries) with pointers
945 if (ppn && (!pmap_valid_page(ppn) || (!ref->zoneSize && pmap_is_noencrypt(ppn)))) {
946 ppn = 0;
947 }
948 if (!ppn) {
949 continue;
950 }
951
952 for (ptrIdx = 0; ptrIdx < (page_size / sizeof(uintptr_t)); ptrIdx++) {
953 ptr = ((uintptr_t *)vphysaddr)[ptrIdx];
94ff46dc
A
954#if defined(HAS_APPLE_PAC)
955 // strip possible ptrauth signature from candidate data pointer
956 ptr = (uintptr_t)ptrauth_strip((void*)ptr, ptrauth_key_process_independent_data);
957#endif /* defined(HAS_APPLE_PAC) */
0a7de745
A
958
959 for (lim = count, baseIdx = 0; lim; lim >>= 1) {
960 inst = instances[baseIdx + (lim >> 1)];
961 instance = (typeof(instance))INSTANCE_GET(inst);
962
963 if (ref->zoneSize) {
964 addr = INSTANCE_PUT(inst) & ~kInstanceFlags;
965 } else if (kInstanceFlagAddress & inst) {
966 addr = ~((IOTrackingAddress *)instance)->address;
967 origsize = size = ((IOTrackingAddress *)instance)->size;
968 if (!size) {
969 size = 1;
970 }
971 } else {
972 addr = (uintptr_t) (instance + 1);
973 origsize = size = instance->site->queue->allocSize;
974 }
975 if ((ptr >= addr) && (ptr < (addr + size))
976
977 && (((vaddr + ptrIdx * sizeof(uintptr_t)) < addr)
978 || ((vaddr + ptrIdx * sizeof(uintptr_t)) >= (addr + size)))) {
979 if (!(kInstanceFlagReferenced & inst)) {
980 inst |= kInstanceFlagReferenced;
981 instances[baseIdx + (lim >> 1)] = inst;
982 ref->found++;
983 if (!origsize) {
984 ref->foundzlen++;
985 }
986 }
987 break;
988 }
989 if (ptr > addr) {
990 // move right
991 baseIdx += (lim >> 1) + 1;
992 lim--;
993 }
994 // else move left
995 }
996 }
997 ref->bytes += page_size;
998 }
3e170ce0
A
999}
1000
39037602
A
1001/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1002
1003extern "C" void
1004zone_leaks_scan(uintptr_t * instances, uint32_t count, uint32_t zoneSize, uint32_t * found)
1005{
0a7de745
A
1006 IOTrackingLeaksRef ref;
1007 IOTrackingCallSiteInfo siteInfo;
1008 uint32_t idx;
1009
1010 qsort(instances, count, sizeof(*instances), &IOTrackingZoneElementCompare);
1011
1012 bzero(&siteInfo, sizeof(siteInfo));
1013 bzero(&ref, sizeof(ref));
1014 ref.instances = instances;
1015 ref.count = count;
1016 ref.zoneSize = zoneSize;
1017
1018 for (idx = 0; idx < 2; idx++) {
1019 ref.bytes = 0;
1020 IOTrackingLeakScan(&ref);
1021 IOLog("leaks(%d) scanned %ld MB, instance count %d, found %d\n", idx, ref.bytes / 1024 / 1024, count, ref.found);
1022 if (count <= ref.found) {
1023 break;
1024 }
1025 }
1026
1027 *found = ref.found;
39037602
A
1028}
1029
1030/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1031
1032static void
1033ZoneSiteProc(void * refCon, uint32_t siteCount, uint32_t zoneSize,
0a7de745 1034 uintptr_t * backtrace, uint32_t btCount)
39037602 1035{
0a7de745
A
1036 IOTrackingCallSiteInfo siteInfo;
1037 OSData * leakData;
1038 uint32_t idx;
39037602 1039
0a7de745 1040 leakData = (typeof(leakData))refCon;
39037602 1041
0a7de745
A
1042 bzero(&siteInfo, sizeof(siteInfo));
1043 siteInfo.count = siteCount;
1044 siteInfo.size[0] = zoneSize * siteCount;
39037602 1045
0a7de745
A
1046 for (idx = 0; (idx < btCount) && (idx < kIOTrackingCallSiteBTs); idx++) {
1047 siteInfo.bt[0][idx] = VM_KERNEL_UNSLIDE(backtrace[idx]);
1048 }
39037602 1049
0a7de745 1050 leakData->appendBytes(&siteInfo, sizeof(siteInfo));
39037602
A
1051}
1052
1053
3e170ce0
A
1054/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1055
1056static OSData *
0a7de745 1057IOTrackingLeaks(LIBKERN_CONSUMED OSData * data)
3e170ce0 1058{
0a7de745
A
1059 IOTrackingLeaksRef ref;
1060 IOTrackingCallSiteInfo siteInfo;
1061 IOTrackingCallSite * site;
1062 OSData * leakData;
1063 uintptr_t * instances;
1064 IOTracking * instance;
1065 uintptr_t inst;
1066 uint32_t count, idx, numSites, dups, siteCount;
1067
1068 instances = (typeof(instances))data->getBytesNoCopy();
1069 count = (data->getLength() / sizeof(*instances));
1070 qsort(instances, count, sizeof(*instances), &IOTrackingAddressCompare);
1071
1072 bzero(&siteInfo, sizeof(siteInfo));
1073 bzero(&ref, sizeof(ref));
1074 ref.instances = instances;
1075 ref.count = count;
1076 for (idx = 0; idx < 2; idx++) {
1077 ref.bytes = 0;
1078 IOTrackingLeakScan(&ref);
1079 IOLog("leaks(%d) scanned %ld MB, instance count %d, found %d (zlen %d)\n", idx, ref.bytes / 1024 / 1024, count, ref.found, ref.foundzlen);
1080 if (count <= ref.found) {
1081 break;
1082 }
1083 }
1084
1085 leakData = OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo));
1086
1087 for (numSites = 0, idx = 0; idx < count; idx++) {
1088 inst = instances[idx];
1089 if (kInstanceFlagReferenced & inst) {
1090 continue;
1091 }
1092 instance = (typeof(instance))INSTANCE_GET(inst);
1093 site = instance->site;
1094 instances[numSites] = (uintptr_t) site;
1095 numSites++;
3e170ce0 1096 }
0a7de745
A
1097
1098 for (idx = 0; idx < numSites; idx++) {
1099 inst = instances[idx];
1100 if (!inst) {
1101 continue;
1102 }
1103 site = (typeof(site))inst;
1104 for (siteCount = 1, dups = (idx + 1); dups < numSites; dups++) {
1105 if (instances[dups] == (uintptr_t) site) {
1106 siteCount++;
1107 instances[dups] = 0;
1108 }
1109 }
1110 siteInfo.count = siteCount;
1111 siteInfo.size[0] = (site->size[0] * site->count) / siteCount;
1112 siteInfo.size[1] = (site->size[1] * site->count) / siteCount;;
f427ee49 1113 CopyOutBacktraces(site, &siteInfo);
0a7de745
A
1114 leakData->appendBytes(&siteInfo, sizeof(siteInfo));
1115 }
1116 data->release();
1117
1118 return leakData;
3e170ce0
A
1119}
1120
1121/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1122
1123static bool
1124SkipName(uint32_t options, const char * name, size_t namesLen, const char * names)
1125{
0a7de745
A
1126 const char * scan;
1127 const char * next;
1128 bool exclude, found;
1129 size_t qLen, sLen;
1130
1131 if (!namesLen || !names) {
1132 return false;
1133 }
1134 // <len><name>...<len><name><0>
1135 exclude = (0 != (kIOTrackingExcludeNames & options));
1136 qLen = strlen(name);
1137 scan = names;
1138 found = false;
1139 do{
1140 sLen = scan[0];
1141 scan++;
1142 next = scan + sLen;
1143 if (next >= (names + namesLen)) {
1144 break;
1145 }
1146 found = ((sLen == qLen) && !strncmp(scan, name, sLen));
1147 scan = next;
1148 }while (!found && (scan < (names + namesLen)));
1149
1150 return !(exclude ^ found);
3e170ce0
A
1151}
1152
1153#endif /* IOTRACKING */
1154
1155/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1156
5ba3f43e 1157static kern_return_t
39037602 1158IOTrackingDebug(uint32_t selector, uint32_t options, uint64_t value,
0a7de745
A
1159 uint32_t intag, uint32_t inzsize,
1160 const char * names, size_t namesLen,
1161 size_t size, OSObject ** result)
3e170ce0 1162{
0a7de745
A
1163 kern_return_t ret;
1164 OSData * data;
3e170ce0 1165
0a7de745 1166 if (result) {
cb323159 1167 *result = NULL;
0a7de745 1168 }
cb323159 1169 data = NULL;
0a7de745 1170 ret = kIOReturnNotReady;
3e170ce0
A
1171
1172#if IOTRACKING
1173
0a7de745
A
1174 kern_return_t kr;
1175 IOTrackingQueue * queue;
1176 IOTracking * instance;
1177 IOTrackingCallSite * site;
1178 IOTrackingCallSiteInfo siteInfo;
1179 IOTrackingUser * user;
1180 task_t mapTask;
1181 mach_vm_address_t mapAddress;
1182 mach_vm_size_t mapSize;
1183 uint32_t num, idx, qIdx;
1184 uintptr_t instFlags;
1185 proc_t proc;
1186 bool addresses;
1187
1188 ret = kIOReturnNotFound;
1189 proc = NULL;
1190 if (kIOTrackingGetMappings == selector) {
1191 if (value != -1ULL) {
f427ee49 1192 proc = proc_find((pid_t) value);
0a7de745
A
1193 if (!proc) {
1194 return kIOReturnNotFound;
1195 }
1196 }
39037602 1197 }
0a7de745
A
1198
1199 bzero(&siteInfo, sizeof(siteInfo));
1200 lck_mtx_lock(gIOTrackingLock);
1201 queue_iterate(&gIOTrackingQ, queue, IOTrackingQueue *, link)
39037602 1202 {
0a7de745
A
1203 if (SkipName(options, queue->name, namesLen, names)) {
1204 continue;
1205 }
1206
1207 if (!(kIOTracking & gIOKitDebug) && (kIOTrackingQueueTypeAlloc & queue->type)) {
1208 continue;
1209 }
1210
1211 switch (selector) {
1212 case kIOTrackingResetTracking:
1213 {
1214 IOTrackingReset(queue);
1215 ret = kIOReturnSuccess;
1216 break;
1217 }
1218
1219 case kIOTrackingStartCapture:
1220 case kIOTrackingStopCapture:
1221 {
1222 queue->captureOn = (kIOTrackingStartCapture == selector);
1223 ret = kIOReturnSuccess;
1224 break;
1225 }
1226
1227 case kIOTrackingSetMinCaptureSize:
1228 {
1229 queue->minCaptureSize = size;
1230 ret = kIOReturnSuccess;
1231 break;
1232 }
1233
1234 case kIOTrackingLeaks:
1235 {
1236 if (!(kIOTrackingQueueTypeAlloc & queue->type)) {
1237 break;
1238 }
1239
1240 if (!data) {
1241 data = OSData::withCapacity(1024 * sizeof(uintptr_t));
1242 }
1243
1244 IOTRecursiveLockLock(&queue->lock);
1245 for (idx = 0; idx < queue->numSiteQs; idx++) {
1246 queue_iterate(&queue->sites[idx], site, IOTrackingCallSite *, link)
1247 {
1248 addresses = false;
1249 queue_iterate(&site->instances, instance, IOTracking *, link)
1250 {
1251 if (instance == site->addresses) {
1252 addresses = true;
1253 }
1254 instFlags = (typeof(instFlags))instance;
1255 if (addresses) {
1256 instFlags |= kInstanceFlagAddress;
1257 }
1258 data->appendBytes(&instFlags, sizeof(instFlags));
1259 }
1260 }
1261 }
1262 // queue is locked
1263 ret = kIOReturnSuccess;
1264 break;
1265 }
1266
1267
1268 case kIOTrackingGetTracking:
1269 {
1270 if (kIOTrackingQueueTypeMap & queue->type) {
1271 break;
1272 }
1273
1274 if (!data) {
1275 data = OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo));
1276 }
1277
1278 IOTRecursiveLockLock(&queue->lock);
1279 num = queue->siteCount;
1280 idx = 0;
1281 for (qIdx = 0; qIdx < queue->numSiteQs; qIdx++) {
1282 queue_iterate(&queue->sites[qIdx], site, IOTrackingCallSite *, link)
1283 {
1284 assert(idx < num);
1285 idx++;
1286
1287 size_t tsize[2];
1288 uint32_t count = site->count;
1289 tsize[0] = site->size[0];
1290 tsize[1] = site->size[1];
1291
1292 if (intag || inzsize) {
1293 uintptr_t addr;
1294 vm_size_t size, zoneSize;
1295 vm_tag_t tag;
1296
1297 if (kIOTrackingQueueTypeAlloc & queue->type) {
1298 addresses = false;
1299 count = 0;
1300 tsize[0] = tsize[1] = 0;
1301 queue_iterate(&site->instances, instance, IOTracking *, link)
1302 {
1303 if (instance == site->addresses) {
1304 addresses = true;
1305 }
1306
1307 if (addresses) {
1308 addr = ~((IOTrackingAddress *)instance)->address;
1309 } else {
1310 addr = (uintptr_t) (instance + 1);
1311 }
1312
1313 kr = vm_kern_allocation_info(addr, &size, &tag, &zoneSize);
1314 if (KERN_SUCCESS != kr) {
1315 continue;
1316 }
1317
1318 if ((VM_KERN_MEMORY_NONE != intag) && (intag != tag)) {
1319 continue;
1320 }
1321 if (inzsize && (inzsize != zoneSize)) {
1322 continue;
1323 }
1324
1325 count++;
1326 tsize[0] += size;
1327 }
1328 } else {
1329 if (!intag || inzsize || (intag != site->tag)) {
1330 continue;
1331 }
1332 }
1333 }
1334
1335 if (!count) {
1336 continue;
1337 }
1338 if (size && ((tsize[0] + tsize[1]) < size)) {
1339 continue;
1340 }
0a7de745
A
1341 siteInfo.count = count;
1342 siteInfo.size[0] = tsize[0];
1343 siteInfo.size[1] = tsize[1];
f427ee49 1344 CopyOutBacktraces(site, &siteInfo);
0a7de745
A
1345 data->appendBytes(&siteInfo, sizeof(siteInfo));
1346 }
1347 }
1348 assert(idx == num);
1349 IOTRecursiveLockUnlock(&queue->lock);
1350 ret = kIOReturnSuccess;
1351 break;
1352 }
1353
1354 case kIOTrackingGetMappings:
1355 {
1356 if (!(kIOTrackingQueueTypeMap & queue->type)) {
1357 break;
1358 }
1359 if (!data) {
f427ee49 1360 data = OSData::withCapacity((unsigned int) page_size);
0a7de745
A
1361 }
1362
1363 IOTRecursiveLockLock(&queue->lock);
1364 num = queue->siteCount;
1365 idx = 0;
1366 for (qIdx = 0; qIdx < queue->numSiteQs; qIdx++) {
1367 queue_iterate(&queue->sites[qIdx], user, IOTrackingUser *, link)
1368 {
1369 assert(idx < num);
1370 idx++;
1371
1372 kr = IOMemoryMapTracking(user, &mapTask, &mapAddress, &mapSize);
1373 if (kIOReturnSuccess != kr) {
1374 continue;
1375 }
1376 if (proc && (mapTask != proc_task(proc))) {
1377 continue;
1378 }
1379 if (size && (mapSize < size)) {
1380 continue;
1381 }
1382
1383 siteInfo.count = 1;
1384 siteInfo.size[0] = mapSize;
1385 siteInfo.address = mapAddress;
1386 siteInfo.addressPID = task_pid(mapTask);
1387 siteInfo.btPID = user->btPID;
1388
1389 for (uint32_t j = 0; j < kIOTrackingCallSiteBTs; j++) {
1390 siteInfo.bt[0][j] = VM_KERNEL_UNSLIDE(user->bt[j]);
1391 }
1392 uint32_t * bt32 = (typeof(bt32)) & user->btUser[0];
1393 uint64_t * bt64 = (typeof(bt64))((void *) &user->btUser[0]);
1394 for (uint32_t j = 0; j < kIOTrackingCallSiteBTs; j++) {
1395 if (j >= user->userCount) {
1396 siteInfo.bt[1][j] = 0;
1397 } else if (user->user32) {
1398 siteInfo.bt[1][j] = bt32[j];
1399 } else {
1400 siteInfo.bt[1][j] = bt64[j];
1401 }
1402 }
1403 data->appendBytes(&siteInfo, sizeof(siteInfo));
1404 }
1405 }
1406 assert(idx == num);
1407 IOTRecursiveLockUnlock(&queue->lock);
1408 ret = kIOReturnSuccess;
1409 break;
1410 }
1411
1412 default:
1413 ret = kIOReturnUnsupported;
1414 break;
1415 }
1416 }
1417
1418 if ((kIOTrackingLeaks == selector) && data) {
1419 data = IOTrackingLeaks(data);
1420 queue_iterate(&gIOTrackingQ, queue, IOTrackingQueue *, link)
1421 {
1422 if (SkipName(options, queue->name, namesLen, names)) {
1423 continue;
1424 }
1425 if (!(kIOTrackingQueueTypeAlloc & queue->type)) {
1426 continue;
1427 }
1428 IOTRecursiveLockUnlock(&queue->lock);
1429 }
1430 }
1431
1432 lck_mtx_unlock(gIOTrackingLock);
1433
1434 if ((kIOTrackingLeaks == selector) && namesLen && names) {
1435 const char * scan;
1436 const char * next;
f427ee49 1437 uint8_t sLen;
0a7de745
A
1438
1439 if (!data) {
1440 data = OSData::withCapacity(4096 * sizeof(uintptr_t));
1441 }
1442
1443 // <len><name>...<len><name><0>
1444 scan = names;
1445 do{
f427ee49 1446 sLen = ((uint8_t) scan[0]);
0a7de745
A
1447 scan++;
1448 next = scan + sLen;
1449 if (next >= (names + namesLen)) {
1450 break;
1451 }
1452 kr = zone_leaks(scan, sLen, &ZoneSiteProc, data);
1453 if (KERN_SUCCESS == kr) {
1454 ret = kIOReturnSuccess;
1455 } else if (KERN_INVALID_NAME != kr) {
1456 ret = kIOReturnVMError;
1457 }
1458 scan = next;
1459 }while (scan < (names + namesLen));
1460 }
1461
1462 if (data) {
1463 switch (selector) {
1464 case kIOTrackingLeaks:
1465 case kIOTrackingGetTracking:
1466 case kIOTrackingGetMappings:
1467 {
1468 IOTrackingCallSiteInfo * siteInfos;
1469 siteInfos = (typeof(siteInfos))data->getBytesNoCopy();
1470 num = (data->getLength() / sizeof(*siteInfos));
1471 qsort(siteInfos, num, sizeof(*siteInfos), &IOTrackingCallSiteInfoCompare);
1472 break;
1473 }
1474 default: assert(false); break;
1475 }
39037602 1476 }
3e170ce0 1477
0a7de745
A
1478 *result = data;
1479 if (proc) {
1480 proc_rele(proc);
1481 }
3e170ce0
A
1482
1483#endif /* IOTRACKING */
1484
0a7de745 1485 return ret;
3e170ce0
A
1486}
1487
1488/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1489
1490#include <IOKit/IOKitDiagnosticsUserClient.h>
1491
1492/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1493
1494#undef super
1495#define super IOUserClient
1496
1497OSDefineMetaClassAndStructors(IOKitDiagnosticsClient, IOUserClient)
1498
1499/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1500
1501IOUserClient * IOKitDiagnosticsClient::withTask(task_t owningTask)
1502{
0a7de745 1503 IOKitDiagnosticsClient * inst;
3e170ce0 1504
0a7de745
A
1505 inst = new IOKitDiagnosticsClient;
1506 if (inst && !inst->init()) {
1507 inst->release();
cb323159 1508 inst = NULL;
0a7de745 1509 }
3e170ce0 1510
0a7de745 1511 return inst;
3e170ce0
A
1512}
1513
0a7de745
A
1514IOReturn
1515IOKitDiagnosticsClient::clientClose(void)
3e170ce0 1516{
0a7de745
A
1517 terminate();
1518 return kIOReturnSuccess;
3e170ce0
A
1519}
1520
0a7de745
A
1521IOReturn
1522IOKitDiagnosticsClient::setProperties(OSObject * properties)
3e170ce0 1523{
0a7de745
A
1524 IOReturn kr = kIOReturnUnsupported;
1525 return kr;
3e170ce0
A
1526}
1527
0a7de745
A
1528IOReturn
1529IOKitDiagnosticsClient::externalMethod(uint32_t selector, IOExternalMethodArguments * args,
1530 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
3e170ce0 1531{
0a7de745
A
1532 IOReturn ret = kIOReturnBadArgument;
1533 const IOKitDiagnosticsParameters * params;
1534 const char * names;
1535 size_t namesLen;
1536 OSObject * result;
1537
1538 if (args->structureInputSize < sizeof(IOKitDiagnosticsParameters)) {
1539 return kIOReturnBadArgument;
1540 }
1541 params = (typeof(params))args->structureInput;
1542 if (!params) {
1543 return kIOReturnBadArgument;
1544 }
3e170ce0 1545
cb323159 1546 names = NULL;
0a7de745
A
1547 namesLen = args->structureInputSize - sizeof(IOKitDiagnosticsParameters);
1548 if (namesLen) {
1549 names = (typeof(names))(params + 1);
1550 }
3e170ce0 1551
0a7de745 1552 ret = IOTrackingDebug(selector, params->options, params->value, params->tag, params->zsize, names, namesLen, params->size, &result);
3e170ce0 1553
0a7de745
A
1554 if ((kIOReturnSuccess == ret) && args->structureVariableOutputData) {
1555 *args->structureVariableOutputData = result;
1556 } else if (result) {
1557 result->release();
1558 }
3e170ce0 1559
0a7de745 1560 return ret;
3e170ce0
A
1561}
1562
1563/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */