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/MachineArm.h>
26 #include <unwindstack/MachineArm64.h>
27 #include <unwindstack/MachineMips.h>
28 #include <unwindstack/MachineMips64.h>
29 #include <unwindstack/MachineX86.h>
30 #include <unwindstack/MachineX86_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 uint64_t block_client_timeout_us;
49 bool disable_fork_teardown;
50 bool disable_vfork_detection;
51 };
52
53 // Types needed for the wire format used for communication between the client
54 // and heapprofd. The basic format of a record is
55 // record size (uint64_t) | record type (RecordType = uint64_t) | record
56 // If record type is malloc, the record format is AllocMetdata | raw stack.
57 // If the record type is free, the record is a sequence of FreeBatchEntry.
58
59 // Use uint64_t to make sure the following data is aligned as 64bit is the
60 // strongest alignment requirement.
61
62 // C++11 std::max is not constexpr.
constexpr_max(size_t x,size_t y)63 constexpr size_t constexpr_max(size_t x, size_t y) {
64 return x > y ? x : y;
65 }
66
67 // clang-format makes this unreadable. Turning it off for this block.
68 // clang-format off
69 constexpr size_t kMaxRegisterDataSize =
70 constexpr_max(
71 constexpr_max(
72 constexpr_max(
73 constexpr_max(
74 constexpr_max(
75 sizeof(uint32_t) * unwindstack::ARM_REG_LAST,
76 sizeof(uint64_t) * unwindstack::ARM64_REG_LAST),
77 sizeof(uint32_t) * unwindstack::X86_REG_LAST),
78 sizeof(uint64_t) * unwindstack::X86_64_REG_LAST),
79 sizeof(uint32_t) * unwindstack::MIPS_REG_LAST),
80 sizeof(uint64_t) * unwindstack::MIPS64_REG_LAST
81 );
82 // clang-format on
83
84 constexpr size_t kFreeBatchSize = 1024;
85
86 enum class RecordType : uint64_t {
87 Free = 0,
88 Malloc = 1,
89 };
90
91 struct AllocMetadata {
92 uint64_t sequence_number;
93 // Size of the allocation that was made.
94 uint64_t alloc_size;
95 // Total number of bytes attributed to this allocation.
96 uint64_t sample_size;
97 // Pointer returned by malloc(2) for this allocation.
98 uint64_t alloc_address;
99 // Current value of the stack pointer.
100 uint64_t stack_pointer;
101 // Offset of the data at stack_pointer from the start of this record.
102 uint64_t stack_pointer_offset;
103 uint64_t clock_monotonic_coarse_timestamp;
104 alignas(uint64_t) char register_data[kMaxRegisterDataSize];
105 // CPU architecture of the client.
106 unwindstack::ArchEnum arch;
107 };
108
109 struct FreeBatchEntry {
110 uint64_t sequence_number;
111 uint64_t addr;
112 };
113
114 struct FreeBatch {
115 uint64_t num_entries;
116 uint64_t clock_monotonic_coarse_timestamp;
117 FreeBatchEntry entries[kFreeBatchSize];
118
FreeBatchFreeBatch119 FreeBatch() { num_entries = 0; }
120 };
121
122 enum HandshakeFDs : size_t {
123 kHandshakeMaps = 0,
124 kHandshakeMem,
125 kHandshakePageIdle,
126 kHandshakeSize,
127 };
128
129 struct WireMessage {
130 RecordType record_type;
131
132 AllocMetadata* alloc_header;
133 FreeBatch* free_header;
134
135 char* payload;
136 size_t payload_size;
137 };
138
139 bool SendWireMessage(SharedRingBuffer* buf, const WireMessage& msg);
140
141 // Parse message received over the wire.
142 // |buf| has to outlive |out|.
143 // If buf is not a valid message, return false.
144 bool ReceiveWireMessage(char* buf, size_t size, WireMessage* out);
145
146 constexpr const char* kHeapprofdSocketEnvVar = "ANDROID_SOCKET_heapprofd";
147 constexpr const char* kHeapprofdSocketFile = "/dev/socket/heapprofd";
148
149 } // namespace profiling
150 } // namespace perfetto
151
152 #endif // SRC_PROFILING_MEMORY_WIRE_PROTOCOL_H_
153