• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #include "perfetto/public/abi/pb_decoder_abi.h"
18 
19 #include <limits>
20 #include <type_traits>
21 
22 #include "perfetto/public/pb_utils.h"
23 
24 namespace {
25 template <typename T>
Uint64RepresentableIn(uint64_t val)26 bool Uint64RepresentableIn(uint64_t val) {
27   return val <= std::numeric_limits<T>::max();
28 }
29 }  // namespace
30 
PerfettoPbDecoderParseField(struct PerfettoPbDecoder * decoder)31 struct PerfettoPbDecoderField PerfettoPbDecoderParseField(
32     struct PerfettoPbDecoder* decoder) {
33   struct PerfettoPbDecoderField field;
34   const uint8_t* read_ptr = decoder->read_ptr;
35   if (read_ptr >= decoder->end_ptr) {
36     field.status = PERFETTO_PB_DECODER_DONE;
37     return field;
38   }
39   field.status = PERFETTO_PB_DECODER_ERROR;
40   uint64_t tag;
41   const uint8_t* end_of_tag =
42       PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &tag);
43   if (end_of_tag == read_ptr) {
44     field.status = PERFETTO_PB_DECODER_ERROR;
45     return field;
46   }
47   read_ptr = end_of_tag;
48   constexpr uint8_t kFieldTypeNumBits = 3;
49 
50   field.wire_type = tag & ((1 << kFieldTypeNumBits) - 1);
51   uint64_t id = tag >> kFieldTypeNumBits;
52   static_assert(std::is_same<uint32_t, decltype(field.id)>::value);
53   if (id > std::numeric_limits<uint32_t>::max()) {
54     field.status = PERFETTO_PB_DECODER_ERROR;
55     return field;
56   }
57   field.id = static_cast<uint32_t>(id);
58 
59   switch (field.wire_type) {
60     case PERFETTO_PB_WIRE_TYPE_DELIMITED: {
61       uint64_t len;
62       const uint8_t* end_of_len =
63           PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &len);
64       if (end_of_len == read_ptr || !Uint64RepresentableIn<size_t>(len)) {
65         field.status = PERFETTO_PB_DECODER_ERROR;
66         return field;
67       }
68       read_ptr = end_of_len;
69       field.value.delimited.len = static_cast<size_t>(len);
70       field.value.delimited.start = read_ptr;
71       read_ptr += len;
72       if (read_ptr > decoder->end_ptr) {
73         field.status = PERFETTO_PB_DECODER_ERROR;
74         return field;
75       }
76       field.status = PERFETTO_PB_DECODER_OK;
77       decoder->read_ptr = read_ptr;
78       break;
79     }
80     case PERFETTO_PB_WIRE_TYPE_VARINT: {
81       uint64_t val;
82       const uint8_t* end_of_val =
83           PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &val);
84       if (end_of_val == read_ptr) {
85         field.status = PERFETTO_PB_DECODER_ERROR;
86         return field;
87       }
88       read_ptr = end_of_val;
89       field.value.integer64 = val;
90       field.status = PERFETTO_PB_DECODER_OK;
91       decoder->read_ptr = read_ptr;
92       break;
93     }
94     case PERFETTO_PB_WIRE_TYPE_FIXED32: {
95       const uint8_t* end_of_val = read_ptr + sizeof(uint32_t);
96       if (end_of_val > decoder->end_ptr) {
97         field.status = PERFETTO_PB_DECODER_ERROR;
98         return field;
99       }
100       // Little endian on the wire.
101       field.value.integer32 = read_ptr[0] |
102                               (static_cast<uint32_t>(read_ptr[1]) << 8) |
103                               (static_cast<uint32_t>(read_ptr[2]) << 16) |
104                               (static_cast<uint32_t>(read_ptr[3]) << 24);
105       read_ptr = end_of_val;
106       decoder->read_ptr = read_ptr;
107       field.status = PERFETTO_PB_DECODER_OK;
108       break;
109     }
110     case PERFETTO_PB_WIRE_TYPE_FIXED64: {
111       const uint8_t* end_of_val = read_ptr + sizeof(uint64_t);
112       if (end_of_val > decoder->end_ptr) {
113         field.status = PERFETTO_PB_DECODER_ERROR;
114         return field;
115       }
116       // Little endian on the wire.
117       field.value.integer64 = read_ptr[0] |
118                               (static_cast<uint64_t>(read_ptr[1]) << 8) |
119                               (static_cast<uint64_t>(read_ptr[2]) << 16) |
120                               (static_cast<uint64_t>(read_ptr[3]) << 24) |
121                               (static_cast<uint64_t>(read_ptr[4]) << 32) |
122                               (static_cast<uint64_t>(read_ptr[5]) << 40) |
123                               (static_cast<uint64_t>(read_ptr[6]) << 48) |
124                               (static_cast<uint64_t>(read_ptr[7]) << 56);
125       read_ptr = end_of_val;
126       decoder->read_ptr = read_ptr;
127       field.status = PERFETTO_PB_DECODER_OK;
128       break;
129     }
130     default:
131       field.status = PERFETTO_PB_DECODER_ERROR;
132       return field;
133   }
134   return field;
135 }
136 
PerfettoPbDecoderSkipField(struct PerfettoPbDecoder * decoder)137 uint32_t PerfettoPbDecoderSkipField(struct PerfettoPbDecoder* decoder) {
138   const uint8_t* read_ptr = decoder->read_ptr;
139   if (read_ptr >= decoder->end_ptr) {
140     return PERFETTO_PB_DECODER_DONE;
141   }
142   uint64_t tag;
143   const uint8_t* end_of_tag =
144       PerfettoPbParseVarInt(decoder->read_ptr, decoder->end_ptr, &tag);
145   if (end_of_tag == read_ptr) {
146     return PERFETTO_PB_DECODER_ERROR;
147   }
148   read_ptr = end_of_tag;
149   constexpr uint8_t kFieldTypeNumBits = 3;
150 
151   uint32_t wire_type = tag & ((1 << kFieldTypeNumBits) - 1);
152   switch (wire_type) {
153     case PERFETTO_PB_WIRE_TYPE_DELIMITED: {
154       uint64_t len;
155       const uint8_t* end_of_len =
156           PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &len);
157       if (end_of_len == read_ptr) {
158         return PERFETTO_PB_DECODER_ERROR;
159       }
160       read_ptr = end_of_len;
161       read_ptr += len;
162       if (read_ptr > decoder->end_ptr) {
163         return PERFETTO_PB_DECODER_ERROR;
164       }
165       decoder->read_ptr = read_ptr;
166       return PERFETTO_PB_DECODER_OK;
167     }
168     case PERFETTO_PB_WIRE_TYPE_VARINT: {
169       uint64_t val;
170       const uint8_t* end_of_val =
171           PerfettoPbParseVarInt(read_ptr, decoder->end_ptr, &val);
172       if (end_of_val == read_ptr) {
173         return PERFETTO_PB_DECODER_ERROR;
174       }
175       read_ptr = end_of_val;
176       decoder->read_ptr = read_ptr;
177       return PERFETTO_PB_DECODER_OK;
178     }
179     case PERFETTO_PB_WIRE_TYPE_FIXED32: {
180       const uint8_t* end_of_val = read_ptr + sizeof(uint32_t);
181       if (end_of_val > decoder->end_ptr) {
182         return PERFETTO_PB_DECODER_ERROR;
183       }
184       read_ptr = end_of_val;
185       decoder->read_ptr = read_ptr;
186       return PERFETTO_PB_DECODER_OK;
187     }
188     case PERFETTO_PB_WIRE_TYPE_FIXED64: {
189       const uint8_t* end_of_val = read_ptr + sizeof(uint64_t);
190       if (read_ptr > decoder->end_ptr) {
191         return PERFETTO_PB_DECODER_ERROR;
192       }
193       read_ptr = end_of_val;
194       decoder->read_ptr = read_ptr;
195       return PERFETTO_PB_DECODER_OK;
196     }
197     default:
198       break;
199   }
200   return PERFETTO_PB_DECODER_ERROR;
201 }
202