xref: /xnu-11215/libkern/c++/OSRuntime.cpp (revision 14e3d835)
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 	bzero( mem->dat, 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(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(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 // Given a pointer to a 32 bit mach object segment, iterate the segment to
159 // obtain a 32 bit destructor section for C++ objects, and call each of the
160 // destructors there.
161 void
162 OSRuntimeUnloadCPPForSegment(struct segment_command * segment) {
163 
164     struct section * section;
165 
166     for (section = firstsect(segment);
167          section != 0;
168          section = nextsect(segment, section)) {
169 
170         if (strcmp(section->sectname, "__destructor") == 0) {
171             structor_t * destructors = (structor_t *)section->addr;
172 
173             if (destructors) {
174                 int num_destructors = section->size / sizeof(structor_t);
175 
176                 for (int i = 0; i < num_destructors; i++) {
177                     (*destructors[i])();
178                 }
179             } /* if (destructors) */
180         } /* if (strcmp...) */
181     } /* for (section...) */
182 
183     return;
184 }
185 
186 // This function will only operate on 32 bit kmods
187 void OSRuntimeUnloadCPP(kmod_info_t *ki, void *)
188 {
189     if (ki && ki->address) {
190 
191         struct segment_command * segment;
192         struct mach_header *header;
193 
194 	OSSymbol::checkForPageUnload((void *) ki->address,
195 				     (void *) (ki->address + ki->size));
196 
197         header = (struct mach_header *)ki->address;
198         segment = firstsegfromheader(header);
199 
200         for (segment = firstsegfromheader(header);
201              segment != 0;
202              segment = nextseg(segment)) {
203 
204             OSRuntimeUnloadCPPForSegment(segment);
205         }
206     }
207 }
208 
209 kern_return_t OSRuntimeFinalizeCPP(kmod_info_t *ki, void *)
210 {
211     void *metaHandle;
212 
213     if (OSMetaClass::modHasInstance(ki->name)) {
214         // @@@ gvdl should have a verbose flag
215         printf("Can't unload %s due to -\n", ki->name);
216         OSMetaClass::reportModInstances(ki->name);
217         return kOSMetaClassHasInstances;
218     }
219 
220     // Tell the meta class system that we are starting to unload
221     metaHandle = OSMetaClass::preModLoad(ki->name);
222     OSRuntimeUnloadCPP(ki, 0);	// Do the actual unload
223     (void) OSMetaClass::postModLoad(metaHandle);
224 
225     return KMOD_RETURN_SUCCESS;
226 }
227 
228 // Functions used by the extenTools/kmod library project
229 // This function will only operate on 32 bit kmods
230 kern_return_t OSRuntimeInitializeCPP(kmod_info_t *ki, void *)
231 {
232     struct mach_header *header;
233     void *metaHandle;
234     bool load_success;
235     struct segment_command * segment;
236     struct segment_command * failure_segment;
237 
238     if (!ki || !ki->address)
239         return KMOD_RETURN_FAILURE;
240     else
241         header = (struct mach_header *) ki->address;
242 
243     // Tell the meta class system that we are starting the load
244     metaHandle = OSMetaClass::preModLoad(ki->name);
245     assert(metaHandle);
246     if (!metaHandle)
247         return KMOD_RETURN_FAILURE;
248 
249     load_success = true;
250     failure_segment = 0;
251 
252    /* Scan the header for all sections named "__constructor", in any
253     * segment, and invoke the constructors within those sections.
254     */
255     for (segment = firstsegfromheader(header);
256          segment != 0 && load_success;
257          segment = nextseg(segment)) {
258 
259         struct section * section;
260 
261        /* Record the current segment in the event of a failure.
262         */
263         failure_segment = segment;
264 
265         for (section = firstsect(segment);
266              section != 0 && load_success;
267              section = nextsect(segment, section)) {
268 
269             if (strcmp(section->sectname, "__constructor") == 0) {
270                 structor_t * constructors = (structor_t *)section->addr;
271 
272                 if (constructors) {
273                     // FIXME: can we break here under the assumption that
274                     // section names are unique within a segment?
275 
276                     int num_constructors = section->size / sizeof(structor_t);
277                     int hit_null_constructor = 0;
278 
279                     for (int i = 0;
280                          i < num_constructors &&
281                          OSMetaClass::checkModLoad(metaHandle);
282                          i++) {
283 
284                         if (constructors[i]) {
285                             (*constructors[i])();
286                         } else if (!hit_null_constructor) {
287                             hit_null_constructor = 1;
288                             printf("Error! Null constructor in segment %s.\n",
289                                 section->segname);
290                         }
291                     }
292                     load_success = OSMetaClass::checkModLoad(metaHandle);
293 
294                 } /* if (constructors) */
295             } /* if (strcmp...) */
296         } /* for (section...) */
297     } /* for (segment...) */
298 
299 
300     // We failed so call all of the destructors
301     if (!load_success) {
302 
303        /* Scan the header for all sections named "__constructor", in any
304         * segment, and invoke the constructors within those sections.
305         */
306         for (segment = firstsegfromheader(header);
307              segment != failure_segment && segment != 0;
308              segment = nextseg(segment)) {
309 
310             OSRuntimeUnloadCPPForSegment(segment);
311 
312         } /* for (segment...) */
313     }
314 
315     return OSMetaClass::postModLoad(metaHandle);
316 }
317 
318 static KMOD_LIB_DECL(__kernel__, 0);
319 void OSlibkernInit(void)
320 {
321     vm_address_t *headerArray = (vm_address_t *) getmachheaders();
322 
323     KMOD_INFO_NAME.address = headerArray[0]; assert(!headerArray[1]);
324     if (kOSReturnSuccess != OSRuntimeInitializeCPP(&KMOD_INFO_NAME, 0))
325         panic("OSRuntime: C++ runtime failed to initialize");
326 
327     OSBoolean::initialize();
328 }
329 
330 __END_DECLS
331 
332 void * operator new( size_t size)
333 {
334     void * result;
335 
336     result = (void *) kern_os_malloc( size);
337     return( result);
338 }
339 
340 void operator delete( void * addr)
341 {
342     kern_os_free( addr);
343 }
344 
345