]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOStatistics.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOStatistics.cpp
CommitLineData
6d2010ae
A
1/*
2 * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
6d2010ae
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
0a7de745 14 *
6d2010ae
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
6d2010ae
A
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.
0a7de745 25 *
6d2010ae
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <sys/sysctl.h>
39037602 30#include <kern/backtrace.h>
6d2010ae 31#include <kern/host.h>
39236c6e 32#include <kern/zalloc.h>
6d2010ae
A
33
34#include <IOKit/system.h>
35#include <libkern/c++/OSKext.h>
36#include <libkern/OSAtomic.h>
37
38#include <IOKit/IOStatisticsPrivate.h>
39#include <IOKit/IOUserClient.h>
40#include <IOKit/IOEventSource.h>
41#include <IOKit/IOKitDebug.h>
42
43#if IOKITSTATS
6d2010ae
A
44bool IOStatistics::enabled = false;
45
46uint32_t IOStatistics::sequenceID = 0;
47
48uint32_t IOStatistics::lastClassIndex = 0;
49uint32_t IOStatistics::lastKextIndex = 0;
50
51uint32_t IOStatistics::loadedKexts = 0;
52uint32_t IOStatistics::registeredClasses = 0;
53uint32_t IOStatistics::registeredCounters = 0;
54uint32_t IOStatistics::registeredWorkloops = 0;
55
56uint32_t IOStatistics::attachedEventSources = 0;
57
58IOWorkLoopDependency *IOStatistics::nextWorkLoopDependency = NULL;
59
60/* Logging */
61
62#define LOG_LEVEL 0
63
64#define LOG(level, format, ...) \
65do { \
66 if (level <= LOG_LEVEL) \
0a7de745 67 printf(format, ##__VA_ARGS__); \
6d2010ae
A
68} while (0)
69
70/* Locks */
71
72IORWLock *IOStatistics::lock = NULL;
73
74/* Kext tree */
75
76KextNode *IOStatistics::kextHint = NULL;
77
78IOStatistics::KextTreeHead IOStatistics::kextHead = RB_INITIALIZER(&IOStatistics::kextHead);
79
0a7de745
A
80int
81IOStatistics::kextNodeCompare(KextNode *e1, KextNode *e2)
6d2010ae 82{
0a7de745
A
83 if (e1->kext < e2->kext) {
84 return -1;
85 } else if (e1->kext > e2->kext) {
86 return 1;
87 } else {
88 return 0;
89 }
6d2010ae
A
90}
91
92RB_GENERATE(IOStatistics::KextTree, KextNode, link, kextNodeCompare);
93
94/* Kext tree ordered by address */
95
96IOStatistics::KextAddressTreeHead IOStatistics::kextAddressHead = RB_INITIALIZER(&IOStatistics::kextAddressHead);
97
0a7de745
A
98int
99IOStatistics::kextAddressNodeCompare(KextNode *e1, KextNode *e2)
6d2010ae 100{
0a7de745
A
101 if (e1->address < e2->address) {
102 return -1;
103 } else if (e1->address > e2->address) {
104 return 1;
105 } else {
106 return 0;
107 }
6d2010ae
A
108}
109
110RB_GENERATE(IOStatistics::KextAddressTree, KextNode, addressLink, kextAddressNodeCompare);
111
112/* Class tree */
113
114IOStatistics::ClassTreeHead IOStatistics::classHead = RB_INITIALIZER(&IOStatistics::classHead);
115
0a7de745
A
116int
117IOStatistics::classNodeCompare(ClassNode *e1, ClassNode *e2)
118{
119 if (e1->metaClass < e2->metaClass) {
120 return -1;
121 } else if (e1->metaClass > e2->metaClass) {
122 return 1;
123 } else {
124 return 0;
125 }
6d2010ae
A
126}
127
128RB_GENERATE(IOStatistics::ClassTree, ClassNode, tLink, classNodeCompare);
129
130/* Workloop dependencies */
131
0a7de745
A
132int
133IOWorkLoopCounter::loadTagCompare(IOWorkLoopDependency *e1, IOWorkLoopDependency *e2)
134{
135 if (e1->loadTag < e2->loadTag) {
136 return -1;
137 } else if (e1->loadTag > e2->loadTag) {
138 return 1;
139 } else {
140 return 0;
141 }
6d2010ae
A
142}
143
144RB_GENERATE(IOWorkLoopCounter::DependencyTree, IOWorkLoopDependency, link, IOWorkLoopCounter::loadTagCompare);
145
146/* sysctl stuff */
147
0a7de745 148static int
6d2010ae
A
149oid_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1, int arg2, struct sysctl_req *req)
150{
151 int error = EINVAL;
152 uint32_t request = arg2;
153
c3c9b80d
A
154 if (!IOStatistics::isEnabled()) {
155 return ENOENT;
156 }
157
0a7de745
A
158 switch (request) {
159 case kIOStatisticsGeneral:
160 error = IOStatistics::getStatistics(req);
161 break;
162 case kIOStatisticsWorkLoop:
163 error = IOStatistics::getWorkLoopStatistics(req);
164 break;
165 case kIOStatisticsUserClient:
166 error = IOStatistics::getUserClientStatistics(req);
167 break;
168 default:
169 break;
6d2010ae
A
170 }
171
172 return error;
173}
0a7de745 174
cb323159 175SYSCTL_NODE(_debug, OID_AUTO, iokit_statistics, CTLFLAG_RW | CTLFLAG_LOCKED, NULL, "IOStatistics");
6d2010ae
A
176
177static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, general,
c3c9b80d 178 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159 179 NULL, kIOStatisticsGeneral, oid_sysctl, "S", "");
6d2010ae
A
180
181static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, workloop,
c3c9b80d 182 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159 183 NULL, kIOStatisticsWorkLoop, oid_sysctl, "S", "");
6d2010ae
A
184
185static SYSCTL_PROC(_debug_iokit_statistics, OID_AUTO, userclient,
c3c9b80d 186 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_LOCKED,
cb323159 187 NULL, kIOStatisticsUserClient, oid_sysctl, "S", "");
6d2010ae 188
c3c9b80d 189
0a7de745
A
190void
191IOStatistics::initialize()
6d2010ae
A
192{
193 if (enabled) {
194 return;
195 }
196
316670eb 197 /* Only enabled if the boot argument is set. */
6d2010ae
A
198 if (!(kIOStatistics & gIOKitDebug)) {
199 return;
200 }
0a7de745 201
6d2010ae
A
202 lock = IORWLockAlloc();
203 if (!lock) {
204 return;
205 }
0a7de745 206
6d2010ae
A
207 nextWorkLoopDependency = (IOWorkLoopDependency*)kalloc(sizeof(IOWorkLoopDependency));
208 if (!nextWorkLoopDependency) {
209 return;
210 }
0a7de745 211
6d2010ae
A
212 enabled = true;
213}
214
0a7de745
A
215void
216IOStatistics::onKextLoad(OSKext *kext, kmod_info_t *kmod_info)
6d2010ae
A
217{
218 KextNode *ke;
219
220 assert(kext && kmod_info);
221
222 if (!enabled) {
223 return;
224 }
225
226 LOG(1, "IOStatistics::onKextLoad: %s, tag %d, address 0x%llx, address end 0x%llx\n",
0a7de745 227 kext->getIdentifierCString(), kmod_info->id, (uint64_t)kmod_info->address, (uint64_t)(kmod_info->address + kmod_info->size));
6d2010ae
A
228
229 ke = (KextNode *)kalloc(sizeof(KextNode));
230 if (!ke) {
231 return;
232 }
233
234 memset(ke, 0, sizeof(KextNode));
0a7de745 235
6d2010ae
A
236 ke->kext = kext;
237 ke->loadTag = kmod_info->id;
238 ke->address = kmod_info->address;
239 ke->address_end = kmod_info->address + kmod_info->size;
240
241 SLIST_INIT(&ke->classList);
242 TAILQ_INIT(&ke->userClientCallList);
243
244 IORWLockWrite(lock);
245
246 RB_INSERT(KextTree, &kextHead, ke);
247 RB_INSERT(KextAddressTree, &kextAddressHead, ke);
0a7de745 248
6d2010ae
A
249 sequenceID++;
250 loadedKexts++;
251 lastKextIndex++;
0a7de745 252
6d2010ae
A
253 IORWLockUnlock(lock);
254}
255
0a7de745
A
256void
257IOStatistics::onKextUnload(OSKext *kext)
6d2010ae
A
258{
259 KextNode sought, *found;
0a7de745 260
6d2010ae 261 assert(kext);
0a7de745 262
6d2010ae
A
263 if (!enabled) {
264 return;
265 }
266
267 LOG(1, "IOStatistics::onKextUnload: %s\n", kext->getIdentifierCString());
0a7de745 268
6d2010ae
A
269 IORWLockWrite(lock);
270
271 sought.kext = kext;
272 found = RB_FIND(KextTree, &kextHead, &sought);
273 if (found) {
274 IOWorkLoopCounter *wlc;
275 IOUserClientProcessEntry *uce;
276
39236c6e 277 /* Disconnect workloop counters; cleanup takes place in unregisterWorkLoop() */
6d2010ae
A
278 while ((wlc = SLIST_FIRST(&found->workLoopList))) {
279 SLIST_REMOVE_HEAD(&found->workLoopList, link);
39236c6e 280 wlc->parentKext = NULL;
6d2010ae
A
281 }
282
283 /* Free up the user client list */
284 while ((uce = TAILQ_FIRST(&found->userClientCallList))) {
285 TAILQ_REMOVE(&found->userClientCallList, uce, link);
286 kfree(uce, sizeof(IOUserClientProcessEntry));
287 }
288
289 /* Remove from kext trees */
290 RB_REMOVE(KextTree, &kextHead, found);
291 RB_REMOVE(KextAddressTree, &kextAddressHead, found);
292
293 /*
294 * Clear a matching kextHint to avoid use after free in
295 * onClassAdded() for a class add after a KEXT unload.
296 */
297 if (found == kextHint) {
298 kextHint = NULL;
299 }
0a7de745 300
6d2010ae
A
301 /* Finally, free the class node */
302 kfree(found, sizeof(KextNode));
0a7de745 303
6d2010ae
A
304 sequenceID++;
305 loadedKexts--;
0a7de745 306 } else {
6d2010ae
A
307 panic("IOStatistics::onKextUnload: cannot find kext: %s", kext->getIdentifierCString());
308 }
309
310 IORWLockUnlock(lock);
311}
312
0a7de745
A
313void
314IOStatistics::onClassAdded(OSKext *parentKext, OSMetaClass *metaClass)
6d2010ae
A
315{
316 ClassNode *ce;
317 KextNode soughtKext, *foundKext = NULL;
318
319 assert(parentKext && metaClass);
320
321 if (!enabled) {
322 return;
323 }
324
325 LOG(1, "IOStatistics::onClassAdded: %s\n", metaClass->getClassName());
326
327 ce = (ClassNode *)kalloc(sizeof(ClassNode));
328 if (!ce) {
0a7de745 329 return;
6d2010ae
A
330 }
331
332 memset(ce, 0, sizeof(ClassNode));
333
334 IORWLockWrite(lock);
335
336 /* Hinted? */
337 if (kextHint && kextHint->kext == parentKext) {
338 foundKext = kextHint;
0a7de745 339 } else {
6d2010ae
A
340 soughtKext.kext = parentKext;
341 foundKext = RB_FIND(KextTree, &kextHead, &soughtKext);
342 }
343
344 if (foundKext) {
345 ClassNode soughtClass, *foundClass = NULL;
346 const OSMetaClass *superClass;
347
348 ce->metaClass = metaClass;
349 ce->classID = lastClassIndex++;
350 ce->parentKext = foundKext;
0a7de745 351
6d2010ae 352 /* Has superclass? */
0a7de745 353 superClass = ce->metaClass->getSuperClass();
6d2010ae
A
354 if (superClass) {
355 soughtClass.metaClass = superClass;
356 foundClass = RB_FIND(ClassTree, &classHead, &soughtClass);
357 }
358 ce->superClassID = foundClass ? foundClass->classID : (uint32_t)(-1);
359
360 SLIST_INIT(&ce->counterList);
361 SLIST_INIT(&ce->userClientList);
0a7de745 362
6d2010ae
A
363 RB_INSERT(ClassTree, &classHead, ce);
364 SLIST_INSERT_HEAD(&foundKext->classList, ce, lLink);
0a7de745 365
6d2010ae 366 foundKext->classes++;
0a7de745 367
6d2010ae 368 kextHint = foundKext;
0a7de745
A
369
370 sequenceID++;
6d2010ae 371 registeredClasses++;
0a7de745 372 } else {
6d2010ae
A
373 panic("IOStatistics::onClassAdded: cannot find parent kext: %s", parentKext->getIdentifierCString());
374 }
0a7de745 375
6d2010ae
A
376 IORWLockUnlock(lock);
377}
378
0a7de745
A
379void
380IOStatistics::onClassRemoved(OSKext *parentKext, OSMetaClass *metaClass)
6d2010ae
A
381{
382 ClassNode sought, *found;
383
384 assert(parentKext && metaClass);
385
386 if (!enabled) {
387 return;
388 }
389
390 LOG(1, "IOStatistics::onClassRemoved: %s\n", metaClass->getClassName());
391
392 IORWLockWrite(lock);
393
394 sought.metaClass = metaClass;
395 found = RB_FIND(ClassTree, &classHead, &sought);
396 if (found) {
397 IOEventSourceCounter *esc;
398 IOUserClientCounter *ucc;
0a7de745 399
6d2010ae
A
400 /* Free up the list of counters */
401 while ((esc = SLIST_FIRST(&found->counterList))) {
402 SLIST_REMOVE_HEAD(&found->counterList, link);
403 kfree(esc, sizeof(IOEventSourceCounter));
404 }
405
406 /* Free up the user client list */
407 while ((ucc = SLIST_FIRST(&found->userClientList))) {
408 SLIST_REMOVE_HEAD(&found->userClientList, link);
409 kfree(ucc, sizeof(IOUserClientCounter));
410 }
411
412 /* Remove from class tree */
413 RB_REMOVE(ClassTree, &classHead, found);
0a7de745 414
6d2010ae
A
415 /* Remove from parent */
416 SLIST_REMOVE(&found->parentKext->classList, found, ClassNode, lLink);
0a7de745 417
6d2010ae
A
418 /* Finally, free the class node */
419 kfree(found, sizeof(ClassNode));
0a7de745 420
6d2010ae
A
421 sequenceID++;
422 registeredClasses--;
0a7de745 423 } else {
6d2010ae
A
424 panic("IOStatistics::onClassRemoved: cannot find class: %s", metaClass->getClassName());
425 }
426
427 IORWLockUnlock(lock);
428}
429
0a7de745
A
430IOEventSourceCounter *
431IOStatistics::registerEventSource(OSObject *inOwner)
6d2010ae
A
432{
433 IOEventSourceCounter *counter = NULL;
434 ClassNode sought, *found = NULL;
435 boolean_t createDummyCounter = FALSE;
0a7de745 436
6d2010ae
A
437 assert(inOwner);
438
439 if (!enabled) {
440 return NULL;
441 }
442
443 counter = (IOEventSourceCounter*)kalloc(sizeof(IOEventSourceCounter));
444 if (!counter) {
445 return NULL;
446 }
0a7de745 447
6d2010ae
A
448 memset(counter, 0, sizeof(IOEventSourceCounter));
449
450 IORWLockWrite(lock);
451
452 /* Workaround for <rdar://problem/7158117> - create a dummy counter when inOwner is bad.
453 * We use retainCount here as our best indication that the pointer is awry.
454 */
455 if (inOwner->retainCount > 0xFFFFFF) {
456 kprintf("IOStatistics::registerEventSource - bad metaclass %p\n", inOwner);
457 createDummyCounter = TRUE;
0a7de745 458 } else {
6d2010ae
A
459 sought.metaClass = inOwner->getMetaClass();
460 found = RB_FIND(ClassTree, &classHead, &sought);
461 }
462
463 if (found) {
464 counter->parentClass = found;
465 SLIST_INSERT_HEAD(&found->counterList, counter, link);
466 registeredCounters++;
467 }
468
469 if (!(createDummyCounter || found)) {
470 panic("IOStatistics::registerEventSource: cannot find parent class: %s", inOwner->getMetaClass()->getClassName());
471 }
0a7de745 472
6d2010ae 473 IORWLockUnlock(lock);
0a7de745 474
6d2010ae
A
475 return counter;
476}
477
0a7de745
A
478void
479IOStatistics::unregisterEventSource(IOEventSourceCounter *counter)
6d2010ae
A
480{
481 if (!counter) {
482 return;
483 }
484
485 IORWLockWrite(lock);
486
487 if (counter->parentClass) {
488 SLIST_REMOVE(&counter->parentClass->counterList, counter, IOEventSourceCounter, link);
489 registeredCounters--;
490 }
491 kfree(counter, sizeof(IOEventSourceCounter));
0a7de745 492
6d2010ae
A
493 IORWLockUnlock(lock);
494}
495
0a7de745
A
496IOWorkLoopCounter*
497IOStatistics::registerWorkLoop(IOWorkLoop *workLoop)
6d2010ae
A
498{
499 IOWorkLoopCounter *counter = NULL;
500 KextNode *found;
501
502 assert(workLoop);
503
504 if (!enabled) {
505 return NULL;
506 }
507
508 counter = (IOWorkLoopCounter*)kalloc(sizeof(IOWorkLoopCounter));
509 if (!counter) {
510 return NULL;
511 }
0a7de745 512
6d2010ae
A
513 memset(counter, 0, sizeof(IOWorkLoopCounter));
514
515 found = getKextNodeFromBacktrace(TRUE);
516 if (!found) {
517 panic("IOStatistics::registerWorkLoop: cannot find parent kext");
518 }
519
520 counter->parentKext = found;
521 counter->workLoop = workLoop;
522 RB_INIT(&counter->dependencyHead);
523 SLIST_INSERT_HEAD(&found->workLoopList, counter, link);
524 registeredWorkloops++;
525
526 releaseKextNode(found);
527
528 return counter;
529}
530
0a7de745
A
531void
532IOStatistics::unregisterWorkLoop(IOWorkLoopCounter *counter)
6d2010ae
A
533{
534 if (!counter) {
535 return;
536 }
0a7de745 537
6d2010ae 538 IORWLockWrite(lock);
39236c6e
A
539 if (counter->parentKext) {
540 SLIST_REMOVE(&counter->parentKext->workLoopList, counter, IOWorkLoopCounter, link);
541 }
6d2010ae
A
542 kfree(counter, sizeof(IOWorkLoopCounter));
543 registeredWorkloops--;
0a7de745 544
6d2010ae
A
545 IORWLockUnlock(lock);
546}
547
0a7de745
A
548IOUserClientCounter *
549IOStatistics::registerUserClient(IOUserClient *userClient)
6d2010ae
A
550{
551 ClassNode sought, *found;
552 IOUserClientCounter *counter = NULL;
553
554 assert(userClient);
555
556 if (!enabled) {
557 return NULL;
558 }
559
560 counter = (IOUserClientCounter*)kalloc(sizeof(IOUserClientCounter));
561 if (!counter) {
562 return NULL;
563 }
0a7de745 564
6d2010ae
A
565 memset(counter, 0, sizeof(IOUserClientCounter));
566
567 IORWLockWrite(lock);
568
569 sought.metaClass = userClient->getMetaClass();
570
571 found = RB_FIND(ClassTree, &classHead, &sought);
572 if (found) {
573 counter->parentClass = found;
574 SLIST_INSERT_HEAD(&found->userClientList, counter, link);
0a7de745 575 } else {
6d2010ae
A
576 panic("IOStatistics::registerUserClient: cannot find parent class: %s", sought.metaClass->getClassName());
577 }
578
579 IORWLockUnlock(lock);
580
581 return counter;
582}
583
0a7de745
A
584void
585IOStatistics::unregisterUserClient(IOUserClientCounter *counter)
6d2010ae
A
586{
587 if (!counter) {
588 return;
589 }
0a7de745 590
6d2010ae 591 IORWLockWrite(lock);
0a7de745 592
6d2010ae
A
593 SLIST_REMOVE(&counter->parentClass->userClientList, counter, IOUserClientCounter, link);
594 kfree(counter, sizeof(IOUserClientCounter));
595
596 IORWLockUnlock(lock);
597}
598
0a7de745
A
599void
600IOStatistics::attachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc)
6d2010ae
A
601{
602 if (!wlc) {
0a7de745 603 return;
6d2010ae 604 }
0a7de745 605
6d2010ae 606 IORWLockWrite(lock);
0a7de745 607
6d2010ae
A
608 if (!nextWorkLoopDependency) {
609 return;
610 }
0a7de745 611
6d2010ae
A
612 attachedEventSources++;
613 wlc->attachedEventSources++;
0a7de745 614
6d2010ae
A
615 /* Track the kext dependency */
616 nextWorkLoopDependency->loadTag = esc->parentClass->parentKext->loadTag;
617 if (NULL == RB_INSERT(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, nextWorkLoopDependency)) {
618 nextWorkLoopDependency = (IOWorkLoopDependency*)kalloc(sizeof(IOWorkLoopDependency));
619 }
0a7de745 620
6d2010ae
A
621 IORWLockUnlock(lock);
622}
623
0a7de745
A
624void
625IOStatistics::detachWorkLoopEventSource(IOWorkLoopCounter *wlc, IOEventSourceCounter *esc)
6d2010ae
A
626{
627 IOWorkLoopDependency sought, *found;
0a7de745 628
6d2010ae
A
629 if (!wlc) {
630 return;
631 }
0a7de745 632
6d2010ae
A
633 IORWLockWrite(lock);
634
635 attachedEventSources--;
636 wlc->attachedEventSources--;
0a7de745 637
6d2010ae
A
638 sought.loadTag = esc->parentClass->parentKext->loadTag;
639
640 found = RB_FIND(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, &sought);
641 if (found) {
642 RB_REMOVE(IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead, found);
643 kfree(found, sizeof(IOWorkLoopDependency));
644 }
645
646 IORWLockUnlock(lock);
647}
648
0a7de745
A
649int
650IOStatistics::getStatistics(sysctl_req *req)
6d2010ae
A
651{
652 int error;
653 uint32_t calculatedSize, size;
654 char *buffer, *ptr;
655 IOStatisticsHeader *header;
656
657 assert(IOStatistics::enabled && req);
0a7de745 658
6d2010ae
A
659 IORWLockRead(IOStatistics::lock);
660
661 /* Work out how much we need to allocate. IOStatisticsKext is of variable size. */
0a7de745
A
662 calculatedSize = sizeof(IOStatisticsHeader) +
663 sizeof(IOStatisticsGlobal) +
664 (sizeof(IOStatisticsKext) * loadedKexts) + (sizeof(uint32_t) * registeredClasses) +
665 (sizeof(IOStatisticsMemory) * loadedKexts) +
666 (sizeof(IOStatisticsClass) * registeredClasses) +
667 (sizeof(IOStatisticsCounter) * registeredClasses) +
668 (sizeof(IOStatisticsKextIdentifier) * loadedKexts) +
669 (sizeof(IOStatisticsClassName) * registeredClasses);
6d2010ae
A
670
671 /* Size request? */
672 if (req->oldptr == USER_ADDR_NULL) {
673 error = SYSCTL_OUT(req, NULL, calculatedSize);
674 goto exit;
675 }
0a7de745 676
6d2010ae
A
677 /* Read only */
678 if (req->newptr != USER_ADDR_NULL) {
679 error = EPERM;
680 goto exit;
681 }
682
f427ee49
A
683 buffer = (char*)kheap_alloc(KHEAP_TEMP, calculatedSize,
684 (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
6d2010ae
A
685 if (!buffer) {
686 error = ENOMEM;
687 goto exit;
688 }
689
6d2010ae 690 ptr = buffer;
0a7de745 691
6d2010ae
A
692 header = (IOStatisticsHeader*)((void*)ptr);
693
694 header->sig = IOSTATISTICS_SIG;
695 header->ver = IOSTATISTICS_VER;
696
697 header->seq = sequenceID;
698
699 ptr += sizeof(IOStatisticsHeader);
700
701 /* Global data - seq, timers, interrupts, etc) */
702 header->globalStatsOffset = sizeof(IOStatisticsHeader);
703 size = copyGlobalStatistics((IOStatisticsGlobal*)((void*)ptr));
704 ptr += size;
705
706 /* Kext statistics */
707 header->kextStatsOffset = header->globalStatsOffset + size;
708 size = copyKextStatistics((IOStatisticsKext*)((void*)ptr));
709 ptr += size;
710
711 /* Memory allocation info */
712 header->memoryStatsOffset = header->kextStatsOffset + size;
713 size = copyMemoryStatistics((IOStatisticsMemory*)((void*)ptr));
714 ptr += size;
0a7de745 715
6d2010ae
A
716 /* Class statistics */
717 header->classStatsOffset = header->memoryStatsOffset + size;
718 size = copyClassStatistics((IOStatisticsClass*)((void*)ptr));
719 ptr += size;
0a7de745 720
6d2010ae
A
721 /* Dynamic class counter data */
722 header->counterStatsOffset = header->classStatsOffset + size;
723 size = copyCounterStatistics((IOStatisticsCounter*)((void*)ptr));
724 ptr += size;
0a7de745 725
6d2010ae
A
726 /* Kext identifiers */
727 header->kextIdentifiersOffset = header->counterStatsOffset + size;
728 size = copyKextIdentifiers((IOStatisticsKextIdentifier*)((void*)ptr));
729 ptr += size;
730
731 /* Class names */
732 header->classNamesOffset = header->kextIdentifiersOffset + size;
733 size = copyClassNames((IOStatisticsClassName*)ptr);
734 ptr += size;
0a7de745 735
6d2010ae 736 LOG(2, "IOStatistics::getStatistics - calculatedSize 0x%x, kexts 0x%x, classes 0x%x.\n",
0a7de745 737 calculatedSize, loadedKexts, registeredClasses);
6d2010ae 738
0a7de745 739 assert((uint32_t)(ptr - buffer) == calculatedSize );
6d2010ae
A
740
741 error = SYSCTL_OUT(req, buffer, calculatedSize);
742
f427ee49 743 kheap_free(KHEAP_TEMP, buffer, calculatedSize);
6d2010ae
A
744
745exit:
746 IORWLockUnlock(IOStatistics::lock);
747 return error;
748}
749
0a7de745
A
750int
751IOStatistics::getWorkLoopStatistics(sysctl_req *req)
6d2010ae
A
752{
753 int error;
754 uint32_t calculatedSize, size;
755 char *buffer;
756 IOStatisticsWorkLoopHeader *header;
757
758 assert(IOStatistics::enabled && req);
759
760 IORWLockRead(IOStatistics::lock);
761
762 /* Approximate how much we need to allocate (worse case estimate) */
763 calculatedSize = sizeof(IOStatisticsWorkLoop) * registeredWorkloops +
0a7de745 764 sizeof(uint32_t) * attachedEventSources;
6d2010ae
A
765
766 /* Size request? */
767 if (req->oldptr == USER_ADDR_NULL) {
768 error = SYSCTL_OUT(req, NULL, calculatedSize);
769 goto exit;
770 }
0a7de745 771
6d2010ae
A
772 /* Read only */
773 if (req->newptr != USER_ADDR_NULL) {
774 error = EPERM;
775 goto exit;
776 }
777
f427ee49
A
778 buffer = (char*)kheap_alloc(KHEAP_TEMP, calculatedSize,
779 (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
6d2010ae
A
780 if (!buffer) {
781 error = ENOMEM;
782 goto exit;
783 }
6d2010ae 784 header = (IOStatisticsWorkLoopHeader*)((void*)buffer);
0a7de745 785
6d2010ae
A
786 header->sig = IOSTATISTICS_SIG_WORKLOOP;
787 header->ver = IOSTATISTICS_VER;
788
789 header->seq = sequenceID;
0a7de745 790
6d2010ae
A
791 header->workloopCount = registeredWorkloops;
792
793 size = copyWorkLoopStatistics(&header->workLoopStats);
794
795 LOG(2, "IOStatistics::getWorkLoopStatistics: calculatedSize %d, size %d\n", calculatedSize, size);
796
797 assert( size <= calculatedSize );
798
799 error = SYSCTL_OUT(req, buffer, size);
800
f427ee49 801 kheap_free(KHEAP_TEMP, buffer, calculatedSize);
6d2010ae
A
802
803exit:
804 IORWLockUnlock(IOStatistics::lock);
805 return error;
806}
807
0a7de745
A
808int
809IOStatistics::getUserClientStatistics(sysctl_req *req)
810{
6d2010ae
A
811 int error;
812 uint32_t calculatedSize, size;
813 char *buffer;
814 uint32_t requestedLoadTag = 0;
815 IOStatisticsUserClientHeader *header;
816
817 assert(IOStatistics::enabled && req);
818
819 IORWLockRead(IOStatistics::lock);
820
821 /* Work out how much we need to allocate */
0a7de745
A
822 calculatedSize = sizeof(IOStatisticsUserClientHeader) +
823 sizeof(IOStatisticsUserClientCall) * IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS * loadedKexts;
824
6d2010ae
A
825 /* Size request? */
826 if (req->oldptr == USER_ADDR_NULL) {
827 error = SYSCTL_OUT(req, NULL, calculatedSize);
828 goto exit;
829 }
830
831 /* Kext request (potentially) valid? */
832 if (!req->newptr || req->newlen < sizeof(requestedLoadTag)) {
833 error = EINVAL;
834 goto exit;
835 }
836
5ba3f43e
A
837 error = SYSCTL_IN(req, &requestedLoadTag, sizeof(requestedLoadTag));
838 if (error) {
839 goto exit;
840 }
841
6d2010ae
A
842 LOG(2, "IOStatistics::getUserClientStatistics - requesting kext w/load tag: %d\n", requestedLoadTag);
843
f427ee49
A
844 buffer = (char*)kheap_alloc(KHEAP_TEMP, calculatedSize,
845 (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
6d2010ae
A
846 if (!buffer) {
847 error = ENOMEM;
848 goto exit;
849 }
6d2010ae
A
850 header = (IOStatisticsUserClientHeader*)((void*)buffer);
851
852 header->sig = IOSTATISTICS_SIG_USERCLIENT;
853 header->ver = IOSTATISTICS_VER;
0a7de745 854
6d2010ae
A
855 header->seq = sequenceID;
856
857 header->processes = 0;
858
859 size = copyUserClientStatistics(header, requestedLoadTag);
0a7de745 860
6d2010ae 861 assert((sizeof(IOStatisticsUserClientHeader) + size) <= calculatedSize);
0a7de745 862
6d2010ae
A
863 if (size) {
864 error = SYSCTL_OUT(req, buffer, sizeof(IOStatisticsUserClientHeader) + size);
0a7de745 865 } else {
6d2010ae
A
866 error = EINVAL;
867 }
868
f427ee49 869 kheap_free(KHEAP_TEMP, buffer, calculatedSize);
6d2010ae
A
870
871exit:
872 IORWLockUnlock(IOStatistics::lock);
873 return error;
874}
875
0a7de745
A
876uint32_t
877IOStatistics::copyGlobalStatistics(IOStatisticsGlobal *stats)
6d2010ae
A
878{
879 stats->kextCount = loadedKexts;
880 stats->classCount = registeredClasses;
881 stats->workloops = registeredWorkloops;
0a7de745 882
6d2010ae
A
883 return sizeof(IOStatisticsGlobal);
884}
885
0a7de745
A
886uint32_t
887IOStatistics::copyKextStatistics(IOStatisticsKext *stats)
6d2010ae
A
888{
889 KextNode *ke;
890 ClassNode *ce;
891 uint32_t index = 0;
892
893 RB_FOREACH(ke, KextTree, &kextHead) {
894 stats->loadTag = ke->loadTag;
895 ke->kext->getSizeInfo(&stats->loadSize, &stats->wiredSize);
896
897 stats->classes = ke->classes;
898
899 /* Append indices of owned classes */
900 SLIST_FOREACH(ce, &ke->classList, lLink) {
901 stats->classIndexes[index++] = ce->classID;
902 }
0a7de745 903
6d2010ae
A
904 stats = (IOStatisticsKext *)((void*)((char*)stats + sizeof(IOStatisticsKext) + (ke->classes * sizeof(uint32_t))));
905 }
906
0a7de745 907 return sizeof(IOStatisticsKext) * loadedKexts + sizeof(uint32_t) * registeredClasses;
6d2010ae
A
908}
909
0a7de745
A
910uint32_t
911IOStatistics::copyMemoryStatistics(IOStatisticsMemory *stats)
6d2010ae
A
912{
913 KextNode *ke;
914
915 RB_FOREACH(ke, KextTree, &kextHead) {
916 stats->allocatedSize = ke->memoryCounters[kIOStatisticsMalloc];
0a7de745 917 stats->freedSize = ke->memoryCounters[kIOStatisticsFree];
6d2010ae
A
918 stats->allocatedAlignedSize = ke->memoryCounters[kIOStatisticsMallocAligned];
919 stats->freedAlignedSize = ke->memoryCounters[kIOStatisticsFreeAligned];
920 stats->allocatedContiguousSize = ke->memoryCounters[kIOStatisticsMallocContiguous];
921 stats->freedContiguousSize = ke->memoryCounters[kIOStatisticsFreeContiguous];
922 stats->allocatedPageableSize = ke->memoryCounters[kIOStatisticsMallocPageable];
923 stats->freedPageableSize = ke->memoryCounters[kIOStatisticsFreePageable];
924 stats++;
925 }
0a7de745
A
926
927 return sizeof(IOStatisticsMemory) * loadedKexts;
6d2010ae
A
928}
929
0a7de745
A
930uint32_t
931IOStatistics::copyClassStatistics(IOStatisticsClass *stats)
6d2010ae
A
932{
933 KextNode *ke;
934 ClassNode *ce;
935
936 RB_FOREACH(ke, KextTree, &kextHead) {
937 SLIST_FOREACH(ce, &ke->classList, lLink) {
938 stats->classID = ce->classID;
0a7de745 939 stats->superClassID = ce->superClassID;
6d2010ae
A
940 stats->classSize = ce->metaClass->getClassSize();
941
942 stats++;
943 }
944 }
945
946 return sizeof(IOStatisticsClass) * registeredClasses;
947}
948
0a7de745
A
949uint32_t
950IOStatistics::copyCounterStatistics(IOStatisticsCounter *stats)
6d2010ae
A
951{
952 KextNode *ke;
953 ClassNode *ce;
954
955 RB_FOREACH(ke, KextTree, &kextHead) {
956 SLIST_FOREACH(ce, &ke->classList, lLink) {
957 IOUserClientCounter *userClientCounter;
958 IOEventSourceCounter *counter;
959
960 stats->classID = ce->classID;
961 stats->classInstanceCount = ce->metaClass->getInstanceCount();
962
963 IOStatisticsUserClients *uc = &stats->userClientStatistics;
964
965 /* User client counters */
966 SLIST_FOREACH(userClientCounter, &ce->userClientList, link) {
967 uc->clientCalls += userClientCounter->clientCalls;
968 uc->created++;
969 }
970
971 IOStatisticsInterruptEventSources *iec = &stats->interruptEventSourceStatistics;
972 IOStatisticsInterruptEventSources *fiec = &stats->filterInterruptEventSourceStatistics;
973 IOStatisticsTimerEventSources *tec = &stats->timerEventSourceStatistics;
974 IOStatisticsCommandGates *cgc = &stats->commandGateStatistics;
975 IOStatisticsCommandQueues *cqc = &stats->commandQueueStatistics;
976 IOStatisticsDerivedEventSources *dec = &stats->derivedEventSourceStatistics;
977
978 /* Event source counters */
979 SLIST_FOREACH(counter, &ce->counterList, link) {
0a7de745
A
980 switch (counter->type) {
981 case kIOStatisticsInterruptEventSourceCounter:
982 iec->created++;
983 iec->produced += counter->u.interrupt.produced;
984 iec->checksForWork += counter->u.interrupt.checksForWork;
985 break;
986 case kIOStatisticsFilterInterruptEventSourceCounter:
987 fiec->created++;
988 fiec->produced += counter->u.filter.produced;
989 fiec->checksForWork += counter->u.filter.checksForWork;
990 break;
991 case kIOStatisticsTimerEventSourceCounter:
992 tec->created++;
993 tec->timeouts += counter->u.timer.timeouts;
994 tec->checksForWork += counter->u.timer.checksForWork;
995 tec->timeOnGate += counter->timeOnGate;
996 tec->closeGateCalls += counter->closeGateCalls;
997 tec->openGateCalls += counter->openGateCalls;
998 break;
999 case kIOStatisticsCommandGateCounter:
1000 cgc->created++;
1001 cgc->timeOnGate += counter->timeOnGate;
1002 cgc->actionCalls += counter->u.commandGate.actionCalls;
1003 break;
1004 case kIOStatisticsCommandQueueCounter:
1005 cqc->created++;
1006 cqc->actionCalls += counter->u.commandQueue.actionCalls;
1007 break;
1008 case kIOStatisticsDerivedEventSourceCounter:
1009 dec->created++;
1010 dec->timeOnGate += counter->timeOnGate;
1011 dec->closeGateCalls += counter->closeGateCalls;
1012 dec->openGateCalls += counter->openGateCalls;
1013 break;
1014 default:
1015 break;
6d2010ae
A
1016 }
1017 }
0a7de745 1018
6d2010ae
A
1019 stats++;
1020 }
1021 }
1022
1023 return sizeof(IOStatisticsCounter) * registeredClasses;
1024}
1025
0a7de745
A
1026uint32_t
1027IOStatistics::copyKextIdentifiers(IOStatisticsKextIdentifier *kextIDs)
6d2010ae
A
1028{
1029 KextNode *ke;
1030
1031 RB_FOREACH(ke, KextTree, &kextHead) {
1032 strncpy(kextIDs->identifier, ke->kext->getIdentifierCString(), kIOStatisticsDriverNameLength);
1033 kextIDs++;
1034 }
1035
0a7de745 1036 return sizeof(IOStatisticsKextIdentifier) * loadedKexts;
6d2010ae
A
1037}
1038
0a7de745
A
1039uint32_t
1040IOStatistics::copyClassNames(IOStatisticsClassName *classNames)
6d2010ae
A
1041{
1042 KextNode *ke;
1043 ClassNode *ce;
1044
1045 RB_FOREACH(ke, KextTree, &kextHead) {
1046 SLIST_FOREACH(ce, &ke->classList, lLink) {
1047 strncpy(classNames->name, ce->metaClass->getClassName(), kIOStatisticsClassNameLength);
1048 classNames++;
1049 }
1050 }
0a7de745
A
1051
1052 return sizeof(IOStatisticsClassName) * registeredClasses;
6d2010ae
A
1053}
1054
0a7de745
A
1055uint32_t
1056IOStatistics::copyWorkLoopStatistics(IOStatisticsWorkLoop *stats)
6d2010ae
A
1057{
1058 KextNode *ke;
1059 IOWorkLoopCounter *wlc;
1060 IOWorkLoopDependency *dependentNode;
1061 uint32_t size, accumulatedSize = 0;
1062
1063 RB_FOREACH(ke, KextTree, &kextHead) {
1064 SLIST_FOREACH(wlc, &ke->workLoopList, link) {
1065 stats->kextLoadTag = ke->loadTag;
1066 stats->attachedEventSources = wlc->attachedEventSources;
1067 stats->timeOnGate = wlc->timeOnGate;
1068 stats->dependentKexts = 0;
1069 RB_FOREACH(dependentNode, IOWorkLoopCounter::DependencyTree, &wlc->dependencyHead) {
1070 stats->dependentKextLoadTags[stats->dependentKexts] = dependentNode->loadTag;
1071 stats->dependentKexts++;
1072 }
0a7de745 1073
6d2010ae 1074 size = sizeof(IOStatisticsWorkLoop) + (sizeof(uint32_t) * stats->dependentKexts);
0a7de745 1075
6d2010ae
A
1076 accumulatedSize += size;
1077 stats = (IOStatisticsWorkLoop*)((void*)((char*)stats + size));
1078 }
1079 }
1080
1081 return accumulatedSize;
1082}
1083
0a7de745
A
1084uint32_t
1085IOStatistics::copyUserClientStatistics(IOStatisticsUserClientHeader *stats, uint32_t loadTag)
6d2010ae
A
1086{
1087 KextNode *sought, *found = NULL;
1088 uint32_t procs = 0;
1089 IOUserClientProcessEntry *processEntry;
1090
1091 RB_FOREACH(sought, KextTree, &kextHead) {
1092 if (sought->loadTag == loadTag) {
1093 found = sought;
1094 break;
1095 }
1096 }
0a7de745 1097
6d2010ae
A
1098 if (!found) {
1099 return 0;
1100 }
1101
1102 TAILQ_FOREACH(processEntry, &found->userClientCallList, link) {
1103 strncpy(stats->userClientCalls[procs].processName, processEntry->processName, kIOStatisticsProcessNameLength);
1104 stats->userClientCalls[procs].pid = processEntry->pid;
1105 stats->userClientCalls[procs].calls = processEntry->calls;
1106 stats->processes++;
1107 procs++;
1108 }
1109
1110 return sizeof(IOStatisticsUserClientCall) * stats->processes;
1111}
1112
0a7de745
A
1113void
1114IOStatistics::storeUserClientCallInfo(IOUserClient *userClient, IOUserClientCounter *counter)
1115{
6d2010ae
A
1116 OSString *ossUserClientCreator = NULL;
1117 int32_t pid = -1;
1118 KextNode *parentKext;
1119 IOUserClientProcessEntry *entry, *nextEntry, *prevEntry = NULL;
1120 uint32_t count = 0;
1121 const char *ptr = NULL;
1122 OSObject *obj;
0a7de745 1123
6d2010ae
A
1124 /* TODO: see if this can be more efficient */
1125 obj = userClient->copyProperty("IOUserClientCreator",
0a7de745
A
1126 gIOServicePlane,
1127 kIORegistryIterateRecursively | kIORegistryIterateParents);
6d2010ae 1128
0a7de745 1129 if (!obj) {
6d2010ae 1130 goto err_nounlock;
0a7de745 1131 }
6d2010ae
A
1132
1133 ossUserClientCreator = OSDynamicCast(OSString, obj);
1134
1135 if (ossUserClientCreator) {
0a7de745
A
1136 uint32_t len, lenIter = 0;
1137
6d2010ae
A
1138 ptr = ossUserClientCreator->getCStringNoCopy();
1139 len = ossUserClientCreator->getLength();
0a7de745 1140
6d2010ae
A
1141 while ((*ptr != ' ') && (lenIter < len)) {
1142 ptr++;
1143 lenIter++;
1144 }
0a7de745 1145
6d2010ae
A
1146 if (lenIter < len) {
1147 ptr++; // Skip the space
1148 lenIter++;
1149 pid = 0;
0a7de745
A
1150 while ((*ptr != ',') && (lenIter < len)) {
1151 pid = pid * 10 + (*ptr - '0');
6d2010ae
A
1152 ptr++;
1153 lenIter++;
1154 }
0a7de745
A
1155
1156 if (lenIter == len) {
6d2010ae
A
1157 pid = -1;
1158 } else {
1159 ptr += 2;
1160 }
1161 }
1162 }
0a7de745
A
1163
1164 if (-1 == pid) {
6d2010ae 1165 goto err_nounlock;
0a7de745
A
1166 }
1167
6d2010ae
A
1168 IORWLockWrite(lock);
1169
1170 parentKext = counter->parentClass->parentKext;
1171
1172 TAILQ_FOREACH(entry, &parentKext->userClientCallList, link) {
1173 if (entry->pid == pid) {
1174 /* Found, so increment count and move to the head */
1175 entry->calls++;
1176 if (count) {
1177 TAILQ_REMOVE(&parentKext->userClientCallList, entry, link);
1178 break;
0a7de745 1179 } else {
6d2010ae
A
1180 /* At the head already, so increment and return */
1181 goto err_unlock;
1182 }
1183 }
0a7de745 1184
6d2010ae
A
1185 count++;
1186 }
1187
1188 if (!entry) {
1189 if (count == IOKIT_STATISTICS_RECORDED_USERCLIENT_PROCS) {
1190 /* Max elements hit, so reuse the last */
1191 entry = TAILQ_LAST(&parentKext->userClientCallList, ProcessEntryList);
1192 TAILQ_REMOVE(&parentKext->userClientCallList, entry, link);
0a7de745 1193 } else {
6d2010ae
A
1194 /* Otherwise, allocate a new entry */
1195 entry = (IOUserClientProcessEntry*)kalloc(sizeof(IOUserClientProcessEntry));
1196 if (!entry) {
0a7de745 1197 IORWLockUnlock(lock);
6d2010ae
A
1198 return;
1199 }
1200 }
1201
1202 strncpy(entry->processName, ptr, kIOStatisticsProcessNameLength);
1203 entry->pid = pid;
1204 entry->calls = 1;
1205 }
0a7de745 1206
6d2010ae 1207 TAILQ_FOREACH(nextEntry, &parentKext->userClientCallList, link) {
0a7de745 1208 if (nextEntry->calls <= entry->calls) {
6d2010ae 1209 break;
0a7de745
A
1210 }
1211
6d2010ae
A
1212 prevEntry = nextEntry;
1213 }
0a7de745
A
1214
1215 if (!prevEntry) {
6d2010ae 1216 TAILQ_INSERT_HEAD(&parentKext->userClientCallList, entry, link);
0a7de745 1217 } else {
6d2010ae 1218 TAILQ_INSERT_AFTER(&parentKext->userClientCallList, prevEntry, entry, link);
0a7de745
A
1219 }
1220
6d2010ae
A
1221err_unlock:
1222 IORWLockUnlock(lock);
0a7de745 1223
6d2010ae 1224err_nounlock:
0a7de745 1225 if (obj) {
6d2010ae 1226 obj->release();
0a7de745 1227 }
6d2010ae
A
1228}
1229
0a7de745
A
1230void
1231IOStatistics::countUserClientCall(IOUserClient *client)
1232{
6d2010ae
A
1233 IOUserClient::ExpansionData *data;
1234 IOUserClientCounter *counter;
0a7de745 1235
6d2010ae
A
1236 /* Guard against an uninitialized client object - <rdar://problem/8577946> */
1237 if (!(data = client->reserved)) {
1238 return;
1239 }
0a7de745 1240
6d2010ae
A
1241 if ((counter = data->counter)) {
1242 storeUserClientCallInfo(client, counter);
1243 OSIncrementAtomic(&counter->clientCalls);
1244 }
1245}
1246
0a7de745
A
1247KextNode *
1248IOStatistics::getKextNodeFromBacktrace(boolean_t write)
1249{
6d2010ae
A
1250 const uint32_t btMin = 3;
1251
1252 void *bt[16];
1253 unsigned btCount = sizeof(bt) / sizeof(bt[0]);
1254 vm_offset_t *scanAddr = NULL;
1255 uint32_t i;
1256 KextNode *found = NULL, *ke = NULL;
39236c6e
A
1257
1258 /*
1259 * Gathering the backtrace is a significant source of
1260 * overhead. OSBacktrace does many safety checks that
1261 * are not needed in this situation.
1262 */
cb323159 1263 btCount = backtrace((uintptr_t*)bt, btCount, NULL);
6d2010ae
A
1264
1265 if (write) {
1266 IORWLockWrite(lock);
1267 } else {
1268 IORWLockRead(lock);
1269 }
1270
1271 /* Ignore first levels */
1272 scanAddr = (vm_offset_t *)&bt[btMin - 1];
1273
316670eb 1274 for (i = btMin - 1; i < btCount; i++, scanAddr++) {
6d2010ae
A
1275 ke = RB_ROOT(&kextAddressHead);
1276 while (ke) {
1277 if (*scanAddr < ke->address) {
1278 ke = RB_LEFT(ke, addressLink);
0a7de745 1279 } else {
6d2010ae 1280 if ((*scanAddr < ke->address_end) && (*scanAddr >= ke->address)) {
0a7de745
A
1281 if (!ke->kext->isKernelComponent()) {
1282 return ke;
6d2010ae
A
1283 } else {
1284 found = ke;
1285 }
1286 }
1287 ke = RB_RIGHT(ke, addressLink);
1288 }
1289 }
1290 }
1291
1292 if (!found) {
1293 IORWLockUnlock(lock);
1294 }
0a7de745 1295
6d2010ae
A
1296 return found;
1297}
0a7de745
A
1298
1299void
1300IOStatistics::releaseKextNode(KextNode *node)
1301{
6d2010ae
A
1302#pragma unused(node)
1303 IORWLockUnlock(lock);
1304}
1305
1306/* IOLib allocations */
0a7de745
A
1307void
1308IOStatistics::countAlloc(uint32_t index, vm_size_t size)
1309{
6d2010ae 1310 KextNode *ke;
0a7de745 1311
6d2010ae
A
1312 if (!enabled) {
1313 return;
1314 }
f427ee49
A
1315 if (size > INT_MAX) {
1316 return;
1317 }
6d2010ae
A
1318
1319 ke = getKextNodeFromBacktrace(FALSE);
1320 if (ke) {
f427ee49 1321 OSAddAtomic((SInt32) size, &ke->memoryCounters[index]);
6d2010ae
A
1322 releaseKextNode(ke);
1323 }
1324}
1325
1326#endif /* IOKITSTATS */