• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,const size_t maxSize)62 void PerfFileSection::Init(const char *buffer, const size_t maxSize)
63 {
64     rBuffer_ = buffer;
65     maxSize_ = maxSize;
66     offset_ = 0;
67 }
68 
69 // for write
Init(char * buffer,const size_t maxSize)70 void PerfFileSection::Init(char *buffer, const size_t maxSize)
71 {
72     wBuffer_ = buffer;
73     maxSize_ = maxSize;
74     offset_ = 0;
75 }
76 
Write(const uint32_t u32)77 bool PerfFileSection::Write(const uint32_t u32)
78 {
79     uint32_t value = u32;
80     return Write((char *)&value, sizeof(uint32_t));
81 }
82 
Write(const uint64_t u64)83 bool PerfFileSection::Write(const 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,const size_t size)98 bool PerfFileSection::Write(const char *buf, const size_t size)
99 {
100     return Write(buf, size, size);
101 }
102 
Write(const char * buf,const size_t size,const size_t max)103 bool PerfFileSection::Write(const char *buf, const size_t size, const 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(const size_t size)159 void PerfFileSection::Skip(const size_t size)
160 {
161     offset_ += size;
162 }
163 
Read(char * buf,const size_t size)164 bool PerfFileSection::Read(char *buf, const 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(const std::string & string)185 uint32_t PerfFileSection::SizeOf(const std::string &string)
186 {
187     return sizeof(uint32_t) + string.size() + 1; /* '\0' */
188 }
189 
PerfFileSectionString(const FEATURE id,const char * buf,size_t size)190 PerfFileSectionString::PerfFileSectionString(const 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(const FEATURE id,const std::string & charString)197 PerfFileSectionString::PerfFileSectionString(const FEATURE id, const std::string &charString)
198     : PerfFileSection(id)
199 {
200     stdString_ = charString;
201 }
202 
GetBinary(char * buf,const size_t size)203 bool PerfFileSectionString::GetBinary(char *buf, const 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(const FEATURE id,const char * buf,const size_t size)292 PerfFileSectionSymbolsFiles::PerfFileSectionSymbolsFiles(const FEATURE id, const char *buf, const 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,const size_t size)300 bool PerfFileSectionSymbolsFiles::GetBinary(char *buf, const 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(const FEATURE id,const char * buf,const size_t size)331 PerfFileSectionUniStackTable::PerfFileSectionUniStackTable(const FEATURE id, const char *buf, const 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     }
340     HLOGV("processTableCount %" PRIu32 "\n", processTableCount);
341     for (uint32_t i = 0; i < processTableCount; ++i) {
342         UniStackTableInfo& stackTable = uniStackTableInfos_.emplace_back();
343         Read(stackTable.pid);
344         HLOGV("pid %" PRIu32 " ", stackTable.pid);
345         Read(stackTable.tableSize);
346         HLOGV("tableSize %" PRIu32 " ", stackTable.tableSize);
347         Read(stackTable.numNodes);
348         HLOGV("numNodes %" PRIu32 " ", stackTable.numNodes);
349         for (size_t j = 0; j < stackTable.numNodes; j++) {
350             UniStackNode& node = stackTable.nodes.emplace_back();
351             Read(node.index);
352             Read(node.node.value);
353         }
354     }
355 }
356 
GetBinary(char * buf,const size_t size)357 bool PerfFileSectionUniStackTable::GetBinary(char *buf, const size_t size)
358 {
359     HLOG_ASSERT(size >= GetSize());
360     Init(buf, size);
361     Write(uint32_t(processStackTable_->size()));
362     for (auto it = processStackTable_->begin(); it != processStackTable_->end(); ++it) {
363         const auto &table = it->second;
364         if (table == nullptr) {
365             continue;
366         }
367         Write(table->GetPid());
368         Write(table->GetTabelSize());
369         const auto &idxs = table->GetUsedIndexes();
370         Write(uint32_t(idxs.size()));
371         Node *head = table->GetHeadNode();
372         Node *node = nullptr;
373         for (const auto idx : idxs) {
374             node = head + idx;
375             if (node == nullptr) {
376                 continue;
377             }
378             Write(idx);
379             Write(node->value);
380         }
381     }
382     return true;
383 }
384 
GetSize()385 size_t PerfFileSectionUniStackTable::GetSize()
386 {
387     CHECK_TRUE(processStackTable_ != nullptr, 0, 1, "processStackTable_ is nullptr");
388     size_t size = 0;
389     // section header info size
390     size += sizeof(uint32_t); // how many tables/process
391     for (auto it = processStackTable_->begin(); it != processStackTable_->end(); ++it) {
392         size += it->second->GetWriteSize();
393     }
394     return size;
395 }
396 
PerfFileSectionNrCpus(const FEATURE id,const char * buf,const size_t size)397 PerfFileSectionNrCpus::PerfFileSectionNrCpus(const FEATURE id, const char *buf, const size_t size)
398     : PerfFileSection(id)
399 {
400     Init(buf, size);
401     CHECK_TRUE(Read(nrCpusAvailable_) && Read(nrCpusOnline_), NO_RETVAL, 0, "");
402 }
403 
PerfFileSectionNrCpus(const FEATURE id,const uint32_t nrCpusAvailable,const uint32_t nrCpusOnline)404 PerfFileSectionNrCpus::PerfFileSectionNrCpus(const FEATURE id, const uint32_t nrCpusAvailable,
405                                              const uint32_t nrCpusOnline)
406     : PerfFileSection(id), nrCpusAvailable_(nrCpusAvailable), nrCpusOnline_(nrCpusOnline)
407 {
408 }
409 
GetBinary(char * buf,const size_t size)410 bool PerfFileSectionNrCpus::GetBinary(char *buf, const size_t size)
411 {
412     CHECK_TRUE(size >= GetSize(), false, 0, "");
413 
414     Init(buf, size);
415     Write(nrCpusAvailable_);
416     Write(nrCpusOnline_);
417     return true;
418 }
419 
GetSize()420 size_t PerfFileSectionNrCpus::GetSize()
421 {
422     return (sizeof(nrCpusAvailable_) + sizeof(nrCpusOnline_));
423 }
424 
GetValue(uint32_t & nrCpusAvailable,uint32_t & nrCpusOnline) const425 void PerfFileSectionNrCpus::GetValue(uint32_t &nrCpusAvailable, uint32_t &nrCpusOnline) const
426 {
427     nrCpusAvailable = nrCpusAvailable_;
428     nrCpusOnline = nrCpusOnline_;
429 }
430 
PerfFileSectionU64(FEATURE id,const char * buf,const size_t size)431 PerfFileSectionU64::PerfFileSectionU64(FEATURE id, const char *buf, const size_t size)
432     : PerfFileSection(id)
433 {
434     Init(buf, size);
435     CHECK_TRUE(Read(value_), NO_RETVAL, 0, "");
436 }
437 
PerfFileSectionU64(const FEATURE id,const uint64_t v)438 PerfFileSectionU64::PerfFileSectionU64(const FEATURE id, const uint64_t v) : PerfFileSection(id)
439 {
440     value_ = v;
441 }
442 
GetBinary(char * buf,size_t size)443 bool PerfFileSectionU64::GetBinary(char *buf, size_t size)
444 {
445     CHECK_TRUE(size >= GetSize(), false, 0, "");
446 
447     Init(buf, size);
448     Write(value_);
449     return true;
450 }
451 
GetSize()452 size_t PerfFileSectionU64::GetSize()
453 {
454     return sizeof(value_);
455 }
456 
GetValue(uint64_t & v) const457 void PerfFileSectionU64::GetValue(uint64_t &v) const
458 {
459     v = value_;
460 }
461 
PerfFileSectionEventDesc(FEATURE id,const std::vector<AttrWithId> & eventDesces)462 PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id,
463                                                    const std::vector<AttrWithId> &eventDesces)
464     : PerfFileSection(id)
465 {
466     eventDesces_ = eventDesces;
467 }
468 
PerfFileSectionEventDesc(const FEATURE id,const char * buf,const size_t size)469 PerfFileSectionEventDesc::PerfFileSectionEventDesc(const FEATURE id, const char *buf, const size_t size)
470     : PerfFileSection(id)
471 {
472     constexpr uint32_t maxIds = 600;
473     Init(buf, size);
474     uint32_t nr = 0;
475     CHECK_TRUE(Read(nr), NO_RETVAL, 0, "");
476     uint32_t attrSize = 0;
477     CHECK_TRUE(Read(attrSize), NO_RETVAL, 0, "");
478     if (attrSize != sizeof(perf_event_attr)) { // only for log or debug
479         HLOGW("perf_event_attr version is different, attrSize %d vs %zu", attrSize,
480               sizeof(perf_event_attr));
481     }
482 
483     for (; nr > 0; nr--) {
484         AttrWithId eventDesc;
485         // compatible with the different version of 'perf_event_attr'
486         if (attrSize > sizeof(perf_event_attr)) {
487             if (!Read(reinterpret_cast<char*>(&(eventDesc.attr)), sizeof(perf_event_attr))) {
488                 return;
489             }
490             // skip tail bytes
491             HLOGW("skip %zu byte for diff attr size", attrSize - sizeof(perf_event_attr));
492             Skip(attrSize - sizeof(perf_event_attr));
493         } else if (!Read(reinterpret_cast<char*>(&(eventDesc.attr)), attrSize)) {
494             return;
495         }
496 
497         uint32_t nrIds = 0;
498         if (!Read(nrIds)) {
499             return;
500         } else if (nrIds == 0) {
501             HLOGW("nrIds is not correct ! %u", nrIds);
502             return;
503         } else if (nrIds > maxIds) {
504             HLOGW("nrIds is too large ! %u", nrIds);
505         }
506         CHECK_TRUE(Read(eventDesc.name), NO_RETVAL, 0, "");
507         HIPERF_ASSERT(nrIds <= MAX_VECTOR_RESIZE_COUNT, "nrIds exceeds 100000\n");
508         eventDesc.ids.resize(nrIds, 0);
509         CHECK_TRUE(Read(reinterpret_cast<char*>(eventDesc.ids.data()), sizeof(uint64_t) * nrIds), NO_RETVAL, 0, "");
510         eventDesces_.emplace_back(std::move(eventDesc));
511     }
512     HLOGV("read complete. %zu events", eventDesces_.size());
513 }
514 
GetBinary(char * buf,const size_t size)515 bool PerfFileSectionEventDesc::GetBinary(char *buf, const size_t size)
516 {
517     CHECK_TRUE(size >= GetSize(), false, 0, "");
518     Init(buf, size);
519 
520     CHECK_TRUE(Write(static_cast<uint32_t>(eventDesces_.size())), false, 0, "");
521     CHECK_TRUE(Write(static_cast<uint32_t>(sizeof(perf_event_attr))), false, 0, "");
522     for (auto &eventDesc : eventDesces_) {
523         CHECK_TRUE(Write(reinterpret_cast<char*>(&(eventDesc.attr)), sizeof(perf_event_attr)), false, 0, "");
524         CHECK_TRUE(Write(static_cast<uint32_t>(eventDesc.ids.size())), false, 0, "");
525         CHECK_TRUE(Write(eventDesc.name), false, 0, "");
526         // clang-format off
527         CHECK_TRUE(Write(reinterpret_cast<char*>(eventDesc.ids.data()), sizeof(uint64_t) * eventDesc.ids.size()),
528                    false, 0, ""); // clang-format on
529     }
530     return true;
531 }
532 
GetSize()533 size_t PerfFileSectionEventDesc::GetSize()
534 {
535     size_t size = sizeof(uint32_t); // nr
536     size += sizeof(uint32_t);       // attr_size
537 
538     size += (eventDesces_.size() * sizeof(perf_event_attr));
539     size += (eventDesces_.size() * sizeof(uint32_t)); // nr_ids
540     for (auto &eventDesc : eventDesces_) {
541         size += SizeOf(eventDesc.name);
542         size += (sizeof(uint64_t) * eventDesc.ids.size());
543     }
544     return size;
545 }
546 
GetValue(std::vector<AttrWithId> & eventDesces) const547 void PerfFileSectionEventDesc::GetValue(std::vector<AttrWithId> &eventDesces) const
548 {
549     eventDesces = eventDesces_;
550 }
551 } // namespace HiPerf
552 } // namespace Developtools
553 } // namespace OHOS
554