1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "proto_reader.h"
17 #include <cinttypes>
18 #include "optimize.h"
19
20 namespace SysTuning {
21 namespace ProtoReader {
22 std::map<ProtoWireType, ProtoReaderBase::ParseDataAreaValueByType> ProtoReaderBase::DATA_AREA_TYPE_TO_PARSE_FUNC_MAP = {
23 {ProtoWireType::kVarInt, ProtoReaderBase::ParseVarIntValue},
24 {ProtoWireType::kLengthDelimited, ProtoReaderBase::ParseLengthDelimitedValue},
25 {ProtoWireType::kFixed32, ProtoReaderBase::ParseFixed32Value},
26 {ProtoWireType::kFixed64, ProtoReaderBase::ParseFixed64Value},
27 };
ProtoReaderBase(DataArea * storage,uint32_t dataAreasCount,const uint8_t * buffer,size_t length)28 ProtoReaderBase::ProtoReaderBase(DataArea *storage, uint32_t dataAreasCount, const uint8_t *buffer, size_t length)
29 : startAddr_(buffer),
30 endAddr_(startAddr_ + length),
31 currentReadAddr_(startAddr_),
32 dataAreas_(storage),
33 dataAreasCount_(dataAreasCount),
34 size_(dataAreasCount),
35 volume_(dataAreasCount)
36 {
37 auto dataAreasSize = sizeof(DataArea) * dataAreasCount_;
38 (void)memset_s(dataAreas_, dataAreasSize, 0, dataAreasSize);
39 }
40
41 // return next parse addr and dataAreaTag. if failed returns nullptr
GetNextProtoTag(const uint8_t * const startAddr,const uint8_t * const endAddr,uint64_t * dataAreaTag)42 const uint8_t *ProtoReaderBase::GetNextProtoTag(const uint8_t *const startAddr,
43 const uint8_t *const endAddr,
44 uint64_t *dataAreaTag)
45 {
46 const uint8_t *cursor = startAddr;
47 if (*cursor & BYTE_HIGHEST_BIT_MARK) {
48 const uint8_t *nextAddr = VarIntDecode(cursor, endAddr, dataAreaTag);
49 if (cursor == nextAddr) {
50 return nullptr;
51 }
52 cursor = nextAddr;
53 } else {
54 *dataAreaTag = *(cursor++);
55 }
56 if (cursor >= endAddr) {
57 return nullptr;
58 }
59 return cursor;
60 }
61
ParseVarIntValue(ParseDataAreaResult & result,const uint8_t * startAddr,const uint8_t * const endAddr)62 bool ProtoReaderBase::ParseVarIntValue(ParseDataAreaResult &result,
63 const uint8_t *startAddr,
64 const uint8_t *const endAddr)
65 {
66 uint64_t intValue = 0;
67 auto cursor = VarIntDecode(startAddr, endAddr, &intValue);
68 if (cursor == startAddr) {
69 return false;
70 }
71 result.dataArea.SetDataAreaIntValue(intValue);
72 result.next = cursor;
73 result.status = OK;
74 return true;
75 }
76
ParseLengthDelimitedValue(ParseDataAreaResult & result,const uint8_t * startAddr,const uint8_t * const endAddr)77 bool ProtoReaderBase::ParseLengthDelimitedValue(ParseDataAreaResult &result,
78 const uint8_t *startAddr,
79 const uint8_t *const endAddr)
80 {
81 uint64_t length = 0;
82 auto cursor = VarIntDecode(startAddr, endAddr, &length);
83 if (cursor == startAddr || length > static_cast<uint64_t>(endAddr - cursor)) {
84 return false;
85 }
86 const uintptr_t dataStartAddr = reinterpret_cast<uintptr_t>(cursor);
87 result.dataArea.SetDataAreaIntValue(dataStartAddr);
88 result.dataArea.SetDataAreaSize(length);
89 result.next = cursor + length;
90 if (length > kMaxMessageLength) {
91 TS_LOGD("Skip this data, because it is too large. length: %" PRIu64 "", length);
92 result.status = SKIP;
93 return true;
94 }
95 result.status = OK;
96 return true;
97 }
98
ParseFixed64Value(ParseDataAreaResult & result,const uint8_t * startAddr,const uint8_t * const endAddr)99 bool ProtoReaderBase::ParseFixed64Value(ParseDataAreaResult &result,
100 const uint8_t *startAddr,
101 const uint8_t *const endAddr)
102 {
103 uint64_t intValue = 0;
104 auto cursor = startAddr + sizeof(uint64_t);
105 if (cursor > endAddr) {
106 return false;
107 }
108
109 (void)memcpy_s(&intValue, sizeof(uint64_t), startAddr, sizeof(uint64_t));
110 result.dataArea.SetDataAreaIntValue(intValue);
111 result.next = cursor;
112 result.status = OK;
113 return true;
114 }
115
ParseFixed32Value(ParseDataAreaResult & result,const uint8_t * startAddr,const uint8_t * const endAddr)116 bool ProtoReaderBase::ParseFixed32Value(ParseDataAreaResult &result,
117 const uint8_t *startAddr,
118 const uint8_t *const endAddr)
119 {
120 uint64_t intValue = 0;
121 auto cursor = startAddr + sizeof(uint32_t);
122 if (cursor > endAddr) {
123 return false;
124 }
125 (void)memcpy_s(&intValue, sizeof(uint64_t), startAddr, sizeof(uint32_t));
126 result.dataArea.SetDataAreaIntValue(intValue);
127 result.next = cursor;
128 result.status = OK;
129 return true;
130 }
131
ParseOneDataArea(const uint8_t * const startAddr,const uint8_t * const endAddr)132 ParseDataAreaResult ProtoReaderBase::ParseOneDataArea(const uint8_t *const startAddr, const uint8_t *const endAddr)
133 {
134 ParseDataAreaResult result = {ABORT, startAddr, DataArea{}};
135 if (!startAddr || startAddr >= endAddr) {
136 return result;
137 }
138 uint64_t dataAreaTag = 0;
139 auto cursor = GetNextProtoTag(startAddr, endAddr, &dataAreaTag);
140 if (!cursor) {
141 return result;
142 }
143 uint32_t dataAreaId = static_cast<uint32_t>(dataAreaTag >> DATA_AREA_TYPE_BITS);
144 if (dataAreaId == 0) {
145 return result;
146 }
147 if (TS_UNLIKELY(dataAreaId > std::numeric_limits<uint16_t>::max())) {
148 TS_LOGD("Skip dataArea %d because its too big", dataAreaId);
149 result.status = ParseProtoStatus::SKIP;
150 result.next = cursor;
151 return result;
152 }
153 result.dataArea.SetDataAreaId(dataAreaId);
154
155 auto dataAreaType = static_cast<uint8_t>(dataAreaTag) & DATA_AREA_TYPE_VALUE;
156 result.dataArea.SetDataAreaType(dataAreaType);
157
158 auto itor = DATA_AREA_TYPE_TO_PARSE_FUNC_MAP.find(static_cast<ProtoWireType>(dataAreaType));
159 if (itor == DATA_AREA_TYPE_TO_PARSE_FUNC_MAP.end()) {
160 return result;
161 }
162 itor->second(result, cursor, endAddr_);
163 return result;
164 }
165
FindDataArea(uint32_t dataAreaId)166 DataArea ProtoReaderBase::FindDataArea(uint32_t dataAreaId)
167 {
168 DataArea dataArea{};
169 auto temp = currentReadAddr_;
170 currentReadAddr_ = startAddr_;
171 for (auto nextDataArea = ReadNextDataArea(); nextDataArea.DataAreaValid(); nextDataArea = ReadNextDataArea()) {
172 if (nextDataArea.DataAreaId() == dataAreaId) {
173 dataArea = nextDataArea;
174 break;
175 }
176 }
177 currentReadAddr_ = temp;
178 return dataArea;
179 }
180 TS_INLINE
ReadNextDataArea()181 DataArea ProtoReaderBase::ReadNextDataArea()
182 {
183 ParseDataAreaResult result = {ABORT, currentReadAddr_, DataArea{}};
184 do {
185 result = ParseOneDataArea(currentReadAddr_, endAddr_);
186 currentReadAddr_ = result.next;
187 } while (result.status == ParseProtoStatus::SKIP);
188 return result.dataArea;
189 }
190
ParseAllDataAreas()191 void ProtoReaderBase::ParseAllDataAreas()
192 {
193 const uint8_t *cur = startAddr_;
194 ParseDataAreaResult result = {ABORT, startAddr_, DataArea{}};
195 while (true) {
196 result = ParseOneDataArea(cur, endAddr_);
197 cur = result.next;
198 if (result.status == ParseProtoStatus::SKIP) {
199 continue;
200 } else if (result.status == ParseProtoStatus::ABORT) {
201 break;
202 }
203 auto dataAreaId = result.dataArea.DataAreaId();
204 if (dataAreaId >= dataAreasCount_) {
205 continue;
206 }
207
208 DataArea *dataArea = &dataAreas_[dataAreaId];
209 if (!dataArea->DataAreaValid()) {
210 *dataArea = std::move(result.dataArea);
211 } else {
212 if (size_ >= volume_) {
213 MoveToLargerHeapStorage();
214 dataArea = &dataAreas_[dataAreaId];
215 }
216 dataAreas_[size_++] = *dataArea;
217 *dataArea = std::move(result.dataArea);
218 }
219 }
220 currentReadAddr_ = result.next;
221 }
222
MoveToLargerHeapStorage()223 void ProtoReaderBase::MoveToLargerHeapStorage()
224 {
225 uint32_t largerVolume = volume_ << 1;
226 std::unique_ptr<DataArea[]> largerVolumeStorage = std::make_unique<DataArea[]>(largerVolume);
227 (void)memcpy_s(&largerVolumeStorage[0], sizeof(DataArea) * largerVolume, dataAreas_, sizeof(DataArea) * size_);
228 lagerHeapStorage_ = std::move(largerVolumeStorage);
229 dataAreas_ = &lagerHeapStorage_[0];
230 volume_ = largerVolume;
231 }
232 } // namespace ProtoReader
233 } // namespace SysTuning
234