• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  
GetArchType(const std::string & arch)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  
GetArchForAbi(ArchType machine_arch,int abi)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  
GetArchString(ArchType arch)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  
GetSupportedRegMask(ArchType arch)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  
GetRegName(size_t regno,ArchType arch)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  
RegSet(int abi,uint64_t valid_mask,const uint64_t * valid_regs)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  
GetRegValue(size_t regno,uint64_t * value) const169  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  
GetSpRegValue(uint64_t * value) const178  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  
GetIpRegValue(uint64_t * value) const199  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