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 | #include <stddef.h> |
64 | |
65 | #if PRAGMA_MARK |
66 | #pragma mark Macros |
67 | #endif /* PRAGMA_MARK */ |
68 | /********************************************************************* |
69 | * Macros |
70 | *********************************************************************/ |
71 | __END_DECLS |
72 | |
73 | #if PRAGMA_MARK |
74 | #pragma mark Internal constants & data structs |
75 | #endif /* PRAGMA_MARK */ |
76 | /********************************************************************* |
77 | * Internal constants & data structs |
78 | *********************************************************************/ |
79 | OSKextLogSpec kOSMetaClassLogSpec = |
80 | kOSKextLogErrorLevel | |
81 | kOSKextLogLoadFlag | |
82 | kOSKextLogKextBookkeepingFlag; |
83 | |
84 | static enum { |
85 | kCompletedBootstrap = 0, |
86 | kNoDictionaries = 1, |
87 | kMakingDictionaries = 2 |
88 | } sBootstrapState = kNoDictionaries; |
89 | |
90 | static const int kClassCapacityIncrement = 40; |
91 | static const int kKModCapacityIncrement = 10; |
92 | static OSDictionary * sAllClassesDict; |
93 | static unsigned int sDeepestClass; |
94 | IOLock * sAllClassesLock = NULL; |
95 | IOLock * sInstancesLock = NULL; |
96 | |
97 | /* |
98 | * While loading a kext and running all its constructors to register |
99 | * all OSMetaClass classes, the classes are queued up here. Only one |
100 | * kext can be in flight at a time, guarded by sStalledClassesLock |
101 | */ |
102 | static struct StalledData { |
103 | const char * kextIdentifier; |
104 | OSReturn result; |
105 | unsigned int capacity; |
106 | unsigned int count; |
107 | OSMetaClass ** classes; |
108 | } * sStalled; |
109 | IOLock * sStalledClassesLock = NULL; |
110 | |
111 | struct ExpansionData { |
112 | OSOrderedSet * instances; |
113 | OSKext * kext; |
114 | uint32_t retain; |
115 | #if IOTRACKING |
116 | IOTrackingQueue * tracking; |
117 | #endif |
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 defined(__arm64__) || defined(__arm__) |
133 | void |
134 | OSMetaClassBase::_RESERVEDOSMetaClassBase0() |
135 | { |
136 | panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called." , 0); |
137 | } |
138 | void |
139 | OSMetaClassBase::_RESERVEDOSMetaClassBase1() |
140 | { |
141 | panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called." , 1); |
142 | } |
143 | void |
144 | OSMetaClassBase::_RESERVEDOSMetaClassBase2() |
145 | { |
146 | panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called." , 2); |
147 | } |
148 | void |
149 | OSMetaClassBase::_RESERVEDOSMetaClassBase3() |
150 | { |
151 | panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called." , 3); |
152 | } |
153 | #endif /* defined(__arm64__) || defined(__arm__) */ |
154 | |
155 | // As these slots are used move them up inside the #if above |
156 | void |
157 | OSMetaClassBase::_RESERVEDOSMetaClassBase4() |
158 | { |
159 | panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called." , 4); |
160 | } |
161 | void |
162 | OSMetaClassBase::_RESERVEDOSMetaClassBase5() |
163 | { |
164 | panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called." , 5); |
165 | } |
166 | void |
167 | OSMetaClassBase::_RESERVEDOSMetaClassBase6() |
168 | { |
169 | panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called." , 6); |
170 | } |
171 | #endif |
172 | |
173 | /********************************************************************* |
174 | *********************************************************************/ |
175 | |
176 | #if defined(__arm__) || defined(__arm64__) |
177 | |
178 | #if defined(HAS_APPLE_PAC) |
179 | #include <ptrauth.h> |
180 | #endif /* defined(HAS_APPLE_PAC) */ |
181 | |
182 | /* |
183 | * IHI0059A "C++ Application Binary Interface Standard for the ARM 64 - bit Architecture": |
184 | * |
185 | * 3.2.1 Representation of pointer to member function The generic C++ ABI [GC++ABI] |
186 | * specifies that a pointer to member function is a pair of words <ptr, adj>. The |
187 | * least significant bit of ptr discriminates between (0) the address of a non- |
188 | * virtual member function and (1) the offset in the class's virtual table of the |
189 | * address of a virtual function. This encoding cannot work for the AArch64 |
190 | * instruction set where the architecture reserves all bits of code addresses. This |
191 | * ABI specifies that adj contains twice the this adjustment, plus 1 if the member |
192 | * function is virtual. The least significant bit of adj then makes exactly the |
193 | * same discrimination as the least significant bit of ptr does for Itanium. A |
194 | * pointer to member function is NULL when ptr = 0 and the least significant bit of |
195 | * adj is zero. |
196 | */ |
197 | |
198 | OSMetaClassBase::_ptf_t |
199 | #if defined(HAS_APPLE_PAC) && \ |
200 | __has_feature(ptrauth_member_function_pointer_type_discrimination) |
201 | OSMetaClassBase::_ptmf2ptf(const OSMetaClassBase *self __attribute__((unused)), |
202 | void (OSMetaClassBase::*func)(void)) |
203 | #else |
204 | OSMetaClassBase::_ptmf2ptf(const OSMetaClassBase *self, |
205 | void (OSMetaClassBase::*func)(void)) |
206 | #endif |
207 | { |
208 | struct ptmf_t { |
209 | _ptf_t fPFN; |
210 | ptrdiff_t delta; |
211 | }; |
212 | union { |
213 | void (OSMetaClassBase::*fIn)(void); |
214 | struct ptmf_t pTMF; |
215 | } map; |
216 | _ptf_t pfn; |
217 | |
218 | map.fIn = func; |
219 | pfn = map.pTMF.fPFN; |
220 | |
221 | #if defined(HAS_APPLE_PAC) && \ |
222 | __has_feature(ptrauth_member_function_pointer_type_discrimination) |
223 | // Authenticate 'pfn' using the member function pointer type discriminator |
224 | // and resign it as a C function pointer. 'pfn' can point to either a |
225 | // non-virtual function or a virtual member function thunk. |
226 | // It can also be NULL. |
227 | if (pfn) { |
228 | pfn = ptrauth_auth_and_resign(pfn, ptrauth_key_function_pointer, |
229 | ptrauth_type_discriminator(__typeof__(func)), |
230 | ptrauth_key_function_pointer, |
231 | ptrauth_function_pointer_type_discriminator(_ptf_t)); |
232 | } |
233 | return pfn; |
234 | #else |
235 | if (map.pTMF.delta & 1) { |
236 | // virtual |
237 | union { |
238 | const OSMetaClassBase *fObj; |
239 | _ptf_t **vtablep; |
240 | } u; |
241 | u.fObj = self; |
242 | |
243 | // Virtual member function so dereference table |
244 | #if defined(HAS_APPLE_PAC) |
245 | // The entity hash is stored in the top 32-bits of the vtable offset of a |
246 | // member function pointer. |
247 | uint32_t entity_hash = ((uintptr_t)pfn) >> 32; |
248 | pfn = (_ptf_t)(((uintptr_t) pfn) & 0xFFFFFFFF); |
249 | |
250 | #if __has_builtin(__builtin_get_vtable_pointer) |
251 | const _ptf_t *vtablep = |
252 | (const _ptf_t *)__builtin_get_vtable_pointer(u.fObj); |
253 | #else |
254 | // Authenticate the vtable pointer. |
255 | const _ptf_t *vtablep = ptrauth_auth_data(*u.vtablep, |
256 | ptrauth_key_cxx_vtable_pointer, 0); |
257 | #endif |
258 | // Calculate the address of the vtable entry. |
259 | _ptf_t *vtentryp = (_ptf_t *)(((uintptr_t)vtablep) + (uintptr_t)pfn); |
260 | // Load the pointer from the vtable entry. |
261 | pfn = *vtentryp; |
262 | |
263 | // Finally, resign the vtable entry as a function pointer. |
264 | uintptr_t auth_data = ptrauth_blend_discriminator(vtentryp, entity_hash); |
265 | pfn = ptrauth_auth_and_resign(pfn, ptrauth_key_function_pointer, |
266 | auth_data, ptrauth_key_function_pointer, |
267 | ptrauth_function_pointer_type_discriminator(_ptf_t)); |
268 | #else /* defined(HAS_APPLE_PAC) */ |
269 | pfn = *(_ptf_t *)(((uintptr_t)*u.vtablep) + (uintptr_t)pfn); |
270 | #endif /* !defined(HAS_APPLE_PAC) */ |
271 | return pfn; |
272 | } else { |
273 | // Not virtual, i.e. plain member func |
274 | return pfn; |
275 | } |
276 | #endif |
277 | } |
278 | |
279 | #endif /* defined(__arm__) || defined(__arm64__) */ |
280 | /********************************************************************* |
281 | * These used to be inline in the header but gcc didn't believe us |
282 | * Now we MUST pull the inline out at least until the compiler is |
283 | * repaired. |
284 | * |
285 | * Helper inlines for runtime type preprocessor macros |
286 | *********************************************************************/ |
287 | |
288 | /********************************************************************* |
289 | *********************************************************************/ |
290 | OSMetaClassBase * |
291 | OSMetaClassBase::safeMetaCast( |
292 | const OSMetaClassBase * me, |
293 | const OSMetaClass * toType) |
294 | { |
295 | return (me)? me->metaCast(toMeta: toType) : NULL; |
296 | } |
297 | |
298 | /// A helper function to crash with a kernel panic. |
299 | __attribute__((cold, not_tail_called, noreturn)) |
300 | static inline void |
301 | panic_crash_fail_cast(const OSMetaClassBase *me, |
302 | const OSMetaClass *toType) |
303 | { |
304 | panic("Unexpected cast fail: from %p to %p" , me, toType); |
305 | __builtin_unreachable(); |
306 | } |
307 | |
308 | OSMetaClassBase * |
309 | OSMetaClassBase::requiredMetaCast( |
310 | const OSMetaClassBase * me, |
311 | const OSMetaClass * toType) |
312 | { |
313 | if (!me) { |
314 | return NULL; |
315 | } |
316 | OSMetaClassBase *tmp = safeMetaCast(me, toType); |
317 | if (!tmp) { |
318 | panic_crash_fail_cast(me, toType); |
319 | } |
320 | return tmp; |
321 | } |
322 | |
323 | /********************************************************************* |
324 | *********************************************************************/ |
325 | bool |
326 | OSMetaClassBase::checkTypeInst( |
327 | const OSMetaClassBase * inst, |
328 | const OSMetaClassBase * typeinst) |
329 | { |
330 | const OSMetaClass * toType = OSTypeIDInst(typeinst); |
331 | return typeinst && inst && (NULL != inst->metaCast(toMeta: toType)); |
332 | } |
333 | |
334 | /********************************************************************* |
335 | *********************************************************************/ |
336 | void |
337 | OSMetaClassBase:: |
338 | initialize() |
339 | { |
340 | sAllClassesLock = IOLockAlloc(); |
341 | sStalledClassesLock = IOLockAlloc(); |
342 | sInstancesLock = IOLockAlloc(); |
343 | } |
344 | |
345 | #if APPLE_KEXT_VTABLE_PADDING |
346 | /********************************************************************* |
347 | * If you need this slot you had better setup an IOCTL style interface. |
348 | * 'Cause the whole kernel world depends on OSMetaClassBase and YOU |
349 | * CANT change the VTABLE size ever. |
350 | *********************************************************************/ |
351 | void |
352 | OSMetaClassBase::_RESERVEDOSMetaClassBase7() |
353 | { |
354 | panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called." , 7); |
355 | } |
356 | #endif |
357 | |
358 | /********************************************************************* |
359 | *********************************************************************/ |
360 | OSMetaClassBase::OSMetaClassBase() |
361 | { |
362 | } |
363 | |
364 | /********************************************************************* |
365 | *********************************************************************/ |
366 | OSMetaClassBase::~OSMetaClassBase() |
367 | { |
368 | void ** thisVTable; |
369 | |
370 | thisVTable = (void **) this; |
371 | *thisVTable = (void *) -1UL; |
372 | } |
373 | |
374 | /********************************************************************* |
375 | *********************************************************************/ |
376 | bool |
377 | OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const |
378 | { |
379 | return this == anObj; |
380 | } |
381 | |
382 | /********************************************************************* |
383 | *********************************************************************/ |
384 | OSMetaClassBase * |
385 | OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const |
386 | { |
387 | return toMeta->checkMetaCast(object: this); |
388 | } |
389 | |
390 | /********************************************************************* |
391 | *********************************************************************/ |
392 | OSMetaClassBase * |
393 | OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const |
394 | { |
395 | return OSMetaClass::checkMetaCastWithName(className: toMetaSymb, object: this); |
396 | } |
397 | |
398 | /********************************************************************* |
399 | *********************************************************************/ |
400 | OSMetaClassBase * |
401 | OSMetaClassBase::metaCast(const OSString * toMetaStr) const |
402 | { |
403 | const OSSymbol * tempSymb = OSSymbol::withString(aString: toMetaStr); |
404 | OSMetaClassBase * ret = NULL; |
405 | if (tempSymb) { |
406 | ret = metaCast(toMetaSymb: tempSymb); |
407 | tempSymb->release(); |
408 | } |
409 | return ret; |
410 | } |
411 | |
412 | /********************************************************************* |
413 | *********************************************************************/ |
414 | OSMetaClassBase * |
415 | OSMetaClassBase::metaCast(const char * toMetaCStr) const |
416 | { |
417 | const OSSymbol * tempSymb = OSSymbol::withCString(cString: toMetaCStr); |
418 | OSMetaClassBase * ret = NULL; |
419 | if (tempSymb) { |
420 | ret = metaCast(toMetaSymb: tempSymb); |
421 | tempSymb->release(); |
422 | } |
423 | return ret; |
424 | } |
425 | |
426 | #if PRAGMA_MARK |
427 | #pragma mark OSMetaClassMeta |
428 | #endif /* PRAGMA_MARK */ |
429 | /********************************************************************* |
430 | * OSMetaClassMeta - the bootstrap metaclass of OSMetaClass |
431 | *********************************************************************/ |
432 | class OSMetaClassMeta : public OSMetaClass |
433 | { |
434 | public: |
435 | OSMetaClassMeta(); |
436 | OSObject * alloc() const; |
437 | }; |
438 | OSMetaClassMeta::OSMetaClassMeta() |
439 | : OSMetaClass("OSMetaClass" , NULL, sizeof(OSMetaClass)) |
440 | { |
441 | } |
442 | OSObject * |
443 | OSMetaClassMeta::alloc() const |
444 | { |
445 | return NULL; |
446 | } |
447 | |
448 | static OSMetaClassMeta sOSMetaClassMeta; |
449 | |
450 | const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta; |
451 | const OSMetaClass * |
452 | OSMetaClass::getMetaClass() const |
453 | { |
454 | return &sOSMetaClassMeta; |
455 | } |
456 | |
457 | #if PRAGMA_MARK |
458 | #pragma mark OSMetaClass |
459 | #endif /* PRAGMA_MARK */ |
460 | /********************************************************************* |
461 | * OSMetaClass |
462 | *********************************************************************/ |
463 | |
464 | #if APPLE_KEXT_VTABLE_PADDING |
465 | /********************************************************************* |
466 | * Reserved functions. |
467 | *********************************************************************/ |
468 | void |
469 | OSMetaClass::_RESERVEDOSMetaClass0() |
470 | { |
471 | panic("OSMetaClass::_RESERVEDOSMetaClass%d called" , 0); |
472 | } |
473 | void |
474 | OSMetaClass::_RESERVEDOSMetaClass1() |
475 | { |
476 | panic("OSMetaClass::_RESERVEDOSMetaClass%d called" , 1); |
477 | } |
478 | void |
479 | OSMetaClass::_RESERVEDOSMetaClass2() |
480 | { |
481 | panic("OSMetaClass::_RESERVEDOSMetaClass%d called" , 2); |
482 | } |
483 | void |
484 | OSMetaClass::_RESERVEDOSMetaClass3() |
485 | { |
486 | panic("OSMetaClass::_RESERVEDOSMetaClass%d called" , 3); |
487 | } |
488 | void |
489 | OSMetaClass::_RESERVEDOSMetaClass4() |
490 | { |
491 | panic("OSMetaClass::_RESERVEDOSMetaClass%d called" , 4); |
492 | } |
493 | void |
494 | OSMetaClass::_RESERVEDOSMetaClass5() |
495 | { |
496 | panic("OSMetaClass::_RESERVEDOSMetaClass%d called" , 5); |
497 | } |
498 | void |
499 | OSMetaClass::_RESERVEDOSMetaClass6() |
500 | { |
501 | panic("OSMetaClass::_RESERVEDOSMetaClass%d called" , 6); |
502 | } |
503 | void |
504 | OSMetaClass::_RESERVEDOSMetaClass7() |
505 | { |
506 | panic("OSMetaClass::_RESERVEDOSMetaClass%d called" , 7); |
507 | } |
508 | #endif |
509 | |
510 | /********************************************************************* |
511 | *********************************************************************/ |
512 | static void |
513 | OSMetaClassLogErrorForKext( |
514 | OSReturn error, |
515 | OSKext * aKext) |
516 | { |
517 | const char * message = NULL; |
518 | |
519 | switch (error) { |
520 | case kOSReturnSuccess: |
521 | return; |
522 | case kOSMetaClassNoInit: // xxx - never returned; logged at fail site |
523 | message = "OSMetaClass: preModLoad() wasn't called (runtime internal error)." ; |
524 | break; |
525 | case kOSMetaClassNoDicts: |
526 | message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries." ; |
527 | break; |
528 | case kOSMetaClassNoKModSet: |
529 | message = "OSMetaClass: Allocation failure for internal kext recording set/set missing." ; |
530 | break; |
531 | case kOSMetaClassNoInsKModSet: |
532 | message = "OSMetaClass: Failed to record class in kext." ; |
533 | break; |
534 | case kOSMetaClassDuplicateClass: |
535 | message = "OSMetaClass: Duplicate class encountered." ; |
536 | break; |
537 | case kOSMetaClassNoSuper: // xxx - never returned |
538 | message = "OSMetaClass: Can't associate a class with its superclass." ; |
539 | break; |
540 | case kOSMetaClassInstNoSuper: // xxx - never returned |
541 | message = "OSMetaClass: Instance construction error; unknown superclass." ; |
542 | break; |
543 | case kOSMetaClassNoKext: |
544 | message = "OSMetaClass: Kext not found for metaclass." ; |
545 | break; |
546 | case kOSMetaClassInternal: |
547 | default: |
548 | message = "OSMetaClass: Runtime internal error." ; |
549 | break; |
550 | } |
551 | |
552 | if (message) { |
553 | OSKextLog(aKext, msgLogSpec: kOSMetaClassLogSpec, format: "%s" , message); |
554 | } |
555 | return; |
556 | } |
557 | |
558 | void |
559 | OSMetaClass::logError(OSReturn error) |
560 | { |
561 | OSMetaClassLogErrorForKext(error, NULL); |
562 | } |
563 | |
564 | /********************************************************************* |
565 | * The core constructor for a MetaClass (defined with this name always |
566 | * but within the scope of its represented class). |
567 | * |
568 | * MetaClass constructors are invoked in OSRuntimeInitializeCPP(), |
569 | * in between calls to OSMetaClass::preModLoad(), which sets up for |
570 | * registration, and OSMetaClass::postModLoad(), which actually |
571 | * records all the class/kext relationships of the new MetaClasses. |
572 | *********************************************************************/ |
573 | |
574 | OSMetaClass::OSMetaClass( |
575 | const char * inClassName, |
576 | const OSMetaClass * inSuperClass, |
577 | unsigned int inClassSize) |
578 | { |
579 | instanceCount = 0; |
580 | classSize = inClassSize; |
581 | superClassLink = inSuperClass; |
582 | |
583 | reserved = IOMallocType(ExpansionData); |
584 | #if IOTRACKING |
585 | uint32_t numSiteQs = 0; |
586 | if ((this == &OSSymbol ::gMetaClass) |
587 | || (this == &OSString ::gMetaClass) |
588 | || (this == &OSNumber ::gMetaClass) |
589 | || (this == &OSString ::gMetaClass) |
590 | || (this == &OSData ::gMetaClass) |
591 | || (this == &OSDictionary::gMetaClass) |
592 | || (this == &OSArray ::gMetaClass) |
593 | || (this == &OSSet ::gMetaClass)) { |
594 | numSiteQs = 27; |
595 | } |
596 | |
597 | reserved->tracking = IOTrackingQueueAlloc(inClassName, (uintptr_t) this, |
598 | inClassSize, 0, kIOTrackingQueueTypeAlloc, |
599 | numSiteQs); |
600 | #endif |
601 | |
602 | /* Hack alert: We are just casting inClassName and storing it in |
603 | * an OSString * instance variable. This may be because you can't |
604 | * create C++ objects in static constructors, but I really don't know! |
605 | */ |
606 | className = (const OSSymbol *)inClassName; |
607 | |
608 | // sStalledClassesLock taken in preModLoad |
609 | if (!sStalled) { |
610 | /* There's no way we can look up the kext here, unfortunately. |
611 | */ |
612 | OSKextLog(/* kext */ NULL, msgLogSpec: kOSMetaClassLogSpec, |
613 | format: "OSMetaClass: preModLoad() wasn't called for class %s " |
614 | "(runtime internal error)." , |
615 | inClassName); |
616 | } else if (!sStalled->result) { |
617 | // Grow stalled array if neccessary |
618 | if (sStalled->count >= sStalled->capacity) { |
619 | OSMetaClass **oldStalled = sStalled->classes; |
620 | int oldCount = sStalled->capacity; |
621 | int newCount = oldCount + kKModCapacityIncrement; |
622 | |
623 | sStalled->classes = kalloc_type_tag(OSMetaClass *, newCount, |
624 | Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT); |
625 | if (!sStalled->classes) { |
626 | sStalled->classes = oldStalled; |
627 | sStalled->result = kOSMetaClassNoTempData; |
628 | return; |
629 | } |
630 | |
631 | sStalled->capacity = newCount; |
632 | memmove(dst: sStalled->classes, src: oldStalled, |
633 | n: sizeof(OSMetaClass *) * oldCount); |
634 | kfree_type(OSMetaClass *, oldCount, oldStalled); |
635 | OSMETA_ACCUMSIZE(sizeof(OSMetaClass *) * (newCount - oldCount)); |
636 | } |
637 | |
638 | sStalled->classes[sStalled->count++] = this; |
639 | } |
640 | } |
641 | |
642 | OSMetaClass::OSMetaClass( |
643 | const char * inClassName, |
644 | const OSMetaClass * inSuperClass, |
645 | unsigned int inClassSize, |
646 | zone_t * inZone, |
647 | const char * zone_name, |
648 | zone_create_flags_t zflags) : OSMetaClass(inClassName, inSuperClass, |
649 | inClassSize) |
650 | { |
651 | if (!(kIOTracking & gIOKitDebug)) { |
652 | *inZone = zone_create(name: zone_name, size: inClassSize, |
653 | flags: (zone_create_flags_t) (ZC_ZFREE_CLEARMEM | zflags)); |
654 | } |
655 | } |
656 | |
657 | /********************************************************************* |
658 | *********************************************************************/ |
659 | OSMetaClass::~OSMetaClass() |
660 | { |
661 | OSKext * myKext = reserved->kext; // do not release |
662 | |
663 | /* Hack alert: 'className' is a C string during early C++ init, and |
664 | * is converted to a real OSSymbol only when we record the OSKext in |
665 | * OSMetaClass::postModLoad(). So only do this bit if we have an OSKext. |
666 | * We can't safely cast or check 'className'. |
667 | * |
668 | * Also, release className *after* calling into the kext, |
669 | * as removeClass() may access className. |
670 | */ |
671 | IOLockLock(sAllClassesLock); |
672 | if (sAllClassesDict) { |
673 | if (myKext) { |
674 | sAllClassesDict->removeObject(aKey: className); |
675 | } else { |
676 | sAllClassesDict->removeObject(aKey: (const char *)className); |
677 | } |
678 | } |
679 | IOLockUnlock(sAllClassesLock); |
680 | |
681 | if (myKext) { |
682 | if (myKext->removeClass(aClass: this) != kOSReturnSuccess) { |
683 | // xxx - what can we do? |
684 | } |
685 | className->release(); |
686 | } |
687 | |
688 | // sStalledClassesLock taken in preModLoad |
689 | if (sStalled) { |
690 | unsigned int i; |
691 | |
692 | /* First pass find class in stalled list. If we find it that means |
693 | * we started C++ init with constructors but now we're tearing down |
694 | * because of some failure. |
695 | */ |
696 | for (i = 0; i < sStalled->count; i++) { |
697 | if (this == sStalled->classes[i]) { |
698 | break; |
699 | } |
700 | } |
701 | |
702 | /* Remove this metaclass from the stalled list so postModLoad() doesn't |
703 | * try to register it. |
704 | */ |
705 | if (i < sStalled->count) { |
706 | sStalled->count--; |
707 | if (i < sStalled->count) { |
708 | memmove(dst: &sStalled->classes[i], src: &sStalled->classes[i + 1], |
709 | n: (sStalled->count - i) * sizeof(OSMetaClass *)); |
710 | } |
711 | } |
712 | } |
713 | #if IOTRACKING |
714 | IOTrackingQueueFree(reserved->tracking); |
715 | #endif |
716 | IOFreeType(reserved, ExpansionData); |
717 | } |
718 | |
719 | /********************************************************************* |
720 | * Empty overrides. |
721 | *********************************************************************/ |
722 | void |
723 | OSMetaClass::retain() const |
724 | { |
725 | } |
726 | void |
727 | OSMetaClass::release() const |
728 | { |
729 | } |
730 | void |
731 | OSMetaClass::release(__unused int when) const |
732 | { |
733 | } |
734 | void |
735 | OSMetaClass::taggedRetain(__unused const void * tag) const |
736 | { |
737 | } |
738 | void |
739 | OSMetaClass::taggedRelease(__unused const void * tag) const |
740 | { |
741 | } |
742 | void |
743 | OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const |
744 | { |
745 | } |
746 | int |
747 | OSMetaClass::getRetainCount() const |
748 | { |
749 | return 0; |
750 | } |
751 | |
752 | /********************************************************************* |
753 | *********************************************************************/ |
754 | const char * |
755 | OSMetaClass::getClassName() const |
756 | { |
757 | if (!className) { |
758 | return NULL; |
759 | } |
760 | return className->getCStringNoCopy(); |
761 | } |
762 | /********************************************************************* |
763 | *********************************************************************/ |
764 | const OSSymbol * |
765 | OSMetaClass::getClassNameSymbol() const |
766 | { |
767 | return className; |
768 | } |
769 | /********************************************************************* |
770 | *********************************************************************/ |
771 | unsigned int |
772 | OSMetaClass::getClassSize() const |
773 | { |
774 | return classSize; |
775 | } |
776 | |
777 | /********************************************************************* |
778 | *********************************************************************/ |
779 | void * |
780 | OSMetaClass::preModLoad(const char * kextIdentifier) |
781 | { |
782 | IOLockLock(sStalledClassesLock); |
783 | |
784 | assert(sStalled == NULL); |
785 | sStalled = kalloc_type(StalledData, Z_WAITOK_ZERO_NOFAIL); |
786 | |
787 | sStalled->classes = kalloc_type_tag(OSMetaClass *, |
788 | kKModCapacityIncrement, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT); |
789 | if (!sStalled->classes) { |
790 | kfree_type(StalledData, sStalled); |
791 | return NULL; |
792 | } |
793 | OSMETA_ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + |
794 | sizeof(*sStalled)); |
795 | |
796 | sStalled->result = kOSReturnSuccess; |
797 | sStalled->capacity = kKModCapacityIncrement; |
798 | sStalled->count = 0; |
799 | sStalled->kextIdentifier = kextIdentifier; |
800 | |
801 | // keep sStalledClassesLock locked until postModLoad |
802 | |
803 | return sStalled; |
804 | } |
805 | |
806 | /********************************************************************* |
807 | *********************************************************************/ |
808 | bool |
809 | OSMetaClass::checkModLoad(void * loadHandle) |
810 | { |
811 | return sStalled && loadHandle == sStalled && |
812 | sStalled->result == kOSReturnSuccess; |
813 | } |
814 | |
815 | /********************************************************************* |
816 | *********************************************************************/ |
817 | OSReturn |
818 | OSMetaClass::postModLoad(void * loadHandle) |
819 | { |
820 | OSReturn result = kOSReturnSuccess; |
821 | OSSymbol * myKextName = NULL;// must release |
822 | OSKext * myKext = NULL;// must release |
823 | |
824 | if (!sStalled || loadHandle != sStalled) { |
825 | result = kOSMetaClassInternal; |
826 | goto finish; |
827 | } |
828 | |
829 | if (sStalled->result) { |
830 | result = sStalled->result; |
831 | } else { |
832 | switch (sBootstrapState) { |
833 | case kNoDictionaries: |
834 | sBootstrapState = kMakingDictionaries; |
835 | // No break; fall through |
836 | [[clang::fallthrough]]; |
837 | |
838 | case kMakingDictionaries: |
839 | sAllClassesDict = OSDictionary::withCapacity(capacity: kClassCapacityIncrement); |
840 | if (!sAllClassesDict) { |
841 | result = kOSMetaClassNoDicts; |
842 | break; |
843 | } |
844 | sAllClassesDict->setOptions(options: OSCollection::kSort, mask: OSCollection::kSort); |
845 | |
846 | // No break; fall through |
847 | [[clang::fallthrough]]; |
848 | |
849 | case kCompletedBootstrap: |
850 | { |
851 | unsigned int i; |
852 | myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy( |
853 | cString: sStalled->kextIdentifier)); |
854 | |
855 | if (!sStalled->count) { |
856 | break; // Nothing to do so just get out |
857 | } |
858 | |
859 | myKext = OSKext::lookupKextWithIdentifier(kextIdentifier: myKextName); |
860 | if (!myKext) { |
861 | result = kOSMetaClassNoKext; |
862 | |
863 | /* Log this error here so we can include the kext name. |
864 | */ |
865 | OSKextLog(/* kext */ NULL, msgLogSpec: kOSMetaClassLogSpec, |
866 | format: "OSMetaClass: Can't record classes for kext %s - kext not found." , |
867 | sStalled->kextIdentifier); |
868 | break; |
869 | } |
870 | |
871 | /* First pass checking classes aren't already loaded. If any already |
872 | * exist, we don't register any, and so we don't technically have |
873 | * to do any C++ teardown. |
874 | * |
875 | * Hack alert: me->className has been a C string until now. |
876 | * We only release the OSSymbol if we store the kext. |
877 | */ |
878 | IOLockLock(sAllClassesLock); |
879 | for (i = 0; i < sStalled->count; i++) { |
880 | const OSMetaClass * me = sStalled->classes[i]; |
881 | OSMetaClass * orig = OSDynamicCast(OSMetaClass, |
882 | sAllClassesDict->getObject((const char *)me->className)); |
883 | |
884 | if (orig) { |
885 | /* Log this error here so we can include the class name. |
886 | * xxx - we should look up the other kext that defines the class |
887 | */ |
888 | #if defined(XNU_TARGET_OS_OSX) |
889 | OSKextLog(aKext: myKext, msgLogSpec: kOSMetaClassLogSpec, |
890 | #else |
891 | panic( |
892 | #endif /* defined(XNU_TARGET_OS_OSX) */ |
893 | format: "OSMetaClass: Kext %s class %s is a duplicate;" |
894 | "kext %s already has a class by that name." , |
895 | sStalled->kextIdentifier, (const char *)me->className, |
896 | ((OSKext *)orig->reserved->kext)->getIdentifierCString()); |
897 | result = kOSMetaClassDuplicateClass; |
898 | break; |
899 | } |
900 | unsigned int depth = 1; |
901 | while ((me = me->superClassLink)) { |
902 | depth++; |
903 | } |
904 | if (depth > sDeepestClass) { |
905 | sDeepestClass = depth; |
906 | } |
907 | } |
908 | IOLockUnlock(sAllClassesLock); |
909 | |
910 | /* Bail if we didn't go through the entire list of new classes |
911 | * (if we hit a duplicate). |
912 | */ |
913 | if (i != sStalled->count) { |
914 | break; |
915 | } |
916 | |
917 | // Second pass symbolling strings and inserting classes in dictionary |
918 | IOLockLock(sAllClassesLock); |
919 | for (i = 0; i < sStalled->count; i++) { |
920 | OSMetaClass * me = sStalled->classes[i]; |
921 | |
922 | /* Hack alert: me->className has been a C string until now. |
923 | * We only release the OSSymbol in ~OSMetaClass() |
924 | * if we set the reference to the kext. |
925 | */ |
926 | me->className = |
927 | OSSymbol::withCStringNoCopy(cString: (const char *)me->className); |
928 | |
929 | // xxx - I suppose if these fail we're going to panic soon.... |
930 | sAllClassesDict->setObject(aKey: me->className, anObject: me); |
931 | |
932 | /* Do not retain the kext object here. |
933 | */ |
934 | me->reserved->kext = myKext; |
935 | if (myKext) { |
936 | result = myKext->addClass(aClass: me, numClasses: sStalled->count); |
937 | if (result != kOSReturnSuccess) { |
938 | /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */ |
939 | break; |
940 | } |
941 | } |
942 | } |
943 | IOLockUnlock(sAllClassesLock); |
944 | sBootstrapState = kCompletedBootstrap; |
945 | break; |
946 | } |
947 | |
948 | default: |
949 | result = kOSMetaClassInternal; |
950 | break; |
951 | } |
952 | } |
953 | |
954 | finish: |
955 | /* Don't call logError() for success or the conditions logged above |
956 | * or by called function. |
957 | */ |
958 | if (result != kOSReturnSuccess && |
959 | result != kOSMetaClassNoInsKModSet && |
960 | result != kOSMetaClassDuplicateClass && |
961 | result != kOSMetaClassNoKext) { |
962 | OSMetaClassLogErrorForKext(error: result, aKext: myKext); |
963 | } |
964 | |
965 | OSSafeReleaseNULL(myKextName); |
966 | OSSafeReleaseNULL(myKext); |
967 | |
968 | if (sStalled) { |
969 | OSMETA_ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) + |
970 | sizeof(*sStalled))); |
971 | kfree_type(OSMetaClass *, sStalled->capacity, sStalled->classes); |
972 | kfree_type(StalledData, sStalled); |
973 | sStalled = NULL; |
974 | } |
975 | |
976 | IOLockUnlock(sStalledClassesLock); |
977 | |
978 | return result; |
979 | } |
980 | |
981 | |
982 | /********************************************************************* |
983 | *********************************************************************/ |
984 | void |
985 | OSMetaClass::instanceConstructed() const |
986 | { |
987 | // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink) |
988 | if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) { |
989 | superClassLink->instanceConstructed(); |
990 | } |
991 | } |
992 | |
993 | /********************************************************************* |
994 | *********************************************************************/ |
995 | void |
996 | OSMetaClass::instanceDestructed() const |
997 | { |
998 | if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) { |
999 | superClassLink->instanceDestructed(); |
1000 | } |
1001 | |
1002 | if (((int)instanceCount) < 0) { |
1003 | OSKext * myKext = reserved->kext; |
1004 | |
1005 | OSKextLog(aKext: myKext, msgLogSpec: kOSMetaClassLogSpec, |
1006 | // xxx - this phrasing is rather cryptic |
1007 | format: "OSMetaClass: Class %s - bad retain (%d)" , |
1008 | getClassName(), instanceCount); |
1009 | } |
1010 | } |
1011 | |
1012 | /********************************************************************* |
1013 | *********************************************************************/ |
1014 | bool |
1015 | OSMetaClass::modHasInstance(const char * kextIdentifier) |
1016 | { |
1017 | bool result = false; |
1018 | OSKext * theKext = NULL; // must release |
1019 | |
1020 | theKext = OSKext::lookupKextWithIdentifier(kextIdentifier); |
1021 | if (!theKext) { |
1022 | goto finish; |
1023 | } |
1024 | |
1025 | result = theKext->hasOSMetaClassInstances(); |
1026 | |
1027 | finish: |
1028 | OSSafeReleaseNULL(theKext); |
1029 | return result; |
1030 | } |
1031 | |
1032 | /********************************************************************* |
1033 | *********************************************************************/ |
1034 | void |
1035 | OSMetaClass::reportModInstances(const char * kextIdentifier) |
1036 | { |
1037 | OSKext::reportOSMetaClassInstances(kextIdentifier, |
1038 | kOSKextLogExplicitLevel); |
1039 | return; |
1040 | } |
1041 | /********************************************************************* |
1042 | *********************************************************************/ |
1043 | |
1044 | void |
1045 | OSMetaClass::addInstance(const OSObject * instance, bool super) const |
1046 | { |
1047 | if (!super) { |
1048 | IOLockLock(sInstancesLock); |
1049 | } |
1050 | |
1051 | if (!reserved->instances) { |
1052 | reserved->instances = OSOrderedSet::withCapacity(capacity: 16); |
1053 | if (superClassLink) { |
1054 | superClassLink->addInstance(instance: reserved->instances, super: true); |
1055 | } |
1056 | } |
1057 | reserved->instances->setLastObject(instance); |
1058 | |
1059 | if (!super) { |
1060 | IOLockUnlock(sInstancesLock); |
1061 | } |
1062 | } |
1063 | |
1064 | void |
1065 | OSMetaClass::removeInstance(const OSObject * instance, bool super) const |
1066 | { |
1067 | if (!super) { |
1068 | IOLockLock(sInstancesLock); |
1069 | } |
1070 | |
1071 | if (reserved->instances) { |
1072 | reserved->instances->removeObject(anObject: instance); |
1073 | if (0 == reserved->instances->getCount()) { |
1074 | if (superClassLink) { |
1075 | superClassLink->removeInstance(instance: reserved->instances, super: true); |
1076 | } |
1077 | IOLockLock(sAllClassesLock); |
1078 | reserved->instances->release(); |
1079 | reserved->instances = NULL; |
1080 | IOLockUnlock(sAllClassesLock); |
1081 | } |
1082 | } |
1083 | |
1084 | if (!super) { |
1085 | IOLockUnlock(sInstancesLock); |
1086 | } |
1087 | } |
1088 | |
1089 | void |
1090 | OSMetaClass::applyToInstances(OSOrderedSet * set, |
1091 | OSMetaClassInstanceApplierFunction applier, |
1092 | void * context) |
1093 | { |
1094 | enum { kLocalDepth = 24 }; |
1095 | unsigned int _nextIndex[kLocalDepth]; |
1096 | OSOrderedSet * _sets[kLocalDepth]; |
1097 | unsigned int * nextIndex = &_nextIndex[0]; |
1098 | OSOrderedSet ** sets = &_sets[0]; |
1099 | OSObject * obj; |
1100 | OSOrderedSet * childSet; |
1101 | unsigned int maxDepth; |
1102 | unsigned int idx; |
1103 | unsigned int level; |
1104 | bool done; |
1105 | |
1106 | maxDepth = sDeepestClass; |
1107 | if (maxDepth > kLocalDepth) { |
1108 | nextIndex = IONewData(typeof(nextIndex[0]), maxDepth); |
1109 | sets = IONew(typeof(sets[0]), maxDepth); |
1110 | } |
1111 | done = false; |
1112 | level = 0; |
1113 | idx = 0; |
1114 | do{ |
1115 | while (!done && (obj = set->getObject(index: idx++))) { |
1116 | if ((childSet = OSDynamicCast(OSOrderedSet, obj))) { |
1117 | if (level >= maxDepth) { |
1118 | panic(">maxDepth" ); |
1119 | } |
1120 | sets[level] = set; |
1121 | nextIndex[level] = idx; |
1122 | level++; |
1123 | set = childSet; |
1124 | idx = 0; |
1125 | break; |
1126 | } |
1127 | done = (*applier)(obj, context); |
1128 | } |
1129 | if (!obj) { |
1130 | if (!done && level) { |
1131 | level--; |
1132 | set = sets[level]; |
1133 | idx = nextIndex[level]; |
1134 | } else { |
1135 | done = true; |
1136 | } |
1137 | } |
1138 | }while (!done); |
1139 | if (maxDepth > kLocalDepth) { |
1140 | IODeleteData(nextIndex, typeof(nextIndex[0]), maxDepth); |
1141 | IODelete(sets, typeof(sets[0]), maxDepth); |
1142 | } |
1143 | } |
1144 | |
1145 | void |
1146 | OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier, |
1147 | void * context) const |
1148 | { |
1149 | IOLockLock(sInstancesLock); |
1150 | if (reserved->instances) { |
1151 | applyToInstances(set: reserved->instances, applier, context); |
1152 | } |
1153 | IOLockUnlock(sInstancesLock); |
1154 | } |
1155 | |
1156 | void |
1157 | OSMetaClass::applyToInstancesOfClassName( |
1158 | const OSSymbol * name, |
1159 | OSMetaClassInstanceApplierFunction applier, |
1160 | void * context) |
1161 | { |
1162 | OSMetaClass * meta; |
1163 | OSOrderedSet * set = NULL; |
1164 | |
1165 | IOLockLock(sAllClassesLock); |
1166 | if (sAllClassesDict |
1167 | && (meta = (OSMetaClass *) sAllClassesDict->getObject(aKey: name)) |
1168 | && (set = meta->reserved->instances)) { |
1169 | set->retain(); |
1170 | } |
1171 | IOLockUnlock(sAllClassesLock); |
1172 | |
1173 | if (!set) { |
1174 | return; |
1175 | } |
1176 | |
1177 | IOLockLock(sInstancesLock); |
1178 | applyToInstances(set, applier, context); |
1179 | IOLockUnlock(sInstancesLock); |
1180 | set->release(); |
1181 | } |
1182 | |
1183 | /********************************************************************* |
1184 | *********************************************************************/ |
1185 | void |
1186 | OSMetaClass::considerUnloads() |
1187 | { |
1188 | OSKext::considerUnloads(); |
1189 | } |
1190 | |
1191 | /********************************************************************* |
1192 | *********************************************************************/ |
1193 | bool |
1194 | OSMetaClass::removeClasses(OSCollection * metaClasses) |
1195 | { |
1196 | OSCollectionIterator * classIterator; |
1197 | OSMetaClass * checkClass; |
1198 | bool result; |
1199 | |
1200 | classIterator = OSCollectionIterator::withCollection(inColl: metaClasses); |
1201 | if (!classIterator) { |
1202 | return false; |
1203 | } |
1204 | |
1205 | IOLockLock(sAllClassesLock); |
1206 | |
1207 | result = false; |
1208 | do{ |
1209 | while ((checkClass = (OSMetaClass *)classIterator->getNextObject()) |
1210 | && !checkClass->getInstanceCount() |
1211 | && !checkClass->reserved->retain) { |
1212 | } |
1213 | if (checkClass) { |
1214 | break; |
1215 | } |
1216 | classIterator->reset(); |
1217 | while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) { |
1218 | sAllClassesDict->removeObject(aKey: checkClass->className); |
1219 | } |
1220 | result = true; |
1221 | }while (false); |
1222 | |
1223 | IOLockUnlock(sAllClassesLock); |
1224 | OSSafeReleaseNULL(classIterator); |
1225 | |
1226 | return result; |
1227 | } |
1228 | |
1229 | |
1230 | /********************************************************************* |
1231 | *********************************************************************/ |
1232 | const OSMetaClass * |
1233 | OSMetaClass::getMetaClassWithName(const OSSymbol * name) |
1234 | { |
1235 | OSMetaClass * retMeta = NULL; |
1236 | |
1237 | if (!name) { |
1238 | return NULL; |
1239 | } |
1240 | |
1241 | IOLockLock(sAllClassesLock); |
1242 | if (sAllClassesDict) { |
1243 | retMeta = (OSMetaClass *) sAllClassesDict->getObject(aKey: name); |
1244 | } |
1245 | IOLockUnlock(sAllClassesLock); |
1246 | |
1247 | return retMeta; |
1248 | } |
1249 | |
1250 | /********************************************************************* |
1251 | *********************************************************************/ |
1252 | const OSMetaClass * |
1253 | OSMetaClass::copyMetaClassWithName(const OSSymbol * name) |
1254 | { |
1255 | const OSMetaClass * meta; |
1256 | |
1257 | if (!name) { |
1258 | return NULL; |
1259 | } |
1260 | |
1261 | meta = NULL; |
1262 | IOLockLock(sAllClassesLock); |
1263 | if (sAllClassesDict) { |
1264 | meta = (OSMetaClass *) sAllClassesDict->getObject(aKey: name); |
1265 | if (meta) { |
1266 | OSIncrementAtomic(&meta->reserved->retain); |
1267 | } |
1268 | } |
1269 | IOLockUnlock(sAllClassesLock); |
1270 | |
1271 | return meta; |
1272 | } |
1273 | |
1274 | /********************************************************************* |
1275 | *********************************************************************/ |
1276 | void |
1277 | OSMetaClass::releaseMetaClass() const |
1278 | { |
1279 | OSDecrementAtomic(&reserved->retain); |
1280 | } |
1281 | |
1282 | /********************************************************************* |
1283 | *********************************************************************/ |
1284 | OSObject * |
1285 | OSMetaClass::allocClassWithName(const OSSymbol * name) |
1286 | { |
1287 | const OSMetaClass * meta; |
1288 | OSObject * result; |
1289 | |
1290 | result = NULL; |
1291 | meta = copyMetaClassWithName(name); |
1292 | if (meta) { |
1293 | result = meta->alloc(); |
1294 | meta->releaseMetaClass(); |
1295 | } |
1296 | |
1297 | return result; |
1298 | } |
1299 | |
1300 | /********************************************************************* |
1301 | *********************************************************************/ |
1302 | OSObject * |
1303 | OSMetaClass::allocClassWithName(const OSString * name) |
1304 | { |
1305 | const OSSymbol * tmpKey = OSSymbol::withString(aString: name); |
1306 | OSObject * result = allocClassWithName(name: tmpKey); |
1307 | tmpKey->release(); |
1308 | return result; |
1309 | } |
1310 | |
1311 | /********************************************************************* |
1312 | *********************************************************************/ |
1313 | OSObject * |
1314 | OSMetaClass::allocClassWithName(const char * name) |
1315 | { |
1316 | const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(cString: name); |
1317 | OSObject * result = allocClassWithName(name: tmpKey); |
1318 | tmpKey->release(); |
1319 | return result; |
1320 | } |
1321 | |
1322 | |
1323 | /********************************************************************* |
1324 | *********************************************************************/ |
1325 | OSMetaClassBase * |
1326 | OSMetaClass::checkMetaCastWithName( |
1327 | const OSSymbol * name, |
1328 | const OSMetaClassBase * in) |
1329 | { |
1330 | OSMetaClassBase * result = NULL; |
1331 | |
1332 | const OSMetaClass * const meta = getMetaClassWithName(name); |
1333 | |
1334 | if (meta) { |
1335 | result = meta->checkMetaCast(object: in); |
1336 | } |
1337 | |
1338 | return result; |
1339 | } |
1340 | |
1341 | /********************************************************************* |
1342 | *********************************************************************/ |
1343 | OSMetaClassBase * |
1344 | OSMetaClass:: |
1345 | checkMetaCastWithName( |
1346 | const OSString * name, |
1347 | const OSMetaClassBase * in) |
1348 | { |
1349 | const OSSymbol * tmpKey = OSSymbol::withString(aString: name); |
1350 | OSMetaClassBase * result = checkMetaCastWithName(name: tmpKey, in); |
1351 | |
1352 | tmpKey->release(); |
1353 | return result; |
1354 | } |
1355 | |
1356 | /********************************************************************* |
1357 | *********************************************************************/ |
1358 | OSMetaClassBase * |
1359 | OSMetaClass::checkMetaCastWithName( |
1360 | const char * name, |
1361 | const OSMetaClassBase * in) |
1362 | { |
1363 | const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(cString: name); |
1364 | OSMetaClassBase * result = checkMetaCastWithName(name: tmpKey, in); |
1365 | |
1366 | tmpKey->release(); |
1367 | return result; |
1368 | } |
1369 | |
1370 | /********************************************************************* |
1371 | * OSMetaClass::checkMetaCast() |
1372 | * Check to see if the 'check' object has this object in its metaclass chain. |
1373 | * Returns check if it is indeed a kind of the current meta class, 0 otherwise. |
1374 | * |
1375 | * Generally this method is not invoked directly but is used to implement |
1376 | * the OSMetaClassBase::metaCast member function. |
1377 | * |
1378 | * See also OSMetaClassBase::metaCast |
1379 | *********************************************************************/ |
1380 | OSMetaClassBase * |
1381 | OSMetaClass::checkMetaCast( |
1382 | const OSMetaClassBase * check) const |
1383 | { |
1384 | const OSMetaClass * const toMeta = this; |
1385 | const OSMetaClass * fromMeta; |
1386 | |
1387 | for (fromMeta = check->getMetaClass();; fromMeta = fromMeta->superClassLink) { |
1388 | if (toMeta == fromMeta) { |
1389 | return const_cast<OSMetaClassBase *>(check); // Discard const |
1390 | } |
1391 | if (!fromMeta->superClassLink) { |
1392 | break; |
1393 | } |
1394 | } |
1395 | |
1396 | return NULL; |
1397 | } |
1398 | |
1399 | /********************************************************************* |
1400 | *********************************************************************/ |
1401 | __dead2 |
1402 | void |
1403 | OSMetaClass::reservedCalled(int ind) const |
1404 | { |
1405 | const char * cname = className->getCStringNoCopy(); |
1406 | panic("%s::_RESERVED%s%d called." , cname, cname, ind); |
1407 | } |
1408 | |
1409 | /********************************************************************* |
1410 | *********************************************************************/ |
1411 | const |
1412 | OSMetaClass * |
1413 | OSMetaClass::getSuperClass() const |
1414 | { |
1415 | return superClassLink; |
1416 | } |
1417 | |
1418 | /********************************************************************* |
1419 | *********************************************************************/ |
1420 | const OSSymbol * |
1421 | OSMetaClass::getKmodName() const |
1422 | { |
1423 | OSKext * myKext = reserved ? reserved->kext : NULL; |
1424 | if (myKext) { |
1425 | return myKext->getIdentifier(); |
1426 | } |
1427 | return OSSymbol::withCStringNoCopy(cString: "unknown" ); |
1428 | } |
1429 | |
1430 | /********************************************************************* |
1431 | *********************************************************************/ |
1432 | OSKext * |
1433 | OSMetaClass::getKext() const |
1434 | { |
1435 | return reserved ? reserved->kext : NULL; |
1436 | } |
1437 | |
1438 | /********************************************************************* |
1439 | *********************************************************************/ |
1440 | unsigned int |
1441 | OSMetaClass::getInstanceCount() const |
1442 | { |
1443 | return instanceCount; |
1444 | } |
1445 | |
1446 | /********************************************************************* |
1447 | *********************************************************************/ |
1448 | /* static */ |
1449 | void |
1450 | OSMetaClass::printInstanceCounts() |
1451 | { |
1452 | OSCollectionIterator * classes; |
1453 | OSSymbol * className; |
1454 | OSMetaClass * meta; |
1455 | |
1456 | IOLockLock(sAllClassesLock); |
1457 | classes = OSCollectionIterator::withCollection(inColl: sAllClassesDict); |
1458 | assert(classes); |
1459 | |
1460 | while ((className = (OSSymbol *)classes->getNextObject())) { |
1461 | meta = (OSMetaClass *)sAllClassesDict->getObject(aKey: className); |
1462 | assert(meta); |
1463 | |
1464 | printf("%24s count: %03d x 0x%03x = 0x%06x\n" , |
1465 | className->getCStringNoCopy(), |
1466 | meta->getInstanceCount(), |
1467 | meta->getClassSize(), |
1468 | meta->getInstanceCount() * meta->getClassSize()); |
1469 | } |
1470 | printf("\n" ); |
1471 | classes->release(); |
1472 | IOLockUnlock(sAllClassesLock); |
1473 | return; |
1474 | } |
1475 | |
1476 | /********************************************************************* |
1477 | *********************************************************************/ |
1478 | OSDictionary * |
1479 | OSMetaClass::getClassDictionary() |
1480 | { |
1481 | panic("OSMetaClass::getClassDictionary() is obsoleted." ); |
1482 | return NULL; |
1483 | } |
1484 | |
1485 | /********************************************************************* |
1486 | *********************************************************************/ |
1487 | bool |
1488 | OSMetaClass::serialize(__unused OSSerialize * s) const |
1489 | { |
1490 | panic("OSMetaClass::serialize(): Obsoleted" ); |
1491 | return false; |
1492 | } |
1493 | |
1494 | /********************************************************************* |
1495 | *********************************************************************/ |
1496 | /* static */ |
1497 | void |
1498 | OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary) |
1499 | { |
1500 | OSDictionary * classDict = NULL; |
1501 | |
1502 | IOLockLock(sAllClassesLock); |
1503 | |
1504 | classDict = OSDictionary::withCapacity(capacity: sAllClassesDict->getCount()); |
1505 | if (!classDict) { |
1506 | goto finish; |
1507 | } |
1508 | |
1509 | do { |
1510 | OSCollectionIterator * classes; |
1511 | const OSSymbol * className; |
1512 | |
1513 | classes = OSCollectionIterator::withCollection(inColl: sAllClassesDict); |
1514 | if (!classes) { |
1515 | break; |
1516 | } |
1517 | |
1518 | while ((className = (const OSSymbol *)classes->getNextObject())) { |
1519 | const OSMetaClass * meta; |
1520 | OSNumber * count; |
1521 | |
1522 | meta = (OSMetaClass *)sAllClassesDict->getObject(aKey: className); |
1523 | count = OSNumber::withNumber(value: meta->getInstanceCount(), numberOfBits: 32); |
1524 | if (count) { |
1525 | classDict->setObject(aKey: className, anObject: count); |
1526 | count->release(); |
1527 | } |
1528 | } |
1529 | classes->release(); |
1530 | |
1531 | serializeDictionary->setObject(aKey: "Classes" , anObject: classDict); |
1532 | } while (0); |
1533 | |
1534 | finish: |
1535 | OSSafeReleaseNULL(classDict); |
1536 | |
1537 | IOLockUnlock(sAllClassesLock); |
1538 | |
1539 | return; |
1540 | } |
1541 | |
1542 | |
1543 | /********************************************************************* |
1544 | *********************************************************************/ |
1545 | |
1546 | #if IOTRACKING |
1547 | |
1548 | __typed_allocators_ignore_push |
1549 | |
1550 | void * |
1551 | OSMetaClass::trackedNew(size_t size) |
1552 | { |
1553 | IOTracking * mem; |
1554 | |
1555 | mem = (typeof(mem))kheap_alloc(KHEAP_DEFAULT, size + sizeof(IOTracking), |
1556 | Z_VM_TAG_BT(Z_WAITOK, VM_KERN_MEMORY_LIBKERN)); |
1557 | assert(mem); |
1558 | if (!mem) { |
1559 | return mem; |
1560 | } |
1561 | |
1562 | memset(mem, 0, size + sizeof(IOTracking)); |
1563 | mem++; |
1564 | |
1565 | OSIVAR_ACCUMSIZE(size); |
1566 | |
1567 | return mem; |
1568 | } |
1569 | |
1570 | void |
1571 | OSMetaClass::trackedDelete(void * instance, size_t size) |
1572 | { |
1573 | IOTracking * mem = (typeof(mem))instance; mem--; |
1574 | |
1575 | kheap_free(KHEAP_DEFAULT, mem, size + sizeof(IOTracking)); |
1576 | OSIVAR_ACCUMSIZE(-size); |
1577 | } |
1578 | |
1579 | __typed_allocators_ignore_pop |
1580 | |
1581 | void |
1582 | OSMetaClass::trackedInstance(OSObject * instance) const |
1583 | { |
1584 | IOTracking * mem = (typeof(mem))instance; mem--; |
1585 | |
1586 | return IOTrackingAdd(reserved->tracking, mem, classSize, false, VM_KERN_MEMORY_NONE); |
1587 | } |
1588 | |
1589 | void |
1590 | OSMetaClass::trackedFree(OSObject * instance) const |
1591 | { |
1592 | IOTracking * mem = (typeof(mem))instance; mem--; |
1593 | |
1594 | return IOTrackingRemove(reserved->tracking, mem, classSize); |
1595 | } |
1596 | |
1597 | void |
1598 | OSMetaClass::trackedAccumSize(OSObject * instance, size_t size) const |
1599 | { |
1600 | IOTracking * mem = (typeof(mem))instance; mem--; |
1601 | |
1602 | return IOTrackingAccumSize(reserved->tracking, mem, size); |
1603 | } |
1604 | |
1605 | IOTrackingQueue * |
1606 | OSMetaClass::getTracking() const |
1607 | { |
1608 | return reserved->tracking; |
1609 | } |
1610 | |
1611 | #endif /* IOTRACKING */ |
1612 | |