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