• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     static int messageRepeatCount = 5;
36     if (messageRepeatCount > 0)
37     {
38         messageRepeatCount--;
39         std::cerr << "open(\"" << path << "\", \"" << flags
40                   << "\") is skipped. This message will repeat " << messageRepeatCount
41                   << " more times." << std::endl;
42     }
43 #endif
44 
45     if (flags & O_CREAT)
46     {
47         errno = EACCES;
48         return -1;
49     }
50 
51     // Treat as if the cache doesn't exist
52     errno = ENOENT;
53     return -1;
54 }
55 
HookedFopen(const char * filename,const char * mode)56 FILE *HookedFopen(const char *filename, const char *mode)
57 {
58     std::regex expr(kMetalCacheExpr);
59     if (!std::regex_match(filename, expr))
60     {
61         return fopen(filename, mode);
62     }
63 
64 #if !defined(NDEBUG)
65     static int messageRepeatCount = 5;
66     if (messageRepeatCount > 0)
67     {
68         messageRepeatCount--;
69         std::cerr << "fopen(\"" << filename << "\", \"" << mode
70                   << "\") is skipped. This message will repeat " << messageRepeatCount
71                   << " more times." << std::endl;
72     }
73 #endif
74 
75     if (strstr(mode, "r"))
76     {
77         // Treat as if the cache doesn't exist
78         errno = ENOENT;
79         return nullptr;
80     }
81 
82     errno = EACCES;
83     return nullptr;
84 }
85 
86 // See https://opensource.apple.com/source/dyld/dyld-210.2.3/include/mach-o/dyld-interposing.h
87 #define DYLD_INTERPOSE(_replacment, _replacee)                                  \
88     __attribute__((used)) static struct                                         \
89     {                                                                           \
90         const void *replacment;                                                 \
91         const void *replacee;                                                   \
92     } _interpose_##_replacee __attribute__((section("__DATA,__interpose"))) = { \
93         (const void *)(unsigned long)&_replacment, (const void *)(unsigned long)&_replacee};
94 
95 DYLD_INTERPOSE(HookedOpen, open)
96 DYLD_INTERPOSE(HookedFopen, fopen)
97