Coverage Report

Created: 2026-06-07 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/perfetto/src/base/utils.cc
Line
Count
Source
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_BUT_NOT_QNX) || \
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
0
#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
48
  asm("mov %%rbx, %%rdi\n"                          \
99
48
      "cpuid\n"                                     \
100
48
      "xchg %%rdi, %%rbx\n"                         \
101
48
      : "=a"(a), "=D"(b), "=c"(c), "=d"(d)          \
102
48
      : "a"(a_inp), "2"(c_inp))
103
104
24
uint32_t GetXCR0EAX() {
105
24
  uint32_t eax = 0, edx = 0;
106
24
  asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
107
24
  return eax;
108
24
}
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))
113
24
CheckCpuOptimizations() {
114
24
  uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
115
24
  PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);
116
117
24
  static constexpr uint64_t xcr0_xmm_mask = 0x2;
118
24
  static constexpr uint64_t xcr0_ymm_mask = 0x4;
119
24
  static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;
120
121
24
  const bool have_popcnt = ecx & (1u << 23);
122
24
  const bool have_sse4_2 = ecx & (1u << 20);
123
24
  const bool have_avx =
124
      // Does the OS save/restore XMM and YMM state?
125
24
      (ecx & (1u << 27)) &&  // OS support XGETBV.
126
24
      (ecx & (1u << 28)) &&  // AVX supported in hardware
127
24
      ((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
24
  PERFETTO_GETCPUID(eax, ebx, ecx, edx, 7, 0);
133
24
  const bool have_avx2 = have_avx && ((ebx >> 5) & 0x1);
134
24
  const bool have_bmi = (ebx >> 3) & 0x1;
135
24
  const bool have_bmi2 = (ebx >> 8) & 0x1;
136
137
24
  if (!have_sse4_2 || !have_popcnt || !have_avx2 || !have_bmi || !have_bmi2) {
138
0
    fprintf(
139
0
        stderr,
140
0
        "This executable requires a x86_64 cpu that supports SSE4.2, BMI2 and "
141
0
        "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
0
        "Rebuild with enable_perfetto_x64_cpu_opt=false.\n");
147
0
    _exit(126);
148
0
  }
149
24
}
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
161
7
uint32_t GetSysPageSizeSlowpath() {
162
7
  uint32_t page_size = 0;
163
7
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
164
7
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
165
7
  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
7
  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
7
  PERFETTO_CHECK(page_size > 0 && page_size % 4096 == 0);
177
178
  // Races here are fine because any thread will write the same value.
179
7
  g_cached_page_size.store(page_size, std::memory_order_relaxed);
180
7
  return page_size;
181
7
}
182
183
}  // namespace internal
184
185
348
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
348
}
201
202
350
uid_t GetCurrentUserId() {
203
350
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
204
350
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
205
350
    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
206
350
  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
350
}
215
216
700
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
700
  PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
221
700
#endif
222
700
}
223
224
700
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
700
  PERFETTO_CHECK(::unsetenv(key.c_str()) == 0);
229
700
#endif
230
700
}
231
232
0
void Daemonize(std::function<int()> parent_cb) {
233
0
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
234
0
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
235
0
    (PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) &&  \
236
0
     !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE_TVOS))
237
0
  Pipe pipe = Pipe::Create(Pipe::kBothBlock);
238
0
  pid_t pid;
239
0
  switch (pid = fork()) {
240
0
    case -1:
241
0
      PERFETTO_FATAL("fork");
242
0
    case 0: {
243
0
      PERFETTO_CHECK(setsid() != -1);
244
0
      base::ignore_result(chdir("/"));
245
0
      base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
246
0
      PERFETTO_CHECK(null);
247
0
      PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
248
0
      PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
249
0
      PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
250
      // Do not accidentally close stdin/stdout/stderr.
251
0
      if (*null <= 2)
252
0
        null.release();
253
0
      WriteAll(*pipe.wr, "1", 1);
254
0
      break;
255
0
    }
256
0
    default: {
257
      // Wait for the child process to have reached the setsid() call. This is
258
      // to avoid that 'adb shell perfetto -D' destroys the terminal (hence
259
      // sending a SIGHUP to the child) before the child has detached from the
260
      // terminal (see b/238644870).
261
262
      // This is to unblock the read() below (with EOF, which will fail the
263
      // CHECK) in the unlikely case of the child crashing before WriteAll("1").
264
0
      pipe.wr.reset();
265
0
      char one = '\0';
266
0
      PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1');
267
0
      printf("%d\n", pid);
268
0
      int err = parent_cb();
269
0
      exit(err);
270
0
    }
271
0
  }
272
#else
273
  // Avoid -Wunreachable warnings.
274
  if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
275
    PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
276
  ignore_result(parent_cb);
277
#endif  // OS_WIN
278
0
}
279
280
0
std::string GetCurExecutablePath() {
281
0
  std::string self_path;
282
0
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
283
0
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
284
0
    PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
285
0
  char buf[PATH_MAX];
286
0
  ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
287
0
  PERFETTO_CHECK(size != -1);
288
  // readlink does not null terminate.
289
0
  self_path = std::string(buf, static_cast<size_t>(size));
290
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
291
  uint32_t size = 0;
292
  PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
293
  self_path.resize(size);
294
  PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
295
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
296
  char buf[MAX_PATH];
297
  auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
298
  self_path = std::string(buf, len);
299
#else
300
  PERFETTO_FATAL(
301
      "GetCurExecutableDir() not implemented on the current platform");
302
#endif
303
0
  return self_path;
304
0
}
305
306
0
std::string GetCurExecutableDir() {
307
0
  auto path = GetCurExecutablePath();
308
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
309
  // Paths in Windows can have both kinds of slashes (mingw vs msvc).
310
  path = path.substr(0, path.find_last_of('\\'));
311
#endif
312
0
  path = path.substr(0, path.find_last_of('/'));
313
0
  return path;
314
0
}
315
316
1.14M
void* AlignedAlloc(size_t alignment, size_t size) {
317
1.14M
  void* res = nullptr;
318
1.14M
  alignment = AlignUp<sizeof(void*)>(alignment);  // At least pointer size.
319
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
320
  // Window's _aligned_malloc() has a nearly identically signature to Unix's
321
  // aligned_alloc() but its arguments are obviously swapped.
322
  res = _aligned_malloc(size, alignment);
323
#else
324
  // aligned_alloc() has been introduced in Android only in API 28.
325
  // Also NaCl and Fuchsia seems to have only posix_memalign().
326
1.14M
  ignore_result(posix_memalign(&res, alignment, size));
327
1.14M
#endif
328
1.14M
  PERFETTO_CHECK(res);
329
1.14M
  return res;
330
1.14M
}
331
332
1.14M
void AlignedFree(void* ptr) {
333
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
334
  _aligned_free(ptr);  // MSDN says it is fine to pass nullptr.
335
#else
336
1.14M
  free(ptr);
337
1.14M
#endif
338
1.14M
}
339
340
0
bool IsSyncMemoryTaggingEnabled() {
341
0
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \
342
0
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
343
  // Compute only once per lifetime of the process.
344
0
  static bool cached_value = [] {
345
0
    const int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
346
0
    if (res < 0)
347
0
      return false;
348
0
    const uint32_t actl = static_cast<uint32_t>(res);
349
0
    return (actl & PR_TAGGED_ADDR_ENABLE) && (actl & PR_MTE_TCF_SYNC);
350
0
  }();
351
0
  return cached_value;
352
#else
353
  return false;
354
#endif
355
0
}
356
357
0
std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
358
0
  const char* data = reinterpret_cast<const char*>(data_void);
359
0
  std::string res;
360
0
  static const size_t kPadding = bytes_per_line * 3 + 12;
361
0
  std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
362
0
  for (size_t i = 0; i < len; i += bytes_per_line) {
363
0
    char* wptr = line.get();
364
0
    wptr += base::SprintfTrunc(wptr, 19, "%08zX: ", i);
365
0
    for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
366
0
      wptr += base::SprintfTrunc(wptr, 4, "%02X ",
367
0
                                 static_cast<unsigned>(data[j]) & 0xFF);
368
0
    }
369
0
    for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
370
0
      *(wptr++) = ' ';
371
0
    for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
372
0
      char c = data[j];
373
0
      *(wptr++) = (c >= 32 && c < 127) ? c : '.';
374
0
    }
375
0
    *(wptr++) = '\n';
376
0
    *(wptr++) = '\0';
377
0
    res.append(line.get());
378
0
  }
379
0
  return res;
380
0
}
381
382
}  // namespace base
383
}  // namespace perfetto