blob: 2ef5b41d53f053681e3e85bbbc986bba537076e3 [file] [log] [blame]
Florian Mayerb85a9382018-09-27 13:59:01 +01001/*
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"
Florian Mayerf3c0ac82018-10-02 11:53:55 +010020#include "perfetto/base/unix_socket.h"
Florian Mayerb85a9382018-09-27 13:59:01 +010021#include "perfetto/base/utils.h"
22
23#include <sys/socket.h>
24#include <sys/types.h>
25
26namespace perfetto {
Florian Mayer8c0d0482018-10-22 14:23:40 +010027namespace profiling {
Florian Mayerb85a9382018-09-27 13:59:01 +010028
29namespace {
30template <typename T>
31bool ViewAndAdvance(char** ptr, T** out, const char* end) {
32 if (end - sizeof(T) < *ptr)
33 return false;
Florian Mayer7ad12752018-10-02 16:48:44 +010034 *out = reinterpret_cast<T*>(*ptr);
35 *ptr += sizeof(T);
Florian Mayerb85a9382018-09-27 13:59:01 +010036 return true;
37}
38} // namespace
39
40bool SendWireMessage(int sock, const WireMessage& msg) {
41 uint64_t total_size;
42 struct iovec iovecs[4] = {};
43 // TODO(fmayer): Maye pack these two.
44 iovecs[0].iov_base = &total_size;
45 iovecs[0].iov_len = sizeof(total_size);
46 iovecs[1].iov_base = const_cast<RecordType*>(&msg.record_type);
47 iovecs[1].iov_len = sizeof(msg.record_type);
48 if (msg.alloc_header) {
Florian Mayer7ad12752018-10-02 16:48:44 +010049 PERFETTO_DCHECK(msg.record_type == RecordType::Malloc);
Florian Mayerb85a9382018-09-27 13:59:01 +010050 iovecs[2].iov_base = msg.alloc_header;
51 iovecs[2].iov_len = sizeof(*msg.alloc_header);
52 } else if (msg.free_header) {
Florian Mayer7ad12752018-10-02 16:48:44 +010053 PERFETTO_DCHECK(msg.record_type == RecordType::Free);
Florian Mayerb85a9382018-09-27 13:59:01 +010054 iovecs[2].iov_base = msg.free_header;
55 iovecs[2].iov_len = sizeof(*msg.free_header);
56 } else {
Florian Mayer6db99a92018-10-18 11:34:55 +010057 PERFETTO_DFATAL("Neither alloc_header nor free_header set.");
Florian Mayerb85a9382018-09-27 13:59:01 +010058 return false;
59 }
60
61 iovecs[3].iov_base = msg.payload;
62 iovecs[3].iov_len = msg.payload_size;
63
64 struct msghdr hdr = {};
65 hdr.msg_iov = iovecs;
66 if (msg.payload) {
67 hdr.msg_iovlen = base::ArraySize(iovecs);
68 total_size = iovecs[1].iov_len + iovecs[2].iov_len + iovecs[3].iov_len;
69 } else {
70 // If we are not sending payload, just ignore that iovec.
71 hdr.msg_iovlen = base::ArraySize(iovecs) - 1;
72 total_size = iovecs[1].iov_len + iovecs[2].iov_len;
73 }
74
Florian Mayerf3c0ac82018-10-02 11:53:55 +010075 ssize_t sent = base::SendMsgAll(sock, &hdr, MSG_NOSIGNAL);
Florian Mayerb85a9382018-09-27 13:59:01 +010076 return sent == static_cast<ssize_t>(total_size + sizeof(total_size));
77}
78
79bool ReceiveWireMessage(char* buf, size_t size, WireMessage* out) {
80 RecordType* record_type;
81 char* end = buf + size;
82 if (!ViewAndAdvance<RecordType>(&buf, &record_type, end))
83 return false;
Florian Mayer7ad12752018-10-02 16:48:44 +010084
85 out->payload = nullptr;
86 out->payload_size = 0;
Florian Mayerb85a9382018-09-27 13:59:01 +010087 out->record_type = *record_type;
Florian Mayer7ad12752018-10-02 16:48:44 +010088
89 if (*record_type == RecordType::Malloc) {
90 if (!ViewAndAdvance<AllocMetadata>(&buf, &out->alloc_header, end))
91 return false;
92 out->payload = buf;
93 if (buf > end) {
Florian Mayer6db99a92018-10-18 11:34:55 +010094 PERFETTO_DFATAL("Buffer overflowed");
Florian Mayer7ad12752018-10-02 16:48:44 +010095 return false;
96 }
97 out->payload_size = static_cast<size_t>(end - buf);
98 } else if (*record_type == RecordType::Free) {
99 if (!ViewAndAdvance<FreeMetadata>(&buf, &out->free_header, end))
100 return false;
101 } else {
Florian Mayer6db99a92018-10-18 11:34:55 +0100102 PERFETTO_DFATAL("Invalid record type.");
Florian Mayer7ad12752018-10-02 16:48:44 +0100103 return false;
104 }
Florian Mayerb85a9382018-09-27 13:59:01 +0100105 return true;
106}
107
Florian Mayer8c0d0482018-10-22 14:23:40 +0100108} // namespace profiling
Florian Mayerb85a9382018-09-27 13:59:01 +0100109} // namespace perfetto