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