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 27namespace OHOS { 28namespace Developtools { 29namespace HiPerf { 30static ArchType g_deviceArchType = ArchType::ARCH_UNKNOWN; 31// order is IP , SP for ut 32static 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 46uint64_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 73const 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 114int 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 125const 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 136const 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 152size_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 167size_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 182const 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 195bool 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 206ArchType 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 226ArchType 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 241ArchType 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 248ArchType 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 273void 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