1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "perf_regs.h" 18 19 #include <string.h> 20 21 #include <android-base/logging.h> 22 #include <android-base/stringprintf.h> 23 #include <android-base/strings.h> 24 #include <unordered_map> 25 26 #include "perf_event.h" 27 28 namespace simpleperf { 29 30 ArchType ScopedCurrentArch::current_arch = ARCH_UNSUPPORTED; 31 GetArchType(const std::string & arch)32 ArchType GetArchType(const std::string& arch) { 33 if (arch == "x86" || arch == "i686") { 34 return ARCH_X86_32; 35 } else if (arch == "x86_64") { 36 return ARCH_X86_64; 37 } else if (arch == "riscv64") { 38 return ARCH_RISCV64; 39 } else if (arch == "aarch64") { 40 return ARCH_ARM64; 41 } else if (android::base::StartsWith(arch, "arm")) { 42 // If arch is "armv8l", it is likely that we are using a 32-bit simpleperf 43 // binary on a aarch64 device. In this case, the profiling environment is 44 // ARCH_ARM64, because the kernel is aarch64. 45 if (arch[3] == 'v') { 46 int version = atoi(&arch[4]); 47 if (version >= 8) { 48 return ARCH_ARM64; 49 } 50 } 51 return ARCH_ARM; 52 } 53 LOG(ERROR) << "unsupported arch: " << arch; 54 return ARCH_UNSUPPORTED; 55 } 56 GetArchForAbi(ArchType machine_arch,int abi)57 ArchType GetArchForAbi(ArchType machine_arch, int abi) { 58 if (abi == PERF_SAMPLE_REGS_ABI_32) { 59 if (machine_arch == ARCH_X86_64) { 60 return ARCH_X86_32; 61 } 62 if (machine_arch == ARCH_ARM64) { 63 return ARCH_ARM; 64 } 65 } else if (abi == PERF_SAMPLE_REGS_ABI_64) { 66 if (machine_arch == ARCH_X86_32) { 67 return ARCH_X86_64; 68 } 69 if (machine_arch == ARCH_ARM) { 70 return ARCH_ARM64; 71 } 72 } 73 return machine_arch; 74 } 75 GetArchString(ArchType arch)76 std::string GetArchString(ArchType arch) { 77 switch (arch) { 78 case ARCH_X86_32: 79 return "x86"; 80 case ARCH_X86_64: 81 return "x86_64"; 82 case ARCH_ARM64: 83 return "arm64"; 84 case ARCH_ARM: 85 return "arm"; 86 case ARCH_RISCV64: 87 return "riscv64"; 88 default: 89 break; 90 } 91 return "unknown"; 92 } 93 GetSupportedRegMask(ArchType arch)94 uint64_t GetSupportedRegMask(ArchType arch) { 95 switch (arch) { 96 case ARCH_X86_32: 97 return ((1ULL << PERF_REG_X86_32_MAX) - 1) & ~(1ULL << PERF_REG_X86_DS) & 98 ~(1ULL << PERF_REG_X86_ES) & ~(1ULL << PERF_REG_X86_FS) & ~(1ULL << PERF_REG_X86_GS); 99 case ARCH_X86_64: 100 return (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~(1ULL << PERF_REG_X86_DS) & 101 ~(1ULL << PERF_REG_X86_ES) & ~(1ULL << PERF_REG_X86_FS) & ~(1ULL << PERF_REG_X86_GS)); 102 case ARCH_ARM: 103 return ((1ULL << PERF_REG_ARM_MAX) - 1); 104 case ARCH_ARM64: 105 return ((1ULL << PERF_REG_ARM64_MAX) - 1); 106 case ARCH_RISCV64: 107 return ((1ULL << PERF_REG_RISCV_MAX) - 1); 108 default: 109 return 0; 110 } 111 return 0; 112 } 113 114 static std::unordered_map<size_t, std::string> x86_reg_map = { 115 {PERF_REG_X86_AX, "ax"}, {PERF_REG_X86_BX, "bx"}, {PERF_REG_X86_CX, "cx"}, 116 {PERF_REG_X86_DX, "dx"}, {PERF_REG_X86_SI, "si"}, {PERF_REG_X86_DI, "di"}, 117 {PERF_REG_X86_BP, "bp"}, {PERF_REG_X86_SP, "sp"}, {PERF_REG_X86_IP, "ip"}, 118 {PERF_REG_X86_FLAGS, "flags"}, {PERF_REG_X86_CS, "cs"}, {PERF_REG_X86_SS, "ss"}, 119 {PERF_REG_X86_DS, "ds"}, {PERF_REG_X86_ES, "es"}, {PERF_REG_X86_FS, "fs"}, 120 {PERF_REG_X86_GS, "gs"}, 121 }; 122 123 static std::unordered_map<size_t, std::string> arm_reg_map = { 124 {PERF_REG_ARM_FP, "fp"}, {PERF_REG_ARM_IP, "ip"}, {PERF_REG_ARM_SP, "sp"}, 125 {PERF_REG_ARM_LR, "lr"}, {PERF_REG_ARM_PC, "pc"}, 126 }; 127 128 static std::unordered_map<size_t, std::string> arm64_reg_map = { 129 {PERF_REG_ARM64_LR, "lr"}, 130 {PERF_REG_ARM64_SP, "sp"}, 131 {PERF_REG_ARM64_PC, "pc"}, 132 }; 133 134 static std::unordered_map<size_t, std::string> riscv64_reg_map = { 135 {PERF_REG_RISCV_PC, "pc"}, 136 {PERF_REG_RISCV_RA, "ra"}, 137 {PERF_REG_RISCV_SP, "sp"}, 138 {PERF_REG_RISCV_GP, "gp"}, 139 {PERF_REG_RISCV_TP, "tp"}, 140 {PERF_REG_RISCV_T0, "t0"}, 141 {PERF_REG_RISCV_T1, "t1"}, 142 {PERF_REG_RISCV_T2, "t2"}, 143 {PERF_REG_RISCV_S0, "s0"}, 144 {PERF_REG_RISCV_S1, "s1"}, 145 {PERF_REG_RISCV_A0, "a0"}, 146 {PERF_REG_RISCV_A1, "a1"}, 147 {PERF_REG_RISCV_A2, "a2"}, 148 {PERF_REG_RISCV_A3, "a3"}, 149 {PERF_REG_RISCV_A4, "a4"}, 150 {PERF_REG_RISCV_A5, "a5"}, 151 {PERF_REG_RISCV_A6, "a6"}, 152 {PERF_REG_RISCV_A7, "a7"}, 153 {PERF_REG_RISCV_S2, "s2"}, 154 {PERF_REG_RISCV_S3, "s3"}, 155 {PERF_REG_RISCV_S4, "s4"}, 156 {PERF_REG_RISCV_S5, "s5"}, 157 {PERF_REG_RISCV_S6, "s6"}, 158 {PERF_REG_RISCV_S7, "s7"}, 159 {PERF_REG_RISCV_S8, "s8"}, 160 {PERF_REG_RISCV_S9, "s9"}, 161 {PERF_REG_RISCV_S10, "s10"}, 162 {PERF_REG_RISCV_S11, "s11"}, 163 {PERF_REG_RISCV_T3, "t3"}, 164 {PERF_REG_RISCV_T4, "t4"}, 165 {PERF_REG_RISCV_T5, "t5"}, 166 {PERF_REG_RISCV_T6, "t6"}, 167 }; 168 GetRegName(size_t regno,ArchType arch)169 std::string GetRegName(size_t regno, ArchType arch) { 170 // Cast regno to int type to avoid -Werror=type-limits. 171 int reg = static_cast<int>(regno); 172 switch (arch) { 173 case ARCH_X86_64: { 174 if (reg >= PERF_REG_X86_R8 && reg <= PERF_REG_X86_R15) { 175 return android::base::StringPrintf("r%d", reg - PERF_REG_X86_R8 + 8); 176 } 177 FALLTHROUGH_INTENDED; 178 } 179 case ARCH_X86_32: { 180 auto it = x86_reg_map.find(reg); 181 CHECK(it != x86_reg_map.end()) << "unknown reg " << reg; 182 return it->second; 183 } 184 case ARCH_ARM: { 185 if (reg >= PERF_REG_ARM_R0 && reg <= PERF_REG_ARM_R10) { 186 return android::base::StringPrintf("r%d", reg - PERF_REG_ARM_R0); 187 } 188 if (auto it = arm_reg_map.find(reg); it != arm_reg_map.end()) { 189 return it->second; 190 } 191 FALLTHROUGH_INTENDED; 192 } 193 case ARCH_ARM64: { 194 if (reg >= PERF_REG_ARM64_X0 && reg <= PERF_REG_ARM64_X29) { 195 return android::base::StringPrintf("r%d", reg - PERF_REG_ARM64_X0); 196 } 197 auto it = arm64_reg_map.find(reg); 198 CHECK(it != arm64_reg_map.end()) << "unknown reg " << reg; 199 return it->second; 200 } 201 case ARCH_RISCV64: { 202 auto it = riscv64_reg_map.find(reg); 203 CHECK(it != riscv64_reg_map.end()) << "unknown reg " << reg; 204 return it->second; 205 } 206 default: 207 return "unknown"; 208 } 209 } 210 RegSet(int abi,uint64_t valid_mask,const uint64_t * valid_regs)211 RegSet::RegSet(int abi, uint64_t valid_mask, const uint64_t* valid_regs) : valid_mask(valid_mask) { 212 arch = GetArchForAbi(ScopedCurrentArch::GetCurrentArch(), abi); 213 memset(data, 0, sizeof(data)); 214 for (int i = 0, j = 0; i < 64; ++i) { 215 if ((valid_mask >> i) & 1) { 216 data[i] = valid_regs[j++]; 217 } 218 } 219 if (ScopedCurrentArch::GetCurrentArch() == ARCH_ARM64 && abi == PERF_SAMPLE_REGS_ABI_32) { 220 // The kernel dumps arm64 regs, but we need arm regs. So map arm64 regs into arm regs. 221 data[PERF_REG_ARM_PC] = data[PERF_REG_ARM64_PC]; 222 } 223 } 224 GetRegValue(size_t regno,uint64_t * value) const225 bool RegSet::GetRegValue(size_t regno, uint64_t* value) const { 226 CHECK_LT(regno, 64U); 227 if ((valid_mask >> regno) & 1) { 228 *value = data[regno]; 229 return true; 230 } 231 return false; 232 } 233 GetSpRegValue(uint64_t * value) const234 bool RegSet::GetSpRegValue(uint64_t* value) const { 235 size_t regno; 236 switch (arch) { 237 case ARCH_X86_32: 238 regno = PERF_REG_X86_SP; 239 break; 240 case ARCH_X86_64: 241 regno = PERF_REG_X86_SP; 242 break; 243 case ARCH_ARM: 244 regno = PERF_REG_ARM_SP; 245 break; 246 case ARCH_ARM64: 247 regno = PERF_REG_ARM64_SP; 248 break; 249 case ARCH_RISCV64: 250 regno = PERF_REG_RISCV_SP; 251 break; 252 default: 253 return false; 254 } 255 return GetRegValue(regno, value); 256 } 257 GetIpRegValue(uint64_t * value) const258 bool RegSet::GetIpRegValue(uint64_t* value) const { 259 size_t regno; 260 switch (arch) { 261 case ARCH_X86_64: 262 case ARCH_X86_32: 263 regno = PERF_REG_X86_IP; 264 break; 265 case ARCH_ARM: 266 regno = PERF_REG_ARM_PC; 267 break; 268 case ARCH_ARM64: 269 regno = PERF_REG_ARM64_PC; 270 break; 271 case ARCH_RISCV64: 272 regno = PERF_REG_RISCV_PC; 273 break; 274 default: 275 return false; 276 } 277 return GetRegValue(regno, value); 278 } 279 280 } // namespace simpleperf 281