xref: /xnu-11215/libkern/c++/OSRuntime.cpp (revision fad439e7)
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 
341