1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "perfetto/ext/base/utils.h"
18
19 #include <string>
20
21 #include "perfetto/base/build_config.h"
22 #include "perfetto/base/logging.h"
23 #include "perfetto/ext/base/file_utils.h"
24 #include "perfetto/ext/base/pipe.h"
25 #include "perfetto/ext/base/string_utils.h"
26
27 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
28 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
29 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
30 PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
31 #include <limits.h>
32 #include <stdlib.h> // For _exit()
33 #include <unistd.h> // For getpagesize() and geteuid() & fork()
34 #endif
35
36 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
37 #include <mach-o/dyld.h>
38 #include <mach/vm_page_size.h>
39 #endif
40
41 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
42 #include <Windows.h>
43 #include <io.h>
44 #include <malloc.h> // For _aligned_malloc().
45 #endif
46
47 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
48 #include <dlfcn.h>
49 #include <malloc.h>
50
51 #ifdef M_PURGE
52 #define PERFETTO_M_PURGE M_PURGE
53 #else
54 // Only available in in-tree builds and on newer SDKs.
55 #define PERFETTO_M_PURGE -101
56 #endif // M_PURGE
57
58 #ifdef M_PURGE_ALL
59 #define PERFETTO_M_PURGE_ALL M_PURGE_ALL
60 #else
61 // Only available in in-tree builds and on newer SDKs.
62 #define PERFETTO_M_PURGE_ALL -104
63 #endif // M_PURGE
64
65 namespace {
66 extern "C" {
67 using MalloptType = int (*)(int, int);
68 }
69 } // namespace
70 #endif // OS_ANDROID
71
72 namespace {
73
74 #if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
75
76 // Preserve the %rbx register via %rdi to work around a clang bug
77 // https://bugs.llvm.org/show_bug.cgi?id=17907 (%rbx in an output constraint
78 // is not considered a clobbered register).
79 #define PERFETTO_GETCPUID(a, b, c, d, a_inp, c_inp) \
80 asm("mov %%rbx, %%rdi\n" \
81 "cpuid\n" \
82 "xchg %%rdi, %%rbx\n" \
83 : "=a"(a), "=D"(b), "=c"(c), "=d"(d) \
84 : "a"(a_inp), "2"(c_inp))
85
GetXCR0EAX()86 uint32_t GetXCR0EAX() {
87 uint32_t eax = 0, edx = 0;
88 asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
89 return eax;
90 }
91
92 // If we are building with -msse4 check that the CPU actually supports it.
93 // This file must be kept in sync with gn/standalone/BUILD.gn.
94 void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
CheckCpuOptimizations()95 CheckCpuOptimizations() {
96 uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
97 PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);
98
99 static constexpr uint64_t xcr0_xmm_mask = 0x2;
100 static constexpr uint64_t xcr0_ymm_mask = 0x4;
101 static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;
102
103 const bool have_popcnt = ecx & (1u << 23);
104 const bool have_sse4_2 = ecx & (1u << 20);
105 const bool have_avx =
106 // Does the OS save/restore XMM and YMM state?
107 (ecx & (1u << 27)) && // OS support XGETBV.
108 (ecx & (1u << 28)) && // AVX supported in hardware
109 ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);
110
111 // Get level 7 features (eax = 7 and ecx= 0), to check for AVX2 support.
112 // (See Intel 64 and IA-32 Architectures Software Developer's Manual
113 // Volume 2A: Instruction Set Reference, A-M CPUID).
114 PERFETTO_GETCPUID(eax, ebx, ecx, edx, 7, 0);
115 const bool have_avx2 = have_avx && ((ebx >> 5) & 0x1);
116 const bool have_bmi = (ebx >> 3) & 0x1;
117 const bool have_bmi2 = (ebx >> 8) & 0x1;
118
119 if (!have_sse4_2 || !have_popcnt || !have_avx2 || !have_bmi || !have_bmi2) {
120 fprintf(
121 stderr,
122 "This executable requires a x86_64 cpu that supports SSE4.2, BMI2 and "
123 "AVX2.\n"
124 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
125 "On MacOS, this might be caused by running x86_64 binaries on arm64.\n"
126 "See https://github.com/google/perfetto/issues/294 for more.\n"
127 #endif
128 "Rebuild with enable_perfetto_x64_cpu_opt=false.\n");
129 _exit(126);
130 }
131 }
132 #endif
133
134 } // namespace
135
136 namespace perfetto {
137 namespace base {
138
139 namespace internal {
140
141 std::atomic<uint32_t> g_cached_page_size{0};
142
GetSysPageSizeSlowpath()143 uint32_t GetSysPageSizeSlowpath() {
144 uint32_t page_size = 0;
145 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
146 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
147 const int page_size_int = getpagesize();
148 // If sysconf() fails for obscure reasons (e.g. SELinux denial) assume the
149 // page size is 4KB. This is to avoid regressing subtle SDK usages, as old
150 // versions of this code had a static constant baked in.
151 page_size = static_cast<uint32_t>(page_size_int > 0 ? page_size_int : 4096);
152 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
153 page_size = static_cast<uint32_t>(vm_page_size);
154 #else
155 page_size = 4096;
156 #endif
157
158 PERFETTO_CHECK(page_size > 0 && page_size % 4096 == 0);
159
160 // Races here are fine because any thread will write the same value.
161 g_cached_page_size.store(page_size, std::memory_order_relaxed);
162 return page_size;
163 }
164
165 } // namespace internal
166
MaybeReleaseAllocatorMemToOS()167 void MaybeReleaseAllocatorMemToOS() {
168 #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
169 // mallopt() on Android requires SDK level 26. Many targets and embedders
170 // still depend on a lower SDK level. Given mallopt() is a quite simple API,
171 // use reflection to do this rather than bumping the SDK level for all
172 // embedders. This keeps the behavior of standalone builds aligned with
173 // in-tree builds.
174 static MalloptType mallopt_fn =
175 reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
176 if (!mallopt_fn)
177 return;
178 if (mallopt_fn(PERFETTO_M_PURGE_ALL, 0) == 0) {
179 mallopt_fn(PERFETTO_M_PURGE, 0);
180 }
181 #endif
182 }
183
GetCurrentUserId()184 uid_t GetCurrentUserId() {
185 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
186 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
187 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
188 return geteuid();
189 #else
190 // TODO(primiano): On Windows we could hash the current user SID and derive a
191 // numeric user id [1]. It is not clear whether we need that. Right now that
192 // would not bring any benefit. Returning 0 unil we can prove we need it.
193 // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
194 return 0;
195 #endif
196 }
197
SetEnv(const std::string & key,const std::string & value)198 void SetEnv(const std::string& key, const std::string& value) {
199 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
200 PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
201 #else
202 PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
203 #endif
204 }
205
UnsetEnv(const std::string & key)206 void UnsetEnv(const std::string& key) {
207 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
208 PERFETTO_CHECK(::_putenv_s(key.c_str(), "") == 0);
209 #else
210 PERFETTO_CHECK(::unsetenv(key.c_str()) == 0);
211 #endif
212 }
213
Daemonize(std::function<int ()> parent_cb)214 void Daemonize(std::function<int()> parent_cb) {
215 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
216 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
217 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
218 Pipe pipe = Pipe::Create(Pipe::kBothBlock);
219 pid_t pid;
220 switch (pid = fork()) {
221 case -1:
222 PERFETTO_FATAL("fork");
223 case 0: {
224 PERFETTO_CHECK(setsid() != -1);
225 base::ignore_result(chdir("/"));
226 base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
227 PERFETTO_CHECK(null);
228 PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
229 PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
230 PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
231 // Do not accidentally close stdin/stdout/stderr.
232 if (*null <= 2)
233 null.release();
234 WriteAll(*pipe.wr, "1", 1);
235 break;
236 }
237 default: {
238 // Wait for the child process to have reached the setsid() call. This is
239 // to avoid that 'adb shell perfetto -D' destroys the terminal (hence
240 // sending a SIGHUP to the child) before the child has detached from the
241 // terminal (see b/238644870).
242
243 // This is to unblock the read() below (with EOF, which will fail the
244 // CHECK) in the unlikely case of the child crashing before WriteAll("1").
245 pipe.wr.reset();
246 char one = '\0';
247 PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1');
248 printf("%d\n", pid);
249 int err = parent_cb();
250 exit(err);
251 }
252 }
253 #else
254 // Avoid -Wunreachable warnings.
255 if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
256 PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
257 ignore_result(parent_cb);
258 #endif // OS_WIN
259 }
260
GetCurExecutablePath()261 std::string GetCurExecutablePath() {
262 std::string self_path;
263 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
264 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
265 PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
266 char buf[PATH_MAX];
267 ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
268 PERFETTO_CHECK(size != -1);
269 // readlink does not null terminate.
270 self_path = std::string(buf, static_cast<size_t>(size));
271 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
272 uint32_t size = 0;
273 PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
274 self_path.resize(size);
275 PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
276 #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
277 char buf[MAX_PATH];
278 auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
279 self_path = std::string(buf, len);
280 #else
281 PERFETTO_FATAL(
282 "GetCurExecutableDir() not implemented on the current platform");
283 #endif
284 return self_path;
285 }
286
GetCurExecutableDir()287 std::string GetCurExecutableDir() {
288 auto path = GetCurExecutablePath();
289 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
290 // Paths in Windows can have both kinds of slashes (mingw vs msvc).
291 path = path.substr(0, path.find_last_of('\\'));
292 #endif
293 path = path.substr(0, path.find_last_of('/'));
294 return path;
295 }
296
AlignedAlloc(size_t alignment,size_t size)297 void* AlignedAlloc(size_t alignment, size_t size) {
298 void* res = nullptr;
299 alignment = AlignUp<sizeof(void*)>(alignment); // At least pointer size.
300 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
301 // Window's _aligned_malloc() has a nearly identically signature to Unix's
302 // aligned_alloc() but its arguments are obviously swapped.
303 res = _aligned_malloc(size, alignment);
304 #else
305 // aligned_alloc() has been introduced in Android only in API 28.
306 // Also NaCl and Fuchsia seems to have only posix_memalign().
307 ignore_result(posix_memalign(&res, alignment, size));
308 #endif
309 PERFETTO_CHECK(res);
310 return res;
311 }
312
AlignedFree(void * ptr)313 void AlignedFree(void* ptr) {
314 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
315 _aligned_free(ptr); // MSDN says it is fine to pass nullptr.
316 #else
317 free(ptr);
318 #endif
319 }
320
HexDump(const void * data_void,size_t len,size_t bytes_per_line)321 std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
322 const char* data = reinterpret_cast<const char*>(data_void);
323 std::string res;
324 static const size_t kPadding = bytes_per_line * 3 + 12;
325 std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
326 for (size_t i = 0; i < len; i += bytes_per_line) {
327 char* wptr = line.get();
328 wptr += base::SprintfTrunc(wptr, 19, "%08zX: ", i);
329 for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
330 wptr += base::SprintfTrunc(wptr, 4, "%02X ",
331 static_cast<unsigned>(data[j]) & 0xFF);
332 }
333 for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
334 *(wptr++) = ' ';
335 for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
336 char c = data[j];
337 *(wptr++) = (c >= 32 && c < 127) ? c : '.';
338 }
339 *(wptr++) = '\n';
340 *(wptr++) = '\0';
341 res.append(line.get());
342 }
343 return res;
344 }
345
346 } // namespace base
347 } // namespace perfetto
348