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 20namespace SysTuning { 21namespace ProtoReader { 22std::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}; 28ProtoReaderBase::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 42const 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 62bool 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 77bool 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 99bool 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 116bool 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 132ParseDataAreaResult 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 166DataArea 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} 180TS_INLINE 181DataArea 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 191void 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 223void 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