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
;
95 /*********************************************************************
96 *********************************************************************/
98 kern_os_malloc(size_t size
)
101 size_t memsize
= sizeof (*mem
) + size
;
107 mem
= (struct _mhead
*)kalloc_tag_bt(memsize
, VM_KERN_MEMORY_LIBKERN
);
113 debug_iomalloc_size
+= memsize
;
117 bzero(mem
->dat
, size
);
122 /*********************************************************************
123 *********************************************************************/
125 kern_os_free(void * addr
)
133 hdr
= (struct _mhead
*)addr
;
137 debug_iomalloc_size
-= hdr
->mlen
;
141 memset((vm_offset_t
)hdr
, 0xbb, hdr
->mlen
);
143 kfree(hdr
, hdr
->mlen
);
147 /*********************************************************************
148 *********************************************************************/
154 struct _mhead
* ohdr
;
155 struct _mhead
* nmem
;
156 size_t nmemsize
, osize
;
159 return (kern_os_malloc(nsize
));
162 ohdr
= (struct _mhead
*)addr
;
164 osize
= ohdr
->mlen
- sizeof(*ohdr
);
165 if (nsize
== osize
) {
174 nmemsize
= sizeof (*nmem
) + nsize
;
175 nmem
= (struct _mhead
*) kalloc_tag_bt(nmemsize
, VM_KERN_MEMORY_LIBKERN
);
182 debug_iomalloc_size
+= (nmemsize
- ohdr
->mlen
);
185 nmem
->mlen
= nmemsize
;
187 (void) memset(&nmem
->dat
[osize
], 0, nsize
- osize
);
189 (void)memcpy(nmem
->dat
, ohdr
->dat
, (nsize
> osize
) ? osize
: nsize
);
190 kfree(ohdr
, ohdr
->mlen
);
195 /*********************************************************************
196 *********************************************************************/
198 kern_os_malloc_size(void * addr
)
206 hdr
= (struct _mhead
*) addr
; hdr
--;
207 return hdr
->mlen
- sizeof (struct _mhead
);
211 #pragma mark C++ Runtime Load/Unload
212 #endif /* PRAGMA_MARK */
213 /*********************************************************************
214 * kern_os C++ Runtime Load/Unload
215 *********************************************************************/
217 /*********************************************************************
218 *********************************************************************/
220 void __cxa_pure_virtual( void ) { panic("%s", __FUNCTION__
); }
222 void __pure_virtual( void ) { panic("%s", __FUNCTION__
); }
225 typedef void (*structor_t
)(void);
227 /*********************************************************************
228 *********************************************************************/
230 sectionIsDestructor(kernel_section_t
* section
)
234 result
= !strncmp(section
->sectname
, SECT_MODTERMFUNC
,
235 sizeof(SECT_MODTERMFUNC
) - 1);
237 result
= result
|| !strncmp(section
->sectname
, SECT_DESTRUCTOR
,
238 sizeof(SECT_DESTRUCTOR
) - 1);
244 /*********************************************************************
245 *********************************************************************/
247 sectionIsConstructor(kernel_section_t
* section
)
251 result
= !strncmp(section
->sectname
, SECT_MODINITFUNC
,
252 sizeof(SECT_MODINITFUNC
) - 1);
254 result
= result
|| !strncmp(section
->sectname
, SECT_CONSTRUCTOR
,
255 sizeof(SECT_CONSTRUCTOR
) - 1);
262 /*********************************************************************
263 * OSRuntimeUnloadCPPForSegment()
265 * Given a pointer to a mach object segment, iterate the segment to
266 * obtain a destructor section for C++ objects, and call each of the
268 *********************************************************************/
271 OSRuntimeUnloadCPPForSegmentInKmod(
272 kernel_segment_command_t
* segment
,
273 kmod_info_t
* kmodInfo
)
276 kernel_section_t
* section
= NULL
; // do not free
277 OSKext
* theKext
= NULL
; // must release
279 if (gKernelCPPInitialized
&& kmodInfo
) {
280 theKext
= OSKext::lookupKextWithIdentifier(kmodInfo
->name
);
283 for (section
= firstsect(segment
);
285 section
= nextsect(segment
, section
)) {
287 if (sectionIsDestructor(section
)) {
288 structor_t
* destructors
= (structor_t
*)section
->addr
;
291 int num_destructors
= section
->size
/ sizeof(structor_t
);
292 int hit_null_destructor
= 0;
294 for (int i
= 0; i
< num_destructors
; i
++) {
295 if (destructors
[i
]) {
297 } else if (!hit_null_destructor
) {
298 hit_null_destructor
= 1;
299 OSRuntimeLog(theKext
, kOSRuntimeLogSpec
,
300 "Null destructor in kext %s segment %s!",
301 kmodInfo
? kmodInfo
->name
: "(unknown)",
305 } /* if (destructors) */
306 } /* if (strncmp...) */
307 } /* for (section...) */
309 OSSafeRelease(theKext
);
314 OSRuntimeUnloadCPPForSegment(kernel_segment_command_t
* segment
) {
315 OSRuntimeUnloadCPPForSegmentInKmod(segment
, NULL
);
318 /*********************************************************************
319 *********************************************************************/
322 kmod_info_t
* kmodInfo
,
323 void * data __unused
)
325 if (kmodInfo
&& kmodInfo
->address
) {
327 kernel_segment_command_t
* segment
;
328 kernel_mach_header_t
* header
;
330 OSSymbol::checkForPageUnload((void *)kmodInfo
->address
,
331 (void *)(kmodInfo
->address
+ kmodInfo
->size
));
333 header
= (kernel_mach_header_t
*)kmodInfo
->address
;
334 segment
= firstsegfromheader(header
);
336 for (segment
= firstsegfromheader(header
);
338 segment
= nextsegfromheader(header
, segment
)) {
340 OSRuntimeUnloadCPPForSegmentInKmod(segment
, kmodInfo
);
347 /*********************************************************************
348 *********************************************************************/
350 OSRuntimeFinalizeCPP(
351 kmod_info_t
* kmodInfo
,
352 void * data __unused
)
354 kern_return_t result
= KMOD_RETURN_FAILURE
;
355 void * metaHandle
= NULL
; // do not free
356 OSKext
* theKext
= NULL
; // must release
358 if (gKernelCPPInitialized
) {
359 theKext
= OSKext::lookupKextWithIdentifier(kmodInfo
->name
);
362 if (theKext
&& !theKext
->isCPPInitialized()) {
363 result
= KMOD_RETURN_SUCCESS
;
367 /* OSKext checks for this condition now, but somebody might call
368 * this function directly (the symbol is exported....).
370 if (OSMetaClass::modHasInstance(kmodInfo
->name
)) {
371 // xxx - Don't log under errors? this is more of an info thing
372 OSRuntimeLog(theKext
, kOSRuntimeLogSpec
,
373 "Can't tear down kext %s C++; classes have instances:",
375 OSKext::reportOSMetaClassInstances(kmodInfo
->name
, kOSRuntimeLogSpec
);
376 result
= kOSMetaClassHasInstances
;
380 /* Tell the meta class system that we are starting to unload.
381 * metaHandle isn't actually needed on the finalize path,
382 * so we don't check it here, even though OSMetaClass::postModLoad() will
383 * return a failure (it only does actual work on the init path anyhow).
385 metaHandle
= OSMetaClass::preModLoad(kmodInfo
->name
);
386 OSRuntimeUnloadCPP(kmodInfo
, 0);
387 (void)OSMetaClass::postModLoad(metaHandle
);
390 theKext
->setCPPInitialized(false);
392 result
= KMOD_RETURN_SUCCESS
;
394 OSSafeRelease(theKext
);
398 // Functions used by the extenTools/kmod library project
400 /*********************************************************************
401 *********************************************************************/
403 OSRuntimeInitializeCPP(
404 kmod_info_t
* kmodInfo
,
405 void * data __unused
)
407 kern_return_t result
= KMOD_RETURN_FAILURE
;
408 OSKext
* theKext
= NULL
; // must release
409 kernel_mach_header_t
* header
= NULL
;
410 void * metaHandle
= NULL
; // do not free
411 bool load_success
= true;
412 kernel_segment_command_t
* segment
= NULL
; // do not free
413 kernel_segment_command_t
* failure_segment
= NULL
; // do not free
415 if (!kmodInfo
|| !kmodInfo
->address
) {
416 result
= kOSKextReturnInvalidArgument
;
420 if (gKernelCPPInitialized
) {
421 theKext
= OSKext::lookupKextWithIdentifier(kmodInfo
->name
);
424 if (theKext
&& theKext
->isCPPInitialized()) {
425 result
= KMOD_RETURN_SUCCESS
;
429 header
= (kernel_mach_header_t
*)kmodInfo
->address
;
431 /* Tell the meta class system that we are starting the load
433 metaHandle
= OSMetaClass::preModLoad(kmodInfo
->name
);
439 /* NO GOTO PAST HERE. */
441 /* Scan the header for all constructor sections, in any
442 * segment, and invoke the constructors within those sections.
444 for (segment
= firstsegfromheader(header
);
445 segment
!= NULL
&& load_success
;
446 segment
= nextsegfromheader(header
, segment
)) {
448 kernel_section_t
* section
;
450 /* Record the current segment in the event of a failure.
452 failure_segment
= segment
;
454 for (section
= firstsect(segment
);
456 section
= nextsect(segment
, section
)) {
458 if (sectionIsConstructor(section
)) {
459 structor_t
* constructors
= (structor_t
*)section
->addr
;
462 int num_constructors
= section
->size
/ sizeof(structor_t
);
463 int hit_null_constructor
= 0;
466 i
< num_constructors
&&
467 OSMetaClass::checkModLoad(metaHandle
);
470 if (constructors
[i
]) {
471 (*constructors
[i
])();
472 } else if (!hit_null_constructor
) {
473 hit_null_constructor
= 1;
474 OSRuntimeLog(theKext
, kOSRuntimeLogSpec
,
475 "Null constructor in kext %s segment %s!",
476 kmodInfo
->name
, section
->segname
);
479 load_success
= OSMetaClass::checkModLoad(metaHandle
);
482 } /* if (constructors) */
483 } /* if (strncmp...) */
484 } /* for (section...) */
485 } /* for (segment...) */
487 /* We failed so call all of the destructors. We must do this before
488 * calling OSMetaClass::postModLoad() as the OSMetaClass destructors
489 * will alter state (in the metaHandle) used by that function.
493 /* Scan the header for all destructor sections, in any
494 * segment, and invoke the constructors within those sections.
496 for (segment
= firstsegfromheader(header
);
497 segment
!= failure_segment
&& segment
!= 0;
498 segment
= nextsegfromheader(header
, segment
)) {
500 OSRuntimeUnloadCPPForSegment(segment
);
502 } /* for (segment...) */
505 /* Now, regardless of success so far, do the post-init registration
506 * and cleanup. If we had to call the unloadCPP function, static
507 * destructors have removed classes from the stalled list so no
508 * metaclasses will actually be registered.
510 result
= OSMetaClass::postModLoad(metaHandle
);
512 /* If we've otherwise been fine up to now, but OSMetaClass::postModLoad()
513 * fails (typically due to a duplicate class), tear down all the C++
514 * stuff from the kext. This isn't necessary for libkern/OSMetaClass stuff,
515 * but may be necessary for other C++ code. We ignore the return value
516 * because it's only a fail when there are existing instances of libkern
517 * classes, and there had better not be any created on the C++ init path.
519 if (load_success
&& result
!= KMOD_RETURN_SUCCESS
) {
520 (void)OSRuntimeFinalizeCPP(kmodInfo
, NULL
);
523 if (theKext
&& load_success
&& result
== KMOD_RETURN_SUCCESS
) {
524 theKext
->setCPPInitialized(true);
527 OSSafeRelease(theKext
);
532 #pragma mark Libkern Init
533 #endif /* PRAGMA_MARK */
534 /*********************************************************************
536 *********************************************************************/
538 /*********************************************************************
539 *********************************************************************/
540 extern lck_grp_t
* IOLockGroup
;
541 extern kmod_info_t g_kernel_kmod_info
;
543 void OSlibkernInit(void)
545 // This must be called before calling OSRuntimeInitializeCPP.
546 OSMetaClassBase::initialize();
548 g_kernel_kmod_info
.address
= (vm_address_t
) &_mh_execute_header
;
549 if (kOSReturnSuccess
!= OSRuntimeInitializeCPP(&g_kernel_kmod_info
, 0)) {
550 panic("OSRuntime: C++ runtime failed to initialize.");
553 gKernelCPPInitialized
= true;
561 #pragma mark C++ Allocators & Deallocators
562 #endif /* PRAGMA_MARK */
563 /*********************************************************************
564 * C++ Allocators & Deallocators
565 *********************************************************************/
567 operator new(size_t size
)
568 #if __cplusplus >= 201103L
574 result
= (void *) kern_os_malloc(size
);
579 operator delete(void * addr
)
580 #if __cplusplus >= 201103L
589 operator new[](unsigned long sz
)
590 #if __cplusplus >= 201103L
595 return kern_os_malloc(sz
);
599 operator delete[](void * ptr
)
600 #if __cplusplus >= 201103L
610 /* PR-6481964 - The compiler is going to check for size overflows in calls to
611 * new[], and if there is an overflow, it will call __throw_length_error.
612 * This is an unrecoverable error by the C++ standard, so we must panic here.
614 * We have to put the function inside the std namespace because of how the
615 * compiler expects the name to be mangled.
620 __throw_length_error(const char *msg __unused
)
622 panic("Size of array created by new[] has overflowed");