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 int debug_malloc_size
;
84 int debug_iomalloc_size
;
86 vm_size_t debug_iomallocpageable_size
;
87 int debug_container_malloc_size
;
88 // int debug_ivars_size; // in OSObject.cpp
93 #define DEBG(fmt, args...) { kprintf(fmt, ## args); }
95 #define DEBG(fmt, args...) { IOLog(fmt, ## args); }
98 void 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() );
116 while( (next
= iter
->getNextObjectRecursive())) {
117 snprintf(format
+ 1, sizeof(format
) - 1, "%ds", 2 * next
->getDepth( plane
));
119 DEBG( "\033[33m%s", next
->getName( plane
));
120 if( (next
->getLocation( plane
)))
121 DEBG("@%s", next
->getLocation( plane
));
122 DEBG("\033[0m <class %s", next
->getMetaClass()->getClassName());
123 if( (service
= OSDynamicCast(IOService
, next
)))
124 DEBG(", busy %ld", (long) service
->getBusyState());
131 void db_piokjunk(void)
135 void db_dumpiojunk( const IORegistryPlane
* plane __unused
)
139 void IOPrintMemory( void )
142 // OSMetaClass::printInstanceCounts();
145 "ivar kalloc() 0x%08x\n"
147 "containers kalloc() 0x%08x\n"
148 "IOMalloc() 0x%08x\n"
149 "----------------------------------------\n",
152 debug_container_malloc_size
,
159 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
161 #define super OSObject
162 OSDefineMetaClassAndStructors(IOKitDiagnostics
, OSObject
)
164 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
166 OSObject
* IOKitDiagnostics::diagnostics( void )
168 IOKitDiagnostics
* diags
;
170 diags
= new IOKitDiagnostics
;
171 if( diags
&& !diags
->init()) {
179 void IOKitDiagnostics::updateOffset( OSDictionary
* dict
,
180 UInt64 value
, const char * name
)
184 off
= OSNumber::withNumber( value
, 64 );
188 dict
->setObject( name
, off
);
192 bool IOKitDiagnostics::serialize(OSSerialize
*s
) const
197 dict
= OSDictionary::withCapacity( 5 );
201 updateOffset( dict
, debug_ivars_size
, "Instance allocation" );
202 updateOffset( dict
, debug_container_malloc_size
, "Container allocation" );
203 updateOffset( dict
, debug_iomalloc_size
, "IOMalloc allocation" );
204 updateOffset( dict
, debug_iomallocpageable_size
, "Pageable allocation" );
206 OSMetaClass::serializeClassDictionary(dict
);
208 ok
= dict
->serialize( s
);
215 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
219 #include <libkern/c++/OSCPPDebug.h>
220 #include <libkern/c++/OSKext.h>
221 #include <kern/zalloc.h>
223 __private_extern__
"C" void qsort(
227 int (*)(const void *, const void *));
229 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
230 extern "C" ppnum_t
pmap_valid_page(ppnum_t pn
);
232 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
234 struct IOTRecursiveLock
241 struct IOTrackingQueue
244 IOTRecursiveLock lock
;
248 size_t minCaptureSize
;
253 queue_head_t sites
[];
256 struct IOTrackingCallSite
259 IOTrackingQueue
* queue
;
265 uintptr_t bt
[kIOTrackingCallSiteBTs
];
267 queue_head_t instances
;
268 IOTracking
* addresses
;
271 struct IOTrackingLeaksRef
273 uintptr_t * instances
;
281 lck_mtx_t
* gIOTrackingLock
;
282 queue_head_t gIOTrackingQ
;
286 kTrackingAddressFlagAllocated
= 0x00000001
289 #if defined(__LP64__)
290 #define IOTrackingAddressFlags(ptr) (ptr->flags)
292 #define IOTrackingAddressFlags(ptr) (ptr->tracking.flags)
295 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
298 IOTRecursiveLockLock(IOTRecursiveLock
* lock
)
300 if (lock
->thread
== current_thread()) lock
->count
++;
303 lck_mtx_lock(lock
->mutex
);
304 assert(lock
->thread
== 0);
305 assert(lock
->count
== 0);
306 lock
->thread
= current_thread();
312 IOTRecursiveLockUnlock(IOTRecursiveLock
* lock
)
314 assert(lock
->thread
== current_thread());
315 if (0 == (--lock
->count
))
318 lck_mtx_unlock(lock
->mutex
);
322 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
327 queue_init(&gIOTrackingQ
);
328 gIOTrackingLock
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
);
331 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
334 IOTrackingQueueAlloc(const char * name
, uintptr_t btEntry
,
335 size_t allocSize
, size_t minCaptureSize
,
336 uint32_t type
, uint32_t numSiteQs
)
338 IOTrackingQueue
* queue
;
341 if (!numSiteQs
) numSiteQs
= 1;
342 queue
= (typeof(queue
)) kalloc(sizeof(IOTrackingQueue
) + numSiteQs
* sizeof(queue
->sites
[0]));
343 bzero(queue
, sizeof(IOTrackingQueue
));
346 queue
->btEntry
= btEntry
;
347 queue
->allocSize
= allocSize
;
348 queue
->minCaptureSize
= minCaptureSize
;
349 queue
->lock
.mutex
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
);
350 queue
->numSiteQs
= numSiteQs
;
352 enum { kFlags
= (kIOTracking
| kIOTrackingBoot
) };
353 queue
->captureOn
= (kFlags
== (kFlags
& gIOKitDebug
))
354 || (kIOTrackingQueueTypeDefaultOn
& type
);
356 for (idx
= 0; idx
< numSiteQs
; idx
++) queue_init(&queue
->sites
[idx
]);
358 lck_mtx_lock(gIOTrackingLock
);
359 queue_enter(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
);
360 lck_mtx_unlock(gIOTrackingLock
);
365 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
368 IOTrackingQueueFree(IOTrackingQueue
* queue
)
370 lck_mtx_lock(gIOTrackingLock
);
371 IOTrackingReset(queue
);
372 remque(&queue
->link
);
373 lck_mtx_unlock(gIOTrackingLock
);
375 lck_mtx_free(queue
->lock
.mutex
, IOLockGroup
);
377 kfree(queue
, sizeof(IOTrackingQueue
) + queue
->numSiteQs
* sizeof(queue
->sites
[0]));
380 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
385 Copyright (C) 2012 Zilong Tan (eric.zltan@gmail.com)
387 Permission is hereby granted, free of charge, to any person
388 obtaining a copy of this software and associated documentation
389 files (the "Software"), to deal in the Software without
390 restriction, including without limitation the rights to use, copy,
391 modify, merge, publish, distribute, sublicense, and/or sell copies
392 of the Software, and to permit persons to whom the Software is
393 furnished to do so, subject to the following conditions:
395 The above copyright notice and this permission notice shall be
396 included in all copies or substantial portions of the Software.
398 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
399 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
400 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
401 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
402 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
403 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
404 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
409 // Compression function for Merkle-Damgard construction.
410 // This function is generated using the framework provided.
413 (h) *= 0x2127599bf4325c37ULL; \
417 fasthash64(const void *buf
, size_t len
, uint64_t seed
)
419 const uint64_t m
= 0x880355f21e6d1965ULL
;
420 const uint64_t *pos
= (const uint64_t *)buf
;
421 const uint64_t *end
= pos
+ (len
/ 8);
422 const unsigned char *pos2
;
423 uint64_t h
= seed
^ (len
* m
);
432 pos2
= (const unsigned char*)pos
;
436 case 7: v
^= (uint64_t)pos2
[6] << 48;
437 [[clang::fallthrough]];
438 case 6: v
^= (uint64_t)pos2
[5] << 40;
439 [[clang::fallthrough]];
440 case 5: v
^= (uint64_t)pos2
[4] << 32;
441 [[clang::fallthrough]];
442 case 4: v
^= (uint64_t)pos2
[3] << 24;
443 [[clang::fallthrough]];
444 case 3: v
^= (uint64_t)pos2
[2] << 16;
445 [[clang::fallthrough]];
446 case 2: v
^= (uint64_t)pos2
[1] << 8;
447 [[clang::fallthrough]];
448 case 1: v
^= (uint64_t)pos2
[0];
456 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
459 fasthash32(const void *buf
, size_t len
, uint32_t seed
)
461 // the following trick converts the 64-bit hashcode to Fermat
462 // residue, which shall retain information from both the higher
463 // and lower parts of hashcode.
464 uint64_t h
= fasthash64(buf
, len
, seed
);
465 return h
- (h
>> 32);
468 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
471 IOTrackingAddUser(IOTrackingQueue
* queue
, IOTrackingUser
* mem
, vm_size_t size
)
476 if (!queue
->captureOn
) return;
477 if (size
< queue
->minCaptureSize
) return;
479 assert(!mem
->link
.next
);
481 num
= backtrace(&mem
->bt
[0], kIOTrackingCallSiteBTs
);
483 if ((kernel_task
!= current_task()) && (self
= proc_self()))
486 mem
->btPID
= proc_pid(self
);
487 (void)backtrace_user(&mem
->btUser
[0], kIOTrackingCallSiteBTs
- 1, &num
,
489 mem
->user32
= !user_64
;
492 assert(num
<= kIOTrackingCallSiteBTs
);
493 mem
->userCount
= num
;
495 IOTRecursiveLockLock(&queue
->lock
);
496 queue_enter
/*last*/(&queue
->sites
[0], mem
, IOTrackingUser
*, link
);
498 IOTRecursiveLockUnlock(&queue
->lock
);
502 IOTrackingRemoveUser(IOTrackingQueue
* queue
, IOTrackingUser
* mem
)
504 if (!mem
->link
.next
) return;
506 IOTRecursiveLockLock(&queue
->lock
);
510 assert(queue
->siteCount
);
513 IOTRecursiveLockUnlock(&queue
->lock
);
516 uint64_t gIOTrackingAddTime
;
519 IOTrackingAdd(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
, bool address
, vm_tag_t tag
)
521 IOTrackingCallSite
* site
;
523 uintptr_t bt
[kIOTrackingCallSiteBTs
+ 1];
526 if (mem
->site
) return;
527 if (!queue
->captureOn
) return;
528 if (size
< queue
->minCaptureSize
) return;
530 assert(!mem
->link
.next
);
532 num
= backtrace(&bt
[0], kIOTrackingCallSiteBTs
+ 1);
535 crc
= fasthash32(&bt
[1], num
* sizeof(bt
[0]), 0x04C11DB7);
537 IOTRecursiveLockLock(&queue
->lock
);
538 que
= &queue
->sites
[crc
% queue
->numSiteQs
];
539 queue_iterate(que
, site
, IOTrackingCallSite
*, link
)
541 if (tag
!= site
->tag
) continue;
542 if (crc
== site
->crc
) break;
545 if (queue_end(que
, (queue_entry_t
) site
))
547 site
= (typeof(site
)) kalloc(sizeof(IOTrackingCallSite
));
549 queue_init(&site
->instances
);
550 site
->addresses
= (IOTracking
*) &site
->instances
;
555 memset(&site
->size
[0], 0, sizeof(site
->size
));
556 bcopy(&bt
[1], &site
->bt
[0], num
* sizeof(site
->bt
[0]));
557 assert(num
<= kIOTrackingCallSiteBTs
);
558 bzero(&site
->bt
[num
], (kIOTrackingCallSiteBTs
- num
) * sizeof(site
->bt
[0]));
560 queue_enter_first(que
, site
, IOTrackingCallSite
*, link
);
566 queue_enter
/*last*/(&site
->instances
, mem
, IOTracking
*, link
);
567 if (queue_end(&site
->instances
, (queue_entry_t
)site
->addresses
)) site
->addresses
= mem
;
569 else queue_enter_first(&site
->instances
, mem
, IOTracking
*, link
);
572 site
->size
[0] += size
;
575 IOTRecursiveLockUnlock(&queue
->lock
);
578 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
581 IOTrackingRemove(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
)
583 if (!mem
->link
.next
) return;
585 IOTRecursiveLockLock(&queue
->lock
);
590 if (mem
== mem
->site
->addresses
) mem
->site
->addresses
= (IOTracking
*) queue_next(&mem
->link
);
593 assert(mem
->site
->count
);
595 assert(mem
->site
->size
[0] >= size
);
596 mem
->site
->size
[0] -= size
;
597 if (!mem
->site
->count
)
599 assert(queue_empty(&mem
->site
->instances
));
600 assert(!mem
->site
->size
[0]);
601 assert(!mem
->site
->size
[1]);
603 remque(&mem
->site
->link
);
604 assert(queue
->siteCount
);
606 kfree(mem
->site
, sizeof(IOTrackingCallSite
));
610 IOTRecursiveLockUnlock(&queue
->lock
);
613 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
616 IOTrackingAlloc(IOTrackingQueue
* queue
, uintptr_t address
, size_t size
)
618 IOTrackingAddress
* tracking
;
620 if (!queue
->captureOn
) return;
621 if (size
< queue
->minCaptureSize
) return;
624 tracking
= (typeof(tracking
)) kalloc(sizeof(IOTrackingAddress
));
625 bzero(tracking
, sizeof(IOTrackingAddress
));
626 IOTrackingAddressFlags(tracking
) |= kTrackingAddressFlagAllocated
;
627 tracking
->address
= address
;
628 tracking
->size
= size
;
630 IOTrackingAdd(queue
, &tracking
->tracking
, size
, true, VM_KERN_MEMORY_NONE
);
633 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
636 IOTrackingFree(IOTrackingQueue
* queue
, uintptr_t address
, size_t size
)
638 IOTrackingCallSite
* site
;
639 IOTrackingAddress
* tracking
;
644 IOTRecursiveLockLock(&queue
->lock
);
646 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++)
648 queue_iterate(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
)
650 for (tracking
= (IOTrackingAddress
*) site
->addresses
;
651 !done
&& !queue_end(&site
->instances
, &tracking
->tracking
.link
);
652 tracking
= (IOTrackingAddress
*) queue_next(&tracking
->tracking
.link
))
654 if ((done
= (address
== tracking
->address
)))
656 IOTrackingRemove(queue
, &tracking
->tracking
, size
);
657 kfree(tracking
, sizeof(IOTrackingAddress
));
664 IOTRecursiveLockUnlock(&queue
->lock
);
667 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
670 IOTrackingAccumSize(IOTrackingQueue
* queue
, IOTracking
* mem
, size_t size
)
672 IOTRecursiveLockLock(&queue
->lock
);
676 assert((size
> 0) || (mem
->site
->size
[1] >= -size
));
677 mem
->site
->size
[1] += size
;
679 IOTRecursiveLockUnlock(&queue
->lock
);
682 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
685 IOTrackingReset(IOTrackingQueue
* queue
)
687 IOTrackingCallSite
* site
;
688 IOTrackingUser
* user
;
689 IOTracking
* tracking
;
690 IOTrackingAddress
* trackingAddress
;
694 IOTRecursiveLockLock(&queue
->lock
);
695 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++)
697 while (!queue_empty(&queue
->sites
[idx
]))
699 if (kIOTrackingQueueTypeMap
& queue
->type
)
701 queue_remove_first(&queue
->sites
[idx
], user
, IOTrackingUser
*, link
);
702 user
->link
.next
= user
->link
.prev
= NULL
;
706 queue_remove_first(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
);
708 while (!queue_empty(&site
->instances
))
710 queue_remove_first(&site
->instances
, tracking
, IOTracking
*, link
);
711 if (tracking
== site
->addresses
) addresses
= true;
714 trackingAddress
= (typeof(trackingAddress
)) tracking
;
715 if (kTrackingAddressFlagAllocated
& IOTrackingAddressFlags(trackingAddress
))
717 kfree(tracking
, sizeof(IOTrackingAddress
));
721 kfree(site
, sizeof(IOTrackingCallSite
));
725 queue
->siteCount
= 0;
726 IOTRecursiveLockUnlock(&queue
->lock
);
729 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
732 IOTrackingCallSiteInfoCompare(const void * left
, const void * right
)
734 IOTrackingCallSiteInfo
* l
= (typeof(l
)) left
;
735 IOTrackingCallSiteInfo
* r
= (typeof(r
)) right
;
738 rsize
= r
->size
[0] + r
->size
[1];
739 lsize
= l
->size
[0] + l
->size
[1];
741 return ((rsize
> lsize
) ? 1 : ((rsize
== lsize
) ? 0 : -1));
744 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
747 IOTrackingAddressCompare(const void * left
, const void * right
)
749 IOTracking
* instance
;
750 uintptr_t inst
, laddr
, raddr
;
752 inst
= ((typeof(inst
) *) left
)[0];
753 instance
= (typeof(instance
)) INSTANCE_GET(inst
);
754 if (kInstanceFlagAddress
& inst
) laddr
= ~((IOTrackingAddress
*)instance
)->address
;
755 else laddr
= (uintptr_t) (instance
+ 1);
757 inst
= ((typeof(inst
) *) right
)[0];
758 instance
= (typeof(instance
)) (inst
& ~kInstanceFlags
);
759 if (kInstanceFlagAddress
& inst
) raddr
= ~((IOTrackingAddress
*)instance
)->address
;
760 else raddr
= (uintptr_t) (instance
+ 1);
762 return ((laddr
> raddr
) ? 1 : ((laddr
== raddr
) ? 0 : -1));
767 IOTrackingZoneElementCompare(const void * left
, const void * right
)
769 uintptr_t inst
, laddr
, raddr
;
771 inst
= ((typeof(inst
) *) left
)[0];
772 laddr
= INSTANCE_PUT(inst
);
773 inst
= ((typeof(inst
) *) right
)[0];
774 raddr
= INSTANCE_PUT(inst
);
776 return ((laddr
> raddr
) ? 1 : ((laddr
== raddr
) ? 0 : -1));
779 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
782 CopyOutKernelBacktrace(IOTrackingCallSite
* site
, IOTrackingCallSiteInfo
* siteInfo
)
785 mach_vm_address_t bt
, btEntry
;
787 btEntry
= site
->queue
->btEntry
;
788 for (j
= 0; j
< kIOTrackingCallSiteBTs
; j
++)
792 && (!bt
|| (j
== (kIOTrackingCallSiteBTs
- 1))))
797 siteInfo
->bt
[0][j
] = VM_KERNEL_UNSLIDE(bt
);
801 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
804 IOTrackingLeakScan(void * refcon
)
806 IOTrackingLeaksRef
* ref
= (typeof(ref
)) refcon
;
807 uintptr_t * instances
;
808 IOTracking
* instance
;
809 uint64_t vaddr
, vincr
;
811 uintptr_t ptr
, addr
, vphysaddr
, inst
;
812 size_t size
, origsize
;
813 uint32_t baseIdx
, lim
, ptrIdx
, count
;
815 AbsoluteTime deadline
;
817 instances
= ref
->instances
;
819 size
= origsize
= ref
->zoneSize
;
821 for (deadline
= 0, vaddr
= VM_MIN_KERNEL_AND_KEXT_ADDRESS
;
825 if ((mach_absolute_time() > deadline
) || (vaddr
>= VM_MAX_KERNEL_ADDRESS
))
829 ml_set_interrupts_enabled(is
);
832 if (vaddr
>= VM_MAX_KERNEL_ADDRESS
) break;
833 is
= ml_set_interrupts_enabled(false);
834 clock_interval_to_deadline(10, kMillisecondScale
, &deadline
);
837 ppn
= kernel_pmap_present_mapping(vaddr
, &vincr
, &vphysaddr
);
838 // check noencrypt to avoid VM structs (map entries) with pointers
839 if (ppn
&& (!pmap_valid_page(ppn
) || (!ref
->zoneSize
&& pmap_is_noencrypt(ppn
)))) ppn
= 0;
842 for (ptrIdx
= 0; ptrIdx
< (page_size
/ sizeof(uintptr_t)); ptrIdx
++)
844 ptr
= ((uintptr_t *)vphysaddr
)[ptrIdx
];
846 for (lim
= count
, baseIdx
= 0; lim
; lim
>>= 1)
848 inst
= instances
[baseIdx
+ (lim
>> 1)];
849 instance
= (typeof(instance
)) INSTANCE_GET(inst
);
853 addr
= INSTANCE_PUT(inst
) & ~kInstanceFlags
;
855 else if (kInstanceFlagAddress
& inst
)
857 addr
= ~((IOTrackingAddress
*)instance
)->address
;
858 origsize
= size
= ((IOTrackingAddress
*)instance
)->size
;
863 addr
= (uintptr_t) (instance
+ 1);
864 origsize
= size
= instance
->site
->queue
->allocSize
;
866 if ((ptr
>= addr
) && (ptr
< (addr
+ size
))
868 && (((vaddr
+ ptrIdx
* sizeof(uintptr_t)) < addr
)
869 || ((vaddr
+ ptrIdx
* sizeof(uintptr_t)) >= (addr
+ size
))))
871 if (!(kInstanceFlagReferenced
& inst
))
873 inst
|= kInstanceFlagReferenced
;
874 instances
[baseIdx
+ (lim
>> 1)] = inst
;
876 if (!origsize
) ref
->foundzlen
++;
883 baseIdx
+= (lim
>> 1) + 1;
889 ref
->bytes
+= page_size
;
893 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
896 zone_leaks_scan(uintptr_t * instances
, uint32_t count
, uint32_t zoneSize
, uint32_t * found
)
898 IOTrackingLeaksRef ref
;
899 IOTrackingCallSiteInfo siteInfo
;
902 qsort(instances
, count
, sizeof(*instances
), &IOTrackingZoneElementCompare
);
904 bzero(&siteInfo
, sizeof(siteInfo
));
905 bzero(&ref
, sizeof(ref
));
906 ref
.instances
= instances
;
908 ref
.zoneSize
= zoneSize
;
910 for (idx
= 0; idx
< 2; idx
++)
913 IOTrackingLeakScan(&ref
);
914 IOLog("leaks(%d) scanned %ld MB, instance count %d, found %d\n", idx
, ref
.bytes
/ 1024 / 1024, count
, ref
.found
);
915 if (count
<= ref
.found
) break;
921 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
924 ZoneSiteProc(void * refCon
, uint32_t siteCount
, uint32_t zoneSize
,
925 uintptr_t * backtrace
, uint32_t btCount
)
927 IOTrackingCallSiteInfo siteInfo
;
931 leakData
= (typeof(leakData
)) refCon
;
933 bzero(&siteInfo
, sizeof(siteInfo
));
934 siteInfo
.count
= siteCount
;
935 siteInfo
.size
[0] = zoneSize
* siteCount
;
937 for (idx
= 0; (idx
< btCount
) && (idx
< kIOTrackingCallSiteBTs
); idx
++)
939 siteInfo
.bt
[0][idx
] = VM_KERNEL_UNSLIDE(backtrace
[idx
]);
942 leakData
->appendBytes(&siteInfo
, sizeof(siteInfo
));
946 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
949 IOTrackingLeaks(OSData
* data
)
951 IOTrackingLeaksRef ref
;
952 IOTrackingCallSiteInfo siteInfo
;
953 IOTrackingCallSite
* site
;
955 uintptr_t * instances
;
956 IOTracking
* instance
;
958 uint32_t count
, idx
, numSites
, dups
, siteCount
;
960 instances
= (typeof(instances
)) data
->getBytesNoCopy();
961 count
= (data
->getLength() / sizeof(*instances
));
962 qsort(instances
, count
, sizeof(*instances
), &IOTrackingAddressCompare
);
964 bzero(&siteInfo
, sizeof(siteInfo
));
965 bzero(&ref
, sizeof(ref
));
966 ref
.instances
= instances
;
968 for (idx
= 0; idx
< 2; idx
++)
971 IOTrackingLeakScan(&ref
);
972 IOLog("leaks(%d) scanned %ld MB, instance count %d, found %d (zlen %d)\n", idx
, ref
.bytes
/ 1024 / 1024, count
, ref
.found
, ref
.foundzlen
);
973 if (count
<= ref
.found
) break;
976 leakData
= OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo
));
978 for (numSites
= 0, idx
= 0; idx
< count
; idx
++)
980 inst
= instances
[idx
];
981 if (kInstanceFlagReferenced
& inst
) continue;
982 instance
= (typeof(instance
)) INSTANCE_GET(inst
);
983 site
= instance
->site
;
984 instances
[numSites
] = (uintptr_t) site
;
988 for (idx
= 0; idx
< numSites
; idx
++)
990 inst
= instances
[idx
];
992 site
= (typeof(site
)) inst
;
993 for (siteCount
= 1, dups
= (idx
+ 1); dups
< numSites
; dups
++)
995 if (instances
[dups
] == (uintptr_t) site
)
1001 siteInfo
.count
= siteCount
;
1002 siteInfo
.size
[0] = (site
->size
[0] * site
->count
) / siteCount
;
1003 siteInfo
.size
[1] = (site
->size
[1] * site
->count
) / siteCount
;;
1004 CopyOutKernelBacktrace(site
, &siteInfo
);
1005 leakData
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1012 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1015 SkipName(uint32_t options
, const char * name
, size_t namesLen
, const char * names
)
1019 bool exclude
, found
;
1022 if (!namesLen
|| !names
) return (false);
1023 // <len><name>...<len><name><0>
1024 exclude
= (0 != (kIOTrackingExcludeNames
& options
));
1025 qLen
= strlen(name
);
1033 if (next
>= (names
+ namesLen
)) break;
1034 found
= ((sLen
== qLen
) && !strncmp(scan
, name
, sLen
));
1037 while (!found
&& (scan
< (names
+ namesLen
)));
1039 return (!(exclude
^ found
));
1042 #endif /* IOTRACKING */
1044 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1046 static kern_return_t
1047 IOTrackingDebug(uint32_t selector
, uint32_t options
, uint64_t value
,
1048 uint32_t intag
, uint32_t inzsize
,
1049 const char * names
, size_t namesLen
,
1050 size_t size
, OSObject
** result
)
1055 if (result
) *result
= 0;
1057 ret
= kIOReturnNotReady
;
1062 IOTrackingQueue
* queue
;
1063 IOTracking
* instance
;
1064 IOTrackingCallSite
* site
;
1065 IOTrackingCallSiteInfo siteInfo
;
1066 IOTrackingUser
* user
;
1068 mach_vm_address_t mapAddress
;
1069 mach_vm_size_t mapSize
;
1070 uint32_t num
, idx
, qIdx
;
1071 uintptr_t instFlags
;
1075 ret
= kIOReturnNotFound
;
1077 if (kIOTrackingGetMappings
== selector
)
1081 proc
= proc_find(value
);
1082 if (!proc
) return (kIOReturnNotFound
);
1086 bzero(&siteInfo
, sizeof(siteInfo
));
1087 lck_mtx_lock(gIOTrackingLock
);
1088 queue_iterate(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
)
1090 if (SkipName(options
, queue
->name
, namesLen
, names
)) continue;
1092 if (!(kIOTracking
& gIOKitDebug
) && (kIOTrackingQueueTypeAlloc
& queue
->type
)) continue;
1096 case kIOTrackingResetTracking
:
1098 IOTrackingReset(queue
);
1099 ret
= kIOReturnSuccess
;
1103 case kIOTrackingStartCapture
:
1104 case kIOTrackingStopCapture
:
1106 queue
->captureOn
= (kIOTrackingStartCapture
== selector
);
1107 ret
= kIOReturnSuccess
;
1111 case kIOTrackingSetMinCaptureSize
:
1113 queue
->minCaptureSize
= size
;
1114 ret
= kIOReturnSuccess
;
1118 case kIOTrackingLeaks
:
1120 if (!(kIOTrackingQueueTypeAlloc
& queue
->type
)) break;
1122 if (!data
) data
= OSData::withCapacity(1024 * sizeof(uintptr_t));
1124 IOTRecursiveLockLock(&queue
->lock
);
1125 for (idx
= 0; idx
< queue
->numSiteQs
; idx
++)
1127 queue_iterate(&queue
->sites
[idx
], site
, IOTrackingCallSite
*, link
)
1130 queue_iterate(&site
->instances
, instance
, IOTracking
*, link
)
1132 if (instance
== site
->addresses
) addresses
= true;
1133 instFlags
= (typeof(instFlags
)) instance
;
1134 if (addresses
) instFlags
|= kInstanceFlagAddress
;
1135 data
->appendBytes(&instFlags
, sizeof(instFlags
));
1140 ret
= kIOReturnSuccess
;
1145 case kIOTrackingGetTracking
:
1147 if (kIOTrackingQueueTypeMap
& queue
->type
) break;
1149 if (!data
) data
= OSData::withCapacity(128 * sizeof(IOTrackingCallSiteInfo
));
1151 IOTRecursiveLockLock(&queue
->lock
);
1152 num
= queue
->siteCount
;
1154 for (qIdx
= 0; qIdx
< queue
->numSiteQs
; qIdx
++)
1156 queue_iterate(&queue
->sites
[qIdx
], site
, IOTrackingCallSite
*, link
)
1162 uint32_t count
= site
->count
;
1163 tsize
[0] = site
->size
[0];
1164 tsize
[1] = site
->size
[1];
1166 if (intag
|| inzsize
)
1169 vm_size_t size
, zoneSize
;
1172 if (kIOTrackingQueueTypeAlloc
& queue
->type
)
1176 tsize
[0] = tsize
[1] = 0;
1177 queue_iterate(&site
->instances
, instance
, IOTracking
*, link
)
1179 if (instance
== site
->addresses
) addresses
= true;
1181 if (addresses
) addr
= ~((IOTrackingAddress
*)instance
)->address
;
1182 else addr
= (uintptr_t) (instance
+ 1);
1184 kr
= vm_kern_allocation_info(addr
, &size
, &tag
, &zoneSize
);
1185 if (KERN_SUCCESS
!= kr
) continue;
1187 if ((VM_KERN_MEMORY_NONE
!= intag
) && (intag
!= tag
)) continue;
1188 if (inzsize
&& (inzsize
!= zoneSize
)) continue;
1196 if (!intag
|| inzsize
|| (intag
!= site
->tag
)) continue;
1200 if (!count
) continue;
1201 if (size
&& ((tsize
[0] + tsize
[1]) < size
)) continue;
1203 siteInfo
.count
= count
;
1204 siteInfo
.size
[0] = tsize
[0];
1205 siteInfo
.size
[1] = tsize
[1];
1207 CopyOutKernelBacktrace(site
, &siteInfo
);
1208 data
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1212 IOTRecursiveLockUnlock(&queue
->lock
);
1213 ret
= kIOReturnSuccess
;
1217 case kIOTrackingGetMappings
:
1219 if (!(kIOTrackingQueueTypeMap
& queue
->type
)) break;
1220 if (!data
) data
= OSData::withCapacity(page_size
);
1222 IOTRecursiveLockLock(&queue
->lock
);
1223 num
= queue
->siteCount
;
1225 for (qIdx
= 0; qIdx
< queue
->numSiteQs
; qIdx
++)
1227 queue_iterate(&queue
->sites
[qIdx
], user
, IOTrackingUser
*, link
)
1232 kr
= IOMemoryMapTracking(user
, &mapTask
, &mapAddress
, &mapSize
);
1233 if (kIOReturnSuccess
!= kr
) continue;
1234 if (proc
&& (mapTask
!= proc_task(proc
))) continue;
1235 if (size
&& (mapSize
< size
)) continue;
1238 siteInfo
.size
[0] = mapSize
;
1239 siteInfo
.address
= mapAddress
;
1240 siteInfo
.addressPID
= task_pid(mapTask
);
1241 siteInfo
.btPID
= user
->btPID
;
1243 for (uint32_t j
= 0; j
< kIOTrackingCallSiteBTs
; j
++)
1245 siteInfo
.bt
[0][j
] = VM_KERNEL_UNSLIDE(user
->bt
[j
]);
1247 uint32_t * bt32
= (typeof(bt32
)) &user
->btUser
[0];
1248 uint64_t * bt64
= (typeof(bt64
)) ((void *) &user
->btUser
[0]);
1249 for (uint32_t j
= 0; j
< kIOTrackingCallSiteBTs
; j
++)
1251 if (j
>= user
->userCount
) siteInfo
.bt
[1][j
] = 0;
1252 else if (user
->user32
) siteInfo
.bt
[1][j
] = bt32
[j
];
1253 else siteInfo
.bt
[1][j
] = bt64
[j
];
1255 data
->appendBytes(&siteInfo
, sizeof(siteInfo
));
1259 IOTRecursiveLockUnlock(&queue
->lock
);
1260 ret
= kIOReturnSuccess
;
1265 ret
= kIOReturnUnsupported
;
1270 if ((kIOTrackingLeaks
== selector
) && data
)
1272 data
= IOTrackingLeaks(data
);
1273 queue_iterate(&gIOTrackingQ
, queue
, IOTrackingQueue
*, link
)
1275 if (SkipName(options
, queue
->name
, namesLen
, names
)) continue;
1276 if (!(kIOTrackingQueueTypeAlloc
& queue
->type
)) continue;
1277 IOTRecursiveLockUnlock(&queue
->lock
);
1281 lck_mtx_unlock(gIOTrackingLock
);
1283 if ((kIOTrackingLeaks
== selector
) && namesLen
&& names
)
1289 if (!data
) data
= OSData::withCapacity(4096 * sizeof(uintptr_t));
1291 // <len><name>...<len><name><0>
1298 if (next
>= (names
+ namesLen
)) break;
1299 kr
= zone_leaks(scan
, sLen
, &ZoneSiteProc
, data
);
1300 if (KERN_SUCCESS
== kr
) ret
= kIOReturnSuccess
;
1301 else if (KERN_INVALID_NAME
!= kr
) ret
= kIOReturnVMError
;
1304 while (scan
< (names
+ namesLen
));
1307 if (data
) switch (selector
)
1309 case kIOTrackingLeaks
:
1310 case kIOTrackingGetTracking
:
1311 case kIOTrackingGetMappings
:
1313 IOTrackingCallSiteInfo
* siteInfos
;
1314 siteInfos
= (typeof(siteInfos
)) data
->getBytesNoCopy();
1315 num
= (data
->getLength() / sizeof(*siteInfos
));
1316 qsort(siteInfos
, num
, sizeof(*siteInfos
), &IOTrackingCallSiteInfoCompare
);
1319 default: assert(false); break;
1323 if (proc
) proc_rele(proc
);
1325 #endif /* IOTRACKING */
1330 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1332 #include <IOKit/IOKitDiagnosticsUserClient.h>
1334 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1337 #define super IOUserClient
1339 OSDefineMetaClassAndStructors(IOKitDiagnosticsClient
, IOUserClient
)
1341 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1343 IOUserClient
* IOKitDiagnosticsClient::withTask(task_t owningTask
)
1345 IOKitDiagnosticsClient
* inst
;
1347 inst
= new IOKitDiagnosticsClient
;
1348 if (inst
&& !inst
->init())
1357 IOReturn
IOKitDiagnosticsClient::clientClose(void)
1360 return (kIOReturnSuccess
);
1363 IOReturn
IOKitDiagnosticsClient::setProperties(OSObject
* properties
)
1365 IOReturn kr
= kIOReturnUnsupported
;
1369 IOReturn
IOKitDiagnosticsClient::externalMethod(uint32_t selector
, IOExternalMethodArguments
* args
,
1370 IOExternalMethodDispatch
* dispatch
, OSObject
* target
, void * reference
)
1372 IOReturn ret
= kIOReturnBadArgument
;
1373 const IOKitDiagnosticsParameters
* params
;
1378 if (args
->structureInputSize
< sizeof(IOKitDiagnosticsParameters
)) return (kIOReturnBadArgument
);
1379 params
= (typeof(params
)) args
->structureInput
;
1380 if (!params
) return (kIOReturnBadArgument
);
1383 namesLen
= args
->structureInputSize
- sizeof(IOKitDiagnosticsParameters
);
1384 if (namesLen
) names
= (typeof(names
))(params
+ 1);
1386 ret
= IOTrackingDebug(selector
, params
->options
, params
->value
, params
->tag
, params
->zsize
, names
, namesLen
, params
->size
, &result
);
1388 if ((kIOReturnSuccess
== ret
) && args
->structureVariableOutputData
) *args
->structureVariableOutputData
= result
;
1389 else if (result
) result
->release();
1394 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */