]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSRuntime.cpp
c2d1908f16b796bf486181ceb0e572b31e3e1cfe
[apple/xnu.git] / libkern / c++ / OSRuntime.cpp
1 /*
2 * Copyright (c) 2000 Apple Computer, 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 Computer, Inc.
30 *
31 */
32 #include <libkern/c++/OSMetaClass.h>
33 #include <libkern/c++/OSLib.h>
34 #include <libkern/c++/OSSymbol.h>
35 #include <libkern/c++/OSBoolean.h>
36
37 #include <sys/cdefs.h>
38
39 __BEGIN_DECLS
40
41 #include <string.h>
42
43 struct mach_header;
44
45 #include <mach/mach_types.h>
46 #include <mach-o/mach_header.h>
47 #include <stdarg.h>
48
49 #if OSALLOCDEBUG
50 extern int debug_iomalloc_size;
51 #endif
52
53 struct _mhead {
54 size_t mlen;
55 char dat[0];
56 };
57
58 void *kern_os_malloc(
59 size_t size)
60 {
61 struct _mhead *mem;
62 size_t memsize = sizeof (*mem) + size ;
63
64 if (size == 0)
65 return (0);
66
67 mem = (struct _mhead *)kalloc(memsize);
68 if (!mem)
69 return (0);
70
71 #if OSALLOCDEBUG
72 debug_iomalloc_size += memsize;
73 #endif
74
75 mem->mlen = memsize;
76 bzero( mem->dat, size);
77
78 return (mem->dat);
79 }
80
81 void kern_os_free(
82 void *addr)
83 {
84 struct _mhead *hdr;
85
86 if (!addr)
87 return;
88
89 hdr = (struct _mhead *) addr; hdr--;
90
91 #if OSALLOCDEBUG
92 debug_iomalloc_size -= hdr->mlen;
93 #endif
94
95 #if 0
96 memset((vm_offset_t)hdr, 0xbb, hdr->mlen);
97 #else
98 kfree(hdr, hdr->mlen);
99 #endif
100 }
101
102 void *kern_os_realloc(
103 void *addr,
104 size_t nsize)
105 {
106 struct _mhead *ohdr;
107 struct _mhead *nmem;
108 size_t nmemsize, osize;
109
110 if (!addr)
111 return (kern_os_malloc(nsize));
112
113 ohdr = (struct _mhead *) addr; ohdr--;
114 osize = ohdr->mlen - sizeof (*ohdr);
115 if (nsize == osize)
116 return (addr);
117
118 if (nsize == 0) {
119 kern_os_free(addr);
120 return (0);
121 }
122
123 nmemsize = sizeof (*nmem) + nsize ;
124 nmem = (struct _mhead *) kalloc(nmemsize);
125 if (!nmem){
126 kern_os_free(addr);
127 return (0);
128 }
129
130 #if OSALLOCDEBUG
131 debug_iomalloc_size += (nmemsize - ohdr->mlen);
132 #endif
133
134 nmem->mlen = nmemsize;
135 if (nsize > osize)
136 (void) memset(&nmem->dat[osize], 0, nsize - osize);
137 (void) memcpy(nmem->dat, ohdr->dat,
138 (nsize > osize) ? osize : nsize);
139 kfree(ohdr, ohdr->mlen);
140
141 return (nmem->dat);
142 }
143
144 size_t kern_os_malloc_size(
145 void *addr)
146 {
147 struct _mhead *hdr;
148
149 if (!addr)
150 return( 0);
151
152 hdr = (struct _mhead *) addr; hdr--;
153 return( hdr->mlen - sizeof (struct _mhead));
154 }
155
156 #if __GNUC__ >= 3
157 void __cxa_pure_virtual( void ) { panic(__FUNCTION__); }
158 #else
159 void __pure_virtual( void ) { panic(__FUNCTION__); }
160 #endif
161
162 typedef void (*structor_t)(void);
163
164 // Given a pointer to a 32 bit mach object segment, iterate the segment to
165 // obtain a 32 bit destructor section for C++ objects, and call each of the
166 // destructors there.
167 void
168 OSRuntimeUnloadCPPForSegment(struct segment_command * segment) {
169
170 struct section * section;
171
172 for (section = firstsect(segment);
173 section != 0;
174 section = nextsect(segment, section)) {
175
176 if (strcmp(section->sectname, "__destructor") == 0) {
177 structor_t * destructors = (structor_t *)section->addr;
178
179 if (destructors) {
180 int num_destructors = section->size / sizeof(structor_t);
181
182 for (int i = 0; i < num_destructors; i++) {
183 (*destructors[i])();
184 }
185 } /* if (destructors) */
186 } /* if (strcmp...) */
187 } /* for (section...) */
188
189 return;
190 }
191
192 // This function will only operate on 32 bit kmods
193 void OSRuntimeUnloadCPP(kmod_info_t *ki, void *)
194 {
195 if (ki && ki->address) {
196
197 struct segment_command * segment;
198 struct mach_header *header;
199
200 OSSymbol::checkForPageUnload((void *) ki->address,
201 (void *) (ki->address + ki->size));
202
203 header = (struct mach_header *)ki->address;
204 segment = firstsegfromheader(header);
205
206 for (segment = firstsegfromheader(header);
207 segment != 0;
208 segment = nextseg(segment)) {
209
210 OSRuntimeUnloadCPPForSegment(segment);
211 }
212 }
213 }
214
215 kern_return_t OSRuntimeFinalizeCPP(kmod_info_t *ki, void *)
216 {
217 void *metaHandle;
218
219 if (OSMetaClass::modHasInstance(ki->name)) {
220 // @@@ gvdl should have a verbose flag
221 printf("Can't unload %s due to -\n", ki->name);
222 OSMetaClass::reportModInstances(ki->name);
223 return kOSMetaClassHasInstances;
224 }
225
226 // Tell the meta class system that we are starting to unload
227 metaHandle = OSMetaClass::preModLoad(ki->name);
228 OSRuntimeUnloadCPP(ki, 0); // Do the actual unload
229 (void) OSMetaClass::postModLoad(metaHandle);
230
231 return KMOD_RETURN_SUCCESS;
232 }
233
234 // Functions used by the extenTools/kmod library project
235 // This function will only operate on 32 bit kmods
236 kern_return_t OSRuntimeInitializeCPP(kmod_info_t *ki, void *)
237 {
238 struct mach_header *header;
239 void *metaHandle;
240 bool load_success;
241 struct segment_command * segment;
242 struct segment_command * failure_segment;
243
244 if (!ki || !ki->address)
245 return KMOD_RETURN_FAILURE;
246 else
247 header = (struct mach_header *) ki->address;
248
249 // Tell the meta class system that we are starting the load
250 metaHandle = OSMetaClass::preModLoad(ki->name);
251 assert(metaHandle);
252 if (!metaHandle)
253 return KMOD_RETURN_FAILURE;
254
255 load_success = true;
256 failure_segment = 0;
257
258 /* Scan the header for all sections named "__constructor", in any
259 * segment, and invoke the constructors within those sections.
260 */
261 for (segment = firstsegfromheader(header);
262 segment != 0 && load_success;
263 segment = nextseg(segment)) {
264
265 struct section * section;
266
267 /* Record the current segment in the event of a failure.
268 */
269 failure_segment = segment;
270
271 for (section = firstsect(segment);
272 section != 0 && load_success;
273 section = nextsect(segment, section)) {
274
275 if (strcmp(section->sectname, "__constructor") == 0) {
276 structor_t * constructors = (structor_t *)section->addr;
277
278 if (constructors) {
279 // FIXME: can we break here under the assumption that
280 // section names are unique within a segment?
281
282 int num_constructors = section->size / sizeof(structor_t);
283 int hit_null_constructor = 0;
284
285 for (int i = 0;
286 i < num_constructors &&
287 OSMetaClass::checkModLoad(metaHandle);
288 i++) {
289
290 if (constructors[i]) {
291 (*constructors[i])();
292 } else if (!hit_null_constructor) {
293 hit_null_constructor = 1;
294 printf("Error! Null constructor in segment %s.\n",
295 section->segname);
296 }
297 }
298 load_success = OSMetaClass::checkModLoad(metaHandle);
299
300 } /* if (constructors) */
301 } /* if (strcmp...) */
302 } /* for (section...) */
303 } /* for (segment...) */
304
305
306 // We failed so call all of the destructors
307 if (!load_success) {
308
309 /* Scan the header for all sections named "__constructor", in any
310 * segment, and invoke the constructors within those sections.
311 */
312 for (segment = firstsegfromheader(header);
313 segment != failure_segment && segment != 0;
314 segment = nextseg(segment)) {
315
316 OSRuntimeUnloadCPPForSegment(segment);
317
318 } /* for (segment...) */
319 }
320
321 return OSMetaClass::postModLoad(metaHandle);
322 }
323
324 static KMOD_LIB_DECL(__kernel__, 0);
325 void OSlibkernInit(void)
326 {
327 vm_address_t *headerArray = (vm_address_t *) getmachheaders();
328
329 KMOD_INFO_NAME.address = headerArray[0]; assert(!headerArray[1]);
330 if (kOSReturnSuccess != OSRuntimeInitializeCPP(&KMOD_INFO_NAME, 0))
331 panic("OSRuntime: C++ runtime failed to initialize");
332
333 OSBoolean::initialize();
334 }
335
336 __END_DECLS
337
338 void * operator new( size_t size)
339 {
340 void * result;
341
342 result = (void *) kern_os_malloc( size);
343 return( result);
344 }
345
346 void operator delete( void * addr)
347 {
348 kern_os_free( addr);
349 }
350