blob: 419c7dbc1a648d7983afb175ec5f52d079f04815 [file] [log] [blame]
Primiano Tuccia81d2772020-10-07 00:12:41 +02001/*
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
Primiano Tucci003b20e2021-05-21 10:21:43 +010019#include <string>
20
Primiano Tuccia81d2772020-10-07 00:12:41 +020021#include "perfetto/base/build_config.h"
Primiano Tucci10c9e9e2021-01-08 13:04:40 +010022#include "perfetto/base/logging.h"
Primiano Tucci003b20e2021-05-21 10:21:43 +010023#include "perfetto/ext/base/file_utils.h"
Primiano Tucci2cb8b212022-07-18 14:30:26 +010024#include "perfetto/ext/base/pipe.h"
Justin Cohen85f25b82022-06-06 22:42:11 -040025#include "perfetto/ext/base/string_utils.h"
Primiano Tuccia81d2772020-10-07 00:12:41 +020026
Primiano Tucci10c9e9e2021-01-08 13:04:40 +010027#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
28 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
Primiano Tucci003b20e2021-05-21 10:21:43 +010029 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
30 PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
31#include <limits.h>
Primiano Tucci2277f062021-11-08 22:24:05 +000032#include <stdlib.h> // For _exit()
Rahul Ravikumarce6dcb42021-04-19 11:21:40 -070033#include <unistd.h> // For getpagesize() and geteuid() & fork()
Primiano Tucci10c9e9e2021-01-08 13:04:40 +010034#endif
35
36#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
Primiano Tucci003b20e2021-05-21 10:21:43 +010037#include <mach-o/dyld.h>
Primiano Tucciab293f52020-12-08 11:46:52 +010038#include <mach/vm_page_size.h>
39#endif
40
Primiano Tucciad665f02024-07-16 16:11:22 -070041#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
42 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
Primiano Tucciad665f02024-07-16 16:11:22 -070043#include <sys/prctl.h>
44
45#ifndef PR_GET_TAGGED_ADDR_CTRL
46#define PR_GET_TAGGED_ADDR_CTRL 56
47#endif
48
49#ifndef PR_TAGGED_ADDR_ENABLE
50#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
51#endif
52
53#ifndef PR_MTE_TCF_SYNC
54#define PR_MTE_TCF_SYNC (1UL << 1)
55#endif
56
57#endif // OS_LINUX | OS_ANDROID
58
Primiano Tucci003b20e2021-05-21 10:21:43 +010059#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
60#include <Windows.h>
61#include <io.h>
Primiano Tuccic50345c2021-11-09 23:10:06 +000062#include <malloc.h> // For _aligned_malloc().
Primiano Tucci003b20e2021-05-21 10:21:43 +010063#endif
64
Primiano Tuccia81d2772020-10-07 00:12:41 +020065#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
66#include <dlfcn.h>
67#include <malloc.h>
68
69#ifdef M_PURGE
70#define PERFETTO_M_PURGE M_PURGE
71#else
72// Only available in in-tree builds and on newer SDKs.
73#define PERFETTO_M_PURGE -101
Primiano Tucci003b20e2021-05-21 10:21:43 +010074#endif // M_PURGE
Primiano Tuccia81d2772020-10-07 00:12:41 +020075
Christopher Ferris50f34782023-05-10 14:59:42 -070076#ifdef M_PURGE_ALL
77#define PERFETTO_M_PURGE_ALL M_PURGE_ALL
78#else
79// Only available in in-tree builds and on newer SDKs.
80#define PERFETTO_M_PURGE_ALL -104
81#endif // M_PURGE
82
Primiano Tuccia81d2772020-10-07 00:12:41 +020083namespace {
84extern "C" {
Christopher Ferris50f34782023-05-10 14:59:42 -070085using MalloptType = int (*)(int, int);
Primiano Tuccia81d2772020-10-07 00:12:41 +020086}
87} // namespace
88#endif // OS_ANDROID
89
Primiano Tucci2277f062021-11-08 22:24:05 +000090namespace {
91
92#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
93
94// Preserve the %rbx register via %rdi to work around a clang bug
95// https://bugs.llvm.org/show_bug.cgi?id=17907 (%rbx in an output constraint
96// is not considered a clobbered register).
97#define PERFETTO_GETCPUID(a, b, c, d, a_inp, c_inp) \
98 asm("mov %%rbx, %%rdi\n" \
99 "cpuid\n" \
100 "xchg %%rdi, %%rbx\n" \
101 : "=a"(a), "=D"(b), "=c"(c), "=d"(d) \
102 : "a"(a_inp), "2"(c_inp))
103
104uint32_t GetXCR0EAX() {
105 uint32_t eax = 0, edx = 0;
106 asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
107 return eax;
108}
109
110// If we are building with -msse4 check that the CPU actually supports it.
111// This file must be kept in sync with gn/standalone/BUILD.gn.
Daniele Di Proiettoa79094e2022-04-29 11:09:58 +0100112void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
Daniele Di Proiettoadaabb62022-04-26 13:27:24 +0100113CheckCpuOptimizations() {
Primiano Tucci2277f062021-11-08 22:24:05 +0000114 uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
115 PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);
116
117 static constexpr uint64_t xcr0_xmm_mask = 0x2;
118 static constexpr uint64_t xcr0_ymm_mask = 0x4;
119 static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;
120
121 const bool have_popcnt = ecx & (1u << 23);
122 const bool have_sse4_2 = ecx & (1u << 20);
123 const bool have_avx =
124 // Does the OS save/restore XMM and YMM state?
Primiano Tucci2277f062021-11-08 22:24:05 +0000125 (ecx & (1u << 27)) && // OS support XGETBV.
Primiano Tucci0e7915d2022-02-08 15:25:49 +0000126 (ecx & (1u << 28)) && // AVX supported in hardware
127 ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);
Primiano Tucci2277f062021-11-08 22:24:05 +0000128
Primiano Tucci682a9982022-05-20 17:13:28 +0100129 // Get level 7 features (eax = 7 and ecx= 0), to check for AVX2 support.
130 // (See Intel 64 and IA-32 Architectures Software Developer's Manual
131 // Volume 2A: Instruction Set Reference, A-M CPUID).
132 PERFETTO_GETCPUID(eax, ebx, ecx, edx, 7, 0);
133 const bool have_avx2 = have_avx && ((ebx >> 5) & 0x1);
Lalit Maganti25a45342022-06-14 14:56:48 +0100134 const bool have_bmi = (ebx >> 3) & 0x1;
135 const bool have_bmi2 = (ebx >> 8) & 0x1;
Primiano Tucci682a9982022-05-20 17:13:28 +0100136
Lalit Maganti25a45342022-06-14 14:56:48 +0100137 if (!have_sse4_2 || !have_popcnt || !have_avx2 || !have_bmi || !have_bmi2) {
Primiano Tucci2277f062021-11-08 22:24:05 +0000138 fprintf(
139 stderr,
Lalit Maganti25a45342022-06-14 14:56:48 +0100140 "This executable requires a x86_64 cpu that supports SSE4.2, BMI2 and "
141 "AVX2.\n"
Primiano Tuccib37cdb82022-05-20 16:31:44 +0100142#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
143 "On MacOS, this might be caused by running x86_64 binaries on arm64.\n"
144 "See https://github.com/google/perfetto/issues/294 for more.\n"
145#endif
Primiano Tucci682a9982022-05-20 17:13:28 +0100146 "Rebuild with enable_perfetto_x64_cpu_opt=false.\n");
Primiano Tucci2277f062021-11-08 22:24:05 +0000147 _exit(126);
148 }
149}
150#endif
151
152} // namespace
153
Primiano Tuccia81d2772020-10-07 00:12:41 +0200154namespace perfetto {
155namespace base {
156
Primiano Tucci0b3de742023-11-09 22:55:33 +0000157namespace internal {
158
159std::atomic<uint32_t> g_cached_page_size{0};
160
161uint32_t GetSysPageSizeSlowpath() {
162 uint32_t page_size = 0;
163#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
164 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
165 const int page_size_int = getpagesize();
166 // If sysconf() fails for obscure reasons (e.g. SELinux denial) assume the
167 // page size is 4KB. This is to avoid regressing subtle SDK usages, as old
168 // versions of this code had a static constant baked in.
169 page_size = static_cast<uint32_t>(page_size_int > 0 ? page_size_int : 4096);
170#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
171 page_size = static_cast<uint32_t>(vm_page_size);
172#else
173 page_size = 4096;
174#endif
175
176 PERFETTO_CHECK(page_size > 0 && page_size % 4096 == 0);
177
178 // Races here are fine because any thread will write the same value.
179 g_cached_page_size.store(page_size, std::memory_order_relaxed);
180 return page_size;
181}
182
183} // namespace internal
184
Primiano Tuccia81d2772020-10-07 00:12:41 +0200185void MaybeReleaseAllocatorMemToOS() {
186#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
187 // mallopt() on Android requires SDK level 26. Many targets and embedders
188 // still depend on a lower SDK level. Given mallopt() is a quite simple API,
189 // use reflection to do this rather than bumping the SDK level for all
190 // embedders. This keeps the behavior of standalone builds aligned with
191 // in-tree builds.
192 static MalloptType mallopt_fn =
193 reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
194 if (!mallopt_fn)
195 return;
Christopher Ferris50f34782023-05-10 14:59:42 -0700196 if (mallopt_fn(PERFETTO_M_PURGE_ALL, 0) == 0) {
197 mallopt_fn(PERFETTO_M_PURGE, 0);
198 }
Primiano Tuccia81d2772020-10-07 00:12:41 +0200199#endif
200}
201
Primiano Tucci10c9e9e2021-01-08 13:04:40 +0100202uid_t GetCurrentUserId() {
203#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
204 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
205 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
206 return geteuid();
207#else
208 // TODO(primiano): On Windows we could hash the current user SID and derive a
209 // numeric user id [1]. It is not clear whether we need that. Right now that
210 // would not bring any benefit. Returning 0 unil we can prove we need it.
211 // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
212 return 0;
213#endif
214}
215
216void SetEnv(const std::string& key, const std::string& value) {
217#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
218 PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
219#else
220 PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
221#endif
222}
223
Daniele Di Proietto65c6a282022-09-22 14:54:26 +0100224void UnsetEnv(const std::string& key) {
225#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
226 PERFETTO_CHECK(::_putenv_s(key.c_str(), "") == 0);
227#else
228 PERFETTO_CHECK(::unsetenv(key.c_str()) == 0);
229#endif
230}
231
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100232void Daemonize(std::function<int()> parent_cb) {
Primiano Tucci003b20e2021-05-21 10:21:43 +0100233#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
234 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
235 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
Primiano Tucci2cb8b212022-07-18 14:30:26 +0100236 Pipe pipe = Pipe::Create(Pipe::kBothBlock);
Primiano Tucci003b20e2021-05-21 10:21:43 +0100237 pid_t pid;
238 switch (pid = fork()) {
239 case -1:
240 PERFETTO_FATAL("fork");
241 case 0: {
242 PERFETTO_CHECK(setsid() != -1);
243 base::ignore_result(chdir("/"));
244 base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
245 PERFETTO_CHECK(null);
246 PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
247 PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
248 PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
249 // Do not accidentally close stdin/stdout/stderr.
250 if (*null <= 2)
251 null.release();
Primiano Tucci2cb8b212022-07-18 14:30:26 +0100252 WriteAll(*pipe.wr, "1", 1);
Primiano Tucci003b20e2021-05-21 10:21:43 +0100253 break;
254 }
Primiano Tucci2cb8b212022-07-18 14:30:26 +0100255 default: {
256 // Wait for the child process to have reached the setsid() call. This is
257 // to avoid that 'adb shell perfetto -D' destroys the terminal (hence
258 // sending a SIGHUP to the child) before the child has detached from the
259 // terminal (see b/238644870).
260
261 // This is to unblock the read() below (with EOF, which will fail the
262 // CHECK) in the unlikely case of the child crashing before WriteAll("1").
263 pipe.wr.reset();
264 char one = '\0';
265 PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1');
Primiano Tucci003b20e2021-05-21 10:21:43 +0100266 printf("%d\n", pid);
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100267 int err = parent_cb();
268 exit(err);
Primiano Tucci2cb8b212022-07-18 14:30:26 +0100269 }
Primiano Tucci003b20e2021-05-21 10:21:43 +0100270 }
271#else
272 // Avoid -Wunreachable warnings.
273 if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
274 PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100275 ignore_result(parent_cb);
Primiano Tucci003b20e2021-05-21 10:21:43 +0100276#endif // OS_WIN
277}
278
279std::string GetCurExecutablePath() {
280 std::string self_path;
281#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
282 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
283 PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
284 char buf[PATH_MAX];
285 ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
286 PERFETTO_CHECK(size != -1);
287 // readlink does not null terminate.
288 self_path = std::string(buf, static_cast<size_t>(size));
289#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
290 uint32_t size = 0;
291 PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
292 self_path.resize(size);
293 PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
294#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
295 char buf[MAX_PATH];
296 auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
297 self_path = std::string(buf, len);
298#else
299 PERFETTO_FATAL(
300 "GetCurExecutableDir() not implemented on the current platform");
301#endif
302 return self_path;
303}
304
305std::string GetCurExecutableDir() {
306 auto path = GetCurExecutablePath();
307#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
308 // Paths in Windows can have both kinds of slashes (mingw vs msvc).
Hector Dearman1fe10ce2021-08-23 11:44:26 +0100309 path = path.substr(0, path.find_last_of('\\'));
Primiano Tucci003b20e2021-05-21 10:21:43 +0100310#endif
Hector Dearman1fe10ce2021-08-23 11:44:26 +0100311 path = path.substr(0, path.find_last_of('/'));
Primiano Tucci003b20e2021-05-21 10:21:43 +0100312 return path;
Rahul Ravikumarce6dcb42021-04-19 11:21:40 -0700313}
314
Primiano Tuccic50345c2021-11-09 23:10:06 +0000315void* AlignedAlloc(size_t alignment, size_t size) {
316 void* res = nullptr;
317 alignment = AlignUp<sizeof(void*)>(alignment); // At least pointer size.
Primiano Tuccid99b5d22021-11-10 08:16:02 +0000318#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Primiano Tuccic50345c2021-11-09 23:10:06 +0000319 // Window's _aligned_malloc() has a nearly identically signature to Unix's
320 // aligned_alloc() but its arguments are obviously swapped.
321 res = _aligned_malloc(size, alignment);
322#else
Primiano Tuccid99b5d22021-11-10 08:16:02 +0000323 // aligned_alloc() has been introduced in Android only in API 28.
324 // Also NaCl and Fuchsia seems to have only posix_memalign().
325 ignore_result(posix_memalign(&res, alignment, size));
Primiano Tuccic50345c2021-11-09 23:10:06 +0000326#endif
327 PERFETTO_CHECK(res);
328 return res;
329}
330
Primiano Tucci97cab972021-11-12 00:17:10 +0000331void AlignedFree(void* ptr) {
332#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
333 _aligned_free(ptr); // MSDN says it is fine to pass nullptr.
334#else
335 free(ptr);
336#endif
337}
338
Primiano Tucciad665f02024-07-16 16:11:22 -0700339bool IsSyncMemoryTaggingEnabled() {
340#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
341 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
342 // Compute only once per lifetime of the process.
343 static bool cached_value = [] {
344 const int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
345 if (res < 0)
346 return false;
347 const uint32_t actl = static_cast<uint32_t>(res);
348 return (actl & PR_TAGGED_ADDR_ENABLE) && (actl & PR_MTE_TCF_SYNC);
349 }();
350 return cached_value;
351#else
352 return false;
353#endif
354}
355
Daniele Di Proiettobad67fa2021-11-26 14:50:01 +0000356std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
357 const char* data = reinterpret_cast<const char*>(data_void);
358 std::string res;
359 static const size_t kPadding = bytes_per_line * 3 + 12;
360 std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
361 for (size_t i = 0; i < len; i += bytes_per_line) {
362 char* wptr = line.get();
Justin Cohen85f25b82022-06-06 22:42:11 -0400363 wptr += base::SprintfTrunc(wptr, 19, "%08zX: ", i);
364 for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
365 wptr += base::SprintfTrunc(wptr, 4, "%02X ",
366 static_cast<unsigned>(data[j]) & 0xFF);
367 }
Daniele Di Proiettobad67fa2021-11-26 14:50:01 +0000368 for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
369 *(wptr++) = ' ';
370 for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
371 char c = data[j];
372 *(wptr++) = (c >= 32 && c < 127) ? c : '.';
373 }
374 *(wptr++) = '\n';
375 *(wptr++) = '\0';
376 res.append(line.get());
377 }
378 return res;
379}
380
Primiano Tuccia81d2772020-10-07 00:12:41 +0200381} // namespace base
382} // namespace perfetto