Home | History | Annotate | Download | only in simpleperf
      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