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 #define HILOG_TAG "PerfRecord"
16 
17 #include "perf_event_record.h"
18 #include "spe_decoder.h"
19 #include <cinttypes>
20 
21 #include "utilities.h"
22 
23 using namespace OHOS::HiviewDFX;
24 using namespace std;
25 namespace OHOS {
26 namespace Developtools {
27 namespace HiPerf {
28 
29 void *g_sampleMemCache = nullptr; // for read record from buf thread
30 void *g_sampleMemCacheMain = nullptr; // for main thread:collecttionsymbol
31 constexpr size_t SAMPLE_CACHE_SIZE = 4 * 1024;
32 
GetPerfEventRecord(const int type, uint8_t *p, const perf_event_attr &attr)33 std::unique_ptr<PerfEventRecord> GetPerfEventRecord(const int type, uint8_t *p,
34                                                     const perf_event_attr &attr)
35 {
36     HLOG_ASSERT(p);
37     uint8_t *data = p;
38 
39     // check kernel
40     switch (type) {
41         case PERF_RECORD_SAMPLE:
42             return std::make_unique<PerfRecordSample>(data, attr);
43         case PERF_RECORD_MMAP:
44             return std::make_unique<PerfRecordMmap>(data);
45         case PERF_RECORD_MMAP2:
46             return std::make_unique<PerfRecordMmap2>(data);
47         case PERF_RECORD_LOST:
48             return std::make_unique<PerfRecordLost>(data);
49         case PERF_RECORD_COMM:
50             return std::make_unique<PerfRecordComm>(data);
51         case PERF_RECORD_EXIT:
52             return std::make_unique<PerfRecordExit>(data);
53         case PERF_RECORD_THROTTLE:
54             return std::make_unique<PerfRecordThrottle>(data);
55         case PERF_RECORD_UNTHROTTLE:
56             return std::make_unique<PerfRecordUnthrottle>(data);
57         case PERF_RECORD_FORK:
58             return std::make_unique<PerfRecordFork>(data);
59         case PERF_RECORD_READ:
60             return std::make_unique<PerfRecordRead>(data);
61         case PERF_RECORD_AUX:
62             return std::make_unique<PerfRecordAux>(data);
63         case PERF_RECORD_AUXTRACE:
64             return std::make_unique<PerfRecordAuxtrace>(data);
65         case PERF_RECORD_ITRACE_START:
66             return std::make_unique<PerfRecordItraceStart>(data);
67         case PERF_RECORD_LOST_SAMPLES:
68             return std::make_unique<PerfRecordLostSamples>(data);
69         case PERF_RECORD_SWITCH:
70             return std::make_unique<PerfRecordSwitch>(data);
71         case PERF_RECORD_SWITCH_CPU_WIDE:
72             return std::make_unique<PerfRecordSwitchCpuWide>(data);
73         default:
74             HLOGE("unknown record type %d\n", type);
75             return nullptr;
76     }
77 }
78 
GetPerfSampleFromCache(const int type, uint8_t *p, const perf_event_attr &attr)79 std::unique_ptr<PerfEventRecord> GetPerfSampleFromCache(const int type, uint8_t *p,
80                                                         const perf_event_attr &attr)
81 {
82     HLOG_ASSERT(p);
83     uint8_t *data = p;
84 
85     if (type == PERF_RECORD_SAMPLE) {
86         if (g_sampleMemCache != nullptr) {
87             memset_s(g_sampleMemCache, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE);
88             return std::unique_ptr<PerfEventRecord>(new (g_sampleMemCache) PerfRecordSample(data, attr));
89         } else {
90             g_sampleMemCache = std::malloc(SAMPLE_CACHE_SIZE);
91             memset_s(g_sampleMemCache, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE);
92             return std::unique_ptr<PerfEventRecord>(new (g_sampleMemCache) PerfRecordSample(data, attr));
93         }
94     }
95     return GetPerfEventRecord(type, p, attr);
96 }
97 
GetPerfSampleFromCacheMain(const int type, uint8_t *p, const perf_event_attr &attr)98 std::unique_ptr<PerfEventRecord> GetPerfSampleFromCacheMain(const int type, uint8_t *p,
99                                                             const perf_event_attr &attr)
100 {
101     HLOG_ASSERT(p);
102     uint8_t *data = p;
103 
104     if (type == PERF_RECORD_SAMPLE) {
105         if (g_sampleMemCacheMain != nullptr) {
106             memset_s(g_sampleMemCacheMain, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE);
107             return std::unique_ptr<PerfEventRecord>(new (g_sampleMemCacheMain) PerfRecordSample(data, attr));
108         } else {
109             g_sampleMemCacheMain = std::malloc(SAMPLE_CACHE_SIZE);
110             memset_s(g_sampleMemCacheMain, SAMPLE_CACHE_SIZE, 0, SAMPLE_CACHE_SIZE);
111             return std::unique_ptr<PerfEventRecord>(new (g_sampleMemCacheMain) PerfRecordSample(data, attr));
112         }
113     }
114     return GetPerfEventRecord(type, p, attr);
115 }
116 
117 template<typename T>
PushToBinary(bool condition, uint8_t *&p, const T &v)118 inline void PushToBinary(bool condition, uint8_t *&p, const T &v)
119 {
120     if (condition) {
121         *(reinterpret_cast<T *>(p)) = v;
122         p += sizeof(T);
123     }
124 }
125 
126 template<typename T1, typename T2>
PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2)127 inline void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2)
128 {
129     if (condition) {
130         *(reinterpret_cast<T1 *>(p)) = v1;
131         p += sizeof(T1);
132         *(reinterpret_cast<T2 *>(p)) = v2;
133         p += sizeof(T2);
134     }
135 }
136 
137 template<typename T>
PopFromBinary(bool condition, uint8_t *&p, T &v)138 inline void PopFromBinary(bool condition, uint8_t *&p, T &v)
139 {
140     if (condition) {
141         v = *(reinterpret_cast<const T *>(p));
142         p += sizeof(T);
143     }
144 }
145 
146 template<typename T1, typename T2>
PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2)147 inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2)
148 {
149     if (condition) {
150         v1 = *(reinterpret_cast<const T1 *>(p));
151         p += sizeof(T1);
152         v2 = *(reinterpret_cast<const T2 *>(p));
153         p += sizeof(T2);
154     }
155 }
156 
157 // PerfEventRecord
PerfEventRecord(perf_event_type type, bool inKernel, const std::string &name)158 PerfEventRecord::PerfEventRecord(perf_event_type type, bool inKernel, const std::string &name)
159     : name_(name)
160 {
161     header.type = type;
162     header.misc = inKernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER;
163     header.size = sizeof(header);
164 }
165 
PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name)166 PerfEventRecord::PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name)
167     : name_(name)
168 {
169     header.type = type;
170     header.misc = PERF_RECORD_MISC_USER;
171     header.size = sizeof(header);
172 }
173 
PerfEventRecord(uint8_t *p, const std::string &name)174 PerfEventRecord::PerfEventRecord(uint8_t *p, const std::string &name) : name_(name)
175 {
176     if (p == nullptr) {
177         header.type = PERF_RECORD_MMAP;
178         header.misc = PERF_RECORD_MISC_USER;
179         header.size = 0;
180         return;
181     }
182     header = *(reinterpret_cast<perf_event_header *>(p));
183 }
184 
GetHeaderBinary(std::vector<uint8_t> &buf) const185 void PerfEventRecord::GetHeaderBinary(std::vector<uint8_t> &buf) const
186 {
187     if (buf.size() < GetHeaderSize()) {
188         buf.resize(GetHeaderSize());
189     }
190     uint8_t *p = buf.data();
191     *(reinterpret_cast<perf_event_header *>(p)) = header;
192 }
193 
Dump(int indent, std::string outputFilename, FILE *outputDump) const194 void PerfEventRecord::Dump(int indent, std::string outputFilename, FILE *outputDump) const
195 {
196     if (outputDump != nullptr) {
197         g_outputDump = outputDump;
198     } else if (!outputFilename.empty() && g_outputDump == nullptr) {
199         std::string resolvedPath = CanonicalizeSpecPath(outputFilename.c_str());
200         g_outputDump = fopen(resolvedPath.c_str(), "w");
201         if (g_outputDump == nullptr) {
202             printf("unable open file to '%s' because '%d'\n", outputFilename.c_str(), errno);
203             return;
204         }
205     }
206     PRINT_INDENT(indent, "\n");
207     PRINT_INDENT(indent, "record %s: type %u, misc %u, size %zu\n", GetName().c_str(), GetType(),
208                  GetMisc(), GetSize());
209     DumpData(indent + 1);
210 }
211 
DumpLog(const std::string &prefix) const212 void PerfEventRecord::DumpLog(const std::string &prefix) const
213 {
214     HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName().c_str(),
215           GetType(), GetMisc(), GetSize());
216 }
217 
218 std::vector<u64> PerfRecordSample::ips_ = {};
219 std::vector<DfxFrame> PerfRecordSample::callFrames_ = {};
220 std::vector<pid_t> PerfRecordSample::serverPidMap_ = {};
221 
PerfRecordAuxtrace(uint8_t *p)222 PerfRecordAuxtrace::PerfRecordAuxtrace(uint8_t *p) : PerfEventRecord(p, "auxtrace")
223 {
224     if (header.size >= sizeof(header)) {
225         size_t copySize = header.size - sizeof(header);
226         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
227             HLOGE("memcpy_s retren failed !!!");
228         }
229     } else {
230         HLOGE("PerfRecordAuxtrace retren failed !!!");
231     }
232     rawData_ = p + header.size;
233 }
234 
PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid)235 PerfRecordAuxtrace::PerfRecordAuxtrace(u64 size, u64 offset, u64 reference, u32 idx, u32 tid, u32 cpu, u32 pid)
236     : PerfEventRecord(PERF_RECORD_AUXTRACE, "auxtrace")
237 {
238     data_.size = size;
239     data_.offset = offset;
240     data_.reference = reference;
241     data_.idx = idx;
242     data_.tid = tid;
243     data_.cpu = cpu;
244     data_.reserved__ = pid;
245 
246     header.size = sizeof(header) + sizeof(data_);
247 }
248 
GetBinary1(std::vector<uint8_t> &buf) const249 bool PerfRecordAuxtrace::GetBinary1(std::vector<uint8_t> &buf) const
250 {
251     if (buf.size() < header.size) {
252         buf.resize(header.size);
253     }
254 
255     GetHeaderBinary(buf);
256     uint8_t *p = buf.data() + GetHeaderSize();
257 
258     size_t copySize = header.size - GetHeaderSize();
259     if (memcpy_s(p, sizeof(data_), reinterpret_cast<const uint8_t *>(&data_), copySize) != 0) {
260         HLOGE("memcpy_s return failed");
261         return false;
262     }
263     return true;
264 }
265 
GetBinary(std::vector<uint8_t> &buf) const266 bool PerfRecordAuxtrace::GetBinary(std::vector<uint8_t> &buf) const
267 {
268     if (buf.size() < GetSize()) {
269         buf.resize(GetSize());
270     }
271 
272     GetHeaderBinary(buf);
273     uint8_t *p = buf.data() + GetHeaderSize();
274 
275     size_t copySize = header.size - GetHeaderSize();
276     if (memcpy_s(p, sizeof(data_), reinterpret_cast<const uint8_t *>(&data_), copySize) != 0) {
277         HLOGE("memcpy_s return failed");
278         return false;
279     }
280     p += header.size - GetHeaderSize();
281     if (memcpy_s(p, data_.size, static_cast<uint8_t *>(rawData_), data_.size) != 0) {
282         HLOGE("memcpy_s return failed");
283         return false;
284     }
285     return true;
286 }
287 
DumpData(int indent) const288 void PerfRecordAuxtrace::DumpData(int indent) const
289 {
290     PRINT_INDENT(indent, "size 0x%llx, offset 0x%llx, reference 0x%llx, idx %u, tid %u, cpu %u, pid %u\n",
291                  data_.size, data_.offset, data_.reference, data_.idx, data_.tid, data_.cpu, data_.reserved__);
292 #if defined(is_ohos) && is_ohos
293     if (!SpeDumpRawData(rawData_, data_.size, indent, g_outputDump)) {
294         HLOGE("SpeDumpRawData failed");
295     }
296 #endif
297 }
298 
DumpLog(const std::string &prefix) const299 void PerfRecordAuxtrace::DumpLog(const std::string &prefix) const
300 {
301     HLOGV("size %llu, offset 0x%llx, reference 0x%llx, idx %u, tid %u, cpu %u\n",
302           data_.size, data_.offset, data_.reference, data_.idx, data_.tid, data_.cpu);
303 }
304 
GetSize() const305 size_t PerfRecordAuxtrace::GetSize() const
306 {
307     return header.size + data_.size;
308 }
309 
DumpLog(const std::string &prefix) const310 void PerfRecordSample::DumpLog(const std::string &prefix) const
311 {
312     HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu",
313           prefix.c_str(), data_.sample_id, header.size, data_.pid, data_.tid, data_.nr,
314           data_.reg_nr, data_.dyn_size, data_.time);
315 }
316 
RecoverCallStack()317 void PerfRecordSample::RecoverCallStack()
318 {
319     data_.ips = ips_.data();
320     data_.nr = ips_.size();
321     removeStack_ = true;
322 }
323 
ReplaceWithCallStack(size_t originalSize)324 void PerfRecordSample::ReplaceWithCallStack(size_t originalSize)
325 {
326     // first we check if we have some user unwind stack need to merge ?
327     if (callFrames_.size() != 0) {
328         // when we have some kernel ips , we cp it first
329         // new size is user call frames + kernel call frames
330         // + PERF_CONTEXT_USER(last + 1) + expand mark(also PERF_CONTEXT_USER)
331         const unsigned int perfContextSize = 2;
332         ips_.reserve(data_.nr + callFrames_.size() + perfContextSize);
333         if (data_.nr > 0) {
334             ips_.assign(data_.ips, data_.ips + data_.nr);
335         }
336         // add user context mark
337         ips_.emplace_back(PERF_CONTEXT_USER);
338         // we also need make a expand mark just for debug only
339         const size_t beginIpsSize = ips_.size();
340         bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const DfxFrame &frame) {
341             ips_.emplace_back(frame.pc);
342             if (originalSize != 0 and (originalSize != callFrames_.size()) and
343                 ips_.size() == (originalSize + beginIpsSize)) {
344                 // just for debug
345                 // so we can see which frame begin is expand call frames
346                 ips_.emplace_back(PERF_CONTEXT_USER);
347             }
348             return true;
349         });
350         if (ret) {
351             HLOGV("combed %zu", callFrames_.size());
352         } else {
353             HLOGV("failed to combed %zu", callFrames_.size());
354         }
355 
356         if (sampleType_ & PERF_SAMPLE_REGS_USER) {
357             header.size -= data_.reg_nr * sizeof(u64);
358             data_.reg_nr = 0;
359             data_.user_abi = 0;
360         }
361 
362         if (sampleType_ & PERF_SAMPLE_STACK_USER) {
363             // 1. remove the user stack
364             header.size -= data_.stack_size;
365             header.size -= sizeof(data_.dyn_size);
366 
367             // 2. clean the size
368             data_.stack_size = 0;
369             data_.dyn_size = 0;
370         }
371 
372         if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
373             HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size());
374 
375             // 3. remove the nr size
376             header.size -= data_.nr * sizeof(u64);
377 
378             // 4. add new nr size
379             data_.nr = ips_.size();
380             header.size += data_.nr * sizeof(u64);
381 
382             // 5. change ips potin to our ips array and hold it.
383             data_.ips = ips_.data();
384         }
385     } else {
386         // nothing need change
387         return;
388     }
389 }
390 
PerfRecordSample(uint8_t *p, const perf_event_attr &attr)391 PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr)
392     : PerfEventRecord(p, "sample")
393 {
394     if (p == nullptr) {
395         HLOG_ASSERT(p);
396         return;
397     }
398     // clear the static vector data
399     Clean();
400     sampleType_ = attr.sample_type;
401 
402     uint8_t *start = p;
403 
404     p += sizeof(header);
405 
406     // parse record according SAMPLE_TYPE
407     PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
408     PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
409     PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
410     PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
411     PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
412     PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
413     PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
414     PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
415     PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
416     PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
417     if (data_.nr > 0) {
418         // the pointer is from input(p), require caller keep input(p) with *this together
419         // think it in next time
420         data_.ips = reinterpret_cast<u64 *>(p);
421         p += data_.nr * sizeof(u64);
422     }
423     PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
424     if (data_.raw_size > 0) {
425         data_.raw_data = p;
426         p += data_.raw_size * sizeof(u8);
427     }
428     PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
429     if (data_.bnr > 0) {
430         data_.lbr = reinterpret_cast<PerfBranchEntry *>(p);
431         p += data_.bnr * sizeof(PerfBranchEntry);
432     }
433     PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
434     if (data_.user_abi > 0) {
435         data_.reg_mask = attr.sample_regs_user;
436         data_.reg_nr = __builtin_popcountll(data_.reg_mask);
437         data_.user_regs = reinterpret_cast<u64 *>(p);
438         p += data_.reg_nr * sizeof(u64);
439     }
440     PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr);
441     if (data_.server_nr > 0) {
442         data_.server_pids = reinterpret_cast<u64 *>(p);
443         p += data_.server_nr * sizeof(u64);
444     }
445     PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
446     if (data_.stack_size > 0) {
447         data_.stack_data = p;
448         p += data_.stack_size;
449         PopFromBinary(true, p, data_.dyn_size);
450     }
451     uint32_t remain = header.size - (p - start);
452     if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) {
453         PopFromBinary(true, p, stackId_.value);
454     }
455 }
456 
GetBinary(std::vector<uint8_t> &buf) const457 bool PerfRecordSample::GetBinary(std::vector<uint8_t> &buf) const
458 {
459     if (buf.size() < GetSize()) {
460         buf.resize(GetSize());
461     }
462 
463     GetHeaderBinary(buf);
464     uint8_t *p = buf.data() + GetHeaderSize();
465 
466     PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id);
467     PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip);
468     PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid);
469     PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time);
470     PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr);
471     PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id);
472     PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id);
473     PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res);
474     PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period);
475     PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr);
476     if (data_.nr > 0 && !removeStack_) {
477         std::copy(data_.ips + skipKernel_, data_.ips + data_.nr + skipKernel_,
478                   reinterpret_cast<u64 *>(p));
479         p += data_.nr * sizeof(u64);
480     }
481     PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size);
482     if (data_.raw_size > 0) {
483         std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p);
484         p += data_.raw_size * sizeof(u8);
485     }
486     PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr);
487     if (data_.bnr > 0) {
488         std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast<PerfBranchEntry *>(p));
489         p += data_.bnr * sizeof(PerfBranchEntry);
490     }
491     PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi);
492     if (data_.user_abi > 0 && data_.reg_nr > 0) {
493         std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast<u64 *>(p));
494         p += data_.reg_nr * sizeof(u64);
495     }
496     PushToBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr);
497     if (data_.server_nr > 0) {
498         std::copy(data_.server_pids + skipPid_, data_.server_pids + data_.server_nr + skipPid_,
499                   reinterpret_cast<u64 *>(p));
500         p += data_.server_nr * sizeof(u64);
501     }
502     PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size);
503     if (data_.stack_size > 0) {
504         std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p);
505         p += data_.stack_size * sizeof(u8);
506         PushToBinary(true, p, data_.dyn_size);
507     }
508     PushToBinary(removeStack_, p, stackId_.value);
509     return true;
510 }
511 
DumpData(int indent) const512 void PerfRecordSample::DumpData(int indent) const
513 {
514     PRINT_INDENT(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_);
515 
516     // dump record according sampleType
517     if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
518         PRINT_INDENT(indent, "ID %" PRIu64 "\n", static_cast<uint64_t>(data_.sample_id));
519     }
520     if (sampleType_ & PERF_SAMPLE_IP) {
521         PRINT_INDENT(indent, "ip %llx\n", data_.ip);
522     }
523     if (sampleType_ & PERF_SAMPLE_TID) {
524         PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
525     }
526     if (sampleType_ & PERF_SAMPLE_TIME) {
527         PRINT_INDENT(indent, "time %llu\n", data_.time);
528     }
529     if (sampleType_ & PERF_SAMPLE_ADDR) {
530         PRINT_INDENT(indent, "addr %p\n", reinterpret_cast<void *>(data_.addr));
531     }
532     if (sampleType_ & PERF_SAMPLE_STREAM_ID) {
533         PRINT_INDENT(indent, "stream_id %" PRIu64 "\n", static_cast<uint64_t>(data_.stream_id));
534     }
535     if (sampleType_ & PERF_SAMPLE_CPU) {
536         PRINT_INDENT(indent, "cpu %u, res %u\n", data_.cpu, data_.res);
537     }
538     if (sampleType_ & PERF_SAMPLE_PERIOD) {
539         PRINT_INDENT(indent, "period %" PRIu64 "\n", static_cast<uint64_t>(data_.period));
540     }
541     if (stackId_.section.id > 0) {
542         PRINT_INDENT(indent, "stackid %" PRIu64 "\n", static_cast<uint64_t>(stackId_.section.id));
543     }
544     if (sampleType_ & PERF_SAMPLE_CALLCHAIN) {
545         bool userContext = false;
546         PRINT_INDENT(indent, "callchain nr=%lld\n", data_.nr);
547         for (uint64_t i = 0; i < data_.nr; ++i) {
548             std::string_view supplement = "";
549             if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) {
550                 PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
551                 continue;
552             }
553             // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER
554             if (!userContext) {
555                 userContext = true;
556                 supplement = " <unwind callstack>";
557             } else {
558                 supplement = " <expand callstack>";
559             }
560             PRINT_INDENT(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data());
561         }
562     }
563     if (sampleType_ & PERF_SAMPLE_RAW) {
564         PRINT_INDENT(indent, "raw size=%u\n", data_.raw_size);
565         const uint32_t *data = reinterpret_cast<const uint32_t *>(data_.raw_data);
566         size_t size = data_.raw_size / sizeof(uint32_t);
567         for (size_t i = 0; i < size; ++i) {
568             PRINT_INDENT(indent + 1, "0x%08x (%x)\n", data[i], data[i]);
569         }
570     }
571     if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) {
572         PRINT_INDENT(indent, "branch_stack nr=%lld\n", data_.bnr);
573         for (uint64_t i = 0; i < data_.bnr; ++i) {
574             auto &item = data_.lbr[i];
575             PRINT_INDENT(indent + 1, "from 0x%llx, to 0x%llx, flags 0x%llx\n", item.from, item.to, item.flags);
576         }
577     }
578     if (sampleType_ & PERF_SAMPLE_REGS_USER) {
579         PRINT_INDENT(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr);
580         for (uint64_t i = 0; i < data_.reg_nr; ++i) {
581             PRINT_INDENT(indent + 1, "0x%llx\n", data_.user_regs[i]);
582         }
583     }
584     if (sampleType_ & PERF_SAMPLE_SERVER_PID) {
585         PRINT_INDENT(indent, "server nr=%lld\n", data_.server_nr);
586         for (uint64_t i = 0; i < data_.server_nr; ++i) {
587             PRINT_INDENT(indent + 1, "pid: %llu\n", data_.server_pids[i]);
588         }
589     }
590     if (sampleType_ & PERF_SAMPLE_STACK_USER) {
591         PRINT_INDENT(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size,
592                      data_.dyn_size);
593     }
594 }
595 
GetPid() const596 inline pid_t PerfRecordSample::GetPid() const
597 {
598     return data_.pid;
599 }
600 
Clean()601 void PerfRecordSample::Clean()
602 {
603     ips_.clear();
604     callFrames_.clear();
605     serverPidMap_.clear();
606 }
607 
PerfRecordMmap(uint8_t *p)608 PerfRecordMmap::PerfRecordMmap(uint8_t *p) : PerfEventRecord(p, "mmap")
609 {
610     size_t dataSize = GetSize();
611     if (dataSize >= sizeof(header)) {
612         size_t copySize = dataSize - sizeof(header);
613         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
614             HLOGE("memcpy_s retren failed !!!");
615         }
616     } else {
617         HLOGE("PerfRecordMmap retren failed !!!");
618     }
619 }
620 
PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, const std::string &filename)621 PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
622                                const std::string &filename)
623     : PerfEventRecord(PERF_RECORD_MMAP, inKernel, "mmap")
624 {
625     data_.pid = pid;
626     data_.tid = tid;
627     data_.addr = addr;
628     data_.len = len;
629     data_.pgoff = pgoff;
630     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
631         HLOGE("strncpy_s failed");
632     }
633 
634     header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
635 }
636 
GetBinary(std::vector<uint8_t> &buf) const637 bool PerfRecordMmap::GetBinary(std::vector<uint8_t> &buf) const
638 {
639     if (buf.size() < GetSize()) {
640         buf.resize(GetSize());
641     }
642 
643     GetHeaderBinary(buf);
644     uint8_t *p = buf.data() + GetHeaderSize();
645 
646     // data_.filename[] is variable-length
647     std::copy(reinterpret_cast<const uint8_t *>(&data_),
648               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
649     return true;
650 }
651 
DumpData(int indent) const652 void PerfRecordMmap::DumpData(int indent) const
653 {
654 #if defined(is_ohos) && is_ohos
655     if (IsRoot()) {
656         PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
657                      data_.addr, data_.len);
658         PRINT_INDENT(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename);
659     }
660 #endif
661 }
662 
DumpLog(const std::string &prefix) const663 void PerfRecordMmap::DumpLog(const std::string &prefix) const
664 {
665     HLOGV("%s:  MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
666           header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, data_.pgoff);
667 }
668 
PerfRecordMmap2(uint8_t *p)669 PerfRecordMmap2::PerfRecordMmap2(uint8_t *p) : PerfEventRecord(p, "mmap2")
670 {
671     size_t dataSize = GetSize();
672     if (dataSize >= sizeof(header)) {
673         size_t copySize = dataSize - sizeof(header);
674         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
675             HLOGE("memcpy_s retren failed !!!");
676         }
677     } else {
678         HLOGE("PerfRecordMmap2 retren failed !!!");
679     }
680 }
681 
PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, u32 maj, u32 min, u64 ino, u32 prot, u32 flags, const std::string &filename)682 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff,
683                                  u32 maj, u32 min, u64 ino, u32 prot, u32 flags,
684                                  const std::string &filename)
685     : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
686 {
687     data_.pid = pid;
688     data_.tid = tid;
689     data_.addr = addr;
690     data_.len = len;
691     data_.pgoff = pgoff;
692     data_.maj = maj;
693     data_.min = min;
694     data_.ino = ino;
695     data_.ino_generation = 0;
696     data_.prot = prot;
697     data_.flags = flags;
698     if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) {
699         HLOGE("strncpy_s failed");
700     }
701 
702     header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1;
703 }
704 
PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr<DfxMap> item)705 PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, std::shared_ptr<DfxMap> item)
706     : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2")
707 {
708     data_.pid = pid;
709     data_.tid = tid;
710     if (item != nullptr) {
711         data_.addr = item->begin;
712         data_.len = item->end - item->begin;
713         data_.pgoff = item->offset;
714         data_.maj = item->major;
715         data_.min = item->minor;
716         data_.ino = item->inode;
717         data_.ino_generation = 0;
718         // r--p 00000000 103:3e 12307                         /data/storage/el1/bundle/entry.hap
719         // why prot get from this is 7. rwxp
720         DfxMap::PermsToProts(item->perms, data_.prot, data_.flags);
721         if (strncpy_s(data_.filename, KILO, item->name.c_str(), item->name.size()) != 0) {
722             HLOGE("strncpy_s failed");
723         }
724 
725         header.size = sizeof(header) + sizeof(data_) - KILO + item->name.size() + 1;
726     } else {
727         data_.addr = 0;
728         data_.len = 0;
729         data_.pgoff = 0;
730         data_.maj = 0;
731         data_.min = 0;
732         data_.ino = 0;
733         data_.ino_generation = 0;
734         if (memset_s(data_.filename, KILO, 0, KILO) != EOK) {
735             HLOGE("memset_s failed");
736         }
737     }
738 }
739 
GetBinary(std::vector<uint8_t> &buf) const740 bool PerfRecordMmap2::GetBinary(std::vector<uint8_t> &buf) const
741 {
742     if (buf.size() < GetSize()) {
743         buf.resize(GetSize());
744     }
745 
746     GetHeaderBinary(buf);
747     uint8_t *p = buf.data() + GetHeaderSize();
748 
749     // data_.filename[] is variable-length
750     std::copy(reinterpret_cast<const uint8_t *>(&data_),
751               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
752     return true;
753 }
754 
DumpData(int indent) const755 void PerfRecordMmap2::DumpData(int indent) const
756 {
757 #if defined(is_ohos) && is_ohos
758     if (IsRoot()) {
759         PRINT_INDENT(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid,
760                      data_.addr, data_.len);
761         PRINT_INDENT(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n",
762                      data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation);
763         PRINT_INDENT(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags,
764                      data_.filename);
765     }
766 #endif
767 }
DumpLog(const std::string &prefix) const768 void PerfRecordMmap2::DumpLog(const std::string &prefix) const
769 {
770     HLOGV("%s:  MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(),
771           header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len,
772           data_.pgoff);
773 }
774 
PerfRecordLost(uint8_t *p)775 PerfRecordLost::PerfRecordLost(uint8_t *p) : PerfEventRecord(p, "lost")
776 {
777     size_t dataSize = GetSize();
778     if (dataSize >= sizeof(header)) {
779         size_t copySize = dataSize - sizeof(header);
780         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
781             HLOGE("memcpy_s retren failed !!!");
782         }
783     } else {
784         HLOGE("PerfRecordLost retren failed !!!");
785     }
786 }
787 
GetBinary(std::vector<uint8_t> &buf) const788 bool PerfRecordLost::GetBinary(std::vector<uint8_t> &buf) const
789 {
790     if (buf.size() < GetSize()) {
791         buf.resize(GetSize());
792     }
793 
794     GetHeaderBinary(buf);
795     uint8_t *p = buf.data() + GetHeaderSize();
796 
797     auto pDest = reinterpret_cast<PerfRecordLostData *>(p);
798     *pDest = data_;
799 
800     return true;
801 }
802 
DumpData(int indent) const803 void PerfRecordLost::DumpData(int indent) const
804 {
805     PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost);
806 }
807 
PerfRecordComm(uint8_t *p)808 PerfRecordComm::PerfRecordComm(uint8_t *p) : PerfEventRecord(p, "comm")
809 {
810     size_t dataSize = GetSize();
811     if (dataSize >= sizeof(header)) {
812         size_t copySize = dataSize - sizeof(header);
813         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
814             HLOGE("memcpy_s retren failed !!!");
815         }
816     } else {
817         HLOGE("PerfRecordComm retren failed !!!");
818     }
819 }
820 
PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm)821 PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm)
822     : PerfEventRecord(PERF_RECORD_COMM, inKernel, "comm")
823 {
824     data_.pid = pid;
825     data_.tid = tid;
826     if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) {
827         HLOGE("strncpy_s failed !!!");
828     }
829 
830     header.size = sizeof(header) + sizeof(data_) - KILO + comm.size() + 1;
831 }
832 
GetBinary(std::vector<uint8_t> &buf) const833 bool PerfRecordComm::GetBinary(std::vector<uint8_t> &buf) const
834 {
835     if (buf.size() < GetSize()) {
836         buf.resize(GetSize());
837     }
838 
839     GetHeaderBinary(buf);
840     uint8_t *p = buf.data() + GetHeaderSize();
841 
842     // data_.comm[] is variable-length
843     std::copy(reinterpret_cast<const uint8_t *>(&data_),
844               reinterpret_cast<const uint8_t *>(&data_) + GetSize() - GetHeaderSize(), p);
845 
846     return true;
847 }
848 
DumpData(int indent) const849 void PerfRecordComm::DumpData(int indent) const
850 {
851     PRINT_INDENT(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
852 }
853 
DumpLog(const std::string &prefix) const854 void PerfRecordComm::DumpLog(const std::string &prefix) const
855 {
856     HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm);
857 }
858 
PerfRecordExit(uint8_t *p)859 PerfRecordExit::PerfRecordExit(uint8_t *p) : PerfEventRecord(p, "exit")
860 {
861     size_t dataSize = GetSize();
862     if (dataSize >= sizeof(header)) {
863         size_t copySize = dataSize - sizeof(header);
864         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
865             HLOGE("memcpy_s retren failed !!!");
866         }
867     } else {
868         HLOGE("PerfRecordExit retren failed !!!");
869     }
870 }
871 
GetBinary(std::vector<uint8_t> &buf) const872 bool PerfRecordExit::GetBinary(std::vector<uint8_t> &buf) const
873 {
874     if (buf.size() < GetSize()) {
875         buf.resize(GetSize());
876     }
877 
878     GetHeaderBinary(buf);
879     uint8_t *p = buf.data() + GetHeaderSize();
880 
881     auto pDest = reinterpret_cast<PerfRecordExitData *>(p);
882     *pDest = data_;
883     return true;
884 }
885 
DumpData(int indent) const886 void PerfRecordExit::DumpData(int indent) const
887 {
888     PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid,
889                  data_.tid, data_.ptid, data_.time);
890 }
891 
PerfRecordThrottle(uint8_t *p)892 PerfRecordThrottle::PerfRecordThrottle(uint8_t *p) : PerfEventRecord(p, "throttle")
893 {
894     size_t dataSize = GetSize();
895     if (dataSize >= sizeof(header)) {
896         size_t copySize = dataSize - sizeof(header);
897         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
898             HLOGE("memcpy_s retren failed !!!");
899         }
900     } else {
901         HLOGE("PerfRecordThrottle retren failed !!!");
902     }
903 }
904 
GetBinary(std::vector<uint8_t> &buf) const905 bool PerfRecordThrottle::GetBinary(std::vector<uint8_t> &buf) const
906 {
907     if (buf.size() < GetSize()) {
908         buf.resize(GetSize());
909     }
910 
911     GetHeaderBinary(buf);
912     uint8_t *p = buf.data() + GetHeaderSize();
913 
914     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
915     *pDest = data_;
916     return true;
917 }
918 
DumpData(int indent) const919 void PerfRecordThrottle::DumpData(int indent) const
920 {
921     PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
922                  data_.stream_id);
923 }
924 
PerfRecordUnthrottle(uint8_t *p)925 PerfRecordUnthrottle::PerfRecordUnthrottle(uint8_t *p) : PerfEventRecord(p, "unthrottle")
926 {
927     size_t dataSize = GetSize();
928     if (dataSize >= sizeof(header)) {
929         size_t copySize = dataSize - sizeof(header);
930         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
931             HLOGE("memcpy_s retren failed !!!");
932         }
933     } else {
934         HLOGE("PerfRecordUnthrottle retren failed !!!");
935     }
936 }
937 
GetBinary(std::vector<uint8_t> &buf) const938 bool PerfRecordUnthrottle::GetBinary(std::vector<uint8_t> &buf) const
939 {
940     if (buf.size() < GetSize()) {
941         buf.resize(GetSize());
942     }
943 
944     GetHeaderBinary(buf);
945     uint8_t *p = buf.data() + GetHeaderSize();
946 
947     auto pDest = reinterpret_cast<PerfRecordThrottleData *>(p);
948     *pDest = data_;
949     return true;
950 }
DumpData(int indent) const951 void PerfRecordUnthrottle::DumpData(int indent) const
952 {
953     PRINT_INDENT(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id,
954                  data_.stream_id);
955 }
956 
PerfRecordFork(uint8_t *p)957 PerfRecordFork::PerfRecordFork(uint8_t *p) : PerfEventRecord(p, "fork")
958 {
959     size_t dataSize = GetSize();
960     if (dataSize >= sizeof(header)) {
961         size_t copySize = dataSize - sizeof(header);
962         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
963             HLOGE("memcpy_s retren failed !!!");
964         }
965     } else {
966         HLOGE("PerfRecordFork retren failed !!!");
967     }
968 }
969 
GetBinary(std::vector<uint8_t> &buf) const970 bool PerfRecordFork::GetBinary(std::vector<uint8_t> &buf) const
971 {
972     if (buf.size() < GetSize()) {
973         buf.resize(GetSize());
974     }
975 
976     GetHeaderBinary(buf);
977     uint8_t *p = buf.data() + GetHeaderSize();
978 
979     auto pDest = reinterpret_cast<PerfRecordForkData *>(p);
980     *pDest = data_;
981     return true;
982 }
983 
DumpData(int indent) const984 void PerfRecordFork::DumpData(int indent) const
985 {
986     PRINT_INDENT(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid,
987                  data_.ptid);
988 }
989 
PerfRecordRead(uint8_t *p)990 PerfRecordRead::PerfRecordRead(uint8_t *p) : PerfEventRecord(p, "read")
991 {
992     size_t dataSize = GetSize();
993     if (dataSize >= sizeof(header)) {
994         size_t copySize = dataSize - sizeof(header);
995         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
996             HLOGE("memcpy_s retren failed !!!");
997         }
998     } else {
999         HLOGE("PerfRecordRead retren failed !!!");
1000     }
1001 }
1002 
GetBinary(std::vector<uint8_t> &buf) const1003 bool PerfRecordRead::GetBinary(std::vector<uint8_t> &buf) const
1004 {
1005     if (buf.size() < GetSize()) {
1006         buf.resize(GetSize());
1007     }
1008 
1009     GetHeaderBinary(buf);
1010     uint8_t *p = buf.data() + GetHeaderSize();
1011 
1012     auto pDest = reinterpret_cast<PerfRecordReadData *>(p);
1013     *pDest = data_;
1014     return true;
1015 }
1016 
DumpData(int indent) const1017 void PerfRecordRead::DumpData(int indent) const
1018 {
1019     PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
1020     PRINT_INDENT(indent, "values: value %llx, timeEnabled %llx, timeRunning %llx, id %llx\n",
1021                  data_.values.value, data_.values.timeEnabled, data_.values.timeRunning, data_.values.id);
1022 }
1023 
PerfRecordAux(uint8_t *p)1024 PerfRecordAux::PerfRecordAux(uint8_t *p) : PerfEventRecord(p, "aux")
1025 {
1026     size_t dataSize = GetSize();
1027     if (dataSize >= sizeof(header)) {
1028         size_t copySize = dataSize - sizeof(header);
1029         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
1030             HLOGE("memcpy_s retren failed !!!");
1031         }
1032     } else {
1033         HLOGE("PerfRecordAux retren failed !!!");
1034     }
1035 }
1036 
GetBinary(std::vector<uint8_t> &buf) const1037 bool PerfRecordAux::GetBinary(std::vector<uint8_t> &buf) const
1038 {
1039     if (buf.size() < GetSize()) {
1040         buf.resize(GetSize());
1041     }
1042 
1043     GetHeaderBinary(buf);
1044     uint8_t *p = buf.data() + GetHeaderSize();
1045 
1046     PushToBinary(true, p, data_.aux_offset);
1047     PushToBinary(true, p, data_.aux_size);
1048     PushToBinary(true, p, data_.flags);
1049     PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.sample_id.pid, data_.sample_id.tid);
1050     PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.sample_id.time);
1051     PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.sample_id.id);
1052     PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.sample_id.stream_id);
1053 
1054     PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.sample_id.cpu, data_.sample_id.res);
1055     PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id.id2);
1056     return true;
1057 }
1058 
DumpData(int indent) const1059 void PerfRecordAux::DumpData(int indent) const
1060 {
1061     PRINT_INDENT(indent, "aux_offset 0x%llx aux_size 0x%llx flags 0x%llx pid %u tid %u time %llu",
1062                  data_.aux_offset, data_.aux_size, data_.flags, data_.sample_id.pid, data_.sample_id.tid,
1063                  data_.sample_id.time);
1064 }
1065 
PerfRecordItraceStart(uint8_t *p)1066 PerfRecordItraceStart::PerfRecordItraceStart(uint8_t *p) : PerfEventRecord(p, "itraceStart")
1067 {
1068     size_t dataSize = GetSize();
1069     if (dataSize >= sizeof(header)) {
1070         size_t copySize = dataSize - sizeof(header);
1071         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
1072             HLOGE("memcpy_s retren failed !!!");
1073         }
1074     } else {
1075         HLOGE("PerfRecordItraceStart retren failed !!!");
1076     }
1077 }
1078 
GetBinary(std::vector<uint8_t> &buf) const1079 bool PerfRecordItraceStart::GetBinary(std::vector<uint8_t> &buf) const
1080 {
1081     if (buf.size() < GetSize()) {
1082         buf.resize(GetSize());
1083     }
1084 
1085     GetHeaderBinary(buf);
1086     uint8_t *p = buf.data() + GetHeaderSize();
1087 
1088     auto pDest = reinterpret_cast<PerfRecordItraceStartData *>(p);
1089     *pDest = data_;
1090     return true;
1091 }
1092 
DumpData(int indent) const1093 void PerfRecordItraceStart::DumpData(int indent) const
1094 {
1095     PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
1096 }
1097 
PerfRecordLostSamples(uint8_t *p)1098 PerfRecordLostSamples::PerfRecordLostSamples(uint8_t *p) : PerfEventRecord(p, "lostSamples")
1099 {
1100     size_t dataSize = GetSize();
1101     if (dataSize >= sizeof(header)) {
1102         size_t copySize = dataSize - sizeof(header);
1103         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
1104             HLOGE("memcpy_s retren failed !!!");
1105         }
1106     } else {
1107         HLOGE("PerfRecordLostSamples retren failed !!!");
1108     }
1109 }
1110 
GetBinary(std::vector<uint8_t> &buf) const1111 bool PerfRecordLostSamples::GetBinary(std::vector<uint8_t> &buf) const
1112 {
1113     if (buf.size() < GetSize()) {
1114         buf.resize(GetSize());
1115     }
1116 
1117     GetHeaderBinary(buf);
1118     uint8_t *p = buf.data() + GetHeaderSize();
1119 
1120     auto pDest = reinterpret_cast<PerfRecordLostSamplesData *>(p);
1121     *pDest = data_;
1122     return true;
1123 }
1124 
DumpData(int indent) const1125 void PerfRecordLostSamples::DumpData(int indent) const
1126 {
1127     PRINT_INDENT(indent, "lost %llu\n", data_.lost);
1128 }
1129 
PerfRecordSwitch(uint8_t *p)1130 PerfRecordSwitch::PerfRecordSwitch(uint8_t *p) : PerfEventRecord(p, "switch")
1131 {
1132     size_t dataSize = GetSize();
1133     if (dataSize >= sizeof(header)) {
1134         size_t copySize = dataSize - sizeof(header);
1135         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
1136             HLOGE("memcpy_s retren failed !!!");
1137         }
1138     } else {
1139         HLOGE("PerfRecordSwitch retren failed !!!");
1140     }
1141 }
1142 
GetBinary(std::vector<uint8_t> &buf) const1143 bool PerfRecordSwitch::GetBinary(std::vector<uint8_t> &buf) const
1144 {
1145     if (buf.size() < GetSize()) {
1146         buf.resize(GetSize());
1147     }
1148 
1149     GetHeaderBinary(buf);
1150     uint8_t *p = buf.data() + GetHeaderSize();
1151 
1152     auto pDest = reinterpret_cast<PerfRecordSwitchData *>(p);
1153     *pDest = data_;
1154     return true;
1155 }
1156 
PerfRecordSwitchCpuWide(uint8_t *p)1157 PerfRecordSwitchCpuWide::PerfRecordSwitchCpuWide(uint8_t *p) : PerfEventRecord(p, "switchCpuWide")
1158 {
1159     size_t dataSize = GetSize();
1160     if (dataSize >= sizeof(header)) {
1161         size_t copySize = dataSize - sizeof(header);
1162         if (memcpy_s(reinterpret_cast<uint8_t *>(&data_), sizeof(data_), p + sizeof(header), copySize) != 0) {
1163             HLOGE("memcpy_s retren failed !!!");
1164         }
1165     } else {
1166         HLOGE("PerfRecordSwitchCpuWide retren failed !!!");
1167     }
1168 }
1169 
GetBinary(std::vector<uint8_t> &buf) const1170 bool PerfRecordSwitchCpuWide::GetBinary(std::vector<uint8_t> &buf) const
1171 {
1172     if (buf.size() < GetSize()) {
1173         buf.resize(GetSize());
1174     }
1175 
1176     GetHeaderBinary(buf);
1177     uint8_t *p = buf.data() + GetHeaderSize();
1178 
1179     auto pDest = reinterpret_cast<PerfRecordSwitchCpuWideData *>(p);
1180     *pDest = data_;
1181     return true;
1182 }
1183 
DumpData(int indent) const1184 void PerfRecordSwitchCpuWide::DumpData(int indent) const
1185 {
1186     PRINT_INDENT(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid,
1187                  data_.next_prev_tid);
1188 }
1189 
GetUstackServerPid()1190 pid_t PerfRecordSample::GetUstackServerPid()
1191 {
1192     if (!data_.server_nr) {
1193         return data_.pid;
1194     }
1195 
1196     size_t currServer = 0;
1197     // ipNr == 1...nr: server_pid of data_.ips[nr]
1198     for (size_t i = 0; i < data_.nr; i++) {
1199         // context change, use next server pid
1200         if (data_.ips[i] >= PERF_CONTEXT_MAX) {
1201             currServer++;
1202         }
1203     }
1204     // ipNr == nr + 1: server_pid of ustack
1205     if (currServer > 0) {
1206         currServer++;
1207     }
1208     if (currServer >= data_.server_nr) {
1209         HLOGE("ustack server pid nr %zu out of range", currServer);
1210         return data_.pid;
1211     }
1212 
1213     // return server pid
1214     return data_.server_pids[currServer];
1215 }
1216 
GetServerPidof(unsigned int ipNr)1217 pid_t PerfRecordSample::GetServerPidof(unsigned int ipNr)
1218 {
1219     if (!data_.server_nr) {
1220         return data_.pid;
1221     }
1222 
1223     // init serverPidMap_
1224     if (!serverPidMap_.size()) {
1225         size_t currServer = 0;
1226         // ipNr == 0: server_pid of data_.ip
1227         serverPidMap_.emplace_back(data_.server_pids[currServer]);
1228         // ipNr == 1...nr: server_pid of data_.ips[nr]
1229         for (size_t i = 1; i < data_.nr; i++) {
1230             // context change, use next server pid
1231             if (data_.ips[i] >= PERF_CONTEXT_MAX) {
1232                 currServer++;
1233             }
1234             if (currServer >= data_.server_nr) {
1235                 HLOGE("callchain server pid nr %zu out of range", currServer);
1236                 break;
1237             }
1238             serverPidMap_.emplace_back(data_.server_pids[currServer]);
1239         }
1240     }
1241 
1242     // return server pid
1243     if (ipNr >= serverPidMap_.size()) {
1244         return data_.pid;
1245     } else {
1246         return serverPidMap_[ipNr];
1247     }
1248 }
1249 } // namespace HiPerf
1250 } // namespace Developtools
1251 } // namespace OHOS
1252