• 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