xref: /aosp_15_r20/external/perfetto/src/base/utils.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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_LINUX) || \
42     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
43 #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 
59 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
60 #include <Windows.h>
61 #include <io.h>
62 #include <malloc.h>  // For _aligned_malloc().
63 #endif
64 
65 #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
74 #endif  // M_PURGE
75 
76 #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 
83 namespace {
84 extern "C" {
85 using MalloptType = int (*)(int, int);
86 }
87 }  // namespace
88 #endif  // OS_ANDROID
89 
90 namespace {
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 
GetXCR0EAX()104 uint32_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.
112 void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
CheckCpuOptimizations()113 CheckCpuOptimizations() {
114   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?
125       (ecx & (1u << 27)) &&  // OS support XGETBV.
126       (ecx & (1u << 28)) &&  // AVX supported in hardware
127       ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);
128 
129   // 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);
134   const bool have_bmi = (ebx >> 3) & 0x1;
135   const bool have_bmi2 = (ebx >> 8) & 0x1;
136 
137   if (!have_sse4_2 || !have_popcnt || !have_avx2 || !have_bmi || !have_bmi2) {
138     fprintf(
139         stderr,
140         "This executable requires a x86_64 cpu that supports SSE4.2, BMI2 and "
141         "AVX2.\n"
142 #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
146         "Rebuild with enable_perfetto_x64_cpu_opt=false.\n");
147     _exit(126);
148   }
149 }
150 #endif
151 
152 }  // namespace
153 
154 namespace perfetto {
155 namespace base {
156 
157 namespace internal {
158 
159 std::atomic<uint32_t> g_cached_page_size{0};
160 
GetSysPageSizeSlowpath()161 uint32_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 
MaybeReleaseAllocatorMemToOS()185 void 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;
196   if (mallopt_fn(PERFETTO_M_PURGE_ALL, 0) == 0) {
197     mallopt_fn(PERFETTO_M_PURGE, 0);
198   }
199 #endif
200 }
201 
GetCurrentUserId()202 uid_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 
SetEnv(const std::string & key,const std::string & value)216 void 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 
UnsetEnv(const std::string & key)224 void 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 
Daemonize(std::function<int ()> parent_cb)232 void Daemonize(std::function<int()> parent_cb) {
233 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
234     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
235     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
236   Pipe pipe = Pipe::Create(Pipe::kBothBlock);
237   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();
252       WriteAll(*pipe.wr, "1", 1);
253       break;
254     }
255     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');
266       printf("%d\n", pid);
267       int err = parent_cb();
268       exit(err);
269     }
270   }
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");
275   ignore_result(parent_cb);
276 #endif  // OS_WIN
277 }
278 
GetCurExecutablePath()279 std::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 
GetCurExecutableDir()305 std::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).
309   path = path.substr(0, path.find_last_of('\\'));
310 #endif
311   path = path.substr(0, path.find_last_of('/'));
312   return path;
313 }
314 
AlignedAlloc(size_t alignment,size_t size)315 void* AlignedAlloc(size_t alignment, size_t size) {
316   void* res = nullptr;
317   alignment = AlignUp<sizeof(void*)>(alignment);  // At least pointer size.
318 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
319   // 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
323   // 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));
326 #endif
327   PERFETTO_CHECK(res);
328   return res;
329 }
330 
AlignedFree(void * ptr)331 void 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 
IsSyncMemoryTaggingEnabled()339 bool 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 
HexDump(const void * data_void,size_t len,size_t bytes_per_line)356 std::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();
363     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     }
368     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 
381 }  // namespace base
382 }  // namespace perfetto
383