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