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