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
16 // for libunwind.h empty struct has size 0 in c, size 1 in c++
17 #include "register.h"
18 #if !is_mingw
19 #include <sys/utsname.h>
20 #endif
21 #if HAVE_LIBUNWIND
22 #include <libunwind.h>
23 #endif
24 #include "debug_logger.h"
25
26
27 namespace OHOS {
28 namespace Developtools {
29 namespace HiPerf {
30 static ArchType g_deviceArchType = ArchType::ARCH_UNKNOWN;
31 // order is IP , SP for ut
32 static const std::map<size_t, const std::string> PERF_REG_NAME_MAP = {
33 #if defined(target_cpu_x86_64)
34 {PERF_REG_X86_IP, "PERF_REG_X86_IP"},
35 {PERF_REG_X86_SP, "PERF_REG_X86_SP"},
36 #elif defined(target_cpu_arm)
37 {PERF_REG_ARM_PC, "PERF_REG_ARM_PC"},
38 {PERF_REG_ARM_SP, "PERF_REG_ARM_SP"},
39 #elif defined(target_cpu_arm64)
40 {PERF_REG_ARM64_PC, "PERF_REG_ARM64_PC"},
41 {PERF_REG_ARM64_SP, "PERF_REG_ARM64_SP"},
42 #endif
43 };
44
45 // these copy from kerne uapi perf_regs.h
GetSupportedRegMask(ArchType arch)46 uint64_t GetSupportedRegMask(ArchType arch)
47 {
48 uint64_t result = 0;
49 switch (arch) {
50 case ArchType::ARCH_X86:
51 result = ((1ULL << PERF_REG_X86_32_MAX) - 1);
52 break;
53 case ArchType::ARCH_X86_64:
54 result = ((1ULL << PERF_REG_X86_64_MAX) - 1);
55 result &= ~((1ULL << PERF_REG_X86_DS) | (1ULL << PERF_REG_X86_ES) |
56 (1ULL << PERF_REG_X86_FS) | (1ULL << PERF_REG_X86_GS));
57 break;
58 case ArchType::ARCH_ARM:
59 result = ((1ULL << PERF_REG_ARM_MAX) - 1);
60 break;
61 case ArchType::ARCH_ARM64:
62 result = ((1ULL << PERF_REG_ARM64_MAX) - 1);
63 break;
64 default:
65 result = std::numeric_limits<uint64_t>::max();
66 HLOGE("unsupport arch %d", arch);
67 break;
68 }
69 return result;
70 }
71
72 #if HAVE_LIBUNWIND
73 const std::map<int, int> LibUnwindRegMap = {
74 #if defined(target_cpu_x86_64)
75 {UNW_X86_64_RAX, PERF_REG_X86_AX}, {UNW_X86_64_RDX, PERF_REG_X86_DX},
76 {UNW_X86_64_RCX, PERF_REG_X86_CX}, {UNW_X86_64_RBX, PERF_REG_X86_BX},
77 {UNW_X86_64_RSI, PERF_REG_X86_SI}, {UNW_X86_64_RDI, PERF_REG_X86_DI},
78 {UNW_X86_64_RBP, PERF_REG_X86_BP}, {UNW_X86_64_RSP, PERF_REG_X86_SP},
79 {UNW_X86_64_R8, PERF_REG_X86_R8}, {UNW_X86_64_R9, PERF_REG_X86_R9},
80 {UNW_X86_64_R10, PERF_REG_X86_R10}, {UNW_X86_64_R11, PERF_REG_X86_R11},
81 {UNW_X86_64_R12, PERF_REG_X86_R12}, {UNW_X86_64_R13, PERF_REG_X86_R13},
82 {UNW_X86_64_R14, PERF_REG_X86_R14}, {UNW_X86_64_R15, PERF_REG_X86_R15},
83 {UNW_X86_64_RIP, PERF_REG_X86_IP},
84 #elif defined(target_cpu_arm64)
85 {UNW_AARCH64_X0, PERF_REG_ARM64_X0}, {UNW_AARCH64_X1, PERF_REG_ARM64_X1},
86 {UNW_AARCH64_X2, PERF_REG_ARM64_X2}, {UNW_AARCH64_X3, PERF_REG_ARM64_X3},
87 {UNW_AARCH64_X4, PERF_REG_ARM64_X4}, {UNW_AARCH64_X5, PERF_REG_ARM64_X5},
88 {UNW_AARCH64_X6, PERF_REG_ARM64_X6}, {UNW_AARCH64_X7, PERF_REG_ARM64_X7},
89 {UNW_AARCH64_X8, PERF_REG_ARM64_X8}, {UNW_AARCH64_X9, PERF_REG_ARM64_X9},
90 {UNW_AARCH64_X10, PERF_REG_ARM64_X10}, {UNW_AARCH64_X11, PERF_REG_ARM64_X11},
91 {UNW_AARCH64_X12, PERF_REG_ARM64_X12}, {UNW_AARCH64_X13, PERF_REG_ARM64_X13},
92 {UNW_AARCH64_X14, PERF_REG_ARM64_X14}, {UNW_AARCH64_X15, PERF_REG_ARM64_X15},
93 {UNW_AARCH64_X16, PERF_REG_ARM64_X16}, {UNW_AARCH64_X17, PERF_REG_ARM64_X17},
94 {UNW_AARCH64_X18, PERF_REG_ARM64_X18}, {UNW_AARCH64_X19, PERF_REG_ARM64_X19},
95 {UNW_AARCH64_X20, PERF_REG_ARM64_X20}, {UNW_AARCH64_X21, PERF_REG_ARM64_X21},
96 {UNW_AARCH64_X22, PERF_REG_ARM64_X22}, {UNW_AARCH64_X23, PERF_REG_ARM64_X23},
97 {UNW_AARCH64_X24, PERF_REG_ARM64_X24}, {UNW_AARCH64_X25, PERF_REG_ARM64_X25},
98 {UNW_AARCH64_X26, PERF_REG_ARM64_X26}, {UNW_AARCH64_X27, PERF_REG_ARM64_X27},
99 {UNW_AARCH64_X28, PERF_REG_ARM64_X28}, {UNW_AARCH64_X29, PERF_REG_ARM64_X29},
100 {UNW_AARCH64_X30, PERF_REG_ARM64_LR}, {UNW_AARCH64_SP, PERF_REG_ARM64_SP},
101 {UNW_AARCH64_PC, PERF_REG_ARM64_PC},
102 #elif defined(target_cpu_arm)
103 {UNW_ARM_R0, PERF_REG_ARM_R0}, {UNW_ARM_R1, PERF_REG_ARM_R1}, {UNW_ARM_R2, PERF_REG_ARM_R2},
104 {UNW_ARM_R3, PERF_REG_ARM_R3}, {UNW_ARM_R4, PERF_REG_ARM_R4}, {UNW_ARM_R5, PERF_REG_ARM_R5},
105 {UNW_ARM_R6, PERF_REG_ARM_R6}, {UNW_ARM_R7, PERF_REG_ARM_R7}, {UNW_ARM_R8, PERF_REG_ARM_R8},
106 {UNW_ARM_R9, PERF_REG_ARM_R9}, {UNW_ARM_R10, PERF_REG_ARM_R10}, {UNW_ARM_R11, PERF_REG_ARM_FP},
107 {UNW_ARM_R12, PERF_REG_ARM_IP}, {UNW_ARM_R13, PERF_REG_ARM_SP}, {UNW_ARM_R14, PERF_REG_ARM_LR},
108 {UNW_ARM_R15, PERF_REG_ARM_PC},
109 #else
110 #error not support
111 #endif
112 };
113
LibunwindRegIdToPerfReg(int libUnwindReg)114 int LibunwindRegIdToPerfReg(int libUnwindReg)
115 {
116 if (LibUnwindRegMap.count(libUnwindReg)) {
117 return LibUnwindRegMap.at(libUnwindReg);
118 } else {
119 HLOGE("unwind: invalid reg id %d", libUnwindReg);
120 return -EINVAL;
121 }
122 }
123 #endif
124
UpdatePerfContext(uint64_t addr,perf_callchain_context & perfCallchainContext)125 const std::string UpdatePerfContext(uint64_t addr, perf_callchain_context &perfCallchainContext)
126 {
127 if (PERF_CONTEXT_NAME.count(addr) != 0) {
128 perfCallchainContext = static_cast<perf_callchain_context>(addr);
129 return StringPrintf("%s: %" PRIx64 "", PERF_CONTEXT_NAME.at(addr).c_str(), addr);
130 } else {
131 perfCallchainContext = PERF_CONTEXT_MAX;
132 return StringPrintf("unknow context: %" PRIx64 "", addr);
133 }
134 }
135
GetArchName(ArchType arch)136 const std::string GetArchName(ArchType arch)
137 {
138 switch (arch) {
139 case ArchType::ARCH_X86:
140 return "X86_32";
141 case ArchType::ARCH_X86_64:
142 return "X86_64";
143 case ArchType::ARCH_ARM:
144 return "ARM";
145 case ArchType::ARCH_ARM64:
146 return "ARM64";
147 default:
148 return "Unsupport";
149 }
150 }
151
RegisterGetIP(ArchType arch)152 size_t RegisterGetIP(ArchType arch)
153 {
154 switch (arch) {
155 case ArchType::ARCH_X86:
156 case ArchType::ARCH_X86_64:
157 return PERF_REG_X86_IP;
158 case ArchType::ARCH_ARM:
159 return PERF_REG_ARM_PC;
160 case ArchType::ARCH_ARM64:
161 return PERF_REG_ARM64_PC;
162 default:
163 return std::numeric_limits<size_t>::max();
164 }
165 }
166
RegisterGetSP(ArchType arch)167 size_t RegisterGetSP(ArchType arch)
168 {
169 switch (arch) {
170 case ArchType::ARCH_X86:
171 case ArchType::ARCH_X86_64:
172 return PERF_REG_X86_SP;
173 case ArchType::ARCH_ARM:
174 return PERF_REG_ARM_SP;
175 case ArchType::ARCH_ARM64:
176 return PERF_REG_ARM64_SP;
177 default:
178 return std::numeric_limits<size_t>::max();
179 }
180 }
181
RegisterGetName(size_t registerIndex)182 const std::string RegisterGetName(size_t registerIndex)
183 {
184 std::string name;
185 name.append("PerfReg[");
186 name.append(std::to_string(registerIndex));
187 if (PERF_REG_NAME_MAP.count(registerIndex) > 0) {
188 name.append(":");
189 name.append(PERF_REG_NAME_MAP.at(registerIndex));
190 }
191 name.append("]");
192 return name;
193 }
194
RegisterGetValue(uint64_t & value,const u64 registers[],const size_t registerIndex,const size_t registerNumber)195 bool RegisterGetValue(uint64_t &value, const u64 registers[], const size_t registerIndex,
196 const size_t registerNumber)
197 {
198 if (registerIndex >= registerNumber) {
199 HLOGE("registerIndex is %zu, max is %zu", registerIndex, registerNumber);
200 return false;
201 }
202 value = registers[registerIndex];
203 return true;
204 }
205
GetArchTypeFromUname(const std::string & machine)206 ArchType GetArchTypeFromUname(const std::string &machine)
207 {
208 if (StringStartsWith(machine, "arm")) {
209 if (machine == "armv8l") {
210 // 32 bit elf run in 64 bit cpu
211 return ArchType::ARCH_ARM64;
212 }
213 return ArchType::ARCH_ARM;
214 } else if (machine == "aarch64") {
215 return ArchType::ARCH_ARM64;
216 } else if (machine == "x86_64") {
217 return ArchType::ARCH_X86_64;
218 } else if (machine == "x86" || machine == "i686") {
219 return ArchType::ARCH_X86;
220 } else {
221 HLOGE("unsupport machine %s", machine.c_str());
222 return ArchType::ARCH_UNKNOWN;
223 }
224 }
225
GetArchTypeFromABI(bool abi32)226 ArchType GetArchTypeFromABI(bool abi32)
227 {
228 if (g_deviceArchType == ArchType::ARCH_UNKNOWN) {
229 g_deviceArchType = GetDeviceArch();
230 }
231 if (abi32) {
232 if (g_deviceArchType == ArchType::ARCH_ARM64) {
233 return ArchType::ARCH_ARM;
234 } else if (g_deviceArchType == ArchType::ARCH_X86_64) {
235 return ArchType::ARCH_X86;
236 }
237 }
238 return g_deviceArchType;
239 }
240
SetDeviceArch(ArchType arch)241 ArchType SetDeviceArch(ArchType arch)
242 {
243 HLOGD("g_deviceArchType change to %s", GetArchName(arch).c_str());
244 g_deviceArchType = arch;
245 return g_deviceArchType;
246 }
247
GetDeviceArch()248 ArchType GetDeviceArch()
249 {
250 #if defined(is_mingw) && is_mingw
251 return g_deviceArchType;
252 #else
253 if (g_deviceArchType != ArchType::ARCH_UNKNOWN) {
254 return g_deviceArchType;
255 } else {
256 utsname systemName;
257 if ((uname(&systemName)) != 0) {
258 // fallback
259 g_deviceArchType = BUILD_ARCH_TYPE;
260 } else {
261 g_deviceArchType = GetArchTypeFromUname(systemName.machine);
262 HLOGD("machine arch is %s : %s", systemName.machine,
263 GetArchName(g_deviceArchType).c_str());
264 if (g_deviceArchType == ArchType::ARCH_UNKNOWN) {
265 g_deviceArchType = BUILD_ARCH_TYPE;
266 }
267 }
268 }
269 return g_deviceArchType;
270 #endif
271 }
272
UpdateRegForABI(ArchType arch,u64 * regs)273 void UpdateRegForABI(ArchType arch, u64 *regs)
274 {
275 if (g_deviceArchType == ArchType::ARCH_ARM64 and arch == ArchType::ARCH_ARM) {
276 // arm in arm64
277 regs[PERF_REG_ARM_PC] = regs[PERF_REG_ARM64_PC];
278 }
279 }
280 } // namespace HiPerf
281 } // namespace Developtools
282 } // namespace OHOS
283