2 * Copyright (c) 1998-2010 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <sys/sysctl.h>
32 #include <vm/vm_kern.h>
35 #include <libkern/c++/OSContainers.h>
36 #include <libkern/OSDebug.h>
37 #include <libkern/c++/OSCPPDebug.h>
39 #include <IOKit/IOKitDebug.h>
40 #include <IOKit/IOLib.h>
41 #include <IOKit/assert.h>
42 #include <IOKit/IODeviceTreeSupport.h>
43 #include <IOKit/IOService.h>
46 #define DEBUG_INIT_VALUE IOKITDEBUG
48 #define DEBUG_INIT_VALUE 0
51 SInt64 gIOKitDebug
= DEBUG_INIT_VALUE
;
52 SInt64 gIOKitTrace
= 0;
54 #if DEVELOPMENT || DEBUG
55 #define IODEBUG_CTLFLAGS CTLFLAG_RW
57 #define IODEBUG_CTLFLAGS CTLFLAG_RD
60 SYSCTL_QUAD(_debug
, OID_AUTO
, iokit
, IODEBUG_CTLFLAGS
| CTLFLAG_LOCKED
, &gIOKitDebug
, "boot_arg io");
61 SYSCTL_QUAD(_debug
, OID_AUTO
, iotrace
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &gIOKitTrace
, "trace io");
64 int debug_malloc_size
;
65 int debug_iomalloc_size
;
67 vm_size_t debug_iomallocpageable_size
;
68 int debug_container_malloc_size
;
69 // int debug_ivars_size; // in OSObject.cpp
74 #define DEBG(fmt, args...) { kprintf(fmt, ## args); }
76 #define DEBG(fmt, args...) { IOLog(fmt, ## args); }
79 void IOPrintPlane( const IORegistryPlane
* plane
)
81 IORegistryEntry
* next
;
82 IORegistryIterator
* iter
;
84 char format
[] = "%xxxs";
87 iter
= IORegistryIterator::iterateOver( plane
);
89 all
= iter
->iterateAll();
91 DEBG("Count %d\n", all
->getCount() );
97 while( (next
= iter
->getNextObjectRecursive())) {
98 snprintf(format
+ 1, sizeof(format
) - 1, "%ds", 2 * next
->getDepth( plane
));
100 DEBG( "\033[33m%s", next
->getName( plane
));
101 if( (next
->getLocation( plane
)))
102 DEBG("@%s", next
->getLocation( plane
));
103 DEBG("\033[0m <class %s", next
->getMetaClass()->getClassName());
104 if( (service
= OSDynamicCast(IOService
, next
)))
105 DEBG(", busy %ld", (long) service
->getBusyState());
112 void db_piokjunk(void)
116 void db_dumpiojunk( const IORegistryPlane
* plane __unused
)
120 void IOPrintMemory( void )
123 // OSMetaClass::printInstanceCounts();
126 "ivar kalloc() 0x%08x\n"
128 "containers kalloc() 0x%08x\n"
129 "IOMalloc() 0x%08x\n"
130 "----------------------------------------\n",
133 debug_container_malloc_size
,
140 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
142 #define super OSObject
143 OSDefineMetaClassAndStructors(IOKitDiagnostics
, OSObject
)
145 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
147 OSObject
* IOKitDiagnostics::diagnostics( void )
149 IOKitDiagnostics
* diags
;
151 diags
= new IOKitDiagnostics
;
152 if( diags
&& !diags
->init()) {
160 void IOKitDiagnostics::updateOffset( OSDictionary
* dict
,
161 UInt64 value
, const char * name
)
165 off
= OSNumber::withNumber( value
, 64 );
169 dict
->setObject( name
, off
);
173 bool IOKitDiagnostics::serialize(OSSerialize
*s
) const
178 dict
= OSDictionary::withCapacity( 5 );
182 updateOffset( dict
, debug_ivars_size
, "Instance allocation" );
183 updateOffset( dict
, debug_container_malloc_size
, "Container allocation" );
184 updateOffset( dict
, debug_iomalloc_size
, "IOMalloc allocation" );
185 updateOffset( dict
, debug_iomallocpageable_size
, "Pageable allocation" );
187 OSMetaClass::serializeClassDictionary(dict
);
189 ok
= dict
->serialize( s
);
196 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
200 #include <libkern/c++/OSCPPDebug.h>
201 #include <libkern/c++/OSKext.h>
202 #include <kern/zalloc.h>
204 __private_extern__
"C" void qsort(
208 int (*)(const void *, const void *));
210 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
211 extern "C" ppnum_t
pmap_valid_page(ppnum_t pn
);
213 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
215 struct IOTRecursiveLock
222 struct IOTrackingQueue
225 IOTRecursiveLock lock
;
229 size_t minCaptureSize
;
235 struct IOTrackingCallSite
238 IOTrackingQueue
* queue
;
240 IOTrackingCallSiteInfo info
;
241 queue_chain_t instances
;
242 IOTracking
* addresses
;
245 struct IOTrackingLeaksRef
247 uintptr_t * instances
;
255 kInstanceFlagAddress
= 0x01UL
,
256 kInstanceFlagReferenced
= 0x02UL
,
257 kInstanceFlags
= 0x03UL
260 lck_mtx_t
* gIOTrackingLock
;
261 queue_head_t gIOTrackingQ
;
265 kTrackingAddressFlagAllocated
= 0x00000001
268 #if defined(__LP64__)
269 #define IOTrackingAddressFlags(ptr) (ptr->flags)
271 #define IOTrackingAddressFlags(ptr) (ptr->tracking.flags)
274 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
277 IOTRecursiveLockLock(IOTRecursiveLock
* lock
)
279 if (lock
->thread
== current_thread()) lock
->count
++;
282 lck_mtx_lock(lock
->mutex
);
283 assert(lock
->thread
== 0);
284 assert(lock
->count
== 0);
285 lock
->thread
= current_thread();
291 IOTRecursiveLockUnlock(IOTRecursiveLock
* lock
)
293 assert(lock
->thread
== current_thread());
294 if (0 == (--lock
->count
))
297 lck_mtx_unlock(lock
->mutex
);
301 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
306 queue_init(&gIOTrackingQ
);
307 gIOTrackingLock
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
);
310 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
313 IOTrackingQueueAlloc(const char * name
, size_t allocSize
, size_t minCaptureSize
, bool isAlloc
)
315 IOTrackingQueue
* queue
;
316 queue
= (typeof(queue
)) kalloc(sizeof(IOTrackingQueue
));
317 bzero(queue
, sizeof(IOTrackingQueue
));
320 queue
->allocSize
= allocSize
;
321 queue
->minCaptureSize
= minCaptureSize
;
322 queue
->lock
.mutex
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
);
323 queue_init(&queue
->sites
);
325 queue
->captureOn
= (0 != (kIOTrackingBoot
& gIOKitDebug
));
326 queue
->isAlloc
= isAlloc
;
328 lck_mtx_lock(gIOTrackingLock
);
329 queue_enter(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
);
330 lck_mtx_unlock(gIOTrackingLock
);
335 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
338 IOTrackingQueueFree(IOTrackingQueue
* queue
)
340 lck_mtx_lock(gIOTrackingLock
);
341 IOTrackingReset(queue
);
342 remque(&queue
->link
);
343 lck_mtx_unlock(gIOTrackingLock
);
345 lck_mtx_free(queue
->lock
.mutex
, IOLockGroup
);
347 kfree(queue
, sizeof(IOTrackingQueue
));
350 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
355 Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
357 Permission is hereby granted, free of charge, to any person
358 obtaining a copy of this software and associated documentation
359 files (the "Software"), to deal in the Software without
360 restriction, including without limitation the rights to use, copy,
361 modify, merge, publish, distribute, sublicense, and/or sell copies
362 of the Software, and to permit persons to whom the Software is
363 furnished to do so, subject to the following conditions:
365 The above copyright notice and this permission notice shall be
366 included in all copies or substantial portions of the Software.
368 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
369 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
370 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
371 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
372 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
373 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
374 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
379 // Compression function for Merkle-Damgard construction.
380 // This function is generated using the framework provided.
383 (h) *= 0x2127599bf4325c37ULL; \
387 fasthash64(const void *buf
, size_t len
, uint64_t seed
)
389 const uint64_t m
= 0x880355f21e6d1965ULL
;
390 const uint64_t *pos
= (const uint64_t *)buf
;
391 const uint64_t *end
= pos
+ (len
/ 8);
392 const unsigned char *pos2
;
393 uint64_t h
= seed
^ (len
* m
);
402 pos2
= (const unsigned char*)pos
;
406 case 7: v
^= (uint64_t)pos2
[6] << 48;
407 case 6: v
^= (uint64_t)pos2
[5] << 40;
408 case 5: v
^= (uint64_t)pos2
[4] << 32;
409 case 4: v
^= (uint64_t)pos2
[3] << 24;
410 case 3: v
^= (uint64_t)pos2
[2] << 16;
411 case 2: v
^= (uint64_t)pos2
[1] << 8;
412 case 1: v
^= (uint64_t)pos2
[0];
420 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
423 fasthash32(const void *buf
, size_t len
, uint32_t seed
)
425 // the following trick converts the 64-bit hashcode to Fermat
426 // residue, which shall retain information from both the higher
427 // and lower parts of hashcode.
428 uint64_t h
= fasthash64(buf
, len
, seed
);
429 return h
- (h
>> 32);
432 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
435 IOTrackingAdd(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
, bool address
)
437 IOTrackingCallSite
* site
;
439 uintptr_t bt
[kIOTrackingCallSiteBTs
+ 1];
441 if (mem
->site
) return;
442 if (!queue
->captureOn
) return;
443 if (size
< queue
->minCaptureSize
) return;
445 assert(!mem
->link
.next
);
447 num
= fastbacktrace(&bt
[0], kIOTrackingCallSiteBTs
+ 1);
449 crc
= fasthash32(&bt
[1], num
* sizeof(bt
[0]), 0x04C11DB7);
451 IOTRecursiveLockLock(&queue
->lock
);
452 queue_iterate(&queue
->sites
, site
, IOTrackingCallSite
*, link
)
454 if (crc
== site
->crc
) break;
457 if (queue_end(&queue
->sites
, (queue_entry_t
) site
))
459 site
= (typeof(site
)) kalloc(sizeof(IOTrackingCallSite
));
461 queue_init(&site
->instances
);
462 site
->addresses
= (IOTracking
*) &site
->instances
;
465 site
->info
.count
= 0;
466 memset(&site
->info
.size
[0], 0, sizeof(site
->info
.size
));
467 bcopy(&bt
[1], &site
->info
.bt
[0], num
* sizeof(site
->info
.bt
[0]));
468 assert(num
<= kIOTrackingCallSiteBTs
);
469 bzero(&site
->info
.bt
[num
], (kIOTrackingCallSiteBTs
- num
) * sizeof(site
->info
.bt
[0]));
471 queue_enter_first(&queue
->sites
, site
, IOTrackingCallSite
*, link
);
477 queue_enter
/*last*/(&site
->instances
, mem
, IOTrackingCallSite
*, link
);
478 if (queue_end(&site
->instances
, (queue_entry_t
)site
->addresses
)) site
->addresses
= mem
;
480 else queue_enter_first(&site
->instances
, mem
, IOTrackingCallSite
*, link
);
483 site
->info
.size
[0] += size
;
486 IOTRecursiveLockUnlock(&queue
->lock
);
489 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
492 IOTrackingRemove(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
)
494 if (!mem
->link
.next
) return;
496 IOTRecursiveLockLock(&queue
->lock
);
500 if (mem
== mem
->site
->addresses
) mem
->site
->addresses
= (IOTracking
*) queue_next(&mem
->link
);
503 assert(mem
->site
->info
.count
);
504 mem
->site
->info
.count
--;
505 assert(mem
->site
->info
.size
[0] >= size
);
506 mem
->site
->info
.size
[0] -= size
;
507 if (!mem
->site
->info
.count
)
509 assert(queue_empty(&mem
->site
->instances
));
510 assert(!mem
->site
->info
.size
[0]);
511 assert(!mem
->site
->info
.size
[1]);
513 remque(&mem
->site
->link
);
514 assert(queue
->siteCount
);
516 kfree(mem
->site
, sizeof(IOTrackingCallSite
));
518 IOTRecursiveLockUnlock(&queue
->lock
);
521 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
524 IOTrackingAlloc(IOTrackingQueue
* queue
, uintptr_t address
, size_t size
)
526 IOTrackingAddress
* tracking
;
528 if (!queue
->captureOn
) return;
529 if (size
< queue
->minCaptureSize
) return;
532 tracking
= (typeof(tracking
)) kalloc(sizeof(IOTrackingAddress
));
533 bzero(tracking
, sizeof(IOTrackingAddress
));
534 IOTrackingAddressFlags(tracking
) |= kTrackingAddressFlagAllocated
;
535 tracking
->address
= address
;
536 tracking
->size
= size
;
538 IOTrackingAdd(queue
, &tracking
->tracking
, size
, true);
541 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
544 IOTrackingFree(IOTrackingQueue
* queue
, uintptr_t address
, size_t size
)
546 IOTrackingCallSite
* site
;
547 IOTrackingAddress
* tracking
;
551 IOTRecursiveLockLock(&queue
->lock
);
553 queue_iterate(&queue
->sites
, site
, IOTrackingCallSite
*, link
)
555 for (tracking
= (IOTrackingAddress
*) site
->addresses
;
556 !done
&& !queue_end(&site
->instances
, (queue_entry_t
) tracking
);
557 tracking
= (IOTrackingAddress
*) queue_next(&tracking
->tracking
.link
))
559 if ((done
= (address
== tracking
->address
)))
561 IOTrackingRemove(queue
, &tracking
->tracking
, size
);
562 kfree(tracking
, sizeof(IOTrackingAddress
));
568 IOTRecursiveLockUnlock(&queue
->lock
);
571 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
574 IOTrackingAccumSize(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
)
576 IOTRecursiveLockLock(&queue
->lock
);
580 assert((size
> 0) || (mem
->site
->info
.size
[1] >= -size
));
581 mem
->site
->info
.size
[1] += size
;
583 IOTRecursiveLockUnlock(&queue
->lock
);
586 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
589 IOTrackingReset(IOTrackingQueue
* queue
)
591 IOTrackingCallSite
* site
;
592 IOTracking
* tracking
;
593 IOTrackingAddress
* trackingAddress
;
596 IOTRecursiveLockLock(&queue
->lock
);
597 while (!queue_empty(&queue
->sites
))
599 queue_remove_first(&queue
->sites
, site
, IOTrackingCallSite
*, link
);
601 while (!queue_empty(&site
->instances
))
603 queue_remove_first(&site
->instances
, tracking
, IOTracking
*, link
);
604 tracking
->link
.next
= 0;
605 if (tracking
== site
->addresses
) addresses
= true;
608 trackingAddress
= (typeof(trackingAddress
)) tracking
;
609 if (kTrackingAddressFlagAllocated
& IOTrackingAddressFlags(trackingAddress
))
611 kfree(tracking
, sizeof(IOTrackingAddress
));
615 kfree(site
, sizeof(IOTrackingCallSite
));
617 queue
->siteCount
= 0;
618 IOTRecursiveLockUnlock(&queue
->lock
);
621 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
624 IOTrackingCallSiteInfoCompare(const void * left
, const void * right
)
626 IOTrackingCallSiteInfo
* l
= (typeof(l
)) left
;
627 IOTrackingCallSiteInfo
* r
= (typeof(r
)) right
;
630 rsize
= r
->size
[0] + r
->size
[1];
631 lsize
= l
->size
[0] + l
->size
[1];
633 return ((rsize
> lsize
) ? 1 : ((rsize
== lsize
) ? 0 : -1));
636 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
639 IOTrackingAddressCompare(const void * left
, const void * right
)
641 IOTracking
* instance
;
642 uintptr_t inst
, laddr
, raddr
;
644 inst
= ((typeof(inst
) *) left
)[0];
645 instance
= (typeof(instance
)) (inst
& ~kInstanceFlags
);
646 if (kInstanceFlagAddress
& inst
) laddr
= ~((IOTrackingAddress
*)instance
)->address
;
647 else laddr
= (uintptr_t) (instance
+ 1);
649 inst
= ((typeof(inst
) *) right
)[0];
650 instance
= (typeof(instance
)) (inst
& ~kInstanceFlags
);
651 if (kInstanceFlagAddress
& inst
) raddr
= ~((IOTrackingAddress
*)instance
)->address
;
652 else raddr
= (uintptr_t) (instance
+ 1);
654 return ((laddr
> raddr
) ? 1 : ((laddr
== raddr
) ? 0 : -1));
657 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
660 IOTrackingLeakScan(void * refcon
)
662 IOTrackingLeaksRef
* ref
= (typeof(ref
)) refcon
;
663 uintptr_t * instances
;
664 IOTracking
* instance
;
665 uint64_t vaddr
, vincr
;
667 uintptr_t ptr
, addr
, inst
;
669 uint32_t baseIdx
, lim
, ptrIdx
, count
;
672 // if (cpu_number()) return;
674 instances
= ref
->instances
;
677 for (vaddr
= VM_MIN_KERNEL_AND_KEXT_ADDRESS
;
678 vaddr
< VM_MAX_KERNEL_ADDRESS
;
679 ml_set_interrupts_enabled(is
), vaddr
+= vincr
)
681 #if !defined(__LP64__)
684 is
= ml_set_interrupts_enabled(false);
686 ppn
= kernel_pmap_present_mapping(vaddr
, &vincr
);
687 // check noencrypt to avoid VM structs (map entries) with pointers
688 if (ppn
&& (!pmap_valid_page(ppn
) || pmap_is_noencrypt(ppn
))) ppn
= 0;
691 for (ptrIdx
= 0; ptrIdx
< (page_size
/ sizeof(uintptr_t)); ptrIdx
++)
693 ptr
= ((uintptr_t *)vaddr
)[ptrIdx
];
695 for (lim
= count
, baseIdx
= 0; lim
; lim
>>= 1)
697 inst
= instances
[baseIdx
+ (lim
>> 1)];
698 instance
= (typeof(instance
)) (inst
& ~kInstanceFlags
);
699 if (kInstanceFlagAddress
& inst
)
701 addr
= ~((IOTrackingAddress
*)instance
)->address
;
702 size
= ((IOTrackingAddress
*)instance
)->size
;
706 addr
= (uintptr_t) (instance
+ 1);
707 size
= instance
->site
->queue
->allocSize
;
709 if ((ptr
>= addr
) && (ptr
< (addr
+ size
)))
711 if (!(kInstanceFlagReferenced
& inst
))
713 inst
|= kInstanceFlagReferenced
;
714 instances
[baseIdx
+ (lim
>> 1)] = inst
;
722 baseIdx
+= (lim
>> 1) + 1;
728 ref
->bytes
+= page_size
;
732 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
735 IOTrackingLeaks(OSData
* data
)
737 IOTrackingLeaksRef ref
;
738 IOTrackingCallSiteInfo unslideInfo
;
739 IOTrackingCallSite
* site
;
741 uintptr_t * instances
;
742 IOTracking
* instance
;
744 uint32_t count
, idx
, numSites
, dups
, siteCount
;
746 instances
= (typeof(instances
)) data
->getBytesNoCopy();
747 count
= (data
->getLength() / sizeof(*instances
));
748 qsort(instances
, count
, sizeof(*instances
), &IOTrackingAddressCompare
);
750 bzero(&ref
, sizeof(ref
));
751 ref
.instances
= instances
;
754 IOTrackingLeakScan(&ref
);
756 IOLog("leaks scanned %ld MB, instance count %d, found %d\n", ref
.bytes
/ 1024 / 1024, count
, ref
.found
);
758 leakData
= OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo
));
760 for (numSites
= 0, idx
= 0; idx
< count
; idx
++)
762 inst
= instances
[idx
];
763 if (kInstanceFlagReferenced
& inst
) continue;
764 instance
= (typeof(instance
)) (inst
& ~kInstanceFlags
);
765 site
= instance
->site
;
766 instances
[numSites
] = (uintptr_t) site
;
770 for (idx
= 0; idx
< numSites
; idx
++)
772 inst
= instances
[idx
];
774 site
= (typeof(site
)) inst
;
775 for (siteCount
= 1, dups
= (idx
+ 1); dups
< numSites
; dups
++)
777 if (instances
[dups
] == (uintptr_t) site
)
783 unslideInfo
.count
= siteCount
;
784 unslideInfo
.size
[0] = (site
->info
.size
[0] * site
->info
.count
) / siteCount
;
785 unslideInfo
.size
[1] = (site
->info
.size
[1] * site
->info
.count
) / siteCount
;;
786 for (uint32_t j
= 0; j
< kIOTrackingCallSiteBTs
; j
++)
788 unslideInfo
.bt
[j
] = VM_KERNEL_UNSLIDE(site
->info
.bt
[j
]);
790 leakData
->appendBytes(&unslideInfo
, sizeof(unslideInfo
));
797 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
800 SkipName(uint32_t options
, const char * name
, size_t namesLen
, const char * names
)
807 if (!namesLen
|| !names
) return (false);
808 // <len><name>...<len><name><0>
809 exclude
= (0 != (kIOTrackingExcludeNames
& options
));
818 if (next
>= (names
+ namesLen
)) break;
819 found
= ((sLen
== qLen
) && !strncmp(scan
, name
, sLen
));
822 while (!found
&& (scan
< (names
+ namesLen
)));
824 return (!(exclude
^ found
));
827 #endif /* IOTRACKING */
829 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
832 IOTrackingDebug(uint32_t selector
, uint32_t options
,
833 const char * names
, size_t namesLen
,
834 size_t size
, OSObject
** result
)
839 if (result
) *result
= 0;
841 ret
= kIOReturnNotReady
;
845 IOTrackingQueue
* queue
;
846 IOTracking
* instance
;
847 IOTrackingCallSite
* site
;
848 IOTrackingCallSiteInfo
* siteInfos
;
849 IOTrackingCallSiteInfo
* siteInfo
;
854 if (!(kIOTracking
& gIOKitDebug
)) return (kIOReturnNotReady
);
855 ret
= kIOReturnNotFound
;
857 lck_mtx_lock(gIOTrackingLock
);
858 queue_iterate(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
)
860 if (SkipName(options
, queue
->name
, namesLen
, names
)) continue;
864 case kIOTrackingResetTracking
:
866 IOTrackingReset(queue
);
867 ret
= kIOReturnSuccess
;
871 case kIOTrackingStartCapture
:
872 case kIOTrackingStopCapture
:
874 queue
->captureOn
= (kIOTrackingStartCapture
== selector
);
875 ret
= kIOReturnSuccess
;
879 case kIOTrackingSetMinCaptureSize
:
881 queue
->minCaptureSize
= size
;
882 ret
= kIOReturnSuccess
;
886 case kIOTrackingLeaks
:
888 if (!queue
->isAlloc
) break;
890 if (!data
) data
= OSData::withCapacity(1024 * sizeof(uintptr_t));
892 IOTRecursiveLockLock(&queue
->lock
);
893 queue_iterate(&queue
->sites
, site
, IOTrackingCallSite
*, link
)
896 queue_iterate(&site
->instances
, instance
, IOTracking
*, link
)
898 if (instance
== site
->addresses
) addresses
= true;
899 instFlags
= (typeof(instFlags
)) instance
;
900 if (addresses
) instFlags
|= kInstanceFlagAddress
;
901 data
->appendBytes(&instFlags
, sizeof(instFlags
));
905 ret
= kIOReturnSuccess
;
909 case kIOTrackingGetTracking
:
910 case kIOTrackingPrintTracking
:
912 if (!data
) data
= OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo
));
914 IOTRecursiveLockLock(&queue
->lock
);
915 num
= queue
->siteCount
;
917 queue_iterate(&queue
->sites
, site
, IOTrackingCallSite
*, link
)
922 if (size
&& ((site
->info
.size
[0] + site
->info
.size
[1]) < size
)) continue;
924 IOTrackingCallSiteInfo unslideInfo
;
925 unslideInfo
.count
= site
->info
.count
;
926 memcpy(&unslideInfo
.size
[0], &site
->info
.size
[0], sizeof(unslideInfo
.size
));
928 for (uint32_t j
= 0; j
< kIOTrackingCallSiteBTs
; j
++)
930 unslideInfo
.bt
[j
] = VM_KERNEL_UNSLIDE(site
->info
.bt
[j
]);
932 data
->appendBytes(&unslideInfo
, sizeof(unslideInfo
));
935 IOTRecursiveLockUnlock(&queue
->lock
);
936 ret
= kIOReturnSuccess
;
940 ret
= kIOReturnUnsupported
;
945 if ((kIOTrackingLeaks
== selector
) && data
)
947 data
= IOTrackingLeaks(data
);
948 queue_iterate(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
)
950 if (SkipName(options
, queue
->name
, namesLen
, names
)) continue;
951 if (!queue
->isAlloc
) continue;
952 IOTRecursiveLockUnlock(&queue
->lock
);
956 lck_mtx_unlock(gIOTrackingLock
);
960 siteInfos
= (typeof(siteInfos
)) data
->getBytesNoCopy();
961 num
= (data
->getLength() / sizeof(IOTrackingCallSiteInfo
));
962 qsort(siteInfos
, num
, sizeof(*siteInfos
), &IOTrackingCallSiteInfoCompare
);
964 if (kIOTrackingPrintTracking
== selector
)
966 for (idx
= 0; idx
< num
; idx
++)
968 siteInfo
= &siteInfos
[idx
];
969 printf("\n0x%lx bytes (0x%lx + 0x%lx), %d call%s, [%d]\n",
970 siteInfo
->size
[0] + siteInfo
->size
[1],
971 siteInfo
->size
[0], siteInfo
->size
[1],
972 siteInfo
->count
, (siteInfo
->count
!= 1) ? "s" : "", idx
);
973 uintptr_t * bt
= &siteInfo
->bt
[0];
974 printf(" Backtrace 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
975 bt
[0], bt
[1], bt
[2], bt
[3], bt
[4], bt
[5], bt
[6], bt
[7],
976 bt
[8], bt
[9], bt
[10], bt
[11], bt
[12], bt
[13], bt
[14], bt
[15]);
977 kmod_dump_log((vm_offset_t
*) &bt
[0], kIOTrackingCallSiteBTs
, FALSE
);
986 #endif /* IOTRACKING */
991 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
993 #include <IOKit/IOKitDiagnosticsUserClient.h>
995 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
998 #define super IOUserClient
1000 OSDefineMetaClassAndStructors(IOKitDiagnosticsClient
, IOUserClient
)
1002 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1004 IOUserClient
* IOKitDiagnosticsClient::withTask(task_t owningTask
)
1006 IOKitDiagnosticsClient
* inst
;
1008 inst
= new IOKitDiagnosticsClient
;
1009 if (inst
&& !inst
->init())
1018 IOReturn
IOKitDiagnosticsClient::clientClose(void)
1021 return (kIOReturnSuccess
);
1024 IOReturn
IOKitDiagnosticsClient::setProperties(OSObject
* properties
)
1026 IOReturn kr
= kIOReturnUnsupported
;
1030 IOReturn
IOKitDiagnosticsClient::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
1031 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
1033 IOReturn ret
= kIOReturnBadArgument
;
1034 const IOKitDiagnosticsParameters
* params
;
1039 if (args
->structureInputSize
< sizeof(IOKitDiagnosticsParameters
)) return (kIOReturnBadArgument
);
1040 params
= (typeof(params
)) args
->structureInput
;
1041 if (!params
) return (kIOReturnBadArgument
);
1044 namesLen
= args
->structureInputSize
- sizeof(IOKitDiagnosticsParameters
);
1045 if (namesLen
) names
= (typeof(names
))(params
+ 1);
1047 ret
= IOTrackingDebug(selector
, params
->options
, names
, namesLen
, params
->size
, &result
);
1049 if ((kIOReturnSuccess
== ret
) && args
->structureVariableOutputData
) *args
->structureVariableOutputData
= result
;
1050 else if (result
) result
->release();
1055 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */