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