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