1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker * Copyright (C) 2023 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker *
4*6dbdd20aSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker *
8*6dbdd20aSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker *
10*6dbdd20aSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker */
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/public/abi/pb_decoder_abi.h"
18*6dbdd20aSAndroid Build Coastguard Worker
19*6dbdd20aSAndroid Build Coastguard Worker #include <limits>
20*6dbdd20aSAndroid Build Coastguard Worker #include <type_traits>
21*6dbdd20aSAndroid Build Coastguard Worker
22*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/public/pb_utils.h"
23*6dbdd20aSAndroid Build Coastguard Worker
24*6dbdd20aSAndroid Build Coastguard Worker namespace {
25*6dbdd20aSAndroid Build Coastguard Worker template <typename T>
Uint64RepresentableIn(uint64_t val)26*6dbdd20aSAndroid Build Coastguard Worker bool Uint64RepresentableIn(uint64_t val) {
27*6dbdd20aSAndroid Build Coastguard Worker return val <= std::numeric_limits<T>::max();
28*6dbdd20aSAndroid Build Coastguard Worker }
29*6dbdd20aSAndroid Build Coastguard Worker } // namespace
30*6dbdd20aSAndroid Build Coastguard Worker
PerfettoPbDecoderParseField(struct PerfettoPbDecoder * decoder)31*6dbdd20aSAndroid Build Coastguard Worker struct PerfettoPbDecoderField PerfettoPbDecoderParseField(
32*6dbdd20aSAndroid Build Coastguard Worker struct PerfettoPbDecoder* decoder) {
33*6dbdd20aSAndroid Build Coastguard Worker struct PerfettoPbDecoderField field;
34*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* read_ptr = decoder->read_ptr;
35*6dbdd20aSAndroid Build Coastguard Worker if (read_ptr >= decoder->end_ptr) {
36*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_DONE;
37*6dbdd20aSAndroid Build Coastguard Worker return field;
38*6dbdd20aSAndroid Build Coastguard Worker }
39*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
40*6dbdd20aSAndroid Build Coastguard Worker uint64_t tag;
41*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_tag =
42*6dbdd20aSAndroid Build Coastguard Worker PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &tag);
43*6dbdd20aSAndroid Build Coastguard Worker if (end_of_tag == read_ptr) {
44*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
45*6dbdd20aSAndroid Build Coastguard Worker return field;
46*6dbdd20aSAndroid Build Coastguard Worker }
47*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_tag;
48*6dbdd20aSAndroid Build Coastguard Worker constexpr uint8_t kFieldTypeNumBits = 3;
49*6dbdd20aSAndroid Build Coastguard Worker
50*6dbdd20aSAndroid Build Coastguard Worker field.wire_type = tag & ((1 << kFieldTypeNumBits) - 1);
51*6dbdd20aSAndroid Build Coastguard Worker uint64_t id = tag >> kFieldTypeNumBits;
52*6dbdd20aSAndroid Build Coastguard Worker static_assert(std::is_same<uint32_t, decltype(field.id)>::value);
53*6dbdd20aSAndroid Build Coastguard Worker if (id > std::numeric_limits<uint32_t>::max()) {
54*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
55*6dbdd20aSAndroid Build Coastguard Worker return field;
56*6dbdd20aSAndroid Build Coastguard Worker }
57*6dbdd20aSAndroid Build Coastguard Worker field.id = static_cast<uint32_t>(id);
58*6dbdd20aSAndroid Build Coastguard Worker
59*6dbdd20aSAndroid Build Coastguard Worker switch (field.wire_type) {
60*6dbdd20aSAndroid Build Coastguard Worker case PERFETTO_PB_WIRE_TYPE_DELIMITED: {
61*6dbdd20aSAndroid Build Coastguard Worker uint64_t len;
62*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_len =
63*6dbdd20aSAndroid Build Coastguard Worker PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &len);
64*6dbdd20aSAndroid Build Coastguard Worker if (end_of_len == read_ptr || !Uint64RepresentableIn<size_t>(len)) {
65*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
66*6dbdd20aSAndroid Build Coastguard Worker return field;
67*6dbdd20aSAndroid Build Coastguard Worker }
68*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_len;
69*6dbdd20aSAndroid Build Coastguard Worker field.value.delimited.len = static_cast<size_t>(len);
70*6dbdd20aSAndroid Build Coastguard Worker field.value.delimited.start = read_ptr;
71*6dbdd20aSAndroid Build Coastguard Worker read_ptr += len;
72*6dbdd20aSAndroid Build Coastguard Worker if (read_ptr > decoder->end_ptr) {
73*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
74*6dbdd20aSAndroid Build Coastguard Worker return field;
75*6dbdd20aSAndroid Build Coastguard Worker }
76*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_OK;
77*6dbdd20aSAndroid Build Coastguard Worker decoder->read_ptr = read_ptr;
78*6dbdd20aSAndroid Build Coastguard Worker break;
79*6dbdd20aSAndroid Build Coastguard Worker }
80*6dbdd20aSAndroid Build Coastguard Worker case PERFETTO_PB_WIRE_TYPE_VARINT: {
81*6dbdd20aSAndroid Build Coastguard Worker uint64_t val;
82*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_val =
83*6dbdd20aSAndroid Build Coastguard Worker PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &val);
84*6dbdd20aSAndroid Build Coastguard Worker if (end_of_val == read_ptr) {
85*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
86*6dbdd20aSAndroid Build Coastguard Worker return field;
87*6dbdd20aSAndroid Build Coastguard Worker }
88*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_val;
89*6dbdd20aSAndroid Build Coastguard Worker field.value.integer64 = val;
90*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_OK;
91*6dbdd20aSAndroid Build Coastguard Worker decoder->read_ptr = read_ptr;
92*6dbdd20aSAndroid Build Coastguard Worker break;
93*6dbdd20aSAndroid Build Coastguard Worker }
94*6dbdd20aSAndroid Build Coastguard Worker case PERFETTO_PB_WIRE_TYPE_FIXED32: {
95*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_val = read_ptr + sizeof(uint32_t);
96*6dbdd20aSAndroid Build Coastguard Worker if (end_of_val > decoder->end_ptr) {
97*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
98*6dbdd20aSAndroid Build Coastguard Worker return field;
99*6dbdd20aSAndroid Build Coastguard Worker }
100*6dbdd20aSAndroid Build Coastguard Worker // Little endian on the wire.
101*6dbdd20aSAndroid Build Coastguard Worker field.value.integer32 = read_ptr[0] |
102*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint32_t>(read_ptr[1]) << 8) |
103*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint32_t>(read_ptr[2]) << 16) |
104*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint32_t>(read_ptr[3]) << 24);
105*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_val;
106*6dbdd20aSAndroid Build Coastguard Worker decoder->read_ptr = read_ptr;
107*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_OK;
108*6dbdd20aSAndroid Build Coastguard Worker break;
109*6dbdd20aSAndroid Build Coastguard Worker }
110*6dbdd20aSAndroid Build Coastguard Worker case PERFETTO_PB_WIRE_TYPE_FIXED64: {
111*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_val = read_ptr + sizeof(uint64_t);
112*6dbdd20aSAndroid Build Coastguard Worker if (end_of_val > decoder->end_ptr) {
113*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
114*6dbdd20aSAndroid Build Coastguard Worker return field;
115*6dbdd20aSAndroid Build Coastguard Worker }
116*6dbdd20aSAndroid Build Coastguard Worker // Little endian on the wire.
117*6dbdd20aSAndroid Build Coastguard Worker field.value.integer64 = read_ptr[0] |
118*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint64_t>(read_ptr[1]) << 8) |
119*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint64_t>(read_ptr[2]) << 16) |
120*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint64_t>(read_ptr[3]) << 24) |
121*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint64_t>(read_ptr[4]) << 32) |
122*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint64_t>(read_ptr[5]) << 40) |
123*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint64_t>(read_ptr[6]) << 48) |
124*6dbdd20aSAndroid Build Coastguard Worker (static_cast<uint64_t>(read_ptr[7]) << 56);
125*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_val;
126*6dbdd20aSAndroid Build Coastguard Worker decoder->read_ptr = read_ptr;
127*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_OK;
128*6dbdd20aSAndroid Build Coastguard Worker break;
129*6dbdd20aSAndroid Build Coastguard Worker }
130*6dbdd20aSAndroid Build Coastguard Worker default:
131*6dbdd20aSAndroid Build Coastguard Worker field.status = PERFETTO_PB_DECODER_ERROR;
132*6dbdd20aSAndroid Build Coastguard Worker return field;
133*6dbdd20aSAndroid Build Coastguard Worker }
134*6dbdd20aSAndroid Build Coastguard Worker return field;
135*6dbdd20aSAndroid Build Coastguard Worker }
136*6dbdd20aSAndroid Build Coastguard Worker
PerfettoPbDecoderSkipField(struct PerfettoPbDecoder * decoder)137*6dbdd20aSAndroid Build Coastguard Worker uint32_t PerfettoPbDecoderSkipField(struct PerfettoPbDecoder* decoder) {
138*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* read_ptr = decoder->read_ptr;
139*6dbdd20aSAndroid Build Coastguard Worker if (read_ptr >= decoder->end_ptr) {
140*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_DONE;
141*6dbdd20aSAndroid Build Coastguard Worker }
142*6dbdd20aSAndroid Build Coastguard Worker uint64_t tag;
143*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_tag =
144*6dbdd20aSAndroid Build Coastguard Worker PerfettoPbParseVarInt(decoder->read_ptr, decoder->end_ptr, &tag);
145*6dbdd20aSAndroid Build Coastguard Worker if (end_of_tag == read_ptr) {
146*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_ERROR;
147*6dbdd20aSAndroid Build Coastguard Worker }
148*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_tag;
149*6dbdd20aSAndroid Build Coastguard Worker constexpr uint8_t kFieldTypeNumBits = 3;
150*6dbdd20aSAndroid Build Coastguard Worker
151*6dbdd20aSAndroid Build Coastguard Worker uint32_t wire_type = tag & ((1 << kFieldTypeNumBits) - 1);
152*6dbdd20aSAndroid Build Coastguard Worker switch (wire_type) {
153*6dbdd20aSAndroid Build Coastguard Worker case PERFETTO_PB_WIRE_TYPE_DELIMITED: {
154*6dbdd20aSAndroid Build Coastguard Worker uint64_t len;
155*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_len =
156*6dbdd20aSAndroid Build Coastguard Worker PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &len);
157*6dbdd20aSAndroid Build Coastguard Worker if (end_of_len == read_ptr) {
158*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_ERROR;
159*6dbdd20aSAndroid Build Coastguard Worker }
160*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_len;
161*6dbdd20aSAndroid Build Coastguard Worker read_ptr += len;
162*6dbdd20aSAndroid Build Coastguard Worker if (read_ptr > decoder->end_ptr) {
163*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_ERROR;
164*6dbdd20aSAndroid Build Coastguard Worker }
165*6dbdd20aSAndroid Build Coastguard Worker decoder->read_ptr = read_ptr;
166*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_OK;
167*6dbdd20aSAndroid Build Coastguard Worker }
168*6dbdd20aSAndroid Build Coastguard Worker case PERFETTO_PB_WIRE_TYPE_VARINT: {
169*6dbdd20aSAndroid Build Coastguard Worker uint64_t val;
170*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_val =
171*6dbdd20aSAndroid Build Coastguard Worker PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &val);
172*6dbdd20aSAndroid Build Coastguard Worker if (end_of_val == read_ptr) {
173*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_ERROR;
174*6dbdd20aSAndroid Build Coastguard Worker }
175*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_val;
176*6dbdd20aSAndroid Build Coastguard Worker decoder->read_ptr = read_ptr;
177*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_OK;
178*6dbdd20aSAndroid Build Coastguard Worker }
179*6dbdd20aSAndroid Build Coastguard Worker case PERFETTO_PB_WIRE_TYPE_FIXED32: {
180*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_val = read_ptr + sizeof(uint32_t);
181*6dbdd20aSAndroid Build Coastguard Worker if (end_of_val > decoder->end_ptr) {
182*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_ERROR;
183*6dbdd20aSAndroid Build Coastguard Worker }
184*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_val;
185*6dbdd20aSAndroid Build Coastguard Worker decoder->read_ptr = read_ptr;
186*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_OK;
187*6dbdd20aSAndroid Build Coastguard Worker }
188*6dbdd20aSAndroid Build Coastguard Worker case PERFETTO_PB_WIRE_TYPE_FIXED64: {
189*6dbdd20aSAndroid Build Coastguard Worker const uint8_t* end_of_val = read_ptr + sizeof(uint64_t);
190*6dbdd20aSAndroid Build Coastguard Worker if (read_ptr > decoder->end_ptr) {
191*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_ERROR;
192*6dbdd20aSAndroid Build Coastguard Worker }
193*6dbdd20aSAndroid Build Coastguard Worker read_ptr = end_of_val;
194*6dbdd20aSAndroid Build Coastguard Worker decoder->read_ptr = read_ptr;
195*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_OK;
196*6dbdd20aSAndroid Build Coastguard Worker }
197*6dbdd20aSAndroid Build Coastguard Worker default:
198*6dbdd20aSAndroid Build Coastguard Worker break;
199*6dbdd20aSAndroid Build Coastguard Worker }
200*6dbdd20aSAndroid Build Coastguard Worker return PERFETTO_PB_DECODER_ERROR;
201*6dbdd20aSAndroid Build Coastguard Worker }
202