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 // The data types used for communication between heapprofd and the client
18 // embedded in processes that are being profiled.
19
20 #ifndef SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
21 #define SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
22
23 #include <inttypes.h>
24 #include <unwindstack/Elf.h>
25 #include <unwindstack/UserArm.h>
26 #include <unwindstack/UserArm64.h>
27 #include <unwindstack/UserMips.h>
28 #include <unwindstack/UserMips64.h>
29 #include <unwindstack/UserX86.h>
30 #include <unwindstack/UserX86_64.h>
31
32 #include "src/profiling/memory/shared_ring_buffer.h"
33
34 namespace perfetto {
35
36 namespace base {
37 class UnixSocketRaw;
38 }
39
40 namespace profiling {
41
42 struct ClientConfiguration {
43 // On average, sample one allocation every interval bytes,
44 // If interval == 1, sample every allocation.
45 // Must be >= 1.
46 uint64_t interval;
47 bool block_client;
48 };
49
50 // Types needed for the wire format used for communication between the client
51 // and heapprofd. The basic format of a record is
52 // record size (uint64_t) | record type (RecordType = uint64_t) | record
53 // If record type is malloc, the record format is AllocMetdata | raw stack.
54 // If the record type is free, the record is a sequence of FreeBatchEntry.
55
56 // Use uint64_t to make sure the following data is aligned as 64bit is the
57 // strongest alignment requirement.
58
59 // C++11 std::max is not constexpr.
constexpr_max(size_t x,size_t y)60 constexpr size_t constexpr_max(size_t x, size_t y) {
61 return x > y ? x : y;
62 }
63
64 // clang-format makes this unreadable. Turning it off for this block.
65 // clang-format off
66 constexpr size_t kMaxRegisterDataSize =
67 constexpr_max(
68 constexpr_max(
69 constexpr_max(
70 constexpr_max(
71 constexpr_max(
72 sizeof(unwindstack::arm_user_regs),
73 sizeof(unwindstack::arm64_user_regs)),
74 sizeof(unwindstack::x86_user_regs)),
75 sizeof(unwindstack::x86_64_user_regs)),
76 sizeof(unwindstack::mips_user_regs)),
77 sizeof(unwindstack::mips64_user_regs)
78 );
79 // clang-format on
80
81 constexpr size_t kFreeBatchSize = 1024;
82
83 enum class RecordType : uint64_t {
84 Free = 0,
85 Malloc = 1,
86 };
87
88 struct AllocMetadata {
89 uint64_t sequence_number;
90 // Size of the allocation that was made.
91 uint64_t alloc_size;
92 // Total number of bytes attributed to this allocation.
93 uint64_t total_size;
94 // Pointer returned by malloc(2) for this allocation.
95 uint64_t alloc_address;
96 // Current value of the stack pointer.
97 uint64_t stack_pointer;
98 // Offset of the data at stack_pointer from the start of this record.
99 uint64_t stack_pointer_offset;
100 uint64_t clock_monotonic_coarse_timestamp;
101 alignas(uint64_t) char register_data[kMaxRegisterDataSize];
102 // CPU architecture of the client. This determines the size of the
103 // register data that follows this struct.
104 unwindstack::ArchEnum arch;
105 };
106
107 struct FreeBatchEntry {
108 uint64_t sequence_number;
109 uint64_t addr;
110 };
111
112 struct FreeBatch {
113 uint64_t num_entries;
114 uint64_t clock_monotonic_coarse_timestamp;
115 FreeBatchEntry entries[kFreeBatchSize];
116
FreeBatchFreeBatch117 FreeBatch() { num_entries = 0; }
118 };
119
120 enum HandshakeFDs : size_t {
121 kHandshakeMaps = 0,
122 kHandshakeMem = 1,
123 kHandshakeSize = 2,
124 };
125
126 struct WireMessage {
127 RecordType record_type;
128
129 AllocMetadata* alloc_header;
130 FreeBatch* free_header;
131
132 char* payload;
133 size_t payload_size;
134 };
135
136 bool SendWireMessage(SharedRingBuffer* buf, const WireMessage& msg);
137
138 // Parse message received over the wire.
139 // |buf| has to outlive |out|.
140 // If buf is not a valid message, return false.
141 bool ReceiveWireMessage(char* buf, size_t size, WireMessage* out);
142
143 constexpr const char* kHeapprofdSocketEnvVar = "ANDROID_SOCKET_heapprofd";
144 constexpr const char* kHeapprofdSocketFile = "/dev/socket/heapprofd";
145
146 } // namespace profiling
147 } // namespace perfetto
148
149 #endif // SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
150