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