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