/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "perf_file_format.h" #include "debug_logger.h" namespace OHOS { namespace Developtools { namespace HiPerf { std::string PerfFileSection::GetFeatureName(FEATURE featureId) { unsigned int index = static_cast<unsigned int>(featureId); if (featureId >= FEATURE::HIPERF_FIRST_FEATURE) { index -= static_cast<unsigned int>(FEATURE::HIPERF_FIRST_FEATURE); if (index >= extFeatureNames.size()) { return featureNames[0]; } return extFeatureNames[index]; } else { if (index >= featureNames.size()) { return featureNames[0]; } return featureNames[index]; } } // for read void PerfFileSection::Init(const char *buffer, size_t maxSize) { rBuffer_ = buffer; maxSize_ = maxSize; offset_ = 0; } // for write void PerfFileSection::Init(char *buffer, size_t maxSize) { wBuffer_ = buffer; maxSize_ = maxSize; offset_ = 0; } bool PerfFileSection::Write(uint32_t u32) { uint32_t value = u32; return Write((char *)&value, sizeof(uint32_t)); } bool PerfFileSection::Write(uint64_t u64) { uint64_t value = u64; return Write((char *)&value, sizeof(uint64_t)); } bool PerfFileSection::Write(const std::string &str) { if (Write((uint32_t)str.size() + 1)) { // include the ending \0 return Write(str.c_str(), str.size(), str.size() + 1); } else { return false; } } bool PerfFileSection::Write(const char *buf, size_t size) { return Write(buf, size, size); } bool PerfFileSection::Write(const char *buf, size_t size, size_t max) { if (offset_ + size > maxSize_) { HLOGE("write out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); return false; } if (offset_ + max > maxSize_) { HLOGE("write out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); return false; } std::copy(buf, buf + size, wBuffer_ + offset_); if (size >= max) { offset_ += size; } else { offset_ += max; } return true; } bool PerfFileSection::Read(uint32_t &value) { static_assert(sizeof(uint32_t) == 4); return Read((char *)&value, sizeof(uint32_t)); } bool PerfFileSection::Read(uint64_t &value) { static_assert(sizeof(uint64_t) == 8); return Read((char *)&value, sizeof(uint64_t)); } bool PerfFileSection::Read(std::string &value) { uint32_t size = 0; if (!Read(size)) { return false; } // if size large than buf size or 0 size ? // don't assert for fuzz test if (size == 0 or size > maxSize_) { return false; } char buf[size]; if (!Read(buf, size)) { return false; } if (buf[size - 1] != 0) { return false; } value = buf; HLOGDUMMY("Read String size %u buf : %s", size, value.c_str()); return true; } void PerfFileSection::Skip(size_t size) { offset_ += size; } bool PerfFileSection::Read(char *buf, size_t size) { HLOG_ASSERT(buf != nullptr); if (size == 0) { HLOGE("read zero size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); return false; } else if (offset_ + size > maxSize_) { HLOGE("read out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); if (memset_s(buf, size, 0, size) != EOK) { // make sure the content return is 0 when failed HLOGE("memset_s failed in PerfFileSection::Read"); return false; } return false; } HLOGD("PerfFileSection::Read offset_ %zu size %zu maxSize_ %zu", offset_, size, maxSize_); std::copy((rBuffer_ + offset_), (rBuffer_ + offset_ + size), buf); offset_ += size; HLOGDUMMY("after read offset_ %zx size %zu buf %x", offset_, size, buf[0]); return true; } uint32_t PerfFileSection::SizeOf(std::string &string) { return sizeof(uint32_t) + string.size() + 1; /* '\0' */ } PerfFileSectionString::PerfFileSectionString(FEATURE id, const char *buf, size_t size) : PerfFileSection(id) { Init(buf, size); if (!Read(stdString_)) { return; // or throw ... } } PerfFileSectionString::PerfFileSectionString(FEATURE id, const std::string &charString) : PerfFileSection(id) { stdString_ = charString; } bool PerfFileSectionString::GetBinary(char *buf, size_t size) { if (size < GetSize()) { return false; } Init(buf, size); Write(stdString_); return true; } size_t PerfFileSectionString::GetSize() { return SizeOf(stdString_); } const std::string PerfFileSectionString::toString() const { return stdString_; } size_t PerfFileSectionSymbolsFiles::GetSize() { size_t size = 0; size += sizeof(uint32_t); // how many SymbolFileStruct for (auto &symbolFileStruct : symbolFileStructs_) { size += SizeOf(symbolFileStruct.filePath_); size += sizeof(symbolFileStruct.symbolType_); size += sizeof(symbolFileStruct.textExecVaddr_); size += sizeof(symbolFileStruct.textExecVaddrFileOffset_); size += SizeOf(symbolFileStruct.buildId_); size += sizeof(uint32_t); // how many SymbolStruct for (auto &symbolStruct : symbolFileStruct.symbolStructs_) { size += sizeof(symbolStruct.vaddr_); size += sizeof(symbolStruct.len_); size += SizeOf(symbolStruct.symbolName_); } } return size; } PerfFileSectionSymbolsFiles::PerfFileSectionSymbolsFiles(FEATURE id, const char *buf, size_t size) : PerfFileSection(id) { Init(buf, size); uint32_t symbolFileNumber = 0; if (!Read(symbolFileNumber)) { HLOGE(" symbolFileNumber read failed"); return; } else if (symbolFileNumber > MAX_SYMBOLS_FILE_NUMBER) { HLOGE(" symbolFileNumber %u too large", symbolFileNumber); return; } else { HLOGV(" symbolFileNumber %u", symbolFileNumber); } for (uint32_t i = symbolFileNumber; i > 0; i--) { auto &symbolFileStruct = symbolFileStructs_.emplace_back(); Read(symbolFileStruct.filePath_); HLOGV(" symbolFileStruct.filePath_ %s", symbolFileStruct.filePath_.c_str()); Read(symbolFileStruct.symbolType_); Read(symbolFileStruct.textExecVaddr_); Read(symbolFileStruct.textExecVaddrFileOffset_); Read(symbolFileStruct.buildId_); uint32_t symbolsNumber = 0; if (!Read(symbolsNumber)) { HLOGE(" symbols read failed"); return; } else if (symbolsNumber > MAX_SYMBOLS_NUMBER) { HLOGE(" symbols %u too large", symbolsNumber); return; } else { HLOGV(" symbols %u", symbolsNumber); } for (; symbolsNumber > 0; symbolsNumber--) { auto &symbolStruct = symbolFileStruct.symbolStructs_.emplace_back(); Read(symbolStruct.vaddr_); Read(symbolStruct.len_); Read(symbolStruct.symbolName_); } HLOGV(" %zu SymbolStruct read.", symbolFileStruct.symbolStructs_.size()); } HLOGV(" %zu SymbolFileStruct read.", symbolFileStructs_.size()); } bool PerfFileSectionSymbolsFiles::GetBinary(char *buf, size_t size) { HLOGV("PerfFileSectionSymbolsFiles get buffer size %zu.", size); HLOG_ASSERT(size >= GetSize()); Init(buf, size); if (!Write((uint32_t)symbolFileStructs_.size())) { HLOGE("PerfFileSectionSymbolsFiles write failed with %zu.", symbolFileStructs_.size()); return false; } for (auto &symbolFileStruct : symbolFileStructs_) { Write(symbolFileStruct.filePath_); Write(symbolFileStruct.symbolType_); Write(symbolFileStruct.textExecVaddr_); Write(symbolFileStruct.textExecVaddrFileOffset_); Write(symbolFileStruct.buildId_); Write((uint32_t)symbolFileStruct.symbolStructs_.size()); for (auto &symbolStruct : symbolFileStruct.symbolStructs_) { Write(symbolStruct.vaddr_); Write(symbolStruct.len_); Write(symbolStruct.symbolName_); } HLOGV(" %zu SymbolStruct writed. for %s at 0x%016" PRIx64 "@0x%08" PRIx64 ": %s", symbolFileStruct.symbolStructs_.size(), symbolFileStruct.filePath_.c_str(), symbolFileStruct.textExecVaddr_, symbolFileStruct.textExecVaddrFileOffset_, symbolFileStruct.buildId_.c_str()); } HLOGV("%zu SymbolFileStruct writed.", symbolFileStructs_.size()); return true; } PerfFileSectionNrCpus::PerfFileSectionNrCpus(FEATURE id, const char *buf, size_t size) : PerfFileSection(id) { Init(buf, size); if (!Read(nrCpusAvailable_) || !Read(nrCpusOnline_)) { return; } } PerfFileSectionNrCpus::PerfFileSectionNrCpus(FEATURE id, uint32_t nrCpusAvailable, uint32_t nrCpusOnline) : PerfFileSection(id), nrCpusAvailable_(nrCpusAvailable), nrCpusOnline_(nrCpusOnline) { } bool PerfFileSectionNrCpus::GetBinary(char *buf, size_t size) { if (size < GetSize()) { return false; } Init(buf, size); Write(nrCpusAvailable_); Write(nrCpusOnline_); return true; } size_t PerfFileSectionNrCpus::GetSize() { return (sizeof(nrCpusAvailable_) + sizeof(nrCpusOnline_)); } void PerfFileSectionNrCpus::GetValue(uint32_t &nrCpusAvailable, uint32_t &nrCpusOnline) const { nrCpusAvailable = nrCpusAvailable_; nrCpusOnline = nrCpusOnline_; } PerfFileSectionU64::PerfFileSectionU64(FEATURE id, const char *buf, size_t size) : PerfFileSection(id) { Init(buf, size); if (!Read(value_)) { return; } } PerfFileSectionU64::PerfFileSectionU64(FEATURE id, uint64_t v) : PerfFileSection(id) { value_ = v; } bool PerfFileSectionU64::GetBinary(char *buf, size_t size) { if (size < GetSize()) { return false; } Init(buf, size); Write(value_); return true; } size_t PerfFileSectionU64::GetSize() { return sizeof(value_); } void PerfFileSectionU64::GetValue(uint64_t &v) const { v = value_; } PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id, const std::vector<AttrWithId> &eventDesces) : PerfFileSection(id) { eventDesces_ = eventDesces; } PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id, const char *buf, size_t size) : PerfFileSection(id) { constexpr uint32_t maxIds = 500; Init(buf, size); uint32_t nr = 0; if (!Read(nr)) { return; } uint32_t attrSize = 0; if (!Read(attrSize)) { return; } if (attrSize != sizeof(perf_event_attr)) { // only for log or debug HLOGW("perf_event_attr version is different, attrSize %d vs %zu", attrSize, sizeof(perf_event_attr)); } for (; nr > 0; nr--) { AttrWithId eventDesc; // compatible with the different version of 'perf_event_attr' if (attrSize > sizeof(perf_event_attr)) { if (!Read((char *)&(eventDesc.attr), sizeof(perf_event_attr))) { return; } // skip tail bytes HLOGW("skip %zu byte for diff attr size", attrSize - sizeof(perf_event_attr)); Skip(attrSize - sizeof(perf_event_attr)); } else if (!Read((char *)&(eventDesc.attr), attrSize)) { return; } uint32_t nrIds = 0; if (!Read(nrIds)) { return; } else if (nrIds == 0 or nrIds > maxIds) { HLOGW("nrIds is not correct ! %u", nrIds); return; } if (!Read(eventDesc.name)) { return; } eventDesc.ids.resize(nrIds, 0); if (!Read((char *)eventDesc.ids.data(), sizeof(uint64_t) * nrIds)) { return; } eventDesces_.emplace_back(std::move(eventDesc)); } HLOGV("read complete. %zu events", eventDesces_.size()); } bool PerfFileSectionEventDesc::GetBinary(char *buf, size_t size) { if (size < GetSize()) { return false; } Init(buf, size); if (!Write((uint32_t)eventDesces_.size())) { return false; } if (!Write((uint32_t)sizeof(perf_event_attr))) { return false; } for (auto &eventDesc : eventDesces_) { if (!Write((char *)&(eventDesc.attr), sizeof(perf_event_attr))) { return false; } if (!Write((uint32_t)eventDesc.ids.size())) { return false; } if (!Write(eventDesc.name)) { return false; } // clang-format off if (!Write((char *)eventDesc.ids.data(), sizeof(uint64_t) * eventDesc.ids.size())) { // clang-format on return false; } } return true; } size_t PerfFileSectionEventDesc::GetSize() { size_t size = sizeof(uint32_t); // nr size += sizeof(uint32_t); // attr_size size += (eventDesces_.size() * sizeof(perf_event_attr)); size += (eventDesces_.size() * sizeof(uint32_t)); // nr_ids for (auto &eventDesc : eventDesces_) { size += SizeOf(eventDesc.name); size += (sizeof(uint64_t) * eventDesc.ids.size()); } return size; } void PerfFileSectionEventDesc::GetValue(std::vector<AttrWithId> &eventDesces) const { eventDesces = eventDesces_; } } // namespace HiPerf } // namespace Developtools } // namespace OHOS