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