1 //
2 // Copyright 2020 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // shader_cache_file_hooking:
7 // Hooks file API functions to intercept Metal shader cache access and return as if the file
8 // doesn't exist. This is to avoid slow cache access happened after the cache becomes huge over
9 // time.
10 //
11
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <iostream>
18 #include <regex>
19
20 namespace
21 {
22 constexpr char kMetalCacheExpr[] = R"(.*com\.apple\.metal.*(libraries|functions).*\.(maps|data))";
23 }
24
HookedOpen(const char * path,int flags,mode_t mode)25 int HookedOpen(const char *path, int flags, mode_t mode)
26 {
27 std::regex expr(kMetalCacheExpr);
28
29 if (!std::regex_match(path, expr))
30 {
31 return open(path, flags, mode);
32 }
33
34 #if !defined(NDEBUG)
35 std::cerr << "open(\"" << path << "\", \"" << flags << "\") is skipped" << std::endl;
36 #endif
37 if (flags & O_CREAT)
38 {
39 errno = EACCES;
40 return -1;
41 }
42
43 // Treat as if the cache doesn't exist
44 errno = ENOENT;
45 return -1;
46 }
47
HookedFopen(const char * filename,const char * mode)48 FILE *HookedFopen(const char *filename, const char *mode)
49 {
50 std::regex expr(kMetalCacheExpr);
51 if (!std::regex_match(filename, expr))
52 {
53 return fopen(filename, mode);
54 }
55
56 #if !defined(NDEBUG)
57 std::cerr << "fopen(\"" << filename << "\", \"" << mode << "\") is skipped" << std::endl;
58 #endif
59 if (strstr(mode, "r"))
60 {
61 // Treat as if the cache doesn't exist
62 errno = ENOENT;
63 return nullptr;
64 }
65
66 errno = EACCES;
67 return nullptr;
68 }
69
70 // See https://opensource.apple.com/source/dyld/dyld-210.2.3/include/mach-o/dyld-interposing.h
71 #define DYLD_INTERPOSE(_replacment, _replacee) \
72 __attribute__((used)) static struct \
73 { \
74 const void *replacment; \
75 const void *replacee; \
76 } _interpose_##_replacee __attribute__((section("__DATA,__interpose"))) = { \
77 (const void *)(unsigned long)&_replacment, (const void *)(unsigned long)&_replacee};
78
79 DYLD_INTERPOSE(HookedOpen, open)
80 DYLD_INTERPOSE(HookedFopen, fopen)
81