• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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