]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSRuntime.cpp
xnu-3247.1.106.tar.gz
[apple/xnu.git] / libkern / c++ / OSRuntime.cpp
1 /*
2 * Copyright (c) 2000,2008-2009 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 /*
29 * Copyright (c) 1997 Apple Inc.
30 *
31 */
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>
37
38 #include <sys/cdefs.h>
39
40 __BEGIN_DECLS
41
42 #include <string.h>
43 #include <mach/mach_types.h>
44 #include <libkern/kernel_mach_header.h>
45 #include <stdarg.h>
46
47 #if PRAGMA_MARK
48 #pragma mark Constants &c.
49 #endif /* PRAGMA_MARK */
50 OSKextLogSpec kOSRuntimeLogSpec =
51 kOSKextLogErrorLevel |
52 kOSKextLogLoadFlag |
53 kOSKextLogKextBookkeepingFlag;
54
55 #if PRAGMA_MARK
56 #pragma mark Logging Bootstrap
57 #endif /* PRAGMA_MARK */
58 /*********************************************************************
59 * kern_os Logging Bootstrap
60 *
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;
67
68 #define OSRuntimeLog(kext, flags, format, args...) \
69 do { \
70 if (gKernelCPPInitialized) { \
71 OSKextLog((kext), (flags), (format), ## args); \
72 } else { \
73 printf((format), ## args); \
74 } \
75 } while (0)
76
77 #if PRAGMA_MARK
78 #pragma mark kern_os Allocator Package
79 #endif /* PRAGMA_MARK */
80 /*********************************************************************
81 * kern_os Allocator Package
82 *********************************************************************/
83
84 /*********************************************************************
85 *********************************************************************/
86 #if OSALLOCDEBUG
87 extern int debug_iomalloc_size;
88 #endif
89
90 struct _mhead {
91 size_t mlen;
92 char dat[0];
93 };
94
95 /*********************************************************************
96 *********************************************************************/
97 void *
98 kern_os_malloc(size_t size)
99 {
100 struct _mhead * mem;
101 size_t memsize = sizeof (*mem) + size ;
102
103 if (size == 0) {
104 return (0);
105 }
106
107 mem = (struct _mhead *)kalloc_tag_bt(memsize, VM_KERN_MEMORY_LIBKERN);
108 if (!mem) {
109 return (0);
110 }
111
112 #if OSALLOCDEBUG
113 debug_iomalloc_size += memsize;
114 #endif
115
116 mem->mlen = memsize;
117 bzero(mem->dat, size);
118
119 return mem->dat;
120 }
121
122 /*********************************************************************
123 *********************************************************************/
124 void
125 kern_os_free(void * addr)
126 {
127 struct _mhead * hdr;
128
129 if (!addr) {
130 return;
131 }
132
133 hdr = (struct _mhead *)addr;
134 hdr--;
135
136 #if OSALLOCDEBUG
137 debug_iomalloc_size -= hdr->mlen;
138 #endif
139
140 #if 0
141 memset((vm_offset_t)hdr, 0xbb, hdr->mlen);
142 #else
143 kfree(hdr, hdr->mlen);
144 #endif
145 }
146
147 /*********************************************************************
148 *********************************************************************/
149 void *
150 kern_os_realloc(
151 void * addr,
152 size_t nsize)
153 {
154 struct _mhead * ohdr;
155 struct _mhead * nmem;
156 size_t nmemsize, osize;
157
158 if (!addr) {
159 return (kern_os_malloc(nsize));
160 }
161
162 ohdr = (struct _mhead *)addr;
163 ohdr--;
164 osize = ohdr->mlen - sizeof(*ohdr);
165 if (nsize == osize) {
166 return (addr);
167 }
168
169 if (nsize == 0) {
170 kern_os_free(addr);
171 return (0);
172 }
173
174 nmemsize = sizeof (*nmem) + nsize ;
175 nmem = (struct _mhead *) kalloc_tag_bt(nmemsize, VM_KERN_MEMORY_LIBKERN);
176 if (!nmem){
177 kern_os_free(addr);
178 return (0);
179 }
180
181 #if OSALLOCDEBUG
182 debug_iomalloc_size += (nmemsize - ohdr->mlen);
183 #endif
184
185 nmem->mlen = nmemsize;
186 if (nsize > osize) {
187 (void) memset(&nmem->dat[osize], 0, nsize - osize);
188 }
189 (void)memcpy(nmem->dat, ohdr->dat, (nsize > osize) ? osize : nsize);
190 kfree(ohdr, ohdr->mlen);
191
192 return (nmem->dat);
193 }
194
195 /*********************************************************************
196 *********************************************************************/
197 size_t
198 kern_os_malloc_size(void * addr)
199 {
200 struct _mhead * hdr;
201
202 if (!addr) {
203 return(0);
204 }
205
206 hdr = (struct _mhead *) addr; hdr--;
207 return hdr->mlen - sizeof (struct _mhead);
208 }
209
210 #if PRAGMA_MARK
211 #pragma mark C++ Runtime Load/Unload
212 #endif /* PRAGMA_MARK */
213 /*********************************************************************
214 * kern_os C++ Runtime Load/Unload
215 *********************************************************************/
216
217 /*********************************************************************
218 *********************************************************************/
219 #if __GNUC__ >= 3
220 void __cxa_pure_virtual( void ) { panic("%s", __FUNCTION__); }
221 #else
222 void __pure_virtual( void ) { panic("%s", __FUNCTION__); }
223 #endif
224
225 typedef void (*structor_t)(void);
226
227 /*********************************************************************
228 *********************************************************************/
229 static boolean_t
230 sectionIsDestructor(kernel_section_t * section)
231 {
232 boolean_t result;
233
234 result = !strncmp(section->sectname, SECT_MODTERMFUNC,
235 sizeof(SECT_MODTERMFUNC) - 1);
236 #if !__LP64__
237 result = result || !strncmp(section->sectname, SECT_DESTRUCTOR,
238 sizeof(SECT_DESTRUCTOR) - 1);
239 #endif
240
241 return result;
242 }
243
244 /*********************************************************************
245 *********************************************************************/
246 static boolean_t
247 sectionIsConstructor(kernel_section_t * section)
248 {
249 boolean_t result;
250
251 result = !strncmp(section->sectname, SECT_MODINITFUNC,
252 sizeof(SECT_MODINITFUNC) - 1);
253 #if !__LP64__
254 result = result || !strncmp(section->sectname, SECT_CONSTRUCTOR,
255 sizeof(SECT_CONSTRUCTOR) - 1);
256 #endif
257
258 return result;
259 }
260
261
262 /*********************************************************************
263 * OSRuntimeUnloadCPPForSegment()
264 *
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
267 * destructors there.
268 *********************************************************************/
269
270 void
271 OSRuntimeUnloadCPPForSegmentInKmod(
272 kernel_segment_command_t * segment,
273 kmod_info_t * kmodInfo)
274 {
275
276 kernel_section_t * section = NULL; // do not free
277 OSKext * theKext = NULL; // must release
278
279 if (gKernelCPPInitialized && kmodInfo) {
280 theKext = OSKext::lookupKextWithIdentifier(kmodInfo->name);
281 }
282
283 for (section = firstsect(segment);
284 section != 0;
285 section = nextsect(segment, section)) {
286
287 if (sectionIsDestructor(section)) {
288 structor_t * destructors = (structor_t *)section->addr;
289
290 if (destructors) {
291 int num_destructors = section->size / sizeof(structor_t);
292 int hit_null_destructor = 0;
293
294 for (int i = 0; i < num_destructors; i++) {
295 if (destructors[i]) {
296 (*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)",
302 section->segname);
303 }
304 }
305 } /* if (destructors) */
306 } /* if (strncmp...) */
307 } /* for (section...) */
308
309 OSSafeRelease(theKext);
310 return;
311 }
312
313 void
314 OSRuntimeUnloadCPPForSegment(kernel_segment_command_t * segment) {
315 OSRuntimeUnloadCPPForSegmentInKmod(segment, NULL);
316 }
317
318 /*********************************************************************
319 *********************************************************************/
320 void
321 OSRuntimeUnloadCPP(
322 kmod_info_t * kmodInfo,
323 void * data __unused)
324 {
325 if (kmodInfo && kmodInfo->address) {
326
327 kernel_segment_command_t * segment;
328 kernel_mach_header_t * header;
329
330 OSSymbol::checkForPageUnload((void *)kmodInfo->address,
331 (void *)(kmodInfo->address + kmodInfo->size));
332
333 header = (kernel_mach_header_t *)kmodInfo->address;
334 segment = firstsegfromheader(header);
335
336 for (segment = firstsegfromheader(header);
337 segment != 0;
338 segment = nextsegfromheader(header, segment)) {
339
340 OSRuntimeUnloadCPPForSegmentInKmod(segment, kmodInfo);
341 }
342 }
343
344 return;
345 }
346
347 /*********************************************************************
348 *********************************************************************/
349 kern_return_t
350 OSRuntimeFinalizeCPP(
351 kmod_info_t * kmodInfo,
352 void * data __unused)
353 {
354 kern_return_t result = KMOD_RETURN_FAILURE;
355 void * metaHandle = NULL; // do not free
356 OSKext * theKext = NULL; // must release
357
358 if (gKernelCPPInitialized) {
359 theKext = OSKext::lookupKextWithIdentifier(kmodInfo->name);
360 }
361
362 if (theKext && !theKext->isCPPInitialized()) {
363 result = KMOD_RETURN_SUCCESS;
364 goto finish;
365 }
366
367 /* OSKext checks for this condition now, but somebody might call
368 * this function directly (the symbol is exported....).
369 */
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:",
374 kmodInfo->name);
375 OSKext::reportOSMetaClassInstances(kmodInfo->name, kOSRuntimeLogSpec);
376 result = kOSMetaClassHasInstances;
377 goto finish;
378 }
379
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).
384 */
385 metaHandle = OSMetaClass::preModLoad(kmodInfo->name);
386 OSRuntimeUnloadCPP(kmodInfo, 0);
387 (void)OSMetaClass::postModLoad(metaHandle);
388
389 if (theKext) {
390 theKext->setCPPInitialized(false);
391 }
392 result = KMOD_RETURN_SUCCESS;
393 finish:
394 OSSafeRelease(theKext);
395 return result;
396 }
397
398 // Functions used by the extenTools/kmod library project
399
400 /*********************************************************************
401 *********************************************************************/
402 kern_return_t
403 OSRuntimeInitializeCPP(
404 kmod_info_t * kmodInfo,
405 void * data __unused)
406 {
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
414
415 if (!kmodInfo || !kmodInfo->address) {
416 result = kOSKextReturnInvalidArgument;
417 goto finish;
418 }
419
420 if (gKernelCPPInitialized) {
421 theKext = OSKext::lookupKextWithIdentifier(kmodInfo->name);
422 }
423
424 if (theKext && theKext->isCPPInitialized()) {
425 result = KMOD_RETURN_SUCCESS;
426 goto finish;
427 }
428
429 header = (kernel_mach_header_t *)kmodInfo->address;
430
431 /* Tell the meta class system that we are starting the load
432 */
433 metaHandle = OSMetaClass::preModLoad(kmodInfo->name);
434 assert(metaHandle);
435 if (!metaHandle) {
436 goto finish;
437 }
438
439 /* NO GOTO PAST HERE. */
440
441 /* Scan the header for all constructor sections, in any
442 * segment, and invoke the constructors within those sections.
443 */
444 for (segment = firstsegfromheader(header);
445 segment != NULL && load_success;
446 segment = nextsegfromheader(header, segment)) {
447
448 kernel_section_t * section;
449
450 /* Record the current segment in the event of a failure.
451 */
452 failure_segment = segment;
453
454 for (section = firstsect(segment);
455 section != NULL;
456 section = nextsect(segment, section)) {
457
458 if (sectionIsConstructor(section)) {
459 structor_t * constructors = (structor_t *)section->addr;
460
461 if (constructors) {
462 int num_constructors = section->size / sizeof(structor_t);
463 int hit_null_constructor = 0;
464
465 for (int i = 0;
466 i < num_constructors &&
467 OSMetaClass::checkModLoad(metaHandle);
468 i++) {
469
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);
477 }
478 }
479 load_success = OSMetaClass::checkModLoad(metaHandle);
480
481 break;
482 } /* if (constructors) */
483 } /* if (strncmp...) */
484 } /* for (section...) */
485 } /* for (segment...) */
486
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.
490 */
491 if (!load_success) {
492
493 /* Scan the header for all destructor sections, in any
494 * segment, and invoke the constructors within those sections.
495 */
496 for (segment = firstsegfromheader(header);
497 segment != failure_segment && segment != 0;
498 segment = nextsegfromheader(header, segment)) {
499
500 OSRuntimeUnloadCPPForSegment(segment);
501
502 } /* for (segment...) */
503 }
504
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.
509 */
510 result = OSMetaClass::postModLoad(metaHandle);
511
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.
518 */
519 if (load_success && result != KMOD_RETURN_SUCCESS) {
520 (void)OSRuntimeFinalizeCPP(kmodInfo, NULL);
521 }
522
523 if (theKext && load_success && result == KMOD_RETURN_SUCCESS) {
524 theKext->setCPPInitialized(true);
525 }
526 finish:
527 OSSafeRelease(theKext);
528 return result;
529 }
530
531 #if PRAGMA_MARK
532 #pragma mark Libkern Init
533 #endif /* PRAGMA_MARK */
534 /*********************************************************************
535 * Libkern Init
536 *********************************************************************/
537
538 /*********************************************************************
539 *********************************************************************/
540 extern lck_grp_t * IOLockGroup;
541 extern kmod_info_t g_kernel_kmod_info;
542
543 void OSlibkernInit(void)
544 {
545 // This must be called before calling OSRuntimeInitializeCPP.
546 OSMetaClassBase::initialize();
547
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.");
551 }
552
553 gKernelCPPInitialized = true;
554
555 return;
556 }
557
558 __END_DECLS
559
560 #if PRAGMA_MARK
561 #pragma mark C++ Allocators & Deallocators
562 #endif /* PRAGMA_MARK */
563 /*********************************************************************
564 * C++ Allocators & Deallocators
565 *********************************************************************/
566 void *
567 operator new(size_t size)
568 #if __cplusplus >= 201103L
569 noexcept
570 #endif
571 {
572 void * result;
573
574 result = (void *) kern_os_malloc(size);
575 return result;
576 }
577
578 void
579 operator delete(void * addr)
580 #if __cplusplus >= 201103L
581 noexcept
582 #endif
583 {
584 kern_os_free(addr);
585 return;
586 }
587
588 void *
589 operator new[](unsigned long sz)
590 #if __cplusplus >= 201103L
591 noexcept
592 #endif
593 {
594 if (sz == 0) sz = 1;
595 return kern_os_malloc(sz);
596 }
597
598 void
599 operator delete[](void * ptr)
600 #if __cplusplus >= 201103L
601 noexcept
602 #endif
603 {
604 if (ptr) {
605 kern_os_free(ptr);
606 }
607 return;
608 }
609
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.
613 *
614 * We have to put the function inside the std namespace because of how the
615 * compiler expects the name to be mangled.
616 */
617 namespace std {
618
619 void
620 __throw_length_error(const char *msg __unused)
621 {
622 panic("Size of array created by new[] has overflowed");
623 }
624
625 };
626