summaryrefslogtreecommitdiffstats
path: root/system_cmds/gcore.tproj/dyld_shared_cache.c
blob: 0e21163d5dc050ca098c559ffad71316e5792553 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
 * Copyright (c) 2016 Apple Inc.  All rights reserved.
 */

#include "options.h"
#include "dyld_shared_cache.h"
#include "utils.h"

#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
#include <fts.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <TargetConditionals.h>

static const size_t dyld_cache_header_size = sizeof (struct copied_dyld_cache_header);

/*
 * The shared cache must both contain the magic ID and
 * match the uuid we discovered via dyld's information.
 * Assumes that the dyld_cache_header grows in a binary compatible fashion.
 */
bool
get_uuid_from_shared_cache_mapping(const void *addr, size_t size, uuid_t out)
{
    const struct copied_dyld_cache_header *ch = addr;
    if (size < sizeof (*ch))
        return false;
    static const char prefix[] = "dyld_v";
    if (strncmp(ch->magic, prefix, strlen(prefix)) != 0)
        return false;
    uuid_copy(out, ch->uuid);
    return true;
}

/*
 * Look in the known places to see if we can find this one ..
 */
char *
shared_cache_filename(const uuid_t uu)
{
    assert(!uuid_is_null(uu));
    static char *sc_argv[] = {
#if TARGET_OS_OSX
        "/System/Library/dyld",
#elif TARGET_OS_IPHONE
        "/System/Library/Caches/com.apple.dyld",
#else
#error undefined
#endif
        NULL
    };
    char *nm = NULL;
    FTS *fts = fts_open(sc_argv, FTS_NOCHDIR | FTS_LOGICAL | FTS_XDEV, NULL);
    if (NULL != fts) {
        FTSENT *fe;
        while (NULL != (fe = fts_read(fts))) {
            if ((fe->fts_info & FTS_F) == 0 ||
                (fe->fts_info & FTS_ERR) != 0)
                continue;

            static const char prefix[] = "dyld_shared_cache_";
            if (strncmp(fe->fts_name, prefix, strlen(prefix)) != 0)
                continue;

            if (fe->fts_statp->st_size < (off_t)dyld_cache_header_size)
                continue;

            int d = open(fe->fts_accpath, O_RDONLY);
            if (-1 == d) {
                if (OPTIONS_DEBUG(opt, 1))
                    printf("%s: cannot open - %s\n", fe->fts_accpath, strerror(errno));
                continue;
            }
            void *addr = mmap(NULL, dyld_cache_header_size, PROT_READ, MAP_PRIVATE, d, 0);
            close(d);
            if ((void *)-1 == addr) {
                if (OPTIONS_DEBUG(opt, 1))
                    printf("%s: cannot mmap - %s\n", fe->fts_accpath, strerror(errno));
                continue;
            }
            uuid_t scuuid;
            uuid_clear(scuuid);
            if (get_uuid_from_shared_cache_mapping(addr, dyld_cache_header_size, scuuid)) {
                if (uuid_compare(uu, scuuid) == 0)
                    nm = strdup(fe->fts_accpath);
                else if (OPTIONS_DEBUG(opt, 3)) {
                    uuid_string_t scstr;
                    uuid_unparse_lower(scuuid, scstr);
                    printf("%s: shared cache mismatch (%s)\n", fe->fts_accpath, scstr);
                }
            }
            munmap(addr, dyld_cache_header_size);
            if (NULL != nm)
                break;
        }
    }
    if (fts)
        fts_close(fts);
    return nm;
}