Skip to content

Commit 1171dd0

Browse files
committed
Import some code to handle <redacted> syms.
1 parent 0224fea commit 1171dd0

File tree

4 files changed

+304
-12
lines changed

4 files changed

+304
-12
lines changed

configure

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ if 'armv7' in cc_argv or 'arm64' in cc_argv:
7070
settings.extra_link_deps = ['(src)/ent.plist']
7171

7272
settings.host.debug_info = True
73-
settings.c_includes = ['(src)/lib', '(src)/substrate']
73+
settings.c_includes = ['(src)/lib', '(src)/substrate', '(src)/vendor']
7474

7575
emitter = settings.emitter
7676

lib/darwin/find-syms.c

+197-11
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@
33
#include <stdbool.h>
44
#include <dlfcn.h>
55
#include <pthread.h>
6+
#include <sys/mman.h>
7+
#include <limits.h>
8+
#include <fcntl.h>
69

710
#include "substitute.h"
811
#include "substitute-internal.h"
12+
#include "dyld_cache_format.h"
913

1014
extern const struct dyld_all_image_infos *_dyld_get_all_image_infos();
1115

@@ -14,19 +18,190 @@ static pthread_once_t dyld_inspect_once = PTHREAD_ONCE_INIT;
1418
static uintptr_t (*ImageLoaderMachO_getSlide)(void *);
1519
static const struct mach_header *(*ImageLoaderMachO_machHeader)(void *);
1620

17-
static void *sym_to_ptr(substitute_sym *sym, intptr_t slide) {
21+
static void *sym_to_ptr(const substitute_sym *sym, intptr_t slide) {
1822
uintptr_t addr = sym->n_value;
1923
addr += slide;
2024
if (sym->n_desc & N_ARM_THUMB_DEF)
2125
addr |= 1;
2226
return (void *) addr;
2327
}
2428

29+
static const struct dyld_cache_header *_Atomic s_cur_shared_cache_hdr;
30+
static int s_cur_shared_cache_fd;
31+
static pthread_once_t s_open_cache_once = PTHREAD_ONCE_INIT;
32+
static struct dyld_cache_local_symbols_info s_cache_local_symbols_info;
33+
static struct dyld_cache_local_symbols_entry *s_cache_local_symbols_entries;
34+
35+
static bool oscf_try_dir(const char *dir, const char *arch,
36+
const struct dyld_cache_header *dch) {
37+
char path[PATH_MAX];
38+
if (snprintf(path, sizeof(path), "%s/%s%s", dir,
39+
DYLD_SHARED_CACHE_BASE_NAME, arch) >= sizeof(path))
40+
return false;
41+
int fd = open(path, O_RDONLY);
42+
if (fd < 0)
43+
return false;
44+
struct dyld_cache_header this_dch;
45+
if (read(fd, &this_dch, sizeof(this_dch)) != sizeof(this_dch))
46+
goto fail;
47+
if (memcmp(this_dch.uuid, dch->uuid, 16) ||
48+
this_dch.localSymbolsSize != dch->localSymbolsSize /* just in case */)
49+
goto fail;
50+
s_cur_shared_cache_fd = fd;
51+
struct dyld_cache_local_symbols_info *lsi = &s_cache_local_symbols_info;
52+
if (pread(fd, lsi, sizeof(*lsi), dch->localSymbolsOffset) != sizeof(*lsi))
53+
goto fail;
54+
if (lsi->nlistOffset > dch->localSymbolsSize ||
55+
lsi->nlistCount > (dch->localSymbolsSize - lsi->nlistOffset)
56+
/ sizeof(substitute_sym) ||
57+
lsi->stringsOffset > dch->localSymbolsSize ||
58+
lsi->stringsSize > dch->localSymbolsSize - lsi->stringsOffset) {
59+
/* bad format */
60+
goto fail;
61+
}
62+
uint32_t count = lsi->entriesCount;
63+
if (count > 1000000)
64+
goto fail;
65+
struct dyld_cache_local_symbols_entry *lses;
66+
size_t lses_size = count * sizeof(*lses);
67+
if (!(lses = malloc(lses_size)))
68+
goto fail;
69+
if (pread(fd, lses, lses_size, dch->localSymbolsOffset + lsi->entriesOffset)
70+
!= lses_size) {
71+
free(lses);
72+
goto fail;
73+
}
74+
75+
s_cache_local_symbols_entries = lses;
76+
return true;
77+
78+
fail:
79+
close(fd);
80+
return false;
81+
}
82+
83+
static void open_shared_cache_file_once() {
84+
s_cur_shared_cache_fd = -1;
85+
const struct dyld_cache_header *dch = s_cur_shared_cache_hdr;
86+
if (memcmp(dch->magic, "dyld_v1 ", 8))
87+
return;
88+
const char *archp = &dch->magic[8];
89+
while (*archp == ' ')
90+
archp++;
91+
static char filename[32];
92+
const char *env_dir = getenv("DYLD_SHARED_CACHE_DIR");
93+
if (env_dir) {
94+
if (oscf_try_dir(env_dir, archp, dch))
95+
return;
96+
}
97+
#if __IPHONE_OS_VERSION_MIN_REQUIRED
98+
oscf_try_dir(IPHONE_DYLD_SHARED_CACHE_DIR, archp, dch);
99+
#else
100+
oscf_try_dir(MACOSX_DYLD_SHARED_CACHE_DIR, archp, dch);
101+
#endif
102+
}
103+
104+
static bool ul_mmap(int fd, off_t offset, size_t size,
105+
void *data_p, void **mapping_p, size_t *mapping_size_p) {
106+
int pmask = getpagesize() - 1;
107+
int page_off = offset & pmask;
108+
off_t map_offset = offset & ~pmask;
109+
size_t map_size = ((offset + size + pmask) & ~pmask) - map_offset;
110+
void *mapping = mmap(NULL, map_size, PROT_READ, MAP_SHARED, fd, map_offset);
111+
if (mapping == MAP_FAILED)
112+
return false;
113+
*(void **) data_p = (char *) mapping + page_off;
114+
*mapping_p = mapping;
115+
*mapping_size_p = map_size;
116+
return true;
117+
}
118+
119+
static bool get_shared_cache_syms(const void *hdr,
120+
const substitute_sym **syms_p,
121+
const char **strs_p,
122+
size_t *nsyms_p,
123+
void **mapping_p,
124+
size_t *mapping_size_p) {
125+
pthread_once(&s_open_cache_once, open_shared_cache_file_once);
126+
int fd = s_cur_shared_cache_fd;
127+
if (fd == -1)
128+
return false;
129+
const struct dyld_cache_header *dch = s_cur_shared_cache_hdr;
130+
const struct dyld_cache_local_symbols_info *lsi = &s_cache_local_symbols_info;
131+
struct dyld_cache_local_symbols_entry lse;
132+
for (uint32_t i = 0; i < lsi->entriesCount; i++) {
133+
lse = s_cache_local_symbols_entries[i];
134+
if (lse.dylibOffset == (uintptr_t) hdr - (uintptr_t) dch)
135+
goto got_lse;
136+
}
137+
return false;
138+
got_lse:
139+
/* map - we don't do this persistently to avoid wasting address space on
140+
* iOS (my random OS X 10.10 blob pushes 55MB) */
141+
if (lse.nlistStartIndex > lsi->nlistCount ||
142+
lsi->nlistCount - lse.nlistStartIndex < lse.nlistCount)
143+
return false;
144+
145+
char *ls_data;
146+
if (!ul_mmap(fd, dch->localSymbolsOffset, dch->localSymbolsSize,
147+
&ls_data, mapping_p, mapping_size_p))
148+
return false;
149+
const substitute_sym *syms = (void *) (ls_data + lsi->nlistOffset);
150+
*syms_p = syms + lse.nlistStartIndex;
151+
*strs_p = ls_data + lsi->stringsOffset;
152+
*nsyms_p = lse.nlistCount;
153+
return true;
154+
}
155+
156+
157+
static const struct dyld_cache_header *get_cur_shared_cache_hdr() {
158+
const struct dyld_cache_header *dch = s_cur_shared_cache_hdr;
159+
if (!dch) {
160+
/* race is OK */
161+
uint64_t start_address = 0;
162+
if (syscall(294, &start_address)) /* shared_region_check_np */
163+
dch = (void *) 1;
164+
else
165+
dch = (void *) (uintptr_t) start_address;
166+
s_cur_shared_cache_hdr = dch;
167+
}
168+
return dch == (void *) 1 ? NULL : dch;
169+
}
170+
171+
static bool addr_in_shared_cache(const void *addr) {
172+
const struct dyld_cache_header *dch = get_cur_shared_cache_hdr();
173+
if (!dch)
174+
return false;
175+
176+
uint32_t mapping_count = dch->mappingCount;
177+
const struct dyld_cache_mapping_info *mappings =
178+
(void *) ((char *) dch + dch->mappingOffset);
179+
intptr_t slide = (uintptr_t) dch - (uintptr_t) mappings[0].address;
180+
181+
for (uint32_t i = 0; i < mapping_count; i++) {
182+
const struct dyld_cache_mapping_info *mapping = &mappings[i];
183+
uintptr_t diff = (uintptr_t) addr -
184+
((uintptr_t) mapping->address + slide);
185+
if (diff < mapping->size)
186+
return true;
187+
}
188+
return false;
189+
}
190+
25191
static void find_syms_raw(const void *hdr, intptr_t *restrict slide,
26192
const char **restrict names, void **restrict syms,
27193
size_t nsyms) {
28194
memset(syms, 0, sizeof(*syms) * nsyms);
29195

196+
void *mapping = NULL;
197+
size_t mapping_size = 0;
198+
const substitute_sym *cache_syms = NULL;
199+
const char *cache_strs = NULL;
200+
size_t ncache_syms = 0;
201+
if (addr_in_shared_cache(hdr))
202+
get_shared_cache_syms(hdr, &cache_syms, &cache_strs, &ncache_syms,
203+
&mapping, &mapping_size);
204+
30205
/* note: no verification at all */
31206
const mach_header_x *mh = hdr;
32207
uint32_t ncmds = mh->ncmds;
@@ -64,18 +239,28 @@ ok: ;
64239
ok2: ;
65240
symtab = (void *) symtab + *slide;
66241
strtab = (void *) strtab + *slide;
67-
/* This could be optimized for efficiency with a large number of names... */
68-
for (uint32_t i = 0; i < syc.nsyms; i++) {
69-
substitute_sym *sym = &symtab[i];
70-
uint32_t strx = sym->n_un.n_strx;
71-
const char *name = strx == 0 ? "" : strtab + strx;
72-
for (size_t j = 0; j < nsyms; j++) {
73-
if (!strcmp(name, names[j])) {
74-
syms[j] = sym_to_ptr(sym, *slide);
75-
break;
242+
243+
for (int type = 0; type <= 1; type++) {
244+
const substitute_sym *this_symtab = type ? cache_syms : symtab;
245+
const char *this_strtab = type ? cache_strs : strtab;
246+
size_t this_nsyms = type ? ncache_syms : syc.nsyms;
247+
/* This could be optimized for efficiency with a large number of
248+
* names... */
249+
for (uint32_t i = 0; i < syc.nsyms; i++) {
250+
const substitute_sym *sym = &this_symtab[i];
251+
uint32_t strx = sym->n_un.n_strx;
252+
const char *name = strx == 0 ? "" : this_strtab + strx;
253+
for (size_t j = 0; j < nsyms; j++) {
254+
if (!strcmp(name, names[j])) {
255+
syms[j] = sym_to_ptr(sym, *slide);
256+
break;
257+
}
76258
}
77259
}
78260
}
261+
262+
if (mapping_size)
263+
munmap(mapping, mapping_size);
79264
}
80265

81266
/* This is a mess because the usual _dyld_image_count loop is not thread safe.
@@ -92,7 +277,8 @@ static void inspect_dyld() {
92277
const struct dyld_all_image_infos *aii = _dyld_get_all_image_infos();
93278
const void *dyld_hdr = aii->dyldImageLoadAddress;
94279

95-
const char *names[2] = { "__ZNK16ImageLoaderMachO8getSlideEv", "__ZNK16ImageLoaderMachO10machHeaderEv" };
280+
const char *names[2] = { "__ZNK16ImageLoaderMachO8getSlideEv",
281+
"__ZNK16ImageLoaderMachO10machHeaderEv" };
96282
void *syms[2];
97283
intptr_t dyld_slide = -1;
98284
find_syms_raw(dyld_hdr, &dyld_slide, names, syms, 2);

lib/substitute-internal.h

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <mach-o/loader.h>
1717
#include <mach-o/dyld.h>
1818
#include <mach-o/dyld_images.h>
19+
#include <mach-o/nlist.h>
1920
#ifdef __LP64__
2021
typedef struct mach_header_64 mach_header_x;
2122
typedef struct segment_command_64 segment_command_x;
@@ -27,6 +28,7 @@ typedef struct segment_command segment_command_x;
2728
typedef struct section section_x;
2829
#define LC_SEGMENT_X LC_SEGMENT
2930
#endif
31+
/* instead of 'nlist_x', use substitute_sym */
3032
#endif
3133

3234
/* FORCE_* are for tests */

vendor/dyld_cache_format.h

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2+
*
3+
* Copyright (c) 2006-2009 Apple Inc. All rights reserved.
4+
*
5+
* @APPLE_LICENSE_HEADER_START@
6+
*
7+
* This file contains Original Code and/or Modifications of Original Code
8+
* as defined in and that are subject to the Apple Public Source License
9+
* Version 2.0 (the 'License'). You may not use this file except in
10+
* compliance with the License. Please obtain a copy of the License at
11+
* http://www.opensource.apple.com/apsl/ and read it before using this
12+
* file.
13+
*
14+
* The Original Code and all software distributed under the License are
15+
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16+
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17+
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19+
* Please see the License for the specific language governing rights and
20+
* limitations under the License.
21+
*
22+
* @APPLE_LICENSE_HEADER_END@
23+
*/
24+
#ifndef __DYLD_CACHE_FORMAT__
25+
#define __DYLD_CACHE_FORMAT__
26+
27+
#include <stdint.h>
28+
29+
30+
struct dyld_cache_header
31+
{
32+
char magic[16]; // e.g. "dyld_v0 i386"
33+
uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info
34+
uint32_t mappingCount; // number of dyld_cache_mapping_info entries
35+
uint32_t imagesOffset; // file offset to first dyld_cache_image_info
36+
uint32_t imagesCount; // number of dyld_cache_image_info entries
37+
uint64_t dyldBaseAddress; // base address of dyld when cache was built
38+
uint64_t codeSignatureOffset; // file offset of code signature blob
39+
uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file)
40+
uint64_t slideInfoOffset; // file offset of kernel slid info
41+
uint64_t slideInfoSize; // size of kernel slid info
42+
uint64_t localSymbolsOffset; // file offset of where local symbols are stored
43+
uint64_t localSymbolsSize; // size of local symbols information
44+
uint8_t uuid[16]; // unique value for each shared cache file
45+
};
46+
47+
struct dyld_cache_mapping_info {
48+
uint64_t address;
49+
uint64_t size;
50+
uint64_t fileOffset;
51+
uint32_t maxProt;
52+
uint32_t initProt;
53+
};
54+
55+
struct dyld_cache_image_info
56+
{
57+
uint64_t address;
58+
uint64_t modTime;
59+
uint64_t inode;
60+
uint32_t pathFileOffset;
61+
uint32_t pad;
62+
};
63+
64+
struct dyld_cache_slide_info
65+
{
66+
uint32_t version; // currently 1
67+
uint32_t toc_offset;
68+
uint32_t toc_count;
69+
uint32_t entries_offset;
70+
uint32_t entries_count;
71+
uint32_t entries_size; // currently 128
72+
// uint16_t toc[toc_count];
73+
// entrybitmap entries[entries_count];
74+
};
75+
76+
77+
struct dyld_cache_local_symbols_info
78+
{
79+
uint32_t nlistOffset; // offset into this chunk of nlist entries
80+
uint32_t nlistCount; // count of nlist entries
81+
uint32_t stringsOffset; // offset into this chunk of string pool
82+
uint32_t stringsSize; // byte count of string pool
83+
uint32_t entriesOffset; // offset into this chunk of array of dyld_cache_local_symbols_entry
84+
uint32_t entriesCount; // number of elements in dyld_cache_local_symbols_entry array
85+
};
86+
87+
struct dyld_cache_local_symbols_entry
88+
{
89+
uint32_t dylibOffset; // offset in cache file of start of dylib
90+
uint32_t nlistStartIndex; // start index of locals for this dylib
91+
uint32_t nlistCount; // number of local symbols for this dylib
92+
};
93+
94+
95+
96+
#define MACOSX_DYLD_SHARED_CACHE_DIR "/var/db/dyld/"
97+
#define IPHONE_DYLD_SHARED_CACHE_DIR "/System/Library/Caches/com.apple.dyld/"
98+
#define DYLD_SHARED_CACHE_BASE_NAME "dyld_shared_cache_"
99+
100+
101+
102+
#endif // __DYLD_CACHE_FORMAT__
103+
104+

0 commit comments

Comments
 (0)