• 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 <android-base/logging.h>
22  #include <android-base/stringprintf.h>
23  #include <android-base/strings.h>
24  #include <unordered_map>
25  
26  #include "perf_event.h"
27  
28  namespace simpleperf {
29  
30  ArchType ScopedCurrentArch::current_arch = ARCH_UNSUPPORTED;
31  
GetArchType(const std::string & arch)32  ArchType GetArchType(const std::string& arch) {
33    if (arch == "x86" || arch == "i686") {
34      return ARCH_X86_32;
35    } else if (arch == "x86_64") {
36      return ARCH_X86_64;
37    } else if (arch == "riscv64") {
38      return ARCH_RISCV64;
39    } else if (arch == "aarch64") {
40      return ARCH_ARM64;
41    } else if (android::base::StartsWith(arch, "arm")) {
42      // If arch is "armv8l", it is likely that we are using a 32-bit simpleperf
43      // binary on a aarch64 device. In this case, the profiling environment is
44      // ARCH_ARM64, because the kernel is aarch64.
45      if (arch[3] == 'v') {
46        int version = atoi(&arch[4]);
47        if (version >= 8) {
48          return ARCH_ARM64;
49        }
50      }
51      return ARCH_ARM;
52    }
53    LOG(ERROR) << "unsupported arch: " << arch;
54    return ARCH_UNSUPPORTED;
55  }
56  
GetArchForAbi(ArchType machine_arch,int abi)57  ArchType GetArchForAbi(ArchType machine_arch, int abi) {
58    if (abi == PERF_SAMPLE_REGS_ABI_32) {
59      if (machine_arch == ARCH_X86_64) {
60        return ARCH_X86_32;
61      }
62      if (machine_arch == ARCH_ARM64) {
63        return ARCH_ARM;
64      }
65    } else if (abi == PERF_SAMPLE_REGS_ABI_64) {
66      if (machine_arch == ARCH_X86_32) {
67        return ARCH_X86_64;
68      }
69      if (machine_arch == ARCH_ARM) {
70        return ARCH_ARM64;
71      }
72    }
73    return machine_arch;
74  }
75  
GetArchString(ArchType arch)76  std::string GetArchString(ArchType arch) {
77    switch (arch) {
78      case ARCH_X86_32:
79        return "x86";
80      case ARCH_X86_64:
81        return "x86_64";
82      case ARCH_ARM64:
83        return "arm64";
84      case ARCH_ARM:
85        return "arm";
86      case ARCH_RISCV64:
87        return "riscv64";
88      default:
89        break;
90    }
91    return "unknown";
92  }
93  
GetSupportedRegMask(ArchType arch)94  uint64_t GetSupportedRegMask(ArchType arch) {
95    switch (arch) {
96      case ARCH_X86_32:
97        return ((1ULL << PERF_REG_X86_32_MAX) - 1) & ~(1ULL << PERF_REG_X86_DS) &
98               ~(1ULL << PERF_REG_X86_ES) & ~(1ULL << PERF_REG_X86_FS) & ~(1ULL << PERF_REG_X86_GS);
99      case ARCH_X86_64:
100        return (((1ULL << PERF_REG_X86_64_MAX) - 1) & ~(1ULL << PERF_REG_X86_DS) &
101                ~(1ULL << PERF_REG_X86_ES) & ~(1ULL << PERF_REG_X86_FS) & ~(1ULL << PERF_REG_X86_GS));
102      case ARCH_ARM:
103        return ((1ULL << PERF_REG_ARM_MAX) - 1);
104      case ARCH_ARM64:
105        return ((1ULL << PERF_REG_ARM64_MAX) - 1);
106      case ARCH_RISCV64:
107        return ((1ULL << PERF_REG_RISCV_MAX) - 1);
108      default:
109        return 0;
110    }
111    return 0;
112  }
113  
114  static std::unordered_map<size_t, std::string> x86_reg_map = {
115      {PERF_REG_X86_AX, "ax"},       {PERF_REG_X86_BX, "bx"}, {PERF_REG_X86_CX, "cx"},
116      {PERF_REG_X86_DX, "dx"},       {PERF_REG_X86_SI, "si"}, {PERF_REG_X86_DI, "di"},
117      {PERF_REG_X86_BP, "bp"},       {PERF_REG_X86_SP, "sp"}, {PERF_REG_X86_IP, "ip"},
118      {PERF_REG_X86_FLAGS, "flags"}, {PERF_REG_X86_CS, "cs"}, {PERF_REG_X86_SS, "ss"},
119      {PERF_REG_X86_DS, "ds"},       {PERF_REG_X86_ES, "es"}, {PERF_REG_X86_FS, "fs"},
120      {PERF_REG_X86_GS, "gs"},
121  };
122  
123  static std::unordered_map<size_t, std::string> arm_reg_map = {
124      {PERF_REG_ARM_FP, "fp"}, {PERF_REG_ARM_IP, "ip"}, {PERF_REG_ARM_SP, "sp"},
125      {PERF_REG_ARM_LR, "lr"}, {PERF_REG_ARM_PC, "pc"},
126  };
127  
128  static std::unordered_map<size_t, std::string> arm64_reg_map = {
129      {PERF_REG_ARM64_LR, "lr"},
130      {PERF_REG_ARM64_SP, "sp"},
131      {PERF_REG_ARM64_PC, "pc"},
132  };
133  
134  static std::unordered_map<size_t, std::string> riscv64_reg_map = {
135      {PERF_REG_RISCV_PC, "pc"},
136      {PERF_REG_RISCV_RA, "ra"},
137      {PERF_REG_RISCV_SP, "sp"},
138      {PERF_REG_RISCV_GP, "gp"},
139      {PERF_REG_RISCV_TP, "tp"},
140      {PERF_REG_RISCV_T0, "t0"},
141      {PERF_REG_RISCV_T1, "t1"},
142      {PERF_REG_RISCV_T2, "t2"},
143      {PERF_REG_RISCV_S0, "s0"},
144      {PERF_REG_RISCV_S1, "s1"},
145      {PERF_REG_RISCV_A0, "a0"},
146      {PERF_REG_RISCV_A1, "a1"},
147      {PERF_REG_RISCV_A2, "a2"},
148      {PERF_REG_RISCV_A3, "a3"},
149      {PERF_REG_RISCV_A4, "a4"},
150      {PERF_REG_RISCV_A5, "a5"},
151      {PERF_REG_RISCV_A6, "a6"},
152      {PERF_REG_RISCV_A7, "a7"},
153      {PERF_REG_RISCV_S2, "s2"},
154      {PERF_REG_RISCV_S3, "s3"},
155      {PERF_REG_RISCV_S4, "s4"},
156      {PERF_REG_RISCV_S5, "s5"},
157      {PERF_REG_RISCV_S6, "s6"},
158      {PERF_REG_RISCV_S7, "s7"},
159      {PERF_REG_RISCV_S8, "s8"},
160      {PERF_REG_RISCV_S9, "s9"},
161      {PERF_REG_RISCV_S10, "s10"},
162      {PERF_REG_RISCV_S11, "s11"},
163      {PERF_REG_RISCV_T3, "t3"},
164      {PERF_REG_RISCV_T4, "t4"},
165      {PERF_REG_RISCV_T5, "t5"},
166      {PERF_REG_RISCV_T6, "t6"},
167  };
168  
GetRegName(size_t regno,ArchType arch)169  std::string GetRegName(size_t regno, ArchType arch) {
170    // Cast regno to int type to avoid -Werror=type-limits.
171    int reg = static_cast<int>(regno);
172    switch (arch) {
173      case ARCH_X86_64: {
174        if (reg >= PERF_REG_X86_R8 && reg <= PERF_REG_X86_R15) {
175          return android::base::StringPrintf("r%d", reg - PERF_REG_X86_R8 + 8);
176        }
177        FALLTHROUGH_INTENDED;
178      }
179      case ARCH_X86_32: {
180        auto it = x86_reg_map.find(reg);
181        CHECK(it != x86_reg_map.end()) << "unknown reg " << reg;
182        return it->second;
183      }
184      case ARCH_ARM: {
185        if (reg >= PERF_REG_ARM_R0 && reg <= PERF_REG_ARM_R10) {
186          return android::base::StringPrintf("r%d", reg - PERF_REG_ARM_R0);
187        }
188        if (auto it = arm_reg_map.find(reg); it != arm_reg_map.end()) {
189          return it->second;
190        }
191        FALLTHROUGH_INTENDED;
192      }
193      case ARCH_ARM64: {
194        if (reg >= PERF_REG_ARM64_X0 && reg <= PERF_REG_ARM64_X29) {
195          return android::base::StringPrintf("r%d", reg - PERF_REG_ARM64_X0);
196        }
197        auto it = arm64_reg_map.find(reg);
198        CHECK(it != arm64_reg_map.end()) << "unknown reg " << reg;
199        return it->second;
200      }
201      case ARCH_RISCV64: {
202        auto it = riscv64_reg_map.find(reg);
203        CHECK(it != riscv64_reg_map.end()) << "unknown reg " << reg;
204        return it->second;
205      }
206      default:
207        return "unknown";
208    }
209  }
210  
RegSet(int abi,uint64_t valid_mask,const uint64_t * valid_regs)211  RegSet::RegSet(int abi, uint64_t valid_mask, const uint64_t* valid_regs) : valid_mask(valid_mask) {
212    arch = GetArchForAbi(ScopedCurrentArch::GetCurrentArch(), abi);
213    memset(data, 0, sizeof(data));
214    for (int i = 0, j = 0; i < 64; ++i) {
215      if ((valid_mask >> i) & 1) {
216        data[i] = valid_regs[j++];
217      }
218    }
219    if (ScopedCurrentArch::GetCurrentArch() == ARCH_ARM64 && abi == PERF_SAMPLE_REGS_ABI_32) {
220      // The kernel dumps arm64 regs, but we need arm regs. So map arm64 regs into arm regs.
221      data[PERF_REG_ARM_PC] = data[PERF_REG_ARM64_PC];
222    }
223  }
224  
GetRegValue(size_t regno,uint64_t * value) const225  bool RegSet::GetRegValue(size_t regno, uint64_t* value) const {
226    CHECK_LT(regno, 64U);
227    if ((valid_mask >> regno) & 1) {
228      *value = data[regno];
229      return true;
230    }
231    return false;
232  }
233  
GetSpRegValue(uint64_t * value) const234  bool RegSet::GetSpRegValue(uint64_t* value) const {
235    size_t regno;
236    switch (arch) {
237      case ARCH_X86_32:
238        regno = PERF_REG_X86_SP;
239        break;
240      case ARCH_X86_64:
241        regno = PERF_REG_X86_SP;
242        break;
243      case ARCH_ARM:
244        regno = PERF_REG_ARM_SP;
245        break;
246      case ARCH_ARM64:
247        regno = PERF_REG_ARM64_SP;
248        break;
249      case ARCH_RISCV64:
250        regno = PERF_REG_RISCV_SP;
251        break;
252      default:
253        return false;
254    }
255    return GetRegValue(regno, value);
256  }
257  
GetIpRegValue(uint64_t * value) const258  bool RegSet::GetIpRegValue(uint64_t* value) const {
259    size_t regno;
260    switch (arch) {
261      case ARCH_X86_64:
262      case ARCH_X86_32:
263        regno = PERF_REG_X86_IP;
264        break;
265      case ARCH_ARM:
266        regno = PERF_REG_ARM_PC;
267        break;
268      case ARCH_ARM64:
269        regno = PERF_REG_ARM64_PC;
270        break;
271      case ARCH_RISCV64:
272        regno = PERF_REG_RISCV_PC;
273        break;
274      default:
275        return false;
276    }
277    return GetRegValue(regno, value);
278  }
279  
280  }  // namespace simpleperf
281