1/* 2 * Copyright (c) 2021-2022 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#include "perf_file_format.h" 16 17#include "debug_logger.h" 18#include "hiperf_hilog.h" 19 20namespace OHOS { 21namespace Developtools { 22namespace HiPerf { 23static const std::vector<std::string> EXT_FEATURE_NAMES = { 24 "hiperf_files_symbol", 25 "hiperf_workloader_cmd", 26 "hiperf_record_time", 27 "hiperf_cpu_off", 28 "hiperf_hm_devhost", 29 "hiperf_stack_table", 30}; 31static const std::vector<std::string> FEATURE_NAMES = { 32 "unknown_feature", "tracing_data", "build_id", "hostname", "osrelease", 33 "version", "arch", "nrcpus", "cpudesc", "cpuid", 34 "total_mem", "cmdline", "event_desc", "cpu_topology", "numa_topology", 35 "branch_stack", "pmu_mappings", "group_desc", "auxtrace", "stat", 36 "cache", "sample_time", "mem_topology", "last_feature", 37}; 38#ifdef FUZZER_TEST 39 // issue from fuzz test and also will lead to PerfFileSectionSymbolsFiles uncompletely construct 40static constexpr size_t MAX_SYMBOLS_FILE_NUMBER = 300; 41static constexpr size_t MAX_SYMBOLS_NUMBER = 10000; 42#endif 43std::string PerfFileSection::GetFeatureName(FEATURE featureId) 44{ 45 unsigned int index = static_cast<unsigned int>(featureId); 46 if (featureId >= FEATURE::HIPERF_FIRST_FEATURE) { 47 index -= static_cast<unsigned int>(FEATURE::HIPERF_FIRST_FEATURE); 48 if (index >= EXT_FEATURE_NAMES.size()) { 49 return FEATURE_NAMES[0]; 50 } 51 return EXT_FEATURE_NAMES[index]; 52 } else { 53 if (index >= FEATURE_NAMES.size()) { 54 return FEATURE_NAMES[0]; 55 } 56 return FEATURE_NAMES[index]; 57 } 58} 59 60// for read 61void PerfFileSection::Init(const char *buffer, size_t maxSize) 62{ 63 rBuffer_ = buffer; 64 maxSize_ = maxSize; 65 offset_ = 0; 66} 67 68// for write 69void PerfFileSection::Init(char *buffer, size_t maxSize) 70{ 71 wBuffer_ = buffer; 72 maxSize_ = maxSize; 73 offset_ = 0; 74} 75 76bool PerfFileSection::Write(uint32_t u32) 77{ 78 uint32_t value = u32; 79 return Write((char *)&value, sizeof(uint32_t)); 80} 81 82bool PerfFileSection::Write(uint64_t u64) 83{ 84 uint64_t value = u64; 85 return Write((char *)&value, sizeof(uint64_t)); 86} 87 88bool PerfFileSection::Write(const std::string &str) 89{ 90 if (Write((uint32_t)str.size() + 1)) { // include the ending \0 91 return Write(str.c_str(), str.size(), str.size() + 1); 92 } else { 93 return false; 94 } 95} 96 97bool PerfFileSection::Write(const char *buf, size_t size) 98{ 99 return Write(buf, size, size); 100} 101 102bool PerfFileSection::Write(const char *buf, size_t size, size_t max) 103{ 104 CHECK_TRUE(offset_ + size > maxSize_, false, 1, 105 "write out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); 106 CHECK_TRUE(offset_ + max > maxSize_, false, 1, 107 "write out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); 108 CHECK_TRUE(wBuffer_ == nullptr, false, 0, ""); 109 std::copy(buf, buf + size, wBuffer_ + offset_); 110 if (size >= max) { 111 offset_ += size; 112 } else { 113 offset_ += max; 114 } 115 return true; 116} 117 118bool PerfFileSection::Read(uint32_t &value) 119{ 120 static_assert(sizeof(uint32_t) == 4); 121 return Read((char *)&value, sizeof(uint32_t)); 122} 123 124bool PerfFileSection::Read(uint64_t &value) 125{ 126 static_assert(sizeof(uint64_t) == 8); 127 128 return Read((char *)&value, sizeof(uint64_t)); 129} 130 131bool PerfFileSection::Read(std::string &value) 132{ 133 uint32_t size = 0; 134 CHECK_TRUE(!Read(size), false, 0, ""); 135 // if size large than buf size or 0 size ? 136 // don't assert for fuzz test 137 CHECK_TRUE(size == 0 or size > maxSize_, false, 0, ""); 138 char buf[size]; 139 CHECK_TRUE(!Read(buf, size), false, 0, ""); 140 CHECK_TRUE(buf[size - 1] != 0, false, 0, ""); 141 value = buf; 142 HLOGDUMMY("Read String size %u buf : %s", size, value.c_str()); 143 return true; 144} 145void PerfFileSection::Skip(size_t size) 146{ 147 offset_ += size; 148} 149 150bool PerfFileSection::Read(char *buf, size_t size) 151{ 152 HLOG_ASSERT(buf != nullptr); 153 if (size == 0) { 154 HLOGE("read zero size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); 155 return false; 156 } else if (offset_ + size > maxSize_) { 157 HLOGE("read out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); 158 if (memset_s(buf, size, 0, size) != EOK) { // make sure the content return is 0 when failed 159 HLOGE("memset_s failed in PerfFileSection::Read"); 160 return false; 161 } 162 return false; 163 } 164 HLOGD("PerfFileSection::Read offset_ %zu size %zu maxSize_ %zu", offset_, size, maxSize_); 165 std::copy((rBuffer_ + offset_), (rBuffer_ + offset_ + size), buf); 166 offset_ += size; 167 HLOGDUMMY("after read offset_ %zx size %zu buf %x", offset_, size, buf[0]); 168 return true; 169} 170 171uint32_t PerfFileSection::SizeOf(std::string &string) 172{ 173 return sizeof(uint32_t) + string.size() + 1; /* '\0' */ 174} 175 176PerfFileSectionString::PerfFileSectionString(FEATURE id, const char *buf, size_t size) 177 : PerfFileSection(id) 178{ 179 Init(buf, size); 180 CHECK_TRUE(!Read(stdString_), NO_RETVAL, 0, ""); // or throw ... 181} 182 183PerfFileSectionString::PerfFileSectionString(FEATURE id, const std::string &charString) 184 : PerfFileSection(id) 185{ 186 stdString_ = charString; 187} 188 189bool PerfFileSectionString::GetBinary(char *buf, size_t size) 190{ 191 CHECK_TRUE(size < GetSize(), false, 0, ""); 192 193 Init(buf, size); 194 Write(stdString_); 195 return true; 196} 197 198size_t PerfFileSectionString::GetSize() 199{ 200 return SizeOf(stdString_); 201} 202 203const std::string PerfFileSectionString::ToString() const 204{ 205 return stdString_; 206} 207 208size_t PerfFileSectionSymbolsFiles::GetSize() 209{ 210 size_t size = 0; 211 212 size += sizeof(uint32_t); // how many SymbolFileStruct 213 for (auto &symbolFileStruct : symbolFileStructs_) { 214 size += SizeOf(symbolFileStruct.filePath_); 215 size += sizeof(symbolFileStruct.symbolType_); 216 size += sizeof(symbolFileStruct.textExecVaddr_); 217 size += sizeof(symbolFileStruct.textExecVaddrFileOffset_); 218 size += SizeOf(symbolFileStruct.buildId_); 219 220 size += sizeof(uint32_t); // how many SymbolStruct 221 for (auto &symbolStruct : symbolFileStruct.symbolStructs_) { 222 size += sizeof(symbolStruct.vaddr_); 223 size += sizeof(symbolStruct.len_); 224 size += SizeOf(symbolStruct.symbolName_); 225 } 226 } 227 return size; 228} 229 230void PerfFileSectionSymbolsFiles::ReadSymbolFileStructs() 231{ 232 uint32_t symbolFileNumber = 0; 233 if (!Read(symbolFileNumber)) { 234 HLOGE(" symbolFileNumber read failed"); 235 return; 236#ifdef FUZZER_TEST 237 } else if (symbolFileNumber > MAX_SYMBOLS_FILE_NUMBER) { 238 HLOGE(" symbolFileNumber %u too large", symbolFileNumber); 239 return; 240#endif 241 } else { 242 HLOGV(" symbolFileNumber %u", symbolFileNumber); 243 } 244 245 for (uint32_t i = symbolFileNumber; i > 0; i--) { 246 auto &symbolFileStruct = symbolFileStructs_.emplace_back(); 247 248 Read(symbolFileStruct.filePath_); 249 HLOGV(" symbolFileStruct.filePath_ %s", symbolFileStruct.filePath_.c_str()); 250 251 Read(symbolFileStruct.symbolType_); 252 Read(symbolFileStruct.textExecVaddr_); 253 Read(symbolFileStruct.textExecVaddrFileOffset_); 254 Read(symbolFileStruct.buildId_); 255 256 uint32_t symbolsNumber = 0; 257 if (!Read(symbolsNumber)) { 258 HLOGE(" symbols read failed"); 259 return; 260#ifdef FUZZER_TEST 261 } else if (symbolsNumber > MAX_SYMBOLS_NUMBER) { 262 HLOGE(" symbols %u too large", symbolsNumber); 263 return; 264#endif 265 } else { 266 HLOGV(" symbols %u", symbolsNumber); 267 } 268 for (; symbolsNumber > 0; symbolsNumber--) { 269 auto &symbolStruct = symbolFileStruct.symbolStructs_.emplace_back(); 270 Read(symbolStruct.vaddr_); 271 Read(symbolStruct.len_); 272 Read(symbolStruct.symbolName_); 273 } 274 HLOGV(" %zu SymbolStruct read.", symbolFileStruct.symbolStructs_.size()); 275 } 276} 277 278PerfFileSectionSymbolsFiles::PerfFileSectionSymbolsFiles(FEATURE id, const char *buf, size_t size) 279 : PerfFileSection(id) 280{ 281 Init(buf, size); 282 ReadSymbolFileStructs(); 283 HLOGV(" %zu SymbolFileStruct read.", symbolFileStructs_.size()); 284} 285 286bool PerfFileSectionSymbolsFiles::GetBinary(char *buf, size_t size) 287{ 288 HLOGV("PerfFileSectionSymbolsFiles get buffer size %zu.", size); 289 HLOG_ASSERT(size >= GetSize()); 290 291 Init(buf, size); 292 CHECK_TRUE(!Write((uint32_t)symbolFileStructs_.size()), false, 1, 293 "PerfFileSectionSymbolsFiles write failed with %zu.", symbolFileStructs_.size()); 294 for (auto &symbolFileStruct : symbolFileStructs_) { 295 Write(symbolFileStruct.filePath_); 296 Write(symbolFileStruct.symbolType_); 297 Write(symbolFileStruct.textExecVaddr_); 298 Write(symbolFileStruct.textExecVaddrFileOffset_); 299 Write(symbolFileStruct.buildId_); 300 301 Write((uint32_t)symbolFileStruct.symbolStructs_.size()); 302 for (auto &symbolStruct : symbolFileStruct.symbolStructs_) { 303 Write(symbolStruct.vaddr_); 304 Write(symbolStruct.len_); 305 Write(symbolStruct.symbolName_); 306 } 307 HLOGV(" %zu SymbolStruct writed. for %s at 0x%016" PRIx64 "@0x%08" PRIx64 ": %s", 308 symbolFileStruct.symbolStructs_.size(), symbolFileStruct.filePath_.c_str(), 309 symbolFileStruct.textExecVaddr_, symbolFileStruct.textExecVaddrFileOffset_, 310 symbolFileStruct.buildId_.c_str()); 311 } 312 HLOGV("%zu SymbolFileStruct writed.", symbolFileStructs_.size()); 313 314 return true; 315} 316 317PerfFileSectionUniStackTable::PerfFileSectionUniStackTable(FEATURE id, const char *buf, size_t size) 318 : PerfFileSection(id) 319{ 320 uint32_t processTableCount; 321 Init(buf, size); 322 if (!Read(processTableCount)) { 323 HLOGV("processTableCount read failed\n"); 324 return; 325 } else { 326 HLOGV("processTableCount %" PRIu32 "\n", processTableCount); 327 } 328 for (uint32_t i = 0; i < processTableCount; ++i) { 329 UniStackTableInfo& stackTable = uniStackTableInfos_.emplace_back(); 330 Read(stackTable.pid); 331 HLOGV("pid %" PRIu32 " ", stackTable.pid); 332 Read(stackTable.tableSize); 333 HLOGV("tableSize %" PRIu32 " ", stackTable.tableSize); 334 Read(stackTable.numNodes); 335 HLOGV("numNodes %" PRIu32 " ", stackTable.numNodes); 336 for (size_t j = 0; j < stackTable.numNodes; j++) { 337 UniStackNode& node = stackTable.nodes.emplace_back(); 338 Read(node.index); 339 Read(node.node.value); 340 } 341 } 342} 343 344bool PerfFileSectionUniStackTable::GetBinary(char *buf, size_t size) 345{ 346 HLOG_ASSERT(size >= GetSize()); 347 Init(buf, size); 348 Write(uint32_t(processStackTable_->size())); 349 for (auto it = processStackTable_->begin(); it != processStackTable_->end(); ++it) { 350 const auto &table = it->second; 351 if (table == nullptr) { 352 continue; 353 } 354 Write(table->GetPid()); 355 Write(table->GetTabelSize()); 356 const auto &idxs = table->GetUsedIndexes(); 357 Write(uint32_t(idxs.size())); 358 Node *head = table->GetHeadNode(); 359 Node *node = nullptr; 360 for (const auto idx : idxs) { 361 node = head + idx; 362 if (node == nullptr) { 363 continue; 364 } 365 Write(idx); 366 Write(node->value); 367 } 368 } 369 return true; 370} 371 372size_t PerfFileSectionUniStackTable::GetSize() 373{ 374 CHECK_TRUE(processStackTable_ == nullptr, 0, 0, ""); 375 size_t size = 0; 376 // section header info size 377 size += sizeof(uint32_t); // how many tables/process 378 for (auto it = processStackTable_->begin(); it != processStackTable_->end(); ++it) { 379 size += it->second->GetWriteSize(); 380 } 381 return size; 382} 383 384PerfFileSectionNrCpus::PerfFileSectionNrCpus(FEATURE id, const char *buf, size_t size) 385 : PerfFileSection(id) 386{ 387 Init(buf, size); 388 CHECK_TRUE(!Read(nrCpusAvailable_) || !Read(nrCpusOnline_), NO_RETVAL, 0, ""); 389} 390 391PerfFileSectionNrCpus::PerfFileSectionNrCpus(FEATURE id, uint32_t nrCpusAvailable, 392 uint32_t nrCpusOnline) 393 : PerfFileSection(id), nrCpusAvailable_(nrCpusAvailable), nrCpusOnline_(nrCpusOnline) 394{ 395} 396 397bool PerfFileSectionNrCpus::GetBinary(char *buf, size_t size) 398{ 399 CHECK_TRUE(size < GetSize(), false, 0, ""); 400 401 Init(buf, size); 402 Write(nrCpusAvailable_); 403 Write(nrCpusOnline_); 404 return true; 405} 406 407size_t PerfFileSectionNrCpus::GetSize() 408{ 409 return (sizeof(nrCpusAvailable_) + sizeof(nrCpusOnline_)); 410} 411 412void PerfFileSectionNrCpus::GetValue(uint32_t &nrCpusAvailable, uint32_t &nrCpusOnline) const 413{ 414 nrCpusAvailable = nrCpusAvailable_; 415 nrCpusOnline = nrCpusOnline_; 416} 417 418PerfFileSectionU64::PerfFileSectionU64(FEATURE id, const char *buf, size_t size) 419 : PerfFileSection(id) 420{ 421 Init(buf, size); 422 CHECK_TRUE(!Read(value_), NO_RETVAL, 0, ""); 423} 424 425PerfFileSectionU64::PerfFileSectionU64(FEATURE id, uint64_t v) : PerfFileSection(id) 426{ 427 value_ = v; 428} 429 430bool PerfFileSectionU64::GetBinary(char *buf, size_t size) 431{ 432 CHECK_TRUE(size < GetSize(), false, 0, ""); 433 434 Init(buf, size); 435 Write(value_); 436 return true; 437} 438 439size_t PerfFileSectionU64::GetSize() 440{ 441 return sizeof(value_); 442} 443 444void PerfFileSectionU64::GetValue(uint64_t &v) const 445{ 446 v = value_; 447} 448 449PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id, 450 const std::vector<AttrWithId> &eventDesces) 451 : PerfFileSection(id) 452{ 453 eventDesces_ = eventDesces; 454} 455 456PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id, const char *buf, size_t size) 457 : PerfFileSection(id) 458{ 459 constexpr uint32_t maxIds = 600; 460 Init(buf, size); 461 uint32_t nr = 0; 462 CHECK_TRUE(!Read(nr), NO_RETVAL, 0, ""); 463 uint32_t attrSize = 0; 464 CHECK_TRUE(!Read(attrSize), NO_RETVAL, 0, ""); 465 if (attrSize != sizeof(perf_event_attr)) { // only for log or debug 466 HLOGW("perf_event_attr version is different, attrSize %d vs %zu", attrSize, 467 sizeof(perf_event_attr)); 468 } 469 470 for (; nr > 0; nr--) { 471 AttrWithId eventDesc; 472 // compatible with the different version of 'perf_event_attr' 473 if (attrSize > sizeof(perf_event_attr)) { 474 if (!Read(reinterpret_cast<char*>(&(eventDesc.attr)), sizeof(perf_event_attr))) { 475 return; 476 } 477 // skip tail bytes 478 HLOGW("skip %zu byte for diff attr size", attrSize - sizeof(perf_event_attr)); 479 Skip(attrSize - sizeof(perf_event_attr)); 480 } else if (!Read(reinterpret_cast<char*>(&(eventDesc.attr)), attrSize)) { 481 return; 482 } 483 484 uint32_t nrIds = 0; 485 if (!Read(nrIds)) { 486 return; 487 } else if (nrIds == 0) { 488 HLOGW("nrIds is not correct ! %u", nrIds); 489 return; 490 } else if (nrIds > maxIds) { 491 HLOGW("nrIds is too large ! %u", nrIds); 492 } 493 CHECK_TRUE(!Read(eventDesc.name), NO_RETVAL, 0, ""); 494 eventDesc.ids.resize(nrIds, 0); 495 CHECK_TRUE(!Read(reinterpret_cast<char*>(eventDesc.ids.data()), sizeof(uint64_t) * nrIds), NO_RETVAL, 0, ""); 496 eventDesces_.emplace_back(std::move(eventDesc)); 497 } 498 HLOGV("read complete. %zu events", eventDesces_.size()); 499} 500 501bool PerfFileSectionEventDesc::GetBinary(char *buf, size_t size) 502{ 503 CHECK_TRUE(size < GetSize(), false, 0, ""); 504 Init(buf, size); 505 506 CHECK_TRUE(!Write(static_cast<uint32_t>(eventDesces_.size())), false, 0, ""); 507 CHECK_TRUE(!Write(static_cast<uint32_t>(sizeof(perf_event_attr))), false, 0, ""); 508 for (auto &eventDesc : eventDesces_) { 509 CHECK_TRUE(!Write(reinterpret_cast<char*>(&(eventDesc.attr)), sizeof(perf_event_attr)), false, 0, ""); 510 CHECK_TRUE(!Write(static_cast<uint32_t>(eventDesc.ids.size())), false, 0, ""); 511 CHECK_TRUE(!Write(eventDesc.name), false, 0, ""); 512 // clang-format off 513 CHECK_TRUE(!Write(reinterpret_cast<char*>(eventDesc.ids.data()), sizeof(uint64_t) * eventDesc.ids.size()), 514 false, 0, ""); // clang-format on 515 } 516 return true; 517} 518 519size_t PerfFileSectionEventDesc::GetSize() 520{ 521 size_t size = sizeof(uint32_t); // nr 522 size += sizeof(uint32_t); // attr_size 523 524 size += (eventDesces_.size() * sizeof(perf_event_attr)); 525 size += (eventDesces_.size() * sizeof(uint32_t)); // nr_ids 526 for (auto &eventDesc : eventDesces_) { 527 size += SizeOf(eventDesc.name); 528 size += (sizeof(uint64_t) * eventDesc.ids.size()); 529 } 530 return size; 531} 532 533void PerfFileSectionEventDesc::GetValue(std::vector<AttrWithId> &eventDesces) const 534{ 535 eventDesces = eventDesces_; 536} 537} // namespace HiPerf 538} // namespace Developtools 539} // namespace OHOS 540