1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker
7*8975f5c5SAndroid Build Coastguard Worker // system_utils_posix.cpp: Implementation of POSIX OS-specific functions.
8*8975f5c5SAndroid Build Coastguard Worker
9*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
10*8975f5c5SAndroid Build Coastguard Worker #include "system_utils.h"
11*8975f5c5SAndroid Build Coastguard Worker
12*8975f5c5SAndroid Build Coastguard Worker #include <array>
13*8975f5c5SAndroid Build Coastguard Worker #include <iostream>
14*8975f5c5SAndroid Build Coastguard Worker
15*8975f5c5SAndroid Build Coastguard Worker #include <dlfcn.h>
16*8975f5c5SAndroid Build Coastguard Worker #include <grp.h>
17*8975f5c5SAndroid Build Coastguard Worker #include <inttypes.h>
18*8975f5c5SAndroid Build Coastguard Worker #include <pwd.h>
19*8975f5c5SAndroid Build Coastguard Worker #include <signal.h>
20*8975f5c5SAndroid Build Coastguard Worker #include <string.h>
21*8975f5c5SAndroid Build Coastguard Worker #include <sys/mman.h>
22*8975f5c5SAndroid Build Coastguard Worker #include <sys/stat.h>
23*8975f5c5SAndroid Build Coastguard Worker #include <sys/types.h>
24*8975f5c5SAndroid Build Coastguard Worker #include <sys/wait.h>
25*8975f5c5SAndroid Build Coastguard Worker #include <unistd.h>
26*8975f5c5SAndroid Build Coastguard Worker
27*8975f5c5SAndroid Build Coastguard Worker #include "common/string_utils.h"
28*8975f5c5SAndroid Build Coastguard Worker
29*8975f5c5SAndroid Build Coastguard Worker #ifdef ANGLE_PLATFORM_FUCHSIA
30*8975f5c5SAndroid Build Coastguard Worker # include <zircon/process.h>
31*8975f5c5SAndroid Build Coastguard Worker # include <zircon/syscalls.h>
32*8975f5c5SAndroid Build Coastguard Worker #else
33*8975f5c5SAndroid Build Coastguard Worker # include <sys/resource.h>
34*8975f5c5SAndroid Build Coastguard Worker #endif
35*8975f5c5SAndroid Build Coastguard Worker
36*8975f5c5SAndroid Build Coastguard Worker namespace angle
37*8975f5c5SAndroid Build Coastguard Worker {
38*8975f5c5SAndroid Build Coastguard Worker
39*8975f5c5SAndroid Build Coastguard Worker namespace
40*8975f5c5SAndroid Build Coastguard Worker {
GetModulePath(void * moduleOrSymbol)41*8975f5c5SAndroid Build Coastguard Worker std::string GetModulePath(void *moduleOrSymbol)
42*8975f5c5SAndroid Build Coastguard Worker {
43*8975f5c5SAndroid Build Coastguard Worker Dl_info dlInfo;
44*8975f5c5SAndroid Build Coastguard Worker if (dladdr(moduleOrSymbol, &dlInfo) == 0)
45*8975f5c5SAndroid Build Coastguard Worker {
46*8975f5c5SAndroid Build Coastguard Worker return "";
47*8975f5c5SAndroid Build Coastguard Worker }
48*8975f5c5SAndroid Build Coastguard Worker
49*8975f5c5SAndroid Build Coastguard Worker #ifdef ANGLE_PLATFORM_LINUX
50*8975f5c5SAndroid Build Coastguard Worker // Chrome changes process title on Linux that causes dladdr returns wrong module
51*8975f5c5SAndroid Build Coastguard Worker // file name for executable binary, so return GetExecutablePath() if dli_fname
52*8975f5c5SAndroid Build Coastguard Worker // doesn't exist.
53*8975f5c5SAndroid Build Coastguard Worker struct stat buf;
54*8975f5c5SAndroid Build Coastguard Worker if (stat(dlInfo.dli_fname, &buf) != 0)
55*8975f5c5SAndroid Build Coastguard Worker {
56*8975f5c5SAndroid Build Coastguard Worker return GetExecutablePath();
57*8975f5c5SAndroid Build Coastguard Worker }
58*8975f5c5SAndroid Build Coastguard Worker #endif
59*8975f5c5SAndroid Build Coastguard Worker
60*8975f5c5SAndroid Build Coastguard Worker return dlInfo.dli_fname;
61*8975f5c5SAndroid Build Coastguard Worker }
62*8975f5c5SAndroid Build Coastguard Worker
OpenPosixLibrary(const std::string & fullPath,int extraFlags,std::string * errorOut)63*8975f5c5SAndroid Build Coastguard Worker void *OpenPosixLibrary(const std::string &fullPath, int extraFlags, std::string *errorOut)
64*8975f5c5SAndroid Build Coastguard Worker {
65*8975f5c5SAndroid Build Coastguard Worker void *module = dlopen(fullPath.c_str(), RTLD_NOW | extraFlags);
66*8975f5c5SAndroid Build Coastguard Worker if (module)
67*8975f5c5SAndroid Build Coastguard Worker {
68*8975f5c5SAndroid Build Coastguard Worker if (errorOut)
69*8975f5c5SAndroid Build Coastguard Worker {
70*8975f5c5SAndroid Build Coastguard Worker *errorOut = fullPath;
71*8975f5c5SAndroid Build Coastguard Worker }
72*8975f5c5SAndroid Build Coastguard Worker }
73*8975f5c5SAndroid Build Coastguard Worker else if (errorOut)
74*8975f5c5SAndroid Build Coastguard Worker {
75*8975f5c5SAndroid Build Coastguard Worker *errorOut = "dlopen(";
76*8975f5c5SAndroid Build Coastguard Worker *errorOut += fullPath;
77*8975f5c5SAndroid Build Coastguard Worker *errorOut += ") failed with error: ";
78*8975f5c5SAndroid Build Coastguard Worker *errorOut += dlerror();
79*8975f5c5SAndroid Build Coastguard Worker struct stat sfile;
80*8975f5c5SAndroid Build Coastguard Worker if (-1 == stat(fullPath.c_str(), &sfile))
81*8975f5c5SAndroid Build Coastguard Worker {
82*8975f5c5SAndroid Build Coastguard Worker *errorOut += ", stat() call failed.";
83*8975f5c5SAndroid Build Coastguard Worker }
84*8975f5c5SAndroid Build Coastguard Worker else
85*8975f5c5SAndroid Build Coastguard Worker {
86*8975f5c5SAndroid Build Coastguard Worker *errorOut += ", stat() info: ";
87*8975f5c5SAndroid Build Coastguard Worker struct passwd *pwuser = getpwuid(sfile.st_uid);
88*8975f5c5SAndroid Build Coastguard Worker if (pwuser)
89*8975f5c5SAndroid Build Coastguard Worker {
90*8975f5c5SAndroid Build Coastguard Worker *errorOut += "owner: ";
91*8975f5c5SAndroid Build Coastguard Worker *errorOut += pwuser->pw_name;
92*8975f5c5SAndroid Build Coastguard Worker *errorOut += ", ";
93*8975f5c5SAndroid Build Coastguard Worker }
94*8975f5c5SAndroid Build Coastguard Worker struct group *grpnam = getgrgid(sfile.st_gid);
95*8975f5c5SAndroid Build Coastguard Worker if (grpnam)
96*8975f5c5SAndroid Build Coastguard Worker {
97*8975f5c5SAndroid Build Coastguard Worker *errorOut += "group: ";
98*8975f5c5SAndroid Build Coastguard Worker *errorOut += grpnam->gr_name;
99*8975f5c5SAndroid Build Coastguard Worker *errorOut += ", ";
100*8975f5c5SAndroid Build Coastguard Worker }
101*8975f5c5SAndroid Build Coastguard Worker *errorOut += "perms: ";
102*8975f5c5SAndroid Build Coastguard Worker *errorOut += std::to_string(sfile.st_mode);
103*8975f5c5SAndroid Build Coastguard Worker *errorOut += ", links: ";
104*8975f5c5SAndroid Build Coastguard Worker *errorOut += std::to_string(sfile.st_nlink);
105*8975f5c5SAndroid Build Coastguard Worker *errorOut += ", size: ";
106*8975f5c5SAndroid Build Coastguard Worker *errorOut += std::to_string(sfile.st_size);
107*8975f5c5SAndroid Build Coastguard Worker }
108*8975f5c5SAndroid Build Coastguard Worker }
109*8975f5c5SAndroid Build Coastguard Worker return module;
110*8975f5c5SAndroid Build Coastguard Worker }
111*8975f5c5SAndroid Build Coastguard Worker } // namespace
112*8975f5c5SAndroid Build Coastguard Worker
GetCWD()113*8975f5c5SAndroid Build Coastguard Worker Optional<std::string> GetCWD()
114*8975f5c5SAndroid Build Coastguard Worker {
115*8975f5c5SAndroid Build Coastguard Worker std::array<char, 4096> pathBuf;
116*8975f5c5SAndroid Build Coastguard Worker char *result = getcwd(pathBuf.data(), pathBuf.size());
117*8975f5c5SAndroid Build Coastguard Worker if (result == nullptr)
118*8975f5c5SAndroid Build Coastguard Worker {
119*8975f5c5SAndroid Build Coastguard Worker return Optional<std::string>::Invalid();
120*8975f5c5SAndroid Build Coastguard Worker }
121*8975f5c5SAndroid Build Coastguard Worker return std::string(pathBuf.data());
122*8975f5c5SAndroid Build Coastguard Worker }
123*8975f5c5SAndroid Build Coastguard Worker
SetCWD(const char * dirName)124*8975f5c5SAndroid Build Coastguard Worker bool SetCWD(const char *dirName)
125*8975f5c5SAndroid Build Coastguard Worker {
126*8975f5c5SAndroid Build Coastguard Worker return (chdir(dirName) == 0);
127*8975f5c5SAndroid Build Coastguard Worker }
128*8975f5c5SAndroid Build Coastguard Worker
UnsetEnvironmentVar(const char * variableName)129*8975f5c5SAndroid Build Coastguard Worker bool UnsetEnvironmentVar(const char *variableName)
130*8975f5c5SAndroid Build Coastguard Worker {
131*8975f5c5SAndroid Build Coastguard Worker return (unsetenv(variableName) == 0);
132*8975f5c5SAndroid Build Coastguard Worker }
133*8975f5c5SAndroid Build Coastguard Worker
SetEnvironmentVar(const char * variableName,const char * value)134*8975f5c5SAndroid Build Coastguard Worker bool SetEnvironmentVar(const char *variableName, const char *value)
135*8975f5c5SAndroid Build Coastguard Worker {
136*8975f5c5SAndroid Build Coastguard Worker return (setenv(variableName, value, 1) == 0);
137*8975f5c5SAndroid Build Coastguard Worker }
138*8975f5c5SAndroid Build Coastguard Worker
GetEnvironmentVar(const char * variableName)139*8975f5c5SAndroid Build Coastguard Worker std::string GetEnvironmentVar(const char *variableName)
140*8975f5c5SAndroid Build Coastguard Worker {
141*8975f5c5SAndroid Build Coastguard Worker const char *value = getenv(variableName);
142*8975f5c5SAndroid Build Coastguard Worker return (value == nullptr ? std::string() : std::string(value));
143*8975f5c5SAndroid Build Coastguard Worker }
144*8975f5c5SAndroid Build Coastguard Worker
GetPathSeparatorForEnvironmentVar()145*8975f5c5SAndroid Build Coastguard Worker const char *GetPathSeparatorForEnvironmentVar()
146*8975f5c5SAndroid Build Coastguard Worker {
147*8975f5c5SAndroid Build Coastguard Worker return ":";
148*8975f5c5SAndroid Build Coastguard Worker }
149*8975f5c5SAndroid Build Coastguard Worker
GetModuleDirectoryAndGetError(std::string * errorOut)150*8975f5c5SAndroid Build Coastguard Worker std::string GetModuleDirectoryAndGetError(std::string *errorOut)
151*8975f5c5SAndroid Build Coastguard Worker {
152*8975f5c5SAndroid Build Coastguard Worker std::string directory;
153*8975f5c5SAndroid Build Coastguard Worker static int placeholderSymbol = 0;
154*8975f5c5SAndroid Build Coastguard Worker std::string moduleName = GetModulePath(&placeholderSymbol);
155*8975f5c5SAndroid Build Coastguard Worker if (!moduleName.empty())
156*8975f5c5SAndroid Build Coastguard Worker {
157*8975f5c5SAndroid Build Coastguard Worker directory = moduleName.substr(0, moduleName.find_last_of('/') + 1);
158*8975f5c5SAndroid Build Coastguard Worker }
159*8975f5c5SAndroid Build Coastguard Worker
160*8975f5c5SAndroid Build Coastguard Worker // Ensure we return the full path to the module, not the relative path
161*8975f5c5SAndroid Build Coastguard Worker if (!IsFullPath(directory))
162*8975f5c5SAndroid Build Coastguard Worker {
163*8975f5c5SAndroid Build Coastguard Worker if (errorOut)
164*8975f5c5SAndroid Build Coastguard Worker {
165*8975f5c5SAndroid Build Coastguard Worker *errorOut += "Directory: '";
166*8975f5c5SAndroid Build Coastguard Worker *errorOut += directory;
167*8975f5c5SAndroid Build Coastguard Worker *errorOut += "' is not full path";
168*8975f5c5SAndroid Build Coastguard Worker }
169*8975f5c5SAndroid Build Coastguard Worker Optional<std::string> cwd = GetCWD();
170*8975f5c5SAndroid Build Coastguard Worker if (cwd.valid())
171*8975f5c5SAndroid Build Coastguard Worker {
172*8975f5c5SAndroid Build Coastguard Worker directory = ConcatenatePath(cwd.value(), directory);
173*8975f5c5SAndroid Build Coastguard Worker if (errorOut)
174*8975f5c5SAndroid Build Coastguard Worker {
175*8975f5c5SAndroid Build Coastguard Worker *errorOut += ", so it has been modified to: '";
176*8975f5c5SAndroid Build Coastguard Worker *errorOut += directory;
177*8975f5c5SAndroid Build Coastguard Worker *errorOut += "'. ";
178*8975f5c5SAndroid Build Coastguard Worker }
179*8975f5c5SAndroid Build Coastguard Worker }
180*8975f5c5SAndroid Build Coastguard Worker else if (errorOut)
181*8975f5c5SAndroid Build Coastguard Worker {
182*8975f5c5SAndroid Build Coastguard Worker *errorOut += " and getcwd was invalid. ";
183*8975f5c5SAndroid Build Coastguard Worker }
184*8975f5c5SAndroid Build Coastguard Worker }
185*8975f5c5SAndroid Build Coastguard Worker return directory;
186*8975f5c5SAndroid Build Coastguard Worker }
187*8975f5c5SAndroid Build Coastguard Worker
GetModuleDirectory()188*8975f5c5SAndroid Build Coastguard Worker std::string GetModuleDirectory()
189*8975f5c5SAndroid Build Coastguard Worker {
190*8975f5c5SAndroid Build Coastguard Worker return GetModuleDirectoryAndGetError(nullptr);
191*8975f5c5SAndroid Build Coastguard Worker }
192*8975f5c5SAndroid Build Coastguard Worker
OpenSystemLibraryWithExtensionAndGetError(const char * libraryName,SearchType searchType,std::string * errorOut)193*8975f5c5SAndroid Build Coastguard Worker void *OpenSystemLibraryWithExtensionAndGetError(const char *libraryName,
194*8975f5c5SAndroid Build Coastguard Worker SearchType searchType,
195*8975f5c5SAndroid Build Coastguard Worker std::string *errorOut)
196*8975f5c5SAndroid Build Coastguard Worker {
197*8975f5c5SAndroid Build Coastguard Worker std::string directory;
198*8975f5c5SAndroid Build Coastguard Worker if (searchType == SearchType::ModuleDir)
199*8975f5c5SAndroid Build Coastguard Worker {
200*8975f5c5SAndroid Build Coastguard Worker #if ANGLE_PLATFORM_IOS_FAMILY
201*8975f5c5SAndroid Build Coastguard Worker // On iOS, shared libraries must be loaded from within the app bundle.
202*8975f5c5SAndroid Build Coastguard Worker directory = GetExecutableDirectory() + "/Frameworks/";
203*8975f5c5SAndroid Build Coastguard Worker #elif ANGLE_PLATFORM_FUCHSIA
204*8975f5c5SAndroid Build Coastguard Worker // On Fuchsia the dynamic loader always looks up libraries in /pkg/lib
205*8975f5c5SAndroid Build Coastguard Worker // and disallows loading of libraries via absolute paths.
206*8975f5c5SAndroid Build Coastguard Worker directory = "";
207*8975f5c5SAndroid Build Coastguard Worker #else
208*8975f5c5SAndroid Build Coastguard Worker directory = GetModuleDirectoryAndGetError(errorOut);
209*8975f5c5SAndroid Build Coastguard Worker #endif
210*8975f5c5SAndroid Build Coastguard Worker }
211*8975f5c5SAndroid Build Coastguard Worker
212*8975f5c5SAndroid Build Coastguard Worker int extraFlags = 0;
213*8975f5c5SAndroid Build Coastguard Worker if (searchType == SearchType::AlreadyLoaded)
214*8975f5c5SAndroid Build Coastguard Worker {
215*8975f5c5SAndroid Build Coastguard Worker extraFlags = RTLD_NOLOAD;
216*8975f5c5SAndroid Build Coastguard Worker }
217*8975f5c5SAndroid Build Coastguard Worker
218*8975f5c5SAndroid Build Coastguard Worker std::string fullPath = directory + libraryName;
219*8975f5c5SAndroid Build Coastguard Worker return OpenPosixLibrary(fullPath, extraFlags, errorOut);
220*8975f5c5SAndroid Build Coastguard Worker }
221*8975f5c5SAndroid Build Coastguard Worker
GetLibrarySymbol(void * libraryHandle,const char * symbolName)222*8975f5c5SAndroid Build Coastguard Worker void *GetLibrarySymbol(void *libraryHandle, const char *symbolName)
223*8975f5c5SAndroid Build Coastguard Worker {
224*8975f5c5SAndroid Build Coastguard Worker if (!libraryHandle)
225*8975f5c5SAndroid Build Coastguard Worker {
226*8975f5c5SAndroid Build Coastguard Worker return nullptr;
227*8975f5c5SAndroid Build Coastguard Worker }
228*8975f5c5SAndroid Build Coastguard Worker
229*8975f5c5SAndroid Build Coastguard Worker return dlsym(libraryHandle, symbolName);
230*8975f5c5SAndroid Build Coastguard Worker }
231*8975f5c5SAndroid Build Coastguard Worker
GetLibraryPath(void * libraryHandle)232*8975f5c5SAndroid Build Coastguard Worker std::string GetLibraryPath(void *libraryHandle)
233*8975f5c5SAndroid Build Coastguard Worker {
234*8975f5c5SAndroid Build Coastguard Worker if (!libraryHandle)
235*8975f5c5SAndroid Build Coastguard Worker {
236*8975f5c5SAndroid Build Coastguard Worker return "";
237*8975f5c5SAndroid Build Coastguard Worker }
238*8975f5c5SAndroid Build Coastguard Worker
239*8975f5c5SAndroid Build Coastguard Worker return GetModulePath(libraryHandle);
240*8975f5c5SAndroid Build Coastguard Worker }
241*8975f5c5SAndroid Build Coastguard Worker
CloseSystemLibrary(void * libraryHandle)242*8975f5c5SAndroid Build Coastguard Worker void CloseSystemLibrary(void *libraryHandle)
243*8975f5c5SAndroid Build Coastguard Worker {
244*8975f5c5SAndroid Build Coastguard Worker if (libraryHandle)
245*8975f5c5SAndroid Build Coastguard Worker {
246*8975f5c5SAndroid Build Coastguard Worker dlclose(libraryHandle);
247*8975f5c5SAndroid Build Coastguard Worker }
248*8975f5c5SAndroid Build Coastguard Worker }
249*8975f5c5SAndroid Build Coastguard Worker
IsDirectory(const char * filename)250*8975f5c5SAndroid Build Coastguard Worker bool IsDirectory(const char *filename)
251*8975f5c5SAndroid Build Coastguard Worker {
252*8975f5c5SAndroid Build Coastguard Worker struct stat st;
253*8975f5c5SAndroid Build Coastguard Worker int result = stat(filename, &st);
254*8975f5c5SAndroid Build Coastguard Worker return result == 0 && ((st.st_mode & S_IFDIR) == S_IFDIR);
255*8975f5c5SAndroid Build Coastguard Worker }
256*8975f5c5SAndroid Build Coastguard Worker
IsDebuggerAttached()257*8975f5c5SAndroid Build Coastguard Worker bool IsDebuggerAttached()
258*8975f5c5SAndroid Build Coastguard Worker {
259*8975f5c5SAndroid Build Coastguard Worker // This could have a fuller implementation.
260*8975f5c5SAndroid Build Coastguard Worker // See https://cs.chromium.org/chromium/src/base/debug/debugger_posix.cc
261*8975f5c5SAndroid Build Coastguard Worker return false;
262*8975f5c5SAndroid Build Coastguard Worker }
263*8975f5c5SAndroid Build Coastguard Worker
BreakDebugger()264*8975f5c5SAndroid Build Coastguard Worker void BreakDebugger()
265*8975f5c5SAndroid Build Coastguard Worker {
266*8975f5c5SAndroid Build Coastguard Worker // This could have a fuller implementation.
267*8975f5c5SAndroid Build Coastguard Worker // See https://cs.chromium.org/chromium/src/base/debug/debugger_posix.cc
268*8975f5c5SAndroid Build Coastguard Worker abort();
269*8975f5c5SAndroid Build Coastguard Worker }
270*8975f5c5SAndroid Build Coastguard Worker
GetExecutableExtension()271*8975f5c5SAndroid Build Coastguard Worker const char *GetExecutableExtension()
272*8975f5c5SAndroid Build Coastguard Worker {
273*8975f5c5SAndroid Build Coastguard Worker return "";
274*8975f5c5SAndroid Build Coastguard Worker }
275*8975f5c5SAndroid Build Coastguard Worker
GetPathSeparator()276*8975f5c5SAndroid Build Coastguard Worker char GetPathSeparator()
277*8975f5c5SAndroid Build Coastguard Worker {
278*8975f5c5SAndroid Build Coastguard Worker return '/';
279*8975f5c5SAndroid Build Coastguard Worker }
280*8975f5c5SAndroid Build Coastguard Worker
GetRootDirectory()281*8975f5c5SAndroid Build Coastguard Worker std::string GetRootDirectory()
282*8975f5c5SAndroid Build Coastguard Worker {
283*8975f5c5SAndroid Build Coastguard Worker return "/";
284*8975f5c5SAndroid Build Coastguard Worker }
285*8975f5c5SAndroid Build Coastguard Worker
CreateDirectories(const std::string & path)286*8975f5c5SAndroid Build Coastguard Worker bool CreateDirectories(const std::string &path)
287*8975f5c5SAndroid Build Coastguard Worker {
288*8975f5c5SAndroid Build Coastguard Worker // First sanitize path so we can use "/" as universal path separator
289*8975f5c5SAndroid Build Coastguard Worker std::string sanitizedPath(path);
290*8975f5c5SAndroid Build Coastguard Worker MakeForwardSlashThePathSeparator(sanitizedPath);
291*8975f5c5SAndroid Build Coastguard Worker
292*8975f5c5SAndroid Build Coastguard Worker size_t pos = 0;
293*8975f5c5SAndroid Build Coastguard Worker do
294*8975f5c5SAndroid Build Coastguard Worker {
295*8975f5c5SAndroid Build Coastguard Worker pos = sanitizedPath.find("/", pos);
296*8975f5c5SAndroid Build Coastguard Worker std::string checkPath(sanitizedPath.substr(0, pos));
297*8975f5c5SAndroid Build Coastguard Worker if (!checkPath.empty() && !IsDirectory(checkPath.c_str()))
298*8975f5c5SAndroid Build Coastguard Worker {
299*8975f5c5SAndroid Build Coastguard Worker if (mkdir(checkPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == -1)
300*8975f5c5SAndroid Build Coastguard Worker {
301*8975f5c5SAndroid Build Coastguard Worker return false;
302*8975f5c5SAndroid Build Coastguard Worker }
303*8975f5c5SAndroid Build Coastguard Worker }
304*8975f5c5SAndroid Build Coastguard Worker if (pos == std::string::npos)
305*8975f5c5SAndroid Build Coastguard Worker {
306*8975f5c5SAndroid Build Coastguard Worker break;
307*8975f5c5SAndroid Build Coastguard Worker }
308*8975f5c5SAndroid Build Coastguard Worker ++pos;
309*8975f5c5SAndroid Build Coastguard Worker } while (true);
310*8975f5c5SAndroid Build Coastguard Worker return true;
311*8975f5c5SAndroid Build Coastguard Worker }
312*8975f5c5SAndroid Build Coastguard Worker
MakeForwardSlashThePathSeparator(std::string & path)313*8975f5c5SAndroid Build Coastguard Worker void MakeForwardSlashThePathSeparator(std::string &path)
314*8975f5c5SAndroid Build Coastguard Worker {
315*8975f5c5SAndroid Build Coastguard Worker // Nothing to do here for *nix side
316*8975f5c5SAndroid Build Coastguard Worker return;
317*8975f5c5SAndroid Build Coastguard Worker }
318*8975f5c5SAndroid Build Coastguard Worker
GetTempDirectory()319*8975f5c5SAndroid Build Coastguard Worker Optional<std::string> GetTempDirectory()
320*8975f5c5SAndroid Build Coastguard Worker {
321*8975f5c5SAndroid Build Coastguard Worker const char *tmp = getenv("TMPDIR");
322*8975f5c5SAndroid Build Coastguard Worker if (tmp != nullptr)
323*8975f5c5SAndroid Build Coastguard Worker {
324*8975f5c5SAndroid Build Coastguard Worker return std::string(tmp);
325*8975f5c5SAndroid Build Coastguard Worker }
326*8975f5c5SAndroid Build Coastguard Worker
327*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_ANDROID)
328*8975f5c5SAndroid Build Coastguard Worker // Not used right now in the ANGLE test runner.
329*8975f5c5SAndroid Build Coastguard Worker // return PathService::Get(DIR_CACHE, path);
330*8975f5c5SAndroid Build Coastguard Worker return Optional<std::string>::Invalid();
331*8975f5c5SAndroid Build Coastguard Worker #else
332*8975f5c5SAndroid Build Coastguard Worker return std::string("/tmp");
333*8975f5c5SAndroid Build Coastguard Worker #endif
334*8975f5c5SAndroid Build Coastguard Worker }
335*8975f5c5SAndroid Build Coastguard Worker
CreateTemporaryFileInDirectory(const std::string & directory)336*8975f5c5SAndroid Build Coastguard Worker Optional<std::string> CreateTemporaryFileInDirectory(const std::string &directory)
337*8975f5c5SAndroid Build Coastguard Worker {
338*8975f5c5SAndroid Build Coastguard Worker return CreateTemporaryFileInDirectoryWithExtension(directory, std::string());
339*8975f5c5SAndroid Build Coastguard Worker }
340*8975f5c5SAndroid Build Coastguard Worker
CreateTemporaryFileInDirectoryWithExtension(const std::string & directory,const std::string & extension)341*8975f5c5SAndroid Build Coastguard Worker Optional<std::string> CreateTemporaryFileInDirectoryWithExtension(const std::string &directory,
342*8975f5c5SAndroid Build Coastguard Worker const std::string &extension)
343*8975f5c5SAndroid Build Coastguard Worker {
344*8975f5c5SAndroid Build Coastguard Worker std::string tempFileTemplate = directory + "/.angle.XXXXXX" + extension;
345*8975f5c5SAndroid Build Coastguard Worker
346*8975f5c5SAndroid Build Coastguard Worker int fd = mkstemps(&tempFileTemplate[0], static_cast<int>(extension.size()));
347*8975f5c5SAndroid Build Coastguard Worker close(fd);
348*8975f5c5SAndroid Build Coastguard Worker
349*8975f5c5SAndroid Build Coastguard Worker if (fd != -1)
350*8975f5c5SAndroid Build Coastguard Worker {
351*8975f5c5SAndroid Build Coastguard Worker return tempFileTemplate;
352*8975f5c5SAndroid Build Coastguard Worker }
353*8975f5c5SAndroid Build Coastguard Worker
354*8975f5c5SAndroid Build Coastguard Worker return Optional<std::string>::Invalid();
355*8975f5c5SAndroid Build Coastguard Worker }
356*8975f5c5SAndroid Build Coastguard Worker
GetCurrentProcessCpuTime()357*8975f5c5SAndroid Build Coastguard Worker double GetCurrentProcessCpuTime()
358*8975f5c5SAndroid Build Coastguard Worker {
359*8975f5c5SAndroid Build Coastguard Worker #ifdef ANGLE_PLATFORM_FUCHSIA
360*8975f5c5SAndroid Build Coastguard Worker static zx_handle_t me = zx_process_self();
361*8975f5c5SAndroid Build Coastguard Worker zx_info_task_runtime_t task_runtime;
362*8975f5c5SAndroid Build Coastguard Worker zx_object_get_info(me, ZX_INFO_TASK_RUNTIME, &task_runtime, sizeof(task_runtime), nullptr,
363*8975f5c5SAndroid Build Coastguard Worker nullptr);
364*8975f5c5SAndroid Build Coastguard Worker return static_cast<double>(task_runtime.cpu_time) * 1e-9;
365*8975f5c5SAndroid Build Coastguard Worker #else
366*8975f5c5SAndroid Build Coastguard Worker // We could also have used /proc/stat, but that requires us to read the
367*8975f5c5SAndroid Build Coastguard Worker // filesystem and convert from jiffies. /proc/stat also relies on jiffies
368*8975f5c5SAndroid Build Coastguard Worker // (lower resolution) while getrusage can potentially use a sched_clock()
369*8975f5c5SAndroid Build Coastguard Worker // underneath that has higher resolution.
370*8975f5c5SAndroid Build Coastguard Worker struct rusage usage;
371*8975f5c5SAndroid Build Coastguard Worker getrusage(RUSAGE_SELF, &usage);
372*8975f5c5SAndroid Build Coastguard Worker double userTime = usage.ru_utime.tv_sec + usage.ru_utime.tv_usec * 1e-6;
373*8975f5c5SAndroid Build Coastguard Worker double systemTime = usage.ru_stime.tv_sec + usage.ru_stime.tv_usec * 1e-6;
374*8975f5c5SAndroid Build Coastguard Worker return userTime + systemTime;
375*8975f5c5SAndroid Build Coastguard Worker #endif
376*8975f5c5SAndroid Build Coastguard Worker }
377*8975f5c5SAndroid Build Coastguard Worker
378*8975f5c5SAndroid Build Coastguard Worker namespace
379*8975f5c5SAndroid Build Coastguard Worker {
SetMemoryProtection(uintptr_t start,size_t size,int protections)380*8975f5c5SAndroid Build Coastguard Worker bool SetMemoryProtection(uintptr_t start, size_t size, int protections)
381*8975f5c5SAndroid Build Coastguard Worker {
382*8975f5c5SAndroid Build Coastguard Worker int ret = mprotect(reinterpret_cast<void *>(start), size, protections);
383*8975f5c5SAndroid Build Coastguard Worker if (ret < 0)
384*8975f5c5SAndroid Build Coastguard Worker {
385*8975f5c5SAndroid Build Coastguard Worker perror("mprotect failed");
386*8975f5c5SAndroid Build Coastguard Worker }
387*8975f5c5SAndroid Build Coastguard Worker return ret == 0;
388*8975f5c5SAndroid Build Coastguard Worker }
389*8975f5c5SAndroid Build Coastguard Worker
390*8975f5c5SAndroid Build Coastguard Worker class PosixPageFaultHandler : public PageFaultHandler
391*8975f5c5SAndroid Build Coastguard Worker {
392*8975f5c5SAndroid Build Coastguard Worker public:
PosixPageFaultHandler(PageFaultCallback callback)393*8975f5c5SAndroid Build Coastguard Worker PosixPageFaultHandler(PageFaultCallback callback) : PageFaultHandler(callback) {}
~PosixPageFaultHandler()394*8975f5c5SAndroid Build Coastguard Worker ~PosixPageFaultHandler() override {}
395*8975f5c5SAndroid Build Coastguard Worker
396*8975f5c5SAndroid Build Coastguard Worker bool enable() override;
397*8975f5c5SAndroid Build Coastguard Worker bool disable() override;
398*8975f5c5SAndroid Build Coastguard Worker void handle(int sig, siginfo_t *info, void *unused);
399*8975f5c5SAndroid Build Coastguard Worker
400*8975f5c5SAndroid Build Coastguard Worker private:
401*8975f5c5SAndroid Build Coastguard Worker struct sigaction mDefaultBusAction = {};
402*8975f5c5SAndroid Build Coastguard Worker struct sigaction mDefaultSegvAction = {};
403*8975f5c5SAndroid Build Coastguard Worker };
404*8975f5c5SAndroid Build Coastguard Worker
405*8975f5c5SAndroid Build Coastguard Worker PosixPageFaultHandler *gPosixPageFaultHandler = nullptr;
SegfaultHandlerFunction(int sig,siginfo_t * info,void * unused)406*8975f5c5SAndroid Build Coastguard Worker void SegfaultHandlerFunction(int sig, siginfo_t *info, void *unused)
407*8975f5c5SAndroid Build Coastguard Worker {
408*8975f5c5SAndroid Build Coastguard Worker gPosixPageFaultHandler->handle(sig, info, unused);
409*8975f5c5SAndroid Build Coastguard Worker }
410*8975f5c5SAndroid Build Coastguard Worker
handle(int sig,siginfo_t * info,void * unused)411*8975f5c5SAndroid Build Coastguard Worker void PosixPageFaultHandler::handle(int sig, siginfo_t *info, void *unused)
412*8975f5c5SAndroid Build Coastguard Worker {
413*8975f5c5SAndroid Build Coastguard Worker bool found = false;
414*8975f5c5SAndroid Build Coastguard Worker if ((sig == SIGSEGV || sig == SIGBUS) &&
415*8975f5c5SAndroid Build Coastguard Worker (info->si_code == SEGV_ACCERR || info->si_code == SEGV_MAPERR))
416*8975f5c5SAndroid Build Coastguard Worker {
417*8975f5c5SAndroid Build Coastguard Worker found = mCallback(reinterpret_cast<uintptr_t>(info->si_addr)) ==
418*8975f5c5SAndroid Build Coastguard Worker PageFaultHandlerRangeType::InRange;
419*8975f5c5SAndroid Build Coastguard Worker }
420*8975f5c5SAndroid Build Coastguard Worker
421*8975f5c5SAndroid Build Coastguard Worker // Fall back to default signal handler
422*8975f5c5SAndroid Build Coastguard Worker if (!found)
423*8975f5c5SAndroid Build Coastguard Worker {
424*8975f5c5SAndroid Build Coastguard Worker if (sig == SIGSEGV)
425*8975f5c5SAndroid Build Coastguard Worker {
426*8975f5c5SAndroid Build Coastguard Worker mDefaultSegvAction.sa_sigaction(sig, info, unused);
427*8975f5c5SAndroid Build Coastguard Worker }
428*8975f5c5SAndroid Build Coastguard Worker else if (sig == SIGBUS)
429*8975f5c5SAndroid Build Coastguard Worker {
430*8975f5c5SAndroid Build Coastguard Worker mDefaultBusAction.sa_sigaction(sig, info, unused);
431*8975f5c5SAndroid Build Coastguard Worker }
432*8975f5c5SAndroid Build Coastguard Worker else
433*8975f5c5SAndroid Build Coastguard Worker {
434*8975f5c5SAndroid Build Coastguard Worker UNREACHABLE();
435*8975f5c5SAndroid Build Coastguard Worker }
436*8975f5c5SAndroid Build Coastguard Worker }
437*8975f5c5SAndroid Build Coastguard Worker }
438*8975f5c5SAndroid Build Coastguard Worker
disable()439*8975f5c5SAndroid Build Coastguard Worker bool PosixPageFaultHandler::disable()
440*8975f5c5SAndroid Build Coastguard Worker {
441*8975f5c5SAndroid Build Coastguard Worker return sigaction(SIGSEGV, &mDefaultSegvAction, nullptr) == 0 &&
442*8975f5c5SAndroid Build Coastguard Worker sigaction(SIGBUS, &mDefaultBusAction, nullptr) == 0;
443*8975f5c5SAndroid Build Coastguard Worker }
444*8975f5c5SAndroid Build Coastguard Worker
enable()445*8975f5c5SAndroid Build Coastguard Worker bool PosixPageFaultHandler::enable()
446*8975f5c5SAndroid Build Coastguard Worker {
447*8975f5c5SAndroid Build Coastguard Worker struct sigaction sigAction = {};
448*8975f5c5SAndroid Build Coastguard Worker sigAction.sa_flags = SA_SIGINFO;
449*8975f5c5SAndroid Build Coastguard Worker sigAction.sa_sigaction = &SegfaultHandlerFunction;
450*8975f5c5SAndroid Build Coastguard Worker sigemptyset(&sigAction.sa_mask);
451*8975f5c5SAndroid Build Coastguard Worker
452*8975f5c5SAndroid Build Coastguard Worker // Some POSIX implementations use SIGBUS for mprotect faults
453*8975f5c5SAndroid Build Coastguard Worker return sigaction(SIGSEGV, &sigAction, &mDefaultSegvAction) == 0 &&
454*8975f5c5SAndroid Build Coastguard Worker sigaction(SIGBUS, &sigAction, &mDefaultBusAction) == 0;
455*8975f5c5SAndroid Build Coastguard Worker }
456*8975f5c5SAndroid Build Coastguard Worker } // namespace
457*8975f5c5SAndroid Build Coastguard Worker
458*8975f5c5SAndroid Build Coastguard Worker // Set write protection
ProtectMemory(uintptr_t start,size_t size)459*8975f5c5SAndroid Build Coastguard Worker bool ProtectMemory(uintptr_t start, size_t size)
460*8975f5c5SAndroid Build Coastguard Worker {
461*8975f5c5SAndroid Build Coastguard Worker return SetMemoryProtection(start, size, PROT_READ);
462*8975f5c5SAndroid Build Coastguard Worker }
463*8975f5c5SAndroid Build Coastguard Worker
464*8975f5c5SAndroid Build Coastguard Worker // Allow reading and writing
UnprotectMemory(uintptr_t start,size_t size)465*8975f5c5SAndroid Build Coastguard Worker bool UnprotectMemory(uintptr_t start, size_t size)
466*8975f5c5SAndroid Build Coastguard Worker {
467*8975f5c5SAndroid Build Coastguard Worker return SetMemoryProtection(start, size, PROT_READ | PROT_WRITE);
468*8975f5c5SAndroid Build Coastguard Worker }
469*8975f5c5SAndroid Build Coastguard Worker
GetPageSize()470*8975f5c5SAndroid Build Coastguard Worker size_t GetPageSize()
471*8975f5c5SAndroid Build Coastguard Worker {
472*8975f5c5SAndroid Build Coastguard Worker long pageSize = sysconf(_SC_PAGE_SIZE);
473*8975f5c5SAndroid Build Coastguard Worker if (pageSize < 0)
474*8975f5c5SAndroid Build Coastguard Worker {
475*8975f5c5SAndroid Build Coastguard Worker perror("Could not get sysconf page size");
476*8975f5c5SAndroid Build Coastguard Worker return 0;
477*8975f5c5SAndroid Build Coastguard Worker }
478*8975f5c5SAndroid Build Coastguard Worker return static_cast<size_t>(pageSize);
479*8975f5c5SAndroid Build Coastguard Worker }
480*8975f5c5SAndroid Build Coastguard Worker
CreatePageFaultHandler(PageFaultCallback callback)481*8975f5c5SAndroid Build Coastguard Worker PageFaultHandler *CreatePageFaultHandler(PageFaultCallback callback)
482*8975f5c5SAndroid Build Coastguard Worker {
483*8975f5c5SAndroid Build Coastguard Worker gPosixPageFaultHandler = new PosixPageFaultHandler(callback);
484*8975f5c5SAndroid Build Coastguard Worker return gPosixPageFaultHandler;
485*8975f5c5SAndroid Build Coastguard Worker }
486*8975f5c5SAndroid Build Coastguard Worker
GetProcessMemoryUsageKB()487*8975f5c5SAndroid Build Coastguard Worker uint64_t GetProcessMemoryUsageKB()
488*8975f5c5SAndroid Build Coastguard Worker {
489*8975f5c5SAndroid Build Coastguard Worker FILE *file = fopen("/proc/self/status", "r");
490*8975f5c5SAndroid Build Coastguard Worker
491*8975f5c5SAndroid Build Coastguard Worker if (!file)
492*8975f5c5SAndroid Build Coastguard Worker {
493*8975f5c5SAndroid Build Coastguard Worker return 0;
494*8975f5c5SAndroid Build Coastguard Worker }
495*8975f5c5SAndroid Build Coastguard Worker
496*8975f5c5SAndroid Build Coastguard Worker const char *kSearchString = "VmRSS:";
497*8975f5c5SAndroid Build Coastguard Worker constexpr size_t kMaxLineSize = 100;
498*8975f5c5SAndroid Build Coastguard Worker std::array<char, kMaxLineSize> line = {};
499*8975f5c5SAndroid Build Coastguard Worker
500*8975f5c5SAndroid Build Coastguard Worker uint64_t kb = 0;
501*8975f5c5SAndroid Build Coastguard Worker
502*8975f5c5SAndroid Build Coastguard Worker while (fgets(line.data(), line.size(), file) != nullptr)
503*8975f5c5SAndroid Build Coastguard Worker {
504*8975f5c5SAndroid Build Coastguard Worker if (strncmp(line.data(), kSearchString, strlen(kSearchString)) == 0)
505*8975f5c5SAndroid Build Coastguard Worker {
506*8975f5c5SAndroid Build Coastguard Worker std::vector<std::string> strings;
507*8975f5c5SAndroid Build Coastguard Worker SplitStringAlongWhitespace(line.data(), &strings);
508*8975f5c5SAndroid Build Coastguard Worker
509*8975f5c5SAndroid Build Coastguard Worker sscanf(strings[1].c_str(), "%" SCNu64, &kb);
510*8975f5c5SAndroid Build Coastguard Worker break;
511*8975f5c5SAndroid Build Coastguard Worker }
512*8975f5c5SAndroid Build Coastguard Worker }
513*8975f5c5SAndroid Build Coastguard Worker fclose(file);
514*8975f5c5SAndroid Build Coastguard Worker
515*8975f5c5SAndroid Build Coastguard Worker return kb;
516*8975f5c5SAndroid Build Coastguard Worker }
517*8975f5c5SAndroid Build Coastguard Worker } // namespace angle
518