2 * Copyright (c) 2000,2008-2009 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1997 Apple Inc.
32 #include <libkern/c++/OSMetaClass.h>
33 #include <libkern/c++/OSKext.h>
34 #include <libkern/c++/OSLib.h>
35 #include <libkern/c++/OSSymbol.h>
36 #include <IOKit/IOKitDebug.h>
38 #include <sys/cdefs.h>
43 #include <mach/mach_types.h>
44 #include <libkern/kernel_mach_header.h>
48 #pragma mark Constants &c.
49 #endif /* PRAGMA_MARK */
50 OSKextLogSpec kOSRuntimeLogSpec
=
51 kOSKextLogErrorLevel
|
53 kOSKextLogKextBookkeepingFlag
;
56 #pragma mark Logging Bootstrap
57 #endif /* PRAGMA_MARK */
58 /*********************************************************************
59 * kern_os Logging Bootstrap
61 * We can't call in to OSKext until the kernel's C++ environment is up
62 * and running, so let's mask those references with a check variable.
63 * We print unconditionally if C++ isn't up, but if that's the case
64 * we've generally hit a serious error in kernel init!
65 *********************************************************************/
66 static bool gKernelCPPInitialized
= false;
68 #define OSRuntimeLog(kext, flags, format, args...) \
70 if (gKernelCPPInitialized) { \
71 OSKextLog((kext), (flags), (format), ## args); \
73 printf((format), ## args); \
78 #pragma mark kern_os Allocator Package
79 #endif /* PRAGMA_MARK */
80 /*********************************************************************
81 * kern_os Allocator Package
82 *********************************************************************/
84 /*********************************************************************
85 *********************************************************************/
87 extern int debug_iomalloc_size
;
90 /*********************************************************************
91 *********************************************************************/
93 kern_os_malloc(size_t size
)
100 mem
= kallocp_tag_bt((vm_size_t
*)&size
, VM_KERN_MEMORY_LIBKERN
);
106 OSAddAtomic(size
, &debug_iomalloc_size
);
114 /*********************************************************************
115 *********************************************************************/
117 kern_os_free(void * addr
)
120 size
= kalloc_size(addr
);
122 OSAddAtomic(-size
, &debug_iomalloc_size
);
128 /*********************************************************************
129 *********************************************************************/
139 return (kern_os_malloc(nsize
));
142 osize
= kalloc_size(addr
);
143 if (nsize
== osize
) {
152 nmem
= kallocp_tag_bt((vm_size_t
*)&nsize
, VM_KERN_MEMORY_LIBKERN
);
159 OSAddAtomic((nsize
- osize
), &debug_iomalloc_size
);
163 (void)memset((char *)nmem
+ osize
, 0, nsize
- osize
);
165 (void)memcpy(nmem
, addr
, (nsize
> osize
) ? osize
: nsize
);
172 #pragma mark C++ Runtime Load/Unload
173 #endif /* PRAGMA_MARK */
174 /*********************************************************************
175 * kern_os C++ Runtime Load/Unload
176 *********************************************************************/
178 /*********************************************************************
179 *********************************************************************/
181 void __cxa_pure_virtual( void ) { panic("%s", __FUNCTION__
); }
183 void __pure_virtual( void ) { panic("%s", __FUNCTION__
); }
186 typedef void (*structor_t
)(void);
188 /*********************************************************************
189 *********************************************************************/
191 sectionIsDestructor(kernel_section_t
* section
)
195 result
= !strncmp(section
->sectname
, SECT_MODTERMFUNC
,
196 sizeof(SECT_MODTERMFUNC
) - 1);
198 result
= result
|| !strncmp(section
->sectname
, SECT_DESTRUCTOR
,
199 sizeof(SECT_DESTRUCTOR
) - 1);
205 /*********************************************************************
206 *********************************************************************/
208 sectionIsConstructor(kernel_section_t
* section
)
212 result
= !strncmp(section
->sectname
, SECT_MODINITFUNC
,
213 sizeof(SECT_MODINITFUNC
) - 1);
215 result
= result
|| !strncmp(section
->sectname
, SECT_CONSTRUCTOR
,
216 sizeof(SECT_CONSTRUCTOR
) - 1);
223 /*********************************************************************
224 * OSRuntimeUnloadCPPForSegment()
226 * Given a pointer to a mach object segment, iterate the segment to
227 * obtain a destructor section for C++ objects, and call each of the
229 *********************************************************************/
232 OSRuntimeUnloadCPPForSegmentInKmod(
233 kernel_segment_command_t
* segment
,
234 kmod_info_t
* kmodInfo
)
237 kernel_section_t
* section
= NULL
; // do not free
238 OSKext
* theKext
= NULL
; // must release
240 if (gKernelCPPInitialized
&& kmodInfo
) {
241 theKext
= OSKext::lookupKextWithIdentifier(kmodInfo
->name
);
244 for (section
= firstsect(segment
);
246 section
= nextsect(segment
, section
)) {
248 if (sectionIsDestructor(section
)) {
249 structor_t
* destructors
= (structor_t
*)section
->addr
;
252 int num_destructors
= section
->size
/ sizeof(structor_t
);
253 int hit_null_destructor
= 0;
255 for (int i
= 0; i
< num_destructors
; i
++) {
256 if (destructors
[i
]) {
258 } else if (!hit_null_destructor
) {
259 hit_null_destructor
= 1;
260 OSRuntimeLog(theKext
, kOSRuntimeLogSpec
,
261 "Null destructor in kext %s segment %s!",
262 kmodInfo
? kmodInfo
->name
: "(unknown)",
266 } /* if (destructors) */
267 } /* if (strncmp...) */
268 } /* for (section...) */
270 OSSafeReleaseNULL(theKext
);
275 OSRuntimeUnloadCPPForSegment(kernel_segment_command_t
* segment
) {
276 OSRuntimeUnloadCPPForSegmentInKmod(segment
, NULL
);
279 /*********************************************************************
280 *********************************************************************/
283 kmod_info_t
* kmodInfo
,
284 void * data __unused
)
286 if (kmodInfo
&& kmodInfo
->address
) {
288 kernel_segment_command_t
* segment
;
289 kernel_mach_header_t
* header
;
291 OSSymbol::checkForPageUnload((void *)kmodInfo
->address
,
292 (void *)(kmodInfo
->address
+ kmodInfo
->size
));
294 header
= (kernel_mach_header_t
*)kmodInfo
->address
;
295 segment
= firstsegfromheader(header
);
297 for (segment
= firstsegfromheader(header
);
299 segment
= nextsegfromheader(header
, segment
)) {
301 OSRuntimeUnloadCPPForSegmentInKmod(segment
, kmodInfo
);
308 /*********************************************************************
309 *********************************************************************/
311 OSRuntimeFinalizeCPP(
312 kmod_info_t
* kmodInfo
,
313 void * data __unused
)
315 kern_return_t result
= KMOD_RETURN_FAILURE
;
316 void * metaHandle
= NULL
; // do not free
317 OSKext
* theKext
= NULL
; // must release
319 if (gKernelCPPInitialized
) {
320 theKext
= OSKext::lookupKextWithIdentifier(kmodInfo
->name
);
323 if (theKext
&& !theKext
->isCPPInitialized()) {
324 result
= KMOD_RETURN_SUCCESS
;
328 /* OSKext checks for this condition now, but somebody might call
329 * this function directly (the symbol is exported....).
331 if (OSMetaClass::modHasInstance(kmodInfo
->name
)) {
332 // xxx - Don't log under errors? this is more of an info thing
333 OSRuntimeLog(theKext
, kOSRuntimeLogSpec
,
334 "Can't tear down kext %s C++; classes have instances:",
336 OSKext::reportOSMetaClassInstances(kmodInfo
->name
, kOSRuntimeLogSpec
);
337 result
= kOSMetaClassHasInstances
;
341 /* Tell the meta class system that we are starting to unload.
342 * metaHandle isn't actually needed on the finalize path,
343 * so we don't check it here, even though OSMetaClass::postModLoad() will
344 * return a failure (it only does actual work on the init path anyhow).
346 metaHandle
= OSMetaClass::preModLoad(kmodInfo
->name
);
347 OSRuntimeUnloadCPP(kmodInfo
, 0);
348 (void)OSMetaClass::postModLoad(metaHandle
);
351 theKext
->setCPPInitialized(false);
353 result
= KMOD_RETURN_SUCCESS
;
355 OSSafeReleaseNULL(theKext
);
359 // Functions used by the extenTools/kmod library project
361 /*********************************************************************
362 *********************************************************************/
364 OSRuntimeInitializeCPP(
365 kmod_info_t
* kmodInfo
,
366 void * data __unused
)
368 kern_return_t result
= KMOD_RETURN_FAILURE
;
369 OSKext
* theKext
= NULL
; // must release
370 kernel_mach_header_t
* header
= NULL
;
371 void * metaHandle
= NULL
; // do not free
372 bool load_success
= true;
373 kernel_segment_command_t
* segment
= NULL
; // do not free
374 kernel_segment_command_t
* failure_segment
= NULL
; // do not free
376 if (!kmodInfo
|| !kmodInfo
->address
) {
377 result
= kOSKextReturnInvalidArgument
;
381 if (gKernelCPPInitialized
) {
382 theKext
= OSKext::lookupKextWithIdentifier(kmodInfo
->name
);
385 if (theKext
&& theKext
->isCPPInitialized()) {
386 result
= KMOD_RETURN_SUCCESS
;
390 header
= (kernel_mach_header_t
*)kmodInfo
->address
;
392 /* Tell the meta class system that we are starting the load
394 metaHandle
= OSMetaClass::preModLoad(kmodInfo
->name
);
400 /* NO GOTO PAST HERE. */
402 /* Scan the header for all constructor sections, in any
403 * segment, and invoke the constructors within those sections.
405 for (segment
= firstsegfromheader(header
);
406 segment
!= NULL
&& load_success
;
407 segment
= nextsegfromheader(header
, segment
)) {
409 kernel_section_t
* section
;
411 /* Record the current segment in the event of a failure.
413 failure_segment
= segment
;
415 for (section
= firstsect(segment
);
417 section
= nextsect(segment
, section
)) {
419 if (sectionIsConstructor(section
)) {
420 structor_t
* constructors
= (structor_t
*)section
->addr
;
423 int num_constructors
= section
->size
/ sizeof(structor_t
);
424 int hit_null_constructor
= 0;
427 i
< num_constructors
&&
428 OSMetaClass::checkModLoad(metaHandle
);
431 if (constructors
[i
]) {
432 (*constructors
[i
])();
433 } else if (!hit_null_constructor
) {
434 hit_null_constructor
= 1;
435 OSRuntimeLog(theKext
, kOSRuntimeLogSpec
,
436 "Null constructor in kext %s segment %s!",
437 kmodInfo
->name
, section
->segname
);
440 load_success
= OSMetaClass::checkModLoad(metaHandle
);
443 } /* if (constructors) */
444 } /* if (strncmp...) */
445 } /* for (section...) */
446 } /* for (segment...) */
448 /* We failed so call all of the destructors. We must do this before
449 * calling OSMetaClass::postModLoad() as the OSMetaClass destructors
450 * will alter state (in the metaHandle) used by that function.
454 /* Scan the header for all destructor sections, in any
455 * segment, and invoke the constructors within those sections.
457 for (segment
= firstsegfromheader(header
);
458 segment
!= failure_segment
&& segment
!= 0;
459 segment
= nextsegfromheader(header
, segment
)) {
461 OSRuntimeUnloadCPPForSegment(segment
);
463 } /* for (segment...) */
466 /* Now, regardless of success so far, do the post-init registration
467 * and cleanup. If we had to call the unloadCPP function, static
468 * destructors have removed classes from the stalled list so no
469 * metaclasses will actually be registered.
471 result
= OSMetaClass::postModLoad(metaHandle
);
473 /* If we've otherwise been fine up to now, but OSMetaClass::postModLoad()
474 * fails (typically due to a duplicate class), tear down all the C++
475 * stuff from the kext. This isn't necessary for libkern/OSMetaClass stuff,
476 * but may be necessary for other C++ code. We ignore the return value
477 * because it's only a fail when there are existing instances of libkern
478 * classes, and there had better not be any created on the C++ init path.
480 if (load_success
&& result
!= KMOD_RETURN_SUCCESS
) {
481 (void)OSRuntimeFinalizeCPP(kmodInfo
, NULL
);
484 if (theKext
&& load_success
&& result
== KMOD_RETURN_SUCCESS
) {
485 theKext
->setCPPInitialized(true);
488 OSSafeReleaseNULL(theKext
);
493 #pragma mark Libkern Init
494 #endif /* PRAGMA_MARK */
495 /*********************************************************************
497 *********************************************************************/
499 /*********************************************************************
500 *********************************************************************/
501 extern lck_grp_t
* IOLockGroup
;
502 extern kmod_info_t g_kernel_kmod_info
;
504 void OSlibkernInit(void)
506 // This must be called before calling OSRuntimeInitializeCPP.
507 OSMetaClassBase::initialize();
509 g_kernel_kmod_info
.address
= (vm_address_t
) &_mh_execute_header
;
510 if (kOSReturnSuccess
!= OSRuntimeInitializeCPP(&g_kernel_kmod_info
, 0)) {
511 panic("OSRuntime: C++ runtime failed to initialize.");
514 gKernelCPPInitialized
= true;
522 #pragma mark C++ Allocators & Deallocators
523 #endif /* PRAGMA_MARK */
524 /*********************************************************************
525 * C++ Allocators & Deallocators
526 *********************************************************************/
528 operator new(size_t size
)
529 #if __cplusplus >= 201103L
535 result
= (void *) kern_os_malloc(size
);
540 operator delete(void * addr
)
541 #if __cplusplus >= 201103L
550 operator new[](unsigned long sz
)
551 #if __cplusplus >= 201103L
556 return kern_os_malloc(sz
);
560 operator delete[](void * ptr
)
561 #if __cplusplus >= 201103L
571 /* PR-6481964 - The compiler is going to check for size overflows in calls to
572 * new[], and if there is an overflow, it will call __throw_length_error.
573 * This is an unrecoverable error by the C++ standard, so we must panic here.
575 * We have to put the function inside the std namespace because of how the
576 * compiler expects the name to be mangled.
581 __throw_length_error(const char *msg __unused
)
583 panic("Size of array created by new[] has overflowed");