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 <unordered_map> 20 #include <android-base/logging.h> 21 #include <android-base/stringprintf.h> 22 #include <android-base/strings.h> 23 24 #include "perf_event.h" 25 26 ArchType ScopedCurrentArch::current_arch = ARCH_UNSUPPORTED; 27 ArchType ScopedCurrentArch::current_arch32 = ARCH_UNSUPPORTED; 28 29 ArchType GetArchType(const std::string& arch) { 30 if (arch == "x86" || arch == "i686") { 31 return ARCH_X86_32; 32 } else if (arch == "x86_64") { 33 return ARCH_X86_64; 34 } else if (arch == "aarch64") { 35 return ARCH_ARM64; 36 } else if (android::base::StartsWith(arch, "arm")) { 37 // If arch is "armv8l", it is likely that we are using a 32-bit simpleperf 38 // binary on a aarch64 device. In this case, the profiling environment is 39 // ARCH_ARM64, because the kernel is aarch64. 40 if (arch[3] == 'v') { 41 int version = atoi(&arch[4]); 42 if (version >= 8) { 43 return ARCH_ARM64; 44 } 45 } 46 return ARCH_ARM; 47 } 48 LOG(ERROR) << "unsupported arch: " << arch; 49 return ARCH_UNSUPPORTED; 50 } 51 52 ArchType GetArchForAbi(ArchType machine_arch, int abi) { 53 if (abi == PERF_SAMPLE_REGS_ABI_32) { 54 if (machine_arch == ARCH_X86_64) { 55 return ARCH_X86_32; 56 } 57 if (machine_arch == ARCH_ARM64) { 58 return ARCH_ARM; 59 } 60 } 61 return machine_arch; 62 } 63 64 std::string GetArchString(ArchType arch) { 65 switch (arch) { 66 case ARCH_X86_32: 67 return "x86"; 68 case ARCH_X86_64: 69 return "x86_64"; 70 case ARCH_ARM64: 71 return "arm64"; 72 case ARCH_ARM: 73 return "arm"; 74 default: 75 break; 76 } 77 return "unknown"; 78 } 79 80 // If strict_check, must have arch1 == arch2. 81 // Otherwise, allow X86_32 with X86_64, ARM with ARM64. 82 bool IsArchTheSame(ArchType arch1, ArchType arch2, bool strict_check) { 83 if (strict_check) { 84 return arch1 == arch2; 85 } 86 switch (arch1) { 87 case ARCH_X86_32: 88 case ARCH_X86_64: 89 return arch2 == ARCH_X86_32 || arch2 == ARCH_X86_64; 90 case ARCH_ARM64: 91 case ARCH_ARM: 92 return arch2 == ARCH_ARM64 || arch2 == ARCH_ARM; 93 default: 94 break; 95 } 96 return arch1 == arch2; 97 } 98 99 uint64_t GetSupportedRegMask(ArchType arch) { 100 switch (arch) { 101 case ARCH_X86_32: 102 return ((1ULL << PERF_REG_X86_32_MAX) - 1); 103 case ARCH_X86_64: 104 return (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~(1ULL << PERF_REG_X86_DS) & 105 ~(1ULL << PERF_REG_X86_ES) & ~(1ULL << PERF_REG_X86_FS) & ~(1ULL << PERF_REG_X86_GS)); 106 case ARCH_ARM: 107 return ((1ULL << PERF_REG_ARM_MAX) - 1); 108 case ARCH_ARM64: 109 return ((1ULL << PERF_REG_ARM64_MAX) - 1); 110 default: 111 return 0; 112 } 113 return 0; 114 } 115 116 static std::unordered_map<size_t, std::string> x86_reg_map = { 117 {PERF_REG_X86_AX, "ax"}, {PERF_REG_X86_BX, "bx"}, {PERF_REG_X86_CX, "cx"}, 118 {PERF_REG_X86_DX, "dx"}, {PERF_REG_X86_SI, "si"}, {PERF_REG_X86_DI, "di"}, 119 {PERF_REG_X86_BP, "bp"}, {PERF_REG_X86_SP, "sp"}, {PERF_REG_X86_IP, "ip"}, 120 {PERF_REG_X86_FLAGS, "flags"}, {PERF_REG_X86_CS, "cs"}, {PERF_REG_X86_SS, "ss"}, 121 {PERF_REG_X86_DS, "ds"}, {PERF_REG_X86_ES, "es"}, {PERF_REG_X86_FS, "fs"}, 122 {PERF_REG_X86_GS, "gs"}, 123 }; 124 125 static std::unordered_map<size_t, std::string> arm_reg_map = { 126 {PERF_REG_ARM_FP, "fp"}, {PERF_REG_ARM_IP, "ip"}, {PERF_REG_ARM_SP, "sp"}, 127 {PERF_REG_ARM_LR, "lr"}, {PERF_REG_ARM_PC, "pc"}, 128 }; 129 130 static std::unordered_map<size_t, std::string> arm64_reg_map = { 131 {PERF_REG_ARM64_LR, "lr"}, {PERF_REG_ARM64_SP, "sp"}, {PERF_REG_ARM64_PC, "pc"}, 132 }; 133 134 std::string GetRegName(size_t regno, ArchType arch) { 135 // Cast regno to int type to avoid -Werror=type-limits. 136 int reg = static_cast<int>(regno); 137 switch (arch) { 138 case ARCH_X86_64: { 139 if (reg >= PERF_REG_X86_R8 && reg <= PERF_REG_X86_R15) { 140 return android::base::StringPrintf("r%d", reg - PERF_REG_X86_R8 + 8); 141 } 142 } // go through 143 case ARCH_X86_32: { 144 auto it = x86_reg_map.find(reg); 145 CHECK(it != x86_reg_map.end()) << "unknown reg " << reg; 146 return it->second; 147 } 148 case ARCH_ARM: { 149 if (reg >= PERF_REG_ARM_R0 && reg <= PERF_REG_ARM_R10) { 150 return android::base::StringPrintf("r%d", reg - PERF_REG_ARM_R0); 151 } 152 auto it = arm_reg_map.find(reg); 153 CHECK(it != arm_reg_map.end()) << "unknown reg " << reg; 154 return it->second; 155 } 156 case ARCH_ARM64: { 157 if (reg >= PERF_REG_ARM64_X0 && reg <= PERF_REG_ARM64_X29) { 158 return android::base::StringPrintf("r%d", reg - PERF_REG_ARM64_X0); 159 } 160 auto it = arm64_reg_map.find(reg); 161 CHECK(it != arm64_reg_map.end()) << "unknown reg " << reg; 162 return it->second; 163 } 164 default: 165 return "unknown"; 166 } 167 } 168 169 RegSet CreateRegSet(int abi, uint64_t valid_mask, const uint64_t* valid_regs) { 170 RegSet regs; 171 regs.valid_mask = valid_mask; 172 for (int i = 0, j = 0; i < 64; ++i) { 173 if ((valid_mask >> i) & 1) { 174 regs.data[i] = valid_regs[j++]; 175 } 176 } 177 if (ScopedCurrentArch::GetCurrentArch() == ARCH_ARM64 && 178 abi == PERF_SAMPLE_REGS_ABI_32) { 179 // The kernel dumps arm64 regs, but we need arm regs. So map arm64 180 // regs into arm regs. 181 regs.data[PERF_REG_ARM_PC] = regs.data[PERF_REG_ARM64_PC]; 182 } 183 return regs; 184 } 185 186 void SetIpReg(ArchType arch, uint64_t ip, RegSet* regs) { 187 int regno; 188 switch (arch) { 189 case ARCH_X86_64: 190 case ARCH_X86_32: 191 regno = PERF_REG_X86_IP; 192 break; 193 case ARCH_ARM: 194 regno = PERF_REG_ARM_PC; 195 break; 196 case ARCH_ARM64: 197 regno = PERF_REG_ARM64_PC; 198 break; 199 default: 200 return; 201 } 202 regs->valid_mask |= (1ULL << regno); 203 regs->data[regno] = ip; 204 } 205 206 bool GetRegValue(const RegSet& regs, size_t regno, uint64_t* value) { 207 CHECK_LT(regno, 64U); 208 if ((regs.valid_mask >> regno) & 1) { 209 *value = regs.data[regno]; 210 return true; 211 } 212 return false; 213 } 214 215 bool GetSpRegValue(const RegSet& regs, ArchType arch, uint64_t* value) { 216 size_t regno; 217 switch (arch) { 218 case ARCH_X86_32: 219 regno = PERF_REG_X86_SP; 220 break; 221 case ARCH_X86_64: 222 regno = PERF_REG_X86_SP; 223 break; 224 case ARCH_ARM: 225 regno = PERF_REG_ARM_SP; 226 break; 227 case ARCH_ARM64: 228 regno = PERF_REG_ARM64_SP; 229 break; 230 default: 231 return false; 232 } 233 return GetRegValue(regs, regno, value); 234 } 235