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 } // go through 127 case ARCH_X86_32: { 128 auto it = x86_reg_map.find(reg); 129 CHECK(it != x86_reg_map.end()) << "unknown reg " << reg; 130 return it->second; 131 } 132 case ARCH_ARM: { 133 if (reg >= PERF_REG_ARM_R0 && reg <= PERF_REG_ARM_R10) { 134 return android::base::StringPrintf("r%d", reg - PERF_REG_ARM_R0); 135 } 136 auto it = arm_reg_map.find(reg); 137 CHECK(it != arm_reg_map.end()) << "unknown reg " << reg; 138 return it->second; 139 } 140 case ARCH_ARM64: { 141 if (reg >= PERF_REG_ARM64_X0 && reg <= PERF_REG_ARM64_X29) { 142 return android::base::StringPrintf("r%d", reg - PERF_REG_ARM64_X0); 143 } 144 auto it = arm64_reg_map.find(reg); 145 CHECK(it != arm64_reg_map.end()) << "unknown reg " << reg; 146 return it->second; 147 } 148 default: 149 return "unknown"; 150 } 151 } 152 153 RegSet::RegSet(int abi, uint64_t valid_mask, const uint64_t* valid_regs) 154 : valid_mask(valid_mask) { 155 arch = (abi == PERF_SAMPLE_REGS_ABI_32) ? ScopedCurrentArch::GetCurrentArch32() 156 : ScopedCurrentArch::GetCurrentArch(); 157 memset(data, 0, sizeof(data)); 158 for (int i = 0, j = 0; i < 64; ++i) { 159 if ((valid_mask >> i) & 1) { 160 data[i] = valid_regs[j++]; 161 } 162 } 163 if (ScopedCurrentArch::GetCurrentArch() == ARCH_ARM64 && abi == PERF_SAMPLE_REGS_ABI_32) { 164 // The kernel dumps arm64 regs, but we need arm regs. So map arm64 regs into arm regs. 165 data[PERF_REG_ARM_PC] = data[PERF_REG_ARM64_PC]; 166 } 167 } 168 169 bool RegSet::GetRegValue(size_t regno, uint64_t* value) const { 170 CHECK_LT(regno, 64U); 171 if ((valid_mask >> regno) & 1) { 172 *value = data[regno]; 173 return true; 174 } 175 return false; 176 } 177 178 bool RegSet::GetSpRegValue(uint64_t* value) const { 179 size_t regno; 180 switch (arch) { 181 case ARCH_X86_32: 182 regno = PERF_REG_X86_SP; 183 break; 184 case ARCH_X86_64: 185 regno = PERF_REG_X86_SP; 186 break; 187 case ARCH_ARM: 188 regno = PERF_REG_ARM_SP; 189 break; 190 case ARCH_ARM64: 191 regno = PERF_REG_ARM64_SP; 192 break; 193 default: 194 return false; 195 } 196 return GetRegValue(regno, value); 197 } 198 199 bool RegSet::GetIpRegValue(uint64_t* value) const { 200 size_t regno; 201 switch (arch) { 202 case ARCH_X86_64: 203 case ARCH_X86_32: 204 regno = PERF_REG_X86_IP; 205 break; 206 case ARCH_ARM: 207 regno = PERF_REG_ARM_PC; 208 break; 209 case ARCH_ARM64: 210 regno = PERF_REG_ARM64_PC; 211 break; 212 default: 213 return false; 214 } 215 return GetRegValue(regno, value); 216 } 217