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