1/* 2 * Copyright (c) 2006-2008 Apple 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#include <stdlib.h> 29#include <unistd.h> 30#include <string.h> 31#include <mach-o/arch.h> 32 33#include <stdio.h> 34#include <fcntl.h> 35 36#include <mach/vm_types.h> 37 38#include <sys/types.h> 39#include <sys/stat.h> 40#include <sys/mman.h> 41 42#include "fat_util.h" 43#include "macho_util.h" 44 45/******************************************************************************* 46* 47*******************************************************************************/ 48struct __fat_iterator { 49 void * file_start; 50 void * file_end; 51 struct fat_header * fat_header; 52 struct fat_arch * fat_arches; 53 uint32_t num_arches; 54 uint32_t arch_index; 55 56 int unmap : 1; // we own the data 57 int iterable : 1; // is fat or a thin mach-o 58}; 59 60/******************************************************************************* 61* 62*******************************************************************************/ 63static int __fat_iterator_init( 64 struct __fat_iterator * iter, 65 const void * file_data, 66 const void * file_end, 67 int macho_only) 68{ 69 int result = -1; 70 size_t length = file_end - file_data; 71 uint32_t magic; 72 73 if (length < sizeof(magic)) { 74 goto finish; 75 } 76 77 iter->file_start = (void *)file_data; 78 iter->file_end = (void *)file_end; 79 80 magic = MAGIC32(file_data); 81 82 if (ISFAT(magic)) { 83 void * arches_end; 84 85 if (length < sizeof(struct fat_header)) { 86 goto finish; 87 } 88 89 iter->fat_header = (struct fat_header *)file_data; 90 iter->fat_arches = (struct fat_arch *)((char *)iter->fat_header + 91 sizeof(struct fat_header)); 92 iter->num_arches = OSSwapBigToHostInt32( 93 iter->fat_header->nfat_arch); 94 arches_end = (void *)iter->fat_arches + 95 (iter->num_arches * sizeof(struct fat_arch)); 96 97 if (arches_end > iter->file_end) { 98 99 goto finish; 100 } 101 102 iter->iterable = 1; 103 104 } else if (ISMACHO(magic)) { 105 106 if (length < sizeof(struct mach_header)) { 107 goto finish; 108 } 109 110 iter->iterable = 1; 111 iter->num_arches = 1; 112 iter->arch_index = 0; 113 114 } else if (macho_only) { 115 goto finish; 116 } 117 118 result = 0; 119 120finish: 121 return result; 122} 123 124/******************************************************************************* 125* 126*******************************************************************************/ 127fat_iterator fat_iterator_open(const char * path, int macho_only) 128{ 129 struct __fat_iterator * result = NULL; 130 struct __fat_iterator local_iter; 131 132 int fd = -1; 133 struct stat stat_buf; 134 vm_address_t file_data = (vm_address_t)MAP_FAILED; // must munmap() 135 136 memset(&local_iter, 0, sizeof(local_iter)); 137 138 fd = open(path, O_RDONLY); 139 if (fd == -1) { 140 goto finish; 141 } 142 143 if (fstat(fd, &stat_buf) == -1) { 144 goto finish; 145 } 146 147 if (stat_buf.st_size < (off_t)sizeof(struct mach_header)) { 148 goto finish; 149 } 150 151 file_data = (vm_address_t)mmap(0, stat_buf.st_size, PROT_READ, 152 MAP_FILE|MAP_PRIVATE, fd, 0); 153 if (file_data == (vm_address_t)MAP_FAILED) { 154 goto finish; 155 } 156 157 local_iter.unmap = 1; 158 159 if (-1 == __fat_iterator_init(&local_iter, (char *)file_data, 160 (char *)file_data + stat_buf.st_size, macho_only)) { 161 162 goto finish; 163 } 164 165 result = (struct __fat_iterator *)malloc(sizeof(struct __fat_iterator)); 166 if (!result) { 167 goto finish; 168 } 169 bzero(result, sizeof(struct __fat_iterator)); 170 memcpy(result, &local_iter, sizeof(struct __fat_iterator)); 171 172finish: 173 if (fd != -1) close(fd); 174 175 if (!result) { 176 if (file_data != (vm_address_t)MAP_FAILED) { 177 munmap((void *)file_data, stat_buf.st_size); 178 } 179 } 180 return (fat_iterator)result; 181} 182 183/******************************************************************************* 184* 185*******************************************************************************/ 186fat_iterator fat_iterator_for_data( 187 const void * file_data, 188 const void * file_end, 189 int macho_only) 190{ 191 struct __fat_iterator * result = NULL; 192 struct __fat_iterator local_iter; 193 194 memset(&local_iter, 0, sizeof(local_iter)); 195 196 if (-1 == __fat_iterator_init(&local_iter, file_data, 197 file_end, macho_only)) { 198 199 goto finish; 200 } 201 202 result = (struct __fat_iterator *)malloc( 203 sizeof(struct __fat_iterator)); 204 if (!result) { 205 goto finish; 206 } 207 bzero(result, sizeof(struct __fat_iterator)); 208 memcpy(result, &local_iter, sizeof(struct __fat_iterator)); 209 210finish: 211 return (fat_iterator)result; 212} 213 214/******************************************************************************* 215* 216*******************************************************************************/ 217void fat_iterator_close(fat_iterator iter) 218{ 219 220 if (iter->unmap) { 221 if (iter->file_start) { 222 munmap((void *)iter->file_start, iter->file_end - 223 iter->file_start); 224 } 225 } 226 227 free(iter); 228 229 return; 230} 231 232/******************************************************************************* 233* 234*******************************************************************************/ 235int fat_iterator_num_arches( 236 fat_iterator iter) 237{ 238 return iter->num_arches; 239} 240 241/******************************************************************************* 242* 243*******************************************************************************/ 244int fat_iterator_is_iterable(fat_iterator iter) 245{ 246 return iter->iterable; 247} 248 249/******************************************************************************* 250* 251*******************************************************************************/ 252void * fat_iterator_next_arch( 253 fat_iterator iter, 254 void ** file_end) 255{ 256 void * result = NULL; 257 258 if (!iter->fat_header) { 259 if (iter->arch_index == 0) { 260 result = iter->file_start; 261 if (file_end) { 262 *file_end = iter->file_end; 263 } 264 iter->arch_index++; 265 } 266 } else { 267 if (iter->arch_index < iter->num_arches) { 268 struct fat_arch * arch_start; 269 void * arch_end; 270 271 arch_start = (struct fat_arch *)((void *)iter->fat_arches + 272 (iter->arch_index * sizeof(struct fat_arch))); 273 274 result = ((void *)iter->file_start + 275 OSSwapBigToHostInt32(arch_start->offset)); 276 arch_end = (void *)result + OSSwapBigToHostInt32(arch_start->size); 277 278 if (arch_end > iter->file_end) { 279 result = NULL; 280 iter->arch_index = iter->num_arches; 281 goto finish; 282 } 283 284 if (file_end) { 285 *file_end = arch_end; 286 } 287 288 iter->arch_index++; 289 } 290 } 291 292finish: 293 return result; 294} 295 296/******************************************************************************* 297* 298*******************************************************************************/ 299void fat_iterator_reset(fat_iterator iter) 300{ 301 iter->arch_index = 0; 302 return; 303} 304 305/******************************************************************************* 306* 307*******************************************************************************/ 308int fat_iterator_find_fat_arch( 309 fat_iterator iter, 310 cpu_type_t cputype, 311 cpu_subtype_t cpusubtype, 312 struct fat_arch * fat_arch_out) 313{ 314 int result = 0; 315 uint32_t magic; 316 317 uint32_t nfat_arch; 318 319 struct fat_arch * fat_arches; 320 struct fat_arch * fat_arches_copy = NULL; // must free 321 322 struct fat_arch * found_arch; 323 324 magic = MAGIC32(iter->file_start); 325 326 if (iter->fat_header) { 327 uint32_t fat_arches_size; 328 uint32_t index; 329 330 nfat_arch = iter->num_arches; 331 fat_arches_size = nfat_arch * sizeof(struct fat_arch); 332 333 fat_arches_copy = (struct fat_arch *)(malloc(fat_arches_size)); 334 if (!fat_arches_copy) { 335 goto finish; 336 } 337 338 fat_arches = fat_arches_copy; 339 340 memcpy(fat_arches, iter->fat_arches, fat_arches_size); 341 342 /* NXFindBestFatArch() requires all the fat info to be in host 343 * byte order. 344 */ 345 for (index = 0; index < nfat_arch; index++) { 346 fat_arches[index].cputype = 347 OSSwapBigToHostInt32(fat_arches[index].cputype); 348 fat_arches[index].cpusubtype = 349 OSSwapBigToHostInt32(fat_arches[index].cpusubtype); 350 fat_arches[index].offset = 351 OSSwapBigToHostInt32(fat_arches[index].offset); 352 fat_arches[index].size = 353 OSSwapBigToHostInt32(fat_arches[index].size); 354 fat_arches[index].align = 355 OSSwapBigToHostInt32(fat_arches[index].align); 356 } 357 } else { 358 struct fat_arch fake_fat_arches; 359 uint8_t swap; 360 struct mach_header * mach_hdr; 361 362 nfat_arch = 1; 363 364 bzero(&fake_fat_arches, sizeof(fake_fat_arches)); 365 366 fat_arches = &fake_fat_arches; 367 368 swap = ISSWAPPEDMACHO(magic); 369 mach_hdr = (struct mach_header *)iter->file_start; 370 fat_arches[0].cputype = CondSwapInt32(swap, mach_hdr->cputype); 371 fat_arches[0].cpusubtype = CondSwapInt32(swap, mach_hdr->cpusubtype); 372 373 fat_arches[0].offset = 0; 374 fat_arches[0].size = iter->file_end - iter->file_start; 375 fat_arches[0].align = 1; // not used anyhow 376 } 377 378 found_arch = NXFindBestFatArch(cputype, cpusubtype, fat_arches, nfat_arch); 379 if (found_arch) { 380 result = 1; 381 if (fat_arch_out) { 382 memcpy(fat_arch_out, found_arch, sizeof(*fat_arch_out)); 383 } 384 } 385 386finish: 387 if (fat_arches_copy) { 388 free(fat_arches_copy); 389 } 390 391 return result; 392} 393 394/******************************************************************************* 395* 396*******************************************************************************/ 397void * fat_iterator_find_arch( 398 fat_iterator iter, 399 cpu_type_t cputype, 400 cpu_subtype_t cpusubtype, 401 void ** arch_end_ptr) 402{ 403 struct fat_arch found_arch; 404 void * arch_start = NULL; 405 void * arch_end = NULL; 406 407 if (!fat_iterator_find_fat_arch(iter, cputype, cpusubtype, &found_arch)) { 408 goto finish; 409 } 410 411 // These are already swapped so don't swap them here. 412 arch_start = iter->file_start + found_arch.offset; 413 arch_end = arch_start + found_arch.size; 414 415 if (arch_end_ptr) { 416 *arch_end_ptr = arch_end; 417 } 418 419finish: 420 421 return arch_start; 422} 423 424/******************************************************************************* 425* 426*******************************************************************************/ 427void * fat_iterator_find_host_arch( 428 fat_iterator iter, 429 void ** arch_end_ptr) 430{ 431 const NXArchInfo * archinfo; 432 433 archinfo = NXGetLocalArchInfo(); 434 if (!archinfo) { 435 return NULL; 436 } 437 return fat_iterator_find_arch(iter, archinfo->cputype, 438 archinfo->cpusubtype, arch_end_ptr); 439} 440 441/******************************************************************************* 442* 443*******************************************************************************/ 444const void * fat_iterator_file_start(fat_iterator iter) 445{ 446 return iter->file_start; 447 return NULL; 448} 449 450/******************************************************************************* 451 * 452 *******************************************************************************/ 453const void * fat_iterator_file_end(fat_iterator iter) 454{ 455 return iter->file_end; 456 return NULL; 457} 458