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