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