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