1 /*
2 * Copyright (C) 2022 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 #ifndef INCLUDE_PERFETTO_PUBLIC_PB_MSG_H_
18 #define INCLUDE_PERFETTO_PUBLIC_PB_MSG_H_
19
20 #include <assert.h>
21 #include <stdint.h>
22 #include <string.h>
23
24 #include "perfetto/public/abi/stream_writer_abi.h"
25 #include "perfetto/public/compiler.h"
26 #include "perfetto/public/pb_utils.h"
27 #include "perfetto/public/stream_writer.h"
28
29 // The number of bytes reserved by this implementation to encode a protobuf type
30 // 2 field size as var-int. Keep this in sync with kMessageLengthFieldSize in
31 // proto_utils.h.
32 #define PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE 4
33
34 // Points to the memory used by a `PerfettoPbMsg` for writing.
35 struct PerfettoPbMsgWriter {
36 struct PerfettoStreamWriter writer;
37 };
38
39 struct PerfettoPbMsg {
40 // Pointer to a non-aligned pre-reserved var-int slot of
41 // PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE bytes. If not NULL,
42 // protozero_length_buf_finalize() will write the size of proto-encoded
43 // message in the pointed memory region.
44 uint8_t* size_field;
45
46 // Current size of the buffer.
47 uint32_t size;
48
49 struct PerfettoPbMsgWriter* writer;
50
51 struct PerfettoPbMsg* nested;
52 struct PerfettoPbMsg* parent;
53 };
54
PerfettoPbMsgInit(struct PerfettoPbMsg * msg,struct PerfettoPbMsgWriter * writer)55 static inline void PerfettoPbMsgInit(struct PerfettoPbMsg* msg,
56 struct PerfettoPbMsgWriter* writer) {
57 msg->size_field = PERFETTO_NULL;
58 msg->size = 0;
59 msg->writer = writer;
60 msg->nested = PERFETTO_NULL;
61 msg->parent = PERFETTO_NULL;
62 }
63
PerfettoPbMsgPatch(struct PerfettoPbMsg * msg)64 static inline void PerfettoPbMsgPatch(struct PerfettoPbMsg* msg) {
65 static_assert(
66 PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE == PERFETTO_STREAM_WRITER_PATCH_SIZE,
67 "PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE doesn't match patch size");
68 msg->size_field =
69 PerfettoStreamWriterAnnotatePatch(&msg->writer->writer, msg->size_field);
70 }
71
PerfettoPbMsgPatchStack(struct PerfettoPbMsg * msg)72 static inline void PerfettoPbMsgPatchStack(struct PerfettoPbMsg* msg) {
73 uint8_t* const cur_range_end = msg->writer->writer.end;
74 uint8_t* const cur_range_begin = msg->writer->writer.begin;
75 while (msg && cur_range_begin <= msg->size_field &&
76 msg->size_field < cur_range_end) {
77 PerfettoPbMsgPatch(msg);
78 msg = msg->parent;
79 }
80 }
81
PerfettoPbMsgAppendBytes(struct PerfettoPbMsg * msg,const uint8_t * begin,size_t size)82 static inline void PerfettoPbMsgAppendBytes(struct PerfettoPbMsg* msg,
83 const uint8_t* begin,
84 size_t size) {
85 if (PERFETTO_UNLIKELY(
86 size > PerfettoStreamWriterAvailableBytes(&msg->writer->writer))) {
87 PerfettoPbMsgPatchStack(msg);
88 }
89 PerfettoStreamWriterAppendBytes(&msg->writer->writer, begin, size);
90 msg->size += size;
91 }
92
PerfettoPbMsgAppendByte(struct PerfettoPbMsg * msg,uint8_t value)93 static inline void PerfettoPbMsgAppendByte(struct PerfettoPbMsg* msg,
94 uint8_t value) {
95 PerfettoPbMsgAppendBytes(msg, &value, 1);
96 }
97
PerfettoPbMsgAppendVarInt(struct PerfettoPbMsg * msg,uint64_t value)98 static inline void PerfettoPbMsgAppendVarInt(struct PerfettoPbMsg* msg,
99 uint64_t value) {
100 uint8_t* buf_end;
101 uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_64];
102 buf_end = PerfettoPbWriteVarInt(value, buf);
103
104 PerfettoPbMsgAppendBytes(msg, buf,
105 PERFETTO_STATIC_CAST(size_t, buf_end - buf));
106 }
107
PerfettoPbMsgAppendType0Field(struct PerfettoPbMsg * msg,int32_t field_id,uint64_t value)108 static inline void PerfettoPbMsgAppendType0Field(struct PerfettoPbMsg* msg,
109 int32_t field_id,
110 uint64_t value) {
111 uint8_t* buf_end;
112 uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_64 + PERFETTO_PB_VARINT_MAX_SIZE_32];
113 buf_end = PerfettoPbWriteVarInt(
114 PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_VARINT), buf);
115 buf_end = PerfettoPbWriteVarInt(value, buf_end);
116
117 PerfettoPbMsgAppendBytes(msg, buf,
118 PERFETTO_STATIC_CAST(size_t, buf_end - buf));
119 }
120
PerfettoPbMsgAppendType2Field(struct PerfettoPbMsg * msg,int32_t field_id,const uint8_t * data,size_t size)121 static inline void PerfettoPbMsgAppendType2Field(struct PerfettoPbMsg* msg,
122 int32_t field_id,
123 const uint8_t* data,
124 size_t size) {
125 uint8_t* buf_end;
126 uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_64 + PERFETTO_PB_VARINT_MAX_SIZE_32];
127 buf_end = PerfettoPbWriteVarInt(
128 PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_DELIMITED), buf);
129 buf_end =
130 PerfettoPbWriteVarInt(PERFETTO_STATIC_CAST(uint64_t, size), buf_end);
131 PerfettoPbMsgAppendBytes(msg, buf,
132 PERFETTO_STATIC_CAST(size_t, buf_end - buf));
133
134 PerfettoPbMsgAppendBytes(msg, data, size);
135 }
136
PerfettoPbMsgAppendFixed32Field(struct PerfettoPbMsg * msg,int32_t field_id,uint32_t value)137 static inline void PerfettoPbMsgAppendFixed32Field(struct PerfettoPbMsg* msg,
138 int32_t field_id,
139 uint32_t value) {
140 uint8_t* buf_end;
141 uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_32 + 4];
142 buf_end = PerfettoPbWriteVarInt(
143 PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_FIXED32), buf);
144 buf_end[0] = PERFETTO_STATIC_CAST(uint8_t, value);
145 buf_end[1] = PERFETTO_STATIC_CAST(uint8_t, value >> 8);
146 buf_end[2] = PERFETTO_STATIC_CAST(uint8_t, value >> 16);
147 buf_end[3] = PERFETTO_STATIC_CAST(uint8_t, value >> 24);
148 buf_end += 4;
149
150 PerfettoPbMsgAppendBytes(msg, buf,
151 PERFETTO_STATIC_CAST(size_t, buf_end - buf));
152 }
153
PerfettoPbMsgAppendFloatField(struct PerfettoPbMsg * msg,int32_t field_id,float value)154 static inline void PerfettoPbMsgAppendFloatField(struct PerfettoPbMsg* msg,
155 int32_t field_id,
156 float value) {
157 uint32_t val;
158 memcpy(&val, &value, sizeof val);
159 PerfettoPbMsgAppendFixed32Field(msg, field_id, val);
160 }
161
PerfettoPbMsgAppendFixed64Field(struct PerfettoPbMsg * msg,int32_t field_id,uint64_t value)162 static inline void PerfettoPbMsgAppendFixed64Field(struct PerfettoPbMsg* msg,
163 int32_t field_id,
164 uint64_t value) {
165 uint8_t* buf_end;
166 uint8_t buf[PERFETTO_PB_VARINT_MAX_SIZE_32 + 8];
167 buf_end = PerfettoPbWriteVarInt(
168 PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_FIXED64), buf);
169 buf_end[0] = PERFETTO_STATIC_CAST(uint8_t, value);
170 buf_end[1] = PERFETTO_STATIC_CAST(uint8_t, value >> 8);
171 buf_end[2] = PERFETTO_STATIC_CAST(uint8_t, value >> 16);
172 buf_end[3] = PERFETTO_STATIC_CAST(uint8_t, value >> 24);
173 buf_end[4] = PERFETTO_STATIC_CAST(uint8_t, value >> 32);
174 buf_end[5] = PERFETTO_STATIC_CAST(uint8_t, value >> 40);
175 buf_end[6] = PERFETTO_STATIC_CAST(uint8_t, value >> 48);
176 buf_end[7] = PERFETTO_STATIC_CAST(uint8_t, value >> 56);
177 buf_end += 8;
178
179 PerfettoPbMsgAppendBytes(msg, buf,
180 PERFETTO_STATIC_CAST(size_t, buf_end - buf));
181 }
182
PerfettoPbMsgAppendDoubleField(struct PerfettoPbMsg * msg,int32_t field_id,double value)183 static inline void PerfettoPbMsgAppendDoubleField(struct PerfettoPbMsg* msg,
184 int32_t field_id,
185 double value) {
186 uint64_t val;
187 memcpy(&val, &value, sizeof val);
188 PerfettoPbMsgAppendFixed64Field(msg, field_id, val);
189 }
190
PerfettoPbMsgAppendCStrField(struct PerfettoPbMsg * msg,int32_t field_id,const char * c_str)191 static inline void PerfettoPbMsgAppendCStrField(struct PerfettoPbMsg* msg,
192 int32_t field_id,
193 const char* c_str) {
194 PerfettoPbMsgAppendType2Field(
195 msg, field_id, PERFETTO_REINTERPRET_CAST(const uint8_t*, c_str),
196 strlen(c_str));
197 }
198
PerfettoPbMsgBeginNested(struct PerfettoPbMsg * parent,struct PerfettoPbMsg * nested,int32_t field_id)199 static inline void PerfettoPbMsgBeginNested(struct PerfettoPbMsg* parent,
200 struct PerfettoPbMsg* nested,
201 int32_t field_id) {
202 PerfettoPbMsgAppendVarInt(
203 parent, PerfettoPbMakeTag(field_id, PERFETTO_PB_WIRE_TYPE_DELIMITED));
204
205 PerfettoPbMsgInit(nested, parent->writer);
206 if (PERFETTO_UNLIKELY(
207 PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE >
208 PerfettoStreamWriterAvailableBytes(&parent->writer->writer))) {
209 PerfettoPbMsgPatchStack(parent);
210 }
211 nested->size_field = PERFETTO_REINTERPRET_CAST(
212 uint8_t*,
213 PerfettoStreamWriterReserveBytes(&nested->writer->writer,
214 PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE));
215 nested->parent = parent;
216 parent->size += PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE;
217 parent->nested = nested;
218 }
219
220 static inline size_t PerfettoPbMsgFinalize(struct PerfettoPbMsg* msg);
221
PerfettoPbMsgEndNested(struct PerfettoPbMsg * parent)222 static inline void PerfettoPbMsgEndNested(struct PerfettoPbMsg* parent) {
223 parent->size += PerfettoPbMsgFinalize(parent->nested);
224 parent->nested = PERFETTO_NULL;
225 }
226
PerfettoPbMsgFinalize(struct PerfettoPbMsg * msg)227 static inline size_t PerfettoPbMsgFinalize(struct PerfettoPbMsg* msg) {
228 if (msg->nested)
229 PerfettoPbMsgEndNested(msg);
230
231 // Write the length of the nested message a posteriori, using a leading-zero
232 // redundant varint encoding.
233 if (msg->size_field) {
234 uint32_t size_to_write;
235 size_to_write = msg->size;
236 for (size_t i = 0; i < PROTOZERO_MESSAGE_LENGTH_FIELD_SIZE; i++) {
237 const uint8_t msb = (i < 3) ? 0x80 : 0;
238 msg->size_field[i] = (size_to_write & 0xFF) | msb;
239 size_to_write >>= 7;
240 }
241 msg->size_field = PERFETTO_NULL;
242 }
243
244 return msg->size;
245 }
246
247 #endif // INCLUDE_PERFETTO_PUBLIC_PB_MSG_H_
248