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/wire_protocol.h"
18
19 #include "perfetto/base/logging.h"
20 #include "perfetto/ext/base/unix_socket.h"
21 #include "perfetto/ext/base/utils.h"
22 #include "src/profiling/memory/shared_ring_buffer.h"
23
24 #include <sys/socket.h>
25 #include <sys/types.h>
26
27 #if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
28 #include <bionic/mte.h>
29 #else
30 struct ScopedDisableMTE {
31 // Silence unused variable warnings in non-Android builds.
ScopedDisableMTEScopedDisableMTE32 ScopedDisableMTE() {}
33 };
34 #endif
35
36 namespace perfetto {
37 namespace profiling {
38
39 namespace {
40
41 template <typename T>
ViewAndAdvance(char ** ptr,T ** out,const char * end)42 bool ViewAndAdvance(char** ptr, T** out, const char* end) {
43 if (end - sizeof(T) < *ptr)
44 return false;
45 *out = reinterpret_cast<T*>(*ptr);
46 *ptr += sizeof(T);
47 return true;
48 }
49
50 // We need this to prevent crashes due to FORTIFY_SOURCE.
UnsafeMemcpy(char * dest,const char * src,size_t n)51 void UnsafeMemcpy(char* dest, const char* src, size_t n)
52 __attribute__((no_sanitize("address", "hwaddress"))) {
53 ScopedDisableMTE m;
54 for (size_t i = 0; i < n; ++i) {
55 dest[i] = src[i];
56 }
57 }
58
59 template <typename F>
WithBuffer(SharedRingBuffer * shmem,size_t total_size,F fn)60 int64_t WithBuffer(SharedRingBuffer* shmem, size_t total_size, F fn) {
61 if (total_size > shmem->size()) {
62 errno = EMSGSIZE;
63 return -1;
64 }
65 SharedRingBuffer::Buffer buf;
66 {
67 ScopedSpinlock lock = shmem->AcquireLock(ScopedSpinlock::Mode::Try);
68 if (!lock.locked()) {
69 PERFETTO_DLOG("Failed to acquire spinlock.");
70 errno = EAGAIN;
71 return -1;
72 }
73 buf = shmem->BeginWrite(lock, total_size);
74 }
75 if (!buf) {
76 PERFETTO_DLOG("Buffer overflow.");
77 shmem->EndWrite(std::move(buf));
78 errno = EAGAIN;
79 return -1;
80 }
81
82 fn(&buf);
83
84 auto bytes_free = buf.bytes_free;
85 shmem->EndWrite(std::move(buf));
86 return static_cast<int64_t>(bytes_free);
87 }
88
89 } // namespace
90
SendWireMessage(SharedRingBuffer * shmem,const WireMessage & msg)91 int64_t SendWireMessage(SharedRingBuffer* shmem, const WireMessage& msg) {
92 switch (msg.record_type) {
93 case RecordType::Malloc: {
94 size_t total_size = sizeof(msg.record_type) + sizeof(*msg.alloc_header) +
95 msg.payload_size;
96 return WithBuffer(
97 shmem, total_size, [msg](SharedRingBuffer::Buffer* buf) {
98 memcpy(buf->data, &msg.record_type, sizeof(msg.record_type));
99 memcpy(buf->data + sizeof(msg.record_type), msg.alloc_header,
100 sizeof(*msg.alloc_header));
101 UnsafeMemcpy(reinterpret_cast<char*>(buf->data) +
102 sizeof(msg.record_type) +
103 sizeof(*msg.alloc_header),
104 msg.payload, msg.payload_size);
105 });
106 }
107 case RecordType::Free: {
108 constexpr size_t total_size =
109 sizeof(msg.record_type) + sizeof(*msg.free_header);
110 return WithBuffer(
111 shmem, total_size, [msg](SharedRingBuffer::Buffer* buf) {
112 memcpy(buf->data, &msg.record_type, sizeof(msg.record_type));
113 memcpy(buf->data + sizeof(msg.record_type), msg.free_header,
114 sizeof(*msg.free_header));
115 });
116 }
117 case RecordType::HeapName: {
118 constexpr size_t total_size =
119 sizeof(msg.record_type) + sizeof(*msg.heap_name_header);
120 return WithBuffer(
121 shmem, total_size, [msg](SharedRingBuffer::Buffer* buf) {
122 memcpy(buf->data, &msg.record_type, sizeof(msg.record_type));
123 memcpy(buf->data + sizeof(msg.record_type), msg.heap_name_header,
124 sizeof(*msg.heap_name_header));
125 });
126 }
127 }
128 }
129
ReceiveWireMessage(char * buf,size_t size,WireMessage * out)130 bool ReceiveWireMessage(char* buf, size_t size, WireMessage* out) {
131 RecordType* record_type;
132 char* end = buf + size;
133 if (!ViewAndAdvance<RecordType>(&buf, &record_type, end)) {
134 PERFETTO_DFATAL_OR_ELOG("Cannot read record type.");
135 return false;
136 }
137
138 out->payload = nullptr;
139 out->payload_size = 0;
140 out->record_type = *record_type;
141
142 if (*record_type == RecordType::Malloc) {
143 if (!ViewAndAdvance<AllocMetadata>(&buf, &out->alloc_header, end)) {
144 PERFETTO_DFATAL_OR_ELOG("Cannot read alloc header.");
145 return false;
146 }
147 out->payload = buf;
148 if (buf > end) {
149 PERFETTO_DFATAL_OR_ELOG("Receive buffer overflowed");
150 return false;
151 }
152 out->payload_size = static_cast<size_t>(end - buf);
153 } else if (*record_type == RecordType::Free) {
154 if (!ViewAndAdvance<FreeEntry>(&buf, &out->free_header, end)) {
155 PERFETTO_DFATAL_OR_ELOG("Cannot read free header.");
156 return false;
157 }
158 } else if (*record_type == RecordType::HeapName) {
159 if (!ViewAndAdvance<HeapName>(&buf, &out->heap_name_header, end)) {
160 PERFETTO_DFATAL_OR_ELOG("Cannot read free header.");
161 return false;
162 }
163 } else {
164 PERFETTO_DFATAL_OR_ELOG("Invalid record type.");
165 return false;
166 }
167 return true;
168 }
169
GetHeapSamplingInterval(const ClientConfiguration & cli_config,const char * heap_name)170 uint64_t GetHeapSamplingInterval(const ClientConfiguration& cli_config,
171 const char* heap_name) {
172 for (uint32_t i = 0; i < cli_config.num_heaps; ++i) {
173 const ClientConfigurationHeap& heap = cli_config.heaps[i];
174 static_assert(sizeof(heap.name) == HEAPPROFD_HEAP_NAME_SZ,
175 "correct heap name size");
176 if (strncmp(&heap.name[0], heap_name, HEAPPROFD_HEAP_NAME_SZ) == 0) {
177 return heap.interval;
178 }
179 }
180 if (cli_config.all_heaps) {
181 return cli_config.default_interval;
182 }
183 return 0;
184 }
185
186 } // namespace profiling
187 } // namespace perfetto
188