1/* 2 * Copyright (c) 2000-2006 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 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. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 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. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */ 29 30#include <string.h> 31 32#include <libkern/OSReturn.h> 33 34#include <libkern/c++/OSMetaClass.h> 35#include <libkern/c++/OSObject.h> 36#include <libkern/c++/OSKext.h> 37 38#include <libkern/c++/OSCollectionIterator.h> 39#include <libkern/c++/OSDictionary.h> 40#include <libkern/c++/OSArray.h> 41#include <libkern/c++/OSSet.h> 42#include <libkern/c++/OSSymbol.h> 43#include <libkern/c++/OSNumber.h> 44#include <libkern/c++/OSSerialize.h> 45 46#include <libkern/c++/OSLib.h> 47#include <libkern/OSAtomic.h> 48 49#include <IOKit/IOLib.h> 50 51__BEGIN_DECLS 52 53#include <sys/systm.h> 54#include <mach/mach_types.h> 55#include <kern/locks.h> 56#include <kern/clock.h> 57#include <kern/thread_call.h> 58#include <kern/host.h> 59#include <mach/mach_interface.h> 60 61#if PRAGMA_MARK 62#pragma mark Macros 63#endif /* PRAGMA_MARK */ 64/********************************************************************* 65* Macros 66*********************************************************************/ 67#if OSALLOCDEBUG 68extern int debug_container_malloc_size; 69#define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while (0) 70#else 71#define ACCUMSIZE(s) 72#endif /* OSALLOCDEBUG */ 73 74__END_DECLS 75 76#if PRAGMA_MARK 77#pragma mark Internal constants & data structs 78#endif /* PRAGMA_MARK */ 79/********************************************************************* 80* Internal constants & data structs 81*********************************************************************/ 82OSKextLogSpec kOSMetaClassLogSpec = 83 kOSKextLogErrorLevel | 84 kOSKextLogLoadFlag | 85 kOSKextLogKextBookkeepingFlag; 86 87static enum { 88 kCompletedBootstrap = 0, 89 kNoDictionaries = 1, 90 kMakingDictionaries = 2 91} sBootstrapState = kNoDictionaries; 92 93static const int kClassCapacityIncrement = 40; 94static const int kKModCapacityIncrement = 10; 95static OSDictionary * sAllClassesDict; 96static unsigned int sDeepestClass; 97IOLock * sAllClassesLock = NULL; 98IOLock * sInstancesLock = NULL; 99 100/* 101 * While loading a kext and running all its constructors to register 102 * all OSMetaClass classes, the classes are queued up here. Only one 103 * kext can be in flight at a time, guarded by sStalledClassesLock 104 */ 105static struct StalledData { 106 const char * kextIdentifier; 107 OSReturn result; 108 unsigned int capacity; 109 unsigned int count; 110 OSMetaClass ** classes; 111} * sStalled; 112IOLock * sStalledClassesLock = NULL; 113 114 115struct ExpansionData { 116 OSOrderedSet * instances; 117 OSKext * kext; 118}; 119 120 121#if PRAGMA_MARK 122#pragma mark OSMetaClassBase 123#endif /* PRAGMA_MARK */ 124/********************************************************************* 125* OSMetaClassBase. 126*********************************************************************/ 127 128#if APPLE_KEXT_VTABLE_PADDING 129/********************************************************************* 130* Reserved vtable functions. 131*********************************************************************/ 132#if SLOT_USED 133void OSMetaClassBase::_RESERVEDOSMetaClassBase0() 134 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0); } 135void OSMetaClassBase::_RESERVEDOSMetaClassBase1() 136 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1); } 137void OSMetaClassBase::_RESERVEDOSMetaClassBase2() 138 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 2); } 139#endif /* SLOT_USED */ 140 141// As these slots are used move them up inside the #if above 142void OSMetaClassBase::_RESERVEDOSMetaClassBase3() 143 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3); } 144void OSMetaClassBase::_RESERVEDOSMetaClassBase4() 145 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4); } 146void OSMetaClassBase::_RESERVEDOSMetaClassBase5() 147 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); } 148void OSMetaClassBase::_RESERVEDOSMetaClassBase6() 149 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 6); } 150#endif 151 152/********************************************************************* 153* These used to be inline in the header but gcc didn't believe us 154* Now we MUST pull the inline out at least until the compiler is 155* repaired. 156* 157* Helper inlines for runtime type preprocessor macros 158*********************************************************************/ 159 160/********************************************************************* 161*********************************************************************/ 162OSMetaClassBase * 163OSMetaClassBase::safeMetaCast( 164 const OSMetaClassBase * me, 165 const OSMetaClass * toType) 166{ 167 return (me)? me->metaCast(toType) : 0; 168} 169 170/********************************************************************* 171*********************************************************************/ 172bool 173OSMetaClassBase::checkTypeInst( 174 const OSMetaClassBase * inst, 175 const OSMetaClassBase * typeinst) 176{ 177 const OSMetaClass * toType = OSTypeIDInst(typeinst); 178 return typeinst && inst && (0 != inst->metaCast(toType)); 179} 180 181/********************************************************************* 182*********************************************************************/ 183void OSMetaClassBase:: 184initialize() 185{ 186 sAllClassesLock = IOLockAlloc(); 187 sStalledClassesLock = IOLockAlloc(); 188 sInstancesLock = IOLockAlloc(); 189} 190 191#if APPLE_KEXT_VTABLE_PADDING 192/********************************************************************* 193* If you need this slot you had better setup an IOCTL style interface. 194* 'Cause the whole kernel world depends on OSMetaClassBase and YOU 195* CANT change the VTABLE size ever. 196*********************************************************************/ 197void 198OSMetaClassBase::_RESERVEDOSMetaClassBase7() 199{ panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); } 200#endif 201 202/********************************************************************* 203*********************************************************************/ 204OSMetaClassBase::OSMetaClassBase() 205{ 206} 207 208/********************************************************************* 209*********************************************************************/ 210OSMetaClassBase::~OSMetaClassBase() 211{ 212 void ** thisVTable; 213 214 thisVTable = (void **) this; 215 *thisVTable = (void *) -1UL; 216} 217 218/********************************************************************* 219*********************************************************************/ 220bool 221OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const 222{ 223 return this == anObj; 224} 225 226/********************************************************************* 227*********************************************************************/ 228OSMetaClassBase * 229OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const 230{ 231 return toMeta->checkMetaCast(this); 232} 233 234/********************************************************************* 235*********************************************************************/ 236OSMetaClassBase * 237OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const 238{ 239 return OSMetaClass::checkMetaCastWithName(toMetaSymb, this); 240} 241 242/********************************************************************* 243*********************************************************************/ 244OSMetaClassBase * 245OSMetaClassBase::metaCast(const OSString * toMetaStr) const 246{ 247 const OSSymbol * tempSymb = OSSymbol::withString(toMetaStr); 248 OSMetaClassBase * ret = 0; 249 if (tempSymb) { 250 ret = metaCast(tempSymb); 251 tempSymb->release(); 252 } 253 return ret; 254} 255 256/********************************************************************* 257*********************************************************************/ 258OSMetaClassBase * 259OSMetaClassBase::metaCast(const char * toMetaCStr) const 260{ 261 const OSSymbol * tempSymb = OSSymbol::withCString(toMetaCStr); 262 OSMetaClassBase * ret = 0; 263 if (tempSymb) { 264 ret = metaCast(tempSymb); 265 tempSymb->release(); 266 } 267 return ret; 268} 269 270#if PRAGMA_MARK 271#pragma mark OSMetaClassMeta 272#endif /* PRAGMA_MARK */ 273/********************************************************************* 274* OSMetaClassMeta - the bootstrap metaclass of OSMetaClass 275*********************************************************************/ 276class OSMetaClassMeta : public OSMetaClass 277{ 278public: 279 OSMetaClassMeta(); 280 OSObject * alloc() const; 281}; 282OSMetaClassMeta::OSMetaClassMeta() 283 : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass)) 284 { } 285OSObject * OSMetaClassMeta::alloc() const { return 0; } 286 287static OSMetaClassMeta sOSMetaClassMeta; 288 289const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta; 290const OSMetaClass * OSMetaClass::getMetaClass() const 291 { return &sOSMetaClassMeta; } 292 293#if PRAGMA_MARK 294#pragma mark OSMetaClass 295#endif /* PRAGMA_MARK */ 296/********************************************************************* 297* OSMetaClass 298*********************************************************************/ 299 300#if APPLE_KEXT_VTABLE_PADDING 301/********************************************************************* 302* Reserved functions. 303*********************************************************************/ 304void OSMetaClass::_RESERVEDOSMetaClass0() 305 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0); } 306void OSMetaClass::_RESERVEDOSMetaClass1() 307 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1); } 308void OSMetaClass::_RESERVEDOSMetaClass2() 309 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2); } 310void OSMetaClass::_RESERVEDOSMetaClass3() 311 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3); } 312void OSMetaClass::_RESERVEDOSMetaClass4() 313 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4); } 314void OSMetaClass::_RESERVEDOSMetaClass5() 315 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5); } 316void OSMetaClass::_RESERVEDOSMetaClass6() 317 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); } 318void OSMetaClass::_RESERVEDOSMetaClass7() 319 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); } 320#endif 321 322/********************************************************************* 323*********************************************************************/ 324static void 325OSMetaClassLogErrorForKext( 326 OSReturn error, 327 OSKext * aKext) 328{ 329 const char * message = NULL; 330 331 switch (error) { 332 case kOSReturnSuccess: 333 return; 334 case kOSMetaClassNoInit: // xxx - never returned; logged at fail site 335 message = "OSMetaClass: preModLoad() wasn't called (runtime internal error)."; 336 break; 337 case kOSMetaClassNoDicts: 338 message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries."; 339 break; 340 case kOSMetaClassNoKModSet: 341 message = "OSMetaClass: Allocation failure for internal kext recording set/set missing."; 342 break; 343 case kOSMetaClassNoInsKModSet: 344 message = "OSMetaClass: Failed to record class in kext."; 345 break; 346 case kOSMetaClassDuplicateClass: 347 message = "OSMetaClass: Duplicate class encountered."; 348 break; 349 case kOSMetaClassNoSuper: // xxx - never returned 350 message = "OSMetaClass: Can't associate a class with its superclass."; 351 break; 352 case kOSMetaClassInstNoSuper: // xxx - never returned 353 message = "OSMetaClass: Instance construction error; unknown superclass."; 354 break; 355 case kOSMetaClassNoKext: 356 message = "OSMetaClass: Kext not found for metaclass."; 357 break; 358 case kOSMetaClassInternal: 359 default: 360 message = "OSMetaClass: Runtime internal error."; 361 break; 362 } 363 364 if (message) { 365 OSKextLog(aKext, kOSMetaClassLogSpec, "%s", message); 366 } 367 return; 368} 369 370void 371OSMetaClass::logError(OSReturn error) 372{ 373 OSMetaClassLogErrorForKext(error, NULL); 374} 375 376/********************************************************************* 377* The core constructor for a MetaClass (defined with this name always 378* but within the scope of its represented class). 379* 380* MetaClass constructors are invoked in OSRuntimeInitializeCPP(), 381* in between calls to OSMetaClass::preModLoad(), which sets up for 382* registration, and OSMetaClass::postModLoad(), which actually 383* records all the class/kext relationships of the new MetaClasses. 384*********************************************************************/ 385OSMetaClass::OSMetaClass( 386 const char * inClassName, 387 const OSMetaClass * inSuperClass, 388 unsigned int inClassSize) 389{ 390 instanceCount = 0; 391 classSize = inClassSize; 392 superClassLink = inSuperClass; 393 394 reserved = IONew(ExpansionData, 1); 395 bzero(reserved, sizeof(ExpansionData)); 396 397 /* Hack alert: We are just casting inClassName and storing it in 398 * an OSString * instance variable. This may be because you can't 399 * create C++ objects in static constructors, but I really don't know! 400 */ 401 className = (const OSSymbol *)inClassName; 402 403 // sStalledClassesLock taken in preModLoad 404 if (!sStalled) { 405 /* There's no way we can look up the kext here, unfortunately. 406 */ 407 OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec, 408 "OSMetaClass: preModLoad() wasn't called for class %s " 409 "(runtime internal error).", 410 inClassName); 411 } else if (!sStalled->result) { 412 // Grow stalled array if neccessary 413 if (sStalled->count >= sStalled->capacity) { 414 OSMetaClass **oldStalled = sStalled->classes; 415 int oldSize = sStalled->capacity * sizeof(OSMetaClass *); 416 int newSize = oldSize 417 + kKModCapacityIncrement * sizeof(OSMetaClass *); 418 419 sStalled->classes = (OSMetaClass **)kalloc(newSize); 420 if (!sStalled->classes) { 421 sStalled->classes = oldStalled; 422 sStalled->result = kOSMetaClassNoTempData; 423 return; 424 } 425 426 sStalled->capacity += kKModCapacityIncrement; 427 memmove(sStalled->classes, oldStalled, oldSize); 428 kfree(oldStalled, oldSize); 429 ACCUMSIZE(newSize - oldSize); 430 } 431 432 sStalled->classes[sStalled->count++] = this; 433 } 434} 435 436/********************************************************************* 437*********************************************************************/ 438OSMetaClass::~OSMetaClass() 439{ 440 OSKext * myKext = reserved ? reserved->kext : 0; // do not release 441 442 /* Hack alert: 'className' is a C string during early C++ init, and 443 * is converted to a real OSSymbol only when we record the OSKext in 444 * OSMetaClass::postModLoad(). So only do this bit if we have an OSKext. 445 * We can't safely cast or check 'className'. 446 * 447 * Also, release className *after* calling into the kext, 448 * as removeClass() may access className. 449 */ 450 IOLockLock(sAllClassesLock); 451 if (sAllClassesDict) { 452 if (myKext) { 453 sAllClassesDict->removeObject(className); 454 } else { 455 sAllClassesDict->removeObject((char *)className); 456 } 457 } 458 IOLockUnlock(sAllClassesLock); 459 460 if (myKext) { 461 if (myKext->removeClass(this) != kOSReturnSuccess) { 462 // xxx - what can we do? 463 } 464 className->release(); 465 } 466 467 // sStalledClassesLock taken in preModLoad 468 if (sStalled) { 469 unsigned int i; 470 471 /* First pass find class in stalled list. If we find it that means 472 * we started C++ init with constructors but now we're tearing down 473 * because of some failure. 474 */ 475 for (i = 0; i < sStalled->count; i++) { 476 if (this == sStalled->classes[i]) { 477 break; 478 } 479 } 480 481 /* Remove this metaclass from the stalled list so postModLoad() doesn't 482 * try to register it. 483 */ 484 if (i < sStalled->count) { 485 sStalled->count--; 486 if (i < sStalled->count) { 487 memmove(&sStalled->classes[i], &sStalled->classes[i+1], 488 (sStalled->count - i) * sizeof(OSMetaClass *)); 489 } 490 } 491 } 492} 493 494/********************************************************************* 495* Empty overrides. 496*********************************************************************/ 497void * OSMetaClass::operator new(__unused size_t size) { return 0; } 498void OSMetaClass::retain() const { } 499void OSMetaClass::release() const { } 500void OSMetaClass::release(__unused int when) const { } 501void OSMetaClass::taggedRetain(__unused const void * tag) const { } 502void OSMetaClass::taggedRelease(__unused const void * tag) const { } 503void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { } 504int OSMetaClass::getRetainCount() const { return 0; } 505 506/********************************************************************* 507*********************************************************************/ 508const char * 509OSMetaClass::getClassName() const 510{ 511 if (!className) return NULL; 512 return className->getCStringNoCopy(); 513} 514/********************************************************************* 515*********************************************************************/ 516const OSSymbol * 517OSMetaClass::getClassNameSymbol() const 518{ 519 return className; 520} 521/********************************************************************* 522*********************************************************************/ 523unsigned int 524OSMetaClass::getClassSize() const 525{ 526 return classSize; 527} 528 529/********************************************************************* 530*********************************************************************/ 531void * 532OSMetaClass::preModLoad(const char * kextIdentifier) 533{ 534 IOLockLock(sStalledClassesLock); 535 536 assert (sStalled == NULL); 537 sStalled = (StalledData *)kalloc(sizeof(* sStalled)); 538 if (sStalled) { 539 sStalled->classes = (OSMetaClass **) 540 kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *)); 541 if (!sStalled->classes) { 542 kfree(sStalled, sizeof(*sStalled)); 543 return 0; 544 } 545 ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + 546 sizeof(*sStalled)); 547 548 sStalled->result = kOSReturnSuccess; 549 sStalled->capacity = kKModCapacityIncrement; 550 sStalled->count = 0; 551 sStalled->kextIdentifier = kextIdentifier; 552 bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *)); 553 } 554 555 // keep sStalledClassesLock locked until postModLoad 556 557 return sStalled; 558} 559 560/********************************************************************* 561*********************************************************************/ 562bool 563OSMetaClass::checkModLoad(void * loadHandle) 564{ 565 return sStalled && loadHandle == sStalled && 566 sStalled->result == kOSReturnSuccess; 567} 568 569/********************************************************************* 570*********************************************************************/ 571OSReturn 572OSMetaClass::postModLoad(void * loadHandle) 573{ 574 OSReturn result = kOSReturnSuccess; 575 OSSymbol * myKextName = 0; // must release 576 OSKext * myKext = 0; // must release 577 578 if (!sStalled || loadHandle != sStalled) { 579 result = kOSMetaClassInternal; 580 goto finish; 581 } 582 583 if (sStalled->result) { 584 result = sStalled->result; 585 } else switch (sBootstrapState) { 586 587 case kNoDictionaries: 588 sBootstrapState = kMakingDictionaries; 589 // No break; fall through 590 591 case kMakingDictionaries: 592 sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement); 593 if (!sAllClassesDict) { 594 result = kOSMetaClassNoDicts; 595 break; 596 } 597 sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort); 598 599 // No break; fall through 600 601 case kCompletedBootstrap: 602 { 603 unsigned int i; 604 myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy( 605 sStalled->kextIdentifier)); 606 607 if (!sStalled->count) { 608 break; // Nothing to do so just get out 609 } 610 611 myKext = OSKext::lookupKextWithIdentifier(myKextName); 612 if (!myKext) { 613 result = kOSMetaClassNoKext; 614 615 /* Log this error here so we can include the kext name. 616 */ 617 OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec, 618 "OSMetaClass: Can't record classes for kext %s - kext not found.", 619 sStalled->kextIdentifier); 620 break; 621 } 622 623 /* First pass checking classes aren't already loaded. If any already 624 * exist, we don't register any, and so we don't technically have 625 * to do any C++ teardown. 626 * 627 * Hack alert: me->className has been a C string until now. 628 * We only release the OSSymbol if we store the kext. 629 */ 630 IOLockLock(sAllClassesLock); 631 for (i = 0; i < sStalled->count; i++) { 632 const OSMetaClass * me = sStalled->classes[i]; 633 OSMetaClass * orig = OSDynamicCast(OSMetaClass, 634 sAllClassesDict->getObject((const char *)me->className)); 635 636 if (orig) { 637 638 /* Log this error here so we can include the class name. 639 * xxx - we should look up the other kext that defines the class 640 */ 641 OSKextLog(myKext, kOSMetaClassLogSpec, 642 "OSMetaClass: Kext %s class %s is a duplicate;" 643 "kext %s already has a class by that name.", 644 sStalled->kextIdentifier, (const char *)me->className, 645 ((OSKext *)orig->reserved->kext)->getIdentifierCString()); 646 result = kOSMetaClassDuplicateClass; 647 break; 648 } 649 unsigned int depth = 1; 650 while ((me = me->superClassLink)) depth++; 651 if (depth > sDeepestClass) sDeepestClass = depth; 652 } 653 IOLockUnlock(sAllClassesLock); 654 655 /* Bail if we didn't go through the entire list of new classes 656 * (if we hit a duplicate). 657 */ 658 if (i != sStalled->count) { 659 break; 660 } 661 662 // Second pass symbolling strings and inserting classes in dictionary 663 IOLockLock(sAllClassesLock); 664 for (i = 0; i < sStalled->count; i++) { 665 OSMetaClass * me = sStalled->classes[i]; 666 667 /* Hack alert: me->className has been a C string until now. 668 * We only release the OSSymbol in ~OSMetaClass() 669 * if we set the reference to the kext. 670 */ 671 me->className = 672 OSSymbol::withCStringNoCopy((const char *)me->className); 673 674 // xxx - I suppose if these fail we're going to panic soon.... 675 sAllClassesDict->setObject(me->className, me); 676 677 /* Do not retain the kext object here. 678 */ 679 me->reserved->kext = myKext; 680 if (myKext) { 681 result = myKext->addClass(me, sStalled->count); 682 if (result != kOSReturnSuccess) { 683 /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */ 684 break; 685 } 686 } 687 } 688 IOLockUnlock(sAllClassesLock); 689 sBootstrapState = kCompletedBootstrap; 690 break; 691 } 692 693 default: 694 result = kOSMetaClassInternal; 695 break; 696 } 697 698finish: 699 /* Don't call logError() for success or the conditions logged above 700 * or by called function. 701 */ 702 if (result != kOSReturnSuccess && 703 result != kOSMetaClassNoInsKModSet && 704 result != kOSMetaClassDuplicateClass && 705 result != kOSMetaClassNoKext) { 706 707 OSMetaClassLogErrorForKext(result, myKext); 708 } 709 710 OSSafeRelease(myKextName); 711 OSSafeRelease(myKext); 712 713 if (sStalled) { 714 ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) + 715 sizeof(*sStalled))); 716 kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *)); 717 kfree(sStalled, sizeof(*sStalled)); 718 sStalled = 0; 719 } 720 721 IOLockUnlock(sStalledClassesLock); 722 723 return result; 724} 725 726 727/********************************************************************* 728*********************************************************************/ 729void 730OSMetaClass::instanceConstructed() const 731{ 732 // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink) 733 if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) { 734 superClassLink->instanceConstructed(); 735 } 736} 737 738/********************************************************************* 739*********************************************************************/ 740void 741OSMetaClass::instanceDestructed() const 742{ 743 if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) { 744 superClassLink->instanceDestructed(); 745 } 746 747 if (((int)instanceCount) < 0) { 748 OSKext * myKext = reserved->kext; 749 750 OSKextLog(myKext, kOSMetaClassLogSpec, 751 // xxx - this phrasing is rather cryptic 752 "OSMetaClass: Class %s - bad retain (%d)", 753 getClassName(), instanceCount); 754 } 755} 756 757/********************************************************************* 758*********************************************************************/ 759bool 760OSMetaClass::modHasInstance(const char * kextIdentifier) 761{ 762 bool result = false; 763 OSKext * theKext = NULL; // must release 764 765 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier); 766 if (!theKext) { 767 goto finish; 768 } 769 770 result = theKext->hasOSMetaClassInstances(); 771 772finish: 773 OSSafeRelease(theKext); 774 return result; 775} 776 777/********************************************************************* 778*********************************************************************/ 779void 780OSMetaClass::reportModInstances(const char * kextIdentifier) 781{ 782 OSKext::reportOSMetaClassInstances(kextIdentifier, 783 kOSKextLogExplicitLevel); 784 return; 785} 786/********************************************************************* 787*********************************************************************/ 788 789void 790OSMetaClass::addInstance(const OSObject * instance, bool super) const 791{ 792 if (!super) IOLockLock(sInstancesLock); 793 794 if (!reserved->instances) { 795 reserved->instances = OSOrderedSet::withCapacity(16); 796 if (superClassLink) { 797 superClassLink->addInstance(reserved->instances, true); 798 } 799 } 800 reserved->instances->setLastObject(instance); 801 802 if (!super) IOLockUnlock(sInstancesLock); 803} 804 805void 806OSMetaClass::removeInstance(const OSObject * instance, bool super) const 807{ 808 if (!super) IOLockLock(sInstancesLock); 809 810 if (reserved->instances) { 811 reserved->instances->removeObject(instance); 812 if (0 == reserved->instances->getCount()) { 813 if (superClassLink) { 814 superClassLink->removeInstance(reserved->instances, true); 815 } 816 reserved->instances->release(); 817 reserved->instances = 0; 818 } 819 } 820 821 if (!super) IOLockUnlock(sInstancesLock); 822} 823 824void 825OSMetaClass::applyToInstances(OSOrderedSet * set, 826 OSMetaClassInstanceApplierFunction applier, 827 void * context) 828{ 829 enum { kLocalDepth = 24 }; 830 unsigned int _nextIndex[kLocalDepth]; 831 OSOrderedSet * _sets[kLocalDepth]; 832 unsigned int * nextIndex = &_nextIndex[0]; 833 OSOrderedSet ** sets = &_sets[0]; 834 OSObject * obj; 835 OSOrderedSet * childSet; 836 unsigned int maxDepth; 837 unsigned int idx; 838 unsigned int level; 839 bool done; 840 841 maxDepth = sDeepestClass; 842 if (maxDepth > kLocalDepth) 843 { 844 nextIndex = IONew(typeof(nextIndex[0]), maxDepth); 845 sets = IONew(typeof(sets[0]), maxDepth); 846 } 847 done = false; 848 level = 0; 849 idx = 0; 850 do 851 { 852 while (!done && (obj = set->getObject(idx++))) 853 { 854 if ((childSet = OSDynamicCast(OSOrderedSet, obj))) 855 { 856 if (level >= maxDepth) panic(">maxDepth"); 857 sets[level] = set; 858 nextIndex[level] = idx; 859 level++; 860 set = childSet; 861 idx = 0; 862 break; 863 } 864 done = (*applier)(obj, context); 865 } 866 if (!obj) 867 { 868 if (!done && level) 869 { 870 level--; 871 set = sets[level]; 872 idx = nextIndex[level]; 873 } else done = true; 874 } 875 } 876 while (!done); 877 if (maxDepth > kLocalDepth) 878 { 879 IODelete(nextIndex, typeof(nextIndex[0]), maxDepth); 880 IODelete(sets, typeof(sets[0]), maxDepth); 881 } 882} 883 884void 885OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier, 886 void * context) const 887{ 888 IOLockLock(sInstancesLock); 889 if (reserved->instances) applyToInstances(reserved->instances, applier, context); 890 IOLockUnlock(sInstancesLock); 891} 892 893void 894OSMetaClass::applyToInstancesOfClassName( 895 const OSSymbol * name, 896 OSMetaClassInstanceApplierFunction applier, 897 void * context) 898{ 899 OSMetaClass * meta; 900 OSOrderedSet * set = 0; 901 902 IOLockLock(sAllClassesLock); 903 if (sAllClassesDict 904 && (meta = (OSMetaClass *) sAllClassesDict->getObject(name)) 905 && (set = meta->reserved->instances)) 906 { 907 set->retain(); 908 } 909 IOLockUnlock(sAllClassesLock); 910 911 if (!set) return; 912 913 IOLockLock(sInstancesLock); 914 applyToInstances(set, applier, context); 915 IOLockUnlock(sInstancesLock); 916 set->release(); 917} 918 919/********************************************************************* 920*********************************************************************/ 921void 922OSMetaClass::considerUnloads() 923{ 924 OSKext::considerUnloads(); 925} 926 927/********************************************************************* 928*********************************************************************/ 929const OSMetaClass * 930OSMetaClass::getMetaClassWithName(const OSSymbol * name) 931{ 932 OSMetaClass * retMeta = 0; 933 934 if (!name) { 935 return 0; 936 } 937 938 IOLockLock(sAllClassesLock); 939 if (sAllClassesDict) { 940 retMeta = (OSMetaClass *) sAllClassesDict->getObject(name); 941 } 942 IOLockUnlock(sAllClassesLock); 943 944 return retMeta; 945} 946 947/********************************************************************* 948*********************************************************************/ 949OSObject * 950OSMetaClass::allocClassWithName(const OSSymbol * name) 951{ 952 OSObject * result = 0; 953 954 const OSMetaClass * const meta = getMetaClassWithName(name); 955 956 if (meta) { 957 result = meta->alloc(); 958 } 959 960 return result; 961} 962 963/********************************************************************* 964*********************************************************************/ 965OSObject * 966OSMetaClass::allocClassWithName(const OSString * name) 967{ 968 const OSSymbol * tmpKey = OSSymbol::withString(name); 969 OSObject * result = allocClassWithName(tmpKey); 970 tmpKey->release(); 971 return result; 972} 973 974/********************************************************************* 975*********************************************************************/ 976OSObject * 977OSMetaClass::allocClassWithName(const char * name) 978{ 979 const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name); 980 OSObject * result = allocClassWithName(tmpKey); 981 tmpKey->release(); 982 return result; 983} 984 985 986/********************************************************************* 987*********************************************************************/ 988OSMetaClassBase * 989OSMetaClass::checkMetaCastWithName( 990 const OSSymbol * name, 991 const OSMetaClassBase * in) 992{ 993 OSMetaClassBase * result = 0; 994 995 const OSMetaClass * const meta = getMetaClassWithName(name); 996 997 if (meta) { 998 result = meta->checkMetaCast(in); 999 } 1000 1001 return result; 1002} 1003 1004/********************************************************************* 1005*********************************************************************/ 1006OSMetaClassBase * OSMetaClass:: 1007checkMetaCastWithName( 1008 const OSString * name, 1009 const OSMetaClassBase * in) 1010{ 1011 const OSSymbol * tmpKey = OSSymbol::withString(name); 1012 OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in); 1013 1014 tmpKey->release(); 1015 return result; 1016} 1017 1018/********************************************************************* 1019*********************************************************************/ 1020OSMetaClassBase * 1021OSMetaClass::checkMetaCastWithName( 1022 const char * name, 1023 const OSMetaClassBase * in) 1024{ 1025 const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name); 1026 OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in); 1027 1028 tmpKey->release(); 1029 return result; 1030} 1031 1032/********************************************************************* 1033 * OSMetaClass::checkMetaCast() 1034 * Check to see if the 'check' object has this object in its metaclass chain. 1035 * Returns check if it is indeed a kind of the current meta class, 0 otherwise. 1036 * 1037 * Generally this method is not invoked directly but is used to implement 1038 * the OSMetaClassBase::metaCast member function. 1039 * 1040 * See also OSMetaClassBase::metaCast 1041*********************************************************************/ 1042OSMetaClassBase * OSMetaClass::checkMetaCast( 1043 const OSMetaClassBase * check) const 1044{ 1045 const OSMetaClass * const toMeta = this; 1046 const OSMetaClass * fromMeta; 1047 1048 for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) { 1049 if (toMeta == fromMeta) { 1050 return const_cast<OSMetaClassBase *>(check); // Discard const 1051 } 1052 if (!fromMeta->superClassLink) { 1053 break; 1054 } 1055 } 1056 1057 return 0; 1058} 1059 1060/********************************************************************* 1061*********************************************************************/ 1062void 1063OSMetaClass::reservedCalled(int ind) const 1064{ 1065 const char * cname = className->getCStringNoCopy(); 1066 panic("%s::_RESERVED%s%d called.", cname, cname, ind); 1067} 1068 1069/********************************************************************* 1070*********************************************************************/ 1071const 1072OSMetaClass * 1073OSMetaClass::getSuperClass() const 1074{ 1075 return superClassLink; 1076} 1077 1078/********************************************************************* 1079* xxx - I want to rename this :-/ 1080*********************************************************************/ 1081const OSSymbol * 1082OSMetaClass::getKmodName() const 1083{ 1084 OSKext * myKext = reserved ? reserved->kext : 0; 1085 if (myKext) { 1086 return myKext->getIdentifier(); 1087 } 1088 return OSSymbol::withCStringNoCopy("unknown"); 1089} 1090 1091/********************************************************************* 1092*********************************************************************/ 1093unsigned int 1094OSMetaClass::getInstanceCount() const 1095{ 1096 return instanceCount; 1097} 1098 1099/********************************************************************* 1100*********************************************************************/ 1101/* static */ 1102void 1103OSMetaClass::printInstanceCounts() 1104{ 1105 OSCollectionIterator * classes; 1106 OSSymbol * className; 1107 OSMetaClass * meta; 1108 1109 IOLockLock(sAllClassesLock); 1110 classes = OSCollectionIterator::withCollection(sAllClassesDict); 1111 assert(classes); 1112 1113 while( (className = (OSSymbol *)classes->getNextObject())) { 1114 meta = (OSMetaClass *)sAllClassesDict->getObject(className); 1115 assert(meta); 1116 1117 printf("%24s count: %03d x 0x%03x = 0x%06x\n", 1118 className->getCStringNoCopy(), 1119 meta->getInstanceCount(), 1120 meta->getClassSize(), 1121 meta->getInstanceCount() * meta->getClassSize() ); 1122 } 1123 printf("\n"); 1124 classes->release(); 1125 IOLockUnlock(sAllClassesLock); 1126 return; 1127} 1128 1129/********************************************************************* 1130*********************************************************************/ 1131OSDictionary * 1132OSMetaClass::getClassDictionary() 1133{ 1134 panic("OSMetaClass::getClassDictionary() is obsoleted.\n"); 1135 return 0; 1136} 1137 1138/********************************************************************* 1139*********************************************************************/ 1140bool 1141OSMetaClass::serialize(__unused OSSerialize * s) const 1142{ 1143 panic("OSMetaClass::serialize(): Obsoleted\n"); 1144 return false; 1145} 1146 1147/********************************************************************* 1148*********************************************************************/ 1149/* static */ 1150void 1151OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary) 1152{ 1153 OSDictionary * classDict = NULL; 1154 1155 IOLockLock(sAllClassesLock); 1156 1157 classDict = OSDictionary::withCapacity(sAllClassesDict->getCount()); 1158 if (!classDict) { 1159 goto finish; 1160 } 1161 1162 do { 1163 OSCollectionIterator * classes; 1164 const OSSymbol * className; 1165 1166 classes = OSCollectionIterator::withCollection(sAllClassesDict); 1167 if (!classes) { 1168 break; 1169 } 1170 1171 while ((className = (const OSSymbol *)classes->getNextObject())) { 1172 const OSMetaClass * meta; 1173 OSNumber * count; 1174 1175 meta = (OSMetaClass *)sAllClassesDict->getObject(className); 1176 count = OSNumber::withNumber(meta->getInstanceCount(), 32); 1177 if (count) { 1178 classDict->setObject(className, count); 1179 count->release(); 1180 } 1181 } 1182 classes->release(); 1183 1184 serializeDictionary->setObject("Classes", classDict); 1185 } while (0); 1186 1187finish: 1188 OSSafeRelease(classDict); 1189 1190 IOLockUnlock(sAllClassesLock); 1191 1192 return; 1193} 1194