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