2 * Copyright (c) 1998-2016 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>
33 #include <kern/task.h>
34 #include <kern/debug.h>
37 #include <libkern/c++/OSContainers.h>
38 #include <libkern/OSDebug.h>
39 #include <libkern/c++/OSCPPDebug.h>
40 #include <kern/backtrace.h>
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>
48 #include "IOKitKernelInternal.h"
51 #define DEBUG_INIT_VALUE IOKITDEBUG
53 #define DEBUG_INIT_VALUE 0
56 SInt64 gIOKitDebug
= DEBUG_INIT_VALUE
;
57 SInt64 gIOKitTrace
= 0;
59 #if DEVELOPMENT || DEBUG
60 #define IODEBUG_CTLFLAGS CTLFLAG_RW
62 #define IODEBUG_CTLFLAGS CTLFLAG_RD
65 SYSCTL_QUAD(_debug
, OID_AUTO
, iokit
, IODEBUG_CTLFLAGS
| CTLFLAG_LOCKED
, &gIOKitDebug
, "boot_arg io");
66 SYSCTL_QUAD(_debug
, OID_AUTO
, iotrace
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &gIOKitTrace
, "trace io");
69 int debug_malloc_size
;
70 int debug_iomalloc_size
;
72 vm_size_t debug_iomallocpageable_size
;
73 int debug_container_malloc_size
;
74 // int debug_ivars_size; // in OSObject.cpp
79 #define DEBG(fmt, args...) { kprintf(fmt, ## args); }
81 #define DEBG(fmt, args...) { IOLog(fmt, ## args); }
84 void IOPrintPlane( const IORegistryPlane
* plane
)
86 IORegistryEntry
* next
;
87 IORegistryIterator
* iter
;
89 char format
[] = "%xxxs";
92 iter
= IORegistryIterator::iterateOver( plane
);
94 all
= iter
->iterateAll();
96 DEBG("Count %d\n", all
->getCount() );
102 while( (next
= iter
->getNextObjectRecursive())) {
103 snprintf(format
+ 1, sizeof(format
) - 1, "%ds", 2 * next
->getDepth( plane
));
105 DEBG( "\033[33m%s", next
->getName( plane
));
106 if( (next
->getLocation( plane
)))
107 DEBG("@%s", next
->getLocation( plane
));
108 DEBG("\033[0m <class %s", next
->getMetaClass()->getClassName());
109 if( (service
= OSDynamicCast(IOService
, next
)))
110 DEBG(", busy %ld", (long) service
->getBusyState());
117 void db_piokjunk(void)
121 void db_dumpiojunk( const IORegistryPlane
* plane __unused
)
125 void IOPrintMemory( void )
128 // OSMetaClass::printInstanceCounts();
131 "ivar kalloc() 0x%08x\n"
133 "containers kalloc() 0x%08x\n"
134 "IOMalloc() 0x%08x\n"
135 "----------------------------------------\n",
138 debug_container_malloc_size
,
145 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
147 #define super OSObject
148 OSDefineMetaClassAndStructors(IOKitDiagnostics
, OSObject
)
150 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
152 OSObject
* IOKitDiagnostics::diagnostics( void )
154 IOKitDiagnostics
* diags
;
156 diags
= new IOKitDiagnostics
;
157 if( diags
&& !diags
->init()) {
165 void IOKitDiagnostics::updateOffset( OSDictionary
* dict
,
166 UInt64 value
, const char * name
)
170 off
= OSNumber::withNumber( value
, 64 );
174 dict
->setObject( name
, off
);
178 bool IOKitDiagnostics::serialize(OSSerialize
*s
) const
183 dict
= OSDictionary::withCapacity( 5 );
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" );
190 updateOffset( dict
, debug_iomallocpageable_size
, "Pageable allocation" );
192 OSMetaClass::serializeClassDictionary(dict
);
194 ok
= dict
->serialize( s
);
201 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
205 #include <libkern/c++/OSCPPDebug.h>
206 #include <libkern/c++/OSKext.h>
207 #include <kern/zalloc.h>
209 __private_extern__
"C" void qsort(
213 int (*)(const void *, const void *));
215 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
216 extern "C" ppnum_t
pmap_valid_page(ppnum_t pn
);
218 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
220 struct IOTRecursiveLock
227 struct IOTrackingQueue
230 IOTRecursiveLock lock
;
234 size_t minCaptureSize
;
239 queue_head_t sites
[];
242 struct IOTrackingCallSite
245 IOTrackingQueue
* queue
;
250 uintptr_t bt
[kIOTrackingCallSiteBTs
];
252 queue_head_t instances
;
253 IOTracking
* addresses
;
256 struct IOTrackingLeaksRef
258 uintptr_t * instances
;
265 lck_mtx_t
* gIOTrackingLock
;
266 queue_head_t gIOTrackingQ
;
270 kTrackingAddressFlagAllocated
= 0x00000001
273 #if defined(__LP64__)
274 #define IOTrackingAddressFlags(ptr) (ptr->flags)
276 #define IOTrackingAddressFlags(ptr) (ptr->tracking.flags)
279 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
282 IOTRecursiveLockLock(IOTRecursiveLock
* lock
)
284 if (lock
->thread
== current_thread()) lock
->count
++;
287 lck_mtx_lock(lock
->mutex
);
288 assert(lock
->thread
== 0);
289 assert(lock
->count
== 0);
290 lock
->thread
= current_thread();
296 IOTRecursiveLockUnlock(IOTRecursiveLock
* lock
)
298 assert(lock
->thread
== current_thread());
299 if (0 == (--lock
->count
))
302 lck_mtx_unlock(lock
->mutex
);
306 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
311 queue_init(&gIOTrackingQ
);
312 gIOTrackingLock
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
);
315 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
318 IOTrackingQueueAlloc(const char * name
, uintptr_t btEntry
,
319 size_t allocSize
, size_t minCaptureSize
,
320 uint32_t type
, uint32_t numSiteQs
)
322 IOTrackingQueue
* queue
;
325 if (!numSiteQs
) numSiteQs
= 1;
326 queue
= (typeof(queue
)) kalloc(sizeof(IOTrackingQueue
) + numSiteQs
* sizeof(queue
->sites
[0]));
327 bzero(queue
, sizeof(IOTrackingQueue
));
330 queue
->btEntry
= btEntry
;
331 queue
->allocSize
= allocSize
;
332 queue
->minCaptureSize
= minCaptureSize
;
333 queue
->lock
.mutex
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
);
334 queue
->numSiteQs
= numSiteQs
;
336 enum { kFlags
= (kIOTracking
| kIOTrackingBoot
) };
337 queue
->captureOn
= (kFlags
== (kFlags
& gIOKitDebug
))
338 || (kIOTrackingQueueTypeDefaultOn
& type
);
340 for (idx
= 0; idx
< numSiteQs
; idx
++) queue_init(&queue
->sites
[idx
]);
342 lck_mtx_lock(gIOTrackingLock
);
343 queue_enter(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
);
344 lck_mtx_unlock(gIOTrackingLock
);
349 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
352 IOTrackingQueueFree(IOTrackingQueue
* queue
)
354 lck_mtx_lock(gIOTrackingLock
);
355 IOTrackingReset(queue
);
356 remque(&queue
->link
);
357 lck_mtx_unlock(gIOTrackingLock
);
359 lck_mtx_free(queue
->lock
.mutex
, IOLockGroup
);
361 kfree(queue
, sizeof(IOTrackingQueue
) + queue
->numSiteQs
* sizeof(queue
->sites
[0]));
364 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
369 Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
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:
379 The above copyright notice and this permission notice shall be
380 included in all copies or substantial portions of the Software.
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
393 // Compression function for Merkle-Damgard construction.
394 // This function is generated using the framework provided.
397 (h) *= 0x2127599bf4325c37ULL; \
401 fasthash64(const void *buf
, size_t len
, uint64_t seed
)
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
);
416 pos2
= (const unsigned char*)pos
;
420 case 7: v
^= (uint64_t)pos2
[6] << 48;
421 [[clang::fallthrough]];
422 case 6: v
^= (uint64_t)pos2
[5] << 40;
423 [[clang::fallthrough]];
424 case 5: v
^= (uint64_t)pos2
[4] << 32;
425 [[clang::fallthrough]];
426 case 4: v
^= (uint64_t)pos2
[3] << 24;
427 [[clang::fallthrough]];
428 case 3: v
^= (uint64_t)pos2
[2] << 16;
429 [[clang::fallthrough]];
430 case 2: v
^= (uint64_t)pos2
[1] << 8;
431 [[clang::fallthrough]];
432 case 1: v
^= (uint64_t)pos2
[0];
440 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
443 fasthash32(const void *buf
, size_t len
, uint32_t seed
)
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);
452 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
455 IOTrackingAddUser(IOTrackingQueue
* queue
, IOTrackingUser
* mem
, vm_size_t size
)
460 if (!queue
->captureOn
) return;
461 if (size
< queue
->minCaptureSize
) return;
463 assert(!mem
->link
.next
);
465 num
= backtrace(&mem
->bt
[0], kIOTrackingCallSiteBTs
);
467 if ((kernel_task
!= current_task()) && (self
= proc_self()))
470 mem
->btPID
= proc_pid(self
);
471 (void)backtrace_user(&mem
->btUser
[0], kIOTrackingCallSiteBTs
- 1, &num
,
473 mem
->user32
= !user_64
;
476 assert(num
<= kIOTrackingCallSiteBTs
);
477 mem
->userCount
= num
;
479 IOTRecursiveLockLock(&queue
->lock
);
480 queue_enter
/*last*/(&queue
->sites
[0], mem
, IOTrackingUser
*, link
);
482 IOTRecursiveLockUnlock(&queue
->lock
);
486 IOTrackingRemoveUser(IOTrackingQueue
* queue
, IOTrackingUser
* mem
)
488 if (!mem
->link
.next
) return;
490 IOTRecursiveLockLock(&queue
->lock
);
494 assert(queue
->siteCount
);
497 IOTRecursiveLockUnlock(&queue
->lock
);
500 uint64_t gIOTrackingAddTime
;
503 IOTrackingAdd(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
, bool address
)
505 IOTrackingCallSite
* site
;
507 uintptr_t bt
[kIOTrackingCallSiteBTs
+ 1];
510 if (mem
->site
) return;
511 if (!queue
->captureOn
) return;
512 if (size
< queue
->minCaptureSize
) return;
514 assert(!mem
->link
.next
);
516 num
= backtrace(&bt
[0], kIOTrackingCallSiteBTs
+ 1);
519 crc
= fasthash32(&bt
[1], num
* sizeof(bt
[0]), 0x04C11DB7);
521 IOTRecursiveLockLock(&queue
->lock
);
522 que
= &queue
->sites
[crc
% queue
->numSiteQs
];
523 queue_iterate(que
, site
, IOTrackingCallSite
*, link
)
525 if (crc
== site
->crc
) break;
528 if (queue_end(que
, (queue_entry_t
) site
))
530 site
= (typeof(site
)) kalloc(sizeof(IOTrackingCallSite
));
532 queue_init(&site
->instances
);
533 site
->addresses
= (IOTracking
*) &site
->instances
;
537 memset(&site
->size
[0], 0, sizeof(site
->size
));
538 bcopy(&bt
[1], &site
->bt
[0], num
* sizeof(site
->bt
[0]));
539 assert(num
<= kIOTrackingCallSiteBTs
);
540 bzero(&site
->bt
[num
], (kIOTrackingCallSiteBTs
- num
) * sizeof(site
->bt
[0]));
542 queue_enter_first(que
, site
, IOTrackingCallSite
*, link
);
548 queue_enter
/*last*/(&site
->instances
, mem
, IOTracking
*, link
);
549 if (queue_end(&site
->instances
, (queue_entry_t
)site
->addresses
)) site
->addresses
= mem
;
551 else queue_enter_first(&site
->instances
, mem
, IOTracking
*, link
);
554 site
->size
[0] += size
;
557 IOTRecursiveLockUnlock(&queue
->lock
);
560 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
563 IOTrackingRemove(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
)
565 if (!mem
->link
.next
) return;
567 IOTRecursiveLockLock(&queue
->lock
);
572 if (mem
== mem
->site
->addresses
) mem
->site
->addresses
= (IOTracking
*) queue_next(&mem
->link
);
575 assert(mem
->site
->count
);
577 assert(mem
->site
->size
[0] >= size
);
578 mem
->site
->size
[0] -= size
;
579 if (!mem
->site
->count
)
581 assert(queue_empty(&mem
->site
->instances
));
582 assert(!mem
->site
->size
[0]);
583 assert(!mem
->site
->size
[1]);
585 remque(&mem
->site
->link
);
586 assert(queue
->siteCount
);
588 kfree(mem
->site
, sizeof(IOTrackingCallSite
));
591 IOTRecursiveLockUnlock(&queue
->lock
);
594 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
597 IOTrackingAlloc(IOTrackingQueue
* queue
, uintptr_t address
, size_t size
)
599 IOTrackingAddress
* tracking
;
601 if (!queue
->captureOn
) return;
602 if (size
< queue
->minCaptureSize
) return;
605 tracking
= (typeof(tracking
)) kalloc(sizeof(IOTrackingAddress
));
606 bzero(tracking
, sizeof(IOTrackingAddress
));
607 IOTrackingAddressFlags(tracking
) |= kTrackingAddressFlagAllocated
;
608 tracking
->address
= address
;
609 tracking
->size
= size
;
611 IOTrackingAdd(queue
, &tracking
->tracking
, size
, true);
614 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
617 IOTrackingFree(IOTrackingQueue
* queue
, uintptr_t address
, size_t size
)
619 IOTrackingCallSite
* site
;
620 IOTrackingAddress
* tracking
;
625 IOTRecursiveLockLock(&queue
->lock
);
627 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++)
629 queue_iterate(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
)
631 for (tracking
= (IOTrackingAddress
*) site
->addresses
;
632 !done
&& !queue_end(&site
->instances
, &tracking
->tracking
.link
);
633 tracking
= (IOTrackingAddress
*) queue_next(&tracking
->tracking
.link
))
635 if ((done
= (address
== tracking
->address
)))
637 IOTrackingRemove(queue
, &tracking
->tracking
, size
);
638 kfree(tracking
, sizeof(IOTrackingAddress
));
645 IOTRecursiveLockUnlock(&queue
->lock
);
648 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
651 IOTrackingAccumSize(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
)
653 IOTRecursiveLockLock(&queue
->lock
);
657 assert((size
> 0) || (mem
->site
->size
[1] >= -size
));
658 mem
->site
->size
[1] += size
;
660 IOTRecursiveLockUnlock(&queue
->lock
);
663 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
666 IOTrackingReset(IOTrackingQueue
* queue
)
668 IOTrackingCallSite
* site
;
669 IOTrackingUser
* user
;
670 IOTracking
* tracking
;
671 IOTrackingAddress
* trackingAddress
;
675 IOTRecursiveLockLock(&queue
->lock
);
676 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++)
678 while (!queue_empty(&queue
->sites
[idx
]))
680 if (kIOTrackingQueueTypeMap
& queue
->type
)
682 queue_remove_first(&queue
->sites
[idx
], user
, IOTrackingUser
*, link
);
683 user
->link
.next
= user
->link
.prev
= NULL
;
687 queue_remove_first(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
);
689 while (!queue_empty(&site
->instances
))
691 queue_remove_first(&site
->instances
, tracking
, IOTracking
*, link
);
692 if (tracking
== site
->addresses
) addresses
= true;
695 trackingAddress
= (typeof(trackingAddress
)) tracking
;
696 if (kTrackingAddressFlagAllocated
& IOTrackingAddressFlags(trackingAddress
))
698 kfree(tracking
, sizeof(IOTrackingAddress
));
702 kfree(site
, sizeof(IOTrackingCallSite
));
706 queue
->siteCount
= 0;
707 IOTRecursiveLockUnlock(&queue
->lock
);
710 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
713 IOTrackingCallSiteInfoCompare(const void * left
, const void * right
)
715 IOTrackingCallSiteInfo
* l
= (typeof(l
)) left
;
716 IOTrackingCallSiteInfo
* r
= (typeof(r
)) right
;
719 rsize
= r
->size
[0] + r
->size
[1];
720 lsize
= l
->size
[0] + l
->size
[1];
722 return ((rsize
> lsize
) ? 1 : ((rsize
== lsize
) ? 0 : -1));
725 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
728 IOTrackingAddressCompare(const void * left
, const void * right
)
730 IOTracking
* instance
;
731 uintptr_t inst
, laddr
, raddr
;
733 inst
= ((typeof(inst
) *) left
)[0];
734 instance
= (typeof(instance
)) INSTANCE_GET(inst
);
735 if (kInstanceFlagAddress
& inst
) laddr
= ~((IOTrackingAddress
*)instance
)->address
;
736 else laddr
= (uintptr_t) (instance
+ 1);
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);
743 return ((laddr
> raddr
) ? 1 : ((laddr
== raddr
) ? 0 : -1));
748 IOTrackingZoneElementCompare(const void * left
, const void * right
)
750 uintptr_t inst
, laddr
, raddr
;
752 inst
= ((typeof(inst
) *) left
)[0];
753 laddr
= INSTANCE_PUT(inst
);
754 inst
= ((typeof(inst
) *) right
)[0];
755 raddr
= INSTANCE_PUT(inst
);
757 return ((laddr
> raddr
) ? 1 : ((laddr
== raddr
) ? 0 : -1));
760 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
763 CopyOutKernelBacktrace(IOTrackingCallSite
* site
, IOTrackingCallSiteInfo
* siteInfo
)
766 mach_vm_address_t bt
, btEntry
;
768 btEntry
= site
->queue
->btEntry
;
769 for (j
= 0; j
< kIOTrackingCallSiteBTs
; j
++)
773 && (!bt
|| (j
== (kIOTrackingCallSiteBTs
- 1))))
778 siteInfo
->bt
[0][j
] = VM_KERNEL_UNSLIDE(bt
);
782 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
785 IOTrackingLeakScan(void * refcon
)
787 IOTrackingLeaksRef
* ref
= (typeof(ref
)) refcon
;
788 uintptr_t * instances
;
789 IOTracking
* instance
;
790 uint64_t vaddr
, vincr
;
792 uintptr_t ptr
, addr
, vphysaddr
, inst
;
794 uint32_t baseIdx
, lim
, ptrIdx
, count
;
796 AbsoluteTime deadline
;
798 instances
= ref
->instances
;
800 size
= ref
->zoneSize
;
802 for (deadline
= 0, vaddr
= VM_MIN_KERNEL_AND_KEXT_ADDRESS
;
806 if ((mach_absolute_time() > deadline
) || (vaddr
>= VM_MAX_KERNEL_ADDRESS
))
810 ml_set_interrupts_enabled(is
);
813 if (vaddr
>= VM_MAX_KERNEL_ADDRESS
) break;
814 is
= ml_set_interrupts_enabled(false);
815 clock_interval_to_deadline(10, kMillisecondScale
, &deadline
);
818 ppn
= kernel_pmap_present_mapping(vaddr
, &vincr
, &vphysaddr
);
819 // check noencrypt to avoid VM structs (map entries) with pointers
820 if (ppn
&& (!pmap_valid_page(ppn
) || (!ref
->zoneSize
&& pmap_is_noencrypt(ppn
)))) ppn
= 0;
823 for (ptrIdx
= 0; ptrIdx
< (page_size
/ sizeof(uintptr_t)); ptrIdx
++)
825 ptr
= ((uintptr_t *)vphysaddr
)[ptrIdx
];
827 for (lim
= count
, baseIdx
= 0; lim
; lim
>>= 1)
829 inst
= instances
[baseIdx
+ (lim
>> 1)];
830 instance
= (typeof(instance
)) INSTANCE_GET(inst
);
834 addr
= INSTANCE_PUT(inst
) & ~kInstanceFlags
;
836 else if (kInstanceFlagAddress
& inst
)
838 addr
= ~((IOTrackingAddress
*)instance
)->address
;
839 size
= ((IOTrackingAddress
*)instance
)->size
;
843 addr
= (uintptr_t) (instance
+ 1);
844 size
= instance
->site
->queue
->allocSize
;
846 if ((ptr
>= addr
) && (ptr
< (addr
+ size
))
848 && (((vaddr
+ ptrIdx
* sizeof(uintptr_t)) < addr
)
849 || ((vaddr
+ ptrIdx
* sizeof(uintptr_t)) >= (addr
+ size
))))
851 if (!(kInstanceFlagReferenced
& inst
))
853 inst
|= kInstanceFlagReferenced
;
854 instances
[baseIdx
+ (lim
>> 1)] = inst
;
862 baseIdx
+= (lim
>> 1) + 1;
868 ref
->bytes
+= page_size
;
872 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
875 zone_leaks_scan(uintptr_t * instances
, uint32_t count
, uint32_t zoneSize
, uint32_t * found
)
877 IOTrackingLeaksRef ref
;
878 IOTrackingCallSiteInfo siteInfo
;
881 qsort(instances
, count
, sizeof(*instances
), &IOTrackingZoneElementCompare
);
883 bzero(&siteInfo
, sizeof(siteInfo
));
884 bzero(&ref
, sizeof(ref
));
885 ref
.instances
= instances
;
887 ref
.zoneSize
= zoneSize
;
889 for (idx
= 0; idx
< 2; idx
++)
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;
900 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
903 ZoneSiteProc(void * refCon
, uint32_t siteCount
, uint32_t zoneSize
,
904 uintptr_t * backtrace
, uint32_t btCount
)
906 IOTrackingCallSiteInfo siteInfo
;
910 leakData
= (typeof(leakData
)) refCon
;
912 bzero(&siteInfo
, sizeof(siteInfo
));
913 siteInfo
.count
= siteCount
;
914 siteInfo
.size
[0] = zoneSize
* siteCount
;
916 for (idx
= 0; (idx
< btCount
) && (idx
< kIOTrackingCallSiteBTs
); idx
++)
918 siteInfo
.bt
[0][idx
] = VM_KERNEL_UNSLIDE(backtrace
[idx
]);
921 leakData
->appendBytes(&siteInfo
, sizeof(siteInfo
));
925 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
928 IOTrackingLeaks(OSData
* data
)
930 IOTrackingLeaksRef ref
;
931 IOTrackingCallSiteInfo siteInfo
;
932 IOTrackingCallSite
* site
;
934 uintptr_t * instances
;
935 IOTracking
* instance
;
937 uint32_t count
, idx
, numSites
, dups
, siteCount
;
939 instances
= (typeof(instances
)) data
->getBytesNoCopy();
940 count
= (data
->getLength() / sizeof(*instances
));
941 qsort(instances
, count
, sizeof(*instances
), &IOTrackingAddressCompare
);
943 bzero(&siteInfo
, sizeof(siteInfo
));
944 bzero(&ref
, sizeof(ref
));
945 ref
.instances
= instances
;
947 for (idx
= 0; idx
< 2; idx
++)
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;
955 leakData
= OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo
));
957 for (numSites
= 0, idx
= 0; idx
< count
; idx
++)
959 inst
= instances
[idx
];
960 if (kInstanceFlagReferenced
& inst
) continue;
961 instance
= (typeof(instance
)) INSTANCE_GET(inst
);
962 site
= instance
->site
;
963 instances
[numSites
] = (uintptr_t) site
;
967 for (idx
= 0; idx
< numSites
; idx
++)
969 inst
= instances
[idx
];
971 site
= (typeof(site
)) inst
;
972 for (siteCount
= 1, dups
= (idx
+ 1); dups
< numSites
; dups
++)
974 if (instances
[dups
] == (uintptr_t) site
)
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
));
991 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
994 SkipName(uint32_t options
, const char * name
, size_t namesLen
, const char * names
)
1001 if (!namesLen
|| !names
) return (false);
1002 // <len><name>...<len><name><0>
1003 exclude
= (0 != (kIOTrackingExcludeNames
& options
));
1004 qLen
= strlen(name
);
1012 if (next
>= (names
+ namesLen
)) break;
1013 found
= ((sLen
== qLen
) && !strncmp(scan
, name
, sLen
));
1016 while (!found
&& (scan
< (names
+ namesLen
)));
1018 return (!(exclude
^ found
));
1021 #endif /* IOTRACKING */
1023 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1026 IOTrackingDebug(uint32_t selector
, uint32_t options
, uint64_t value
,
1027 const char * names
, size_t namesLen
,
1028 size_t size
, OSObject
** result
)
1033 if (result
) *result
= 0;
1035 ret
= kIOReturnNotReady
;
1040 IOTrackingQueue
* queue
;
1041 IOTracking
* instance
;
1042 IOTrackingCallSite
* site
;
1043 IOTrackingCallSiteInfo siteInfo
;
1044 IOTrackingUser
* user
;
1046 mach_vm_address_t mapAddress
;
1047 mach_vm_size_t mapSize
;
1048 uint32_t num
, idx
, qIdx
;
1049 uintptr_t instFlags
;
1053 ret
= kIOReturnNotFound
;
1055 if (kIOTrackingGetMappings
== selector
)
1059 proc
= proc_find(value
);
1060 if (!proc
) return (kIOReturnNotFound
);
1064 bzero(&siteInfo
, sizeof(siteInfo
));
1065 lck_mtx_lock(gIOTrackingLock
);
1066 queue_iterate(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
)
1068 if (SkipName(options
, queue
->name
, namesLen
, names
)) continue;
1070 if (!(kIOTracking
& gIOKitDebug
) && (kIOTrackingQueueTypeAlloc
& queue
->type
)) continue;
1074 case kIOTrackingResetTracking
:
1076 IOTrackingReset(queue
);
1077 ret
= kIOReturnSuccess
;
1081 case kIOTrackingStartCapture
:
1082 case kIOTrackingStopCapture
:
1084 queue
->captureOn
= (kIOTrackingStartCapture
== selector
);
1085 ret
= kIOReturnSuccess
;
1089 case kIOTrackingSetMinCaptureSize
:
1091 queue
->minCaptureSize
= size
;
1092 ret
= kIOReturnSuccess
;
1096 case kIOTrackingLeaks
:
1098 if (!(kIOTrackingQueueTypeAlloc
& queue
->type
)) break;
1100 if (!data
) data
= OSData::withCapacity(1024 * sizeof(uintptr_t));
1102 IOTRecursiveLockLock(&queue
->lock
);
1103 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++)
1105 queue_iterate(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
)
1108 queue_iterate(&site
->instances
, instance
, IOTracking
*, link
)
1110 if (instance
== site
->addresses
) addresses
= true;
1111 instFlags
= (typeof(instFlags
)) instance
;
1112 if (addresses
) instFlags
|= kInstanceFlagAddress
;
1113 data
->appendBytes(&instFlags
, sizeof(instFlags
));
1118 ret
= kIOReturnSuccess
;
1122 case kIOTrackingGetTracking
:
1124 if (kIOTrackingQueueTypeMap
& queue
->type
) break;
1126 if (!data
) data
= OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo
));
1128 IOTRecursiveLockLock(&queue
->lock
);
1129 num
= queue
->siteCount
;
1131 for (qIdx
= 0; qIdx
< queue
->numSiteQs
; qIdx
++)
1133 queue_iterate(&queue
->sites
[qIdx
], site
, IOTrackingCallSite
*, link
)
1138 if (size
&& ((site
->size
[0] + site
->size
[1]) < size
)) continue;
1140 siteInfo
.count
= site
->count
;
1141 siteInfo
.size
[0] = site
->size
[0];
1142 siteInfo
.size
[1] = site
->size
[1];
1144 CopyOutKernelBacktrace(site
, &siteInfo
);
1145 data
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1149 IOTRecursiveLockUnlock(&queue
->lock
);
1150 ret
= kIOReturnSuccess
;
1154 case kIOTrackingGetMappings
:
1156 if (!(kIOTrackingQueueTypeMap
& queue
->type
)) break;
1157 if (!data
) data
= OSData::withCapacity(page_size
);
1159 IOTRecursiveLockLock(&queue
->lock
);
1160 num
= queue
->siteCount
;
1162 for (qIdx
= 0; qIdx
< queue
->numSiteQs
; qIdx
++)
1164 queue_iterate(&queue
->sites
[qIdx
], user
, IOTrackingUser
*, link
)
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;
1175 siteInfo
.size
[0] = mapSize
;
1176 siteInfo
.address
= mapAddress
;
1177 siteInfo
.addressPID
= task_pid(mapTask
);
1178 siteInfo
.btPID
= user
->btPID
;
1180 for (uint32_t j
= 0; j
< kIOTrackingCallSiteBTs
; j
++)
1182 siteInfo
.bt
[0][j
] = VM_KERNEL_UNSLIDE(user
->bt
[j
]);
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
++)
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
];
1192 data
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1196 IOTRecursiveLockUnlock(&queue
->lock
);
1197 ret
= kIOReturnSuccess
;
1202 ret
= kIOReturnUnsupported
;
1207 if ((kIOTrackingLeaks
== selector
) && data
)
1209 data
= IOTrackingLeaks(data
);
1210 queue_iterate(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
)
1212 if (SkipName(options
, queue
->name
, namesLen
, names
)) continue;
1213 if (!(kIOTrackingQueueTypeAlloc
& queue
->type
)) continue;
1214 IOTRecursiveLockUnlock(&queue
->lock
);
1218 lck_mtx_unlock(gIOTrackingLock
);
1220 if ((kIOTrackingLeaks
== selector
) && namesLen
&& names
)
1226 if (!data
) data
= OSData::withCapacity(4096 * sizeof(uintptr_t));
1228 // <len><name>...<len><name><0>
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
;
1241 while (scan
< (names
+ namesLen
));
1244 if (data
) switch (selector
)
1246 case kIOTrackingLeaks
:
1247 case kIOTrackingGetTracking
:
1248 case kIOTrackingGetMappings
:
1250 IOTrackingCallSiteInfo
* siteInfos
;
1251 siteInfos
= (typeof(siteInfos
)) data
->getBytesNoCopy();
1252 num
= (data
->getLength() / sizeof(*siteInfos
));
1253 qsort(siteInfos
, num
, sizeof(*siteInfos
), &IOTrackingCallSiteInfoCompare
);
1256 default: assert(false); break;
1260 if (proc
) proc_rele(proc
);
1262 #endif /* IOTRACKING */
1267 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1269 #include <IOKit/IOKitDiagnosticsUserClient.h>
1271 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1274 #define super IOUserClient
1276 OSDefineMetaClassAndStructors(IOKitDiagnosticsClient
, IOUserClient
)
1278 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1280 IOUserClient
* IOKitDiagnosticsClient::withTask(task_t owningTask
)
1282 IOKitDiagnosticsClient
* inst
;
1284 inst
= new IOKitDiagnosticsClient
;
1285 if (inst
&& !inst
->init())
1294 IOReturn
IOKitDiagnosticsClient::clientClose(void)
1297 return (kIOReturnSuccess
);
1300 IOReturn
IOKitDiagnosticsClient::setProperties(OSObject
* properties
)
1302 IOReturn kr
= kIOReturnUnsupported
;
1306 IOReturn
IOKitDiagnosticsClient::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
1307 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
1309 IOReturn ret
= kIOReturnBadArgument
;
1310 const IOKitDiagnosticsParameters
* params
;
1315 if (args
->structureInputSize
< sizeof(IOKitDiagnosticsParameters
)) return (kIOReturnBadArgument
);
1316 params
= (typeof(params
)) args
->structureInput
;
1317 if (!params
) return (kIOReturnBadArgument
);
1320 namesLen
= args
->structureInputSize
- sizeof(IOKitDiagnosticsParameters
);
1321 if (namesLen
) names
= (typeof(names
))(params
+ 1);
1323 ret
= IOTrackingDebug(selector
, params
->options
, params
->value
, names
, namesLen
, params
->size
, &result
);
1325 if ((kIOReturnSuccess
== ret
) && args
->structureVariableOutputData
) *args
->structureVariableOutputData
= result
;
1326 else if (result
) result
->release();
1331 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */