1 /*
2 * Copyright (c) 2025 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
16 #include "lperf_event_record.h"
17
18 namespace OHOS {
19 namespace HiviewDFX {
20 namespace {
21 #undef LOG_DOMAIN
22 #undef LOG_TAG
23 #define LOG_DOMAIN 0xD002D11
24 #define LOG_TAG "DfxLperfRecordSample"
25
26 const char* const PERF_RECORD_TYPE_SAMPLE = "sample";
27 }
28 LperfRecordSample LperfRecordFactory::record_ = {};
29
GetName()30 const char* LperfRecordSample::GetName()
31 {
32 return PERF_RECORD_TYPE_SAMPLE;
33 }
34
GetType() const35 uint32_t LperfRecordSample::GetType() const
36 {
37 return header_.type;
38 }
39
InitHeader(uint8_t * data)40 void LperfRecordSample::InitHeader(uint8_t* data)
41 {
42 if (data == nullptr) {
43 header_.type = PERF_RECORD_MMAP;
44 header_.misc = PERF_RECORD_MISC_USER;
45 header_.size = 0;
46 return;
47 }
48 header_ = *(reinterpret_cast<perf_event_header *>(data));
49 }
50
Init(uint8_t * data)51 bool LperfRecordSample::Init(uint8_t* data)
52 {
53 InitHeader(data);
54 CHECK_TRUE_AND_RET(data != nullptr, false, "LperfRecordSample Init error");
55 data_ = {};
56 uint64_t dataSize = static_cast<uint64_t>(RECORD_SIZE_LIMIT);
57 CHECK_TRUE_AND_RET(SetPointerOffset(data, sizeof(header_), dataSize), false, "set header_ offset error");
58
59 // parse record according SAMPLE_TYPE
60 bool popId = PopFromBinary2<uint32_t, uint32_t>(sampleType_ & PERF_SAMPLE_TID,
61 data, data_.pid, data_.tid, dataSize);
62 CHECK_TRUE_AND_RET(popId, false, "Init PERF_SAMPLE_TID error");
63 CHECK_TRUE_AND_RET(PopFromBinary<uint64_t>(sampleType_ & PERF_SAMPLE_TIME, data, data_.time, dataSize),
64 false, "Init PERF_SAMPLE_TIME error");
65 CHECK_TRUE_AND_RET(PopFromBinary<uint64_t>(sampleType_ & PERF_SAMPLE_CALLCHAIN, data, data_.nr, dataSize),
66 false, "Init PERF_SAMPLE_CALLCHAIN error");
67 if (data_.nr > 0) {
68 // the pointer is from input(data), require caller keep input(data) with *this together
69 // think it in next time
70 data_.ips = reinterpret_cast<uint64_t *>(data);
71 CHECK_TRUE_AND_RET(SetPointerOffset(data, data_.nr * sizeof(uint64_t), dataSize),
72 false, "set ips offset error");
73 }
74 return true;
75 }
76
Clear()77 void LperfRecordSample::Clear()
78 {
79 data_.pid = 0;
80 data_.tid = 0;
81 data_.time = 0;
82 data_.nr = 0;
83 data_.ips = nullptr;
84 }
85
GetLperfRecord(uint32_t type,uint8_t * data)86 LperfRecordSample& LperfRecordFactory::GetLperfRecord(uint32_t type, uint8_t* data)
87 {
88 if (type != PERF_RECORD_SAMPLE || !record_.Init(data)) {
89 record_.Clear();
90 DFXLOGE("Init LperfRecordSample data error");
91 }
92 return record_;
93 }
94
ClearData()95 void LperfRecordFactory::ClearData()
96 {
97 record_.Clear();
98 }
99
100 template<typename T>
PopFromBinary(bool condition,uint8_t * & data,T & dest,uint64_t & size)101 inline bool PopFromBinary(bool condition, uint8_t*& data, T& dest, uint64_t& size)
102 {
103 CHECK_TRUE_AND_RET(sizeof(T) <= size, false, "PopFromBinary error");
104 if (condition) {
105 dest = *(reinterpret_cast<const T *>(data));
106 data += sizeof(T);
107 size -= sizeof(T);
108 }
109 return true;
110 }
111
112 template<typename T1, typename T2>
PopFromBinary2(bool condition,uint8_t * & data,T1 & dest1,T2 & dest2,uint64_t & size)113 inline bool PopFromBinary2(bool condition, uint8_t*& data, T1& dest1, T2& dest2, uint64_t& size)
114 {
115 CHECK_TRUE_AND_RET(sizeof(T1) + sizeof(T2) <= size, false, "PopFromBinary2 error");
116 if (condition) {
117 dest1 = *(reinterpret_cast<const T1 *>(data));
118 data += sizeof(T1);
119 dest2 = *(reinterpret_cast<const T2 *>(data));
120 data += sizeof(T2);
121 size -= (sizeof(T1) + sizeof(T2));
122 }
123 return true;
124 }
125
SetPointerOffset(uint8_t * & data,uint64_t offset,uint64_t & size)126 inline bool SetPointerOffset(uint8_t*& data, uint64_t offset, uint64_t& size)
127 {
128 CHECK_TRUE_AND_RET(offset <= size && offset <= RECORD_SIZE_LIMIT, false, "SetPointerOffset error");
129 size -= offset;
130 data += offset;
131 return true;
132 }
133 } // namespace HiviewDFX
134 } // namespace OHOS