• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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