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 68 extern 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 *********************************************************************/ 82 OSKextLogSpec kOSMetaClassLogSpec = 83 kOSKextLogErrorLevel | 84 kOSKextLogLoadFlag | 85 kOSKextLogKextBookkeepingFlag; 86 87 static enum { 88 kCompletedBootstrap = 0, 89 kNoDictionaries = 1, 90 kMakingDictionaries = 2 91 } sBootstrapState = kNoDictionaries; 92 93 static const int kClassCapacityIncrement = 40; 94 static const int kKModCapacityIncrement = 10; 95 static OSDictionary * sAllClassesDict; 96 static unsigned int sDeepestClass; 97 IOLock * sAllClassesLock = NULL; 98 IOLock * 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 */ 105 static struct StalledData { 106 const char * kextIdentifier; 107 OSReturn result; 108 unsigned int capacity; 109 unsigned int count; 110 OSMetaClass ** classes; 111 } * sStalled; 112 IOLock * sStalledClassesLock = NULL; 113 114 115 struct 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 133 void OSMetaClassBase::_RESERVEDOSMetaClassBase0() 134 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0); } 135 void OSMetaClassBase::_RESERVEDOSMetaClassBase1() 136 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1); } 137 void 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 142 void OSMetaClassBase::_RESERVEDOSMetaClassBase3() 143 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3); } 144 void OSMetaClassBase::_RESERVEDOSMetaClassBase4() 145 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4); } 146 void OSMetaClassBase::_RESERVEDOSMetaClassBase5() 147 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); } 148 void 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 *********************************************************************/ 162 OSMetaClassBase * 163 OSMetaClassBase::safeMetaCast( 164 const OSMetaClassBase * me, 165 const OSMetaClass * toType) 166 { 167 return (me)? me->metaCast(toType) : 0; 168 } 169 170 /********************************************************************* 171 *********************************************************************/ 172 bool 173 OSMetaClassBase::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 *********************************************************************/ 183 void OSMetaClassBase:: 184 initialize() 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 *********************************************************************/ 197 void 198 OSMetaClassBase::_RESERVEDOSMetaClassBase7() 199 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); } 200 #endif 201 202 /********************************************************************* 203 *********************************************************************/ 204 OSMetaClassBase::OSMetaClassBase() 205 { 206 } 207 208 /********************************************************************* 209 *********************************************************************/ 210 OSMetaClassBase::~OSMetaClassBase() 211 { 212 void ** thisVTable; 213 214 thisVTable = (void **) this; 215 *thisVTable = (void *) -1UL; 216 } 217 218 /********************************************************************* 219 *********************************************************************/ 220 bool 221 OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const 222 { 223 return this == anObj; 224 } 225 226 /********************************************************************* 227 *********************************************************************/ 228 OSMetaClassBase * 229 OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const 230 { 231 return toMeta->checkMetaCast(this); 232 } 233 234 /********************************************************************* 235 *********************************************************************/ 236 OSMetaClassBase * 237 OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const 238 { 239 return OSMetaClass::checkMetaCastWithName(toMetaSymb, this); 240 } 241 242 /********************************************************************* 243 *********************************************************************/ 244 OSMetaClassBase * 245 OSMetaClassBase::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 *********************************************************************/ 258 OSMetaClassBase * 259 OSMetaClassBase::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 *********************************************************************/ 276 class OSMetaClassMeta : public OSMetaClass 277 { 278 public: 279 OSMetaClassMeta(); 280 OSObject * alloc() const; 281 }; 282 OSMetaClassMeta::OSMetaClassMeta() 283 : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass)) 284 { } 285 OSObject * OSMetaClassMeta::alloc() const { return 0; } 286 287 static OSMetaClassMeta sOSMetaClassMeta; 288 289 const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta; 290 const 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 *********************************************************************/ 304 void OSMetaClass::_RESERVEDOSMetaClass0() 305 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0); } 306 void OSMetaClass::_RESERVEDOSMetaClass1() 307 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1); } 308 void OSMetaClass::_RESERVEDOSMetaClass2() 309 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2); } 310 void OSMetaClass::_RESERVEDOSMetaClass3() 311 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3); } 312 void OSMetaClass::_RESERVEDOSMetaClass4() 313 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4); } 314 void OSMetaClass::_RESERVEDOSMetaClass5() 315 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5); } 316 void OSMetaClass::_RESERVEDOSMetaClass6() 317 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); } 318 void OSMetaClass::_RESERVEDOSMetaClass7() 319 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); } 320 #endif 321 322 /********************************************************************* 323 *********************************************************************/ 324 static void 325 OSMetaClassLogErrorForKext( 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 370 void 371 OSMetaClass::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 *********************************************************************/ 385 OSMetaClass::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 *********************************************************************/ 438 OSMetaClass::~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 *********************************************************************/ 497 void OSMetaClass::retain() const { } 498 void OSMetaClass::release() const { } 499 void OSMetaClass::release(__unused int when) const { } 500 void OSMetaClass::taggedRetain(__unused const void * tag) const { } 501 void OSMetaClass::taggedRelease(__unused const void * tag) const { } 502 void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { } 503 int OSMetaClass::getRetainCount() const { return 0; } 504 505 /********************************************************************* 506 *********************************************************************/ 507 const char * 508 OSMetaClass::getClassName() const 509 { 510 if (!className) return NULL; 511 return className->getCStringNoCopy(); 512 } 513 /********************************************************************* 514 *********************************************************************/ 515 const OSSymbol * 516 OSMetaClass::getClassNameSymbol() const 517 { 518 return className; 519 } 520 /********************************************************************* 521 *********************************************************************/ 522 unsigned int 523 OSMetaClass::getClassSize() const 524 { 525 return classSize; 526 } 527 528 /********************************************************************* 529 *********************************************************************/ 530 void * 531 OSMetaClass::preModLoad(const char * kextIdentifier) 532 { 533 IOLockLock(sStalledClassesLock); 534 535 assert (sStalled == NULL); 536 sStalled = (StalledData *)kalloc(sizeof(* sStalled)); 537 if (sStalled) { 538 sStalled->classes = (OSMetaClass **) 539 kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *)); 540 if (!sStalled->classes) { 541 kfree(sStalled, sizeof(*sStalled)); 542 return 0; 543 } 544 ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + 545 sizeof(*sStalled)); 546 547 sStalled->result = kOSReturnSuccess; 548 sStalled->capacity = kKModCapacityIncrement; 549 sStalled->count = 0; 550 sStalled->kextIdentifier = kextIdentifier; 551 bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *)); 552 } 553 554 // keep sStalledClassesLock locked until postModLoad 555 556 return sStalled; 557 } 558 559 /********************************************************************* 560 *********************************************************************/ 561 bool 562 OSMetaClass::checkModLoad(void * loadHandle) 563 { 564 return sStalled && loadHandle == sStalled && 565 sStalled->result == kOSReturnSuccess; 566 } 567 568 /********************************************************************* 569 *********************************************************************/ 570 OSReturn 571 OSMetaClass::postModLoad(void * loadHandle) 572 { 573 OSReturn result = kOSReturnSuccess; 574 OSSymbol * myKextName = 0; // must release 575 OSKext * myKext = 0; // must release 576 577 if (!sStalled || loadHandle != sStalled) { 578 result = kOSMetaClassInternal; 579 goto finish; 580 } 581 582 if (sStalled->result) { 583 result = sStalled->result; 584 } else switch (sBootstrapState) { 585 586 case kNoDictionaries: 587 sBootstrapState = kMakingDictionaries; 588 // No break; fall through 589 590 case kMakingDictionaries: 591 sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement); 592 if (!sAllClassesDict) { 593 result = kOSMetaClassNoDicts; 594 break; 595 } 596 sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort); 597 598 // No break; fall through 599 600 case kCompletedBootstrap: 601 { 602 unsigned int i; 603 myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy( 604 sStalled->kextIdentifier)); 605 606 if (!sStalled->count) { 607 break; // Nothing to do so just get out 608 } 609 610 myKext = OSKext::lookupKextWithIdentifier(myKextName); 611 if (!myKext) { 612 result = kOSMetaClassNoKext; 613 614 /* Log this error here so we can include the kext name. 615 */ 616 OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec, 617 "OSMetaClass: Can't record classes for kext %s - kext not found.", 618 sStalled->kextIdentifier); 619 break; 620 } 621 622 /* First pass checking classes aren't already loaded. If any already 623 * exist, we don't register any, and so we don't technically have 624 * to do any C++ teardown. 625 * 626 * Hack alert: me->className has been a C string until now. 627 * We only release the OSSymbol if we store the kext. 628 */ 629 IOLockLock(sAllClassesLock); 630 for (i = 0; i < sStalled->count; i++) { 631 const OSMetaClass * me = sStalled->classes[i]; 632 OSMetaClass * orig = OSDynamicCast(OSMetaClass, 633 sAllClassesDict->getObject((const char *)me->className)); 634 635 if (orig) { 636 637 /* Log this error here so we can include the class name. 638 * xxx - we should look up the other kext that defines the class 639 */ 640 OSKextLog(myKext, kOSMetaClassLogSpec, 641 "OSMetaClass: Kext %s class %s is a duplicate;" 642 "kext %s already has a class by that name.", 643 sStalled->kextIdentifier, (const char *)me->className, 644 ((OSKext *)orig->reserved->kext)->getIdentifierCString()); 645 result = kOSMetaClassDuplicateClass; 646 break; 647 } 648 unsigned int depth = 1; 649 while ((me = me->superClassLink)) depth++; 650 if (depth > sDeepestClass) sDeepestClass = depth; 651 } 652 IOLockUnlock(sAllClassesLock); 653 654 /* Bail if we didn't go through the entire list of new classes 655 * (if we hit a duplicate). 656 */ 657 if (i != sStalled->count) { 658 break; 659 } 660 661 // Second pass symbolling strings and inserting classes in dictionary 662 IOLockLock(sAllClassesLock); 663 for (i = 0; i < sStalled->count; i++) { 664 OSMetaClass * me = sStalled->classes[i]; 665 666 /* Hack alert: me->className has been a C string until now. 667 * We only release the OSSymbol in ~OSMetaClass() 668 * if we set the reference to the kext. 669 */ 670 me->className = 671 OSSymbol::withCStringNoCopy((const char *)me->className); 672 673 // xxx - I suppose if these fail we're going to panic soon.... 674 sAllClassesDict->setObject(me->className, me); 675 676 /* Do not retain the kext object here. 677 */ 678 me->reserved->kext = myKext; 679 if (myKext) { 680 result = myKext->addClass(me, sStalled->count); 681 if (result != kOSReturnSuccess) { 682 /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */ 683 break; 684 } 685 } 686 } 687 IOLockUnlock(sAllClassesLock); 688 sBootstrapState = kCompletedBootstrap; 689 break; 690 } 691 692 default: 693 result = kOSMetaClassInternal; 694 break; 695 } 696 697 finish: 698 /* Don't call logError() for success or the conditions logged above 699 * or by called function. 700 */ 701 if (result != kOSReturnSuccess && 702 result != kOSMetaClassNoInsKModSet && 703 result != kOSMetaClassDuplicateClass && 704 result != kOSMetaClassNoKext) { 705 706 OSMetaClassLogErrorForKext(result, myKext); 707 } 708 709 OSSafeRelease(myKextName); 710 OSSafeRelease(myKext); 711 712 if (sStalled) { 713 ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) + 714 sizeof(*sStalled))); 715 kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *)); 716 kfree(sStalled, sizeof(*sStalled)); 717 sStalled = 0; 718 } 719 720 IOLockUnlock(sStalledClassesLock); 721 722 return result; 723 } 724 725 726 /********************************************************************* 727 *********************************************************************/ 728 void 729 OSMetaClass::instanceConstructed() const 730 { 731 // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink) 732 if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) { 733 superClassLink->instanceConstructed(); 734 } 735 } 736 737 /********************************************************************* 738 *********************************************************************/ 739 void 740 OSMetaClass::instanceDestructed() const 741 { 742 if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) { 743 superClassLink->instanceDestructed(); 744 } 745 746 if (((int)instanceCount) < 0) { 747 OSKext * myKext = reserved->kext; 748 749 OSKextLog(myKext, kOSMetaClassLogSpec, 750 // xxx - this phrasing is rather cryptic 751 "OSMetaClass: Class %s - bad retain (%d)", 752 getClassName(), instanceCount); 753 } 754 } 755 756 /********************************************************************* 757 *********************************************************************/ 758 bool 759 OSMetaClass::modHasInstance(const char * kextIdentifier) 760 { 761 bool result = false; 762 OSKext * theKext = NULL; // must release 763 764 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier); 765 if (!theKext) { 766 goto finish; 767 } 768 769 result = theKext->hasOSMetaClassInstances(); 770 771 finish: 772 OSSafeRelease(theKext); 773 return result; 774 } 775 776 /********************************************************************* 777 *********************************************************************/ 778 void 779 OSMetaClass::reportModInstances(const char * kextIdentifier) 780 { 781 OSKext::reportOSMetaClassInstances(kextIdentifier, 782 kOSKextLogExplicitLevel); 783 return; 784 } 785 /********************************************************************* 786 *********************************************************************/ 787 788 void 789 OSMetaClass::addInstance(const OSObject * instance, bool super) const 790 { 791 if (!super) IOLockLock(sInstancesLock); 792 793 if (!reserved->instances) { 794 reserved->instances = OSOrderedSet::withCapacity(16); 795 if (superClassLink) { 796 superClassLink->addInstance(reserved->instances, true); 797 } 798 } 799 reserved->instances->setLastObject(instance); 800 801 if (!super) IOLockUnlock(sInstancesLock); 802 } 803 804 void 805 OSMetaClass::removeInstance(const OSObject * instance, bool super) const 806 { 807 if (!super) IOLockLock(sInstancesLock); 808 809 if (reserved->instances) { 810 reserved->instances->removeObject(instance); 811 if (0 == reserved->instances->getCount()) { 812 if (superClassLink) { 813 superClassLink->removeInstance(reserved->instances, true); 814 } 815 IOLockLock(sAllClassesLock); 816 reserved->instances->release(); 817 reserved->instances = 0; 818 IOLockUnlock(sAllClassesLock); 819 } 820 } 821 822 if (!super) IOLockUnlock(sInstancesLock); 823 } 824 825 void 826 OSMetaClass::applyToInstances(OSOrderedSet * set, 827 OSMetaClassInstanceApplierFunction applier, 828 void * context) 829 { 830 enum { kLocalDepth = 24 }; 831 unsigned int _nextIndex[kLocalDepth]; 832 OSOrderedSet * _sets[kLocalDepth]; 833 unsigned int * nextIndex = &_nextIndex[0]; 834 OSOrderedSet ** sets = &_sets[0]; 835 OSObject * obj; 836 OSOrderedSet * childSet; 837 unsigned int maxDepth; 838 unsigned int idx; 839 unsigned int level; 840 bool done; 841 842 maxDepth = sDeepestClass; 843 if (maxDepth > kLocalDepth) 844 { 845 nextIndex = IONew(typeof(nextIndex[0]), maxDepth); 846 sets = IONew(typeof(sets[0]), maxDepth); 847 } 848 done = false; 849 level = 0; 850 idx = 0; 851 do 852 { 853 while (!done && (obj = set->getObject(idx++))) 854 { 855 if ((childSet = OSDynamicCast(OSOrderedSet, obj))) 856 { 857 if (level >= maxDepth) panic(">maxDepth"); 858 sets[level] = set; 859 nextIndex[level] = idx; 860 level++; 861 set = childSet; 862 idx = 0; 863 break; 864 } 865 done = (*applier)(obj, context); 866 } 867 if (!obj) 868 { 869 if (!done && level) 870 { 871 level--; 872 set = sets[level]; 873 idx = nextIndex[level]; 874 } else done = true; 875 } 876 } 877 while (!done); 878 if (maxDepth > kLocalDepth) 879 { 880 IODelete(nextIndex, typeof(nextIndex[0]), maxDepth); 881 IODelete(sets, typeof(sets[0]), maxDepth); 882 } 883 } 884 885 void 886 OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier, 887 void * context) const 888 { 889 IOLockLock(sInstancesLock); 890 if (reserved->instances) applyToInstances(reserved->instances, applier, context); 891 IOLockUnlock(sInstancesLock); 892 } 893 894 void 895 OSMetaClass::applyToInstancesOfClassName( 896 const OSSymbol * name, 897 OSMetaClassInstanceApplierFunction applier, 898 void * context) 899 { 900 OSMetaClass * meta; 901 OSOrderedSet * set = 0; 902 903 IOLockLock(sAllClassesLock); 904 if (sAllClassesDict 905 && (meta = (OSMetaClass *) sAllClassesDict->getObject(name)) 906 && (set = meta->reserved->instances)) 907 { 908 set->retain(); 909 } 910 IOLockUnlock(sAllClassesLock); 911 912 if (!set) return; 913 914 IOLockLock(sInstancesLock); 915 applyToInstances(set, applier, context); 916 IOLockUnlock(sInstancesLock); 917 set->release(); 918 } 919 920 /********************************************************************* 921 *********************************************************************/ 922 void 923 OSMetaClass::considerUnloads() 924 { 925 OSKext::considerUnloads(); 926 } 927 928 /********************************************************************* 929 *********************************************************************/ 930 const OSMetaClass * 931 OSMetaClass::getMetaClassWithName(const OSSymbol * name) 932 { 933 OSMetaClass * retMeta = 0; 934 935 if (!name) { 936 return 0; 937 } 938 939 IOLockLock(sAllClassesLock); 940 if (sAllClassesDict) { 941 retMeta = (OSMetaClass *) sAllClassesDict->getObject(name); 942 } 943 IOLockUnlock(sAllClassesLock); 944 945 return retMeta; 946 } 947 948 /********************************************************************* 949 *********************************************************************/ 950 OSObject * 951 OSMetaClass::allocClassWithName(const OSSymbol * name) 952 { 953 OSObject * result = 0; 954 955 const OSMetaClass * const meta = getMetaClassWithName(name); 956 957 if (meta) { 958 result = meta->alloc(); 959 } 960 961 return result; 962 } 963 964 /********************************************************************* 965 *********************************************************************/ 966 OSObject * 967 OSMetaClass::allocClassWithName(const OSString * name) 968 { 969 const OSSymbol * tmpKey = OSSymbol::withString(name); 970 OSObject * result = allocClassWithName(tmpKey); 971 tmpKey->release(); 972 return result; 973 } 974 975 /********************************************************************* 976 *********************************************************************/ 977 OSObject * 978 OSMetaClass::allocClassWithName(const char * name) 979 { 980 const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name); 981 OSObject * result = allocClassWithName(tmpKey); 982 tmpKey->release(); 983 return result; 984 } 985 986 987 /********************************************************************* 988 *********************************************************************/ 989 OSMetaClassBase * 990 OSMetaClass::checkMetaCastWithName( 991 const OSSymbol * name, 992 const OSMetaClassBase * in) 993 { 994 OSMetaClassBase * result = 0; 995 996 const OSMetaClass * const meta = getMetaClassWithName(name); 997 998 if (meta) { 999 result = meta->checkMetaCast(in); 1000 } 1001 1002 return result; 1003 } 1004 1005 /********************************************************************* 1006 *********************************************************************/ 1007 OSMetaClassBase * OSMetaClass:: 1008 checkMetaCastWithName( 1009 const OSString * name, 1010 const OSMetaClassBase * in) 1011 { 1012 const OSSymbol * tmpKey = OSSymbol::withString(name); 1013 OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in); 1014 1015 tmpKey->release(); 1016 return result; 1017 } 1018 1019 /********************************************************************* 1020 *********************************************************************/ 1021 OSMetaClassBase * 1022 OSMetaClass::checkMetaCastWithName( 1023 const char * name, 1024 const OSMetaClassBase * in) 1025 { 1026 const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name); 1027 OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in); 1028 1029 tmpKey->release(); 1030 return result; 1031 } 1032 1033 /********************************************************************* 1034 * OSMetaClass::checkMetaCast() 1035 * Check to see if the 'check' object has this object in its metaclass chain. 1036 * Returns check if it is indeed a kind of the current meta class, 0 otherwise. 1037 * 1038 * Generally this method is not invoked directly but is used to implement 1039 * the OSMetaClassBase::metaCast member function. 1040 * 1041 * See also OSMetaClassBase::metaCast 1042 *********************************************************************/ 1043 OSMetaClassBase * OSMetaClass::checkMetaCast( 1044 const OSMetaClassBase * check) const 1045 { 1046 const OSMetaClass * const toMeta = this; 1047 const OSMetaClass * fromMeta; 1048 1049 for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) { 1050 if (toMeta == fromMeta) { 1051 return const_cast<OSMetaClassBase *>(check); // Discard const 1052 } 1053 if (!fromMeta->superClassLink) { 1054 break; 1055 } 1056 } 1057 1058 return 0; 1059 } 1060 1061 /********************************************************************* 1062 *********************************************************************/ 1063 void 1064 OSMetaClass::reservedCalled(int ind) const 1065 { 1066 const char * cname = className->getCStringNoCopy(); 1067 panic("%s::_RESERVED%s%d called.", cname, cname, ind); 1068 } 1069 1070 /********************************************************************* 1071 *********************************************************************/ 1072 const 1073 OSMetaClass * 1074 OSMetaClass::getSuperClass() const 1075 { 1076 return superClassLink; 1077 } 1078 1079 /********************************************************************* 1080 * xxx - I want to rename this :-/ 1081 *********************************************************************/ 1082 const OSSymbol * 1083 OSMetaClass::getKmodName() const 1084 { 1085 OSKext * myKext = reserved ? reserved->kext : 0; 1086 if (myKext) { 1087 return myKext->getIdentifier(); 1088 } 1089 return OSSymbol::withCStringNoCopy("unknown"); 1090 } 1091 1092 /********************************************************************* 1093 *********************************************************************/ 1094 unsigned int 1095 OSMetaClass::getInstanceCount() const 1096 { 1097 return instanceCount; 1098 } 1099 1100 /********************************************************************* 1101 *********************************************************************/ 1102 /* static */ 1103 void 1104 OSMetaClass::printInstanceCounts() 1105 { 1106 OSCollectionIterator * classes; 1107 OSSymbol * className; 1108 OSMetaClass * meta; 1109 1110 IOLockLock(sAllClassesLock); 1111 classes = OSCollectionIterator::withCollection(sAllClassesDict); 1112 assert(classes); 1113 1114 while( (className = (OSSymbol *)classes->getNextObject())) { 1115 meta = (OSMetaClass *)sAllClassesDict->getObject(className); 1116 assert(meta); 1117 1118 printf("%24s count: %03d x 0x%03x = 0x%06x\n", 1119 className->getCStringNoCopy(), 1120 meta->getInstanceCount(), 1121 meta->getClassSize(), 1122 meta->getInstanceCount() * meta->getClassSize() ); 1123 } 1124 printf("\n"); 1125 classes->release(); 1126 IOLockUnlock(sAllClassesLock); 1127 return; 1128 } 1129 1130 /********************************************************************* 1131 *********************************************************************/ 1132 OSDictionary * 1133 OSMetaClass::getClassDictionary() 1134 { 1135 panic("OSMetaClass::getClassDictionary() is obsoleted.\n"); 1136 return 0; 1137 } 1138 1139 /********************************************************************* 1140 *********************************************************************/ 1141 bool 1142 OSMetaClass::serialize(__unused OSSerialize * s) const 1143 { 1144 panic("OSMetaClass::serialize(): Obsoleted\n"); 1145 return false; 1146 } 1147 1148 /********************************************************************* 1149 *********************************************************************/ 1150 /* static */ 1151 void 1152 OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary) 1153 { 1154 OSDictionary * classDict = NULL; 1155 1156 IOLockLock(sAllClassesLock); 1157 1158 classDict = OSDictionary::withCapacity(sAllClassesDict->getCount()); 1159 if (!classDict) { 1160 goto finish; 1161 } 1162 1163 do { 1164 OSCollectionIterator * classes; 1165 const OSSymbol * className; 1166 1167 classes = OSCollectionIterator::withCollection(sAllClassesDict); 1168 if (!classes) { 1169 break; 1170 } 1171 1172 while ((className = (const OSSymbol *)classes->getNextObject())) { 1173 const OSMetaClass * meta; 1174 OSNumber * count; 1175 1176 meta = (OSMetaClass *)sAllClassesDict->getObject(className); 1177 count = OSNumber::withNumber(meta->getInstanceCount(), 32); 1178 if (count) { 1179 classDict->setObject(className, count); 1180 count->release(); 1181 } 1182 } 1183 classes->release(); 1184 1185 serializeDictionary->setObject("Classes", classDict); 1186 } while (0); 1187 1188 finish: 1189 OSSafeRelease(classDict); 1190 1191 IOLockUnlock(sAllClassesLock); 1192 1193 return; 1194 } 1195