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
, iotrace
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &gIOKitTrace
, "trace io");
69 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
72 int changed
, error
= sysctl_io_number(req
, gIOKitDebug
, sizeof(gIOKitDebug
), &newValue
, &changed
);
74 gIOKitDebug
= ((gIOKitDebug
& ~kIOKitDebugUserOptions
) | (newValue
& kIOKitDebugUserOptions
));
79 SYSCTL_PROC(_debug
, OID_AUTO
, iokit
,
80 CTLTYPE_QUAD
| IODEBUG_CTLFLAGS
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
81 &gIOKitDebug
, 0, sysctl_debug_iokit
, "Q", "boot_arg io");
83 size_t debug_malloc_size
;
84 size_t debug_iomalloc_size
;
86 vm_size_t debug_iomallocpageable_size
;
87 size_t debug_container_malloc_size
;
88 // int debug_ivars_size; // in OSObject.cpp
92 #define DEBG(fmt, args...) { kprintf(fmt, ## args); }
94 #define DEBG(fmt, args...) { IOLog(fmt, ## args); }
98 IOPrintPlane( const IORegistryPlane
* plane
)
100 IORegistryEntry
* next
;
101 IORegistryIterator
* iter
;
103 char format
[] = "%xxxs";
106 iter
= IORegistryIterator::iterateOver( plane
);
108 all
= iter
->iterateAll();
110 DEBG("Count %d\n", all
->getCount());
117 while ((next
= iter
->getNextObjectRecursive())) {
118 snprintf(format
+ 1, sizeof(format
) - 1, "%ds", 2 * next
->getDepth( plane
));
120 DEBG( "\033[33m%s", next
->getName( plane
));
121 if ((next
->getLocation( plane
))) {
122 DEBG("@%s", next
->getLocation( plane
));
124 DEBG("\033[0m <class %s", next
->getMetaClass()->getClassName());
125 if ((service
= OSDynamicCast(IOService
, next
))) {
126 DEBG(", busy %ld", (long) service
->getBusyState());
140 db_dumpiojunk( const IORegistryPlane
* plane __unused
)
145 IOPrintMemory( void )
147 // OSMetaClass::printInstanceCounts();
150 "ivar kalloc() 0x%08lx\n"
152 "containers kalloc() 0x%08lx\n"
153 "IOMalloc() 0x%08lx\n"
154 "----------------------------------------\n",
157 debug_container_malloc_size
,
163 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
165 #define super OSObject
166 OSDefineMetaClassAndStructors(IOKitDiagnostics
, OSObject
)
168 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
170 OSObject
* IOKitDiagnostics::diagnostics( void )
172 IOKitDiagnostics
* diags
;
174 diags
= new IOKitDiagnostics
;
175 if (diags
&& !diags
->init()) {
184 IOKitDiagnostics::updateOffset( OSDictionary
* dict
,
185 UInt64 value
, const char * name
)
189 off
= OSNumber::withNumber( value
, 64 );
194 dict
->setObject( name
, off
);
199 IOKitDiagnostics::serialize(OSSerialize
*s
) const
204 dict
= OSDictionary::withCapacity( 5 );
209 updateOffset( dict
, debug_ivars_size
, "Instance allocation" );
210 updateOffset( dict
, debug_container_malloc_size
, "Container allocation" );
211 updateOffset( dict
, debug_iomalloc_size
, "IOMalloc allocation" );
212 updateOffset( dict
, debug_iomallocpageable_size
, "Pageable allocation" );
214 OSMetaClass::serializeClassDictionary(dict
);
216 ok
= dict
->serialize( s
);
223 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
227 #include <libkern/c++/OSCPPDebug.h>
228 #include <libkern/c++/OSKext.h>
229 #include <kern/zalloc.h>
231 __private_extern__
"C" void qsort(
235 int (*)(const void *, const void *));
237 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
238 extern "C" ppnum_t
pmap_valid_page(ppnum_t pn
);
240 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
242 struct IOTRecursiveLock
{
248 struct IOTrackingQueue
{
250 IOTRecursiveLock lock
;
254 size_t minCaptureSize
;
259 queue_head_t sites
[];
263 struct IOTrackingCallSiteUser
{
267 uintptr_t bt
[kIOTrackingCallSiteBTs
];
270 struct IOTrackingCallSite
{
272 queue_head_t instances
;
273 IOTrackingQueue
* queue
;
274 IOTracking
* addresses
;
284 uintptr_t bt
[kIOTrackingCallSiteBTs
];
285 IOTrackingCallSiteUser user
[0];
289 struct IOTrackingLeaksRef
{
290 uintptr_t * instances
;
298 lck_mtx_t
* gIOTrackingLock
;
299 queue_head_t gIOTrackingQ
;
302 kTrackingAddressFlagAllocated
= 0x00000001
305 #if defined(__LP64__)
306 #define IOTrackingAddressFlags(ptr) (ptr->flags)
308 #define IOTrackingAddressFlags(ptr) (ptr->tracking.flags)
311 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
314 IOTRecursiveLockLock(IOTRecursiveLock
* lock
)
316 if (lock
->thread
== current_thread()) {
319 lck_mtx_lock(lock
->mutex
);
320 assert(lock
->thread
== NULL
);
321 assert(lock
->count
== 0);
322 lock
->thread
= current_thread();
328 IOTRecursiveLockUnlock(IOTRecursiveLock
* lock
)
330 assert(lock
->thread
== current_thread());
331 if (0 == (--lock
->count
)) {
333 lck_mtx_unlock(lock
->mutex
);
337 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
342 queue_init(&gIOTrackingQ
);
343 gIOTrackingLock
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
);
346 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
349 IOTrackingQueueAlloc(const char * name
, uintptr_t btEntry
,
350 size_t allocSize
, size_t minCaptureSize
,
351 uint32_t type
, uint32_t numSiteQs
)
353 IOTrackingQueue
* queue
;
359 queue
= (typeof(queue
))kalloc(sizeof(IOTrackingQueue
) + numSiteQs
* sizeof(queue
->sites
[0]));
360 bzero(queue
, sizeof(IOTrackingQueue
));
363 queue
->btEntry
= btEntry
;
364 queue
->allocSize
= allocSize
;
365 queue
->minCaptureSize
= minCaptureSize
;
366 queue
->lock
.mutex
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
);
367 queue
->numSiteQs
= numSiteQs
;
369 enum { kFlags
= (kIOTracking
| kIOTrackingBoot
) };
370 queue
->captureOn
= (kFlags
== (kFlags
& gIOKitDebug
))
371 || (kIOTrackingQueueTypeDefaultOn
& type
);
373 for (idx
= 0; idx
< numSiteQs
; idx
++) {
374 queue_init(&queue
->sites
[idx
]);
377 lck_mtx_lock(gIOTrackingLock
);
378 queue_enter(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
);
379 lck_mtx_unlock(gIOTrackingLock
);
385 IOTrackingQueueCollectUser(IOTrackingQueue
* queue
)
387 assert(0 == queue
->siteCount
);
388 queue
->type
|= kIOTrackingQueueTypeUser
;
391 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
394 IOTrackingQueueFree(IOTrackingQueue
* queue
)
396 lck_mtx_lock(gIOTrackingLock
);
397 IOTrackingReset(queue
);
398 remque(&queue
->link
);
399 lck_mtx_unlock(gIOTrackingLock
);
401 lck_mtx_free(queue
->lock
.mutex
, IOLockGroup
);
403 kfree(queue
, sizeof(IOTrackingQueue
) + queue
->numSiteQs
* sizeof(queue
->sites
[0]));
406 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
411 * Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
413 * Permission is hereby granted, free of charge, to any person
414 * obtaining a copy of this software and associated documentation
415 * files (the "Software"), to deal in the Software without
416 * restriction, including without limitation the rights to use, copy,
417 * modify, merge, publish, distribute, sublicense, and/or sell copies
418 * of the Software, and to permit persons to whom the Software is
419 * furnished to do so, subject to the following conditions:
421 * The above copyright notice and this permission notice shall be
422 * included in all copies or substantial portions of the Software.
424 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
425 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
426 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
427 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
428 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
429 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
430 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
435 // Compression function for Merkle-Damgard construction.
436 // This function is generated using the framework provided.
439 (h) *= 0x2127599bf4325c37ULL; \
443 fasthash64(const void *buf
, size_t len
, uint64_t seed
)
445 const uint64_t m
= 0x880355f21e6d1965ULL
;
446 const uint64_t *pos
= (const uint64_t *)buf
;
447 const uint64_t *end
= pos
+ (len
/ 8);
448 const unsigned char *pos2
;
449 uint64_t h
= seed
^ (len
* m
);
458 pos2
= (const unsigned char*)pos
;
462 case 7: v
^= (uint64_t)pos2
[6] << 48;
463 [[clang::fallthrough]];
464 case 6: v
^= (uint64_t)pos2
[5] << 40;
465 [[clang::fallthrough]];
466 case 5: v
^= (uint64_t)pos2
[4] << 32;
467 [[clang::fallthrough]];
468 case 4: v
^= (uint64_t)pos2
[3] << 24;
469 [[clang::fallthrough]];
470 case 3: v
^= (uint64_t)pos2
[2] << 16;
471 [[clang::fallthrough]];
472 case 2: v
^= (uint64_t)pos2
[1] << 8;
473 [[clang::fallthrough]];
474 case 1: v
^= (uint64_t)pos2
[0];
482 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
485 fasthash32(const void *buf
, size_t len
, uint32_t seed
)
487 // the following trick converts the 64-bit hashcode to Fermat
488 // residue, which shall retain information from both the higher
489 // and lower parts of hashcode.
490 uint64_t h
= fasthash64(buf
, len
, seed
);
491 return (uint32_t) (h
- (h
>> 32));
494 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
497 IOTrackingAddUser(IOTrackingQueue
* queue
, IOTrackingUser
* mem
, vm_size_t size
)
502 if (!queue
->captureOn
) {
505 if (size
< queue
->minCaptureSize
) {
509 assert(!mem
->link
.next
);
511 num
= backtrace(&mem
->bt
[0], kIOTrackingCallSiteBTs
, NULL
);
513 if ((kernel_task
!= current_task()) && (pid
= proc_selfpid())) {
514 bool user_64
= false;
516 num
= backtrace_user(&mem
->btUser
[0], kIOTrackingCallSiteBTs
- 1, NULL
,
518 mem
->user32
= !user_64
;
520 assert(num
<= kIOTrackingCallSiteBTs
);
521 static_assert(kIOTrackingCallSiteBTs
<= UINT8_MAX
);
522 mem
->userCount
= ((uint8_t) num
);
524 IOTRecursiveLockLock(&queue
->lock
);
525 queue_enter
/*last*/ (&queue
->sites
[0], mem
, IOTrackingUser
*, link
);
527 IOTRecursiveLockUnlock(&queue
->lock
);
531 IOTrackingRemoveUser(IOTrackingQueue
* queue
, IOTrackingUser
* mem
)
533 if (!mem
->link
.next
) {
537 IOTRecursiveLockLock(&queue
->lock
);
538 if (mem
->link
.next
) {
540 assert(queue
->siteCount
);
543 IOTRecursiveLockUnlock(&queue
->lock
);
546 uint64_t gIOTrackingAddTime
;
549 IOTrackingAdd(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
, bool address
, vm_tag_t tag
)
551 IOTrackingCallSite
* site
;
553 uintptr_t bt
[kIOTrackingCallSiteBTs
+ 1];
554 uintptr_t btUser
[kIOTrackingCallSiteBTs
];
564 if (!queue
->captureOn
) {
567 if (size
< queue
->minCaptureSize
) {
571 user
= (0 != (kIOTrackingQueueTypeUser
& queue
->type
));
573 assert(!mem
->link
.next
);
575 num
= backtrace(&bt
[0], kIOTrackingCallSiteBTs
+ 1, NULL
);
580 crc
= fasthash32(&bt
[1], num
* sizeof(bt
[0]), 0x04C11DB7);
586 if ((kernel_task
!= current_task()) && (pid
= proc_selfpid())) {
587 userCount
= backtrace_user(&btUser
[0], kIOTrackingCallSiteBTs
, NULL
, &user64
, NULL
);
588 assert(userCount
<= kIOTrackingCallSiteBTs
);
589 crc
= fasthash32(&btUser
[0], userCount
* sizeof(bt
[0]), crc
);
593 IOTRecursiveLockLock(&queue
->lock
);
594 que
= &queue
->sites
[crc
% queue
->numSiteQs
];
595 queue_iterate(que
, site
, IOTrackingCallSite
*, link
)
597 if (tag
!= site
->tag
) {
600 if (user
&& (pid
!= site
->user
[0].pid
)) {
603 if (crc
== site
->crc
) {
608 if (queue_end(que
, (queue_entry_t
) site
)) {
609 size_t siteSize
= sizeof(IOTrackingCallSite
);
611 siteSize
+= sizeof(IOTrackingCallSiteUser
);
613 site
= (typeof(site
))kalloc(siteSize
);
615 queue_init(&site
->instances
);
616 site
->addresses
= (IOTracking
*) &site
->instances
;
621 memset(&site
->size
[0], 0, sizeof(site
->size
));
622 bcopy(&bt
[1], &site
->bt
[0], num
* sizeof(site
->bt
[0]));
623 assert(num
<= kIOTrackingCallSiteBTs
);
624 bzero(&site
->bt
[num
], (kIOTrackingCallSiteBTs
- num
) * sizeof(site
->bt
[0]));
626 bcopy(&btUser
[0], &site
->user
[0].bt
[0], userCount
* sizeof(site
->user
[0].bt
[0]));
627 assert(userCount
<= kIOTrackingCallSiteBTs
);
628 bzero(&site
->user
[0].bt
[userCount
], (kIOTrackingCallSiteBTs
- userCount
) * sizeof(site
->user
[0].bt
[0]));
629 site
->user
[0].pid
= pid
;
630 site
->user
[0].user32
= !user64
;
631 static_assert(kIOTrackingCallSiteBTs
<= UINT8_MAX
);
632 site
->user
[0].userCount
= ((uint8_t) userCount
);
634 queue_enter_first(que
, site
, IOTrackingCallSite
*, link
);
639 queue_enter
/*last*/ (&site
->instances
, mem
, IOTracking
*, link
);
640 if (queue_end(&site
->instances
, (queue_entry_t
)site
->addresses
)) {
641 site
->addresses
= mem
;
644 queue_enter_first(&site
->instances
, mem
, IOTracking
*, link
);
648 site
->size
[0] += size
;
651 IOTRecursiveLockUnlock(&queue
->lock
);
654 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
657 IOTrackingRemove(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
)
659 if (!mem
->link
.next
) {
663 IOTRecursiveLockLock(&queue
->lock
);
664 if (mem
->link
.next
) {
667 if (mem
== mem
->site
->addresses
) {
668 mem
->site
->addresses
= (IOTracking
*) queue_next(&mem
->link
);
672 assert(mem
->site
->count
);
674 assert(mem
->site
->size
[0] >= size
);
675 mem
->site
->size
[0] -= size
;
676 if (!mem
->site
->count
) {
677 assert(queue_empty(&mem
->site
->instances
));
678 assert(!mem
->site
->size
[0]);
679 assert(!mem
->site
->size
[1]);
681 remque(&mem
->site
->link
);
682 assert(queue
->siteCount
);
684 size_t siteSize
= sizeof(IOTrackingCallSite
);
685 if (kIOTrackingQueueTypeUser
& queue
->type
) {
686 siteSize
+= sizeof(IOTrackingCallSiteUser
);
688 kfree(mem
->site
, siteSize
);
692 IOTRecursiveLockUnlock(&queue
->lock
);
695 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
698 IOTrackingAlloc(IOTrackingQueue
* queue
, uintptr_t address
, size_t size
)
700 IOTrackingAddress
* tracking
;
702 if (!queue
->captureOn
) {
705 if (size
< queue
->minCaptureSize
) {
710 tracking
= (typeof(tracking
))kalloc(sizeof(IOTrackingAddress
));
711 bzero(tracking
, sizeof(IOTrackingAddress
));
712 IOTrackingAddressFlags(tracking
) |= kTrackingAddressFlagAllocated
;
713 tracking
->address
= address
;
714 tracking
->size
= size
;
716 IOTrackingAdd(queue
, &tracking
->tracking
, size
, true, VM_KERN_MEMORY_NONE
);
719 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
722 IOTrackingFree(IOTrackingQueue
* queue
, uintptr_t address
, size_t size
)
724 IOTrackingCallSite
* site
;
725 IOTrackingAddress
* tracking
;
730 IOTRecursiveLockLock(&queue
->lock
);
732 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++) {
733 queue_iterate(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
)
735 tracking
= (IOTrackingAddress
*) site
->addresses
;
736 while (!queue_end(&site
->instances
, &tracking
->tracking
.link
)) {
737 if ((done
= (address
== tracking
->address
))) {
738 IOTrackingRemove(queue
, &tracking
->tracking
, size
);
739 kfree(tracking
, sizeof(IOTrackingAddress
));
742 tracking
= (IOTrackingAddress
*) queue_next(&tracking
->tracking
.link
);
753 IOTRecursiveLockUnlock(&queue
->lock
);
756 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
759 IOTrackingAccumSize(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
)
761 IOTRecursiveLockLock(&queue
->lock
);
762 if (mem
->link
.next
) {
764 assert((size
> 0) || (mem
->site
->size
[1] >= -size
));
765 mem
->site
->size
[1] += size
;
768 IOTRecursiveLockUnlock(&queue
->lock
);
771 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
774 IOTrackingReset(IOTrackingQueue
* queue
)
776 IOTrackingCallSite
* site
;
777 IOTrackingUser
* user
;
778 IOTracking
* tracking
;
779 IOTrackingAddress
* trackingAddress
;
783 IOTRecursiveLockLock(&queue
->lock
);
784 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++) {
785 while (!queue_empty(&queue
->sites
[idx
])) {
786 if (kIOTrackingQueueTypeMap
& queue
->type
) {
787 queue_remove_first(&queue
->sites
[idx
], user
, IOTrackingUser
*, link
);
788 user
->link
.next
= user
->link
.prev
= NULL
;
790 queue_remove_first(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
);
792 while (!queue_empty(&site
->instances
)) {
793 queue_remove_first(&site
->instances
, tracking
, IOTracking
*, link
);
794 if (tracking
== site
->addresses
) {
798 trackingAddress
= (typeof(trackingAddress
))tracking
;
799 if (kTrackingAddressFlagAllocated
& IOTrackingAddressFlags(trackingAddress
)) {
800 kfree(tracking
, sizeof(IOTrackingAddress
));
804 size_t siteSize
= sizeof(IOTrackingCallSite
);
805 if (kIOTrackingQueueTypeUser
& queue
->type
) {
806 siteSize
+= sizeof(IOTrackingCallSiteUser
);
808 kfree(site
, siteSize
);
812 queue
->siteCount
= 0;
813 IOTRecursiveLockUnlock(&queue
->lock
);
816 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
819 IOTrackingCallSiteInfoCompare(const void * left
, const void * right
)
821 IOTrackingCallSiteInfo
* l
= (typeof(l
))left
;
822 IOTrackingCallSiteInfo
* r
= (typeof(r
))right
;
825 rsize
= r
->size
[0] + r
->size
[1];
826 lsize
= l
->size
[0] + l
->size
[1];
828 return (rsize
> lsize
) ? 1 : ((rsize
== lsize
) ? 0 : -1);
831 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
834 IOTrackingAddressCompare(const void * left
, const void * right
)
836 IOTracking
* instance
;
837 uintptr_t inst
, laddr
, raddr
;
839 inst
= ((typeof(inst
) *)left
)[0];
840 instance
= (typeof(instance
))INSTANCE_GET(inst
);
841 if (kInstanceFlagAddress
& inst
) {
842 laddr
= ~((IOTrackingAddress
*)instance
)->address
;
844 laddr
= (uintptr_t) (instance
+ 1);
847 inst
= ((typeof(inst
) *)right
)[0];
848 instance
= (typeof(instance
))(inst
& ~kInstanceFlags
);
849 if (kInstanceFlagAddress
& inst
) {
850 raddr
= ~((IOTrackingAddress
*)instance
)->address
;
852 raddr
= (uintptr_t) (instance
+ 1);
855 return (laddr
> raddr
) ? 1 : ((laddr
== raddr
) ? 0 : -1);
860 IOTrackingZoneElementCompare(const void * left
, const void * right
)
862 uintptr_t inst
, laddr
, raddr
;
864 inst
= ((typeof(inst
) *)left
)[0];
865 laddr
= INSTANCE_PUT(inst
);
866 inst
= ((typeof(inst
) *)right
)[0];
867 raddr
= INSTANCE_PUT(inst
);
869 return (laddr
> raddr
) ? 1 : ((laddr
== raddr
) ? 0 : -1);
872 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
875 CopyOutBacktraces(IOTrackingCallSite
* site
, IOTrackingCallSiteInfo
* siteInfo
)
878 mach_vm_address_t bt
, btEntry
;
880 btEntry
= site
->queue
->btEntry
;
881 for (j
= 0; j
< kIOTrackingCallSiteBTs
; j
++) {
884 && (!bt
|| (j
== (kIOTrackingCallSiteBTs
- 1)))) {
888 siteInfo
->bt
[0][j
] = VM_KERNEL_UNSLIDE(bt
);
892 if (kIOTrackingQueueTypeUser
& site
->queue
->type
) {
893 siteInfo
->btPID
= site
->user
[0].pid
;
894 uint32_t * bt32
= (typeof(bt32
))((void *) &site
->user
[0].bt
[0]);
895 uint64_t * bt64
= (typeof(bt64
))((void *) &site
->user
[0].bt
[0]);
896 for (uint32_t j
= 0; j
< kIOTrackingCallSiteBTs
; j
++) {
897 if (j
>= site
->user
[0].userCount
) {
898 siteInfo
->bt
[1][j
] = 0;
899 } else if (site
->user
[0].user32
) {
900 siteInfo
->bt
[1][j
] = bt32
[j
];
902 siteInfo
->bt
[1][j
] = bt64
[j
];
908 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
911 IOTrackingLeakScan(void * refcon
)
913 IOTrackingLeaksRef
* ref
= (typeof(ref
))refcon
;
914 uintptr_t * instances
;
915 IOTracking
* instance
;
916 uint64_t vaddr
, vincr
;
918 uintptr_t ptr
, addr
, vphysaddr
, inst
;
919 size_t size
, origsize
;
920 uint32_t baseIdx
, lim
, ptrIdx
, count
;
922 AbsoluteTime deadline
;
924 instances
= ref
->instances
;
926 size
= origsize
= ref
->zoneSize
;
928 for (deadline
= 0, vaddr
= VM_MIN_KERNEL_AND_KEXT_ADDRESS
;
931 if ((mach_absolute_time() > deadline
) || (vaddr
>= VM_MAX_KERNEL_ADDRESS
)) {
933 ml_set_interrupts_enabled(is
);
936 if (vaddr
>= VM_MAX_KERNEL_ADDRESS
) {
939 is
= ml_set_interrupts_enabled(false);
940 clock_interval_to_deadline(10, kMillisecondScale
, &deadline
);
943 ppn
= kernel_pmap_present_mapping(vaddr
, &vincr
, &vphysaddr
);
944 // check noencrypt to avoid VM structs (map entries) with pointers
945 if (ppn
&& (!pmap_valid_page(ppn
) || (!ref
->zoneSize
&& pmap_is_noencrypt(ppn
)))) {
952 for (ptrIdx
= 0; ptrIdx
< (page_size
/ sizeof(uintptr_t)); ptrIdx
++) {
953 ptr
= ((uintptr_t *)vphysaddr
)[ptrIdx
];
954 #if defined(HAS_APPLE_PAC)
955 // strip possible ptrauth signature from candidate data pointer
956 ptr
= (uintptr_t)ptrauth_strip((void*)ptr
, ptrauth_key_process_independent_data
);
957 #endif /* defined(HAS_APPLE_PAC) */
959 for (lim
= count
, baseIdx
= 0; lim
; lim
>>= 1) {
960 inst
= instances
[baseIdx
+ (lim
>> 1)];
961 instance
= (typeof(instance
))INSTANCE_GET(inst
);
964 addr
= INSTANCE_PUT(inst
) & ~kInstanceFlags
;
965 } else if (kInstanceFlagAddress
& inst
) {
966 addr
= ~((IOTrackingAddress
*)instance
)->address
;
967 origsize
= size
= ((IOTrackingAddress
*)instance
)->size
;
972 addr
= (uintptr_t) (instance
+ 1);
973 origsize
= size
= instance
->site
->queue
->allocSize
;
975 if ((ptr
>= addr
) && (ptr
< (addr
+ size
))
977 && (((vaddr
+ ptrIdx
* sizeof(uintptr_t)) < addr
)
978 || ((vaddr
+ ptrIdx
* sizeof(uintptr_t)) >= (addr
+ size
)))) {
979 if (!(kInstanceFlagReferenced
& inst
)) {
980 inst
|= kInstanceFlagReferenced
;
981 instances
[baseIdx
+ (lim
>> 1)] = inst
;
991 baseIdx
+= (lim
>> 1) + 1;
997 ref
->bytes
+= page_size
;
1001 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1004 zone_leaks_scan(uintptr_t * instances
, uint32_t count
, uint32_t zoneSize
, uint32_t * found
)
1006 IOTrackingLeaksRef ref
;
1007 IOTrackingCallSiteInfo siteInfo
;
1010 qsort(instances
, count
, sizeof(*instances
), &IOTrackingZoneElementCompare
);
1012 bzero(&siteInfo
, sizeof(siteInfo
));
1013 bzero(&ref
, sizeof(ref
));
1014 ref
.instances
= instances
;
1016 ref
.zoneSize
= zoneSize
;
1018 for (idx
= 0; idx
< 2; idx
++) {
1020 IOTrackingLeakScan(&ref
);
1021 IOLog("leaks(%d) scanned %ld MB, instance count %d, found %d\n", idx
, ref
.bytes
/ 1024 / 1024, count
, ref
.found
);
1022 if (count
<= ref
.found
) {
1030 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1033 ZoneSiteProc(void * refCon
, uint32_t siteCount
, uint32_t zoneSize
,
1034 uintptr_t * backtrace
, uint32_t btCount
)
1036 IOTrackingCallSiteInfo siteInfo
;
1040 leakData
= (typeof(leakData
))refCon
;
1042 bzero(&siteInfo
, sizeof(siteInfo
));
1043 siteInfo
.count
= siteCount
;
1044 siteInfo
.size
[0] = zoneSize
* siteCount
;
1046 for (idx
= 0; (idx
< btCount
) && (idx
< kIOTrackingCallSiteBTs
); idx
++) {
1047 siteInfo
.bt
[0][idx
] = VM_KERNEL_UNSLIDE(backtrace
[idx
]);
1050 leakData
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1054 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1057 IOTrackingLeaks(LIBKERN_CONSUMED OSData
* data
)
1059 IOTrackingLeaksRef ref
;
1060 IOTrackingCallSiteInfo siteInfo
;
1061 IOTrackingCallSite
* site
;
1063 uintptr_t * instances
;
1064 IOTracking
* instance
;
1066 uint32_t count
, idx
, numSites
, dups
, siteCount
;
1068 instances
= (typeof(instances
))data
->getBytesNoCopy();
1069 count
= (data
->getLength() / sizeof(*instances
));
1070 qsort(instances
, count
, sizeof(*instances
), &IOTrackingAddressCompare
);
1072 bzero(&siteInfo
, sizeof(siteInfo
));
1073 bzero(&ref
, sizeof(ref
));
1074 ref
.instances
= instances
;
1076 for (idx
= 0; idx
< 2; idx
++) {
1078 IOTrackingLeakScan(&ref
);
1079 IOLog("leaks(%d) scanned %ld MB, instance count %d, found %d (zlen %d)\n", idx
, ref
.bytes
/ 1024 / 1024, count
, ref
.found
, ref
.foundzlen
);
1080 if (count
<= ref
.found
) {
1085 leakData
= OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo
));
1087 for (numSites
= 0, idx
= 0; idx
< count
; idx
++) {
1088 inst
= instances
[idx
];
1089 if (kInstanceFlagReferenced
& inst
) {
1092 instance
= (typeof(instance
))INSTANCE_GET(inst
);
1093 site
= instance
->site
;
1094 instances
[numSites
] = (uintptr_t) site
;
1098 for (idx
= 0; idx
< numSites
; idx
++) {
1099 inst
= instances
[idx
];
1103 site
= (typeof(site
))inst
;
1104 for (siteCount
= 1, dups
= (idx
+ 1); dups
< numSites
; dups
++) {
1105 if (instances
[dups
] == (uintptr_t) site
) {
1107 instances
[dups
] = 0;
1110 siteInfo
.count
= siteCount
;
1111 siteInfo
.size
[0] = (site
->size
[0] * site
->count
) / siteCount
;
1112 siteInfo
.size
[1] = (site
->size
[1] * site
->count
) / siteCount
;;
1113 CopyOutBacktraces(site
, &siteInfo
);
1114 leakData
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1121 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1124 SkipName(uint32_t options
, const char * name
, size_t namesLen
, const char * names
)
1128 bool exclude
, found
;
1131 if (!namesLen
|| !names
) {
1134 // <len><name>...<len><name><0>
1135 exclude
= (0 != (kIOTrackingExcludeNames
& options
));
1136 qLen
= strlen(name
);
1143 if (next
>= (names
+ namesLen
)) {
1146 found
= ((sLen
== qLen
) && !strncmp(scan
, name
, sLen
));
1148 }while (!found
&& (scan
< (names
+ namesLen
)));
1150 return !(exclude
^ found
);
1153 #endif /* IOTRACKING */
1155 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1157 static kern_return_t
1158 IOTrackingDebug(uint32_t selector
, uint32_t options
, uint64_t value
,
1159 uint32_t intag
, uint32_t inzsize
,
1160 const char * names
, size_t namesLen
,
1161 size_t size
, OSObject
** result
)
1170 ret
= kIOReturnNotReady
;
1175 IOTrackingQueue
* queue
;
1176 IOTracking
* instance
;
1177 IOTrackingCallSite
* site
;
1178 IOTrackingCallSiteInfo siteInfo
;
1179 IOTrackingUser
* user
;
1181 mach_vm_address_t mapAddress
;
1182 mach_vm_size_t mapSize
;
1183 uint32_t num
, idx
, qIdx
;
1184 uintptr_t instFlags
;
1188 ret
= kIOReturnNotFound
;
1190 if (kIOTrackingGetMappings
== selector
) {
1191 if (value
!= -1ULL) {
1192 proc
= proc_find((pid_t
) value
);
1194 return kIOReturnNotFound
;
1199 bzero(&siteInfo
, sizeof(siteInfo
));
1200 lck_mtx_lock(gIOTrackingLock
);
1201 queue_iterate(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
)
1203 if (SkipName(options
, queue
->name
, namesLen
, names
)) {
1207 if (!(kIOTracking
& gIOKitDebug
) && (kIOTrackingQueueTypeAlloc
& queue
->type
)) {
1212 case kIOTrackingResetTracking
:
1214 IOTrackingReset(queue
);
1215 ret
= kIOReturnSuccess
;
1219 case kIOTrackingStartCapture
:
1220 case kIOTrackingStopCapture
:
1222 queue
->captureOn
= (kIOTrackingStartCapture
== selector
);
1223 ret
= kIOReturnSuccess
;
1227 case kIOTrackingSetMinCaptureSize
:
1229 queue
->minCaptureSize
= size
;
1230 ret
= kIOReturnSuccess
;
1234 case kIOTrackingLeaks
:
1236 if (!(kIOTrackingQueueTypeAlloc
& queue
->type
)) {
1241 data
= OSData::withCapacity(1024 * sizeof(uintptr_t));
1244 IOTRecursiveLockLock(&queue
->lock
);
1245 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++) {
1246 queue_iterate(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
)
1249 queue_iterate(&site
->instances
, instance
, IOTracking
*, link
)
1251 if (instance
== site
->addresses
) {
1254 instFlags
= (typeof(instFlags
))instance
;
1256 instFlags
|= kInstanceFlagAddress
;
1258 data
->appendBytes(&instFlags
, sizeof(instFlags
));
1263 ret
= kIOReturnSuccess
;
1268 case kIOTrackingGetTracking
:
1270 if (kIOTrackingQueueTypeMap
& queue
->type
) {
1275 data
= OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo
));
1278 IOTRecursiveLockLock(&queue
->lock
);
1279 num
= queue
->siteCount
;
1281 for (qIdx
= 0; qIdx
< queue
->numSiteQs
; qIdx
++) {
1282 queue_iterate(&queue
->sites
[qIdx
], site
, IOTrackingCallSite
*, link
)
1288 uint32_t count
= site
->count
;
1289 tsize
[0] = site
->size
[0];
1290 tsize
[1] = site
->size
[1];
1292 if (intag
|| inzsize
) {
1294 vm_size_t size
, zoneSize
;
1297 if (kIOTrackingQueueTypeAlloc
& queue
->type
) {
1300 tsize
[0] = tsize
[1] = 0;
1301 queue_iterate(&site
->instances
, instance
, IOTracking
*, link
)
1303 if (instance
== site
->addresses
) {
1308 addr
= ~((IOTrackingAddress
*)instance
)->address
;
1310 addr
= (uintptr_t) (instance
+ 1);
1313 kr
= vm_kern_allocation_info(addr
, &size
, &tag
, &zoneSize
);
1314 if (KERN_SUCCESS
!= kr
) {
1318 if ((VM_KERN_MEMORY_NONE
!= intag
) && (intag
!= tag
)) {
1321 if (inzsize
&& (inzsize
!= zoneSize
)) {
1329 if (!intag
|| inzsize
|| (intag
!= site
->tag
)) {
1338 if (size
&& ((tsize
[0] + tsize
[1]) < size
)) {
1341 siteInfo
.count
= count
;
1342 siteInfo
.size
[0] = tsize
[0];
1343 siteInfo
.size
[1] = tsize
[1];
1344 CopyOutBacktraces(site
, &siteInfo
);
1345 data
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1349 IOTRecursiveLockUnlock(&queue
->lock
);
1350 ret
= kIOReturnSuccess
;
1354 case kIOTrackingGetMappings
:
1356 if (!(kIOTrackingQueueTypeMap
& queue
->type
)) {
1360 data
= OSData::withCapacity((unsigned int) page_size
);
1363 IOTRecursiveLockLock(&queue
->lock
);
1364 num
= queue
->siteCount
;
1366 for (qIdx
= 0; qIdx
< queue
->numSiteQs
; qIdx
++) {
1367 queue_iterate(&queue
->sites
[qIdx
], user
, IOTrackingUser
*, link
)
1372 kr
= IOMemoryMapTracking(user
, &mapTask
, &mapAddress
, &mapSize
);
1373 if (kIOReturnSuccess
!= kr
) {
1376 if (proc
&& (mapTask
!= proc_task(proc
))) {
1379 if (size
&& (mapSize
< size
)) {
1384 siteInfo
.size
[0] = mapSize
;
1385 siteInfo
.address
= mapAddress
;
1386 siteInfo
.addressPID
= task_pid(mapTask
);
1387 siteInfo
.btPID
= user
->btPID
;
1389 for (uint32_t j
= 0; j
< kIOTrackingCallSiteBTs
; j
++) {
1390 siteInfo
.bt
[0][j
] = VM_KERNEL_UNSLIDE(user
->bt
[j
]);
1392 uint32_t * bt32
= (typeof(bt32
)) & user
->btUser
[0];
1393 uint64_t * bt64
= (typeof(bt64
))((void *) &user
->btUser
[0]);
1394 for (uint32_t j
= 0; j
< kIOTrackingCallSiteBTs
; j
++) {
1395 if (j
>= user
->userCount
) {
1396 siteInfo
.bt
[1][j
] = 0;
1397 } else if (user
->user32
) {
1398 siteInfo
.bt
[1][j
] = bt32
[j
];
1400 siteInfo
.bt
[1][j
] = bt64
[j
];
1403 data
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1407 IOTRecursiveLockUnlock(&queue
->lock
);
1408 ret
= kIOReturnSuccess
;
1413 ret
= kIOReturnUnsupported
;
1418 if ((kIOTrackingLeaks
== selector
) && data
) {
1419 data
= IOTrackingLeaks(data
);
1420 queue_iterate(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
)
1422 if (SkipName(options
, queue
->name
, namesLen
, names
)) {
1425 if (!(kIOTrackingQueueTypeAlloc
& queue
->type
)) {
1428 IOTRecursiveLockUnlock(&queue
->lock
);
1432 lck_mtx_unlock(gIOTrackingLock
);
1434 if ((kIOTrackingLeaks
== selector
) && namesLen
&& names
) {
1440 data
= OSData::withCapacity(4096 * sizeof(uintptr_t));
1443 // <len><name>...<len><name><0>
1446 sLen
= ((uint8_t) scan
[0]);
1449 if (next
>= (names
+ namesLen
)) {
1452 kr
= zone_leaks(scan
, sLen
, &ZoneSiteProc
, data
);
1453 if (KERN_SUCCESS
== kr
) {
1454 ret
= kIOReturnSuccess
;
1455 } else if (KERN_INVALID_NAME
!= kr
) {
1456 ret
= kIOReturnVMError
;
1459 }while (scan
< (names
+ namesLen
));
1464 case kIOTrackingLeaks
:
1465 case kIOTrackingGetTracking
:
1466 case kIOTrackingGetMappings
:
1468 IOTrackingCallSiteInfo
* siteInfos
;
1469 siteInfos
= (typeof(siteInfos
))data
->getBytesNoCopy();
1470 num
= (data
->getLength() / sizeof(*siteInfos
));
1471 qsort(siteInfos
, num
, sizeof(*siteInfos
), &IOTrackingCallSiteInfoCompare
);
1474 default: assert(false); break;
1483 #endif /* IOTRACKING */
1488 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1490 #include <IOKit/IOKitDiagnosticsUserClient.h>
1492 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1495 #define super IOUserClient
1497 OSDefineMetaClassAndStructors(IOKitDiagnosticsClient
, IOUserClient
)
1499 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1501 IOUserClient
* IOKitDiagnosticsClient::withTask(task_t owningTask
)
1503 IOKitDiagnosticsClient
* inst
;
1505 inst
= new IOKitDiagnosticsClient
;
1506 if (inst
&& !inst
->init()) {
1515 IOKitDiagnosticsClient::clientClose(void)
1518 return kIOReturnSuccess
;
1522 IOKitDiagnosticsClient::setProperties(OSObject
* properties
)
1524 IOReturn kr
= kIOReturnUnsupported
;
1529 IOKitDiagnosticsClient::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
1530 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
1532 IOReturn ret
= kIOReturnBadArgument
;
1533 const IOKitDiagnosticsParameters
* params
;
1538 if (args
->structureInputSize
< sizeof(IOKitDiagnosticsParameters
)) {
1539 return kIOReturnBadArgument
;
1541 params
= (typeof(params
))args
->structureInput
;
1543 return kIOReturnBadArgument
;
1547 namesLen
= args
->structureInputSize
- sizeof(IOKitDiagnosticsParameters
);
1549 names
= (typeof(names
))(params
+ 1);
1552 ret
= IOTrackingDebug(selector
, params
->options
, params
->value
, params
->tag
, params
->zsize
, names
, namesLen
, params
->size
, &result
);
1554 if ((kIOReturnSuccess
== ret
) && args
->structureVariableOutputData
) {
1555 *args
->structureVariableOutputData
= result
;
1556 } else if (result
) {
1563 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */