1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
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 #ifndef HIPERF_REGISTER_H
16 #define HIPERF_REGISTER_H
17 
18 #include <linux/perf_event.h>
19 
20 #include <cinttypes>
21 #include <string>
22 
23 #include "utilities.h"
24 #include "unwind_define.h"
25 
26 namespace OHOS {
27 namespace Developtools {
28 namespace NativeDaemon {
29 using namespace OHOS::HiviewDFX;
30 
31 // these define copy from kernel uapi
32 enum perf_event_x86_regs {
33     PERF_REG_X86_AX,
34     PERF_REG_X86_BX,
35     PERF_REG_X86_CX,
36     PERF_REG_X86_DX,
37     PERF_REG_X86_SI,
38     PERF_REG_X86_DI,
39     PERF_REG_X86_BP,
40     PERF_REG_X86_SP,
41     PERF_REG_X86_IP,
42     PERF_REG_X86_FLAGS,
43     PERF_REG_X86_CS,
44     PERF_REG_X86_SS,
45     PERF_REG_X86_DS,
46     PERF_REG_X86_ES,
47     PERF_REG_X86_FS,
48     PERF_REG_X86_GS,
49     PERF_REG_X86_R8,
50     PERF_REG_X86_R9,
51     PERF_REG_X86_R10,
52     PERF_REG_X86_R11,
53     PERF_REG_X86_R12,
54     PERF_REG_X86_R13,
55     PERF_REG_X86_R14,
56     PERF_REG_X86_R15,
57     PERF_REG_X86_32_MAX = PERF_REG_X86_GS + 1,
58     PERF_REG_X86_64_MAX = PERF_REG_X86_R15 + 1,
59 };
60 
61 enum perf_event_arm64_regs {
62     PERF_REG_ARM64_X0,
63     PERF_REG_ARM64_X1,
64     PERF_REG_ARM64_X2,
65     PERF_REG_ARM64_X3,
66     PERF_REG_ARM64_X4,
67     PERF_REG_ARM64_X5,
68     PERF_REG_ARM64_X6,
69     PERF_REG_ARM64_X7,
70     PERF_REG_ARM64_X8,
71     PERF_REG_ARM64_X9,
72     PERF_REG_ARM64_X10,
73     PERF_REG_ARM64_X11,
74     PERF_REG_ARM64_X12,
75     PERF_REG_ARM64_X13,
76     PERF_REG_ARM64_X14,
77     PERF_REG_ARM64_X15,
78     PERF_REG_ARM64_X16,
79     PERF_REG_ARM64_X17,
80     PERF_REG_ARM64_X18,
81     PERF_REG_ARM64_X19,
82     PERF_REG_ARM64_X20,
83     PERF_REG_ARM64_X21,
84     PERF_REG_ARM64_X22,
85     PERF_REG_ARM64_X23,
86     PERF_REG_ARM64_X24,
87     PERF_REG_ARM64_X25,
88     PERF_REG_ARM64_X26,
89     PERF_REG_ARM64_X27,
90     PERF_REG_ARM64_X28,
91     PERF_REG_ARM64_X29,
92     PERF_REG_ARM64_LR,
93     PERF_REG_ARM64_SP,
94     PERF_REG_ARM64_PC,
95     PERF_REG_ARM64_MAX,
96 };
97 
98 enum perf_event_arm_regs {
99     PERF_REG_ARM_R0,
100     PERF_REG_ARM_R1,
101     PERF_REG_ARM_R2,
102     PERF_REG_ARM_R3,
103     PERF_REG_ARM_R4,
104     PERF_REG_ARM_R5,
105     PERF_REG_ARM_R6,
106     PERF_REG_ARM_R7,
107     PERF_REG_ARM_R8,
108     PERF_REG_ARM_R9,
109     PERF_REG_ARM_R10,
110     PERF_REG_ARM_FP = 11,
111     PERF_REG_ARM_IP = 12,
112     PERF_REG_ARM_SP = 13,
113     PERF_REG_ARM_LR = 14,
114     PERF_REG_ARM_PC = 15,
115     PERF_REG_ARM_MAX,
116 };
117 
118 // order is IP , SP for ut
119 static const std::map<size_t, const std::string> PERF_REG_NAME_MAP = {
120 #if defined(target_cpu_x86_64)
121     {PERF_REG_X86_IP, "PERF_REG_X86_IP"},
122     {PERF_REG_X86_SP, "PERF_REG_X86_SP"},
123 #elif defined(target_cpu_arm)
124     {PERF_REG_ARM_PC, "PERF_REG_ARM_PC"},
125     {PERF_REG_ARM_SP, "PERF_REG_ARM_SP"},
126 #elif defined(target_cpu_arm64)
127     {PERF_REG_ARM64_PC, "PERF_REG_ARM64_PC"},
128     {PERF_REG_ARM64_SP, "PERF_REG_ARM64_SP"},
129 #endif
130 };
131 
132 // context name
133 static const std::map<uint64_t, const std::string> PERF_CONTEXT_NAME = {
134     {PERF_CONTEXT_HV, "PERF_CONTEXT_HV"},
135     {PERF_CONTEXT_KERNEL, "PERF_CONTEXT_KERNEL"},
136     {PERF_CONTEXT_USER, "PERF_CONTEXT_USER"},
137     {PERF_CONTEXT_GUEST, "PERF_CONTEXT_GUEST"},
138     {PERF_CONTEXT_GUEST_KERNEL, "PERF_CONTEXT_GUEST_KERNEL"},
139     {PERF_CONTEXT_GUEST_USER, "PERF_CONTEXT_GUEST_USER"},
140     {PERF_CONTEXT_MAX, "PERF_CONTEXT_MAX"},
141 };
142 
143 #if defined(target_cpu_x86_64)
144 constexpr ArchType buildArchType = ArchType::ARCH_X86_64;
145 #elif defined(target_cpu_arm64)
146 constexpr ArchType buildArchType = ArchType::ARCH_ARM64;
147 #elif defined(target_cpu_arm)
148 constexpr ArchType buildArchType = ArchType::ARCH_ARM;
149 #else
150 #error NOT SUPPORT ARCH
151 #endif
152 
153 const std::string UpdatePerfContext(uint64_t addr, perf_callchain_context &perfCallchainContext);
154 
155 uint64_t GetSupportedRegMask(ArchType arch);
156 
157 // this is only for debug
158 const std::string RegisterGetName(size_t registerIndex);
159 
160 size_t RegisterGetCount();
161 
162 size_t RegisterGetSP(ArchType arch);
163 
GetArchName(ArchType arch)164 inline const std::string GetArchName(ArchType arch)
165 {
166     switch (arch) {
167         case ArchType::ARCH_X86:
168             return "X86_32";
169         case ArchType::ARCH_X86_64:
170             return "X86_64";
171         case ArchType::ARCH_ARM:
172             return "ARM";
173         case ArchType::ARCH_ARM64:
174             return "ARM64";
175         default:
176             return "Unsupport";
177     }
178 }
179 
180 size_t RegisterGetIP(ArchType arch);
181 
RegisterGetCount()182 inline size_t RegisterGetCount()
183 {
184     switch (buildArchType) {
185         case ArchType::ARCH_X86:
186             return PERF_REG_X86_32_MAX;
187         case ArchType::ARCH_X86_64:
188             return PERF_REG_X86_64_MAX;
189         case ArchType::ARCH_ARM:
190             return PERF_REG_ARM_MAX;
191         case ArchType::ARCH_ARM64:
192             return PERF_REG_ARM64_MAX;
193         default: {
194             HLOGM("Registers in an unknown CPU.");
195             return std::numeric_limits<size_t>::max();
196         }
197     }
198 }
199 
RegisterGetValue(uint64_t &value, const u64 registers[], const size_t registerIndex, const size_t registerNumber)200 inline bool RegisterGetValue(uint64_t &value, const u64 registers[], const size_t registerIndex,
201     const size_t registerNumber)
202 {
203     if (registerIndex >= registerNumber) {
204         HLOGE("registerIndex is %zu, max is %zu", registerIndex, registerNumber);
205         return false;
206     }
207     value = registers[registerIndex];
208     return true;
209 }
210 
RegisterGetSPValue(uint64_t &value, ArchType arch, const u64 registers[], const size_t registerNumber)211 inline bool RegisterGetSPValue(uint64_t &value, ArchType arch, const u64 registers[],
212                                const size_t registerNumber)
213 {
214     return RegisterGetValue(value, registers, RegisterGetSP(arch), registerNumber);
215 }
216 
RegisterGetIPValue(uint64_t &value, ArchType arch, const u64 registers[], const size_t registerNumber)217 inline bool RegisterGetIPValue(uint64_t &value, ArchType arch, const u64 registers[],
218                                const size_t registerNumber)
219 {
220     return RegisterGetValue(value, registers, RegisterGetIP(arch), registerNumber);
221 }
222 
223 int LibunwindRegIdToPerfReg(int regnum);
224 
225 ArchType GetDeviceArch();
226 ArchType SetDeviceArch(ArchType arch);
227 ArchType GetArchTypeFromUname(const std::string &machine);
228 ArchType GetArchTypeFromABI(bool abi32);
229 void UpdateRegForABI(ArchType arch, u64 registers[]);
230 } // namespace NativeDaemon
231 } // namespace Developtools
232 } // namespace OHOS
233 #endif