1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
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 "optimize.h"
18
19 namespace SysTuning {
20 namespace ProtoReader {
ProtoReaderBase(DataArea * storage,uint32_t dataAreasCount,const uint8_t * buffer,size_t length)21 ProtoReaderBase::ProtoReaderBase(DataArea* storage, uint32_t dataAreasCount, const uint8_t* buffer, size_t length)
22 : startAddr_(buffer),
23 endAddr_(startAddr_ + length),
24 currentReadAddr_(startAddr_),
25 dataAreas_(storage),
26 dataAreasCount_(dataAreasCount),
27 size_(dataAreasCount),
28 volume_(dataAreasCount)
29 {
30 auto dataAreasSize = sizeof(DataArea) * dataAreasCount_;
31 (void)memset_s(dataAreas_, dataAreasSize, 0, dataAreasSize);
32 dataAreaTypeToParseFuncMap_ = {
33 {ProtoWireType::kVarInt, std::bind(&ProtoReaderBase::ParseVarIntValue, this, std::placeholders::_1,
34 std::placeholders::_2, std::placeholders::_3)},
35 {ProtoWireType::kLengthDelimited,
36 std::bind(&ProtoReaderBase::ParseLengthDelimitedValue, this, std::placeholders::_1, std::placeholders::_2,
37 std::placeholders::_3)},
38 {ProtoWireType::kFixed64, std::bind(&ProtoReaderBase::ParseFixed64Value, this, std::placeholders::_1,
39 std::placeholders::_2, std::placeholders::_3)},
40 {ProtoWireType::kFixed32, std::bind(&ProtoReaderBase::ParseFixed32Value, this, std::placeholders::_1,
41 std::placeholders::_2, std::placeholders::_3)}};
42 }
43
44 // return next parse addr and dataAreaTag. if failed returns nullptr
GetNextProtoTag(const uint8_t * const startAddr,const uint8_t * const endAddr,uint64_t * dataAreaTag)45 const uint8_t* ProtoReaderBase::GetNextProtoTag(const uint8_t* const startAddr,
46 const uint8_t* const endAddr,
47 uint64_t* dataAreaTag)
48 {
49 const uint8_t* cursor = startAddr;
50 if (*cursor & BYTE_HIGHEST_BIT_MARK) {
51 const uint8_t* nextAddr = VarIntDecode(cursor, endAddr, dataAreaTag);
52 if (cursor == nextAddr) {
53 return nullptr;
54 }
55 cursor = nextAddr;
56 } else {
57 *dataAreaTag = *(cursor++);
58 }
59 if (cursor >= endAddr) {
60 return nullptr;
61 }
62 return cursor;
63 }
64
ParseVarIntValue(ParseDataAreaResult & result,const uint8_t * startAddr,const uint8_t * const endAddr)65 bool ProtoReaderBase::ParseVarIntValue(ParseDataAreaResult& result,
66 const uint8_t* startAddr,
67 const uint8_t* const endAddr)
68 {
69 uint64_t intValue = 0;
70 auto cursor = VarIntDecode(startAddr, endAddr, &intValue);
71 if (cursor == startAddr) {
72 return false;
73 }
74 result.dataArea.SetDataAreaIntValue(intValue);
75 result.next = cursor;
76 result.status = OK;
77 return true;
78 }
79
ParseLengthDelimitedValue(ParseDataAreaResult & result,const uint8_t * startAddr,const uint8_t * const endAddr)80 bool ProtoReaderBase::ParseLengthDelimitedValue(ParseDataAreaResult& result,
81 const uint8_t* startAddr,
82 const uint8_t* const endAddr)
83 {
84 uint64_t length = 0;
85 auto cursor = VarIntDecode(startAddr, endAddr, &length);
86 if (cursor == startAddr || length > static_cast<uint64_t>(endAddr - cursor)) {
87 return false;
88 }
89 const uintptr_t dataStartAddr = reinterpret_cast<uintptr_t>(cursor);
90 result.dataArea.SetDataAreaIntValue(dataStartAddr);
91 result.dataArea.SetDataAreaSize(length);
92 result.next = cursor + length;
93 if (length > kMaxMessageLength) {
94 TS_LOGD("Skip this data, because it is too large. length: %d", length);
95 result.status = SKIP;
96 return true;
97 }
98 result.status = OK;
99 return true;
100 }
101
ParseFixed64Value(ParseDataAreaResult & result,const uint8_t * startAddr,const uint8_t * const endAddr)102 bool ProtoReaderBase::ParseFixed64Value(ParseDataAreaResult& result,
103 const uint8_t* startAddr,
104 const uint8_t* const endAddr)
105 {
106 uint64_t intValue = 0;
107 auto cursor = startAddr + sizeof(uint64_t);
108 if (cursor > endAddr) {
109 return false;
110 }
111
112 (void*)memcpy_s(&intValue, sizeof(uint64_t), startAddr, sizeof(uint64_t));
113 result.dataArea.SetDataAreaIntValue(intValue);
114 result.next = cursor;
115 result.status = OK;
116 return true;
117 }
118
ParseFixed32Value(ParseDataAreaResult & result,const uint8_t * startAddr,const uint8_t * const endAddr)119 bool ProtoReaderBase::ParseFixed32Value(ParseDataAreaResult& result,
120 const uint8_t* startAddr,
121 const uint8_t* const endAddr)
122 {
123 uint64_t intValue = 0;
124 auto cursor = startAddr + sizeof(uint32_t);
125 if (cursor > endAddr) {
126 return false;
127 }
128 (void*)memcpy_s(&intValue, sizeof(uint64_t), startAddr, sizeof(uint32_t));
129 result.dataArea.SetDataAreaIntValue(intValue);
130 result.next = cursor;
131 result.status = OK;
132 return true;
133 }
134
ParseOneDataArea(const uint8_t * const startAddr,const uint8_t * const endAddr)135 ParseDataAreaResult ProtoReaderBase::ParseOneDataArea(const uint8_t* const startAddr, const uint8_t* const endAddr)
136 {
137 ParseDataAreaResult result = {ABORT, startAddr, DataArea{}};
138 if (!startAddr || startAddr >= endAddr) {
139 return result;
140 }
141 uint64_t dataAreaTag = 0;
142 auto cursor = GetNextProtoTag(startAddr, endAddr, &dataAreaTag);
143 if (!cursor) {
144 return result;
145 }
146 uint32_t dataAreaId = static_cast<uint32_t>(dataAreaTag >> DATA_AREA_TYPE_BITS);
147 if (dataAreaId == 0) {
148 return result;
149 }
150
151 if (TS_UNLIKELY(dataAreaId > std::numeric_limits<uint16_t>::max())) {
152 TS_LOGD("Skip dataArea %d because its too big", dataAreaId);
153 result.status = ParseProtoStatus::SKIP;
154 return result;
155 }
156 result.dataArea.SetDataAreaId(dataAreaId);
157
158 auto dataAreaType = static_cast<uint8_t>(dataAreaTag) & DATA_AREA_TYPE_VALUE;
159 result.dataArea.SetDataAreaType(dataAreaType);
160
161 auto itor = dataAreaTypeToParseFuncMap_.find(static_cast<ProtoWireType>(dataAreaType));
162 if (itor == dataAreaTypeToParseFuncMap_.end()) {
163 return result;
164 }
165 itor->second(result, cursor, endAddr_);
166 return result;
167 }
168
FindDataArea(uint32_t dataAreaId)169 DataArea ProtoReaderBase::FindDataArea(uint32_t dataAreaId)
170 {
171 DataArea dataArea{};
172 auto temp = currentReadAddr_;
173 currentReadAddr_ = startAddr_;
174 for (auto nextDataArea = ReadNextDataArea(); nextDataArea.DataAreaValid(); nextDataArea = ReadNextDataArea()) {
175 if (nextDataArea.DataAreaId() == dataAreaId) {
176 dataArea = nextDataArea;
177 break;
178 }
179 }
180 currentReadAddr_ = temp;
181 return dataArea;
182 }
183 TS_INLINE
ReadNextDataArea()184 DataArea ProtoReaderBase::ReadNextDataArea()
185 {
186 ParseDataAreaResult result = {ABORT, currentReadAddr_, DataArea{}};
187 do {
188 result = ParseOneDataArea(currentReadAddr_, endAddr_);
189 currentReadAddr_ = result.next;
190 } while (result.status == ParseProtoStatus::SKIP);
191 return result.dataArea;
192 }
193
ParseAllDataAreas()194 void ProtoReaderBase::ParseAllDataAreas()
195 {
196 const uint8_t* cur = startAddr_;
197 ParseDataAreaResult result = {ABORT, startAddr_, DataArea{}};
198 while (true) {
199 result = ParseOneDataArea(cur, endAddr_);
200 cur = result.next;
201 if (result.status == ParseProtoStatus::SKIP) {
202 continue;
203 } else if (result.status == ParseProtoStatus::ABORT) {
204 break;
205 }
206 auto dataAreaId = result.dataArea.DataAreaId();
207 if (dataAreaId >= dataAreasCount_) {
208 continue;
209 }
210
211 DataArea* dataArea = &dataAreas_[dataAreaId];
212 if (!dataArea->DataAreaValid()) {
213 *dataArea = std::move(result.dataArea);
214 } else {
215 if (size_ >= volume_) {
216 MoveToLargerHeapStorage();
217 dataArea = &dataAreas_[dataAreaId];
218 }
219 dataAreas_[size_++] = *dataArea;
220 *dataArea = std::move(result.dataArea);
221 }
222 }
223 currentReadAddr_ = result.next;
224 }
225
MoveToLargerHeapStorage()226 void ProtoReaderBase::MoveToLargerHeapStorage()
227 {
228 uint32_t largerVolume = volume_ << 1;
229 std::unique_ptr<DataArea[]> largerVolumeStorage(new DataArea[largerVolume]);
230 (void*)memcpy_s(&largerVolumeStorage[0], sizeof(DataArea) * largerVolume, dataAreas_, sizeof(DataArea) * size_);
231 lagerHeapStorage_ = std::move(largerVolumeStorage);
232 dataAreas_ = &lagerHeapStorage_[0];
233 volume_ = largerVolume;
234 }
235 } // namespace ProtoReader
236 } // namespace SysTuning
237