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 #include "debug_logger.h"
22
23
24 namespace OHOS {
25 namespace Developtools {
26 namespace HiPerf {
27 static ArchType g_deviceArchType = ArchType::ARCH_UNKNOWN;
28 // order is IP , SP for ut
29 static const std::map<size_t, const std::string> PERF_REG_NAME_MAP = {
30 #if defined(target_cpu_x86_64)
31 {PERF_REG_X86_IP, "PERF_REG_X86_IP"},
32 {PERF_REG_X86_SP, "PERF_REG_X86_SP"},
33 #elif defined(target_cpu_arm)
34 {PERF_REG_ARM_PC, "PERF_REG_ARM_PC"},
35 {PERF_REG_ARM_SP, "PERF_REG_ARM_SP"},
36 #elif defined(target_cpu_arm64)
37 {PERF_REG_ARM64_PC, "PERF_REG_ARM64_PC"},
38 {PERF_REG_ARM64_SP, "PERF_REG_ARM64_SP"},
39 #endif
40 };
41
42 // these copy from kerne uapi perf_regs.h
GetSupportedRegMask(ArchType arch)43 uint64_t GetSupportedRegMask(ArchType arch)
44 {
45 uint64_t result = 0;
46 switch (arch) {
47 case ArchType::ARCH_X86:
48 result = ((1ULL << PERF_REG_X86_32_MAX) - 1);
49 break;
50 case ArchType::ARCH_X86_64:
51 result = ((1ULL << PERF_REG_X86_64_MAX) - 1);
52 result &= ~((1ULL << PERF_REG_X86_DS) | (1ULL << PERF_REG_X86_ES) |
53 (1ULL << PERF_REG_X86_FS) | (1ULL << PERF_REG_X86_GS));
54 break;
55 case ArchType::ARCH_ARM:
56 result = ((1ULL << PERF_REG_ARM_MAX) - 1);
57 break;
58 case ArchType::ARCH_ARM64:
59 result = ((1ULL << PERF_REG_ARM64_MAX) - 1);
60 break;
61 default:
62 result = std::numeric_limits<uint64_t>::max();
63 HLOGE("unsupport arch %u", arch);
64 break;
65 }
66 return result;
67 }
68
UpdatePerfContext(uint64_t addr,perf_callchain_context & perfCallchainContext)69 const std::string UpdatePerfContext(uint64_t addr, perf_callchain_context &perfCallchainContext)
70 {
71 if (PERF_CONTEXT_NAME.count(addr) != 0) {
72 perfCallchainContext = static_cast<perf_callchain_context>(addr);
73 return StringPrintf("%s: %" PRIx64 "", PERF_CONTEXT_NAME.at(addr).c_str(), addr);
74 } else {
75 perfCallchainContext = PERF_CONTEXT_MAX;
76 return StringPrintf("unknow context: %" PRIx64 "", addr);
77 }
78 }
79
GetArchName(ArchType arch)80 const std::string GetArchName(ArchType arch)
81 {
82 switch (arch) {
83 case ArchType::ARCH_X86:
84 return "X86_32";
85 case ArchType::ARCH_X86_64:
86 return "X86_64";
87 case ArchType::ARCH_ARM:
88 return "ARM";
89 case ArchType::ARCH_ARM64:
90 return "ARM64";
91 default:
92 return "Unsupport";
93 }
94 }
95
RegisterGetIP(ArchType arch)96 size_t RegisterGetIP(ArchType arch)
97 {
98 switch (arch) {
99 case ArchType::ARCH_X86:
100 case ArchType::ARCH_X86_64:
101 return PERF_REG_X86_IP;
102 case ArchType::ARCH_ARM:
103 return PERF_REG_ARM_PC;
104 case ArchType::ARCH_ARM64:
105 return PERF_REG_ARM64_PC;
106 default:
107 return std::numeric_limits<size_t>::max();
108 }
109 }
110
RegisterGetSP(ArchType arch)111 size_t RegisterGetSP(ArchType arch)
112 {
113 switch (arch) {
114 case ArchType::ARCH_X86:
115 case ArchType::ARCH_X86_64:
116 return PERF_REG_X86_SP;
117 case ArchType::ARCH_ARM:
118 return PERF_REG_ARM_SP;
119 case ArchType::ARCH_ARM64:
120 return PERF_REG_ARM64_SP;
121 default:
122 return std::numeric_limits<size_t>::max();
123 }
124 }
125
RegisterGetName(size_t registerIndex)126 const std::string RegisterGetName(size_t registerIndex)
127 {
128 std::string name;
129 name.append("PerfReg[");
130 name.append(std::to_string(registerIndex));
131 if (PERF_REG_NAME_MAP.count(registerIndex) > 0) {
132 name.append(":");
133 name.append(PERF_REG_NAME_MAP.at(registerIndex));
134 }
135 name.append("]");
136 return name;
137 }
138
RegisterGetValue(uint64_t & value,const u64 registers[],const size_t registerIndex,const size_t registerNumber)139 bool RegisterGetValue(uint64_t &value, const u64 registers[], const size_t registerIndex,
140 const size_t registerNumber)
141 {
142 if (registerIndex >= registerNumber) {
143 HLOGE("registerIndex is %zu, max is %zu", registerIndex, registerNumber);
144 return false;
145 }
146 value = registers[registerIndex];
147 return true;
148 }
149
GetArchTypeFromUname(const std::string & machine)150 ArchType GetArchTypeFromUname(const std::string &machine)
151 {
152 if (StringStartsWith(machine, "arm")) {
153 if (machine == "armv8l") {
154 // 32 bit elf run in 64 bit cpu
155 return ArchType::ARCH_ARM64;
156 }
157 return ArchType::ARCH_ARM;
158 } else if (machine == "aarch64") {
159 return ArchType::ARCH_ARM64;
160 } else if (machine == "x86_64") {
161 return ArchType::ARCH_X86_64;
162 } else if (machine == "x86" || machine == "i686") {
163 return ArchType::ARCH_X86;
164 } else {
165 HLOGE("unsupport machine %s", machine.c_str());
166 return ArchType::ARCH_UNKNOWN;
167 }
168 }
169
GetArchTypeFromABI(bool abi32)170 ArchType GetArchTypeFromABI(bool abi32)
171 {
172 if (g_deviceArchType == ArchType::ARCH_UNKNOWN) {
173 g_deviceArchType = GetDeviceArch();
174 }
175 if (abi32) {
176 if (g_deviceArchType == ArchType::ARCH_ARM64) {
177 return ArchType::ARCH_ARM;
178 } else if (g_deviceArchType == ArchType::ARCH_X86_64) {
179 return ArchType::ARCH_X86;
180 }
181 }
182 return g_deviceArchType;
183 }
184
SetDeviceArch(ArchType arch)185 ArchType SetDeviceArch(ArchType arch)
186 {
187 HLOGD("g_deviceArchType change to %s", GetArchName(arch).c_str());
188 g_deviceArchType = arch;
189 return g_deviceArchType;
190 }
191
GetDeviceArch()192 ArchType GetDeviceArch()
193 {
194 #if defined(is_mingw) && is_mingw
195 return g_deviceArchType;
196 #else
197 if (g_deviceArchType != ArchType::ARCH_UNKNOWN) {
198 return g_deviceArchType;
199 } else {
200 utsname systemName;
201 if ((uname(&systemName)) != 0) {
202 // fallback
203 g_deviceArchType = BUILD_ARCH_TYPE;
204 } else {
205 g_deviceArchType = GetArchTypeFromUname(systemName.machine);
206 HLOGD("machine arch is %s : %s", systemName.machine,
207 GetArchName(g_deviceArchType).c_str());
208 if (g_deviceArchType == ArchType::ARCH_UNKNOWN) {
209 g_deviceArchType = BUILD_ARCH_TYPE;
210 }
211 }
212 }
213 return g_deviceArchType;
214 #endif
215 }
216
UpdateRegForABI(ArchType arch,u64 * regs)217 void UpdateRegForABI(ArchType arch, u64 *regs)
218 {
219 if (g_deviceArchType == ArchType::ARCH_ARM64 && arch == ArchType::ARCH_ARM) {
220 // arm in arm64
221 regs[PERF_REG_ARM_PC] = regs[PERF_REG_ARM64_PC];
222 }
223 }
224 } // namespace HiPerf
225 } // namespace Developtools
226 } // namespace OHOS
227