1 /*
2 * Copyright (C) 2018 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 "src/profiling/memory/client.h"
18
19 #include <signal.h>
20 #include <sys/prctl.h>
21 #include <sys/syscall.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include <algorithm>
26 #include <atomic>
27 #include <cinttypes>
28 #include <new>
29
30 #include <unwindstack/Regs.h>
31 #include <unwindstack/RegsGetLocal.h>
32
33 #include "perfetto/base/build_config.h"
34 #include "perfetto/base/compiler.h"
35 #include "perfetto/base/logging.h"
36 #include "perfetto/base/thread_utils.h"
37 #include "perfetto/base/time.h"
38 #include "perfetto/ext/base/file_utils.h"
39 #include "perfetto/ext/base/scoped_file.h"
40 #include "perfetto/ext/base/string_utils.h"
41 #include "perfetto/ext/base/unix_socket.h"
42 #include "perfetto/ext/base/utils.h"
43 #include "src/profiling/memory/sampler.h"
44 #include "src/profiling/memory/scoped_spinlock.h"
45 #include "src/profiling/memory/shared_ring_buffer.h"
46 #include "src/profiling/memory/wire_protocol.h"
47
48 namespace perfetto {
49 namespace profiling {
50 namespace {
51
52 const char kSingleByte[1] = {'x'};
53 constexpr auto kResendBackoffUs = 100;
54
IsMainThread()55 inline bool IsMainThread() {
56 return getpid() == base::GetThreadId();
57 }
58
UnsetDumpable(int)59 int UnsetDumpable(int) {
60 prctl(PR_SET_DUMPABLE, 0);
61 return 0;
62 }
63
Contained(const StackRange & base,const char * ptr)64 bool Contained(const StackRange& base, const char* ptr) {
65 return (ptr >= base.begin && ptr < base.end);
66 }
67
68 } // namespace
69
GetMaxTries(const ClientConfiguration & client_config)70 uint64_t GetMaxTries(const ClientConfiguration& client_config) {
71 if (!client_config.block_client)
72 return 1u;
73 if (client_config.block_client_timeout_us == 0)
74 return kInfiniteTries;
75 return std::max<uint64_t>(
76 1ul, client_config.block_client_timeout_us / kResendBackoffUs);
77 }
78
GetThreadStackRange()79 StackRange GetThreadStackRange() {
80 // In glibc pthread_getattr_np can call realloc, even for a non-main-thread.
81 // This is fine, because the heapprofd wrapper for glibc prevents re-entering
82 // malloc.
83 pthread_attr_t attr;
84 if (pthread_getattr_np(pthread_self(), &attr) != 0)
85 return {nullptr, nullptr};
86 base::ScopedResource<pthread_attr_t*, pthread_attr_destroy, nullptr> cleanup(
87 &attr);
88
89 char* stackaddr;
90 size_t stacksize;
91 if (pthread_attr_getstack(&attr, reinterpret_cast<void**>(&stackaddr),
92 &stacksize) != 0)
93 return {nullptr, nullptr};
94 return {stackaddr, stackaddr + stacksize};
95 }
96
GetSigAltStackRange()97 StackRange GetSigAltStackRange() {
98 stack_t altstack;
99
100 if (sigaltstack(nullptr, &altstack) == -1) {
101 PERFETTO_PLOG("sigaltstack");
102 return {nullptr, nullptr};
103 }
104
105 if ((altstack.ss_flags & SS_ONSTACK) == 0) {
106 return {nullptr, nullptr};
107 }
108
109 return {static_cast<char*>(altstack.ss_sp),
110 static_cast<char*>(altstack.ss_sp) + altstack.ss_size};
111 }
112
113 // The implementation of pthread_getattr_np for the main thread on bionic uses
114 // malloc, so we cannot use it in GetStackEnd, which we use inside of
115 // RecordMalloc (which is called from malloc). We would re-enter malloc if we
116 // used it.
117 //
118 // This is why we find the stack base for the main-thread when constructing
119 // the client and remember it.
GetMainThreadStackRange()120 StackRange GetMainThreadStackRange() {
121 base::ScopedFstream maps(fopen("/proc/self/maps", "re"));
122 if (!maps) {
123 return {nullptr, nullptr};
124 }
125 while (!feof(*maps)) {
126 char line[1024];
127 char* data = fgets(line, sizeof(line), *maps);
128 if (data != nullptr && strstr(data, "[stack]")) {
129 char* sep = strstr(data, "-");
130 if (sep == nullptr)
131 continue;
132
133 char* min = reinterpret_cast<char*>(strtoll(data, nullptr, 16));
134 char* max = reinterpret_cast<char*>(strtoll(sep + 1, nullptr, 16));
135 return {min, max};
136 }
137 }
138 return {nullptr, nullptr};
139 }
140
141 // static
ConnectToHeapprofd(const std::string & sock_name)142 std::optional<base::UnixSocketRaw> Client::ConnectToHeapprofd(
143 const std::string& sock_name) {
144 auto sock = base::UnixSocketRaw::CreateMayFail(base::SockFamily::kUnix,
145 base::SockType::kStream);
146 if (!sock || !sock.Connect(sock_name)) {
147 PERFETTO_PLOG("Failed to connect to %s", sock_name.c_str());
148 return std::nullopt;
149 }
150 if (!sock.SetTxTimeout(kClientSockTimeoutMs)) {
151 PERFETTO_PLOG("Failed to set send timeout for %s", sock_name.c_str());
152 return std::nullopt;
153 }
154 if (!sock.SetRxTimeout(kClientSockTimeoutMs)) {
155 PERFETTO_PLOG("Failed to set receive timeout for %s", sock_name.c_str());
156 return std::nullopt;
157 }
158 return std::move(sock);
159 }
160
161 // static
CreateAndHandshake(base::UnixSocketRaw sock,UnhookedAllocator<Client> unhooked_allocator)162 std::shared_ptr<Client> Client::CreateAndHandshake(
163 base::UnixSocketRaw sock,
164 UnhookedAllocator<Client> unhooked_allocator) {
165 if (!sock) {
166 PERFETTO_DFATAL_OR_ELOG("Socket not connected.");
167 return nullptr;
168 }
169
170 sock.DcheckIsBlocking(true);
171
172 // We might be running in a process that is not dumpable (such as app
173 // processes on user builds), in which case the /proc/self/mem will be chown'd
174 // to root:root, and will not be accessible even to the process itself (see
175 // man 5 proc). In such situations, temporarily mark the process dumpable to
176 // be able to open the files, unsetting dumpability immediately afterwards.
177 int orig_dumpable = prctl(PR_GET_DUMPABLE);
178
179 enum { kNop, kDoUnset };
180 base::ScopedResource<int, UnsetDumpable, kNop, false> unset_dumpable(kNop);
181 if (orig_dumpable == 0) {
182 unset_dumpable.reset(kDoUnset);
183 prctl(PR_SET_DUMPABLE, 1);
184 }
185
186 base::ScopedFile maps(base::OpenFile("/proc/self/maps", O_RDONLY));
187 if (!maps) {
188 PERFETTO_DFATAL_OR_ELOG("Failed to open /proc/self/maps");
189 return nullptr;
190 }
191 base::ScopedFile mem(base::OpenFile("/proc/self/mem", O_RDONLY));
192 if (!mem) {
193 PERFETTO_DFATAL_OR_ELOG("Failed to open /proc/self/mem");
194 return nullptr;
195 }
196
197 // Restore original dumpability value if we overrode it.
198 unset_dumpable.reset();
199
200 int fds[kHandshakeSize];
201 fds[kHandshakeMaps] = *maps;
202 fds[kHandshakeMem] = *mem;
203
204 // Send an empty record to transfer fds for /proc/self/maps and
205 // /proc/self/mem.
206 if (sock.Send(kSingleByte, sizeof(kSingleByte), fds, kHandshakeSize) !=
207 sizeof(kSingleByte)) {
208 PERFETTO_DFATAL_OR_ELOG("Failed to send file descriptors.");
209 return nullptr;
210 }
211
212 ClientConfiguration client_config;
213 base::ScopedFile shmem_fd;
214 size_t recv = 0;
215 while (recv < sizeof(client_config)) {
216 size_t num_fds = 0;
217 base::ScopedFile* fd = nullptr;
218 if (!shmem_fd) {
219 num_fds = 1;
220 fd = &shmem_fd;
221 }
222 ssize_t rd = sock.Receive(reinterpret_cast<char*>(&client_config) + recv,
223 sizeof(client_config) - recv, fd, num_fds);
224 if (rd == -1) {
225 PERFETTO_PLOG("Failed to receive ClientConfiguration.");
226 return nullptr;
227 }
228 if (rd == 0) {
229 PERFETTO_LOG("Server disconnected while sending ClientConfiguration.");
230 return nullptr;
231 }
232 recv += static_cast<size_t>(rd);
233 }
234
235 if (!shmem_fd) {
236 PERFETTO_DFATAL_OR_ELOG("Did not receive shmem fd.");
237 return nullptr;
238 }
239
240 auto shmem = SharedRingBuffer::Attach(std::move(shmem_fd));
241 if (!shmem || !shmem->is_valid()) {
242 PERFETTO_DFATAL_OR_ELOG("Failed to attach to shmem.");
243 return nullptr;
244 }
245
246 sock.SetBlocking(false);
247 // note: the shared_ptr will retain a copy of the unhooked_allocator
248 return std::allocate_shared<Client>(unhooked_allocator, std::move(sock),
249 client_config, std::move(shmem.value()),
250 getpid(), GetMainThreadStackRange());
251 }
252
Client(base::UnixSocketRaw sock,ClientConfiguration client_config,SharedRingBuffer shmem,pid_t pid_at_creation,StackRange main_thread_stack_range)253 Client::Client(base::UnixSocketRaw sock,
254 ClientConfiguration client_config,
255 SharedRingBuffer shmem,
256 pid_t pid_at_creation,
257 StackRange main_thread_stack_range)
258 : client_config_(client_config),
259 max_shmem_tries_(GetMaxTries(client_config_)),
260 sock_(std::move(sock)),
261 main_thread_stack_range_(main_thread_stack_range),
262 shmem_(std::move(shmem)),
263 pid_at_creation_(pid_at_creation) {}
264
~Client()265 Client::~Client() {
266 // This is work-around for code like the following:
267 // https://android.googlesource.com/platform/libcore/+/4ecb71f94378716f88703b9f7548b5d24839262f/ojluni/src/main/native/UNIXProcess_md.c#427
268 // They fork, close all fds by iterating over /proc/self/fd using opendir.
269 // Unfortunately closedir calls free, which detects the fork, and then tries
270 // to destruct this Client.
271 //
272 // ScopedResource crashes on failure to close, so we explicitly ignore
273 // failures here.
274 int fd = sock_.ReleaseFd().release();
275 if (fd != -1)
276 close(fd);
277 }
278
GetStackEnd(const char * stackptr)279 const char* Client::GetStackEnd(const char* stackptr) {
280 StackRange thread_stack_range;
281 bool is_main_thread = IsMainThread();
282 if (is_main_thread) {
283 thread_stack_range = main_thread_stack_range_;
284 } else {
285 thread_stack_range = GetThreadStackRange();
286 }
287 if (Contained(thread_stack_range, stackptr)) {
288 return thread_stack_range.end;
289 }
290 StackRange sigalt_stack_range = GetSigAltStackRange();
291 if (Contained(sigalt_stack_range, stackptr)) {
292 return sigalt_stack_range.end;
293 }
294 // The main thread might have expanded since we read its bounds. We now know
295 // it is not the sigaltstack, so it has to be the main stack.
296 // TODO(fmayer): We should reparse maps here, because now we will keep
297 // hitting the slow-path that calls the sigaltstack syscall.
298 if (is_main_thread && stackptr < thread_stack_range.end) {
299 return thread_stack_range.end;
300 }
301 return nullptr;
302 }
303
304 // Best-effort detection of whether we're continuing work in a forked child of
305 // the profiled process, in which case we want to stop. Note that due to
306 // malloc_hooks.cc's atfork handler, the proper fork calls should leak the child
307 // before reaching this point. Therefore this logic exists primarily to handle
308 // clone and vfork.
309 // TODO(rsavitski): rename/delete |disable_fork_teardown| config option if this
310 // logic sticks, as the option becomes more clone-specific, and quite narrow.
IsPostFork()311 bool Client::IsPostFork() {
312 if (PERFETTO_UNLIKELY(getpid() != pid_at_creation_)) {
313 // Only print the message once, even if we do not shut down the client.
314 if (!detected_fork_) {
315 detected_fork_ = true;
316 const char* vfork_detected = "";
317
318 // We use the fact that vfork does not update Bionic's TID cache, so
319 // we will have a mismatch between the actual TID (from the syscall)
320 // and the cached one.
321 //
322 // What we really want to check is if we are sharing virtual memory space
323 // with the original process. This would be
324 // syscall(__NR_kcmp, syscall(__NR_getpid), pid_at_creation_,
325 // KCMP_VM, 0, 0),
326 // but that is not compiled into our kernels and disallowed by seccomp.
327 if (!client_config_.disable_vfork_detection &&
328 syscall(__NR_gettid) != base::GetThreadId()) {
329 postfork_return_value_ = true;
330 vfork_detected = " (vfork detected)";
331 } else {
332 postfork_return_value_ = client_config_.disable_fork_teardown;
333 }
334 const char* action =
335 postfork_return_value_ ? "Not shutting down" : "Shutting down";
336 const char* force =
337 postfork_return_value_ ? " (fork teardown disabled)" : "";
338 PERFETTO_LOG(
339 "Detected post-fork child situation. Not profiling the child. "
340 "%s client%s%s",
341 action, force, vfork_detected);
342 }
343 return true;
344 }
345 return false;
346 }
347
348 #if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_RISCV) && \
349 !PERFETTO_HAS_BUILTIN_STACK_ADDRESS()
GetStackRegister(unwindstack::ArchEnum arch)350 ssize_t Client::GetStackRegister(unwindstack::ArchEnum arch) {
351 ssize_t reg_sp, reg_size;
352 switch (arch) {
353 case unwindstack::ARCH_X86:
354 reg_sp = unwindstack::X86_REG_SP;
355 reg_size = sizeof(uint32_t);
356 break;
357 case unwindstack::ARCH_X86_64:
358 reg_sp = unwindstack::X86_64_REG_SP;
359 reg_size = sizeof(uint64_t);
360 break;
361 case unwindstack::ARCH_ARM:
362 reg_sp = unwindstack::ARM_REG_SP;
363 reg_size = sizeof(uint32_t);
364 break;
365 case unwindstack::ARCH_ARM64:
366 reg_sp = unwindstack::ARM64_REG_SP;
367 reg_size = sizeof(uint64_t);
368 break;
369 case unwindstack::ARCH_RISCV64:
370 reg_sp = unwindstack::RISCV64_REG_SP;
371 reg_size = sizeof(uint64_t);
372 break;
373 case unwindstack::ARCH_UNKNOWN:
374 return -1;
375 }
376 return reg_sp * reg_size;
377 }
378
GetStackAddress(char * reg_data,unwindstack::ArchEnum arch)379 uintptr_t Client::GetStackAddress(char* reg_data, unwindstack::ArchEnum arch) {
380 ssize_t reg = GetStackRegister(arch);
381 if (reg < 0)
382 return reinterpret_cast<uintptr_t>(nullptr);
383 return *reinterpret_cast<uintptr_t*>(®_data[reg]);
384 }
385 #endif /* PERFETTO_ARCH_CPU_RISCV && !PERFETTO_HAS_BUILTIN_STACK_ADDRESS() */
386
387 // The stack grows towards numerically smaller addresses, so the stack layout
388 // of main calling malloc is as follows.
389 //
390 // +------------+
391 // |SendWireMsg |
392 // stackptr +--> +------------+ 0x1000
393 // |RecordMalloc| +
394 // +------------+ |
395 // | malloc | |
396 // +------------+ |
397 // | main | v
398 // stackend +-> +------------+ 0xffff
RecordMalloc(uint32_t heap_id,uint64_t sample_size,uint64_t alloc_size,uint64_t alloc_address)399 bool Client::RecordMalloc(uint32_t heap_id,
400 uint64_t sample_size,
401 uint64_t alloc_size,
402 uint64_t alloc_address) {
403 if (PERFETTO_UNLIKELY(IsPostFork())) {
404 return postfork_return_value_;
405 }
406
407 AllocMetadata metadata;
408 // By the difference between calling conventions, the frame pointer might
409 // include the current frame or not. So, using __builtin_frame_address()
410 // on specific architectures such as riscv can make stack unwinding failed.
411 // Thus, using __builtin_stack_address() or reading the stack pointer in
412 // register data directly instead of using __builtin_frame_address() on riscv.
413 #if PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_RISCV)
414 #if PERFETTO_HAS_BUILTIN_STACK_ADDRESS()
415 const char* stackptr = reinterpret_cast<char*>(__builtin_stack_address());
416 unwindstack::AsmGetRegs(metadata.register_data);
417 #else
418 char* register_data = metadata.register_data;
419 unwindstack::AsmGetRegs(register_data);
420 const char* stackptr = reinterpret_cast<char*>(
421 GetStackAddress(register_data, unwindstack::Regs::CurrentArch()));
422 if (!stackptr) {
423 PERFETTO_ELOG("Failed to get stack address.");
424 shmem_.SetErrorState(SharedRingBuffer::kInvalidStackBounds);
425 return false;
426 }
427 #endif /* PERFETTO_HAS_BUILTIN_STACK_ADDRESS() */
428 #else
429 const char* stackptr = reinterpret_cast<char*>(__builtin_frame_address(0));
430 unwindstack::AsmGetRegs(metadata.register_data);
431 #endif /* PERFETTO_BUILDFLAG(PERFETTO_ARCH_CPU_RISCV) */
432 const char* stackend = GetStackEnd(stackptr);
433 if (!stackend) {
434 PERFETTO_ELOG("Failed to find stackend.");
435 shmem_.SetErrorState(SharedRingBuffer::kInvalidStackBounds);
436 return false;
437 }
438 uint64_t stack_size = static_cast<uint64_t>(stackend - stackptr);
439 metadata.sample_size = sample_size;
440 metadata.alloc_size = alloc_size;
441 metadata.alloc_address = alloc_address;
442 metadata.stack_pointer = reinterpret_cast<uint64_t>(stackptr);
443 metadata.arch = unwindstack::Regs::CurrentArch();
444 metadata.sequence_number =
445 1 + sequence_number_[heap_id].fetch_add(1, std::memory_order_acq_rel);
446 metadata.heap_id = heap_id;
447
448 struct timespec ts;
449 if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) {
450 metadata.clock_monotonic_coarse_timestamp =
451 static_cast<uint64_t>(base::FromPosixTimespec(ts).count());
452 } else {
453 metadata.clock_monotonic_coarse_timestamp = 0;
454 }
455
456 WireMessage msg{};
457 msg.record_type = RecordType::Malloc;
458 msg.alloc_header = &metadata;
459 msg.payload = const_cast<char*>(stackptr);
460 msg.payload_size = static_cast<size_t>(stack_size);
461
462 if (SendWireMessageWithRetriesIfBlocking(msg) == -1)
463 return false;
464
465 if (!shmem_.GetAndResetReaderPaused())
466 return true;
467 return SendControlSocketByte();
468 }
469
SendWireMessageWithRetriesIfBlocking(const WireMessage & msg)470 int64_t Client::SendWireMessageWithRetriesIfBlocking(const WireMessage& msg) {
471 for (uint64_t i = 0;
472 max_shmem_tries_ == kInfiniteTries || i < max_shmem_tries_; ++i) {
473 if (shmem_.shutting_down())
474 return -1;
475 int64_t res = SendWireMessage(&shmem_, msg);
476 if (PERFETTO_LIKELY(res >= 0))
477 return res;
478 // retry if in blocking mode and still connected
479 if (client_config_.block_client && base::IsAgain(errno) && IsConnected()) {
480 usleep(kResendBackoffUs);
481 } else {
482 break;
483 }
484 }
485 if (IsConnected())
486 shmem_.SetErrorState(SharedRingBuffer::kHitTimeout);
487 PERFETTO_PLOG("Failed to write to shared ring buffer. Disconnecting.");
488 return -1;
489 }
490
RecordFree(uint32_t heap_id,const uint64_t alloc_address)491 bool Client::RecordFree(uint32_t heap_id, const uint64_t alloc_address) {
492 if (PERFETTO_UNLIKELY(IsPostFork())) {
493 return postfork_return_value_;
494 }
495
496 FreeEntry current_entry;
497 current_entry.sequence_number =
498 1 + sequence_number_[heap_id].fetch_add(1, std::memory_order_acq_rel);
499 current_entry.addr = alloc_address;
500 current_entry.heap_id = heap_id;
501 WireMessage msg = {};
502 msg.record_type = RecordType::Free;
503 msg.free_header = ¤t_entry;
504 // Do not send control socket byte, as frees are very cheap to handle, so we
505 // just delay to the next alloc. Sending the control socket byte is ~10x the
506 // rest of the client overhead.
507 int64_t bytes_free = SendWireMessageWithRetriesIfBlocking(msg);
508 if (bytes_free == -1)
509 return false;
510 // Seems like we are filling up the shmem with frees. Flush.
511 if (static_cast<uint64_t>(bytes_free) < shmem_.size() / 2 &&
512 shmem_.GetAndResetReaderPaused()) {
513 return SendControlSocketByte();
514 }
515 return true;
516 }
517
RecordHeapInfo(uint32_t heap_id,const char * heap_name,uint64_t interval)518 bool Client::RecordHeapInfo(uint32_t heap_id,
519 const char* heap_name,
520 uint64_t interval) {
521 if (PERFETTO_UNLIKELY(IsPostFork())) {
522 return postfork_return_value_;
523 }
524
525 HeapName hnr;
526 hnr.heap_id = heap_id;
527 base::StringCopy(&hnr.heap_name[0], heap_name, sizeof(hnr.heap_name));
528 hnr.sample_interval = interval;
529
530 WireMessage msg = {};
531 msg.record_type = RecordType::HeapName;
532 msg.heap_name_header = &hnr;
533 return SendWireMessageWithRetriesIfBlocking(msg);
534 }
535
IsConnected()536 bool Client::IsConnected() {
537 sock_.DcheckIsBlocking(false);
538 char buf[1];
539 ssize_t recv_bytes = sock_.Receive(buf, sizeof(buf), nullptr, 0);
540 if (recv_bytes == 0)
541 return false;
542 // This is not supposed to happen because currently heapprofd does not send
543 // data to the client. Here for generality's sake.
544 if (recv_bytes > 0)
545 return true;
546 return base::IsAgain(errno);
547 }
548
SendControlSocketByte()549 bool Client::SendControlSocketByte() {
550 // If base::IsAgain(errno), the socket buffer is full, so the service will
551 // pick up the notification even without adding another byte.
552 // In other error cases (usually EPIPE) we want to disconnect, because that
553 // is how the service signals the tracing session was torn down.
554 if (sock_.Send(kSingleByte, sizeof(kSingleByte)) == -1 &&
555 !base::IsAgain(errno)) {
556 if (shmem_.shutting_down()) {
557 PERFETTO_LOG("Profiling session ended.");
558 } else {
559 PERFETTO_PLOG("Failed to send control socket byte.");
560 }
561 return false;
562 }
563 return true;
564 }
565
566 } // namespace profiling
567 } // namespace perfetto
568