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
23using namespace OHOS::HiviewDFX;
24using namespace std;
25namespace OHOS {
26namespace Developtools {
27namespace HiPerf {
28
29void *g_sampleMemCache = nullptr; // for read record from buf thread
30void *g_sampleMemCacheMain = nullptr; // for main thread:collecttionsymbol
31constexpr size_t SAMPLE_CACHE_SIZE = 4 * 1024;
32
33std::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
79std::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
98std::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
117template<typename T>
118inline 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
126template<typename T1, typename T2>
127inline 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
137template<typename T>
138inline 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
146template<typename T1, typename T2>
147inline 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
158PerfEventRecord::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
166PerfEventRecord::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
174PerfEventRecord::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
185void 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
194void 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
212void 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
218std::vector<u64> PerfRecordSample::ips_ = {};
219std::vector<DfxFrame> PerfRecordSample::callFrames_ = {};
220std::vector<pid_t> PerfRecordSample::serverPidMap_ = {};
221
222PerfRecordAuxtrace::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
235PerfRecordAuxtrace::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
249bool 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
266bool 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
288void 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
299void 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
305size_t PerfRecordAuxtrace::GetSize() const
306{
307    return header.size + data_.size;
308}
309
310void 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
317void PerfRecordSample::RecoverCallStack()
318{
319    data_.ips = ips_.data();
320    data_.nr = ips_.size();
321    removeStack_ = true;
322}
323
324void 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
391PerfRecordSample::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
457bool 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
512void 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
596inline pid_t PerfRecordSample::GetPid() const
597{
598    return data_.pid;
599}
600
601void PerfRecordSample::Clean()
602{
603    ips_.clear();
604    callFrames_.clear();
605    serverPidMap_.clear();
606}
607
608PerfRecordMmap::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
621PerfRecordMmap::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
637bool 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
652void 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
663void 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
669PerfRecordMmap2::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
682PerfRecordMmap2::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
705PerfRecordMmap2::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
740bool 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
755void 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}
768void 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
775PerfRecordLost::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
788bool 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
803void PerfRecordLost::DumpData(int indent) const
804{
805    PRINT_INDENT(indent, "id %llu, lost %llu\n", data_.id, data_.lost);
806}
807
808PerfRecordComm::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
821PerfRecordComm::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
833bool 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
849void 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
854void 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
859PerfRecordExit::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
872bool 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
886void 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
892PerfRecordThrottle::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
905bool 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
919void 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
925PerfRecordUnthrottle::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
938bool 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}
951void 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
957PerfRecordFork::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
970bool 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
984void 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
990PerfRecordRead::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
1003bool 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
1017void 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
1024PerfRecordAux::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
1037bool 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
1059void 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
1066PerfRecordItraceStart::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
1079bool 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
1093void PerfRecordItraceStart::DumpData(int indent) const
1094{
1095    PRINT_INDENT(indent, "pid %u, tid %u\n", data_.pid, data_.tid);
1096}
1097
1098PerfRecordLostSamples::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
1111bool 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
1125void PerfRecordLostSamples::DumpData(int indent) const
1126{
1127    PRINT_INDENT(indent, "lost %llu\n", data_.lost);
1128}
1129
1130PerfRecordSwitch::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
1143bool 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
1157PerfRecordSwitchCpuWide::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
1170bool 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
1184void 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
1190pid_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
1217pid_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