1 /*
2 * Copyright (c) 2021 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
PerfFileSectionSymbolsFiles(FEATURE id,const char * buf,size_t size)224 PerfFileSectionSymbolsFiles::PerfFileSectionSymbolsFiles(FEATURE id, const char *buf, size_t size)
225 : PerfFileSection(id)
226 {
227 Init(buf, size);
228 uint32_t symbolFileNumber = 0;
229 if (!Read(symbolFileNumber)) {
230 HLOGE(" symbolFileNumber read failed");
231 return;
232 } else if (symbolFileNumber > MAX_SYMBOLS_FILE_NUMBER) {
233 HLOGE(" symbolFileNumber %u too large", symbolFileNumber);
234 return;
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 } else if (symbolsNumber > MAX_SYMBOLS_NUMBER) {
255 HLOGE(" symbols %u too large", symbolsNumber);
256 return;
257 } else {
258 HLOGV(" symbols %u", symbolsNumber);
259 }
260 for (; symbolsNumber > 0; symbolsNumber--) {
261 auto &symbolStruct = symbolFileStruct.symbolStructs_.emplace_back();
262 Read(symbolStruct.vaddr_);
263 Read(symbolStruct.len_);
264 Read(symbolStruct.symbolName_);
265 }
266 HLOGV(" %zu SymbolStruct read.", symbolFileStruct.symbolStructs_.size());
267 }
268 HLOGV(" %zu SymbolFileStruct read.", symbolFileStructs_.size());
269 }
270
GetBinary(char * buf,size_t size)271 bool PerfFileSectionSymbolsFiles::GetBinary(char *buf, size_t size)
272 {
273 HLOGV("PerfFileSectionSymbolsFiles get buffer size %zu.", size);
274 HLOG_ASSERT(size >= GetSize());
275
276 Init(buf, size);
277 if (!Write((uint32_t)symbolFileStructs_.size())) {
278 HLOGE("PerfFileSectionSymbolsFiles write failed with %zu.", symbolFileStructs_.size());
279 return false;
280 }
281 for (auto &symbolFileStruct : symbolFileStructs_) {
282 Write(symbolFileStruct.filePath_);
283 Write(symbolFileStruct.symbolType_);
284 Write(symbolFileStruct.textExecVaddr_);
285 Write(symbolFileStruct.textExecVaddrFileOffset_);
286 Write(symbolFileStruct.buildId_);
287
288 Write((uint32_t)symbolFileStruct.symbolStructs_.size());
289 for (auto &symbolStruct : symbolFileStruct.symbolStructs_) {
290 Write(symbolStruct.vaddr_);
291 Write(symbolStruct.len_);
292 Write(symbolStruct.symbolName_);
293 }
294 HLOGV(" %zu SymbolStruct writed. for %s at 0x%016" PRIx64 "@0x%08" PRIx64 ": %s",
295 symbolFileStruct.symbolStructs_.size(), symbolFileStruct.filePath_.c_str(),
296 symbolFileStruct.textExecVaddr_, symbolFileStruct.textExecVaddrFileOffset_,
297 symbolFileStruct.buildId_.c_str());
298 }
299 HLOGV("%zu SymbolFileStruct writed.", symbolFileStructs_.size());
300
301 return true;
302 }
303
PerfFileSectionNrCpus(FEATURE id,const char * buf,size_t size)304 PerfFileSectionNrCpus::PerfFileSectionNrCpus(FEATURE id, const char *buf, size_t size)
305 : PerfFileSection(id)
306 {
307 Init(buf, size);
308 if (!Read(nrCpusAvailable_) || !Read(nrCpusOnline_)) {
309 return;
310 }
311 }
312
PerfFileSectionNrCpus(FEATURE id,uint32_t nrCpusAvailable,uint32_t nrCpusOnline)313 PerfFileSectionNrCpus::PerfFileSectionNrCpus(FEATURE id, uint32_t nrCpusAvailable,
314 uint32_t nrCpusOnline)
315 : PerfFileSection(id), nrCpusAvailable_(nrCpusAvailable), nrCpusOnline_(nrCpusOnline)
316 {
317 }
318
GetBinary(char * buf,size_t size)319 bool PerfFileSectionNrCpus::GetBinary(char *buf, size_t size)
320 {
321 if (size < GetSize()) {
322 return false;
323 }
324
325 Init(buf, size);
326 Write(nrCpusAvailable_);
327 Write(nrCpusOnline_);
328 return true;
329 }
330
GetSize()331 size_t PerfFileSectionNrCpus::GetSize()
332 {
333 return (sizeof(nrCpusAvailable_) + sizeof(nrCpusOnline_));
334 }
335
GetValue(uint32_t & nrCpusAvailable,uint32_t & nrCpusOnline) const336 void PerfFileSectionNrCpus::GetValue(uint32_t &nrCpusAvailable, uint32_t &nrCpusOnline) const
337 {
338 nrCpusAvailable = nrCpusAvailable_;
339 nrCpusOnline = nrCpusOnline_;
340 }
341
PerfFileSectionU64(FEATURE id,const char * buf,size_t size)342 PerfFileSectionU64::PerfFileSectionU64(FEATURE id, const char *buf, size_t size)
343 : PerfFileSection(id)
344 {
345 Init(buf, size);
346 if (!Read(value_)) {
347 return;
348 }
349 }
350
PerfFileSectionU64(FEATURE id,uint64_t v)351 PerfFileSectionU64::PerfFileSectionU64(FEATURE id, uint64_t v) : PerfFileSection(id)
352 {
353 value_ = v;
354 }
355
GetBinary(char * buf,size_t size)356 bool PerfFileSectionU64::GetBinary(char *buf, size_t size)
357 {
358 if (size < GetSize()) {
359 return false;
360 }
361
362 Init(buf, size);
363 Write(value_);
364 return true;
365 }
366
GetSize()367 size_t PerfFileSectionU64::GetSize()
368 {
369 return sizeof(value_);
370 }
371
GetValue(uint64_t & v) const372 void PerfFileSectionU64::GetValue(uint64_t &v) const
373 {
374 v = value_;
375 }
376
PerfFileSectionEventDesc(FEATURE id,const std::vector<AttrWithId> & eventDesces)377 PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id,
378 const std::vector<AttrWithId> &eventDesces)
379 : PerfFileSection(id)
380 {
381 eventDesces_ = eventDesces;
382 }
383
PerfFileSectionEventDesc(FEATURE id,const char * buf,size_t size)384 PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id, const char *buf, size_t size)
385 : PerfFileSection(id)
386 {
387 constexpr uint32_t maxIds = 500;
388 Init(buf, size);
389 uint32_t nr = 0;
390 if (!Read(nr)) {
391 return;
392 }
393 uint32_t attrSize = 0;
394 if (!Read(attrSize)) {
395 return;
396 }
397 if (attrSize != sizeof(perf_event_attr)) { // only for log or debug
398 HLOGW("perf_event_attr version is different, attrSize %d vs %zu", attrSize,
399 sizeof(perf_event_attr));
400 }
401
402 for (; nr > 0; nr--) {
403 AttrWithId eventDesc;
404 // compatible with the different version of 'perf_event_attr'
405 if (attrSize > sizeof(perf_event_attr)) {
406 if (!Read((char *)&(eventDesc.attr), sizeof(perf_event_attr))) {
407 return;
408 }
409 // skip tail bytes
410 HLOGW("skip %zu byte for diff attr size", attrSize - sizeof(perf_event_attr));
411 Skip(attrSize - sizeof(perf_event_attr));
412 } else if (!Read((char *)&(eventDesc.attr), attrSize)) {
413 return;
414 }
415
416 uint32_t nrIds = 0;
417 if (!Read(nrIds)) {
418 return;
419 } else if (nrIds == 0 or nrIds > maxIds) {
420 HLOGW("nrIds is not correct ! %u", nrIds);
421 return;
422 }
423 if (!Read(eventDesc.name)) {
424 return;
425 }
426 eventDesc.ids.resize(nrIds, 0);
427 if (!Read((char *)eventDesc.ids.data(), sizeof(uint64_t) * nrIds)) {
428 return;
429 }
430 eventDesces_.emplace_back(std::move(eventDesc));
431 }
432 HLOGV("read complete. %zu events", eventDesces_.size());
433 }
434
GetBinary(char * buf,size_t size)435 bool PerfFileSectionEventDesc::GetBinary(char *buf, size_t size)
436 {
437 if (size < GetSize()) {
438 return false;
439 }
440 Init(buf, size);
441
442 if (!Write((uint32_t)eventDesces_.size())) {
443 return false;
444 }
445 if (!Write((uint32_t)sizeof(perf_event_attr))) {
446 return false;
447 }
448 for (auto &eventDesc : eventDesces_) {
449 if (!Write((char *)&(eventDesc.attr), sizeof(perf_event_attr))) {
450 return false;
451 }
452 if (!Write((uint32_t)eventDesc.ids.size())) {
453 return false;
454 }
455 if (!Write(eventDesc.name)) {
456 return false;
457 }
458 // clang-format off
459 if (!Write((char *)eventDesc.ids.data(),
460 sizeof(uint64_t) * eventDesc.ids.size())) {
461 // clang-format on
462 return false;
463 }
464 }
465 return true;
466 }
467
GetSize()468 size_t PerfFileSectionEventDesc::GetSize()
469 {
470 size_t size = sizeof(uint32_t); // nr
471 size += sizeof(uint32_t); // attr_size
472
473 size += (eventDesces_.size() * sizeof(perf_event_attr));
474 size += (eventDesces_.size() * sizeof(uint32_t)); // nr_ids
475 for (auto &eventDesc : eventDesces_) {
476 size += SizeOf(eventDesc.name);
477 size += (sizeof(uint64_t) * eventDesc.ids.size());
478 }
479 return size;
480 }
481
GetValue(std::vector<AttrWithId> & eventDesces) const482 void PerfFileSectionEventDesc::GetValue(std::vector<AttrWithId> &eventDesces) const
483 {
484 eventDesces = eventDesces_;
485 }
486 } // namespace HiPerf
487 } // namespace Developtools
488 } // namespace OHOS