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